示例#1
0
void inicializa_jogo( Jogo* jogo, int x, int y, int largura, int altura ) {
   ALLEGRO_DISPLAY *display = NULL;

   al_set_new_window_position( x, y );
  
   if(!al_init()) {
      fprintf(stderr, "Falha ao inicializar o Allegro!\n");
      exit(-1);
   }
   
   if (!al_init_primitives_addon()) {
     fprintf(stderr, "Falha ao inicializar add-on de primitivas.\n");
     exit(-1);
   }
   
   if (!al_init_image_addon()) {
     fprintf(stderr, "Falha ao inicializar add-on de imagens.\n");
     exit(-1);
   }
   
   display = al_create_display( largura, altura );
   if(!display) {
      fprintf(stderr, "Falha ao criar o display!\n");
      exit(-1);
   }
   
   if (!al_install_keyboard())
    {
        fprintf(stderr, "Falha ao inicializar o teclado.\n");
        exit(-1);
    }
    
    jogo->fila_eventos = al_create_event_queue();
    if (!jogo->fila_eventos)
    {
        fprintf(stderr, "Falha ao criar fila de eventos.\n");
        exit(-1);
    }
   
   jogo->altura = altura;
   jogo->largura = largura;
      
   for( int i = 0, x = (jogo->largura / 4 - TAMANHO_BUNKER) / 2; 
        i < 4; 
        i++, x += jogo->largura / 4 ) {
     inicializa_bunker( &jogo->bunker[i], x, 360 );
   } 
   
   inicializa_tanque( &jogo->tanque, jogo->largura/2, 475, 0, jogo->largura );

   inicializa_zbuffer( &jogo->zbuffer, display, jogo->altura, jogo->largura, 
                       jogo->bunker, &jogo->tanque );

  al_register_event_source(jogo->fila_eventos, al_get_keyboard_event_source());
}
示例#2
0
void init_event_things(ALLEGRO_TIMER* &timer, ALLEGRO_EVENT_QUEUE* &queue) {
    al_set_new_window_position(window_x, window_y);
    display = al_create_display(scr_w, scr_h);
    timer = al_create_timer(1.0 / game_fps);
    
    queue = al_create_event_queue();
    al_register_event_source(queue, al_get_mouse_event_source());
    al_register_event_source(queue, al_get_keyboard_event_source());
    al_register_event_source(queue, al_get_joystick_event_source());
    al_register_event_source(queue, al_get_display_event_source(display));
    al_register_event_source(queue, al_get_timer_event_source(timer));
}
示例#3
0
void init(int width, int height) {
	danmakux.width = width;
	danmakux.height = height;

	if (!al_init()) al_show_native_message_box(display, "Error", "Error", "Failed to initialize Allegro!", NULL, ALLEGRO_MESSAGEBOX_ERROR);
	
	if (!al_install_keyboard()) al_show_native_message_box(display, "Error", "Error", "Failed to install keyboard!", NULL, ALLEGRO_MESSAGEBOX_ERROR);

	if (!al_install_audio()) al_show_native_message_box(display, "Error", "Error", "Failed to install audio!", NULL, ALLEGRO_MESSAGEBOX_ERROR);
	
	if (!al_reserve_samples(10)) al_show_native_message_box(display, "Error", "Error", "Failed to reserve samples!", NULL, ALLEGRO_MESSAGEBOX_ERROR);

	timer = al_create_timer(1.0 / FPS);
	if (!timer) al_show_native_message_box(display, "Error", "Error", "Failed to create timer!", NULL, ALLEGRO_MESSAGEBOX_ERROR);
	
	al_set_new_display_flags(ALLEGRO_WINDOWED);
	al_set_new_window_position(700, 200);
	display = al_create_display(danmakux.width, danmakux.height);
	if (!display) al_show_native_message_box(display, "Error", "Error", "Failed to create display!", NULL, ALLEGRO_MESSAGEBOX_ERROR);

	event_queue = al_create_event_queue();
	if (!event_queue) al_show_native_message_box(display, "Error", "Error", "Failed to create event queue!", NULL, ALLEGRO_MESSAGEBOX_ERROR);

	al_register_event_source(event_queue, al_get_keyboard_event_source());
	al_register_event_source(event_queue, al_get_timer_event_source(timer));
	al_register_event_source(event_queue, al_get_display_event_source(display));

	redraw = false;
	danmakux.fireBomb = false;
	danmakux.lives = 2;
	danmakux.bombsRemain = 2;
	danmakux.weaponLevel = 1;
	danmakux.done = false;
	danmakux.state_menu = true;
	danmakux.state_paused = false;
	danmakux.state_playing = false;
	danmakux.state_dialog = false;
	danmakux.menuChoice = 0;
	danmakux.currentLevel = 1;
	danmakux.player = &playerset;
	UI = danmakux.resources.get_image("ui.png");

	al_start_timer(timer);
	loadMenu("mainmenu");
	/*danmakux.state_menu = false;
							danmakux.state_playing = true;
							danmakux.state_paused = false;
							loadLevel("level1");*/
	al_play_sample(danmakux.bgm, 1.0, 0.0, 1.0, ALLEGRO_PLAYMODE_LOOP, NULL);
}
示例#4
0
/*
 * The window must be created in the same thread that
 * runs the message loop.
 */
