diff urogue/state.c @ 256:c495a4f288c6

Import UltraRogue from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 31 Jan 2017 19:56:04 -0500
parents
children 2908dc47f9e2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/state.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1445 @@
+/*
+    state.c - Portable Rogue Save State Code
+
+    Copyright (C) 1993, 1995 Nicholas J. Kisseberth
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+    3. Neither the name(s) of the author(s) nor the names of other contributors
+       may be used to endorse or promote products derived from this software
+       without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+*/
+
+/*
+    Notes
+
+        Should move all game variables into one place
+        Should move save/restore code into save.c or some such
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rogue.h"
+
+/*
+     Variables for global game state.
+
+     All variables that need to get saved when saving a game
+     are defined in this file. Long term goal is to move many
+     of these variables into a "struct level" data type of some
+     kind... perhaps not, maybe struct game...
+
+     Other global variables that don't need to get saved are
+     kept in main.c.
+
+     Other global variables that don't change during the course
+     of a game are kept in urogue.c, monsdata.c, data.c.
+*/
+
+#define _X_ { 0, 0, 0, 0, 0 }
+
+struct delayed_action
+d_list[MAXDAEMONS] =        /* daemon/fuse list                         */
+{
+        _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
+        _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
+        _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
+        _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
+        _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
+        _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
+};
+
+#undef _X_
+
+char *s_names[MAXSCROLLS];   /* Names of the scrolls         */
+char *p_colors[MAXPOTIONS];  /* Colors of the potions        */
+char *r_stones[MAXRINGS];    /* Stone settings of the rings  */
+char *ws_made[MAXSTICKS];    /* What sticks are made of      */
+char *ws_type[MAXSTICKS];    /* Is it a wand or a staff      */
+
+char *guess_items[MAXMAGICTYPES][MAXMAGICITEMS]; /* guess magic is          */
+int   know_items[MAXMAGICTYPES][MAXMAGICITEMS];  /* flag knowlede of magic  */
+                                                 /* object data             */
+
+struct trap          traps[2 * MAXTRAPS];   /* 2x for special effects       */
+struct room          rooms[MAXROOMS];       /* One for each room -- A level */
+struct room         *oldrp = NULL;          /* Roomin(&player.t_oldpos)     */
+struct thing         player;                /* The rogue                    */
+struct linked_list  *lvl_obj = NULL;        /* Treasure on this level       */
+struct linked_list  *fam_ptr = NULL;        /* A ptr to the familiar        */
+struct linked_list  *mlist = NULL;          /* Monsters on this level       */
+struct thing        *beast;                 /* The last beast that attacked */
+struct object       *cur_armor  = NULL;     /* what rogue  wears            */
+struct object       *cur_weapon = NULL;     /* ... and wields               */
+struct object       *cur_ring[10];          /* His rings                    */
+struct linked_list  *curr_mons  = NULL;     /* The mons. currently moving   */
+struct linked_list  *next_mons = NULL;      /* The mons. after curr_mons    */
+
+/* Misc. game state info */
+char dummybuf1[50000];
+char dummybuf2[50000];
+char msgbuf[10][2*LINELEN]; /* message buffer history                   */
+int  msg_index = 0;         /* index in msg history buffer for nxt msg  */
+int  foodlev         = 1;           /* how fast he eats food            */
+int  ntraps          = 0;           /* Number of traps on this level    */
+int  dnum            = 0;           /* Dungeon number                   */
+int  max_level       = 0;           /* Deepest player has gone          */
+int  lost_dext       = 0;           /* amount of lost dexterity         */
+int  no_command      = 0;
+int  level           = 0;
+int  see_dist        = 3;
+int  no_food         = 0;
+int  count           = 0;
+int  food_left       = HUNGERTIME;
+int  group           = 1;
+int  hungry_state    = F_OK;
+int  infest_dam      = 0;
+int  lost_str        = 0;
+int  hold_count      = 0;
+int  trap_tries      = 0;
+int  has_artifact    = 0;
+int  picked_artifact = 0;
+int  luck            = 0;
+int  resurrect       = 0;
+int  fam_type        = 0;           /* The type of familiar             */
+int  mons_summoned   = 0;           /* Number of summoned monsters      */
+char PLAYER          = VPLAYER;     /* what the player looks like       */
+char take            = 0;           /* Thing the rogue is taking        */
+char runch           = 0;           /* Direction player is running      */
+int  char_type       = C_NOTSET;    /* what type of character is player */
+int  inv_type        = INV_CLEAR;   /* Overwrite style of inventory     */
+int  pool_teleport   = FALSE;       /* just teleported from a pool      */
+int  inwhgt          = FALSE;       /* true if from wghtchk()           */
+int  after           = 0;           /* True if we want after daemons    */
+int  waswizard       = 0;           /* Was a wizard sometime            */
+int  canwizard       = 1;           /* Will be permitted to do this     */
+int  playing         = TRUE;
+int  running         = FALSE;
+int  fighting        = FALSE;
+int  wizard          = FALSE;
+int  wiz_verbose     = TRUE;
+int  moving          = FALSE;
+coord    delta;                     /* Change indicated to get_dir()    */
+LEVTYPE  levtype;                   /* type of level i'm on             */
+long purse  = 0;
+unsigned long total  = 0;
+
+WINDOW  *cw;                        /* Window that the player sees      */
+WINDOW  *hw;                        /* Used for the help command        */
+WINDOW  *mw;                        /* Used to store mosnters           */
+
+/* options.o    */
+/* game options */
+
+int  terse       = FALSE;
+int  door_stop   = FALSE;
+int  jump        = TRUE;
+int  doorstop    = TRUE;
+int  firstmove   = FALSE;
+int  askme       = FALSE;
+char whoami[2 * LINELEN];           /* Name of player  */
+char fruit[2 * LINELEN];            /* Favorite fruit  */
+char file_name[2 * LINELEN];        /* Save file name  */
+char score_file[2 * LINELEN];       /* Score file name */
+
+/****************************************************************************/
+/* Portable Save State Code                                                 */
+/*                                                                          */
+/*    UltraRogue v1.04                                                      */
+/****************************************************************************/
+
+#define URS_STATS        0xABCD0001
+#define URS_THING        0xABCD0002
+#define URS_OBJECT       0xABCD0003
+#define URS_MAGIC        0xABCD0004
+#define URS_KNOWS        0xABCD0005
+#define URS_GUESSES      0xABCD0006
+#define URS_STACKOBJECT  0xABCD0007
+#define URS_BAGOBJECT    0xABCD0008
+#define URS_MONSTERLIST  0xABCD0009
+#define URS_MONSTERSTATS 0xABCD000A
+#define URS_MONSTER      0xABCD000B
+#define URS_TRAP         0xABCD000C
+#define URS_WINDOW       0xABCD000D
+#define URS_DAEMONS      0xABCD000E
+
+void
+ur_write(FILE *savef, void *ptr, size_t size)
+{
+    if (size == 0)
+        return;
+
+    fwrite(ptr,size,1,savef);
+}
+
+void
+ur_read(FILE *savef, void *ptr, size_t size)
+{
+    if (size == 0)
+        return;
+
+    fread(ptr,size,1,savef);
+}
+
+void
+ur_write_int(FILE *savef, int c)
+{
+    ur_write(savef,&c,sizeof(int));
+}
+
+int
+ur_read_int(FILE *savef)
+{
+    int i;
+
+    ur_read(savef, &i, sizeof(int));
+
+    return(i);
+}
+
+void
+ur_write_short(FILE *savef, short c)
+{
+    ur_write(savef,&c,sizeof(short));
+}
+
+short
+ur_read_short(FILE *savef)
+{
+    short s;
+
+    ur_read(savef, &s, sizeof(short));
+
+    return(s);
+}
+
+void
+ur_write_long(FILE *savef, long c)
+{
+    ur_write(savef,&c,sizeof(long));
+}
+
+long
+ur_read_long(FILE *savef)
+{
+    long l;
+
+    ur_read(savef, &l, sizeof(long));
+
+    return(l);
+}
+
+void
+ur_write_ulong(FILE *savef, unsigned long c)
+{
+    ur_write(savef,&c,sizeof(unsigned long));
+}
+
+unsigned long
+ur_read_ulong(FILE *savef)
+{
+    long l;
+
+    ur_read(savef, &l, sizeof(unsigned long));
+
+    return(l);
+}
+
+void
+ur_unread_long(FILE *savef)
+{
+    fseek(savef, -(long)sizeof(long), SEEK_CUR);
+}
+
+void
+ur_write_char(FILE *savef, char c)
+{
+    ur_write(savef,&c,sizeof(char));
+}
+
+char
+ur_read_char(FILE *savef)
+{
+    char c;
+
+    ur_read(savef, &c, sizeof(char));
+
+    return(c);
+}
+
+void
+ur_write_string(FILE *savef, char *s)
+{
+    size_t len;
+
+    len = (s == NULL) ? 0L : strlen(s) + 1 ;
+
+    ur_write_long(savef, (long) len);
+    ur_write(savef,s,len);
+}
+
+
+char *
+ur_read_string(FILE *savef)
+{
+    size_t  len;
+    char   *buf;
+
+    len = ur_read_long(savef);
+
+    if (len == 0)
+        return(NULL);
+
+    buf = ur_alloc(len);
+
+    if (buf == NULL)     /* Should flag a global error condition... */
+        return(NULL);
+
+    ur_read(savef,buf,len);
+
+    return(buf);
+}
+
+void
+ur_write_coord(FILE *savef, coord c)
+{
+    ur_write_int(savef, c.x);
+    ur_write_int(savef, c.y);
+}
+
+coord
+ur_read_coord(FILE *savef)
+{
+    coord c;
+
+    c.x = ur_read_int(savef);
+    c.y = ur_read_int(savef);
+
+    return(c);
+}
+
+void
+ur_write_room(FILE *savef, struct room *r)
+{
+    int i;
+
+    ur_write_coord(savef, r->r_pos);
+    ur_write_coord(savef, r->r_max);
+
+    for(i=0; i<MAXDOORS; i++)
+        ur_write_coord(savef, r->r_exit[i]);
+
+    ur_write_int(savef, r->r_flags);
+    ur_write_int(savef, r->r_nexits);
+    ur_write_int(savef, r->r_flags);
+}
+
+struct room *
+ur_read_room(FILE *savef)
+{
+    struct room *r;
+    int i;
+
+    r = ur_alloc( sizeof(struct room) );
+
+    r->r_pos = ur_read_coord(savef);
+    r->r_max = ur_read_coord(savef);
+
+    for(i=0; i<MAXDOORS; i++)
+        r->r_exit[i] = ur_read_coord(savef);
+
+    r->r_flags = ur_read_int(savef);
+    r->r_nexits = ur_read_int(savef);
+    r->r_flags = ur_read_short(savef);
+
+    return(r);
+}
+
+void
+ur_write_object(FILE *savef, struct object *o)
+{
+    int other;
+
+    ur_write_long(savef,      URS_OBJECT);
+    ur_write_coord(savef,     o->o_pos);
+    ur_write_string(savef,    o->o_text);
+    ur_write_string(savef,    o->o_damage);
+    ur_write_string(savef,    o->o_hurldmg);
+    ur_write_long(savef,      o->o_flags);
+    ur_write_long(savef,      o->ar_flags);
+    ur_write_char(savef,       o->o_type);
+    ur_write_int(savef,       o->o_ident);
+    ur_write_int(savef,       o->o_count);
+    ur_write_int(savef,       o->o_which);
+    ur_write_int(savef,       o->o_hplus);
+    ur_write_int(savef,       o->o_dplus);
+    ur_write_int(savef,       o->o_ac);
+    ur_write_int(savef,       o->o_group);
+    ur_write_int(savef,       o->o_weight);
+    ur_write_char(savef,      o->o_launch);
+    ur_write(savef,          &o->o_mark[0], MARKLEN);
+    ur_write_long(savef,      o->o_worth);
+
+    other = 0;
+
+    if (o->o_bag)
+        other = 1;
+    else if (o->next_obj)
+        other |= 2;
+
+    ur_write_int(savef,other);
+
+    if (o->o_bag)
+        ur_write_bag(savef,o->o_bag);
+    if (o->next_obj && (o->next_obj->l_prev == NULL) )
+        ur_write_object_stack(savef, o->next_obj);
+}
+
+struct object *
+ur_read_object(FILE *savef)
+{
+    struct object *o;
+    long id;
+    int other;
+
+    o = ur_alloc(sizeof(struct object));
+
+    if (o == NULL)
+        return(NULL);
+
+    memset(o,0,sizeof(struct object));
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_OBJECT);
+
+    o->o_pos  = ur_read_coord(savef);
+    o->o_text = ur_read_string(savef);
+    o->o_damage = ur_read_string(savef);
+    o->o_hurldmg = ur_read_string(savef);
+    o->o_flags = ur_read_long(savef);
+    o->ar_flags = ur_read_long(savef);
+    o->o_type = ur_read_char(savef);
+    o->o_ident = ur_read_int(savef);
+    o->o_count = ur_read_int(savef);
+    o->o_which = ur_read_int(savef);
+    o->o_hplus = ur_read_int(savef);
+    o->o_dplus = ur_read_int(savef);
+    o->o_ac = ur_read_int(savef);
+    o->o_group = ur_read_int(savef);
+    o->o_weight = ur_read_int(savef);
+    o->o_launch = ur_read_char(savef);
+    ur_read(savef, &o->o_mark[0], MARKLEN);
+    o->o_worth = ur_read_long(savef);
+
+    other = ur_read_int(savef);
+
+    if (other & 1)
+        o->o_bag = ur_read_bag(savef);
+    if (other & 2)
+        o->next_obj = ur_read_object_stack(savef);
+
+    return(o);
+}
+
+int
+list_size(struct linked_list *l)
+{
+    int cnt=0;
+
+    if (l == NULL)
+        return(0);
+
+    while(l != NULL)
+    {
+        cnt++;
+        l = l->l_next;
+    }
+
+    return(cnt);
+}
+
+int
+find_thing_index(struct linked_list *l, struct thing *item)
+{
+    int cnt=0;
+
+    if (l == NULL)
+        return(-1);
+
+    while(l != NULL)
+    {
+        if (item == l->data.th)
+            return(cnt+1);
+
+        cnt++;
+        l = l->l_next;
+    }
+
+    return(0);
+}
+
+
+int
+find_list_index(struct linked_list *l, struct object *item)
+{
+    int cnt=0;
+
+    if (l == NULL)
+        return(-1);
+
+    while(l != NULL)
+    {
+        if (item == l->data.obj)
+            return(cnt+1);
+
+        cnt++;
+        l = l->l_next;
+    }
+
+    return(0);
+}
+
+struct object *
+find_object(struct linked_list *list, int num)
+{
+    int cnt = 0;
+    struct linked_list *l = list;
+	
+    if ( (num < 1) || (list == NULL) )
+        return(NULL);
+    
+	num--;
+
+    for(cnt = 0; cnt < num; cnt++)
+    {
+        if ( l == NULL )
+            return(NULL);
+
+        l = l->l_next;
+    }
+
+    return(l->data.obj);
+}
+
+struct thing *
+find_thing(struct linked_list *list, int num)
+{
+    int cnt = 0;
+    struct linked_list *l = list;
+
+    if ( (num < 1) || (list == NULL) )
+        return(NULL);
+    num--;
+
+    for(cnt = 0; cnt < num; cnt++)
+    {
+        if (l == NULL)
+            return(NULL);
+
+        l = l->l_next;
+    }
+
+    return(l->data.th);
+}
+
+
+void
+ur_write_object_stack(FILE *savef, struct linked_list *l)
+{
+    int cnt;
+
+    ur_write_long(savef, URS_STACKOBJECT);
+
+    ur_write_int(savef, cnt = list_size(l) );
+
+    if (cnt == 0)
+        return;
+
+    while(l != NULL)
+    {
+        ur_write_object(savef, l->data.obj);
+        l = l->l_next;
+    }
+}
+
+void
+ur_write_bag(FILE *savef, struct linked_list *l)
+{
+    int cnt;
+
+    ur_write_long(savef, URS_BAGOBJECT);
+
+    ur_write_int(savef, cnt = list_size(l) );
+
+    if (cnt == 0)
+        return;
+
+    while(l != NULL)
+    {
+        ur_write_object(savef, l->data.obj);
+        l = l->l_next;
+    }
+}
+
+struct linked_list *
+ur_read_object_stack(FILE *savef)
+{
+    long id;
+    int i,cnt;
+    struct linked_list *l = NULL, *previous = NULL, *head = NULL;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_STACKOBJECT);
+
+    cnt = ur_read_int(savef);
+
+    for(i = 0; i < cnt; i++)
+    {
+        l         = new_list();
+        l->l_prev = previous;
+
+        if (previous != NULL)
+            previous->l_next = l;
+
+        l->data.obj = ur_read_object(savef);
+
+        if (previous == NULL)
+            head = l;
+
+        previous = l;
+    }
+
+    if (l != NULL)
+        l->l_next = NULL;
+
+    return(head);
+}
+
+
+struct linked_list *
+ur_read_bag(FILE *savef)
+{
+    long id;
+    int i,cnt;
+    struct linked_list *l = NULL, *previous = NULL, *head = NULL;
+
+    id = ur_read_long(savef);
+
+    assert( id == URS_BAGOBJECT );
+
+    cnt = ur_read_int(savef);
+
+    for(i = 0; i < cnt; i++)
+    {
+        l         = new_list();
+        l->l_prev = previous;
+
+        if (previous != NULL)
+            previous->l_next = l;
+
+        l->data.obj =  ur_read_object(savef);
+
+        if (previous == NULL)
+            head = l;
+
+        previous = l;
+    }
+
+    if (l != NULL)
+        l->l_next = NULL;
+
+    return(head);
+}
+
+void
+ur_fixup_monsters(struct linked_list *l)
+{
+    while(l != NULL)
+    {
+        if (l->data.th->t_chasee == (void *) -1L)
+            l->data.th->t_chasee = &player;
+        else
+            l->data.th->t_chasee = find_thing(mlist, l->data.th->chasee_index);
+
+        l->data.th->t_horde = find_object(lvl_obj, l->data.th->horde_index);
+
+        l = l->l_next;
+    }
+}
+
+void
+ur_write_monsters(FILE *savef, struct linked_list *l)
+{
+    int cnt;
+
+    ur_write_long(savef, URS_MONSTERLIST);
+
+    cnt = list_size(l);
+
+    ur_write_int(savef, cnt);
+
+    if (cnt < 1)
+        return;
+
+    while(l != NULL)
+    {
+        ur_write_thing(savef, l->data.th);
+        l = l->l_next;
+    }
+}
+
+struct linked_list *
+ur_read_monsters(FILE *savef)
+{
+    long id;
+    int i,cnt;
+    struct linked_list *l=NULL, *previous = NULL, *head = NULL;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_MONSTERLIST);
+
+    cnt = ur_read_int(savef);
+
+    if (cnt == 0)
+        return(NULL);
+
+    for(i = 0; i < cnt; i++)
+    {
+        l = new_list();
+
+        l->l_prev = previous;
+
+        if (previous != NULL)
+            previous->l_next = l;
+
+        l->data.th = ur_read_thing(savef);
+
+        if (previous == NULL)
+            head = l;
+
+        previous = l;
+    }
+
+    if (l != NULL)
+        l->l_next = NULL;
+
+    return(head);
+}
+
+void
+ur_write_monster_stats(FILE *savef, struct mstats *m)
+{
+    ur_write_long(savef, URS_MONSTERSTATS);
+    ur_write_short(savef, m->s_str);
+    ur_write_long(savef, m->s_exp);
+    ur_write_int(savef, m->s_lvl);
+    ur_write_int(savef, m->s_arm);
+    ur_write_string(savef, m->s_hpt);
+    ur_write_string(savef, m->s_dmg);
+}
+
+struct mstats *
+ur_read_monster_stats(FILE *savef)
+{
+    long id;
+    struct mstats *m;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_MONSTERSTATS);
+
+    m = ur_alloc( sizeof(struct mstats) );
+
+    m->s_str = ur_read_short(savef);
+    m->s_exp = ur_read_long(savef);
+    m->s_lvl = ur_read_int(savef);
+    m->s_arm = ur_read_int(savef);
+    m->s_hpt = ur_read_string(savef);
+    m->s_dmg = ur_read_string(savef);
+
+    return(m);
+}
+
+void
+ur_write_monster(FILE *savef, struct monster *m)
+{
+    int i;
+
+    ur_write_long(savef, URS_MONSTER);
+    ur_write_string(savef, m->m_name);
+    ur_write_short(savef, m->m_carry);
+    ur_write_int(savef, m->m_normal);
+    ur_write_int(savef, m->m_wander);
+    ur_write_char(savef, m->m_appear);
+    ur_write_string(savef, m->m_intel);
+
+    for(i = 0; i < 10; i++)
+        ur_write_long(savef, m->m_flags[i]);
+
+    ur_write_string(savef, m->m_typesum);
+    ur_write_short(savef, m->m_numsum);
+    ur_write_short(savef, m->m_add_exp);
+    ur_write_monster_stats(savef, &m->m_stats);
+}
+
+struct monster *
+ur_read_monster(FILE *savef)
+{
+    struct monster *m;
+    struct mstats *mstats;
+
+    m = ur_alloc( sizeof(struct monster) );
+
+    m->m_name = ur_read_string(savef);
+    m->m_carry = ur_read_short(savef);
+    m->m_normal = ur_read_int(savef);
+    m->m_wander = ur_read_int(savef);
+    m->m_appear = ur_read_char(savef);
+    m->m_intel = ur_read_string(savef);
+    ur_read(savef, &m->m_flags[0], 10*sizeof(long));
+    m->m_typesum = ur_read_string(savef);
+    m->m_numsum = ur_read_short(savef);
+    m->m_add_exp = ur_read_short(savef);
+
+    mstats = ur_read_monster_stats(savef);
+
+    m->m_stats = *mstats;
+    ur_free(mstats);
+
+    return(m);
+}
+
+void
+ur_write_trap(FILE *savef, struct trap *t)
+{
+    ur_write_long(savef, URS_TRAP);
+    ur_write_coord(savef, t->tr_pos);
+    ur_write_long(savef, t->tr_flags);
+    ur_write_char(savef, t->tr_type);
+    ur_write_char(savef, t->tr_show);
+}
+
+struct trap *
+ur_read_trap(FILE *savef)
+{
+    struct trap *t;
+    long id;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_TRAP);
+
+    t = ur_alloc( sizeof(struct trap));
+
+    t->tr_pos = ur_read_coord(savef);
+    t->tr_flags = ur_read_long(savef);
+    t->tr_type = ur_read_char(savef);
+    t->tr_show = ur_read_char(savef);
+
+    return(t);
+}
+
+void
+ur_write_stats(FILE *savef, struct stats *s)
+{
+    ur_write_long(savef, URS_STATS);
+    ur_write_string(savef, s->s_dmg);
+    ur_write_long(savef, s->s_exp);
+    ur_write_int(savef, s->s_hpt);
+    ur_write_int(savef, s->s_pack);
+    ur_write_int(savef, s->s_carry);
+    ur_write_int(savef, s->s_lvl);
+    ur_write_int(savef, s->s_arm);
+    ur_write_int(savef, s->s_acmod);
+    ur_write_int(savef, s->s_power);
+    ur_write_int(savef, s->s_str);
+    ur_write_int(savef, s->s_intel);
+    ur_write_int(savef, s->s_wisdom);
+    ur_write_int(savef, s->s_dext);
+    ur_write_int(savef, s->s_const);
+    ur_write_int(savef, s->s_charisma);
+}
+
+struct stats *
+ur_read_stats(FILE *savef)
+{
+    struct stats *s;
+    long id;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_STATS);
+
+    s = ur_alloc(sizeof(struct stats));
+
+    s->s_dmg = ur_read_string(savef);
+    s->s_exp = ur_read_long(savef);
+    s->s_hpt = ur_read_int(savef);
+    s->s_pack = ur_read_int(savef);
+    s->s_carry = ur_read_int(savef);
+    s->s_lvl = ur_read_int(savef);
+    s->s_arm = ur_read_int(savef);
+    s->s_acmod = ur_read_int(savef);
+    s->s_power = ur_read_int(savef);
+    s->s_str = ur_read_int(savef);
+    s->s_intel = ur_read_int(savef);
+    s->s_wisdom = ur_read_int(savef);
+    s->s_dext = ur_read_int(savef);
+    s->s_const = ur_read_int(savef);
+    s->s_charisma = ur_read_int(savef);
+
+    return(s);
+}
+
+void
+ur_write_thing(FILE *savef, struct thing *t)
+{
+    int i;
+
+    ur_write_long(savef, URS_THING);
+    ur_write_bag(savef, t->t_pack);
+    ur_write_stats(savef, &t->t_stats);
+    ur_write_stats(savef, &t->maxstats);
+    ur_write_int(savef, t->t_ischasing);
+
+    if (t->t_chasee == &player)
+        ur_write_long(savef, -1L);
+    else if (t->t_chasee == NULL)
+         ur_write_long(savef, 0L);
+    else
+    {
+        long m;
+		
+        m = find_thing_index(mlist, t->t_chasee);
+		
+        ur_write_long(savef,m);
+    }
+
+    ur_write_long(savef, find_list_index(lvl_obj, t->t_horde));
+    ur_write_coord(savef, t->t_pos);
+    ur_write_coord(savef, t->t_oldpos);
+    ur_write_coord(savef, t->t_nxtpos);
+
+    for(i = 0; i < 16; i++)
+        ur_write_long(savef, t->t_flags[i]);
+
+    ur_write_int(savef, t->t_praycnt);
+    ur_write_int(savef, t->t_trans);
+    ur_write_int(savef, t->t_turn);
+    ur_write_int(savef, t->t_wasshot);
+    ur_write_int(savef, t->t_ctype);
+    ur_write_int(savef, t->t_index);
+    ur_write_int(savef, t->t_no_move);
+    ur_write_int(savef, t->t_rest_hpt);
+    ur_write_int(savef, t->t_rest_pow);
+    ur_write_int(savef, t->t_doorgoal);
+    ur_write_char(savef, t->t_type);
+    ur_write_char(savef, t->t_disguise);
+    ur_write_char(savef, t->t_oldch);
+}
+
+struct thing *
+ur_read_thing(FILE *savef)
+{
+    long id;
+    int i;
+    struct thing *t;
+    struct stats *s;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_THING);
+
+    t = ur_alloc( sizeof(struct thing) );
+
+    t->t_pack = ur_read_bag(savef);
+
+    s = ur_read_stats(savef);
+    t->t_stats = *s;
+    ur_free(s);
+
+    s = ur_read_stats(savef);
+    t->maxstats = *s;
+    ur_free(s);
+
+    t->t_ischasing = ur_read_int(savef);
+    t->chasee_index = ur_read_long(savef);
+    t->horde_index = ur_read_long(savef);
+    t->t_pos = ur_read_coord(savef);
+    t->t_oldpos = ur_read_coord(savef);
+    t->t_nxtpos = ur_read_coord(savef);
+
+    for(i = 0; i < 16; i++)
+        t->t_flags[i] = ur_read_long(savef);
+
+    t->t_praycnt = ur_read_int(savef);
+    t->t_trans = ur_read_int(savef);
+    t->t_turn = ur_read_int(savef);
+    t->t_wasshot = ur_read_int(savef);
+    t->t_ctype = ur_read_int(savef);
+    t->t_index = ur_read_int(savef);
+    t->t_no_move = ur_read_int(savef);
+    t->t_rest_hpt = ur_read_int(savef);
+    t->t_rest_pow = ur_read_int(savef);
+    t->t_doorgoal = ur_read_int(savef);
+    t->t_type = ur_read_char(savef);
+    t->t_disguise = ur_read_char(savef);
+    t->t_oldch = ur_read_char(savef);
+
+    return(t);
+}
+
+void
+ur_write_window(FILE *savef, WINDOW *win)
+{
+    int i,j;
+
+    ur_write_long(savef, URS_WINDOW);
+
+    ur_write_int(savef, win->_maxy);
+    ur_write_int(savef, win->_maxx);
+
+    for(i=0; i < win->_maxy; i++)
+        for(j = 0; j < win->_maxx; j++)
+            ur_write_ulong(savef, mvwinch(win,i,j));
+}
+
+void
+ur_read_window(FILE *savef, WINDOW *win)
+{
+    int i,j;
+    int maxy, maxx;
+    long id;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_WINDOW);
+
+    maxy = ur_read_int(savef);
+    maxx = ur_read_int(savef);
+
+    for(i=0; i < maxy; i++)
+        for(j = 0; j < maxx; j++)
+            mvwaddch(win,i,j,ur_read_long(savef));
+}
+
+void
+ur_write_daemons(FILE *savef)
+{
+    int i;
+    int id=0;
+
+    ur_write_long(savef, URS_DAEMONS);
+
+    for(i = 0; i < MAXDAEMONS; i++)
+    {
+        ur_write_int(savef, d_list[i].d_type );
+        ur_write_int(savef, d_list[i].d_when );
+        ur_write_int(savef, d_list[i].d_id);
+
+        if (d_list[i].d_id == FUSE_UNSUMMON)
+            id = find_thing_index(mlist, d_list[i].d_arg);
+
+        if (d_list[i].d_id == DAEMON_DOCTOR)
+            id = find_thing_index(mlist, d_list[i].d_arg);
+
+        ur_write_int(savef, id);
+        ur_write_int(savef, d_list[i].d_time );
+    }
+}
+
+void
+ur_read_daemons(FILE *savef)
+{
+    long id;
+    int i;
+    demoncnt = 0;
+	
+    id = ur_read_long(savef);
+
+    assert(id == URS_DAEMONS);
+
+    for(i = 0; i < MAXDAEMONS; i++)
+    {
+        d_list[i].d_type = ur_read_int(savef);
+        d_list[i].d_when = ur_read_int(savef);
+        d_list[i].d_id = ur_read_int(savef);
+        id = ur_read_int(savef);
+        d_list[i].d_time = ur_read_int(savef);
+
+        if ((d_list[i].d_type != EMPTY) && (d_list[i].d_id == FUSE_UNSUMMON))
+        {
+            d_list[i].d_arg = find_thing(mlist,id);
+
+            if (d_list[i].d_arg == NULL)
+                d_list[i].d_type = EMPTY;
+        }
+
+        if ((d_list[i].d_type != EMPTY) &&  (d_list[i].d_id == DAEMON_DOCTOR) )
+        {
+            if (id == 0)
+                d_list[i].d_arg = &player;
+            else
+                d_list[i].d_arg = find_thing(mlist, id);
+
+            if (d_list[i].d_arg == NULL)
+                d_list[i].d_type = EMPTY;
+        }
+
+        if (d_list[i].d_type != EMPTY)
+            demoncnt++;
+    }
+}
+
+void
+save_file(FILE *savef)
+{
+    int i,weapon,armor,ring=0,room= -1,monster;
+
+    ur_write_string(savef, save_format);
+
+    ur_write_string(savef,"\nScroll Names\n");
+    for(i = 0; i < MAXSCROLLS; i++)
+        ur_write_string(savef,s_names[i]);
+
+    ur_write_string(savef,"\nPotion Colors\n");
+    for(i = 0; i < MAXPOTIONS; i++)
+        ur_write_string(savef,p_colors[i]);
+
+    ur_write_string(savef,"\nRing Stones\n");
+    for(i = 0; i < MAXRINGS; i++)
+        ur_write_string(savef,r_stones[i]);
+
+    ur_write_string(savef,"\nStick types\n");
+    for(i = 0; i < MAXSTICKS; i++)
+        ur_write_string(savef,ws_made[i]);
+
+    ur_write_string(savef,"\nStick types\n");
+    for(i = 0; i < MAXSTICKS; i++)
+        ur_write_string(savef,ws_type[i]);
+
+    ur_write_string(savef, "\nTraps on this level\n");
+    ur_write_int(savef, MAXTRAPS);
+    for(i = 0; i < MAXTRAPS; i++)
+        ur_write_trap(savef, &traps[i]);
+
+    ur_write_string(savef,"\nRooms on this level\n");
+    ur_write_int(savef, MAXROOMS);
+    for(i = 0; i < MAXROOMS; i++)
+    {
+        ur_write_room(savef, &rooms[i]);
+
+        if (&rooms[i] == oldrp)
+            room = i;
+    }
+    ur_write_int(savef,room); /* save for recovery of oldrp */
+
+    ur_write_string(savef,"\nThe Rogue\n");
+    ur_write_thing(savef, &player);
+
+    ur_write_string(savef,"\nObjects on this level\n");
+    ur_write_bag(savef, lvl_obj);
+
+    ur_write_string(savef,"\nRogue's Familiar, if any \n");
+    ur_write_monsters(savef, fam_ptr);
+
+    ur_write_string(savef,"\nMonsters on this level\n");
+    ur_write_monsters(savef, mlist);
+
+    monster = find_thing_index(mlist, beast);
+    ur_write_int(savef, monster);
+
+    ur_write_string(savef,"\nItems in use by rogue\n");
+    weapon = find_list_index(player.t_pack, cur_weapon);
+    armor  = find_list_index(player.t_pack, cur_armor);
+    ur_write_int(savef, weapon);
+    ur_write_int(savef, armor);
+
+    for(i=0; i < 10; i++)
+    {
+        if (cur_ring[i] == NULL)
+            ring = find_list_index(player.t_pack, cur_ring[i]);
+
+        ur_write_int(savef, ring);
+    }
+
+    ur_write_string(savef,"\nActive Daemons and Fuses\n");
+    ur_write_daemons(savef);
+
+    ur_write_string(savef, "\nMisc\n");
+
+    for(i = 0; i < 10; i++)
+        ur_write_string(savef, msgbuf[i]);
+
+    ur_write_int(savef, msg_index);
+    ur_write_int(savef, foodlev);
+    ur_write_int(savef, ntraps);
+    ur_write_int(savef, dnum);
+    ur_write_int(savef, max_level);
+    ur_write_int(savef, lost_dext);
+    ur_write_int(savef, no_command);
+    ur_write_int(savef, level);
+    ur_write_int(savef, see_dist);
+    ur_write_int(savef, no_food);
+    ur_write_int(savef, count);
+    ur_write_int(savef, food_left);
+    ur_write_int(savef, group);
+    ur_write_int(savef, hungry_state);
+    ur_write_int(savef, infest_dam);
+    ur_write_int(savef, lost_str);
+    ur_write_int(savef, hold_count);
+    ur_write_int(savef, trap_tries);
+    ur_write_int(savef, has_artifact);
+    ur_write_int(savef, picked_artifact);
+    ur_write_int(savef, luck);
+    ur_write_int(savef, resurrect);
+    ur_write_int(savef, fam_type);
+    ur_write_int(savef, mons_summoned);
+    ur_write_char(savef, PLAYER);
+    ur_write_char(savef, take);
+    ur_write_char(savef, runch);
+    ur_write_int(savef, char_type);
+    ur_write_int(savef, inv_type);
+    ur_write_int(savef,  pool_teleport);
+    ur_write_int(savef, inwhgt);
+    ur_write_int(savef, after);
+    ur_write_int(savef, waswizard);
+    ur_write_int(savef, canwizard);
+    ur_write_int(savef, playing);
+    ur_write_int(savef, running);
+    ur_write_int(savef, fighting);
+    ur_write_int(savef, wizard);
+    ur_write_int(savef, wiz_verbose);
+    ur_write_int(savef, moving);
+    ur_write_coord(savef, delta);
+    ur_write_int(savef, levtype);
+    ur_write_int(savef, purse);
+    ur_write_int(savef, total);
+    ur_write_window(savef, cw);
+    ur_write_window(savef, hw);
+    ur_write_window(savef, mw);
+    ur_write_window(savef, stdscr);
+
+    ur_write_string(savef,"\nGame Options\n");
+    ur_write_int(savef, terse);
+    ur_write_int(savef, door_stop);
+    ur_write_int(savef, doorstop);
+    ur_write_int(savef, jump);
+    ur_write_int(savef, firstmove);
+    ur_write_int(savef, askme);
+    ur_write_string(savef,whoami);
+    ur_write_string(savef,fruit);
+    ur_write_string(savef,file_name);
+    ur_write_string(savef,score_file);
+
+    ur_write_string(savef,"\nEnd of UltraRogue Game State\n");
+}
+
+#define DUMPSTRING { str = ur_read_string(savef); /*printf("%s",str);*/ ur_free(str); }
+
+int
+restore_file(FILE *savef)
+{
+    int i,j;
+    char *str;
+    struct trap *t;
+    struct room *r;
+    struct thing *p;
+
+    str = ur_read_string(savef);
+
+    if (strcmp(str, save_format) != 0)
+    {
+        printf("Save Game Version: %s\n", str);
+        printf("Real Game Version: %s\n", save_format);
+        printf("Sorry, versions don't match.\n");
+        return(FALSE);
+    }
+
+    DUMPSTRING
+    for(i=0; i < MAXSCROLLS; i++)
+        s_names[i] = ur_read_string(savef);
+
+    DUMPSTRING
+    for(i=0; i < MAXPOTIONS; i++)
+        p_colors[i] = ur_read_string(savef);
+
+    DUMPSTRING
+    for(i=0; i < MAXRINGS; i++)
+        r_stones[i] = ur_read_string(savef);
+
+    DUMPSTRING
+    for(i=0; i < MAXSTICKS; i++)
+        ws_made[i] = ur_read_string(savef);
+
+    DUMPSTRING
+    for(i=0; i < MAXSTICKS; i++)
+        ws_type[i] = ur_read_string(savef);
+
+    DUMPSTRING
+    i = ur_read_int(savef);
+    assert(i == MAXTRAPS);
+
+    for(i=0;i<MAXTRAPS;i++)
+    {
+        t = ur_read_trap(savef);
+        traps[i] = *t;
+        ur_free(t);
+    }
+
+    DUMPSTRING
+    i = ur_read_int(savef);
+    assert(i == MAXROOMS);
+
+    for(i=0;i<MAXROOMS;i++)
+    {
+        r = ur_read_room(savef);
+        rooms[i] = *r;
+        ur_free(r);
+    }
+    i = ur_read_int(savef);
+    oldrp = &rooms[i];
+
+    DUMPSTRING
+    p = ur_read_thing(savef);
+    player = *p;
+    ur_free(p);
+
+    DUMPSTRING
+    lvl_obj = ur_read_bag(savef);
+
+    DUMPSTRING
+    fam_ptr = ur_read_monsters(savef);
+
+    DUMPSTRING
+    mlist = ur_read_monsters(savef);
+    i = ur_read_int(savef);
+    beast = find_thing(mlist, i);
+
+    ur_fixup_monsters(fam_ptr);
+    ur_fixup_monsters(fam_ptr);
+
+    DUMPSTRING
+    i = ur_read_int(savef);
+    cur_weapon = find_object(player.t_pack, i);
+
+    i = ur_read_int(savef);
+    cur_armor = find_object(player.t_pack, i);
+
+    for(j=0; j < 10; j++)
+    {
+        i = ur_read_int(savef);
+        if (i == -1)
+            cur_ring[j] = NULL;
+        else
+            cur_ring[j] = find_object(player.t_pack, i);
+    }
+
+    DUMPSTRING
+    ur_read_daemons(savef);
+
+    DUMPSTRING
+    for(i = 0; i < 10; i++)
+    {
+        str = ur_read_string(savef);
+        strcpy(&msgbuf[i][0],str);
+        ur_free(str);
+    }
+
+    msg_index = ur_read_int(savef);
+
+    foodlev  = ur_read_int(savef);
+    ntraps = ur_read_int(savef);
+    dnum = ur_read_int(savef);
+    max_level = ur_read_int(savef);
+    lost_dext = ur_read_int(savef);
+    no_command = ur_read_int(savef);
+    level = ur_read_int(savef);
+    see_dist  = ur_read_int(savef);
+    no_food = ur_read_int(savef);
+    count = ur_read_int(savef);
+    food_left = ur_read_int(savef);
+    group = ur_read_int(savef);
+    hungry_state = ur_read_int(savef);
+    infest_dam = ur_read_int(savef);
+    lost_str = ur_read_int(savef);
+    hold_count = ur_read_int(savef);
+    trap_tries = ur_read_int(savef);
+    has_artifact  = ur_read_int(savef);
+    picked_artifact  = ur_read_int(savef);
+    luck = ur_read_int(savef);
+    resurrect = ur_read_int(savef);
+    fam_type = ur_read_int(savef);
+    mons_summoned = ur_read_int(savef);
+    PLAYER = ur_read_char(savef);
+    take = ur_read_char(savef);
+    runch = ur_read_char(savef);
+    char_type = ur_read_int(savef);
+    inv_type = ur_read_int(savef);
+    pool_teleport = ur_read_int(savef);
+    inwhgt = ur_read_int(savef);
+    after = ur_read_int(savef);
+    waswizard = ur_read_int(savef);
+    canwizard = ur_read_int(savef);
+    playing = ur_read_int(savef);
+    running = ur_read_int(savef);
+    fighting = ur_read_int(savef);
+    wizard = ur_read_int(savef);
+    wiz_verbose = ur_read_int(savef);
+    moving = ur_read_int(savef);
+    delta = ur_read_coord(savef);
+    levtype = ur_read_int(savef);
+    purse = ur_read_int(savef);
+    total = ur_read_int(savef);
+    ur_read_window(savef, cw);
+    ur_read_window(savef, hw);
+    ur_read_window(savef, mw);
+    ur_read_window(savef, stdscr);
+
+    DUMPSTRING
+    terse = ur_read_int(savef);
+    door_stop = ur_read_int(savef);
+    doorstop = ur_read_int(savef);
+    jump = ur_read_int(savef);
+    firstmove = ur_read_int(savef);
+    askme = ur_read_int(savef);
+    str = ur_read_string(savef);
+    strcpy(whoami,str);
+    ur_free(str);
+    str = ur_read_string(savef);
+    strcpy(fruit,str);
+    ur_free(str);
+    str = ur_read_string(savef);
+    strcpy(file_name,str);
+    ur_free(str);
+    str = ur_read_string(savef);
+    strcpy(score_file,str);
+    ur_free(str);
+
+    DUMPSTRING
+    return(TRUE);
+}
+
+