Alchemy jugs are refilled by the alchemy() fuse, which takes a pointer
to the jug object as an argument. When written to a save file and read
back out, the pointer is unlikely to point anywhere useful.
Instead, rs_write_daemons() now stores an index into the player's pack
or the list of objects on the floor. rs_read_daemons() uses this
number to locate the object when restoring.
This change should not cause any new issues with old savefiles, but it
is unable to make a broken alchemy jug work again.
Daemons and fuses take a single argument, nominally an int but either
ignored or unsafely cast to a pointer. Its type has now been changed
to void*.
The save/restore code no longer tries to store this argument in the
savefile. For doctor(), this is not a problem, because player is the
only argument it is ever given as a daemon. However, alchemy() will
fail to do anything when passed NULL. Fixing this would be complicated
but possible.
Summary: the code is slightly safer, but alchemy jugs are guaranteed to
stop working after save and restore, instead of just extremely likely.
The save/restore code took the pointer intended as an argument for the
doctor() daemon and wrote it to the savefile as an int. I don't know
why it took so long to fail horribly. The problem has been avoided by
replacing the value with &player when restoring. That seems to be the
only argument ever actually used.
The code also writes only four bytes for an unsigned long; if
sizeof(long) == 8, it casts to unsigned int first. It failed to do the
cast when reading back, with the result that four bytes were read and
the other half of the number was effectively uninitialized.
It apparently works now, but the save/restore code ought still to be
regarded as decidedly unfortunate.
In all games, rs_write_room_reference() stored -1 for a nonexistent
room, but rs_read_room_reference() did not check for out-of-bounds
values, leading to pointers to rooms[-1], which sometimes caused
crashes. rs_read_room_reference() has now been modified to use NULL
instead.
Some of the games required further changes to replace NULL with the
pointer to the actual room. Others are capable of handling NULL for
objects not in any room.
A buffer called curpurch, which stores a description of an item in a
trading post which the player might be interested in, was only 15
bytes. It was overflowing into oldrp, a room pointer, leading to
segfaults. The size of curpurch has been increased to LINELEN*2,
which matches the size of prbuf, which is returned by inv_name and
then strcpy()'d to curpurch. As long as nothing overflows prbuf it
should be safe now.
NOTE that this breaks savefile compatibility.