static void display_thread_proc(void *arg)
{
   WGL_DISPLAY_PARAMETERS *ndp = arg;
   ALLEGRO_DISPLAY *disp = (ALLEGRO_DISPLAY*)ndp->display;
   ALLEGRO_DISPLAY_WGL *wgl_disp = (void*)disp;
   ALLEGRO_DISPLAY_WIN *win_disp = (void*)disp;
   MSG msg;

   al_set_new_window_position(ndp->window_x, ndp->window_y);

   /* So that we can call the functions using TLS from this thread. */
   al_set_new_display_flags(disp->flags);
   
   if (disp->flags & ALLEGRO_FULLSCREEN) {
      if (!change_display_mode(disp)) {
         win_disp->thread_ended = true;
         destroy_display_internals(wgl_disp);
         SetEvent(ndp->AckEvent);
         return;
      }
   }
   else if (disp->flags & ALLEGRO_FULLSCREEN_WINDOW) {
      ALLEGRO_MONITOR_INFO mi;
      int adapter = win_disp->adapter;
      al_get_monitor_info(adapter, &mi);
      win_disp->toggle_w = disp->w;
      win_disp->toggle_h = disp->h;
      disp->w = mi.x2 - mi.x1;
      disp->h = mi.y2 - mi.y1;
   }
   else {
      win_disp->toggle_w = disp->w;
      win_disp->toggle_h = disp->h;
   }

   win_disp->window = _al_win_create_window(disp, disp->w, disp->h, disp->flags);

   if (!win_disp->window) {
      win_disp->thread_ended = true;
      destroy_display_internals(wgl_disp);
      SetEvent(ndp->AckEvent);
      return;
   }

   /* FIXME: can't _al_win_create_window() do this? */
   if ((disp->flags & ALLEGRO_FULLSCREEN) ||
         (disp->flags & ALLEGRO_FULLSCREEN_WINDOW)) {
      RECT rect;
      rect.left = 0;
      rect.right = disp->w;
      rect.top  = 0;
      rect.bottom = disp->h;
      SetWindowPos(win_disp->window, 0, rect.left, rect.top,
             rect.right - rect.left, rect.bottom - rect.top,
             SWP_NOZORDER | SWP_FRAMECHANGED);
   }
   
   if (disp->flags & ALLEGRO_FULLSCREEN_WINDOW) {
      bool frameless = true;
      _al_win_set_window_frameless(disp, win_disp->window, disp->w, disp->h, frameless);
   }

   /* Yep, the following is really needed sometimes. */
   /* ... Or is it now that we have dumped DInput? */
   /* <rohannessian> Win98/2k/XP's window forground rules don't let us
    * make our window the topmost window on launch. This causes issues on 
    * full-screen apps, as DInput loses input focus on them.
    * We use this trick to force the window to be topmost, when switching
    * to full-screen only. Note that this only works for Win98 and greater.
    * Win95 will ignore our SystemParametersInfo() calls.
    * 
    * See http://support.microsoft.com:80/support/kb/articles/Q97/9/25.asp
    * for details.
    */
   {
      DWORD lock_time;
      HWND wnd = win_disp->window;

#define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000
#define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001
      if (disp->flags & ALLEGRO_FULLSCREEN) {
         SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,
               0, (LPVOID)&lock_time, 0);
         SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,
               0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
      }

      ShowWindow(wnd, SW_SHOWNORMAL);
      SetForegroundWindow(wnd);
      /* In some rare cases, it doesn't seem to work without the loop. And we
       * absolutely need this to succeed, else we trap the user in a
       * fullscreen window without input.
       */
      while (GetForegroundWindow() != wnd) {
         al_rest(0.01);
         SetForegroundWindow(wnd);
      }
      UpdateWindow(wnd);

      if (disp->flags & ALLEGRO_FULLSCREEN) {
         SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,
              0, (LPVOID)(DWORD)lock_time, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
      }
#undef SPI_GETFOREGROUNDLOCKTIMEOUT
#undef SPI_SETFOREGROUNDLOCKTIMEOUT
   }

