-+-+-+-+-+-+-+-+ START OF PART 56 -+-+-+-+-+-+-+-+
X#include <fcntl.h>
X#endif
X#else
X#include "string.h"
X#endif
X#else
X#include <strings.h>
X#endif
X#endif
X
X/* This must be included after fcntl.h, which has a prototype for `60open'
X   on some systems.  Otherwise, the `60open' prototype conflicts with the
X   `60topen' declaration.  */
X#include "externs.h"
X
X#ifdef ATARIST_TC
X#include <time.h>
X#endif
X
XDEBUG(static FILE *logfile);
X
X#if defined(LINT_ARGS)
Xstatic int sv_write(void);
Xstatic void wr_byte(int8u);
Xstatic void wr_short(int16u);
Xstatic void wr_long(int32u);
Xstatic void wr_bytes(int8u *, int);
Xstatic void wr_string(char *);
Xstatic void wr_shorts(int16u *, int);
Xstatic void wr_item(inven_type *);
Xstatic void wr_monster(monster_type *);
Xstatic void rd_byte(int8u *);
Xstatic void rd_short(int16u *);
Xstatic void rd_long(int32u *);
Xstatic void rd_bytes(int8u *, int);
Xstatic void rd_string(char *);
Xstatic void rd_shorts(int16u *, int);
Xstatic void rd_item(inven_type *);
Xstatic void rd_monster(monster_type *);
X#else
Xstatic int sv_write();
Xstatic void wr_byte();
Xstatic void wr_short();
Xstatic void wr_long();
Xstatic void wr_bytes();
Xstatic void wr_string();
Xstatic void wr_shorts();
Xstatic void wr_item();
Xstatic void wr_monster();
Xstatic void rd_byte();
Xstatic void rd_short();
Xstatic void rd_long();
Xstatic void rd_bytes();
Xstatic void rd_string();
Xstatic void rd_shorts();
Xstatic void rd_item();
Xstatic void rd_monster();
X#endif
X
X#if !defined(ATARIST_MWC)
X#ifdef MAC
X#include <time.h>
X#else
Xlong time();
X#endif
X#else
Xchar *malloc();
X#endif
X
X/* these are used for the save file, to avoid having to pass them to every
X   procedure */
Xstatic FILE *fileptr;
Xstatic int8u xor_byte;
Xstatic int from_savefile;`09/* can overwrite old savefile when save */
Xstatic int32u start_time;`09/* time that play started */
X
X/* This save package was brought to by`09`09`09-JWT-
X   and`09`09`09`09`09`09`09-RAK-
X   and has been completely rewritten for UNIX by`09-JEW-  */
X/* and has been completely rewritten again by`09 -CJS-`09*/
X/* and completely rewritten again! for portability by -JEW- */
X
Xstatic int sv_write()
X`7B
X  int32u l;
X  register int i, j;
X  int count;
X  int8u char_tmp, prev_char;
X  register cave_type *c_ptr;
X  register recall_type *r_ptr;
X  struct stats *s_ptr;
X  register struct flags *f_ptr;
X  store_type *st_ptr;
X  struct misc *m_ptr;
X#if defined(MSDOS) `7C`7C defined(ATARI_ST)
X  inven_type *t_ptr;
X#endif
X
X  /* clear the death flag when creating a HANGUP save file, so that player
X     can see tombstone when restart */
X  if (eof_flag)
X    death = FALSE;
X
X  l = 0;
X  if (find_cut)
X    l `7C= 0x1;
X  if (find_examine)
X    l `7C= 0x2;
X  if (find_prself)
X    l `7C= 0x4;
X  if (find_bound)
X    l `7C= 0x8;
X  if (prompt_carry_flag)
X    l `7C= 0x10;
X  if (rogue_like_commands)
X    l `7C= 0x20;
X  if (show_weight_flag)
X    l `7C= 0x40;
X  if (highlight_seams)
X    l `7C= 0x80;
X  if (find_ignore_doors)
X    l `7C= 0x100;
X  if (sound_beep_flag)
X    l `7C= 0x200;
X  if (display_counts)
X    l `7C= 0x400;
X  if (death)
X    l `7C= 0x80000000L;`09/* Sign bit */
X  if (total_winner)
X    l `7C= 0x40000000L;
X
X  for (i = 0; i < MAX_CREATURES; i++)
X    `7B
X      r_ptr = &c_recall`5Bi`5D;
X      if (r_ptr->r_cmove `7C`7C r_ptr->r_cdefense `7C`7C r_ptr->r_kills `7C`
V7C
X`09  r_ptr->r_spells `7C`7C r_ptr->r_deaths `7C`7C r_ptr->r_attacks`5B0`5D `
V7C`7C
X`09  r_ptr->r_attacks`5B1`5D `7C`7C r_ptr->r_attacks`5B2`5D `7C`7C r_ptr->r_
Vattacks`5B3`5D)
X`09`7B
X`09  wr_short((int16u)i);
X`09  wr_long(r_ptr->r_cmove);
X`09  wr_long(r_ptr->r_spells);
X`09  wr_short(r_ptr->r_kills);
X`09  wr_short(r_ptr->r_deaths);
X`09  wr_short(r_ptr->r_cdefense);
X`09  wr_byte(r_ptr->r_wake);
X`09  wr_byte(r_ptr->r_ignore);
X`09  wr_bytes(r_ptr->r_attacks, MAX_MON_NATTACK);
X`09`7D
X    `7D
X  wr_short((int16u)0xFFFF); /* sentinel to indicate no more monster info */
X
X  wr_long(l);
X
X  m_ptr = &py.misc;
X  wr_string(m_ptr->name);
X  wr_byte(m_ptr->male);
X  wr_long((int32u)m_ptr->au);
X  wr_long((int32u)m_ptr->max_exp);
X  wr_long((int32u)m_ptr->exp);
X  wr_short(m_ptr->exp_frac);
X  wr_short(m_ptr->age);
X  wr_short(m_ptr->ht);
X  wr_short(m_ptr->wt);
X  wr_short(m_ptr->lev);
X  wr_short(m_ptr->max_dlv);
X  wr_short((int16u)m_ptr->srh);
X  wr_short((int16u)m_ptr->fos);
X  wr_short((int16u)m_ptr->bth);
X  wr_short((int16u)m_ptr->bthb);
X  wr_short((int16u)m_ptr->mana);
X  wr_short((int16u)m_ptr->mhp);
X  wr_short((int16u)m_ptr->ptohit);
X  wr_short((int16u)m_ptr->ptodam);
X  wr_short((int16u)m_ptr->pac);
X  wr_short((int16u)m_ptr->ptoac);
X  wr_short((int16u)m_ptr->dis_th);
X  wr_short((int16u)m_ptr->dis_td);
X  wr_short((int16u)m_ptr->dis_ac);
X  wr_short((int16u)m_ptr->dis_tac);
X  wr_short((int16u)m_ptr->disarm);
X  wr_short((int16u)m_ptr->save);
X  wr_short((int16u)m_ptr->sc);
X  wr_short((int16u)m_ptr->stl);
X  wr_byte(m_ptr->pclass);
X  wr_byte(m_ptr->prace);
X  wr_byte(m_ptr->hitdie);
X  wr_byte(m_ptr->expfact);
X  wr_short((int16u)m_ptr->cmana);
X  wr_short(m_ptr->cmana_frac);
X  wr_short((int16u)m_ptr->chp);
X  wr_short(m_ptr->chp_frac);
X  for (i = 0; i < 4; i++)
X    wr_string (m_ptr->history`5Bi`5D);
X
X  s_ptr = &py.stats;
X  wr_bytes(s_ptr->max_stat, 6);
X  wr_bytes(s_ptr->cur_stat, 6);
X  wr_shorts((int16u *)s_ptr->mod_stat, 6);
X  wr_bytes(s_ptr->use_stat, 6);
X
X  f_ptr = &py.flags;
X  wr_long(f_ptr->status);
X  wr_short((int16u)f_ptr->rest);
X  wr_short((int16u)f_ptr->blind);
X  wr_short((int16u)f_ptr->paralysis);
X  wr_short((int16u)f_ptr->confused);
X  wr_short((int16u)f_ptr->food);
X  wr_short((int16u)f_ptr->food_digested);
X  wr_short((int16u)f_ptr->protection);
X  wr_short((int16u)f_ptr->speed);
X  wr_short((int16u)f_ptr->fast);
X  wr_short((int16u)f_ptr->slow);
X  wr_short((int16u)f_ptr->afraid);
X  wr_short((int16u)f_ptr->poisoned);
X  wr_short((int16u)f_ptr->image);
X  wr_short((int16u)f_ptr->protevil);
X  wr_short((int16u)f_ptr->invuln);
X  wr_short((int16u)f_ptr->hero);
X  wr_short((int16u)f_ptr->shero);
X  wr_short((int16u)f_ptr->blessed);
X  wr_short((int16u)f_ptr->resist_heat);
X  wr_short((int16u)f_ptr->resist_cold);
X  wr_short((int16u)f_ptr->detect_inv);
X  wr_short((int16u)f_ptr->word_recall);
X  wr_short((int16u)f_ptr->see_infra);
X  wr_short((int16u)f_ptr->tim_infra);
X  wr_byte(f_ptr->see_inv);
X  wr_byte(f_ptr->teleport);
X  wr_byte(f_ptr->free_act);
X  wr_byte(f_ptr->slow_digest);
X  wr_byte(f_ptr->aggravate);
X  wr_byte(f_ptr->fire_resist);
X  wr_byte(f_ptr->cold_resist);
X  wr_byte(f_ptr->acid_resist);
X  wr_byte(f_ptr->regenerate);
X  wr_byte(f_ptr->lght_resist);
X  wr_byte(f_ptr->ffall);
X  wr_byte(f_ptr->sustain_str);
X  wr_byte(f_ptr->sustain_int);
X  wr_byte(f_ptr->sustain_wis);
X  wr_byte(f_ptr->sustain_con);
X  wr_byte(f_ptr->sustain_dex);
X  wr_byte(f_ptr->sustain_chr);
X  wr_byte(f_ptr->confuse_monster);
X  wr_byte(f_ptr->new_spells);
X
X  wr_short((int16u)missile_ctr);
X  wr_long((int32u)turn);
X  wr_short((int16u)inven_ctr);
X  for (i = 0; i < inven_ctr; i++)
X    wr_item(&inventory`5Bi`5D);
X  for (i = INVEN_WIELD; i < INVEN_ARRAY_SIZE; i++)
X    wr_item(&inventory`5Bi`5D);
X  wr_short((int16u)inven_weight);
X  wr_short((int16u)equip_ctr);
X  wr_long(spell_learned);
X  wr_long(spell_worked);
X  wr_long(spell_forgotten);
X  wr_bytes(spell_order, 32);
X  wr_bytes(object_ident, OBJECT_IDENT_SIZE);
X  wr_long(randes_seed);
X  wr_long(town_seed);
X  wr_short((int16u)last_msg);
X  for (i = 0; i < MAX_SAVE_MSG; i++)
X    wr_string(old_msg`5Bi`5D);
X
X  /* this indicates 'cheating' if it is a one */
X  wr_short((int16u)panic_save);
X  wr_short((int16u)total_winner);
X  wr_short((int16u)noscore);
X  wr_shorts(player_hp, MAX_PLAYER_LEVEL);
X
X  for (i = 0; i < MAX_STORES; i++)
X    `7B
X      st_ptr = &store`5Bi`5D;
X      wr_long((int32u)st_ptr->store_open);
X      wr_short((int16u)st_ptr->insult_cur);
X      wr_byte(st_ptr->owner);
X      wr_byte(st_ptr->store_ctr);
X      wr_short(st_ptr->good_buy);
X      wr_short(st_ptr->bad_buy);
X      for (j = 0; j < st_ptr->store_ctr; j++)
X`09`7B
X`09  wr_long((int32u)st_ptr->store_inven`5Bj`5D.scost);
X`09  wr_item(&st_ptr->store_inven`5Bj`5D.sitem);
X`09`7D
X    `7D
X
X  /* save the current time in the savefile */
X#ifdef MAC
X  l = time((time_t *)0);
X#else
X  l = time((long *)0);
X#endif
X  if (l < start_time)
X    `7B
X      /* someone is messing with the clock!, assume that we have been
X`09 playing for 1 day */
X      l = start_time + 86400L;
X    `7D
X  wr_long(l);
X
X  /* starting with 5.2, put died_from string in savefile */
X  wr_string(died_from);
X
X  /* starting with 5.2.2, put the max_score in the savefile */
X  l = total_points ();
X  wr_long (l);
X
X  /* starting with 5.2.2, put the birth_date in the savefile */
X  wr_long ((int32u) birth_date);
X
X  /* only level specific info follows, this allows characters to be
X     resurrected, the dungeon level info is not needed for a resurrection */
X  if (death)
X    `7B
X      if (ferror(fileptr) `7C`7C fflush(fileptr) == EOF)
X`09return FALSE;
X      return TRUE;
X    `7D
X
X  wr_short((int16u)dun_level);
X  wr_short((int16u)char_row);
X  wr_short((int16u)char_col);
X  wr_short((int16u)mon_tot_mult);
X  wr_short((int16u)cur_height);
X  wr_short((int16u)cur_width);
X  wr_short((int16u)max_panel_rows);
X  wr_short((int16u)max_panel_cols);
X
X  for (i = 0; i < MAX_HEIGHT; i++)
X    for (j = 0; j < MAX_WIDTH; j++)
X      `7B
X`09c_ptr = &cave`5Bi`5D`5Bj`5D;
X`09if (c_ptr->cptr != 0)
X`09  `7B
X`09    wr_byte((int8u)i);
X`09    wr_byte((int8u)j);
X`09    wr_byte(c_ptr->cptr);
X`09  `7D
X      `7D
X  wr_byte((int8u)0xFF); /* marks end of cptr info */
X  for (i = 0; i < MAX_HEIGHT; i++)
X    for (j = 0; j < MAX_WIDTH; j++)
X      `7B
X`09c_ptr = &cave`5Bi`5D`5Bj`5D;
X`09if (c_ptr->tptr != 0)
X`09  `7B
X`09    wr_byte((int8u)i);
X`09    wr_byte((int8u)j);
X`09    wr_byte(c_ptr->tptr);
X`09  `7D
X      `7D
X  wr_byte((int8u)0xFF); /* marks end of tptr info */
X  /* must set counter to zero, note that code may write out two bytes
X     unnecessarily */
X  count = 0;
X  prev_char = 0;
X  for (i = 0; i < MAX_HEIGHT; i++)
X    for (j = 0; j < MAX_WIDTH; j++)
X      `7B
X`09c_ptr = &cave`5Bi`5D`5Bj`5D;
X`09char_tmp = c_ptr->fval `7C (c_ptr->lr << 4) `7C (c_ptr->fm << 5) `7C
X`09  (c_ptr->pl << 6) `7C (c_ptr->tl << 7);
X`09if (char_tmp != prev_char `7C`7C count == MAX_UCHAR)
X`09  `7B
X`09    wr_byte((int8u)count);
X`09    wr_byte(prev_char);
X`09    prev_char = char_tmp;
X`09    count = 1;
X`09  `7D
X`09else
X`09  count++;
X      `7D
X  /* save last entry */
X  wr_byte((int8u)count);
X  wr_byte(prev_char);
X
X#if defined(MSDOS) `7C`7C defined(ATARI_ST)
X  /* must change graphics symbols for walls and floors back to default chars
V,
X     this is necessary so that if the user changes the graphics line, the
X     program will be able change all existing walls and floors to the new
X     symbol */
X  /* Or if the user moves the savefile from one machine to another, we
X     must have a consistent representation here.  */
X  t_ptr = &t_list`5Btcptr - 1`5D;
X  for (i = tcptr - 1; i >= MIN_TRIX; i--)
X    `7B
X#ifdef MSDOS
X      if (t_ptr->tchar == wallsym)
X`09t_ptr->tchar = '#';
X#endif
X#ifdef ATARI_ST
X      if (t_ptr->tchar == (unsigned char)240)
X`09t_ptr->tchar = '#';
X#endif
X      t_ptr--;
X    `7D
X#endif
X  wr_short((int16u)tcptr);
X  for (i = MIN_TRIX; i < tcptr; i++)
X    wr_item(&t_list`5Bi`5D);
X  wr_short((int16u)mfptr);
X  for (i = MIN_MONIX; i < mfptr; i++)
X    wr_monster(&m_list`5Bi`5D);
X
X  if (ferror(fileptr) `7C`7C (fflush(fileptr) == EOF))
X    return FALSE;
X  return TRUE;
X`7D
X
X#ifdef MAC
X
X/* Set up prior to actual save, do the save, then clean up */
X/* Notice that Mac version of this function takes a parameter */
X/* To do a "save as" set always_ask */
X/* To do a "save" clear always_ask */
X
Xint save_char(always_ask)
Xint always_ask;
X`7B
X  int rc, already_set, proceed;
X  int16 vrefnum;
X
X  /* cannot rely on _save_char to do this because we may put up a dialog */
X  if (character_saved) return(TRUE);
X
X  enablefilemenu(FALSE);
X
X  already_set = getsavedefaults(savefile, &vrefnum);
X
X  if (!already_set `7C`7C always_ask)
X    `7B
X      /* Here if always_ask or user has not yet specified a save file */
X      /* User specifies a save file when he restarts a previous one */
X      sfposition(vrefnum);
X      proceed = doputfile(death ? "Save memories as:" : "Save game as:",
X`09`09`09  savefile, &vrefnum);
X    `7D
X  else
X    proceed = TRUE;
X
X  if (proceed)
X    `7B
X      changedirectory(vrefnum);
X      rc = _save_char(savefile);
X      restoredirectory();
X    `7D
X  else
X    rc = FALSE;
X
X  if (rc)
X    (void) setfileinfo(savefile, vrefnum, SAVE_FTYPE);
X
X  enablefilemenu(TRUE);
X
X  return(rc);
X`7D
X
X#else
X
X/* The Mac has different logic here -- See above */
X
Xint save_char()
X`7B
X  int i;
X  vtype temp;
X
X#ifdef SECURE
X  bePlayer();
X#endif
X
X  while (!_save_char(savefile))
X    `7B
X      (void) sprintf(temp, "Savefile '%s' fails.", savefile);
X      msg_print(temp);
X      i = 0;
X      if (access(savefile, 0) < 0
X`09  `7C`7C get_check("File exists. Delete old savefile?") == 0
X`09  `7C`7C (i = unlink(savefile)) < 0)
X`09`7B
X`09  if (i < 0)
X`09    `7B
X`09      (void) sprintf(temp, "Can't delete '%s'", savefile);
X`09      msg_print(temp);
X`09    `7D
X`09  prt("New Savefile `5BESC to give up`5D:", 0, 0);
X`09  if (!get_string(temp, 0, 31, 45))
X`09    return FALSE;
X`09  if (temp`5B0`5D)
X`09    (void) strcpy(savefile, temp);
X`09`7D
X      (void) sprintf(temp, "Saving with %s...", savefile);
X      prt(temp, 0, 0);
X    `7D
X#ifdef SECURE
X  beGames();
X#endif
X  return TRUE;
X`7D
X#endif
X
Xint _save_char(fnam)
Xchar *fnam;
X`7B
X  vtype temp;
X  register int ok, fd;
X  int8u char_tmp;
X
X  if (character_saved)
X    return TRUE;`09/* Nothing to save. */
X
X  nosignals();
X  put_qio();
X  disturb (1, 0);`09`09/* Turn off resting and searching. */
X  change_speed(-pack_heavy);`09/* Fix the speed */
X  pack_heavy = 0;
X  ok = FALSE;
+-+-+-+-+-+-+-+-  END  OF PART 56 +-+-+-+-+-+-+-+-
