// changing levels within a unit
void Host_Changelevel2_f (void)
{
    char	level[MAX_QPATH];
    char	_startspot[MAX_QPATH];
    char	*startspot;

    if (Cmd_Argc() < 2)
    {
        Con_Printf ("changelevel2 <levelname> : continue game on a new level in the unit\n");
        return;
    }
    if (!sv.active || cls.demoplayback)
    {
        Con_Printf ("Only the server may changelevel\n");
        return;
    }

    strcpy (level, Cmd_Argv(1));
    if (Cmd_Argc() == 2)
        startspot = NULL;
    else
    {
        strcpy (_startspot, Cmd_Argv(2));
        startspot = _startspot;
    }

    SV_SaveSpawnparms ();

    // save the current level's state
    SaveGamestate ();

    // try to restore the new level
    if (LoadGamestate (level, startspot))
        SV_SpawnServer (level, startspot);
}
Exemple #2
0
/*
==================
Host_Restart_f

Restarts the current server for a dead player
==================
*/
static void Host_Restart_f (void)
{
	char	mapname[MAX_QPATH];
	char	startspot[MAX_QPATH];

	if (cls.demoplayback || !sv.active)
		return;

	if (cmd_source != src_command)
		return;

	q_strlcpy (mapname, sv.name, sizeof(mapname));	// mapname gets cleared in spawnserver
	q_strlcpy (startspot, sv.startspot, sizeof(startspot));

	if (Cmd_Argc() == 2 && q_strcasecmp(Cmd_Argv(1),"restore") == 0)
	{
		if (LoadGamestate(mapname, startspot, 3) != 0)
		{
			SV_SpawnServer (mapname, startspot);
			if (!sv.active)
				Host_Error ("%s: cannot restart map %s", __thisfunc__, mapname);
			RestoreClients (0);
		}
	}
	else
	{
		SV_SpawnServer (mapname, startspot);
		if (!sv.active)
			Host_Error ("%s: cannot restart map %s", __thisfunc__, mapname);
	}
}
Exemple #3
0
/*
==================
Host_Restart_f

Restarts the current server for a dead player
==================
*/
void Host_Restart_f (void)
{
	char	mapname[MAX_QPATH];
#if 666
	char	startspot[MAX_QPATH];
#endif

	if (cls.demoplayback || !sv.active)
		return;

	if (cmd_source != src_command)
		return;
	strcpy (mapname, sv.name);	// must copy out, because it gets cleared
								// in sv_spawnserver
#if 666
	strcpy(startspot, sv.startspot);
	// try to restore the new level
	if (LoadGamestate (mapname, startspot))
	SV_SpawnServer (mapname, startspot);
	else
	SV_SpawnServer (mapname, NULL);
#else
	SV_SpawnServer (mapname);
#endif
}
Exemple #4
0
void Gamestate_Logic(struct Game *game, struct MenuResources* data) {

	data->title_pos += 0.05;

	if (data->starting) {
		data->monster_pos -= 6;

		if (data->monster_pos < -202) {
			data->starting = false;
			LoadGamestate(game, "info");
			LoadGamestate(game, "level");
			StartGamestate(game, "info");
			StopGamestate(game, "menu");
		}

	} else {
		data->monster_pos += 6;
		if (data->monster_pos > 0) {
			data->monster_pos = 0;
		}
	}

	if (data->menustate == MENUSTATE_HIDDEN) {
		data->screen_pos -= (180 - data->screen_pos) / 4 + 1;
		if (data->screen_pos < 0) {
			data->screen_pos = 0;
			data->invisible = false;
		}
	} else {
		data->screen_pos += (data->screen_pos) / 4 + 1;
		if (data->screen_pos > 180) {
			data->screen_pos = 180;
		}
	}

}
Exemple #5
0
/*
==================
Host_Changelevel2_f

changing levels within a unit
==================
*/
static void Host_Changelevel2_f (void)
{
	char	level[MAX_QPATH];
	char	_startspot[MAX_QPATH];
	char	*startspot;

	if (Cmd_Argc() < 2)
	{
		Con_Printf ("changelevel2 <levelname> : continue game on a new level in the unit\n");
		return;
	}
	if (!sv.active || cls.demoplayback)
	{
		Con_Printf ("Only the server may changelevel\n");
		return;
	}

	q_snprintf (level, sizeof(level), "maps/%s.bsp", Cmd_Argv(1));
	if (!FS_FileExists(level, NULL))
		Host_Error ("%s: cannot find map %s", __thisfunc__, level);

	q_strlcpy (level, Cmd_Argv(1), sizeof(level));
	if (Cmd_Argc() == 2)
		startspot = NULL;
	else
	{
		q_strlcpy (_startspot, Cmd_Argv(2), sizeof(_startspot));
		startspot = _startspot;
	}

	SV_SaveSpawnparms ();

	// save the current level's state
	old_svtime = sv.time;
	if (SaveGamestate(false) != 0)
		return;

	// try to restore the new level
	if (LoadGamestate(level, startspot, 0) != 0)
	{
		SV_SpawnServer (level, startspot);
		if (!sv.active)
			Host_Error ("%s: cannot run map %s", __thisfunc__, level);
		RestoreClients (0);
	}
}
Exemple #6
0
static void RestoreClients (int ClientsMode)
{
	int		i, j;
	edict_t		*ent;
	double		time_diff;

	if (LoadGamestate(NULL, NULL, 1) != 0)
		return;

/* O.S. -- mode 3 is only in response to the single player game "restart restore"
 * command issued by progs.dat::client.hc::respawn() function.  No level change,
 * just respawning in the same map with the same playtime from when clients.gip
 * was saved, therefore there _CANNOT_ be a time_diff.  See uhexen2 bug #2176023:
 * http://sourceforge.net/tracker/?group_id=124987&atid=701006&aid=2176023&func=detail
 */
	time_diff = (ClientsMode == 3) ? 0 : sv.time - old_svtime;

	for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++)
	{
		if (host_client->active)
		{
			ent = host_client->edict;

			//ent->v.colormap = NUM_FOR_EDICT(ent);
			ent->v.team = (host_client->colors & 15) + 1;
			ent->v.netname = PR_SetEngineString(host_client->name);
			ent->v.playerclass = host_client->playerclass;

			// copy spawn parms out of the client_t
			for (j = 0; j < NUM_SPAWN_PARMS; j++)
				sv_globals.parm[j] = host_client->spawn_parms[j];
			// call the spawn function
			*sv_globals.time = sv.time;
			*sv_globals.self = EDICT_TO_PROG(ent);
			G_FLOAT(OFS_PARM0) = time_diff;
			PR_ExecuteProgram (*sv_globals.ClientReEnter);
		}
	}

	SaveGamestate (true);
}
Exemple #7
0
/*
===============
Host_Loadgame_f
===============
*/
static void Host_Loadgame_f (void)
{
	FILE	*f;
	char		mapname[MAX_QPATH];
	float		playtime;
	char		str[32768];
	int		version;
	int		i, error_state;
	int		tempi;
	float		tempf;
	edict_t		*ent;
	float		spawn_parms[NUM_SPAWN_PARMS];

	if (cmd_source != src_command)
		return;

	if (Cmd_Argc() != 2)
	{
		Con_Printf ("load <savename> : load a game\n");
		return;
	}

	cls.demonum = -1;		// stop demo loop in case this fails
	CL_Disconnect();
	Host_RemoveGIPFiles(NULL);
	Key_SetDest (key_game);		// remove console or menu

	FS_MakePath_BUF (FS_USERDIR, &error_state, savename, sizeof(savename), Cmd_Argv(1));
	if (error_state)
	{
		Con_Printf ("%s: save directory name too long\n", __thisfunc__);
		return;
	}
	Con_Printf ("Loading game from %s...\n", savename);

	if (q_snprintf(savedest, sizeof(savedest), "%s/info.dat", savename) >= (int)sizeof(savedest))
	{
		Host_Error("%s: %d: string buffer overflow!", __thisfunc__, __LINE__);
		return;
	}

	f = fopen (savedest, "r");
	if (!f)
	{
		Con_Printf ("%s: ERROR: couldn't open savefile\n", __thisfunc__);
		return;
	}

	fscanf (f, "%i\n", &version);

	if (version != SAVEGAME_VERSION)
	{
		fclose (f);
		Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
		return;
	}
	fscanf (f, "%s\n", str);
	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		fscanf (f, "%f\n", &spawn_parms[i]);
// this silliness is so we can load 1.06 save files, which have float skill values
	fscanf (f, "%f\n", &tempf);
	current_skill = (int)(tempf + 0.1);
	Cvar_SetValue ("skill", current_skill);

	Cvar_Set ("deathmatch", "0");
	Cvar_Set ("coop", "0");
	Cvar_Set ("teamplay", "0");
	Cvar_Set ("randomclass", "0");

	fscanf (f, "%s\n", mapname);
	fscanf (f, "%f\n", &playtime);

	tempi = -1;
	fscanf (f, "%d\n", &tempi);
	if (tempi >= 1)
		svs.maxclients = tempi;

	tempf = -1;
	fscanf (f, "%f\n", &tempf);
	if (tempf >= 0)
		Cvar_SetValue ("deathmatch", tempf);

	tempf = -1;
	fscanf (f, "%f\n", &tempf);
	if (tempf >= 0)
		Cvar_SetValue ("coop", tempf);

	tempf = -1;
	fscanf (f, "%f\n", &tempf);
	if (tempf >= 0)
		Cvar_SetValue ("teamplay", tempf);

	tempf = -1;
	fscanf (f, "%f\n", &tempf);
	if (tempf >= 0)
		Cvar_SetValue ("randomclass", tempf);

	tempf = -1;
	fscanf (f, "%f\n", &tempf);
	if (tempf >= 0)
		Cvar_SetValue ("_cl_playerclass", tempf);

	// mission pack, objectives strings
	fscanf (f, "%u\n", &info_mask);
	fscanf (f, "%u\n", &info_mask2);

	fclose (f);

	Host_RemoveGIPFiles(FS_GetUserdir());

	FS_MakePath_BUF (FS_USERDIR, NULL, savedest, sizeof(savedest), Cmd_Argv(1));
	error_state = Host_CopyFiles(savedest, "*.gip", FS_GetUserdir());
	if (error_state)
	{
		Host_Error ("%s: The game could not be loaded properly!", __thisfunc__);
		return;
	}

	if (LoadGamestate(mapname, NULL, 2) != 0)
		return;

	SV_SaveSpawnparms ();

	ent = EDICT_NUM(1);

	Cvar_SetValue ("_cl_playerclass", ent->v.playerclass);//this better be the same as above...

	// this may be rudundant with the setting in PR_LoadProgs, but not sure so its here too
	if (sv_globals.cl_playerclass)
		*sv_globals.cl_playerclass = ent->v.playerclass;

	svs.clients->playerclass = ent->v.playerclass;

	sv.paused = true;		// pause until all clients connect
	sv.loadgame = true;

	if (cls.state != ca_dedicated)
	{
		CL_EstablishConnection ("local");
		Host_Reconnect_f ();
	}
}
Exemple #8
0
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 {