void show_order_form() { if (CGameArg.SysNoTitles) return; #if defined(DXX_BUILD_DESCENT_I) show_first_found_title_screen( "warning.pcx", // D1 Registered "apple.pcx", // D1 Mac OEM Demo "order01.pcx" // D1 Demo ); #elif defined(DXX_BUILD_DESCENT_II) #if !DXX_USE_EDITOR key_flush(); const auto hiresmode = HIRESMODE; /* * If D2 registered, all checks fail and nothing is shown. */ const char *exit_screen = hiresmode ? "ordrd2ob.pcx" : "ordrd2o.pcx"; // OEM if ((PHYSFSX_exists(exit_screen, 1)) || // SHAREWARE, prefer mac if hires (exit_screen = hiresmode ? "orderd2b.pcx" : "orderd2.pcx", PHYSFSX_exists(exit_screen, 1)) || // SHAREWARE, have to rescale (exit_screen = hiresmode ? "orderd2.pcx" : "orderd2b.pcx", PHYSFSX_exists(exit_screen, 1)) || // D1 (exit_screen = hiresmode ? "warningb.pcx" : "warning.pcx", PHYSFSX_exists(exit_screen, 1)) ) show_title_screen(exit_screen,1,0); #endif #endif }
void save_screen_shot(int automap_flag) { static int savenum=0; char savename[13+sizeof(SCRNS_DIR)]; unsigned char *buf; if (!GameArg.DbgGlReadPixelsOk){ if (!automap_flag) HUD_init_message_literal(HM_DEFAULT, "glReadPixels not supported on your configuration"); return; } stop_time(); if (!PHYSFSX_exists(SCRNS_DIR,0)) PHYSFS_mkdir(SCRNS_DIR); //try making directory do { sprintf(savename, "%sscrn%04d.tga",SCRNS_DIR, savenum++); } while (PHYSFSX_exists(savename,0)); if (!automap_flag) HUD_init_message(HM_DEFAULT, "%s 'scrn%04d.tga'", TXT_DUMPING_SCREEN, savenum-1 ); #ifndef OGLES glReadBuffer(GL_FRONT); #endif buf = d_malloc(grd_curscreen->sc_w*grd_curscreen->sc_h*3); write_bmp(savename,grd_curscreen->sc_w,grd_curscreen->sc_h,buf); d_free(buf); start_time(); }
static void show_first_found_title_screen(const char *oem, const char *share, const char *macshare) { const char *filename = oem; if ((PHYSFSX_exists(filename, 1)) || (filename = share, PHYSFSX_exists(filename, 1)) || (filename = macshare, PHYSFSX_exists(filename, 1)) ) show_title_screen(filename, 1, 1); }
/* Open an m3u using fopen, not PHYSFS. If the path seems to be under * PHYSFS, that will be preferred over a raw filesystem path. */ static std::unique_ptr<FILE, FILE_deleter> open_m3u_from_disk(const char *const cfgpath) { array<char, PATH_MAX> absbuf; return std::unique_ptr<FILE, FILE_deleter>(fopen( // it's a child of Sharepath, build full path (PHYSFSX_exists(cfgpath, 0) ? (PHYSFSX_getRealPath(cfgpath, absbuf), absbuf.data()) : cfgpath), "rb") ); }
static void gamefont_loadfont(int gf,int fi) { if (PHYSFSX_exists(font_conf[gf].font[fi].f.name,1)){ gamefont_unloadfont(gf); Gamefonts[gf]=gr_init_font(font_conf[gf].font[fi].f.name); }else { if (Gamefonts[gf]==NULL){ Gamefonts[gf]=gr_init_font(Gamefont_filenames_l[gf]); font_conf[gf].cur=-1; } return; } font_conf[gf].cur=fi; }
static void addfontconf(int gf, int x, int y, const char *const fn) { if (!PHYSFSX_exists(fn,1)) return; for (int i=0;i<font_conf[gf].num;i++){ if (font_conf[gf].font[i].x==x && font_conf[gf].font[i].y==y){ if (i==font_conf[gf].cur) gamefont_unloadfont(gf); strcpy(font_conf[gf].font[i].f.name,fn); if (i==font_conf[gf].cur) gamefont_loadfont(gf,i); return; } } font_conf[gf].font[font_conf[gf].num].x=x; font_conf[gf].font[font_conf[gf].num].y=y; strcpy(font_conf[gf].font[font_conf[gf].num].f.name,fn); font_conf[gf].num++; }
int load_exit_models() { int start_num; bm_free_extra_models(); bm_free_extra_objbitmaps(); start_num = N_ObjBitmaps; if (!bm_load_extra_objbitmap("steel1.bbm") || !bm_load_extra_objbitmap("rbot061.bbm") || !bm_load_extra_objbitmap("rbot062.bbm") || !bm_load_extra_objbitmap("steel1.bbm") || !bm_load_extra_objbitmap("rbot061.bbm") || !bm_load_extra_objbitmap("rbot063.bbm")) { con_puts(CON_NORMAL, "Can't load exit models!"); return 0; } if (auto exit_hamfile = PHYSFSX_openReadBuffered("exit.ham")) { exit_modelnum = N_polygon_models++; destroyed_exit_modelnum = N_polygon_models++; polymodel_read(&Polygon_models[exit_modelnum], exit_hamfile); polymodel_read(&Polygon_models[destroyed_exit_modelnum], exit_hamfile); Polygon_models[exit_modelnum].first_texture = start_num; Polygon_models[destroyed_exit_modelnum].first_texture = start_num+3; polygon_model_data_read(&Polygon_models[exit_modelnum], exit_hamfile); polygon_model_data_read(&Polygon_models[destroyed_exit_modelnum], exit_hamfile); } else if (PHYSFSX_exists("exit01.pof",1) && PHYSFSX_exists("exit01d.pof",1)) { exit_modelnum = load_polygon_model("exit01.pof", 3, start_num, NULL); destroyed_exit_modelnum = load_polygon_model("exit01d.pof", 3, start_num + 3, NULL); #if DXX_USE_OGL ogl_cache_polymodel_textures(exit_modelnum); ogl_cache_polymodel_textures(destroyed_exit_modelnum); #endif } else if ((exit_hamfile = PHYSFSX_openReadBuffered(D1_PIGFILE))) { int offset, offset2; int hamsize; hamsize = PHYSFS_fileLength(exit_hamfile); switch (hamsize) { //total hack for loading models case D1_PIGSIZE: offset = 91848; /* and 92582 */ offset2 = 383390; /* and 394022 */ break; default: case D1_SHARE_BIG_PIGSIZE: case D1_SHARE_10_PIGSIZE: case D1_SHARE_PIGSIZE: case D1_10_BIG_PIGSIZE: case D1_10_PIGSIZE: Int3(); /* exit models should be in .pofs */ /*-fallthrough*/ case D1_OEM_PIGSIZE: case D1_MAC_PIGSIZE: case D1_MAC_SHARE_PIGSIZE: con_puts(CON_NORMAL, "Can't load exit models!"); return 0; } PHYSFSX_fseek(exit_hamfile, offset, SEEK_SET); exit_modelnum = N_polygon_models++; destroyed_exit_modelnum = N_polygon_models++; polymodel_read(&Polygon_models[exit_modelnum], exit_hamfile); polymodel_read(&Polygon_models[destroyed_exit_modelnum], exit_hamfile); Polygon_models[exit_modelnum].first_texture = start_num; Polygon_models[destroyed_exit_modelnum].first_texture = start_num+3; PHYSFSX_fseek(exit_hamfile, offset2, SEEK_SET); polygon_model_data_read(&Polygon_models[exit_modelnum], exit_hamfile); polygon_model_data_read(&Polygon_models[destroyed_exit_modelnum], exit_hamfile); } else { con_puts(CON_NORMAL, "Can't load exit models!"); return 0; } return 1; }
// Process a character for the briefing, // including special characters preceded by a '$'. // Return 1 when page is finished, 0 otherwise static int briefing_process_char(grs_canvas &canvas, briefing *const br) { auto &game_font = *GAME_FONT; char ch = *br->message++; if (ch == '$') { ch = *br->message++; #if defined(DXX_BUILD_DESCENT_II) if (ch=='D') { br->cur_screen = DefineBriefingBox(canvas.cv_bitmap, br->message); br->screen.reset(&Briefing_screens[br->cur_screen]); init_char_pos(br, br->screen->text_ulx, br->screen->text_uly); br->line_adjustment=0; br->prev_ch = 10; // read to eoln } else if (ch=='U') { br->cur_screen = get_message_num(br->message); br->screen.reset(&Briefing_screens[br->cur_screen]); init_char_pos(br, br->screen->text_ulx, br->screen->text_uly); br->prev_ch = 10; // read to eoln } else #endif if (ch == 'C') { auto cc = get_message_num(br->message) - 1; if (cc < 0) cc = 0; else if (cc > Briefing_text_colors.size() - 1) cc = Briefing_text_colors.size() - 1; Current_color = &Briefing_text_colors[cc]; br->prev_ch = 10; } else if (ch == 'F') { // toggle flashing cursor br->flashing_cursor = !br->flashing_cursor; br->prev_ch = 10; while (*br->message++ != 10) ; } else if (ch == 'T') { br->tab_stop = get_message_num(br->message); br->prev_ch = 10; // read to eoln } else if (ch == 'R') { br->robot_canv.reset(); #if defined(DXX_BUILD_DESCENT_II) if (br->robot_playing) { DeInitRobotMovie(br->pMovie); br->robot_playing=0; } #endif if (EMULATING_D1) { init_spinning_robot(canvas, *br); br->robot_num = get_message_num(br->message); #if defined(DXX_BUILD_DESCENT_II) while (*br->message++ != 10) ; #endif } else { #if defined(DXX_BUILD_DESCENT_II) char spinRobotName[]="RBA.MVE", kludge; // matt don't change this! kludge=*br->message++; spinRobotName[2]=kludge; // ugly but proud br->robot_playing=InitRobotMovie(spinRobotName, br->pMovie); // gr_remap_bitmap_good( &grd_curcanv->cv_bitmap, pal, -1, -1 ); if (br->robot_playing) { RotateRobot(br->pMovie); set_briefing_fontcolor(*br); } #endif } br->prev_ch = 10; // read to eoln } else if ((ch == 'N' && (br->animating_bitmap_type = 0, true)) || (ch == 'O' && (br->animating_bitmap_type = 1, true))) { br->robot_canv.reset(); br->prev_ch = 10; get_message_name(br->message, br->bitmap_name, "#0"); } else if (ch=='A') { #if defined(DXX_BUILD_DESCENT_II) br->line_adjustment=1-br->line_adjustment; #endif } else if (ch=='Z') { #if defined(DXX_BUILD_DESCENT_II) char fname[15]; int i; br->got_z=1; br->dumb_adjust=1; i=0; while ((fname[i]=*br->message) != '\n') { i++; br->message++; } fname[i]=0; if (*br->message != 10) while (*br->message++ != 10) // Get and drop eoln ; { char fname2[15]; i=0; while (fname[i]!='.') { fname2[i] = fname[i]; i++; } fname2[i++]='b'; fname2[i++]='.'; fname2[i++]='p'; fname2[i++]='c'; fname2[i++]='x'; fname2[i++]=0; if ((HIRESMODE && PHYSFSX_exists(fname2,1)) || !PHYSFSX_exists(fname,1)) strcpy(fname,fname2); load_briefing_screen(*grd_curcanv, br, fname); } #endif } else if (ch == 'B') { array<char, 32> bitmap_name; palette_array_t temp_palette; int iff_error; br->robot_canv.reset(); get_message_name(br->message, bitmap_name, ".bbm"); br->guy_bitmap.reset(); iff_error = iff_read_bitmap(&bitmap_name[0], br->guy_bitmap, &temp_palette); #if defined(DXX_BUILD_DESCENT_II) gr_remap_bitmap_good( br->guy_bitmap, temp_palette, -1, -1 ); #endif Assert(iff_error == IFF_NO_ERROR); (void)iff_error; br->prev_ch = 10; } else if (ch == 'S') { #if defined(DXX_BUILD_DESCENT_II) br->chattering = 0; br->printing_channel.reset(); #endif br->new_screen = 1; return 1; } else if (ch == 'P') { // New page. #if defined(DXX_BUILD_DESCENT_II) if (!br->got_z) { Int3(); // Hey ryan!!!! You gotta load a screen before you start // printing to it! You know, $Z !!! load_briefing_screen(*grd_curcanv, br, HIRESMODE ? "end01b.pcx" : "end01.pcx"); } br->chattering = 0; br->printing_channel.reset(); #endif br->new_page = 1; while (*br->message != 10) { br->message++; // drop carriage return after special escape sequence } br->message++; br->prev_ch = 10; return 1; } #if defined(DXX_BUILD_DESCENT_II) else if (ch == ':') { br->prev_ch = 10; auto p = br->message; /* Legacy clients do not understand $: and will instead show * the remainder of the line. However, if the next two * characters after $: are $F, legacy clients will treat * the $F as above, toggle the flashing_cursor flag, then * discard the rest of the line. This special case allows * briefing authors to hide the directive from legacy * clients, but get the same state of flashing_cursor for * both legacy and aware clients. Briefing authors will * likely need an additional $F nearby to balance this * toggle, but no additional code here is needed to support * that. * * The trailing colon is cosmetic, so that the compatibility * $F is not directly adjacent to the directive. */ if (!strncmp(p, "$F:", 3)) { br->flashing_cursor = !br->flashing_cursor; p += 3; } auto &rotate_robot_label = "Rebirth.rotate.robot "; constexpr auto rotate_robot_len = sizeof(rotate_robot_label) - 1; if (!strncmp(p, rotate_robot_label, rotate_robot_len)) { char *p2; const auto id = strtoul(p + rotate_robot_len, &p2, 10); if (*p2 == '\n') { p = p2; br->robot_canv.reset(); if (br->robot_playing) { br->robot_playing = 0; DeInitRobotMovie(br->pMovie); } init_spinning_robot(canvas, *br); /* This modifies the appearance of the frame, which * is unfortunate. However, without it, all robots * come out blue shifted. */ gr_use_palette_table("groupa.256"); br->robot_num = id; } } else { const char *p2 = p; /* Suppress non-printing characters. No need to support * encodings. */ for (char c; (c = *p2) >= ' ' && c <= '~'; ++p2) { } con_printf(CON_VERBOSE, "warning: unknown briefing directive \"%.*s\"", DXX_ptrdiff_cast_int(p2 - p), p); } for (char c; (c = *p) && (++p, c) != '\n';) { /* Discard through newline. On break, *p is '\0' or * p[-1] is '\n'. */ } br->message = p; } #endif else if (ch == '$' || ch == ';') // Print a $/; put_char_delay(game_font, br, ch); } else if (ch == '\t') { // Tab const auto &&fspacx = FSPACX(); if (br->text_x - br->screen->text_ulx < fspacx(br->tab_stop)) br->text_x = br->screen->text_ulx + fspacx(br->tab_stop); } else if ((ch == ';') && (br->prev_ch == 10)) { while (*br->message++ != 10) ; br->prev_ch = 10; } else if (ch == '\\') { br->prev_ch = ch; } else if (ch == 10) { if (br->prev_ch != '\\') { br->prev_ch = ch; #if defined(DXX_BUILD_DESCENT_II) if (br->dumb_adjust) br->dumb_adjust--; else #endif br->text_y += FSPACY(5)+FSPACY(5)*3/5; br->text_x = br->screen->text_ulx; if (br->text_y > br->screen->text_uly + br->screen->text_height) { #if defined(DXX_BUILD_DESCENT_I) load_briefing_screen(*grd_curcanv, br, D1_Briefing_screens[br->cur_screen].bs_name); #elif defined(DXX_BUILD_DESCENT_II) load_briefing_screen(*grd_curcanv, br, Briefing_screens[br->cur_screen].bs_name); #endif br->text_x = br->screen->text_ulx; br->text_y = br->screen->text_uly; } } else { if (ch == 13) //Can this happen? Above says ch==10 Int3(); br->prev_ch = ch; } } else { #if defined(DXX_BUILD_DESCENT_II) if (!br->got_z) { LevelError("briefing wrote to screen without using $Z to load a screen; loading default."); //Int3(); // Hey ryan!!!! You gotta load a screen before you start // printing to it! You know, $Z !!! load_briefing_screen(*grd_curcanv, br, HIRESMODE ? "end01b.pcx" : "end01.pcx"); } #endif put_char_delay(game_font, br, ch); } return 0; }
//read in the player's saved games. returns errno (0 == no error) int read_player_file() { char filename[PATH_MAX]; PHYSFS_file *file; int player_file_size, shareware_file = -1, id = 0; short saved_game_version, player_struct_version; Assert(Player_num>=0 && Player_num<MAX_PLAYERS); memset(filename, '\0', PATH_MAX); snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%.8s.plr" : "%.8s.plr", Players[Player_num].callsign); if (!PHYSFSX_exists(filename,0)) return ENOENT; file = PHYSFSX_openReadBuffered(filename); if (!file) goto read_player_file_failed; new_player_config(); // Set defaults! // Unfortunatly d1x has been writing both shareware and registered // player files with a saved_game_version of 7 and 8, whereas the // original decent used 4 for shareware games and 7 for registered // games. Because of this the player files didn't get properly read // when reading d1x shareware player files in d1x registered or // vica versa. The problem is that the sizeof of the taunt macros // differ between the share and registered versions, causing the // reading of the player file to go wrong. Thus we now determine the // sizeof the player file to determine what kinda player file we are // dealing with so that we can do the right thing PHYSFS_seek(file, 0); player_file_size = PHYSFS_fileLength(file); PHYSFS_readSLE32(file, &id); saved_game_version = PHYSFSX_readShort(file); player_struct_version = PHYSFSX_readShort(file); PlayerCfg.NHighestLevels = PHYSFSX_readInt(file); PlayerCfg.DefaultDifficulty = PHYSFSX_readInt(file); PlayerCfg.AutoLeveling = PHYSFSX_readInt(file); if (id!=SAVE_FILE_ID) { nm_messagebox(TXT_ERROR, 1, TXT_OK, "Invalid player file"); PHYSFS_close(file); return -1; } if (saved_game_version<COMPATIBLE_SAVED_GAME_VERSION || player_struct_version<COMPATIBLE_PLAYER_STRUCT_VERSION) { nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_ERROR_PLR_VERSION); PHYSFS_close(file); return -1; } /* determine if we're dealing with a shareware or registered playerfile */ switch (saved_game_version) { case 4: shareware_file = 1; break; case 5: case 6: shareware_file = 0; break; case 7: /* version 7 doesn't have the saved games array */ if ((player_file_size - (sizeof(hli)*PlayerCfg.NHighestLevels)) == (2212 - sizeof(saved_games))) shareware_file = 1; if ((player_file_size - (sizeof(hli)*PlayerCfg.NHighestLevels)) == (2252 - sizeof(saved_games))) shareware_file = 0; break; case 8: if ((player_file_size - (sizeof(hli)*PlayerCfg.NHighestLevels)) == 2212) shareware_file = 1; if ((player_file_size - (sizeof(hli)*PlayerCfg.NHighestLevels)) == 2252) shareware_file = 0; /* d1x-rebirth v0.31 to v0.42 broke things by adding stuff to the player struct without thinking (sigh) */ if ((player_file_size - (sizeof(hli)*PlayerCfg.NHighestLevels)) == (2212 + 2*sizeof(int))) { shareware_file = 1; /* skip the cruft added to the player_info struct */ PHYSFS_seek(file, PHYSFS_tell(file)+2*sizeof(int)); } if ((player_file_size - (sizeof(hli)*PlayerCfg.NHighestLevels)) == (2252 + 2*sizeof(int))) { shareware_file = 0; /* skip the cruft added to the player_info struct */ PHYSFS_seek(file, PHYSFS_tell(file)+2*sizeof(int)); } } if (shareware_file == -1) { nm_messagebox(TXT_ERROR, 1, TXT_OK, "Error invalid or unknown\nplayerfile-size"); PHYSFS_close(file); return -1; } if (saved_game_version <= 5) { //deal with old-style highest level info PlayerCfg.HighestLevels[0].Shortname[0] = 0; //no name for mission 0 PlayerCfg.HighestLevels[0].LevelNum = PlayerCfg.NHighestLevels; //was highest level in old struct //This hack allows the player to start on level 8 if he's made it to //level 7 on the shareware. We do this because the shareware didn't //save the information that the player finished level 7, so the most //we know is that he made it to level 7. if (PlayerCfg.NHighestLevels==7) PlayerCfg.HighestLevels[0].LevelNum = 8; } else { //read new highest level info if (PHYSFS_read(file,PlayerCfg.HighestLevels,sizeof(hli),PlayerCfg.NHighestLevels) != PlayerCfg.NHighestLevels) goto read_player_file_failed; } if ( saved_game_version != 7 ) { // Read old & SW saved games. if (PHYSFS_read(file,saved_games,sizeof(saved_games),1) != 1) goto read_player_file_failed; } //read taunt macros { int i; int len = shareware_file? 25:35; #ifdef NETWORK for (i = 0; i < 4; i++) if (PHYSFS_read(file, PlayerCfg.NetworkMessageMacro[i], len, 1) != 1) goto read_player_file_failed; #else i = 0; PHYSFS_seek( file, PHYSFS_tell(file)+4*len ); #endif } //read kconfig data { ubyte dummy_joy_sens; if (PHYSFS_read(file, &PlayerCfg.KeySettings[0], sizeof(PlayerCfg.KeySettings[0]),1)!=1) goto read_player_file_failed; if (PHYSFS_read(file, &PlayerCfg.KeySettings[1], sizeof(PlayerCfg.KeySettings[1]),1)!=1) goto read_player_file_failed; PHYSFS_seek( file, PHYSFS_tell(file)+(sizeof(ubyte)*MAX_CONTROLS*3) ); // Skip obsolete Flightstick/Thrustmaster/Gravis map fields if (PHYSFS_read(file, &PlayerCfg.KeySettings[2], sizeof(PlayerCfg.KeySettings[2]),1)!=1) goto read_player_file_failed; PHYSFS_seek( file, PHYSFS_tell(file)+(sizeof(ubyte)*MAX_CONTROLS) ); // Skip obsolete Cyberman map field if (PHYSFS_read(file, &PlayerCfg.ControlType, sizeof(ubyte), 1 )!=1) goto read_player_file_failed; else if (PHYSFS_read(file, &dummy_joy_sens, sizeof(ubyte), 1 )!=1) goto read_player_file_failed; } if ( saved_game_version != 7 ) { int i, found=0; Assert( N_SAVE_SLOTS == 10 ); for (i=0; i<N_SAVE_SLOTS; i++ ) { if ( saved_games[i].name[0] ) { state_save_old_game(i, saved_games[i].name, &saved_games[i].sg_player, saved_games[i].difficulty_level, saved_games[i].primary_weapon, saved_games[i].secondary_weapon, saved_games[i].next_level_num ); // make sure we do not do this again, which would possibly overwrite // a new newstyle savegame saved_games[i].name[0] = 0; found++; } } if (found) write_player_file(); } if (!PHYSFS_close(file)) goto read_player_file_failed; filename[strlen(filename) - 4] = 0; strcat(filename, ".plx"); read_player_d1x(filename); kc_set_controls(); return EZERO; read_player_file_failed: nm_messagebox(TXT_ERROR, 1, TXT_OK, "%s\n\n%s", "Error reading PLR file", PHYSFS_getLastError()); if (file) PHYSFS_close(file); return -1; }
int main(int argc, char *argv[]) { mem_init(); #ifdef __LINUX__ error_init(NULL, NULL); #else error_init(msgbox_error, NULL); set_warn_func(msgbox_warning); #endif PHYSFSX_init(argc, argv); con_init(); // Initialise the console setbuf(stdout, NULL); // unbuffered output via printf #ifdef _WIN32 freopen( "CON", "w", stdout ); freopen( "CON", "w", stderr ); #endif if (GameArg.SysShowCmdHelp) { print_commandline_help(); set_exit_message(""); return(0); } printf("\nType %s -help' for a list of command-line options.\n\n", PROGNAME); PHYSFSX_listSearchPathContent(); if (!PHYSFSX_checkSupportedArchiveTypes()) return(0); if (! PHYSFSX_contfile_init("descent.hog", 1)) Error("Could not find a valid hog file (descent.hog)\nPossible locations are:\n" #if defined(__unix__) && !defined(__APPLE__) "\t$HOME/.d1x-rebirth\n" "\t" SHAREPATH "\n" #else "\tDirectory containing D1X\n" #endif "\tIn a subdirectory called 'Data'\n" #if (defined(__APPLE__) && defined(__MACH__)) || defined(macintosh) "\tIn 'Resources' inside the application bundle\n" #endif "Or use the -hogdir option to specify an alternate location."); switch (PHYSFSX_fsize("descent.hog")) { case D1_MAC_SHARE_MISSION_HOGSIZE: case D1_MAC_MISSION_HOGSIZE: MacHog = 1; // used for fonts and the Automap break; } load_text(); //print out the banner title con_printf(CON_NORMAL, "%s", DESCENT_VERSION); // D1X version con_printf(CON_NORMAL, " %s %s\n", __DATE__,__TIME__); con_printf(CON_NORMAL, "This is a MODIFIED version of Descent, based on %s.\n", BASED_VERSION); con_printf(CON_NORMAL, "%s\n%s\n",TXT_COPYRIGHT,TXT_TRADEMARK); con_printf(CON_NORMAL, "Copyright (C) 2005-2011 Christian Beckhaeuser\n\n"); if (GameArg.DbgVerbose) con_printf(CON_VERBOSE,"%s%s", TXT_VERBOSE_1, "\n"); ReadConfigFile(); PHYSFSX_addArchiveContent(); arch_init(); select_tmap(GameArg.DbgTexMap); con_printf(CON_VERBOSE, "Going into graphics mode...\n"); gr_set_mode(Game_screen_mode); // Load the palette stuff. Returns non-zero if error. con_printf(CON_DEBUG, "Initializing palette system...\n" ); gr_use_palette_table( "PALETTE.256" ); con_printf(CON_DEBUG, "Initializing font system...\n" ); gamefont_init(); // must load after palette data loaded. set_default_handler(standard_handler); show_titles(); set_screen_mode(SCREEN_MENU); con_printf( CON_DEBUG, "\nDoing gamedata_init..." ); gamedata_init(); if (GameArg.DbgNoRun) return(0); con_printf( CON_DEBUG, "\nInitializing texture caching system..." ); texmerge_init( 10 ); // 10 cache bitmaps con_printf( CON_DEBUG, "\nRunning game...\n" ); init_game(); Players[Player_num].callsign[0] = '\0'; key_flush(); if(GameArg.SysPilot) { char filename[32] = ""; int j; if (GameArg.SysUsePlayersDir) strcpy(filename, "Players/"); strncat(filename, GameArg.SysPilot, 12); filename[8 + 12] = '\0'; // unfortunately strncat doesn't put the terminating 0 on the end if it reaches 'n' for (j = GameArg.SysUsePlayersDir? 8 : 0; filename[j] != '\0'; j++) { switch (filename[j]) { case ' ': filename[j] = '\0'; } } if(!strstr(filename,".plr")) // if player hasn't specified .plr extension in argument, add it strcat(filename,".plr"); if(PHYSFSX_exists(filename,0)) { strcpy(strstr(filename,".plr"),"\0"); strcpy(Players[Player_num].callsign, GameArg.SysUsePlayersDir? &filename[8] : filename); read_player_file(); WriteConfigFile(); } } Game_mode = GM_GAME_OVER; DoMenu(); setjmp(LeaveEvents); while (window_get_front()) // Send events to windows and the default handler event_process(); // Tidy up - avoids a crash on exit { window *wind; show_menus(); while ((wind = window_get_front())) window_close(wind); } WriteConfigFile(); show_order_form(); con_printf( CON_DEBUG, "\nCleanup...\n" ); close_game(); texmerge_close(); gamedata_close(); gamefont_close(); free_text(); args_exit(); newmenu_free_background(); free_mission(); PHYSFSX_removeArchiveContent(); return(0); //presumably successful exit }
static int main(int argc, char *argv[]) { if (!PHYSFSX_init(argc, argv)) return 1; con_init(); // Initialise the console setbuf(stdout, NULL); // unbuffered output via printf #ifdef _WIN32 freopen( "CON", "w", stdout ); freopen( "CON", "w", stderr ); #endif if (CGameArg.SysShowCmdHelp) { print_commandline_help(); return(0); } printf("\nType '%s -help' for a list of command-line options.\n\n", PROGNAME); PHYSFSX_listSearchPathContent(); if (!PHYSFSX_checkSupportedArchiveTypes()) return(0); #if defined(DXX_BUILD_DESCENT_I) if (! PHYSFSX_contfile_init("descent.hog", 1)) #define DXX_NAME_NUMBER "1" #define DXX_HOGFILE_NAMES "descent.hog" #elif defined(DXX_BUILD_DESCENT_II) if (! PHYSFSX_contfile_init("descent2.hog", 1) && ! PHYSFSX_contfile_init("d2demo.hog", 1)) #define DXX_NAME_NUMBER "2" #define DXX_HOGFILE_NAMES "descent2.hog or d2demo.hog" #endif { #if defined(__unix__) && !defined(__APPLE__) #define DXX_HOGFILE_PROGRAM_DATA_DIRECTORY \ "\t$HOME/.d" DXX_NAME_NUMBER "x-rebirth\n" \ "\t" SHAREPATH "\n" #else #define DXX_HOGFILE_PROGRAM_DATA_DIRECTORY \ "\tDirectory containing D" DXX_NAME_NUMBER "X\n" #endif #if (defined(__APPLE__) && defined(__MACH__)) || defined(macintosh) #define DXX_HOGFILE_APPLICATION_BUNDLE \ "\tIn 'Resources' inside the application bundle\n" #else #define DXX_HOGFILE_APPLICATION_BUNDLE "" #endif #define DXX_MISSING_HOGFILE_ERROR_TEXT \ "Could not find a valid hog file (" DXX_HOGFILE_NAMES ")\nPossible locations are:\n" \ DXX_HOGFILE_PROGRAM_DATA_DIRECTORY \ "\tIn a subdirectory called 'Data'\n" \ DXX_HOGFILE_APPLICATION_BUNDLE \ "Or use the -hogdir option to specify an alternate location." UserError(DXX_MISSING_HOGFILE_ERROR_TEXT); } #if defined(DXX_BUILD_DESCENT_I) switch (PHYSFSX_fsize("descent.hog")) { case D1_MAC_SHARE_MISSION_HOGSIZE: case D1_MAC_MISSION_HOGSIZE: MacHog = 1; // used for fonts and the Automap break; } #endif load_text(); //print out the banner title #if defined(DXX_BUILD_DESCENT_I) con_printf(CON_NORMAL, "%s %s", DESCENT_VERSION, g_descent_build_datetime); // D1X version con_printf(CON_NORMAL, "This is a MODIFIED version of Descent, based on %s.", BASED_VERSION); con_printf(CON_NORMAL, "%s\n%s",TXT_COPYRIGHT,TXT_TRADEMARK); con_printf(CON_NORMAL, "Copyright (C) 2005-2013 Christian Beckhaeuser"); #elif defined(DXX_BUILD_DESCENT_II) con_printf(CON_NORMAL, "%s%s %s", DESCENT_VERSION, PHYSFSX_exists(MISSION_DIR "d2x.hog",1) ? " Vertigo Enhanced" : "", g_descent_build_datetime); // D2X version con_printf(CON_NORMAL, "This is a MODIFIED version of Descent 2, based on %s.", BASED_VERSION); con_printf(CON_NORMAL, "%s\n%s",TXT_COPYRIGHT,TXT_TRADEMARK); con_printf(CON_NORMAL, "Copyright (C) 1999 Peter Hawkins, 2002 Bradley Bell, 2005-2013 Christian Beckhaeuser"); #endif if (CGameArg.DbgVerbose) con_puts(CON_VERBOSE, TXT_VERBOSE_1); ReadConfigFile(); PHYSFSX_addArchiveContent(); arch_init(); select_tmap(CGameArg.DbgTexMap); #if defined(DXX_BUILD_DESCENT_II) Lighting_on = 1; #endif con_printf(CON_VERBOSE, "Going into graphics mode..."); gr_set_mode(Game_screen_mode); // Load the palette stuff. Returns non-zero if error. con_printf(CON_DEBUG, "Initializing palette system..." ); #if defined(DXX_BUILD_DESCENT_I) gr_use_palette_table( "PALETTE.256" ); #elif defined(DXX_BUILD_DESCENT_II) gr_use_palette_table(D2_DEFAULT_PALETTE ); #endif con_printf(CON_DEBUG, "Initializing font system..." ); gamefont_init(); // must load after palette data loaded. #if defined(DXX_BUILD_DESCENT_II) con_printf( CON_DEBUG, "Initializing movie libraries..." ); init_movies(); //init movie libraries #endif show_titles(); set_screen_mode(SCREEN_MENU); #ifdef DEBUG_MEMORY_ALLOCATIONS /* Memdebug runs before global destructors, so it incorrectly * reports as leaked any allocations that would be freed by a global * destructor. This local will force the newmenu globals to be * reset before memdebug scans, which prevents memdebug falsely * reporting them as leaked. * * External tools, such as Valgrind, know to run global destructors * before checking for leaks, so this hack is only necessary when * memdebug is used. */ struct hack_free_global_backgrounds { ~hack_free_global_backgrounds() { newmenu_free_background(); } }; hack_free_global_backgrounds hack_free_global_background; #endif con_printf( CON_DEBUG, "\nDoing gamedata_init..." ); gamedata_init(); #if defined(DXX_BUILD_DESCENT_II) #if DXX_USE_EDITOR if (GameArg.EdiSaveHoardData) { save_hoard_data(); exit(1); } #endif #endif if (CGameArg.DbgNoRun) return(0); con_printf( CON_DEBUG, "\nInitializing texture caching system..." ); texmerge_init(); // 10 cache bitmaps #if defined(DXX_BUILD_DESCENT_II) piggy_init_pigfile("groupa.pig"); //get correct pigfile #endif con_printf( CON_DEBUG, "\nRunning game..." ); init_game(); get_local_player().callsign = {}; #if defined(DXX_BUILD_DESCENT_I) key_flush(); #elif defined(DXX_BUILD_DESCENT_II) // If built with editor, option to auto-load a level and quit game // to write certain data. #ifdef EDITOR if (!GameArg.EdiAutoLoad.empty()) { Players[0].callsign = "dummy"; } else #endif #endif { if (!CGameArg.SysPilot.empty()) { char filename[sizeof(PLAYER_DIRECTORY_TEXT) + CALLSIGN_LEN + 4]; /* Step over the literal PLAYER_DIRECTORY_TEXT when it is * present. Point at &filename[0] when * PLAYER_DIRECTORY_TEXT is absent. */ const auto b = &filename[-CGameArg.SysUsePlayersDir]; snprintf(filename, sizeof(filename), PLAYER_DIRECTORY_STRING("%.12s"), CGameArg.SysPilot.c_str()); /* The pilot name is never used after this. Clear it to * free the allocated memory, if any. */ CGameArg.SysPilot.clear(); auto p = b; for (const auto &facet = std::use_facet<std::ctype<char>>(std::locale::classic()); char &c = *p; ++p) { c = facet.tolower(static_cast<uint8_t>(c)); } auto j = p - filename; if (j < sizeof(filename) - 4 && (j <= 4 || strcmp(&filename[j - 4], ".plr"))) // if player hasn't specified .plr extension in argument, add it { strcpy(&filename[j], ".plr"); j += 4; } if(PHYSFSX_exists(filename,0)) { get_local_player().callsign.copy(b, std::distance(b, &filename[j - 4])); read_player_file(); WriteConfigFile(); } } } #if defined(DXX_BUILD_DESCENT_II) #if DXX_USE_EDITOR if (!GameArg.EdiAutoLoad.empty()) { /* Any number >= FILENAME_LEN works */ Level_names[0].copy_if(GameArg.EdiAutoLoad.c_str(), GameArg.EdiAutoLoad.size()); LoadLevel(1, 1); } else #endif #endif { Game_mode = GM_GAME_OVER; DoMenu(); } while (window_get_front()) // Send events to windows and the default handler event_process(); // Tidy up - avoids a crash on exit { window *wind; show_menus(); while ((wind = window_get_front())) window_close(wind); } WriteConfigFile(); show_order_form(); con_printf( CON_DEBUG, "\nCleanup..." ); close_game(); texmerge_close(); gamedata_close(); gamefont_close(); Current_mission.reset(); PHYSFSX_removeArchiveContent(); return(0); //presumably successful exit }
// read stored values from ngp file to netgame_info void read_netgame_profile(netgame_info *ng) { char filename[PATH_MAX], line[50], *token, *value, *ptr; PHYSFS_file *file; memset(filename, '\0', PATH_MAX); snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%.8s.ngp" : "%.8s.ngp", Players[Player_num].callsign); if (!PHYSFSX_exists(filename,0)) return; file = PHYSFSX_openReadBuffered(filename); if (!file) return; // NOTE that we do not set any defaults here or even initialize netgame_info. For flexibility, leave that to the function calling this. while (!PHYSFS_eof(file)) { memset(line, 0, 50); PHYSFSX_gets(file, line); ptr = &(line[0]); while (isspace(*ptr)) ptr++; if (*ptr != '\0') { token = strtok(ptr, "="); value = strtok(NULL, "="); if (!value) value = ""; if (!strcmp(token, "game_name")) { char * p; strncpy( ng->game_name, value, NETGAME_NAME_LEN+1 ); p = strchr( ng->game_name, '\n'); if ( p ) *p = 0; } else if (!strcmp(token, "gamemode")) ng->gamemode = strtol(value, NULL, 10); else if (!strcmp(token, "RefusePlayers")) ng->RefusePlayers = strtol(value, NULL, 10); else if (!strcmp(token, "difficulty")) ng->difficulty = strtol(value, NULL, 10); else if (!strcmp(token, "game_flags")) ng->game_flags = strtol(value, NULL, 10); else if (!strcmp(token, "AllowedItems")) ng->AllowedItems = strtol(value, NULL, 10); else if (!strcmp(token, "ShowEnemyNames")) ng->ShowEnemyNames = strtol(value, NULL, 10); else if (!strcmp(token, "BrightPlayers")) ng->BrightPlayers = strtol(value, NULL, 10); else if (!strcmp(token, "InvulAppear")) ng->InvulAppear = strtol(value, NULL, 10); else if (!strcmp(token, "KillGoal")) ng->KillGoal = strtol(value, NULL, 10); else if (!strcmp(token, "PlayTimeAllowed")) ng->PlayTimeAllowed = strtol(value, NULL, 10); else if (!strcmp(token, "control_invul_time")) ng->control_invul_time = strtol(value, NULL, 10); else if (!strcmp(token, "PacketsPerSec")) ng->PacketsPerSec = strtol(value, NULL, 10); else if (!strcmp(token, "NoFriendlyFire")) ng->NoFriendlyFire = strtol(value, NULL, 10); #ifdef USE_TRACKER else if (!strcmp(token, "Tracker")) ng->Tracker = strtol(value, NULL, 10); #endif } } PHYSFS_close(file); }
//loads the specfied mission from the mission list. //build_mission_list() must have been called. //Returns true if mission loaded ok, else false. int load_mission(mle *mission) { PHYSFS_file *mfile; char buf[PATH_MAX], *v; if (Current_mission) free_mission(); Current_mission = d_malloc(sizeof(Mission)); if (!Current_mission) return 0; *(mle *) Current_mission = *mission; Current_mission->path = d_strdup(mission->path); Current_mission->filename = Current_mission->path + (mission->filename - mission->path); Current_mission->n_secret_levels = 0; //init vars Last_level = 0; Last_secret_level = 0; memset(&Briefing_text_filename, '\0', sizeof(Briefing_text_filename)); memset(&Ending_text_filename, '\0', sizeof(Ending_text_filename)); Secret_level_table = NULL; Level_names = NULL; Secret_level_names = NULL; // for Descent 1 missions, load descent.hog if (!PHYSFSX_contfile_init("descent.hog", 1)) Error("descent.hog not available!\n"); if (!d_stricmp(Current_mission_filename, D1_MISSION_FILENAME)) return load_mission_d1(); //read mission from file switch (mission->location) { case ML_MISSIONDIR: strcpy(buf,MISSION_DIR); break; default: Int3(); //fall through case ML_CURDIR: strcpy(buf,""); break; } strcat(buf, mission->path); strcat(buf,".msn"); PHYSFSEXT_locateCorrectCase(buf); mfile = PHYSFSX_openReadBuffered(buf); if (mfile == NULL) { free_mission(); return 0; //error! } //for non-builtin missions, load HOG strcpy(buf+strlen(buf)-4,".hog"); //change extension PHYSFSEXT_locateCorrectCase(buf); if (PHYSFSX_exists(buf,1)) PHYSFSX_contfile_init(buf, 0); snprintf(Briefing_text_filename, sizeof(Briefing_text_filename), "%s.tex",Current_mission_filename); if (!PHYSFSX_exists(Briefing_text_filename,1)) snprintf(Briefing_text_filename, sizeof(Briefing_text_filename), "%s.txb",Current_mission_filename); snprintf(Ending_text_filename, sizeof(Ending_text_filename), "%s.tex",Current_mission_filename); if (!PHYSFSX_exists(Ending_text_filename,1)) snprintf(Ending_text_filename, sizeof(Ending_text_filename), "%s.txb",Current_mission_filename); while (PHYSFSX_fgets(buf,sizeof(buf),mfile)) { if (istok(buf,"type")) continue; //already have name, go to next line else if (istok(buf,"briefing")) { if ((v = get_value(buf)) != NULL) { add_term(v); if (strlen(v) < FILENAME_LEN && strlen(v) > 0) { char *tmp, *ptr; MALLOC(tmp, char, FILENAME_LEN); snprintf(tmp, FILENAME_LEN, "%s", v); if ((ptr = strrchr(tmp, '.'))) // if there's a filename extension, kill it. No one knows it's the right one. *ptr = '\0'; strncat(tmp, ".tex", sizeof(char)*FILENAME_LEN); // apply tex-extenstion if (PHYSFSX_exists(tmp,1)) // check if this file exists ... snprintf(Briefing_text_filename, FILENAME_LEN, "%s", tmp); // ... and apply ... else // ... otherwise ... { if ((ptr = strrchr(tmp, '.'))) *ptr = '\0'; strncat(tmp, ".txb", sizeof(char)*FILENAME_LEN); // apply txb extension if (PHYSFSX_exists(tmp,1)) // check if this file exists ... snprintf(Briefing_text_filename, FILENAME_LEN, "%s", tmp); // ... and apply ... } d_free(tmp); } } } else if (istok(buf,"ending")) { if ((v = get_value(buf)) != NULL) { add_term(v); if (strlen(v) < FILENAME_LEN && strlen(v) > 0) { char *tmp, *ptr; MALLOC(tmp, char, FILENAME_LEN); snprintf(tmp, FILENAME_LEN, "%s", v); if ((ptr = strrchr(tmp, '.'))) // if there's a filename extension, kill it. No one knows it's the right one. *ptr = '\0'; strncat(tmp, ".tex", sizeof(char)*FILENAME_LEN); // apply tex-extenstion if (PHYSFSX_exists(tmp,1)) // check if this file exists ... snprintf(Briefing_text_filename, FILENAME_LEN, "%s", tmp); // ... and apply ... else // ... otherwise ... { if ((ptr = strrchr(tmp, '.'))) *ptr = '\0'; strncat(tmp, ".txb", sizeof(char)*FILENAME_LEN); // apply txb extension if (PHYSFSX_exists(tmp,1)) // check if this file exists ... snprintf(Ending_text_filename, FILENAME_LEN, "%s", tmp); // ... and apply ... } d_free(tmp); } } } else if (istok(buf,"num_levels")) { if ((v=get_value(buf))!=NULL) { int n_levels,i; n_levels = atoi(v); Assert(n_levels <= MAX_LEVELS_PER_MISSION); n_levels = min(n_levels, MAX_LEVELS_PER_MISSION); MALLOC(Level_names, d_fname, n_levels); if (!Level_names) { free_mission(); return 0; } for (i=0;i<n_levels;i++) { PHYSFSX_fgets(buf,sizeof(buf),mfile); add_term(buf); if (strlen(buf) <= 12) { strcpy(Level_names[i],buf); Last_level++; } else break; } } } else if (istok(buf,"num_secrets")) { if ((v=get_value(buf))!=NULL) { int i; N_secret_levels = atoi(v); Assert(N_secret_levels <= MAX_SECRET_LEVELS_PER_MISSION); N_secret_levels = min(N_secret_levels, MAX_SECRET_LEVELS_PER_MISSION); MALLOC(Secret_level_names, d_fname, N_secret_levels); if (!Secret_level_names) { free_mission(); return 0; } MALLOC(Secret_level_table, ubyte, N_secret_levels); if (!Secret_level_table) { free_mission(); return 0; } for (i=0;i<N_secret_levels;i++) { char *t; PHYSFSX_fgets(buf,sizeof(buf),mfile); if ((t=strchr(buf,','))!=NULL) *t++=0; else break; add_term(buf); if (strlen(buf) <= 12) { strcpy(Secret_level_names[i],buf); Secret_level_table[i] = atoi(t); if (Secret_level_table[i]<1 || Secret_level_table[i]>Last_level) break; Last_secret_level--; } else break; } } } } PHYSFS_close(mfile); if (Last_level <= 0) { free_mission(); //no valid mission loaded return 0; } return 1; }
// Set up everything for our music // NOTE: you might think this is done once per runtime but it's not! It's done for EACH song so that each mission can have it's own descent.sng structure. We COULD optimize that by only doing this once per mission. void songs_init() { int i = 0; char inputline[80+1]; PHYSFS_file * fp = NULL; char sng_file[PATH_MAX]; Songs_initialized = 0; if (BIMSongs != NULL) d_free(BIMSongs); memset(sng_file, '\0', sizeof(sng_file)); if (Current_mission != NULL) // try MISSION_NAME.sngdxx - might be rarely used but handy if you want a songfile for a specific mission outside of the mission hog file. use special extension to not crash with other ports of the game { snprintf(sng_file, strlen(Current_mission_filename)+8, "%s.sngdxx", Current_mission_filename); fp = PHYSFSX_openReadBuffered(sng_file); } if (fp == NULL) // try descent.sngdxx - a songfile specifically for dxx which level authors CAN use (dxx does not care if descent.sng contains MP3/OGG/etc. as well) besides the normal descent.sng containing files other versions of the game cannot play. this way a mission can contain a DOS-Descent compatible OST (hmp files) as well as a OST using MP3, OGG, etc. fp = PHYSFSX_openReadBuffered( "descent.sngdxx" ); if (fp == NULL) // try to open regular descent.sng fp = PHYSFSX_openReadBuffered( "descent.sng" ); if ( fp == NULL ) // No descent.sng available. Define a default song-set { int predef=30; // define 30 songs - period MALLOC(BIMSongs, bim_song_info, predef); if (!BIMSongs) return; strncpy(BIMSongs[SONG_TITLE].filename, "descent.hmp",sizeof(BIMSongs[SONG_TITLE].filename)); strncpy(BIMSongs[SONG_BRIEFING].filename, "briefing.hmp",sizeof(BIMSongs[SONG_BRIEFING].filename)); strncpy(BIMSongs[SONG_CREDITS].filename, "credits.hmp",sizeof(BIMSongs[SONG_CREDITS].filename)); strncpy(BIMSongs[SONG_ENDLEVEL].filename, "endlevel.hmp",sizeof(BIMSongs[SONG_ENDLEVEL].filename)); // can't find it? give a warning strncpy(BIMSongs[SONG_ENDGAME].filename, "endgame.hmp",sizeof(BIMSongs[SONG_ENDGAME].filename)); // ditto for (i = SONG_FIRST_LEVEL_SONG; i < predef; i++) { snprintf(BIMSongs[i].filename, sizeof(BIMSongs[i].filename), "game%02d.hmp", i - SONG_FIRST_LEVEL_SONG + 1); if (!PHYSFSX_exists(BIMSongs[i].filename,1)) snprintf(BIMSongs[i].filename, sizeof(BIMSongs[i].filename), "game%d.hmp", i - SONG_FIRST_LEVEL_SONG); if (!PHYSFSX_exists(BIMSongs[i].filename,1)) { memset(BIMSongs[i].filename, '\0', sizeof(BIMSongs[i].filename)); // music not available break; } } } else { while (!PHYSFS_eof(fp)) { PHYSFSX_fgets(inputline, 80, fp ); if ( strlen( inputline ) ) { BIMSongs = d_realloc(BIMSongs, sizeof(bim_song_info)*(i+1)); memset(BIMSongs[i].filename, '\0', sizeof(BIMSongs[i].filename)); sscanf( inputline, "%15s", BIMSongs[i].filename ); if (strrchr(BIMSongs[i].filename, '.')) if (!stricmp(strrchr(BIMSongs[i].filename, '.'), ".hmp") || !stricmp(strrchr(BIMSongs[i].filename, '.'), ".mp3") || !stricmp(strrchr(BIMSongs[i].filename, '.'), ".ogg") || !stricmp(strrchr(BIMSongs[i].filename, '.'), ".aif") || !stricmp(strrchr(BIMSongs[i].filename, '.'), ".mid") || !stricmp(strrchr(BIMSongs[i].filename, '.'), ".flac") ) i++; } } // HACK: If Descent.hog is patched from 1.0 to 1.5, descent.sng is turncated. So let's patch it up here if (i==12 && PHYSFSX_fsize("descent.sng")==422) { BIMSongs = d_realloc(BIMSongs, sizeof(bim_song_info)*(i+15)); for (i = 12; i <= 26; i++) snprintf(BIMSongs[i].filename, sizeof(BIMSongs[i].filename), "game%02d.hmp", i-4); } } Num_bim_songs = i; Songs_initialized = 1; if (fp != NULL) PHYSFS_close(fp); if (GameArg.SndNoMusic) GameCfg.MusicType = MUSIC_TYPE_NONE; // If SDL_Mixer is not supported (or deactivated), switch to no-music type if SDL_mixer-related music type was selected #ifdef USE_SDLMIXER if (GameArg.SndDisableSdlMixer) #else if (1) #endif { #ifndef _WIN32 if (GameCfg.MusicType == MUSIC_TYPE_BUILTIN) GameCfg.MusicType = MUSIC_TYPE_NONE; #endif if (GameCfg.MusicType == MUSIC_TYPE_CUSTOM) GameCfg.MusicType = MUSIC_TYPE_NONE; } if (GameCfg.MusicType == MUSIC_TYPE_REDBOOK) RBAInit(); #ifdef USE_SDLMIXER else if (GameCfg.MusicType == MUSIC_TYPE_CUSTOM) jukebox_load(); #endif songs_set_volume(GameCfg.MusicVolume); }
//loads the specfied mission from the mission list. //build_mission_list() must have been called. //Returns true if mission loaded ok, else false. static int load_mission(mle *mission) { PHYSFS_file *mfile; char buf[PATH_MAX], *v; if (Current_mission) free_mission(); MALLOC(Current_mission, Mission, 1); if (!Current_mission) return 0; *(mle *) Current_mission = *mission; Current_mission->path = d_strdup(mission->path); Current_mission->filename = Current_mission->path + (mission->filename - mission->path); Current_mission->n_secret_levels = 0; Current_mission->enhanced = 0; //init vars Last_level = 0; Last_secret_level = 0; memset(&Briefing_text_filename, '\0', sizeof(Briefing_text_filename)); memset(&Ending_text_filename, '\0', sizeof(Ending_text_filename)); // for Descent 1 missions, load descent.hog if (EMULATING_D1) { if (!PHYSFSX_contfile_init("descent.hog", 1)) Warning("descent.hog not available, this mission may be missing some files required for briefings and exit sequence\n"); if (!stricmp(Current_mission_filename, D1_MISSION_FILENAME)) return load_mission_d1(); } if (PLAYING_BUILTIN_MISSION) { switch (Current_mission->builtin_hogsize) { case SHAREWARE_MISSION_HOGSIZE: case MAC_SHARE_MISSION_HOGSIZE: strcpy(Briefing_text_filename,BIMD2_BRIEFING_FILE_SHARE); strcpy(Ending_text_filename,BIMD2_ENDING_FILE_SHARE); return load_mission_shareware(); break; case OEM_MISSION_HOGSIZE: strcpy(Briefing_text_filename,BIMD2_BRIEFING_FILE_OEM); strcpy(Ending_text_filename,BIMD2_ENDING_FILE_OEM); return load_mission_oem(); break; default: Int3(); // fall through case FULL_MISSION_HOGSIZE: case FULL_10_MISSION_HOGSIZE: case MAC_FULL_MISSION_HOGSIZE: strcpy(Briefing_text_filename,BIMD2_BRIEFING_FILE); // continue on... (use d2.mn2 from hogfile) break; } } //read mission from file switch (mission->location) { case ML_MISSIONDIR: strcpy(buf,MISSION_DIR); break; default: Int3(); //fall through case ML_CURDIR: strcpy(buf,""); break; } strcat(buf, mission->path); if (mission->descent_version == 2) strcat(buf,".mn2"); else strcat(buf,".msn"); PHYSFSEXT_locateCorrectCase(buf); mfile = PHYSFSX_openReadBuffered(buf); if (mfile == NULL) { free_mission(); return 0; //error! } //for non-builtin missions, load HOG if (!PLAYING_BUILTIN_MISSION) { strcpy(buf+strlen(buf)-4,".hog"); //change extension PHYSFSEXT_locateCorrectCase(buf); if (PHYSFSX_exists(buf,1)) PHYSFSX_contfile_init(buf, 0); snprintf(Briefing_text_filename, sizeof(Briefing_text_filename), "%s.tex",Current_mission_filename); if (!PHYSFSX_exists(Briefing_text_filename,1)) snprintf(Briefing_text_filename, sizeof(Briefing_text_filename), "%s.txb",Current_mission_filename); snprintf(Ending_text_filename, sizeof(Ending_text_filename), "%s.tex",Current_mission_filename); if (!PHYSFSX_exists(Ending_text_filename,1)) snprintf(Ending_text_filename, sizeof(Ending_text_filename), "%s.txb",Current_mission_filename); } while (PHYSFSX_fgets(buf,sizeof(buf),mfile)) { if (istok(buf,"name") && !Current_mission->enhanced) { Current_mission->enhanced = 0; continue; //already have name, go to next line } if (istok(buf,"xname") && !Current_mission->enhanced) { Current_mission->enhanced = 1; continue; //already have name, go to next line } if (istok(buf,"zname") && !Current_mission->enhanced) { Current_mission->enhanced = 2; continue; //already have name, go to next line } else if (istok(buf,"type")) continue; //already have name, go to next line else if (istok(buf,"briefing")) { if ((v = get_value(buf)) != NULL) { add_term(v); if (strlen(v) < FILENAME_LEN && strlen(v) > 0) { char *tmp, *ptr; MALLOC(tmp, char, FILENAME_LEN); snprintf(tmp, FILENAME_LEN, "%s", v); if ((ptr = strrchr(tmp, '.'))) // if there's a filename extension, kill it. No one knows it's the right one. *ptr = '\0'; strncat(tmp, ".tex", sizeof(char)*FILENAME_LEN); // apply tex-extenstion if (PHYSFSX_exists(tmp,1)) // check if this file exists ... snprintf(Briefing_text_filename, FILENAME_LEN, "%s", tmp); // ... and apply ... else // ... otherwise ... { if ((ptr = strrchr(tmp, '.'))) *ptr = '\0'; strncat(tmp, ".txb", sizeof(char)*FILENAME_LEN); // apply txb extension if (PHYSFSX_exists(tmp,1)) // check if this file exists ... snprintf(Briefing_text_filename, FILENAME_LEN, "%s", tmp); // ... and apply ... } d_free(tmp); } } } else if (istok(buf,"ending")) { if ((v = get_value(buf)) != NULL) { add_term(v); if (strlen(v) < FILENAME_LEN && strlen(v) > 0) { char *tmp, *ptr; MALLOC(tmp, char, FILENAME_LEN); snprintf(tmp, FILENAME_LEN, "%s", v); if ((ptr = strrchr(tmp, '.'))) // if there's a filename extension, kill it. No one knows it's the right one. *ptr = '\0'; strncat(tmp, ".tex", sizeof(char)*FILENAME_LEN); // apply tex-extenstion if (PHYSFSX_exists(tmp,1)) // check if this file exists ... snprintf(Briefing_text_filename, FILENAME_LEN, "%s", tmp); // ... and apply ... else // ... otherwise ... { if ((ptr = strrchr(tmp, '.'))) *ptr = '\0'; strncat(tmp, ".txb", sizeof(char)*FILENAME_LEN); // apply txb extension if (PHYSFSX_exists(tmp,1)) // check if this file exists ... snprintf(Ending_text_filename, FILENAME_LEN, "%s", tmp); // ... and apply ... } d_free(tmp); } } } else if (istok(buf,"num_levels")) { if ((v=get_value(buf))!=NULL) { int n_levels,i; n_levels = atoi(v); for (i=0;i<n_levels;i++) { PHYSFSX_fgets(buf,sizeof(buf),mfile); add_term(buf); if (strlen(buf) <= 12) { strcpy(Level_names[i],buf); Last_level++; } else break; } } } else if (istok(buf,"num_secrets")) { if ((v=get_value(buf))!=NULL) { int i; N_secret_levels = atoi(v); Assert(N_secret_levels <= MAX_SECRET_LEVELS_PER_MISSION); for (i=0;i<N_secret_levels;i++) { char *t; PHYSFSX_fgets(buf,sizeof(buf),mfile); if ((t=strchr(buf,','))!=NULL) *t++=0; else break; add_term(buf); if (strlen(buf) <= 12) { strcpy(Secret_level_names[i],buf); Secret_level_table[i] = atoi(t); if (Secret_level_table[i]<1 || Secret_level_table[i]>Last_level) break; Last_secret_level--; } else break; } } } } PHYSFS_close(mfile); if (Last_level <= 0) { free_mission(); //no valid mission loaded return 0; } // re-read default HAM file, in case this mission brings it's own version of it free_polygon_models(); read_hamfile(); if (Current_mission->enhanced) { char t[50]; sprintf(t,"%s.ham",Current_mission_filename); bm_read_extra_robots(t, Current_mission->enhanced); init_extra_robot_movie(Current_mission_filename); } return 1; }
int main(int argc, char *argv[]) { mem_init(); #ifdef __LINUX__ error_init(NULL); #else error_init(msgbox_error); set_warn_func(msgbox_warning); #endif PHYSFSX_init(argc, argv); con_init(); // Initialise the console setbuf(stdout, NULL); // unbuffered output via printf #ifdef _WIN32 freopen( "CON", "w", stdout ); freopen( "CON", "w", stderr ); #endif if (GameArg.SysShowCmdHelp) { print_commandline_help(); return(0); } printf("\nType %s -help' for a list of command-line options.\n\n", PROGNAME); PHYSFSX_listSearchPathContent(); if (!PHYSFSX_checkSupportedArchiveTypes()) return(0); if (! PHYSFSX_contfile_init("descent2.hog", 1)) { if (! PHYSFSX_contfile_init("d2demo.hog", 1)) #define DXX_NAME_NUMBER "2" #define DXX_HOGFILE_NAMES "descent2.hog or d2demo.hog" #if defined(__unix__) && !defined(__APPLE__) #define DXX_HOGFILE_PROGRAM_DATA_DIRECTORY \ "\t$HOME/.d" DXX_NAME_NUMBER "x-rebirth\n" \ "\t" SHAREPATH "\n" #else #define DXX_HOGFILE_PROGRAM_DATA_DIRECTORY \ "\tDirectory containing D" DXX_NAME_NUMBER "X\n" #endif #if (defined(__APPLE__) && defined(__MACH__)) || defined(macintosh) #define DXX_HOGFILE_APPLICATION_BUNDLE \ "\tIn 'Resources' inside the application bundle\n" #else #define DXX_HOGFILE_APPLICATION_BUNDLE "" #endif #define DXX_MISSING_HOGFILE_ERROR_TEXT \ "Could not find a valid hog file (" DXX_HOGFILE_NAMES ")\nPossible locations are:\n" \ DXX_HOGFILE_PROGRAM_DATA_DIRECTORY \ "\tIn a subdirectory called 'Data'\n" \ DXX_HOGFILE_APPLICATION_BUNDLE \ "Or use the -hogdir option to specify an alternate location." Error(DXX_MISSING_HOGFILE_ERROR_TEXT); } load_text(); //print out the banner title con_printf(CON_NORMAL, "%s%s %s\n", DESCENT_VERSION, PHYSFSX_exists(MISSION_DIR "d2x.hog",1) ? " Vertigo Enhanced" : "", g_descent_build_datetime); // D2X version con_printf(CON_NORMAL, "This is a MODIFIED version of Descent 2, based on %s.\n", BASED_VERSION); con_printf(CON_NORMAL, "%s\n%s\n",TXT_COPYRIGHT,TXT_TRADEMARK); con_printf(CON_NORMAL, "Copyright (C) 1999 Peter Hawkins, 2002 Bradley Bell, 2005-2011 Christian Beckhaeuser\n\n"); if (GameArg.DbgVerbose) con_printf(CON_VERBOSE,"%s%s", TXT_VERBOSE_1, "\n"); ReadConfigFile(); PHYSFSX_addArchiveContent(); arch_init(); select_tmap(GameArg.DbgTexMap); Lighting_on = 1; con_printf(CON_VERBOSE, "Going into graphics mode...\n"); gr_set_mode(Game_screen_mode); // Load the palette stuff. Returns non-zero if error. con_printf(CON_DEBUG, "Initializing palette system...\n" ); gr_use_palette_table(D2_DEFAULT_PALETTE ); con_printf(CON_DEBUG, "Initializing font system...\n" ); gamefont_init(); // must load after palette data loaded. set_default_handler(standard_handler); con_printf( CON_DEBUG, "Initializing movie libraries...\n" ); init_movies(); //init movie libraries show_titles(); set_screen_mode(SCREEN_MENU); con_printf( CON_DEBUG, "\nDoing gamedata_init..." ); gamedata_init(); #ifdef EDITOR if (GameArg.EdiSaveHoardData) { save_hoard_data(); exit(1); } #endif if (GameArg.DbgNoRun) return(0); con_printf( CON_DEBUG, "\nInitializing texture caching system..." ); texmerge_init( 10 ); // 10 cache bitmaps piggy_init_pigfile("groupa.pig"); //get correct pigfile con_printf( CON_DEBUG, "\nRunning game...\n" ); init_game(); Players[Player_num].callsign[0] = '\0'; // If built with editor, option to auto-load a level and quit game // to write certain data. #ifdef EDITOR if (GameArg.EdiAutoLoad) { strcpy(Auto_file, GameArg.EdiAutoLoad); strcpy(Players[0].callsign, "dummy"); } else #endif { if(GameArg.SysPilot) { char filename[32] = ""; int j; if (GameArg.SysUsePlayersDir) strcpy(filename, "Players/"); strncat(filename, GameArg.SysPilot, 12); filename[8 + 12] = '\0'; // unfortunately strncat doesn't put the terminating 0 on the end if it reaches 'n' for (j = GameArg.SysUsePlayersDir? 8 : 0; filename[j] != '\0'; j++) { switch (filename[j]) { case ' ': filename[j] = '\0'; } } if(!strstr(filename,".plr")) // if player hasn't specified .plr extension in argument, add it strcat(filename,".plr"); if(PHYSFSX_exists(filename,0)) { strcpy(strstr(filename,".plr"),"\0"); strcpy(Players[Player_num].callsign, GameArg.SysUsePlayersDir? &filename[8] : filename); read_player_file(); WriteConfigFile(); } } } #ifdef EDITOR if (GameArg.EdiAutoLoad) { strcpy((char *)&Level_names[0], Auto_file); LoadLevel(1, 1); } else #endif { Game_mode = GM_GAME_OVER; DoMenu(); } setjmp(LeaveEvents); while (window_get_front()) // Send events to windows and the default handler event_process(); // Tidy up - avoids a crash on exit { window *wind; show_menus(); while ((wind = window_get_front())) window_close(wind); } WriteConfigFile(); show_order_form(); con_printf( CON_DEBUG, "\nCleanup...\n" ); close_game(); texmerge_close(); gamedata_close(); gamefont_close(); free_text(); args_exit(); newmenu_free_background(); free_mission(); PHYSFSX_removeArchiveContent(); return(0); //presumably successful exit }
void show_titles(void) { #if defined(DXX_BUILD_DESCENT_I) songs_play_song(SONG_TITLE, 1); #endif if (CGameArg.SysNoTitles) return; #if defined(DXX_BUILD_DESCENT_I) show_first_found_title_screen( "macplay.pcx", // Mac Shareware "mplaycd.pcx", // Mac Registered "iplogo1.pcx" // PC. Only down here because it's lowres ;-) ); const bool resolution_at_least_640_480 = (SWIDTH >= 640 && SHEIGHT >= 480); auto &logo_hires_pcx = "logoh.pcx"; auto &descent_hires_pcx = "descenth.pcx"; show_title_screen((resolution_at_least_640_480 && PHYSFSX_exists(logo_hires_pcx, 1)) ? logo_hires_pcx : "logo.pcx", 1, 1); show_title_screen((resolution_at_least_640_480 && PHYSFSX_exists(descent_hires_pcx, 1)) ? descent_hires_pcx : "descent.pcx", 1, 1); #elif defined(DXX_BUILD_DESCENT_II) int played=MOVIE_NOT_PLAYED; //default is not played int song_playing = 0; #define MOVIE_REQUIRED 1 //(!is_D2_OEM && !is_SHAREWARE && !is_MAC_SHARE) // causes segfault const auto hiresmode = HIRESMODE; { //show bundler screens played=MOVIE_NOT_PLAYED; //default is not played played = PlayMovie(NULL, "pre_i.mve",0); if (!played) { char filename[12]; strcpy(filename, hiresmode ? "pre_i1b.pcx" : "pre_i1.pcx"); while (PHYSFSX_exists(filename,0)) { show_title_screen( filename, 1, 0 ); filename[5]++; } } } played = PlayMovie("intro.tex", "intro.mve",MOVIE_REQUIRED); if (played != MOVIE_NOT_PLAYED) intro_played = 1; else { //didn't get intro movie, try titles played = PlayMovie(NULL, "titles.mve",MOVIE_REQUIRED); if (played == MOVIE_NOT_PLAYED) { con_puts(CON_DEBUG, "Playing title song..."); songs_play_song( SONG_TITLE, 1); song_playing = 1; con_puts(CON_DEBUG, "Showing logo screens..."); show_first_found_title_screen( hiresmode ? "iplogo1b.pcx" : "iplogo1.pcx", // OEM "iplogo1.pcx", // SHAREWARE "mplogo.pcx" // MAC SHAREWARE ); show_first_found_title_screen( hiresmode ? "logob.pcx" : "logo.pcx", // OEM "logo.pcx", // SHAREWARE "plogo.pcx" // MAC SHAREWARE ); } } { //show bundler movie or screens played=MOVIE_NOT_PLAYED; //default is not played //check if OEM movie exists, so we don't stop the music if it doesn't if (RAIIPHYSFS_File{PHYSFS_openRead("oem.mve")}) { played = PlayMovie(NULL, "oem.mve",0); song_playing = 0; //movie will kill sound } if (!played) { char filename[12]; strcpy(filename, hiresmode ? "oem1b.pcx" : "oem1.pcx"); while (PHYSFSX_exists(filename,0)) { show_title_screen( filename, 1, 0 ); filename[3]++; } } } if (!song_playing) { con_puts(CON_DEBUG, "Playing title song..."); songs_play_song( SONG_TITLE, 1); } con_puts(CON_DEBUG, "Showing logo screen..."); const auto filename = hiresmode ? "descentb.pcx" : "descent.pcx"; if (PHYSFSX_exists(filename,1)) show_title_screen(filename, 1, 1); #endif }
int songs_play_song( int songnum, int repeat ) { songs_init(); if (!Songs_initialized) return 0; switch (GameCfg.MusicType) { case MUSIC_TYPE_BUILTIN: { // EXCEPTION: If SONG_ENDLEVEL is not available, continue playing level song. if (Song_playing >= SONG_FIRST_LEVEL_SONG && songnum == SONG_ENDLEVEL && !PHYSFSX_exists(BIMSongs[songnum].filename, 1)) return Song_playing; Song_playing = -1; #ifdef _WIN32 if (GameArg.SndDisableSdlMixer) { if (digi_win32_play_midi_song( BIMSongs[songnum].filename, repeat )) // NOTE: If SDL_mixer active, this will still be called in mix_play_file in case file is hmp { Song_playing = songnum; } } else #endif #ifdef USE_SDLMIXER { if (mix_play_file(BIMSongs[songnum].filename, repeat, NULL)) { Song_playing = songnum; } } #endif break; } case MUSIC_TYPE_REDBOOK: { int num_tracks = RBAGetNumberOfTracks(); Song_playing = -1; if ((songnum < SONG_ENDGAME) && (songnum + 2 <= num_tracks)) { if (RBAPlayTracks(songnum + 2, songnum + 2, repeat ? redbook_repeat_func : NULL)) { Redbook_playing = songnum + 2; Song_playing = songnum; } } else if ((songnum == SONG_ENDGAME) && (REDBOOK_ENDGAME_TRACK <= num_tracks)) // The endgame track is the last track { if (RBAPlayTracks(REDBOOK_ENDGAME_TRACK, REDBOOK_ENDGAME_TRACK, repeat ? redbook_repeat_func : NULL)) { Redbook_playing = REDBOOK_ENDGAME_TRACK; Song_playing = songnum; } } else if ((songnum > SONG_ENDGAME) && (songnum + 1 <= num_tracks)) { if (RBAPlayTracks(songnum + 1, songnum + 1, repeat ? redbook_repeat_func : NULL)) { Redbook_playing = songnum + 1; Song_playing = songnum; } } break; } #ifdef USE_SDLMIXER case MUSIC_TYPE_CUSTOM: { // EXCEPTION: If SONG_ENDLEVEL is undefined, continue playing level song. if (Song_playing >= SONG_FIRST_LEVEL_SONG && songnum == SONG_ENDLEVEL && !strlen(GameCfg.CMMiscMusic[songnum])) return Song_playing; Song_playing = -1; if (mix_play_file(GameCfg.CMMiscMusic[songnum], repeat, NULL)) Song_playing = songnum; break; } #endif default: Song_playing = -1; break; } // If we couldn't play the song, most likely because it wasn't specified, play no music. if (Song_playing == -1) songs_stop_all(); return Song_playing; }
int load_mine_data_compiled(PHYSFS_file *LoadFile) { int i, segnum, sidenum; ubyte compiled_version; short temp_short; ushort temp_ushort = 0; ubyte bit_mask; d1_pig_present = PHYSFSX_exists(D1_PIGFILE,1); #if 0 // the following will be deleted once reading old pigfiles works reliably if (d1_pig_present) { PHYSFS_file * d1_Piggy_fp = PHYSFSX_openReadBuffered( D1_PIGFILE ); switch (PHYSFS_fileLength(d1_Piggy_fp)) { case D1_SHARE_BIG_PIGSIZE: case D1_SHARE_10_PIGSIZE: case D1_SHARE_PIGSIZE: case D1_10_BIG_PIGSIZE: case D1_10_PIGSIZE: //d1_pig_present = 0; } PHYSFS_close (d1_Piggy_fp); } #endif if (!strcmp(strchr(Gamesave_current_filename, '.'), ".sdl")) New_file_format_load = 0; // descent 1 shareware else New_file_format_load = 1; // For compiled levels, textures map to themselves, prevent tmap_override always being gray, // bug which Matt and John refused to acknowledge, so here is Mike, fixing it. #ifdef EDITOR for (i=0; i<MAX_TEXTURES; i++) tmap_xlate_table[i] = i; #endif // memset( Segments, 0, sizeof(segment)*MAX_SEGMENTS ); fuelcen_reset(); //=============================== Reading part ============================== compiled_version = PHYSFSX_readByte(LoadFile); (void)compiled_version; if (New_file_format_load) Num_vertices = PHYSFSX_readShort(LoadFile); else Num_vertices = PHYSFSX_readInt(LoadFile); Assert( Num_vertices <= MAX_VERTICES ); if (New_file_format_load) Num_segments = PHYSFSX_readShort(LoadFile); else Num_segments = PHYSFSX_readInt(LoadFile); Assert( Num_segments <= MAX_SEGMENTS ); for (i = 0; i < Num_vertices; i++) PHYSFSX_readVector( &(Vertices[i]), LoadFile); for (segnum=0; segnum<Num_segments; segnum++ ) { #ifdef EDITOR Segments[segnum].segnum = segnum; Segments[segnum].group = 0; #endif if (New_file_format_load) bit_mask = PHYSFSX_readByte(LoadFile); else bit_mask = 0x7f; // read all six children and special stuff... if (Gamesave_current_version == 5) { // d2 SHAREWARE level read_special(segnum,bit_mask,LoadFile); read_verts(segnum,LoadFile); read_children(segnum,bit_mask,LoadFile); } else { read_children(segnum,bit_mask,LoadFile); read_verts(segnum,LoadFile); if (Gamesave_current_version <= 1) { // descent 1 level read_special(segnum,bit_mask,LoadFile); } } Segments[segnum].objects = -1; if (Gamesave_current_version <= 5) { // descent 1 thru d2 SHAREWARE level // Read fix Segments[segnum].static_light (shift down 5 bits, write as short) temp_ushort = PHYSFSX_readShort(LoadFile); Segment2s[segnum].static_light = ((fix)temp_ushort) << 4; //PHYSFS_read( LoadFile, &Segments[segnum].static_light, sizeof(fix), 1 ); } // Read the walls as a 6 byte array for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++ ) { Segments[segnum].sides[sidenum].pad = 0; } if (New_file_format_load) bit_mask = PHYSFSX_readByte(LoadFile); else bit_mask = 0x3f; // read all six sides for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) { ubyte byte_wallnum; if (bit_mask & (1 << sidenum)) { byte_wallnum = PHYSFSX_readByte(LoadFile); if ( byte_wallnum == 255 ) Segments[segnum].sides[sidenum].wall_num = -1; else Segments[segnum].sides[sidenum].wall_num = byte_wallnum; } else Segments[segnum].sides[sidenum].wall_num = -1; } for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++ ) { if ( (Segments[segnum].children[sidenum]==-1) || (Segments[segnum].sides[sidenum].wall_num!=-1) ) { // Read short Segments[segnum].sides[sidenum].tmap_num; if (New_file_format_load) { temp_ushort = PHYSFSX_readShort(LoadFile); Segments[segnum].sides[sidenum].tmap_num = temp_ushort & 0x7fff; } else Segments[segnum].sides[sidenum].tmap_num = PHYSFSX_readShort(LoadFile); if (Gamesave_current_version <= 1) Segments[segnum].sides[sidenum].tmap_num = convert_d1_tmap_num(Segments[segnum].sides[sidenum].tmap_num); if (New_file_format_load && !(temp_ushort & 0x8000)) Segments[segnum].sides[sidenum].tmap_num2 = 0; else { // Read short Segments[segnum].sides[sidenum].tmap_num2; Segments[segnum].sides[sidenum].tmap_num2 = PHYSFSX_readShort(LoadFile); if (Gamesave_current_version <= 1 && Segments[segnum].sides[sidenum].tmap_num2 != 0) Segments[segnum].sides[sidenum].tmap_num2 = convert_d1_tmap_num(Segments[segnum].sides[sidenum].tmap_num2); } // Read uvl Segments[segnum].sides[sidenum].uvls[4] (u,v>>5, write as short, l>>1 write as short) for (i=0; i<4; i++ ) { temp_short = PHYSFSX_readShort(LoadFile); Segments[segnum].sides[sidenum].uvls[i].u = ((fix)temp_short) << 5; temp_short = PHYSFSX_readShort(LoadFile); Segments[segnum].sides[sidenum].uvls[i].v = ((fix)temp_short) << 5; temp_ushort = PHYSFSX_readShort(LoadFile); Segments[segnum].sides[sidenum].uvls[i].l = ((fix)temp_ushort) << 1; //PHYSFS_read( LoadFile, &Segments[segnum].sides[sidenum].uvls[i].l, sizeof(fix), 1 ); } } else { Segments[segnum].sides[sidenum].tmap_num = 0; Segments[segnum].sides[sidenum].tmap_num2 = 0; for (i=0; i<4; i++ ) { Segments[segnum].sides[sidenum].uvls[i].u = 0; Segments[segnum].sides[sidenum].uvls[i].v = 0; Segments[segnum].sides[sidenum].uvls[i].l = 0; } } } } #if 0 { FILE *fp; fp = fopen("segments.out", "wt"); for (i = 0; i <= Highest_segment_index; i++) { side sides[MAX_SIDES_PER_SEGMENT]; // 6 sides short children[MAX_SIDES_PER_SEGMENT]; // indices of 6 children segments, front, left, top, right, bottom, back short verts[MAX_VERTICES_PER_SEGMENT]; // vertex ids of 4 front and 4 back vertices int objects; // pointer to objects in this segment for (j = 0; j < MAX_SIDES_PER_SEGMENT; j++) { sbyte type; // replaces num_faces and tri_edge, 1 = quad, 2 = 0:2 triangulation, 3 = 1:3 triangulation ubyte pad; //keep us longword alligned short wall_num; short tmap_num; short tmap_num2; uvl uvls[4]; vms_vector normals[2]; // 2 normals, if quadrilateral, both the same. fprintf(fp, "%d\n", Segments[i].sides[j].type); fprintf(fp, "%d\n", Segments[i].sides[j].pad); fprintf(fp, "%d\n", Segments[i].sides[j].wall_num); fprintf(fp, "%d\n", Segments[i].tmap_num); } fclose(fp); } } #endif Highest_vertex_index = Num_vertices-1; Highest_segment_index = Num_segments-1; validate_segment_all(); // Fill in side type and normals. for (i=0; i<Num_segments; i++) { if (Gamesave_current_version > 5) segment2_read(&Segment2s[i], LoadFile); fuelcen_activate( &Segments[i], Segment2s[i].special ); } reset_objects(1); //one object, the player return 0; }
int properties_init() { int sbytes = 0; char temp_name_read[16]; char temp_name[16]; grs_bitmap temp_bitmap; digi_sound temp_sound; DiskBitmapHeader bmh; DiskSoundHeader sndh; int header_size, N_bitmaps, N_sounds; int i,size; int Pigdata_start; int pigsize; int retval; hashtable_init( &AllBitmapsNames, MAX_BITMAP_FILES ); hashtable_init( &AllDigiSndNames, MAX_SOUND_FILES ); for (i=0; i<MAX_SOUND_FILES; i++ ) { #ifdef ALLEGRO GameSounds[i].len = 0; #else GameSounds[i].length = 0; #endif GameSounds[i].data = NULL; SoundOffset[i] = 0; //added on 11/13/99 by Victor Rachels to ready for changing freq GameSounds[i].bits = 0; GameSounds[i].freq = 0; //end this section addition - VR } for (i=0; i<MAX_BITMAP_FILES; i++ ) { GameBitmapXlat[i] = i; GameBitmaps[i].bm_flags = BM_FLAG_PAGED_OUT; } if ( !bogus_bitmap_initialized ) { int i; ubyte c; bogus_bitmap_initialized = 1; c = gr_find_closest_color( 0, 0, 63 ); for (i=0; i<4096; i++ ) bogus_data[i] = c; c = gr_find_closest_color( 63, 0, 0 ); // Make a big red X ! for (i=0; i<64; i++ ) { bogus_data[i*64+i] = c; bogus_data[i*64+(63-i)] = c; } gr_init_bitmap (&bogus_bitmap, 0, 0, 0, 64, 64, 64, bogus_data); piggy_register_bitmap( &bogus_bitmap, "bogus", 1 ); #ifdef ALLEGRO bogus_sound.len = 64*64; #else bogus_sound.length = 64*64; #endif bogus_sound.data = bogus_data; //added on 11/13/99 by Victor Rachels to ready for changing freq bogus_sound.freq = 11025; bogus_sound.bits = 8; //end this section addition - VR GameBitmapOffset[0] = 0; } Piggy_fp = PHYSFSX_openReadBuffered(DEFAULT_PIGFILE_REGISTERED); if (Piggy_fp==NULL) { if (!PHYSFSX_exists("BITMAPS.TBL",1) && !PHYSFSX_exists("BITMAPS.BIN",1)) Error("Cannot find " DEFAULT_PIGFILE_REGISTERED " or BITMAPS.TBL"); return 1; // need to run gamedata_read_tbl } pigsize = PHYSFS_fileLength(Piggy_fp); switch (pigsize) { case D1_SHARE_BIG_PIGSIZE: case D1_SHARE_10_PIGSIZE: case D1_SHARE_PIGSIZE: PCSharePig = 1; Pigdata_start = 0; break; case D1_10_BIG_PIGSIZE: case D1_10_PIGSIZE: Pigdata_start = 0; break; default: Warning("Unknown size for " DEFAULT_PIGFILE_REGISTERED); Int3(); // fall through case D1_MAC_PIGSIZE: case D1_MAC_SHARE_PIGSIZE: MacPig = 1; case D1_PIGSIZE: case D1_OEM_PIGSIZE: Pigdata_start = PHYSFSX_readInt(Piggy_fp ); break; } HiresGFXAvailable = MacPig; // for now at least if (PCSharePig) retval = PIGGY_PC_SHAREWARE; // run gamedata_read_tbl in shareware mode else if (GameArg.EdiNoBm || (!PHYSFSX_exists("BITMAPS.TBL",1) && !PHYSFSX_exists("BITMAPS.BIN",1))) { properties_read_cmp( Piggy_fp ); // Note connection to above if!!! for (i = 0; i < MAX_BITMAP_FILES; i++) { GameBitmapXlat[i] = PHYSFSX_readShort(Piggy_fp); if (PHYSFS_eof(Piggy_fp)) break; } retval = 0; // don't run gamedata_read_tbl } else retval = 1; // run gamedata_read_tbl PHYSFSX_fseek( Piggy_fp, Pigdata_start, SEEK_SET ); size = PHYSFS_fileLength(Piggy_fp) - Pigdata_start; N_bitmaps = PHYSFSX_readInt(Piggy_fp); size -= sizeof(int); N_sounds = PHYSFSX_readInt(Piggy_fp); size -= sizeof(int); header_size = (N_bitmaps*sizeof(DiskBitmapHeader)) + (N_sounds*sizeof(DiskSoundHeader)); for (i=0; i<N_bitmaps; i++ ) { DiskBitmapHeader_read(&bmh, Piggy_fp); GameBitmapFlags[i+1] = 0; if ( bmh.flags & BM_FLAG_TRANSPARENT ) GameBitmapFlags[i+1] |= BM_FLAG_TRANSPARENT; if ( bmh.flags & BM_FLAG_SUPER_TRANSPARENT ) GameBitmapFlags[i+1] |= BM_FLAG_SUPER_TRANSPARENT; if ( bmh.flags & BM_FLAG_NO_LIGHTING ) GameBitmapFlags[i+1] |= BM_FLAG_NO_LIGHTING; if ( bmh.flags & BM_FLAG_RLE ) GameBitmapFlags[i+1] |= BM_FLAG_RLE; GameBitmapOffset[i+1] = bmh.offset + header_size + (sizeof(int)*2) + Pigdata_start; Assert( (i+1) == Num_bitmap_files ); //size -= sizeof(DiskBitmapHeader); memcpy( temp_name_read, bmh.name, 8 ); temp_name_read[8] = 0; if ( bmh.dflags & DBM_FLAG_ABM ) sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & 63 ); else strcpy( temp_name, temp_name_read ); memset( &temp_bitmap, 0, sizeof(grs_bitmap) ); gr_init_bitmap( &temp_bitmap, 0, 0, 0, (bmh.dflags & DBM_FLAG_LARGE) ? bmh.width + 256 : bmh.width, bmh.height, (bmh.dflags & DBM_FLAG_LARGE) ? bmh.width + 256 : bmh.width, Piggy_bitmap_cache_data); temp_bitmap.bm_flags |= BM_FLAG_PAGED_OUT; temp_bitmap.avg_color = bmh.avg_color; if (MacPig) { // HACK HACK HACK!!!!! if (!strnicmp(bmh.name, "cockpit", 7) || !strnicmp(bmh.name, "status", 6) || !strnicmp(bmh.name, "rearview", 8)) { temp_bitmap.bm_w = temp_bitmap.bm_rowsize = 640; if (GameBitmapFlags[i+1] & BM_FLAG_RLE) GameBitmapFlags[i+1] |= BM_FLAG_RLE_BIG; } if (!strnicmp(bmh.name, "cockpit", 7) || !strnicmp(bmh.name, "rearview", 8)) temp_bitmap.bm_h = 480; } piggy_register_bitmap( &temp_bitmap, temp_name, 1 ); } for (i=0; !MacPig && i<N_sounds; i++ ) { DiskSoundHeader_read(&sndh, Piggy_fp); //size -= sizeof(DiskSoundHeader); #ifdef ALLEGRO temp_sound.len = sndh.length; #else temp_sound.length = sndh.length; #endif //added on 11/13/99 by Victor Rachels to ready for changing freq temp_sound.bits = 8; temp_sound.freq = 11025; //end this section addition - VR temp_sound.data = (ubyte *)(sndh.offset + header_size + (sizeof(int)*2)+Pigdata_start); SoundOffset[Num_sound_files] = sndh.offset + header_size + (sizeof(int)*2)+Pigdata_start; if (PCSharePig) SoundCompressed[Num_sound_files] = sndh.data_length; memcpy( temp_name_read, sndh.name, 8 ); temp_name_read[8] = 0; piggy_register_sound( &temp_sound, temp_name_read, 1 ); sbytes += sndh.length; } if (!MacPig) { SoundBits = d_malloc( sbytes + 16 ); if ( SoundBits == NULL ) Error( "Not enough memory to load DESCENT.PIG sounds\n"); } #if 1 //def EDITOR Piggy_bitmap_cache_size = size - header_size - sbytes + 16; Assert( Piggy_bitmap_cache_size > 0 ); #else Piggy_bitmap_cache_size = PIGGY_BUFFER_SIZE; if (GameArg.SysLowMem) Piggy_bitmap_cache_size = PIGGY_SMALL_BUFFER_SIZE; #endif BitmapBits = d_malloc( Piggy_bitmap_cache_size ); if ( BitmapBits == NULL ) Error( "Not enough memory to load DESCENT.PIG bitmaps\n" ); Piggy_bitmap_cache_data = BitmapBits; Piggy_bitmap_cache_next = 0; return retval; }
//loads a level (.LVL) file from disk //returns 0 if success, else error code int load_level(const char * filename_passed) { #ifdef EDITOR int use_compiled_level=1; #endif PHYSFS_file * LoadFile; char filename[PATH_MAX]; int sig, minedata_offset, gamedata_offset, hostagetext_offset; int mine_err, game_err; #ifdef NETWORK int i; #endif #ifdef NETWORK if (Game_mode & GM_NETWORK) { for (i=0;i<MAX_POWERUP_TYPES;i++) { MaxPowerupsAllowed[i]=0; PowerupsInMine[i]=0; } } #endif #ifdef COMPACT_SEGS ncache_flush(); #endif #ifndef RELEASE Level_being_loaded = filename_passed; #endif strcpy(filename,filename_passed); #ifdef EDITOR //if we have the editor, try the LVL first, no matter what was passed. //if we don't have an LVL, try what was passed or SDL/RDL //if we don't have the editor, we just use what was passed change_filename_extension(filename,filename_passed,".lvl"); use_compiled_level = 0; if (!PHYSFSX_exists(filename,1)) { char *p = strrchr(filename_passed, '.'); if (d_stricmp(p, ".lvl")) strcpy(filename, filename_passed); // set to what was passed else change_filename_extension(filename, filename, ".rdl"); use_compiled_level = 1; } #endif if (!PHYSFSX_exists(filename,1)) sprintf(filename,"%s%s",MISSION_DIR,filename_passed); LoadFile = PHYSFSX_openReadBuffered( filename ); if (!LoadFile) { #ifdef EDITOR return 1; #else Error("Can't open file <%s>\n",filename); #endif } strcpy( Gamesave_current_filename, filename ); sig = PHYSFSX_readInt(LoadFile); Gamesave_current_version = PHYSFSX_readInt(LoadFile); minedata_offset = PHYSFSX_readInt(LoadFile); gamedata_offset = PHYSFSX_readInt(LoadFile); Assert(sig == MAKE_SIG('P','L','V','L')); (void)sig; if (Gamesave_current_version < 5) hostagetext_offset = PHYSFSX_readInt(LoadFile); PHYSFSX_fseek(LoadFile,minedata_offset,SEEK_SET); #ifdef EDITOR if (!use_compiled_level) mine_err = load_mine_data(LoadFile); else #endif //NOTE LINK TO ABOVE!! mine_err = load_mine_data_compiled(LoadFile); /* !!!HACK!!! * Descent 1 - Level 19: OBERON MINE has some ugly overlapping rooms (segment 484). * HACK to make this issue less visible by moving one vertex a little. */ if (Current_mission && !d_stricmp("Descent: First Strike",Current_mission_longname) && !d_stricmp("level19.rdl",filename) && PHYSFS_fileLength(LoadFile) == 136706) Vertices[1905].z =-385*F1_0; if (mine_err == -1) { //error!! PHYSFS_close(LoadFile); return 2; } PHYSFSX_fseek(LoadFile,gamedata_offset,SEEK_SET); game_err = load_game_data(LoadFile); if (game_err == -1) { //error!! PHYSFS_close(LoadFile); return 3; } (void)hostagetext_offset; //======================== CLOSE FILE ============================= PHYSFS_close( LoadFile ); #if 0 //def EDITOR #ifndef RELEASE write_game_text_file(filename); if (Errors_in_mine) { if (is_real_level(filename)) { char ErrorMessage[200]; sprintf( ErrorMessage, "Warning: %i errors in %s!\n", Errors_in_mine, Level_being_loaded ); stop_time(); gr_palette_load(gr_palette); nm_messagebox( NULL, 1, "Continue", ErrorMessage ); start_time(); } } #endif #endif #ifdef EDITOR //If an old version, ask the use if he wants to save as new version if (((LEVEL_FILE_VERSION>1) && Gamesave_current_version<LEVEL_FILE_VERSION) || mine_err==1 || game_err==1) { char ErrorMessage[200]; sprintf( ErrorMessage, "You just loaded a old version level. Would\n" "you like to save it as a current version level?"); gr_palette_load(gr_palette); if (nm_messagebox( NULL, 2, "Don't Save", "Save", ErrorMessage )==1) save_level(filename); } #endif #ifdef EDITOR if (EditorWindow) editor_status_fmt("Loaded NEW mine %s, \"%s\"",filename,Current_level_name); #endif #if !defined(NDEBUG) && !defined(COMPACT_SEGS) if (check_segment_connections()) nm_messagebox( "ERROR", 1, "Ok", "Connectivity errors detected in\n" "mine. See monochrome screen for\n" "details, and contact Matt or Mike." ); #endif return 0; }