2012-12-23 14:29:54 +01:00
/*! \file main.c
* \ brief Main file of SuperDerpy engine .
2012-02-28 13:09:12 +01:00
*
2012-12-23 14:29:54 +01:00
* Contains basic functions shared by all views .
2012-02-28 13:09:12 +01:00
*/
2012-03-04 13:32:42 +01:00
/*
* Copyright ( c ) Sebastian Krzyszkowiak < dos @ dosowisko . net >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2012-09-19 01:20:24 +02:00
*
* Also , ponies .
2012-03-04 13:32:42 +01:00
*/
2012-02-15 23:57:06 +01:00
# include <stdio.h>
2012-03-03 21:09:49 +01:00
# include <math.h>
2012-04-09 18:41:46 +02:00
# include <getopt.h>
2012-05-07 22:44:39 +02:00
# include <locale.h>
2012-08-04 21:58:31 +02:00
# include <signal.h>
2012-12-26 02:25:56 +01:00
# include <dlfcn.h>
2012-12-26 23:48:05 +01:00
# include <allegro5/allegro_primitives.h>
# include <allegro5/allegro_acodec.h>
# include <allegro5/allegro_ttf.h>
2012-12-24 19:41:12 +01:00
# include "utils.h"
2012-02-24 13:03:30 +01:00
# include "config.h"
2012-12-24 19:41:12 +01:00
# include "main.h"
2012-02-15 23:57:06 +01:00
2012-12-24 19:41:12 +01:00
void DrawGamestates ( struct Game * game ) {
2015-03-15 05:38:15 +01:00
al_set_target_backbuffer ( game - > display ) ;
2012-09-26 03:08:58 +02:00
al_clear_to_color ( al_map_rgb ( 0 , 0 , 0 ) ) ;
2012-12-26 02:25:56 +01:00
struct Gamestate * tmp = game - > _priv . gamestates ;
2012-12-25 00:22:03 +01:00
while ( tmp ) {
if ( ( tmp - > loaded ) & & ( tmp - > started ) ) {
2012-12-26 13:24:34 +01:00
( * tmp - > api . Gamestate_Draw ) ( game , tmp - > data ) ;
2012-12-25 00:22:03 +01:00
}
tmp = tmp - > next ;
}
2016-06-27 21:21:59 +02:00
if ( game - > mediator . pause ) {
al_draw_filled_rectangle ( 0 , 0 , 320 , 180 , al_map_rgba ( 0 , 0 , 0 , 192 ) ) ;
DrawTextWithShadow ( game - > _priv . font , al_map_rgb ( 255 , 255 , 255 ) , game - > viewport . width * 0.5 , game - > viewport . height * 0.5 - 25 , ALLEGRO_ALIGN_CENTRE , " Game paused! " ) ;
DrawTextWithShadow ( game - > _priv . font , al_map_rgb ( 255 , 255 , 255 ) , game - > viewport . width * 0.5 , game - > viewport . height * 0.5 + 5 , ALLEGRO_ALIGN_CENTRE , " SPACE to resume " ) ;
}
2012-09-26 03:08:58 +02:00
}
2012-12-24 19:41:12 +01:00
void LogicGamestates ( struct Game * game ) {
2016-06-27 21:21:59 +02:00
if ( game - > mediator . pause ) return ;
2012-12-26 02:25:56 +01:00
struct Gamestate * tmp = game - > _priv . gamestates ;
2012-12-25 00:22:03 +01:00
while ( tmp ) {
if ( ( tmp - > loaded ) & & ( tmp - > started ) & & ( ! tmp - > paused ) ) {
2012-12-26 13:24:34 +01:00
( * tmp - > api . Gamestate_Logic ) ( game , tmp - > data ) ;
2012-12-26 02:25:56 +01:00
}
tmp = tmp - > next ;
}
}
void EventGamestates ( struct Game * game , ALLEGRO_EVENT * ev ) {
struct Gamestate * tmp = game - > _priv . gamestates ;
while ( tmp ) {
if ( ( tmp - > loaded ) & & ( tmp - > started ) & & ( ! tmp - > paused ) ) {
2012-12-26 13:24:34 +01:00
( * tmp - > api . Gamestate_ProcessEvent ) ( game , tmp - > data , ev ) ;
2012-12-25 00:22:03 +01:00
}
tmp = tmp - > next ;
}
2012-03-01 00:37:16 +01:00
}
2016-06-27 21:21:59 +02:00
void PauseGamestates ( struct Game * game ) {
struct Gamestate * tmp = game - > _priv . gamestates ;
while ( tmp ) {
if ( ( tmp - > loaded ) & & ( tmp - > started ) ) {
( * tmp - > api . Gamestate_Pause ) ( game , tmp - > data ) ;
}
tmp = tmp - > next ;
}
}
void ResumeGamestates ( struct Game * game ) {
struct Gamestate * tmp = game - > _priv . gamestates ;
while ( tmp ) {
if ( ( tmp - > loaded ) & & ( tmp - > started ) ) {
( * tmp - > api . Gamestate_Resume ) ( game , tmp - > data ) ;
}
tmp = tmp - > next ;
}
}
2012-08-04 21:58:31 +02:00
void derp ( int sig ) {
2016-06-27 21:20:02 +02:00
int __attribute__ ( ( unused ) ) n = write ( STDERR_FILENO , " Segmentation fault \n I just don't know what went wrong! \n " , 54 ) ;
2012-09-03 02:25:32 +02:00
abort ( ) ;
2012-08-04 21:58:31 +02:00
}
2012-02-15 23:57:06 +01:00
int main ( int argc , char * * argv ) {
2012-08-04 21:58:31 +02:00
signal ( SIGSEGV , derp ) ;
2012-02-25 22:26:31 +01:00
srand ( time ( NULL ) ) ;
2012-02-26 00:47:41 +01:00
2012-07-03 23:44:03 +02:00
al_set_org_name ( " Super Derpy " ) ;
2016-06-27 21:21:59 +02:00
al_set_app_name ( " Mediator " ) ;
2012-07-03 23:44:03 +02:00
2012-09-03 02:25:32 +02:00
if ( ! al_init ( ) ) {
fprintf ( stderr , " failed to initialize allegro! \n " ) ;
return - 1 ;
}
2012-09-03 02:08:12 +02:00
2012-02-25 22:26:31 +01:00
struct Game game ;
2012-02-16 12:48:48 +01:00
2012-12-24 19:41:12 +01:00
InitConfig ( & game ) ;
2012-12-23 14:29:54 +01:00
2012-12-24 19:41:12 +01:00
game . _priv . fps_count . frames_done = 0 ;
game . _priv . fps_count . fps = 0 ;
game . _priv . fps_count . old_time = 0 ;
2015-03-15 05:38:15 +01:00
game . _priv . font_bsod = NULL ;
game . _priv . console = NULL ;
2016-06-27 21:20:02 +02:00
game . config . fullscreen = atoi ( GetConfigOptionDefault ( & game , " SuperDerpy " , " fullscreen " , " 0 " ) ) ;
game . config . music = atoi ( GetConfigOptionDefault ( & game , " SuperDerpy " , " music " , " 10 " ) ) ;
2012-12-24 19:41:12 +01:00
game . config . voice = atoi ( GetConfigOptionDefault ( & game , " SuperDerpy " , " voice " , " 10 " ) ) ;
game . config . fx = atoi ( GetConfigOptionDefault ( & game , " SuperDerpy " , " fx " , " 10 " ) ) ;
game . config . debug = atoi ( GetConfigOptionDefault ( & game , " SuperDerpy " , " debug " , " 0 " ) ) ;
2016-06-27 21:20:02 +02:00
game . config . width = atoi ( GetConfigOptionDefault ( & game , " SuperDerpy " , " width " , " 1280 " ) ) ;
2012-12-24 19:41:12 +01:00
if ( game . config . width < 320 ) game . config . width = 320 ;
2016-06-27 21:20:02 +02:00
game . config . height = atoi ( GetConfigOptionDefault ( & game , " SuperDerpy " , " height " , " 720 " ) ) ;
2012-12-24 19:41:12 +01:00
if ( game . config . height < 180 ) game . config . height = 180 ;
2012-02-26 12:59:45 +01:00
2012-02-25 22:26:31 +01:00
if ( ! al_init_image_addon ( ) ) {
fprintf ( stderr , " failed to initialize image addon! \n " ) ;
2012-04-14 22:26:33 +02:00
/*al_show_native_message_box(display, "Error", "Error", "Failed to initialize al_init_image_addon!",
2012-09-03 02:25:32 +02:00
NULL , ALLEGRO_MESSAGEBOX_ERROR ) ; */
2012-11-14 22:13:25 +01:00
return - 1 ;
2012-02-25 22:26:31 +01:00
}
2012-02-15 23:57:06 +01:00
2012-02-25 22:26:31 +01:00
if ( ! al_init_acodec_addon ( ) ) {
fprintf ( stderr , " failed to initialize audio codecs! \n " ) ;
return - 1 ;
}
2012-02-19 19:17:04 +01:00
2012-02-25 22:26:31 +01:00
if ( ! al_install_audio ( ) ) {
fprintf ( stderr , " failed to initialize audio! \n " ) ;
return - 1 ;
}
2012-02-15 23:57:06 +01:00
2012-02-25 22:26:31 +01:00
if ( ! al_install_keyboard ( ) ) {
fprintf ( stderr , " failed to initialize keyboard! \n " ) ;
return - 1 ;
}
2012-02-15 23:57:06 +01:00
2012-05-09 10:58:45 +02:00
if ( ! al_init_primitives_addon ( ) ) {
fprintf ( stderr , " failed to initialize primitives! \n " ) ;
return - 1 ;
}
2016-06-27 21:21:59 +02:00
if ( ! al_install_mouse ( ) ) {
fprintf ( stderr , " failed to initialize the mouse! \n " ) ;
return - 1 ;
}
2012-05-09 10:58:45 +02:00
2012-02-25 22:26:31 +01:00
al_init_font_addon ( ) ;
2012-02-15 23:57:06 +01:00
2012-02-25 22:26:31 +01:00
if ( ! al_init_ttf_addon ( ) ) {
fprintf ( stderr , " failed to initialize fonts! \n " ) ;
return - 1 ;
}
2012-02-16 12:48:48 +01:00
2012-12-24 19:41:12 +01:00
if ( game . config . fullscreen ) al_set_new_display_flags ( ALLEGRO_FULLSCREEN_WINDOW ) ;
2012-03-08 12:34:47 +01:00
else al_set_new_display_flags ( ALLEGRO_WINDOWED ) ;
2012-12-24 19:41:12 +01:00
al_set_new_display_option ( ALLEGRO_VSYNC , 2 - atoi ( GetConfigOptionDefault ( & game , " SuperDerpy " , " vsync " , " 1 " ) ) , ALLEGRO_SUGGEST ) ;
al_set_new_display_option ( ALLEGRO_OPENGL , atoi ( GetConfigOptionDefault ( & game , " SuperDerpy " , " opengl " , " 1 " ) ) , ALLEGRO_SUGGEST ) ;
2016-06-27 21:20:02 +02:00
# ifdef ALLEGRO_WINDOWS
al_set_new_window_position ( 20 , 40 ) ; // workaround nasty Windows bug with window being created off-screen
# endif
2012-05-10 20:02:22 +02:00
2012-12-24 19:41:12 +01:00
game . display = al_create_display ( game . config . width , game . config . height ) ;
2012-02-25 22:26:31 +01:00
if ( ! game . display ) {
fprintf ( stderr , " failed to create display! \n " ) ;
return - 1 ;
}
2012-12-24 19:41:12 +01:00
2012-12-28 02:55:52 +01:00
SetupViewport ( & game ) ;
PrintConsole ( & game , " Viewport %dx%d " , game . viewport . width , game . viewport . height ) ;
2016-06-27 21:21:59 +02:00
ALLEGRO_BITMAP * icon = al_load_bitmap ( GetDataFilePath ( & game , " icons/mediator.png " ) ) ;
al_set_window_title ( game . display , " Mediator " ) ;
2012-09-19 01:20:24 +02:00
al_set_display_icon ( game . display , icon ) ;
al_destroy_bitmap ( icon ) ;
2016-06-27 21:21:59 +02:00
if ( game . config . fullscreen ) al_hide_mouse_cursor ( game . display ) ;
al_inhibit_screensaver ( true ) ;
2012-02-29 23:00:59 +01:00
2016-06-27 21:20:02 +02:00
al_set_new_bitmap_flags ( ALLEGRO_MIN_LINEAR ) ;
2012-02-29 23:00:59 +01:00
2012-12-26 02:25:56 +01:00
game . _priv . gamestates = NULL ;
2012-12-25 00:22:03 +01:00
2012-12-24 19:41:12 +01:00
game . _priv . event_queue = al_create_event_queue ( ) ;
if ( ! game . _priv . event_queue ) {
2012-12-28 02:55:52 +01:00
FatalError ( & game , true , " Failed to create event queue. " ) ;
2012-02-25 22:26:31 +01:00
al_destroy_display ( game . display ) ;
return - 1 ;
}
2012-02-15 23:57:06 +01:00
2016-06-27 21:20:02 +02:00
game . audio . v = al_create_voice ( 44100 , ALLEGRO_AUDIO_DEPTH_INT16 , ALLEGRO_CHANNEL_CONF_2 ) ;
2012-03-05 21:07:42 +01:00
game . audio . mixer = al_create_mixer ( 44100 , ALLEGRO_AUDIO_DEPTH_FLOAT32 , ALLEGRO_CHANNEL_CONF_2 ) ;
2012-03-05 11:13:08 +01:00
game . audio . fx = al_create_mixer ( 44100 , ALLEGRO_AUDIO_DEPTH_FLOAT32 , ALLEGRO_CHANNEL_CONF_2 ) ;
game . audio . music = al_create_mixer ( 44100 , ALLEGRO_AUDIO_DEPTH_FLOAT32 , ALLEGRO_CHANNEL_CONF_2 ) ;
2012-03-13 12:42:28 +01:00
game . audio . voice = al_create_mixer ( 44100 , ALLEGRO_AUDIO_DEPTH_FLOAT32 , ALLEGRO_CHANNEL_CONF_2 ) ;
al_attach_mixer_to_voice ( game . audio . mixer , game . audio . v ) ;
2012-03-08 12:49:58 +01:00
al_attach_mixer_to_mixer ( game . audio . fx , game . audio . mixer ) ;
al_attach_mixer_to_mixer ( game . audio . music , game . audio . mixer ) ;
2012-03-13 12:42:28 +01:00
al_attach_mixer_to_mixer ( game . audio . voice , game . audio . mixer ) ;
2012-12-24 19:41:12 +01:00
al_set_mixer_gain ( game . audio . fx , game . config . fx / 10.0 ) ;
al_set_mixer_gain ( game . audio . music , game . config . music / 10.0 ) ;
al_set_mixer_gain ( game . audio . voice , game . config . voice / 10.0 ) ;
2012-03-04 22:02:23 +01:00
2012-12-24 19:41:12 +01:00
al_register_event_source ( game . _priv . event_queue , al_get_display_event_source ( game . display ) ) ;
2016-06-27 21:21:59 +02:00
al_register_event_source ( game . _priv . event_queue , al_get_mouse_event_source ( ) ) ;
al_register_event_source ( game . _priv . event_queue , al_get_keyboard_event_source ( ) ) ;
2012-02-15 23:57:06 +01:00
2012-12-24 19:41:12 +01:00
game . _priv . showconsole = game . config . debug ;
2012-02-17 13:25:06 +01:00
2012-08-04 12:56:24 +02:00
al_clear_to_color ( al_map_rgb ( 0 , 0 , 0 ) ) ;
2012-12-24 19:41:12 +01:00
game . _priv . timer = al_create_timer ( ALLEGRO_BPS_TO_SECS ( 60 ) ) ; // logic timer
if ( ! game . _priv . timer ) {
2012-12-28 02:55:52 +01:00
FatalError ( & game , true , " Failed to create logic timer. " ) ;
2012-05-04 02:15:51 +02:00
return - 1 ;
}
2012-12-24 19:41:12 +01:00
al_register_event_source ( game . _priv . event_queue , al_get_timer_event_source ( game . _priv . timer ) ) ;
2016-06-27 21:20:02 +02:00
al_flip_display ( ) ;
2012-12-24 19:41:12 +01:00
al_start_timer ( game . _priv . timer ) ;
2012-02-24 13:08:44 +01:00
2012-12-24 19:41:12 +01:00
setlocale ( LC_NUMERIC , " C " ) ;
2012-05-07 22:44:39 +02:00
2012-02-29 23:00:59 +01:00
game . shuttingdown = false ;
2012-03-08 12:34:47 +01:00
game . restart = false ;
2012-12-24 19:41:12 +01:00
2016-06-27 21:21:59 +02:00
game . mediator . lives = 3 ;
game . mediator . score = 0 ;
game . mediator . modificator = 1 ;
game . mediator . strike = 0 ;
game . mediator . next = " lollipop " ;
game . mediator . pause = false ;
game . mediator . heart = CreateCharacter ( & game , " heart " ) ;
RegisterSpritesheet ( & game , game . mediator . heart , " heart " ) ;
RegisterSpritesheet ( & game , game . mediator . heart , " blank " ) ;
LoadSpritesheets ( & game , game . mediator . heart ) ;
SelectSpritesheet ( & game , game . mediator . heart , " heart " ) ;
2015-03-15 05:38:15 +01:00
char * gamestate = strdup ( " dosowisko " ) ; // FIXME: don't hardcore gamestate
2012-04-09 16:41:10 +02:00
int c ;
2012-07-08 23:08:23 +02:00
while ( ( c = getopt ( argc , argv , " l:s: " ) ) ! = - 1 )
2012-04-09 16:41:10 +02:00
switch ( c ) {
case ' l ' :
2012-12-24 19:41:12 +01:00
free ( gamestate ) ;
gamestate = strdup ( " levelX " ) ;
gamestate [ 5 ] = optarg [ 0 ] ;
2012-04-09 16:41:10 +02:00
break ;
2012-07-08 23:08:23 +02:00
case ' s ' :
2012-12-24 19:41:12 +01:00
free ( gamestate ) ;
gamestate = strdup ( optarg ) ;
2012-07-08 23:08:23 +02:00
break ;
2012-04-09 16:41:10 +02:00
}
2012-12-24 19:41:12 +01:00
LoadGamestate ( & game , gamestate ) ;
2016-06-27 21:21:59 +02:00
LoadGamestate ( & game , " burndt " ) ;
game . _priv . gamestates - > showLoading = false ; // we have only one gamestate right now
game . _priv . gamestates - > next - > showLoading = false ; // well, now two
StartGamestate ( & game , gamestate ) ;
2012-12-26 13:38:15 +01:00
free ( gamestate ) ;
2012-12-24 19:41:12 +01:00
2012-12-28 03:42:59 +01:00
char libname [ 1024 ] = { } ;
2016-06-27 21:21:59 +02:00
snprintf ( libname , 1024 , " libsuperderpy-%s-loading " LIBRARY_EXTENTION , " mediator " ) ;
2015-04-18 18:07:29 +02:00
void * handle = dlopen ( libname , RTLD_NOW ) ;
2012-12-28 03:42:59 +01:00
if ( ! handle ) {
FatalError ( & game , true , " Error while initializing loading screen %s " , dlerror ( ) ) ;
exit ( 1 ) ;
} else {
2016-06-27 21:20:02 +02:00
# define GS_LOADINGERROR FatalError(&game, true, "Error on resolving loading symbol: %s", dlerror()); exit(1);
2012-12-28 03:42:59 +01:00
2016-06-27 21:20:02 +02:00
if ( ! ( game . _priv . loading . Draw = dlsym ( handle , " Draw " ) ) ) { GS_LOADINGERROR ; }
if ( ! ( game . _priv . loading . Load = dlsym ( handle , " Load " ) ) ) { GS_LOADINGERROR ; }
if ( ! ( game . _priv . loading . Start = dlsym ( handle , " Start " ) ) ) { GS_LOADINGERROR ; }
if ( ! ( game . _priv . loading . Stop = dlsym ( handle , " Stop " ) ) ) { GS_LOADINGERROR ; }
if ( ! ( game . _priv . loading . Unload = dlsym ( handle , " Unload " ) ) ) { GS_LOADINGERROR ; }
2012-12-28 03:42:59 +01:00
}
game . _priv . loading . data = ( * game . _priv . loading . Load ) ( & game ) ;
2012-12-25 00:22:03 +01:00
bool redraw = false ;
2012-02-25 22:26:31 +01:00
while ( 1 ) {
ALLEGRO_EVENT ev ;
2012-12-25 00:22:03 +01:00
if ( redraw & & al_is_event_queue_empty ( game . _priv . event_queue ) ) {
2012-12-26 02:25:56 +01:00
struct Gamestate * tmp = game . _priv . gamestates ;
2012-12-28 00:00:37 +01:00
int toLoad = 0 , loaded = 0 ;
2012-12-27 01:02:47 +01:00
// FIXME: move to function
// TODO: support dependences
2012-12-25 00:22:03 +01:00
while ( tmp ) {
2012-12-26 20:02:40 +01:00
if ( ( tmp - > pending_start ) & & ( tmp - > started ) ) {
PrintConsole ( & game , " Stopping gamestate \" %s \" ... " , tmp - > name ) ;
( * tmp - > api . Gamestate_Stop ) ( & game , tmp - > data ) ;
tmp - > started = false ;
tmp - > pending_start = false ;
2012-12-27 21:05:28 +01:00
}
2012-12-28 00:00:37 +01:00
if ( ( tmp - > pending_load ) & & ( ! tmp - > loaded ) ) toLoad + + ;
2012-12-27 21:05:28 +01:00
tmp = tmp - > next ;
}
tmp = game . _priv . gamestates ;
// FIXME: move to function
// TODO: support dependences
2012-12-28 00:00:37 +01:00
2016-06-27 21:21:59 +02:00
double t = - 1 ;
2012-12-27 21:05:28 +01:00
while ( tmp ) {
if ( ( tmp - > pending_load ) & & ( tmp - > loaded ) ) {
2012-12-26 20:02:40 +01:00
PrintConsole ( & game , " Unloading gamestate \" %s \" ... " , tmp - > name ) ;
2015-03-15 05:38:15 +01:00
al_stop_timer ( game . _priv . timer ) ;
2012-12-26 20:02:40 +01:00
tmp - > loaded = false ;
tmp - > pending_load = false ;
( * tmp - > api . Gamestate_Unload ) ( & game , tmp - > data ) ;
dlclose ( tmp - > handle ) ;
tmp - > handle = NULL ;
2015-03-15 05:38:15 +01:00
al_start_timer ( game . _priv . timer ) ;
2012-12-27 21:05:28 +01:00
} else if ( ( tmp - > pending_load ) & & ( ! tmp - > loaded ) ) {
2012-12-26 15:15:02 +01:00
PrintConsole ( & game , " Loading gamestate \" %s \" ... " , tmp - > name ) ;
2015-03-15 05:38:15 +01:00
al_stop_timer ( game . _priv . timer ) ;
2012-12-26 02:25:56 +01:00
// TODO: take proper game name
char libname [ 1024 ] ;
2016-06-27 21:21:59 +02:00
snprintf ( libname , 1024 , " libsuperderpy-%s-%s " LIBRARY_EXTENTION , " mediator " , tmp - > name ) ;
2012-12-26 02:25:56 +01:00
tmp - > handle = dlopen ( libname , RTLD_NOW ) ;
if ( ! tmp - > handle ) {
2012-12-28 02:55:52 +01:00
//PrintConsole(&game, "Error while loading gamestate \"%s\": %s", tmp->name, dlerror());
2016-06-27 21:20:36 +02:00
FatalError ( & game , false , " Error while loading gamestate \" %s \" : %s " , tmp - > name , dlerror ( ) ) ;
2012-12-28 02:55:52 +01:00
2012-12-26 02:25:56 +01:00
tmp - > pending_load = false ;
2012-12-28 00:00:37 +01:00
tmp - > pending_start = false ;
2012-12-26 02:25:56 +01:00
} else {
2016-06-27 21:20:02 +02:00
# define GS_ERROR FatalError(&game, false, "Error on resolving gamestate symbol: %s", dlerror()); tmp->pending_load = false; tmp->pending_start = false; tmp=tmp->next; continue;
2012-12-26 02:25:56 +01:00
2016-06-27 21:20:02 +02:00
if ( ! ( tmp - > api . Gamestate_Draw = dlsym ( tmp - > handle , " Gamestate_Draw " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api . Gamestate_Logic = dlsym ( tmp - > handle , " Gamestate_Logic " ) ) ) { GS_ERROR ; }
2012-12-26 02:25:56 +01:00
2016-06-27 21:20:02 +02:00
if ( ! ( tmp - > api . Gamestate_Load = dlsym ( tmp - > handle , " Gamestate_Load " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api . Gamestate_Start = dlsym ( tmp - > handle , " Gamestate_Start " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api . Gamestate_Pause = dlsym ( tmp - > handle , " Gamestate_Pause " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api . Gamestate_Resume = dlsym ( tmp - > handle , " Gamestate_Resume " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api . Gamestate_Stop = dlsym ( tmp - > handle , " Gamestate_Stop " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api . Gamestate_Unload = dlsym ( tmp - > handle , " Gamestate_Unload " ) ) ) { GS_ERROR ; }
2012-12-26 02:25:56 +01:00
2016-06-27 21:20:02 +02:00
if ( ! ( tmp - > api . Gamestate_ProcessEvent = dlsym ( tmp - > handle , " Gamestate_ProcessEvent " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api . Gamestate_Reload = dlsym ( tmp - > handle , " Gamestate_Reload " ) ) ) { GS_ERROR ; }
2012-12-26 02:25:56 +01:00
2016-06-27 21:20:02 +02:00
if ( ! ( tmp - > api . Gamestate_ProgressCount = dlsym ( tmp - > handle , " Gamestate_ProgressCount " ) ) ) { GS_ERROR ; }
2012-12-26 02:25:56 +01:00
2012-12-28 00:00:37 +01:00
int p = 0 ;
2016-06-27 21:21:59 +02:00
2012-12-28 00:00:37 +01:00
void progress ( struct Game * game ) {
p + + ;
2015-03-15 05:38:15 +01:00
DrawGamestates ( game ) ;
2012-12-28 00:00:37 +01:00
float progress = ( ( p / ( * ( tmp - > api . Gamestate_ProgressCount ) ? ( float ) * ( tmp - > api . Gamestate_ProgressCount ) : 1 ) ) / ( float ) toLoad ) + ( loaded / ( float ) toLoad ) ;
2012-12-28 03:42:59 +01:00
if ( game - > config . debug ) PrintConsole ( game , " [%s] Progress: %d% (%d/%d) " , tmp - > name , ( int ) ( progress * 100 ) , p , * ( tmp - > api . Gamestate_ProgressCount ) ) ;
2015-03-15 05:38:15 +01:00
if ( tmp - > showLoading ) ( * game - > _priv . loading . Draw ) ( game , game - > _priv . loading . data , progress ) ;
2012-12-28 00:00:37 +01:00
DrawConsole ( game ) ;
2016-06-27 21:21:59 +02:00
if ( al_get_time ( ) - t > = 1 / 60.0 ) {
al_flip_display ( ) ;
}
t = al_get_time ( ) ;
2012-12-28 00:00:37 +01:00
}
2016-06-27 21:21:59 +02:00
t = al_get_time ( ) ;
2013-06-04 01:44:17 +02:00
// initially draw loading screen with empty bar
2015-03-15 05:38:15 +01:00
DrawGamestates ( & game ) ;
if ( tmp - > showLoading ) {
2016-06-27 21:21:59 +02:00
( * game . _priv . loading . Draw ) ( & game , game . _priv . loading . data , loaded / ( float ) toLoad ) ;
2015-03-15 05:38:15 +01:00
}
2013-06-04 01:44:17 +02:00
DrawConsole ( & game ) ;
2016-06-27 21:21:59 +02:00
if ( al_get_time ( ) - t > = 1 / 60.0 ) {
al_flip_display ( ) ;
}
t = al_get_time ( ) ;
2016-06-27 21:20:02 +02:00
tmp - > data = ( * tmp - > api . Gamestate_Load ) ( & game , & progress ) ; // feel free to replace "progress" with empty function if you want to compile with clang
2012-12-28 00:00:37 +01:00
loaded + + ;
2012-12-26 02:25:56 +01:00
tmp - > loaded = true ;
tmp - > pending_load = false ;
}
2015-03-15 05:38:15 +01:00
al_start_timer ( game . _priv . timer ) ;
2012-12-25 00:22:03 +01:00
}
2012-12-26 13:38:15 +01:00
2012-12-27 21:05:28 +01:00
tmp = tmp - > next ;
}
bool gameActive = false ;
tmp = game . _priv . gamestates ;
while ( tmp ) {
2016-06-27 21:20:02 +02:00
if ( ( tmp - > pending_start ) & & ( ! tmp - > started ) & & ( tmp - > loaded ) ) {
2012-12-27 21:05:28 +01:00
PrintConsole ( & game , " Starting gamestate \" %s \" ... " , tmp - > name ) ;
2015-03-15 05:38:15 +01:00
al_stop_timer ( game . _priv . timer ) ;
2012-12-27 21:05:28 +01:00
( * tmp - > api . Gamestate_Start ) ( & game , tmp - > data ) ;
2015-03-15 05:38:15 +01:00
al_start_timer ( game . _priv . timer ) ;
2012-12-27 21:05:28 +01:00
tmp - > started = true ;
tmp - > pending_start = false ;
}
2012-12-26 13:38:15 +01:00
2012-12-27 21:05:28 +01:00
if ( ( tmp - > started ) | | ( tmp - > pending_start ) | | ( tmp - > pending_load ) ) gameActive = true ;
2012-12-25 00:22:03 +01:00
tmp = tmp - > next ;
}
2012-12-24 19:41:12 +01:00
2012-12-26 13:38:15 +01:00
if ( ! gameActive ) {
PrintConsole ( & game , " No gamestates left, exiting... " ) ;
break ;
}
2012-12-24 19:41:12 +01:00
DrawGamestates ( & game ) ;
2012-02-25 22:19:12 +01:00
DrawConsole ( & game ) ;
al_flip_display ( ) ;
2012-12-25 00:22:03 +01:00
redraw = false ;
2012-12-24 19:41:12 +01:00
2012-09-26 03:19:10 +02:00
} else {
2012-12-24 19:41:12 +01:00
al_wait_for_event ( game . _priv . event_queue , & ev ) ;
if ( ( ev . type = = ALLEGRO_EVENT_TIMER ) & & ( ev . timer . source = = game . _priv . timer ) ) {
LogicGamestates ( & game ) ;
2012-12-25 00:22:03 +01:00
redraw = true ;
2012-09-26 03:19:10 +02:00
}
else if ( ev . type = = ALLEGRO_EVENT_DISPLAY_CLOSE ) {
break ;
}
2016-06-27 21:20:02 +02:00
else if ( ev . type = = ALLEGRO_EVENT_DISPLAY_FOUND ) {
SetupViewport ( & game ) ;
}
# ifdef ALLEGRO_MACOSX
2012-12-27 01:02:47 +01:00
else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( ev . keyboard . keycode = = 104 ) ) { //TODO: report to upstream
2016-06-27 21:20:02 +02:00
# else
2012-12-27 01:02:47 +01:00
else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( ev . keyboard . keycode = = ALLEGRO_KEY_TILDE ) ) {
2016-06-27 21:20:02 +02:00
# endif
2012-12-27 01:02:47 +01:00
game . _priv . showconsole = ! game . _priv . showconsole ;
}
else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( game . config . debug ) & & ( ev . keyboard . keycode = = ALLEGRO_KEY_F1 ) ) {
int i ;
for ( i = 0 ; i < 512 ; i + + ) {
LogicGamestates ( & game ) ;
2012-09-26 03:19:10 +02:00
}
2012-12-27 01:02:47 +01:00
game . _priv . showconsole = true ;
PrintConsole ( & game , " DEBUG: 512 frames skipped... " ) ;
} else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( game . config . debug ) & & ( ev . keyboard . keycode = = ALLEGRO_KEY_F10 ) ) {
double speed = ALLEGRO_BPS_TO_SECS ( al_get_timer_speed ( game . _priv . timer ) ) ; // inverting
speed - = 10 ;
if ( speed < 10 ) speed = 10 ;
al_set_timer_speed ( game . _priv . timer , ALLEGRO_BPS_TO_SECS ( speed ) ) ;
game . _priv . showconsole = true ;
PrintConsole ( & game , " DEBUG: Gameplay speed: %.2fx " , speed / 60.0 ) ;
} else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( game . config . debug ) & & ( ev . keyboard . keycode = = ALLEGRO_KEY_F11 ) ) {
double speed = ALLEGRO_BPS_TO_SECS ( al_get_timer_speed ( game . _priv . timer ) ) ; // inverting
speed + = 10 ;
if ( speed > 600 ) speed = 600 ;
al_set_timer_speed ( game . _priv . timer , ALLEGRO_BPS_TO_SECS ( speed ) ) ;
game . _priv . showconsole = true ;
PrintConsole ( & game , " DEBUG: Gameplay speed: %.2fx " , speed / 60.0 ) ;
} else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( game . config . debug ) & & ( ev . keyboard . keycode = = ALLEGRO_KEY_F12 ) ) {
ALLEGRO_PATH * path = al_get_standard_path ( ALLEGRO_USER_DOCUMENTS_PATH ) ;
char filename [ 255 ] = { } ;
2016-06-27 21:21:59 +02:00
snprintf ( filename , 255 , " Mediator_%ld_%ld.png " , time ( NULL ) , clock ( ) ) ;
2012-12-27 01:02:47 +01:00
al_set_path_filename ( path , filename ) ;
al_save_bitmap ( al_path_cstr ( path , ALLEGRO_NATIVE_PATH_SEP ) , al_get_backbuffer ( game . display ) ) ;
PrintConsole ( & game , " Screenshot stored in %s " , al_path_cstr ( path , ALLEGRO_NATIVE_PATH_SEP ) ) ;
al_destroy_path ( path ) ;
2016-06-27 21:21:59 +02:00
} else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( ev . keyboard . keycode = = ALLEGRO_KEY_SPACE ) ) {
game . mediator . pause = ! game . mediator . pause ;
if ( game . mediator . pause ) {
PauseGamestates ( & game ) ;
} else {
ResumeGamestates ( & game ) ;
}
2012-12-27 01:02:47 +01:00
} else {
2016-06-27 21:21:59 +02:00
if ( ! game . mediator . pause ) {
EventGamestates ( & game , & ev ) ;
}
2012-09-26 03:19:10 +02:00
}
2012-02-25 22:26:31 +01:00
}
}
2012-02-29 23:00:59 +01:00
game . shuttingdown = true ;
2012-12-24 19:41:12 +01:00
2012-12-26 15:15:02 +01:00
// in case of restart
2012-12-26 13:38:15 +01:00
struct Gamestate * tmp = game . _priv . gamestates ;
while ( tmp ) {
if ( tmp - > started ) {
2012-12-26 15:15:02 +01:00
PrintConsole ( & game , " Stopping gamestate \" %s \" ... " , tmp - > name ) ;
2012-12-26 13:38:15 +01:00
( * tmp - > api . Gamestate_Stop ) ( & game , tmp - > data ) ;
tmp - > started = false ;
}
if ( tmp - > loaded ) {
2012-12-26 15:15:02 +01:00
PrintConsole ( & game , " Unloading gamestate \" %s \" ... " , tmp - > name ) ;
2012-12-26 13:38:15 +01:00
( * tmp - > api . Gamestate_Unload ) ( & game , tmp - > data ) ;
dlclose ( tmp - > handle ) ;
tmp - > loaded = false ;
}
tmp = tmp - > next ;
}
2012-02-25 22:26:31 +01:00
al_clear_to_color ( al_map_rgb ( 0 , 0 , 0 ) ) ;
PrintConsole ( & game , " Shutting down... " ) ;
2012-02-17 13:25:06 +01:00
DrawConsole ( & game ) ;
al_flip_display ( ) ;
2012-02-25 22:26:31 +01:00
al_rest ( 0.1 ) ;
2012-12-28 03:46:27 +01:00
( * game . _priv . loading . Unload ) ( & game , game . _priv . loading . data ) ;
2012-12-24 19:41:12 +01:00
al_destroy_timer ( game . _priv . timer ) ;
Console_Unload ( & game ) ;
2012-02-25 22:26:31 +01:00
al_destroy_display ( game . display ) ;
2012-12-24 19:41:12 +01:00
al_destroy_event_queue ( game . _priv . event_queue ) ;
2012-03-05 11:13:08 +01:00
al_destroy_mixer ( game . audio . fx ) ;
al_destroy_mixer ( game . audio . music ) ;
2012-03-05 21:07:42 +01:00
al_destroy_mixer ( game . audio . mixer ) ;
2012-03-13 12:42:28 +01:00
al_destroy_voice ( game . audio . v ) ;
2012-02-25 22:26:31 +01:00
al_uninstall_audio ( ) ;
2012-12-24 19:41:12 +01:00
DeinitConfig ( & game ) ;
2012-12-26 02:25:56 +01:00
al_uninstall_system ( ) ;
2012-12-24 19:41:12 +01:00
al_shutdown_ttf_addon ( ) ;
al_shutdown_font_addon ( ) ;
2012-03-08 22:21:02 +01:00
if ( game . restart ) {
2012-09-03 02:25:32 +02:00
# ifdef ALLEGRO_MACOSX
return _al_mangled_main ( argc , argv ) ;
# else
return main ( argc , argv ) ;
# endif
2012-03-08 22:21:02 +01:00
}
2012-02-25 22:26:31 +01:00
return 0 ;
2012-02-15 23:57:06 +01:00
}