static void game_ended(int status, fnchar *filename) { fnchar fncopy[1024], logname[1024], savedir[BUFSZ], *bp, *fname; if (status != GAME_OVER) return; show_topten(player.plname, settings.end_top, settings.end_around, settings.end_own); /* * The game ended terminally. Now it would be nice to move the saved game * out of the save/ dir and into the log/ dir, since it's only use now is as * a tropy. */ #if !defined(WIN32) /* dirname and basename may modify the input string, depending on the system */ strncpy(fncopy, filename, sizeof(fncopy)); bp = dirname(fncopy); get_gamedir(SAVE_DIR, savedir); savedir[strlen(savedir)-1] = '\0'; /* remove the trailing '/' */ if (strcmp(bp, savedir) != 0) return; /* file was not in savedir, so don't touch it */ get_gamedir(LOG_DIR, logname); strncpy(fncopy, filename, sizeof(fncopy)); fname = basename(fncopy); strncat(logname, fname, sizeof(logname)-1); /* don't care about errors: rename is nice to have, not essential */ rename(filename, logname); #else bp = wcsrchr(filename, L'\\'); get_gamedir(SAVE_DIR, savedir); if (!bp || wcsncmp(filename, savedir, wcslen(savedir))) return; get_gamedir(LOG_DIR, logname); wcsncat(logname, bp+1, 1024); /* don't care about errors: rename is nice to have, not essential */ _wrename(filename, logname); #endif }
void rungame(void) { int ret, role = initrole, race = initrace, gend = initgend, align = initalign; int fd = -1; char plname[BUFSZ]; fnchar filename[1024]; fnchar savedir[BUFSZ]; long t; if (!get_gamedir(SAVE_DIR, savedir)) { curses_raw_print("Could not find where to put the logfile for a new game."); return; } if (!player_selection(&role, &race, &gend, &align, random_player)) return; strncpy(plname, settings.plname, PL_NSIZ); /* The player name is set to "wizard" (again) in nh_start_game, so setting * it here just prevents wizmode player from being asked for a name. */ if (ui_flags.playmode == MODE_WIZARD) strcpy(plname, "wizard"); while (!plname[0]) curses_getline("what is your name?", plname); if (plname[0] == '\033') /* canceled */ return; t = (long)time(NULL); #if defined(WIN32) snwprintf(filename, 1024, L"%ls%ld_%hs.nhgame", savedir, t, plname); #else snprintf(filename, 1024, "%s%ld_%s.nhgame", savedir, t, plname); #endif fd = sys_open(filename, O_TRUNC | O_CREAT | O_RDWR, FILE_OPEN_MASK); if (fd == -1) { curses_raw_print("Could not create the logfile."); return; } create_game_windows(); if (!nh_start_game(fd, plname, role, race, gend, align, ui_flags.playmode)) { destroy_game_windows(); close(fd); return; } load_keymap(); /* need to load the keymap after the game has been started */ ret = commandloop(); free_keymap(); close(fd); destroy_game_windows(); cleanup_messages(); game_ended(ret, filename); }
/* determine the correct filename for the config file */ static int get_config_name(fnchar * buf, nh_bool ui) { buf[0] = '\0'; /* If running in connection-only mode, we can't get the options until we're already logged into the server. */ if (ui_flags.connection_only && !*ui_flags.username) return 0; #if defined(UNIX) char *envval; if (!ui) { /* check for env override first */ envval = getenv("NETHACK4OPTIONS"); if (envval) { strncpy(buf, envval, BUFSZ); return 1; } } #endif /* look in regular location */ if (!get_gamedir(CONFIG_DIR, buf)) return 0; #ifdef WIN32 wchar_t usernamew[BUFSZ]; int i = 0; while (i < BUFSZ - 2 && ui_flags.username[i]) { usernamew[i] = ui_flags.username[i]; i++; } usernamew[i] = 0; #else /* This is to avoid putting a directive inside the arguments to fnncat, * which is a macro. */ char *usernamew = ui_flags.username; #endif fnncat(buf, ui_flags.connection_only ? usernamew : ui ? FN("curses.conf") : FN("NetHack4.conf"), BUFSZ - fnlen(buf) - 1); if (ui_flags.connection_only) fnncat(buf, ui ? FN(".curses.rc") : FN(".NetHack4.rc"), BUFSZ - fnlen(buf) - 1); return 1; }
/* determine the correct filename for the config file */ static void get_config_name(fnchar *buf, nh_bool ui) { buf[0] = '\0'; #if defined(UNIX) char *envval; if (!ui) { /* check for env override first */ envval = getenv("DYNAHACKOPTIONS"); if (envval) { strncpy(buf, envval, BUFSZ); return; } } #endif /* look in regular location */ if (!get_gamedir(CONFIG_DIR, buf)) return; fnncat(buf, ui ? FN("curses.conf") : FN("DynaHack.conf"), BUFSZ); }
void replay(void) { char buf[BUFSZ]; fnchar logdir[BUFSZ], savedir[BUFSZ], filename[1024], *dir, **files; struct nh_menuitem *items; int i, n, fd, icount, size, filecount, pick[1]; enum nh_log_status status; struct nh_game_info gi; if (!get_gamedir(LOG_DIR, logdir)) logdir[0] = '\0'; if (!get_gamedir(SAVE_DIR, savedir)) savedir[0] = '\0'; if (*logdir) dir = logdir; else if (*savedir) dir = savedir; else { curses_msgwin("There are no games to replay."); return; } while (1) { filename[0] = '\0'; files = list_gamefiles(dir, &filecount); /* make sure there are some files to show */ if (!filecount) { if (dir == savedir) { curses_msgwin("There are no saved games to replay."); savedir[0] = '\0'; } else { curses_msgwin("There are no completed games to replay."); logdir[0] = '\0'; } dir = (dir == savedir) ? logdir : savedir; if (!*dir) return; continue; } icount = 0; size = filecount + 2; items = malloc(size * sizeof (struct nh_menuitem)); /* add all the files to the menu */ for (i = 0; i < filecount; i++) { fd = sys_open(files[i], O_RDWR, 0660); status = nh_get_savegame_status(fd, &gi); close(fd); describe_game(buf, status, &gi); add_menu_item(items, size, icount, (status == LS_IN_PROGRESS) ? 0 : icount + 1, buf, 0, FALSE); } if (dir == logdir && *savedir) { add_menu_txt(items, size, icount, "", MI_NORMAL); add_menu_item(items, size, icount, -1, "View saved games instead", '!', FALSE); } else if (dir == savedir && *logdir) { add_menu_txt(items, size, icount, "", MI_NORMAL); add_menu_item(items, size, icount, -1, "View saved games instead", '!', FALSE); } n = curses_display_menu(items, icount, "Pick a game to view", PICK_ONE, PLHINT_ANYWHERE, pick); free(items); filename[0] = '\0'; if (n > 0 && pick[0] != -1) fnncat(filename, files[pick[0] - 1], sizeof (filename) / sizeof (fnchar) - 1); for (i = 0; i < filecount; i++) free(files[i]); free(files); if (n <= 0) return; if (pick[0] == -1) { dir = (dir == savedir) ? logdir : savedir; continue; } /* we have a valid filename */ break; } fd = sys_open(filename, O_RDWR, 0660); replay_commandloop(fd); close(fd); }
/* ==================================================================== Load terrain types, weather information and hex tile icons. ==================================================================== */ int terrain_load( char *fname ) { int i, j, k; PData *pd, *sub, *subsub, *subsubsub; List *entries, *flags; char path[512]; char *flag, *str; char *domain = 0; int count; /* log info */ int log_dot_limit = 40; /* maximum of dots */ char log_str[128]; sprintf( path, "%s/maps/%s", get_gamedir(), fname ); if ( ( pd = parser_read_file( fname, path ) ) == 0 ) goto parser_failure; domain = determine_domain(pd, fname); locale_load_domain(domain, 0/*FIXME*/); /* get weather */ if ( !parser_get_entries( pd, "weather", &entries ) ) goto parser_failure; weather_type_count = entries->count; weather_types = calloc( weather_type_count, sizeof( Weather_Type ) ); list_reset( entries ); i = 0; while ( ( sub = list_next( entries ) ) ) { weather_types[i].id = strdup( sub->name ); if ( !parser_get_localized_string( sub, "name", domain, &weather_types[i].name ) ) goto parser_failure; if ( !parser_get_values( sub, "flags", &flags ) ) goto parser_failure; list_reset( flags ); while ( ( flag = list_next( flags ) ) ) weather_types[i].flags |= check_flag( flag, fct_terrain ); i++; } /* hex tile geometry */ if ( !parser_get_int( pd, "hex_width", &hex_w ) ) goto parser_failure; if ( !parser_get_int( pd, "hex_height", &hex_h ) ) goto parser_failure; if ( !parser_get_int( pd, "hex_x_offset", &hex_x_offset ) ) goto parser_failure; if ( !parser_get_int( pd, "hex_y_offset", &hex_y_offset ) ) goto parser_failure; /* terrain icons */ terrain_icons = calloc( 1, sizeof( Terrain_Icons ) ); if ( !parser_get_value( pd, "fog", &str, 0 ) ) goto parser_failure; sprintf( path, "terrain/%s", str ); if ( ( terrain_icons->fog = load_surf( path, SDL_SWSURFACE ) ) == 0 ) goto failure; if ( !parser_get_value( pd, "danger", &str, 0 ) ) goto parser_failure; sprintf( path, "terrain/%s", str ); if ( ( terrain_icons->danger = load_surf( path, SDL_SWSURFACE ) ) == 0 ) goto failure; if ( !parser_get_value( pd, "grid", &str, 0 ) ) goto parser_failure; sprintf( path, "terrain/%s", str ); if ( ( terrain_icons->grid = load_surf( path, SDL_SWSURFACE ) ) == 0 ) goto failure; if ( !parser_get_value( pd, "frame", &str, 0 ) ) goto parser_failure; sprintf( path, "terrain/%s", str ); if ( ( terrain_icons->select = load_surf( path, SDL_SWSURFACE ) ) == 0 ) goto failure; if ( !parser_get_value( pd, "crosshair", &str, 0 ) ) goto parser_failure; sprintf( path, "terrain/%s", str ); if ( ( terrain_icons->cross = anim_create( load_surf( path, SDL_SWSURFACE ), 1000/config.anim_speed, hex_w, hex_h, sdl.screen, 0, 0 ) ) == 0 ) goto failure; anim_hide( terrain_icons->cross, 1 ); if ( !parser_get_value( pd, "explosion", &str, 0 ) ) goto parser_failure; sprintf( path, "terrain/%s", str ); if ( ( terrain_icons->expl1 = anim_create( load_surf( path, SDL_SWSURFACE ), 50/config.anim_speed, hex_w, hex_h, sdl.screen, 0, 0 ) ) == 0 ) goto failure; anim_hide( terrain_icons->expl1, 1 ); if ( ( terrain_icons->expl2 = anim_create( load_surf( path, SDL_SWSURFACE ), 50/config.anim_speed, hex_w, hex_h, sdl.screen, 0, 0 ) ) == 0 ) goto failure; anim_hide( terrain_icons->expl2, 1 ); /* terrain sounds */ #ifdef WITH_SOUND if ( parser_get_value( pd, "explosion_sound", &str, 0 ) ) terrain_icons->wav_expl = wav_load( str, 2 ); if ( parser_get_value( pd, "select_sound", &str, 0 ) ) terrain_icons->wav_select = wav_load( str, 1 ); #endif /* terrain types */ if ( !parser_get_entries( pd, "terrain", &entries ) ) goto parser_failure; terrain_type_count = entries->count; terrain_types = calloc( terrain_type_count, sizeof( Terrain_Type ) ); list_reset( entries ); i = 0; while ( ( sub = list_next( entries ) ) ) { /* id */ terrain_types[i].id = sub->name[0]; /* name */ if ( !parser_get_localized_string( sub, "name", domain, &terrain_types[i].name ) ) goto parser_failure; /* each weather type got its own image -- if it's named 'default' we point towards the image of weather_type 0 */ terrain_types[i].images = calloc( weather_type_count, sizeof( SDL_Surface* ) ); for ( j = 0; j < weather_type_count; j++ ) { sprintf( path, "image/%s", weather_types[j].id ); if ( !parser_get_value( sub, path, &str, 0 ) ) goto parser_failure; if ( STRCMP( "default", str ) && j > 0 ) { /* just a pointer */ terrain_types[i].images[j] = terrain_types[i].images[0]; } else { sprintf( path, "terrain/%s", str ); if ( ( terrain_types[i].images[j] = load_surf( path, SDL_SWSURFACE ) ) == 0 ) goto parser_failure; SDL_SetColorKey( terrain_types[i].images[j], SDL_SRCCOLORKEY, get_pixel( terrain_types[i].images[j], 0, 0 ) ); } } /* fog image */ terrain_types[i].images_fogged = calloc( weather_type_count, sizeof( SDL_Surface* ) ); for ( j = 0; j < weather_type_count; j++ ) { if ( terrain_types[i].images[j] == terrain_types[i].images[0] && j > 0 ) { /* just a pointer */ terrain_types[i].images_fogged[j] = terrain_types[i].images_fogged[0]; } else { terrain_types[i].images_fogged[j] = create_surf( terrain_types[i].images[j]->w, terrain_types[i].images[j]->h, SDL_SWSURFACE ); FULL_DEST( terrain_types[i].images_fogged[j] ); FULL_SOURCE( terrain_types[i].images[j] ); blit_surf(); count = terrain_types[i].images[j]->w / hex_w; for ( k = 0; k < count; k++ ) { DEST( terrain_types[i].images_fogged[j], k * hex_w, 0, hex_w, hex_h ); SOURCE( terrain_icons->fog, 0, 0 ); alpha_blit_surf( FOG_ALPHA ); } SDL_SetColorKey( terrain_types[i].images_fogged[j], SDL_SRCCOLORKEY, get_pixel( terrain_types[i].images[j], 0, 0 ) ); } } /* spot cost */ terrain_types[i].spt = calloc( weather_type_count, sizeof( int ) ); if ( !parser_get_pdata( sub, "spot_cost", &subsub ) ) goto parser_failure; for ( j = 0; j < weather_type_count; j++ ) if ( !parser_get_int( subsub, weather_types[j].id, &terrain_types[i].spt[j] ) ) goto parser_failure; /* mov cost */ terrain_types[i].mov = calloc( mov_type_count * weather_type_count, sizeof( int ) ); if ( !parser_get_pdata( sub, "move_cost", &subsub ) ) goto parser_failure; for ( k = 0; k < mov_type_count; k++ ) { if ( !parser_get_pdata( subsub, mov_types[k].id, &subsubsub ) ) goto parser_failure; for ( j = 0; j < weather_type_count; j++ ) { if ( !parser_get_value( subsubsub, weather_types[j].id, &str, 0 ) ) goto parser_failure; if ( str[0] == 'X' ) terrain_types[i].mov[j + k * weather_type_count] = 0; /* impassable */ else if ( str[0] == 'A' ) terrain_types[i].mov[j + k * weather_type_count] = -1; /* costs all */ else terrain_types[i].mov[j + k * weather_type_count] = atoi( str ); /* normal cost */ } } /* entrenchment */ if ( !parser_get_int( sub, "min_entr", &terrain_types[i].min_entr ) ) goto parser_failure; if ( !parser_get_int( sub, "max_entr", &terrain_types[i].max_entr ) ) goto parser_failure; /* initiative modification */ if ( !parser_get_int( sub, "max_init", &terrain_types[i].max_ini ) ) goto parser_failure; /* flags */ terrain_types[i].flags = calloc( weather_type_count, sizeof( int ) ); if ( !parser_get_pdata( sub, "flags", &subsub ) ) goto parser_failure; for ( j = 0; j < weather_type_count; j++ ) { if ( !parser_get_values( subsub, weather_types[j].id, &flags ) ) goto parser_failure; list_reset( flags ); while ( ( flag = list_next( flags ) ) ) terrain_types[i].flags[j] |= check_flag( flag, fct_terrain ); } /* next terrain */ i++; /* LOG */ strcpy( log_str, " [ ]" ); for ( k = 0; k < i * log_dot_limit / entries->count; k++ ) log_str[3 + k] = '*'; write_text( log_font, sdl.screen, log_x, log_y, log_str, 255 ); SDL_UpdateRect( sdl.screen, log_font->last_x, log_font->last_y, log_font->last_width, log_font->last_height ); } parser_free( &pd ); /* LOG */ write_line( sdl.screen, log_font, log_str, log_x, &log_y ); refresh_screen( 0, 0, 0, 0 ); free(domain); return 1; parser_failure: fprintf( stderr, "%s\n", parser_get_error() ); failure: terrain_delete(); if ( pd ) parser_free( &pd ); free(domain); printf(tr("If data seems to be missing, please re-run the converter lgc-pg.\n")); return 0; }
nh_bool loadgame(void) { char buf[BUFSZ]; fnchar savedir[BUFSZ], filename[1024], **files; struct nh_menuitem *items; int size, icount, fd, i, n, ret, pick[1]; enum nh_log_status status; struct nh_game_info gi; if (!get_gamedir(SAVE_DIR, savedir)) { curses_raw_print("Could not find or create the save directory."); return FALSE; } files = list_gamefiles(savedir, &size); if (!size) { curses_msgwin("No saved games found."); return FALSE; } icount = 0; items = malloc(size * sizeof(struct nh_menuitem)); for (i = 0; i < size; i++) { fd = sys_open(files[i], O_RDWR, FILE_OPEN_MASK); status = nh_get_savegame_status(fd, &gi); close(fd); describe_game(buf, status, &gi); add_menu_item(items, size, icount, (status == LS_IN_PROGRESS) ? 0 : icount + 1, buf, 0, FALSE); } n = curses_display_menu(items, icount, "saved games", PICK_ONE, pick); free(items); filename[0] = '\0'; if (n > 0) fnncat(filename, files[pick[0]-1], sizeof(filename)/sizeof(fnchar)-1); for (i = 0; i < icount; i++) free(files[i]); free(files); if (n <= 0) return FALSE; fd = sys_open(filename, O_RDWR, FILE_OPEN_MASK); create_game_windows(); if (nh_restore_game(fd, NULL, FALSE) != GAME_RESTORED) { destroy_game_windows(); close(fd); if (curses_yn_function("Failed to load the save. Do you wish to delete the file?", "yn", 'n') == 'y') unlink(filename); return FALSE; } load_keymap(); /* need to load the keymap after the game has been started */ ret = commandloop(); free_keymap(); close(fd); destroy_game_windows(); cleanup_messages(); game_ended(ret, filename); return TRUE; }