#if 0
   if (disp->flags & ALLEGRO_FULLSCREEN && al_is_mouse_installed()) {
      RAWINPUTDEVICE rid[1];
      rid[0].usUsagePage = 0x01; 
      rid[0].usUsage = 0x02; 
      rid[0].dwFlags = RIDEV_NOLEGACY;
      rid[0].hwndTarget = 0;
      if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == FALSE) {
          ALLEGRO_ERROR(
             "Failed to init mouse. %s\n", get_error_desc(GetLastError()));
      }
   }
#endif

   /* get the device context of our window */
   wgl_disp->dc = GetDC(win_disp->window);

   win_disp->thread_ended = false;
   win_disp->end_thread = false;
   ndp->init_failed = false;
   SetEvent(ndp->AckEvent);

   while (!win_disp->end_thread) {
      /* get a message from the queue */
      if (GetMessage(&msg, NULL, 0, 0) != 0)
         DispatchMessage(&msg);
      else
         break;                 /* WM_QUIT received or error (GetMessage returned -1)  */
   }

   if (wgl_disp->glrc) {
      wglDeleteContext(wgl_disp->glrc);
      wgl_disp->glrc = NULL;
   }
   if (wgl_disp->dc) {
      ReleaseDC(win_disp->window, wgl_disp->dc);
      wgl_disp->dc = NULL;
   }

   if (disp->flags & ALLEGRO_FULLSCREEN && !_wgl_do_not_change_display_mode) {
      ChangeDisplaySettings(NULL, 0);
   }

   if (win_disp->window) {
      DestroyWindow(win_disp->window);
      win_disp->window = NULL;
   }

   ALLEGRO_INFO("wgl display thread exits\n");
   win_disp->thread_ended = true;
}
示例#5
0
int main(int argc, char **argv)
{
   ALLEGRO_DISPLAY *displays[2];
   ALLEGRO_MONITOR_INFO *info;
   int adapter_count;
   int x, y;
   ALLEGRO_FONT *myfont;
   ALLEGRO_EVENT_QUEUE *events;
   ALLEGRO_EVENT event;
   int i;

   (void)argc;
   (void)argv;

   srand(time(NULL));

   if (!al_init()) {
      abort_example("Could not init Allegro.\n");
   }

   al_install_mouse();
   al_init_font_addon();
   al_init_image_addon();

   adapter_count = al_get_num_video_adapters();

   info = malloc(adapter_count * sizeof(ALLEGRO_MONITOR_INFO));

   for (i = 0; i < adapter_count; i++) {
      al_get_monitor_info(i, &info[i]);
   }

   x = ((info[0].x2 - info[0].x1) / 3) - (W / 2);
   y = ((info[0].y2 - info[0].y1) / 2) - (H / 2);

   al_set_new_window_position(x, y);

   displays[0] = al_create_display(W, H);

   x *= 2;
   al_set_new_window_position(x, y);

   displays[1] = al_create_display(W, H);

   if (!displays[0] || !displays[1]) {
      abort_example("Could not create displays.\n");
   }

   al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
   myfont = al_load_font("data/fixed_font.tga", 0, 0);
   if (!myfont) {
      abort_example("Could not load font.\n");
   }

   events = al_create_event_queue();
   al_register_event_source(events, al_get_mouse_event_source());
   al_register_event_source(events, al_get_display_event_source(displays[0]));
   al_register_event_source(events, al_get_display_event_source(displays[1]));

   for (;;) {
      for (i = 0; i < 2; i++) {
        al_set_target_backbuffer(displays[i]);
        al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
        if (i == 0)
           al_clear_to_color(al_map_rgb(255, 0, 255));
        else
           al_clear_to_color(al_map_rgb(155, 255, 0));
        al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
        al_draw_textf(myfont, al_map_rgb(0, 0, 0), 50, 50, ALLEGRO_ALIGN_CENTRE, "Click me..");
        al_flip_display();
      }

      if (al_wait_for_event_timed(events, &event, 1)) {
         if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
            break;
         }
         else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
            int a = rand() % adapter_count;
            int w = info[a].x2 - info[a].x1;
            int h = info[a].y2 - info[a].y1;
            int margin = 20;
            x = margin + info[a].x1 + (rand() % (w - W - margin));
            y = margin + info[a].y1 + (rand() % (h - H - margin));
            al_set_window_position(event.mouse.display, x, y);
         }
      }
   }

   al_destroy_event_queue(events);

   al_destroy_display(displays[0]);
   al_destroy_display(displays[1]);

   free(info);

   return 0;
}
void AllegroFlasher::positionWindow(int x, int y)
{
    al_set_new_window_position(x, y);
}
示例#7
0
文件: main.c 项目: dos1/bttbw
int main(int argc, char **argv){
	signal(SIGSEGV, derp);

	srand(time(NULL));

	al_set_org_name("Super Derpy");
    al_set_app_name("Back to the Browser Wars");

       #ifdef ALLEGRO_MACOSX
       char exe_path[MAXPATHLEN];
       char link_path[MAXPATHLEN];

       uint32_t size = sizeof(exe_path);
       _NSGetExecutablePath(exe_path, &size);
       realpath(exe_path, link_path);
       chdir(link_path);
       #endif

	if(!al_init()) {
		fprintf(stderr, "failed to initialize allegro!\n");
		return -1;
	}

	struct Game game;

	InitConfig(&game);

	game._priv.fps_count.frames_done = 0;
	game._priv.fps_count.fps = 0;
	game._priv.fps_count.old_time = 0;

	game._priv.font_bsod = NULL;
	game._priv.console = NULL;

	game.config.fullscreen = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "fullscreen", "0"));
	game.config.music = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "music", "10"));
	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"));
	game.config.width = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "width", "1280"));
	if (game.config.width<320) game.config.width=320;
	game.config.height = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "height", "720"));
	if (game.config.height<180) game.config.height=180;

	if(!al_init_image_addon()) {
		fprintf(stderr, "failed to initialize image addon!\n");
		/*al_show_native_message_box(display, "Error", "Error", "Failed to initialize al_init_image_addon!",
															 NULL, ALLEGRO_MESSAGEBOX_ERROR);*/
		return -1;
	}

	if(!al_init_acodec_addon()){
		fprintf(stderr, "failed to initialize audio codecs!\n");
		return -1;
	}

	if(!al_install_audio()){
		fprintf(stderr, "failed to initialize audio!\n");
		return -1;
	}

	if(!al_install_keyboard()){
		fprintf(stderr, "failed to initialize keyboard!\n");
		return -1;
	}

	if(!al_init_primitives_addon()){
		fprintf(stderr, "failed to initialize primitives!\n");
		return -1;
	}

    if(!al_install_mouse()) {
        fprintf(stderr, "failed to initialize the mouse!\n");
        return -1;
    }
	
	al_init_font_addon();

	if(!al_init_ttf_addon()){
		fprintf(stderr, "failed to initialize fonts!\n");
		return -1;
	}

	if (game.config.fullscreen) al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW);
	else al_set_new_display_flags(ALLEGRO_WINDOWED);
	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);
