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.3 2003/08/26 23:52:50 drhodus 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 "rogue.h" 55 56 short write_failed = 0; 57 char *save_file = (char *) 0; 58 static char save_name[80]; 59 60 extern boolean detect_monster; 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 save_game() 82 { 83 char fname[64]; 84 85 if (!get_input_line("file name?", save_file, fname, "game not saved", 86 0, 1)) { 87 return; 88 } 89 check_message(); 90 message(fname, 0); 91 save_into_file(fname); 92 } 93 94 save_into_file(sfile) 95 const char *sfile; 96 { 97 FILE *fp; 98 int file_id; 99 char *name_buffer; 100 size_t len; 101 char *hptr; 102 struct rogue_time rt_buf; 103 104 if (sfile[0] == '~') { 105 if (hptr = md_getenv("HOME")) { 106 len = strlen(hptr) + strlen(sfile); 107 name_buffer = md_malloc(len); 108 if (name_buffer == NULL) { 109 message("out of memory for save file name", 0); 110 sfile = error_file; 111 } else { 112 (void) strcpy(name_buffer, hptr); 113 (void) strcat(name_buffer, sfile+1); 114 sfile = name_buffer; 115 } 116 117 } 118 } 119 /* revoke */ 120 setgid(getgid()); 121 if ( ((fp = fopen(sfile, "w")) == NULL) || 122 ((file_id = md_get_file_id(sfile)) == -1)) { 123 message("problem accessing the save file", 0); 124 return; 125 } 126 md_ignore_signals(); 127 write_failed = 0; 128 (void) xxx(1); 129 r_write(fp, (char *) &detect_monster, sizeof(detect_monster)); 130 r_write(fp, (char *) &cur_level, sizeof(cur_level)); 131 r_write(fp, (char *) &max_level, sizeof(max_level)); 132 write_string(hunger_str, fp); 133 write_string(login_name, fp); 134 r_write(fp, (char *) &party_room, sizeof(party_room)); 135 write_pack(&level_monsters, fp); 136 write_pack(&level_objects, fp); 137 r_write(fp, (char *) &file_id, sizeof(file_id)); 138 rw_dungeon(fp, 1); 139 r_write(fp, (char *) &foods, sizeof(foods)); 140 r_write(fp, (char *) &rogue, sizeof(fighter)); 141 write_pack(&rogue.pack, fp); 142 rw_id(id_potions, fp, POTIONS, 1); 143 rw_id(id_scrolls, fp, SCROLS, 1); 144 rw_id(id_wands, fp, WANDS, 1); 145 rw_id(id_rings, fp, RINGS, 1); 146 r_write(fp, (char *) traps, (MAX_TRAPS * sizeof(trap))); 147 r_write(fp, (char *) is_wood, (WANDS * sizeof(boolean))); 148 r_write(fp, (char *) &cur_room, sizeof(cur_room)); 149 rw_rooms(fp, 1); 150 r_write(fp, (char *) &being_held, sizeof(being_held)); 151 r_write(fp, (char *) &bear_trap, sizeof(bear_trap)); 152 r_write(fp, (char *) &halluc, sizeof(halluc)); 153 r_write(fp, (char *) &blind, sizeof(blind)); 154 r_write(fp, (char *) &confused, sizeof(confused)); 155 r_write(fp, (char *) &levitate, sizeof(levitate)); 156 r_write(fp, (char *) &haste_self, sizeof(haste_self)); 157 r_write(fp, (char *) &see_invisible, sizeof(see_invisible)); 158 r_write(fp, (char *) &detect_monster, sizeof(detect_monster)); 159 r_write(fp, (char *) &wizard, sizeof(wizard)); 160 r_write(fp, (char *) &score_only, sizeof(score_only)); 161 r_write(fp, (char *) &m_moves, sizeof(m_moves)); 162 md_gct(&rt_buf); 163 rt_buf.second += 10; /* allow for some processing time */ 164 r_write(fp, (char *) &rt_buf, sizeof(rt_buf)); 165 fclose(fp); 166 167 if (write_failed) { 168 (void) md_df(sfile); /* delete file */ 169 } else { 170 if (strcmp(sfile, save_name) == 0) 171 save_name[0] = 0; 172 clean_up(""); 173 } 174 } 175 176 static del_save_file() 177 { 178 if (!save_name[0]) 179 return; 180 /* revoke */ 181 setgid(getgid()); 182 md_df(save_name); 183 } 184 185 restore(fname) 186 const char *fname; 187 { 188 FILE *fp; 189 struct rogue_time saved_time, mod_time; 190 char buf[4]; 191 char tbuf[40]; 192 int new_file_id, saved_file_id; 193 194 if ( ((new_file_id = md_get_file_id(fname)) == -1) || 195 ((fp = fopen(fname, "r")) == NULL)) { 196 clean_up("cannot open file"); 197 } 198 if (md_link_count(fname) > 1) { 199 clean_up("file has link"); 200 } 201 (void) xxx(1); 202 r_read(fp, (char *) &detect_monster, sizeof(detect_monster)); 203 r_read(fp, (char *) &cur_level, sizeof(cur_level)); 204 r_read(fp, (char *) &max_level, sizeof(max_level)); 205 read_string(hunger_str, fp, sizeof hunger_str); 206 207 (void) strlcpy(tbuf, login_name, sizeof tbuf); 208 read_string(login_name, fp, sizeof login_name); 209 if (strcmp(tbuf, login_name)) { 210 clean_up("you're not the original player"); 211 } 212 213 r_read(fp, (char *) &party_room, sizeof(party_room)); 214 read_pack(&level_monsters, fp, 0); 215 read_pack(&level_objects, fp, 0); 216 r_read(fp, (char *) &saved_file_id, sizeof(saved_file_id)); 217 if (new_file_id != saved_file_id) { 218 clean_up("sorry, saved game is not in the same file"); 219 } 220 rw_dungeon(fp, 0); 221 r_read(fp, (char *) &foods, sizeof(foods)); 222 r_read(fp, (char *) &rogue, sizeof(fighter)); 223 read_pack(&rogue.pack, fp, 1); 224 rw_id(id_potions, fp, POTIONS, 0); 225 rw_id(id_scrolls, fp, SCROLS, 0); 226 rw_id(id_wands, fp, WANDS, 0); 227 rw_id(id_rings, fp, RINGS, 0); 228 r_read(fp, (char *) traps, (MAX_TRAPS * sizeof(trap))); 229 r_read(fp, (char *) is_wood, (WANDS * sizeof(boolean))); 230 r_read(fp, (char *) &cur_room, sizeof(cur_room)); 231 rw_rooms(fp, 0); 232 r_read(fp, (char *) &being_held, sizeof(being_held)); 233 r_read(fp, (char *) &bear_trap, sizeof(bear_trap)); 234 r_read(fp, (char *) &halluc, sizeof(halluc)); 235 r_read(fp, (char *) &blind, sizeof(blind)); 236 r_read(fp, (char *) &confused, sizeof(confused)); 237 r_read(fp, (char *) &levitate, sizeof(levitate)); 238 r_read(fp, (char *) &haste_self, sizeof(haste_self)); 239 r_read(fp, (char *) &see_invisible, sizeof(see_invisible)); 240 r_read(fp, (char *) &detect_monster, sizeof(detect_monster)); 241 r_read(fp, (char *) &wizard, sizeof(wizard)); 242 r_read(fp, (char *) &score_only, sizeof(score_only)); 243 r_read(fp, (char *) &m_moves, sizeof(m_moves)); 244 r_read(fp, (char *) &saved_time, sizeof(saved_time)); 245 246 if (fread(buf, sizeof(char), 1, fp) > 0) { 247 clear(); 248 clean_up("extra characters in file"); 249 } 250 251 md_gfmt(fname, &mod_time); /* get file modification time */ 252 253 if (has_been_touched(&saved_time, &mod_time)) { 254 clear(); 255 clean_up("sorry, file has been touched"); 256 } 257 if ((!wizard)) { 258 strcpy(save_name, fname); 259 atexit(del_save_file); 260 } 261 msg_cleared = 0; 262 ring_stats(0); 263 fclose(fp); 264 } 265 266 write_pack(pack, fp) 267 const object *pack; 268 FILE *fp; 269 { 270 object t; 271 272 while (pack = pack->next_object) { 273 r_write(fp, (const char *) pack, sizeof(object)); 274 } 275 t.ichar = t.what_is = 0; 276 r_write(fp, (const char *) &t, sizeof(object)); 277 } 278 279 read_pack(pack, fp, is_rogue) 280 object *pack; 281 FILE *fp; 282 boolean is_rogue; 283 { 284 object read_obj, *new_obj; 285 286 for (;;) { 287 r_read(fp, (char *) &read_obj, sizeof(object)); 288 if (read_obj.ichar == 0) { 289 pack->next_object = (object *) 0; 290 break; 291 } 292 new_obj = alloc_object(); 293 *new_obj = read_obj; 294 if (is_rogue) { 295 if (new_obj->in_use_flags & BEING_WORN) { 296 do_wear(new_obj); 297 } else if (new_obj->in_use_flags & BEING_WIELDED) { 298 do_wield(new_obj); 299 } else if (new_obj->in_use_flags & (ON_EITHER_HAND)) { 300 do_put_on(new_obj, 301 ((new_obj->in_use_flags & ON_LEFT_HAND) ? 1 : 0)); 302 } 303 } 304 pack->next_object = new_obj; 305 pack = new_obj; 306 } 307 } 308 309 rw_dungeon(fp, rw) 310 FILE *fp; 311 boolean rw; 312 { 313 short i, j; 314 char buf[DCOLS]; 315 316 for (i = 0; i < DROWS; i++) { 317 if (rw) { 318 r_write(fp, (char *) dungeon[i], (DCOLS * sizeof(dungeon[0][0]))); 319 for (j = 0; j < DCOLS; j++) { 320 buf[j] = mvinch(i, j); 321 } 322 r_write(fp, buf, DCOLS); 323 } else { 324 r_read(fp, (char *) dungeon[i], (DCOLS * sizeof(dungeon[0][0]))); 325 r_read(fp, buf, DCOLS); 326 for (j = 0; j < DCOLS; j++) { 327 mvaddch(i, j, buf[j]); 328 } 329 } 330 } 331 } 332 333 rw_id(id_table, fp, n, wr) 334 struct id id_table[]; 335 FILE *fp; 336 int n; 337 boolean wr; 338 { 339 short i; 340 341 for (i = 0; i < n; i++) { 342 if (wr) { 343 r_write(fp, (const char *) &(id_table[i].value), sizeof(short)); 344 r_write(fp, (const char *) &(id_table[i].id_status), 345 sizeof(unsigned short)); 346 write_string(id_table[i].title, fp); 347 } else { 348 r_read(fp, (char *) &(id_table[i].value), sizeof(short)); 349 r_read(fp, (char *) &(id_table[i].id_status), 350 sizeof(unsigned short)); 351 read_string(id_table[i].title, fp, MAX_ID_TITLE_LEN); 352 } 353 } 354 } 355 356 write_string(s, fp) 357 char *s; 358 FILE *fp; 359 { 360 short n; 361 362 n = strlen(s) + 1; 363 xxxx(s, n); 364 r_write(fp, (char *) &n, sizeof(short)); 365 r_write(fp, s, n); 366 } 367 368 read_string(s, fp, len) 369 char *s; 370 FILE *fp; 371 size_t len; 372 { 373 short n; 374 375 r_read(fp, (char *) &n, sizeof(short)); 376 if (n > len) 377 clean_up("read_string: corrupt game file"); 378 r_read(fp, s, n); 379 xxxx(s, n); 380 } 381 382 rw_rooms(fp, rw) 383 FILE *fp; 384 boolean rw; 385 { 386 short i; 387 388 for (i = 0; i < MAXROOMS; i++) { 389 rw ? r_write(fp, (char *) (rooms + i), sizeof(room)) : 390 r_read(fp, (char *) (rooms + i), sizeof(room)); 391 } 392 } 393 394 r_read(fp, buf, n) 395 FILE *fp; 396 char *buf; 397 int n; 398 { 399 if (fread(buf, sizeof(char), n, fp) != n) { 400 clean_up("read() failed, don't know why"); 401 } 402 } 403 404 r_write(fp, buf, n) 405 FILE *fp; 406 const char *buf; 407 int n; 408 { 409 if (!write_failed) { 410 if (fwrite(buf, sizeof(char), n, fp) != n) { 411 message("write() failed, don't know why", 0); 412 sound_bell(); 413 write_failed = 1; 414 } 415 } 416 } 417 418 boolean 419 has_been_touched(saved_time, mod_time) 420 const struct rogue_time *saved_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