1 /* 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Timothy C. Stoehr. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)save.c 8.1 (Berkeley) 5/31/93 37 * $FreeBSD: src/games/rogue/save.c,v 1.6 1999/11/30 03:49:27 billf Exp $ 38 * $DragonFly: src/games/rogue/save.c,v 1.4 2006/09/02 19:31:07 pavalos Exp $ 39 */ 40 41 /* 42 * save.c 43 * 44 * This source herein may be modified and/or distributed by anybody who 45 * so desires, with the following restrictions: 46 * 1.) No portion of this notice shall be removed. 47 * 2.) Credit shall not be taken for the creation of this source. 48 * 3.) This code is not to be traded, sold, or used for personal 49 * gain or profit. 50 * 51 */ 52 53 #include <stdio.h> 54 #include <unistd.h> 55 #include "rogue.h" 56 57 short write_failed = 0; 58 char *save_file = NULL; 59 static char save_name[80]; 60 61 extern short cur_level, max_level; 62 extern short party_room; 63 extern short foods; 64 extern boolean is_wood[]; 65 extern short cur_room; 66 extern boolean being_held; 67 extern short bear_trap; 68 extern short halluc; 69 extern short blind; 70 extern short confused; 71 extern short levitate; 72 extern short haste_self; 73 extern boolean see_invisible; 74 extern boolean detect_monster; 75 extern boolean wizard; 76 extern boolean score_only; 77 extern short m_moves; 78 79 extern boolean msg_cleared; 80 81 static void del_save_file(void); 82 static void write_pack(const object *, FILE *); 83 static void read_pack(object *, FILE *, boolean); 84 static void rw_dungeon(FILE *, boolean); 85 static void rw_id(struct id *, FILE *, int, boolean); 86 static void write_string(char *, FILE *); 87 static void read_string(char *, FILE *, size_t); 88 static void rw_rooms(FILE *, boolean); 89 static void r_read(FILE *, char *, int); 90 static void r_write(FILE *, const char *, int); 91 static boolean has_been_touched(const struct rogue_time *, 92 const struct rogue_time *); 93 94 void 95 save_game(void) 96 { 97 char fname[64]; 98 99 if (!get_input_line("file name?", save_file, fname, "game not saved", 100 0, 1)) { 101 return; 102 } 103 check_message(); 104 message(fname, 0); 105 save_into_file(fname); 106 } 107 108 void 109 save_into_file(const char *sfile) 110 { 111 FILE *fp; 112 int file_id; 113 char *name_buffer; 114 size_t len; 115 char *hptr; 116 struct rogue_time rt_buf; 117 118 if (sfile[0] == '~') { 119 if ((hptr = md_getenv("HOME"))) { 120 len = strlen(hptr) + strlen(sfile); 121 name_buffer = md_malloc(len); 122 if (name_buffer == NULL) { 123 message("out of memory for save file name", 0); 124 sfile = error_file; 125 } else { 126 strcpy(name_buffer, hptr); 127 strcat(name_buffer, sfile+1); 128 sfile = name_buffer; 129 } 130 131 } 132 } 133 /* revoke */ 134 setgid(getgid()); 135 if ( ((fp = fopen(sfile, "w")) == NULL) || 136 ((file_id = md_get_file_id(sfile)) == -1)) { 137 message("problem accessing the save file", 0); 138 return; 139 } 140 md_ignore_signals(); 141 write_failed = 0; 142 xxx(1); 143 r_write(fp, (char *) &detect_monster, sizeof(detect_monster)); 144 r_write(fp, (char *) &cur_level, sizeof(cur_level)); 145 r_write(fp, (char *) &max_level, sizeof(max_level)); 146 write_string(hunger_str, fp); 147 write_string(login_name, fp); 148 r_write(fp, (char *) &party_room, sizeof(party_room)); 149 write_pack(&level_monsters, fp); 150 write_pack(&level_objects, fp); 151 r_write(fp, (char *) &file_id, sizeof(file_id)); 152 rw_dungeon(fp, 1); 153 r_write(fp, (char *) &foods, sizeof(foods)); 154 r_write(fp, (char *) &rogue, sizeof(fighter)); 155 write_pack(&rogue.pack, fp); 156 rw_id(id_potions, fp, POTIONS, 1); 157 rw_id(id_scrolls, fp, SCROLS, 1); 158 rw_id(id_wands, fp, WANDS, 1); 159 rw_id(id_rings, fp, RINGS, 1); 160 r_write(fp, (char *) traps, (MAX_TRAPS * sizeof(trap))); 161 r_write(fp, (char *) is_wood, (WANDS * sizeof(boolean))); 162 r_write(fp, (char *) &cur_room, sizeof(cur_room)); 163 rw_rooms(fp, 1); 164 r_write(fp, (char *) &being_held, sizeof(being_held)); 165 r_write(fp, (char *) &bear_trap, sizeof(bear_trap)); 166 r_write(fp, (char *) &halluc, sizeof(halluc)); 167 r_write(fp, (char *) &blind, sizeof(blind)); 168 r_write(fp, (char *) &confused, sizeof(confused)); 169 r_write(fp, (char *) &levitate, sizeof(levitate)); 170 r_write(fp, (char *) &haste_self, sizeof(haste_self)); 171 r_write(fp, (char *) &see_invisible, sizeof(see_invisible)); 172 r_write(fp, (char *) &detect_monster, sizeof(detect_monster)); 173 r_write(fp, (char *) &wizard, sizeof(wizard)); 174 r_write(fp, (char *) &score_only, sizeof(score_only)); 175 r_write(fp, (char *) &m_moves, sizeof(m_moves)); 176 md_gct(&rt_buf); 177 rt_buf.second += 10; /* allow for some processing time */ 178 r_write(fp, (char *) &rt_buf, sizeof(rt_buf)); 179 fclose(fp); 180 181 if (write_failed) { 182 md_df(sfile); /* delete file */ 183 } else { 184 if (strcmp(sfile, save_name) == 0) 185 save_name[0] = 0; 186 clean_up(""); 187 } 188 } 189 190 static void 191 del_save_file(void) 192 { 193 if (!save_name[0]) 194 return; 195 /* revoke */ 196 setgid(getgid()); 197 md_df(save_name); 198 } 199 200 void 201 restore(const char *fname) 202 { 203 FILE *fp = NULL; 204 struct rogue_time saved_time, mod_time; 205 char buf[4]; 206 char tbuf[40]; 207 int new_file_id, saved_file_id; 208 209 if ( ((new_file_id = md_get_file_id(fname)) == -1) || 210 ((fp = fopen(fname, "r")) == NULL)) { 211 clean_up("cannot open file"); 212 } 213 if (md_link_count(fname) > 1) { 214 clean_up("file has link"); 215 } 216 xxx(1); 217 r_read(fp, (char *) &detect_monster, sizeof(detect_monster)); 218 r_read(fp, (char *) &cur_level, sizeof(cur_level)); 219 r_read(fp, (char *) &max_level, sizeof(max_level)); 220 read_string(hunger_str, fp, sizeof hunger_str); 221 222 strlcpy(tbuf, login_name, sizeof tbuf); 223 read_string(login_name, fp, sizeof login_name); 224 if (strcmp(tbuf, login_name)) { 225 clean_up("you're not the original player"); 226 } 227 228 r_read(fp, (char *) &party_room, sizeof(party_room)); 229 read_pack(&level_monsters, fp, 0); 230 read_pack(&level_objects, fp, 0); 231 r_read(fp, (char *) &saved_file_id, sizeof(saved_file_id)); 232 if (new_file_id != saved_file_id) { 233 clean_up("sorry, saved game is not in the same file"); 234 } 235 rw_dungeon(fp, 0); 236 r_read(fp, (char *) &foods, sizeof(foods)); 237 r_read(fp, (char *) &rogue, sizeof(fighter)); 238 read_pack(&rogue.pack, fp, 1); 239 rw_id(id_potions, fp, POTIONS, 0); 240 rw_id(id_scrolls, fp, SCROLS, 0); 241 rw_id(id_wands, fp, WANDS, 0); 242 rw_id(id_rings, fp, RINGS, 0); 243 r_read(fp, (char *) traps, (MAX_TRAPS * sizeof(trap))); 244 r_read(fp, (char *) is_wood, (WANDS * sizeof(boolean))); 245 r_read(fp, (char *) &cur_room, sizeof(cur_room)); 246 rw_rooms(fp, 0); 247 r_read(fp, (char *) &being_held, sizeof(being_held)); 248 r_read(fp, (char *) &bear_trap, sizeof(bear_trap)); 249 r_read(fp, (char *) &halluc, sizeof(halluc)); 250 r_read(fp, (char *) &blind, sizeof(blind)); 251 r_read(fp, (char *) &confused, sizeof(confused)); 252 r_read(fp, (char *) &levitate, sizeof(levitate)); 253 r_read(fp, (char *) &haste_self, sizeof(haste_self)); 254 r_read(fp, (char *) &see_invisible, sizeof(see_invisible)); 255 r_read(fp, (char *) &detect_monster, sizeof(detect_monster)); 256 r_read(fp, (char *) &wizard, sizeof(wizard)); 257 r_read(fp, (char *) &score_only, sizeof(score_only)); 258 r_read(fp, (char *) &m_moves, sizeof(m_moves)); 259 r_read(fp, (char *) &saved_time, sizeof(saved_time)); 260 261 if (fread(buf, sizeof(char), 1, fp) > 0) { 262 clear(); 263 clean_up("extra characters in file"); 264 } 265 266 md_gfmt(fname, &mod_time); /* get file modification time */ 267 268 if (has_been_touched(&saved_time, &mod_time)) { 269 clear(); 270 clean_up("sorry, file has been touched"); 271 } 272 if ((!wizard)) { 273 strcpy(save_name, fname); 274 atexit(del_save_file); 275 } 276 msg_cleared = 0; 277 ring_stats(0); 278 fclose(fp); 279 } 280 281 static void 282 write_pack(const object *pack, FILE *fp) 283 { 284 object t; 285 286 while ((pack = pack->next_object)) { 287 r_write(fp, (const char *) pack, sizeof(object)); 288 } 289 t.ichar = t.what_is = 0; 290 r_write(fp, (const char *) &t, sizeof(object)); 291 } 292 293 static void 294 read_pack(object *pack, FILE *fp, boolean is_rogue) 295 { 296 object read_obj, *new_obj; 297 298 for (;;) { 299 r_read(fp, (char *) &read_obj, sizeof(object)); 300 if (read_obj.ichar == 0) { 301 pack->next_object = NULL; 302 break; 303 } 304 new_obj = alloc_object(); 305 *new_obj = read_obj; 306 if (is_rogue) { 307 if (new_obj->in_use_flags & BEING_WORN) { 308 do_wear(new_obj); 309 } else if (new_obj->in_use_flags & BEING_WIELDED) { 310 do_wield(new_obj); 311 } else if (new_obj->in_use_flags & (ON_EITHER_HAND)) { 312 do_put_on(new_obj, 313 ((new_obj->in_use_flags & ON_LEFT_HAND) ? 1 : 0)); 314 } 315 } 316 pack->next_object = new_obj; 317 pack = new_obj; 318 } 319 } 320 321 static void 322 rw_dungeon(FILE *fp, boolean rw) 323 { 324 short i, j; 325 char buf[DCOLS]; 326 327 for (i = 0; i < DROWS; i++) { 328 if (rw) { 329 r_write(fp, (char *) dungeon[i], (DCOLS * sizeof(dungeon[0][0]))); 330 for (j = 0; j < DCOLS; j++) { 331 buf[j] = mvinch(i, j); 332 } 333 r_write(fp, buf, DCOLS); 334 } else { 335 r_read(fp, (char *) dungeon[i], (DCOLS * sizeof(dungeon[0][0]))); 336 r_read(fp, buf, DCOLS); 337 for (j = 0; j < DCOLS; j++) { 338 mvaddch(i, j, buf[j]); 339 } 340 } 341 } 342 } 343 344 static void 345 rw_id(struct id id_table[], FILE *fp, int n, boolean wr) 346 { 347 short i; 348 349 for (i = 0; i < n; i++) { 350 if (wr) { 351 r_write(fp, (const char *) &(id_table[i].value), sizeof(short)); 352 r_write(fp, (const char *) &(id_table[i].id_status), 353 sizeof(unsigned short)); 354 write_string(id_table[i].title, fp); 355 } else { 356 r_read(fp, (char *) &(id_table[i].value), sizeof(short)); 357 r_read(fp, (char *) &(id_table[i].id_status), 358 sizeof(unsigned short)); 359 read_string(id_table[i].title, fp, MAX_ID_TITLE_LEN); 360 } 361 } 362 } 363 364 static void 365 write_string(char *s, FILE *fp) 366 { 367 short n; 368 369 n = strlen(s) + 1; 370 xxxx(s, n); 371 r_write(fp, (char *) &n, sizeof(short)); 372 r_write(fp, s, n); 373 } 374 375 static void 376 read_string(char *s, FILE *fp, size_t len) 377 { 378 short n; 379 380 r_read(fp, (char *) &n, sizeof(short)); 381 if (n > (short)len) 382 clean_up("read_string: corrupt game file"); 383 r_read(fp, s, n); 384 xxxx(s, n); 385 } 386 387 static void 388 rw_rooms(FILE *fp, boolean rw) 389 { 390 short i; 391 392 for (i = 0; i < MAXROOMS; i++) { 393 rw ? r_write(fp, (char *) (rooms + i), sizeof(room)) : 394 r_read(fp, (char *) (rooms + i), sizeof(room)); 395 } 396 } 397 398 static void 399 r_read(FILE *fp, char *buf, int n) 400 { 401 if (fread(buf, sizeof(char), n, fp) != (unsigned)n) { 402 clean_up("read() failed, don't know why"); 403 } 404 } 405 406 static void 407 r_write(FILE *fp, const char *buf, int n) 408 { 409 if (!write_failed) { 410 if (fwrite(buf, sizeof(char), n, fp) != (unsigned)n) { 411 message("write() failed, don't know why", 0); 412 sound_bell(); 413 write_failed = 1; 414 } 415 } 416 } 417 418 static boolean 419 has_been_touched(const struct rogue_time *saved_time, 420 const struct rogue_time *mod_time) 421 { 422 if (saved_time->year < mod_time->year) { 423 return(1); 424 } else if (saved_time->year > mod_time->year) { 425 return(0); 426 } 427 if (saved_time->month < mod_time->month) { 428 return(1); 429 } else if (saved_time->month > mod_time->month) { 430 return(0); 431 } 432 if (saved_time->day < mod_time->day) { 433 return(1); 434 } else if (saved_time->day > mod_time->day) { 435 return(0); 436 } 437 if (saved_time->hour < mod_time->hour) { 438 return(1); 439 } else if (saved_time->hour > mod_time->hour) { 440 return(0); 441 } 442 if (saved_time->minute < mod_time->minute) { 443 return(1); 444 } else if (saved_time->minute > mod_time->minute) { 445 return(0); 446 } 447 if (saved_time->second < mod_time->second) { 448 return(1); 449 } 450 return(0); 451 } 452