#ifdef ALLEGRO_WINDOWS
	al_set_new_window_position(20, 40); // workaround nasty Windows bug with window being created off-screen
#endif

	game.display = al_create_display(game.config.width, game.config.height);
	if(!game.display) {
		fprintf(stderr, "failed to create display!\n");
		return -1;
	}

	SetupViewport(&game);

	PrintConsole(&game, "Viewport %dx%d", game.viewport.width, game.viewport.height);

    ALLEGRO_BITMAP *icon = al_load_bitmap(GetDataFilePath(&game, "icons/bttbw.png"));
	al_set_window_title(game.display, "Back to the Browser Wars");
	al_set_display_icon(game.display, icon);
	al_destroy_bitmap(icon);

    if (game.config.fullscreen) al_hide_mouse_cursor(game.display);
    al_inhibit_screensaver(true);

	al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR);

	game._priv.gamestates = NULL;

	game._priv.event_queue = al_create_event_queue();
	if(!game._priv.event_queue) {
		FatalError(&game, true, "Failed to create event queue.");
		al_destroy_display(game.display);
		return -1;
	}

	game.audio.v = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2);
	game.audio.mixer = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2);
	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);
	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);
	al_attach_mixer_to_mixer(game.audio.fx, game.audio.mixer);
	al_attach_mixer_to_mixer(game.audio.music, game.audio.mixer);
	al_attach_mixer_to_mixer(game.audio.voice, game.audio.mixer);
	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);

	al_register_event_source(game._priv.event_queue, al_get_display_event_source(game.display));
    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());

	game._priv.showconsole = game.config.debug;

	al_clear_to_color(al_map_rgb(0,0,0));
	game._priv.timer = al_create_timer(ALLEGRO_BPS_TO_SECS(60)); // logic timer
	if(!game._priv.timer) {
		FatalError(&game, true, "Failed to create logic timer.");
		return -1;
	}
	al_register_event_source(game._priv.event_queue, al_get_timer_event_source(game._priv.timer));

	al_flip_display();
	al_start_timer(game._priv.timer);

	setlocale(LC_NUMERIC, "C");

	game.shuttingdown = false;
	game.restart = false;

    game.mediator.lives = 3;
    game.mediator.score = 0;
    game.mediator.modificator = 1;

    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");

	char* gamestate = strdup("dosowisko"); // FIXME: don't hardcore gamestate

	int c;
	while ((c = getopt (argc, argv, "l:s:")) != -1)
		switch (c) {
			case 'l':
				free(gamestate);
				gamestate = strdup("levelX");
				gamestate[5] = optarg[0];
				break;
			case 's':
				free(gamestate);
				gamestate = strdup(optarg);
				break;
		}

	LoadGamestate(&game, gamestate);
    game._priv.gamestates->showLoading = false; // we have only one gamestate right now
    StartGamestate(&game, gamestate);
	free(gamestate);

	char libname[1024] = {};
    snprintf(libname, 1024, "libsuperderpy-%s-loading" LIBRARY_EXTENTION, "bttbw");
	void *handle = dlopen(libname, RTLD_NOW);
	if (!handle) {
		FatalError(&game, true, "Error while initializing loading screen %s", dlerror());
		exit(1);
	} else {

		#define GS_LOADINGERROR FatalError(&game, true, "Error on resolving loading symbol: %s", dlerror()); exit(1);

		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; }
	}

	game._priv.loading.data = (*game._priv.loading.Load)(&game);

	bool redraw = false;

	while(1) {
		ALLEGRO_EVENT ev;
		if (redraw && al_is_event_queue_empty(game._priv.event_queue)) {

			struct Gamestate *tmp = game._priv.gamestates;
			int toLoad = 0, loaded = 0;

			// FIXME: move to function
			// TODO: support dependences
			while (tmp) {
				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;
				}

				if ((tmp->pending_load) && (!tmp->loaded)) toLoad++;
				tmp=tmp->next;
			}

			tmp = game._priv.gamestates;
			// FIXME: move to function
			// TODO: support dependences

			double t = -1;

			while (tmp) {
				if ((tmp->pending_load) && (tmp->loaded)) {
					PrintConsole(&game, "Unloading gamestate \"%s\"...", tmp->name);
					al_stop_timer(game._priv.timer);
					tmp->loaded = false;
					tmp->pending_load = false;
					(*tmp->api.Gamestate_Unload)(&game, tmp->data);
					dlclose(tmp->handle);
					tmp->handle = NULL;
					al_start_timer(game._priv.timer);
				} else if ((tmp->pending_load) && (!tmp->loaded)) {
					PrintConsole(&game, "Loading gamestate \"%s\"...", tmp->name);
					al_stop_timer(game._priv.timer);
					// TODO: take proper game name
					char libname[1024];
                    snprintf(libname, 1024, "libsuperderpy-%s-%s" LIBRARY_EXTENTION, "bttbw", tmp->name);
					tmp->handle = dlopen(libname,RTLD_NOW);
					if (!tmp->handle) {
						//PrintConsole(&game, "Error while loading gamestate \"%s\": %s", tmp->name, dlerror());
						FatalError(&game, false, "Error while loading gamestate \"%s\": %s", tmp->name, dlerror());

						tmp->pending_load = false;
						tmp->pending_start = false;
					} else {

#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;

						if (!(tmp->api.Gamestate_Draw = dlsym(tmp->handle, "Gamestate_Draw"))) { GS_ERROR; }
						if (!(tmp->api.Gamestate_Logic = dlsym(tmp->handle, "Gamestate_Logic"))) { GS_ERROR; }

						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; }

						if (!(tmp->api.Gamestate_ProcessEvent = dlsym(tmp->handle, "Gamestate_ProcessEvent"))) { GS_ERROR; }
						if (!(tmp->api.Gamestate_Reload = dlsym(tmp->handle, "Gamestate_Reload"))) { GS_ERROR; }

						if (!(tmp->api.Gamestate_ProgressCount = dlsym(tmp->handle, "Gamestate_ProgressCount"))) { GS_ERROR; }

						int p = 0;

						void progress(struct Game *game) {
							p++;
							DrawGamestates(game);
							float progress = ((p / (*(tmp->api.Gamestate_ProgressCount) ? (float)*(tmp->api.Gamestate_ProgressCount) : 1))/(float)toLoad)+(loaded/(float)toLoad);
							if (game->config.debug) PrintConsole(game, "[%s] Progress: %d% (%d/%d)", tmp->name, (int)(progress*100), p, *(tmp->api.Gamestate_ProgressCount));
							if (tmp->showLoading) (*game->_priv.loading.Draw)(game, game->_priv.loading.data, progress);
							DrawConsole(game);
							if (al_get_time() - t >= 1/60.0) {
								al_flip_display();
							}
							t = al_get_time();
						}

						t = al_get_time();

						// initially draw loading screen with empty bar
						DrawGamestates(&game);
						if (tmp->showLoading) {
                            (*game._priv.loading.Draw)(&game, game._priv.loading.data, loaded/(float)toLoad);
						}
						DrawConsole(&game);
						if (al_get_time() - t >= 1/60.0) {
							al_flip_display();
						}
						t = al_get_time();
						tmp->data = (*tmp->api.Gamestate_Load)(&game, &progress); // feel free to replace "progress" with empty function if you want to compile with clang
						loaded++;

						tmp->loaded = true;
						tmp->pending_load = false;
					}
					al_start_timer(game._priv.timer);
				}

				tmp=tmp->next;
			}

			bool gameActive = false;
			tmp=game._priv.gamestates;

			while (tmp) {

				if ((tmp->pending_start) && (!tmp->started) && (tmp->loaded)) {
					PrintConsole(&game, "Starting gamestate \"%s\"...", tmp->name);
					al_stop_timer(game._priv.timer);
					(*tmp->api.Gamestate_Start)(&game, tmp->data);
					al_start_timer(game._priv.timer);
					tmp->started = true;
					tmp->pending_start = false;
				}

				if ((tmp->started) || (tmp->pending_start) || (tmp->pending_load)) gameActive = true;
				tmp=tmp->next;
			}

			if (!gameActive) {
				PrintConsole(&game, "No gamestates left, exiting...");
				break;
			}

			DrawGamestates(&game);
			DrawConsole(&game);
			al_flip_display();
			redraw = false;

		} else {