// 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); }
/* ================== 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); } }
/* ================== 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 }
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; } } }
/* ================== 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); } }
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); }
/* =============== 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 (); } }
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 {