2016-09-19 08:47:59 +00:00
|
|
|
|
2016-09-19 10:53:42 +00:00
|
|
|
#include "a_doomglobal.h"
|
2016-09-19 13:07:53 +00:00
|
|
|
#include "a_hexenglobal.h"
|
|
|
|
#include "a_strifeglobal.h"
|
2016-09-19 10:53:42 +00:00
|
|
|
#include "ravenshared.h"
|
2016-09-19 11:36:58 +00:00
|
|
|
#include "a_weaponpiece.h"
|
2016-09-19 13:07:53 +00:00
|
|
|
#include "d_dehacked.h"
|
2016-09-19 10:53:42 +00:00
|
|
|
|
2016-09-19 08:34:54 +00:00
|
|
|
// For NULL states, which aren't owned by any actor, the owner
|
|
|
|
// is recorded as AActor with the following state. AActor should
|
|
|
|
// never actually have this many states of its own, so this
|
|
|
|
// is (relatively) safe.
|
|
|
|
|
|
|
|
#define NULL_STATE_INDEX 127
|
|
|
|
|
|
|
|
// These are special tokens found in the data stream of an archive.
|
|
|
|
// Whenever a new object is encountered, it gets created using new and
|
|
|
|
// is then asked to serialize itself before processing of the previous
|
|
|
|
// object continues. This can result in some very deep recursion if
|
|
|
|
// you aren't careful about how you organize your data.
|
|
|
|
|
|
|
|
#define NEW_OBJ ((BYTE)1) // Data for a new object follows
|
|
|
|
#define NEW_CLS_OBJ ((BYTE)2) // Data for a new class and object follows
|
|
|
|
#define OLD_OBJ ((BYTE)3) // Reference to an old object follows
|
|
|
|
#define NULL_OBJ ((BYTE)4) // Load as NULL
|
|
|
|
#define M1_OBJ ((BYTE)44) // Load as (DObject*)-1
|
|
|
|
|
|
|
|
#define NEW_PLYR_OBJ ((BYTE)5) // Data for a new player follows
|
|
|
|
#define NEW_PLYR_CLS_OBJ ((BYTE)6) // Data for a new class and player follows
|
|
|
|
|
|
|
|
#define NEW_NAME ((BYTE)27) // A new name follows
|
|
|
|
#define OLD_NAME ((BYTE)28) // Reference to an old name follows
|
|
|
|
#define NIL_NAME ((BYTE)33) // Load as NULL
|
|
|
|
|
|
|
|
#define NEW_SPRITE ((BYTE)11) // A new sprite name follows
|
|
|
|
#define OLD_SPRITE ((BYTE)12) // Reference to an old sprite name follows
|
|
|
|
|
|
|
|
inline FArchive &operator<< (FArchive &arc, FLinkedSector &link)
|
|
|
|
{
|
|
|
|
arc << link.Sector << link.Type;
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// P_ArchiveWorld
|
|
|
|
//
|
|
|
|
void P_SerializeWorld (FArchive &arc)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
sector_t *sec;
|
|
|
|
line_t *li;
|
|
|
|
zone_t *zn;
|
|
|
|
|
|
|
|
// do sectors
|
|
|
|
for (i = 0, sec = sectors; i < numsectors; i++, sec++)
|
|
|
|
{
|
|
|
|
arc << sec->floorplane
|
|
|
|
<< sec->ceilingplane;
|
|
|
|
arc << sec->lightlevel;
|
|
|
|
arc << sec->special;
|
|
|
|
arc << sec->soundtraversed
|
|
|
|
<< sec->seqType
|
|
|
|
<< sec->friction
|
|
|
|
<< sec->movefactor
|
|
|
|
<< sec->stairlock
|
|
|
|
<< sec->prevsec
|
|
|
|
<< sec->nextsec
|
|
|
|
<< sec->planes[sector_t::floor]
|
|
|
|
<< sec->planes[sector_t::ceiling]
|
|
|
|
<< sec->heightsec
|
|
|
|
<< sec->bottommap << sec->midmap << sec->topmap
|
|
|
|
<< sec->gravity;
|
|
|
|
P_SerializeTerrain(arc, sec->terrainnum[0]);
|
|
|
|
P_SerializeTerrain(arc, sec->terrainnum[1]);
|
|
|
|
arc << sec->damageamount;
|
|
|
|
arc << sec->damageinterval
|
|
|
|
<< sec->leakydamage
|
|
|
|
<< sec->damagetype
|
|
|
|
<< sec->sky
|
|
|
|
<< sec->MoreFlags
|
|
|
|
<< sec->Flags
|
|
|
|
<< sec->Portals[sector_t::floor] << sec->Portals[sector_t::ceiling]
|
|
|
|
<< sec->ZoneNumber;
|
|
|
|
arc << sec->interpolations[0]
|
|
|
|
<< sec->interpolations[1]
|
|
|
|
<< sec->interpolations[2]
|
|
|
|
<< sec->interpolations[3]
|
|
|
|
<< sec->SeqName;
|
|
|
|
|
|
|
|
sec->e->Serialize(arc);
|
|
|
|
if (arc.IsStoring ())
|
|
|
|
{
|
|
|
|
arc << sec->ColorMap->Color
|
|
|
|
<< sec->ColorMap->Fade;
|
|
|
|
BYTE sat = sec->ColorMap->Desaturate;
|
|
|
|
arc << sat;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PalEntry color, fade;
|
|
|
|
BYTE desaturate;
|
|
|
|
arc << color << fade
|
|
|
|
<< desaturate;
|
|
|
|
sec->ColorMap = GetSpecialLights (color, fade, desaturate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// do lines
|
|
|
|
for (i = 0, li = lines; i < numlines; i++, li++)
|
|
|
|
{
|
|
|
|
arc << li->flags
|
|
|
|
<< li->activation
|
|
|
|
<< li->special
|
|
|
|
<< li->alpha;
|
|
|
|
|
|
|
|
if (P_IsACSSpecial(li->special))
|
|
|
|
{
|
|
|
|
P_SerializeACSScriptNumber(arc, li->args[0], false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
arc << li->args[0];
|
|
|
|
}
|
|
|
|
arc << li->args[1] << li->args[2] << li->args[3] << li->args[4];
|
|
|
|
|
|
|
|
arc << li->portalindex;
|
|
|
|
for (j = 0; j < 2; j++)
|
|
|
|
{
|
|
|
|
if (li->sidedef[j] == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
side_t *si = li->sidedef[j];
|
|
|
|
arc << si->textures[side_t::top]
|
|
|
|
<< si->textures[side_t::mid]
|
|
|
|
<< si->textures[side_t::bottom]
|
|
|
|
<< si->Light
|
|
|
|
<< si->Flags
|
|
|
|
<< si->LeftSide
|
|
|
|
<< si->RightSide
|
|
|
|
<< si->Index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// do zones
|
|
|
|
unsigned numzones = Zones.Size();
|
|
|
|
arc << numzones;
|
|
|
|
|
|
|
|
if (arc.IsLoading())
|
|
|
|
{
|
|
|
|
Zones.Resize(numzones);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0, zn = &Zones[0]; i < (int)numzones; ++i, ++zn)
|
|
|
|
{
|
|
|
|
arc << zn->Environment;
|
|
|
|
}
|
|
|
|
|
|
|
|
arc << linePortals << sectorPortals;
|
|
|
|
P_CollectLinkedPortals();
|
|
|
|
}
|
|
|
|
|
|
|
|
void P_SerializeWorldActors(FArchive &arc)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
sector_t *sec;
|
|
|
|
line_t *line;
|
|
|
|
|
|
|
|
for (i = 0, sec = sectors; i < numsectors; i++, sec++)
|
|
|
|
{
|
|
|
|
arc << sec->SoundTarget
|
|
|
|
<< sec->SecActTarget
|
|
|
|
<< sec->floordata
|
|
|
|
<< sec->ceilingdata
|
|
|
|
<< sec->lightingdata;
|
|
|
|
}
|
|
|
|
for (auto &s : sectorPortals)
|
|
|
|
{
|
|
|
|
arc << s.mSkybox;
|
|
|
|
}
|
|
|
|
for (i = 0, line = lines; i < numlines; i++, line++)
|
|
|
|
{
|
|
|
|
for (int s = 0; s < 2; s++)
|
|
|
|
{
|
|
|
|
if (line->sidedef[s] != NULL)
|
|
|
|
{
|
|
|
|
DBaseDecal::SerializeChain(arc, &line->sidedef[s]->AttachedDecals);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void extsector_t::Serialize(FArchive &arc)
|
|
|
|
{
|
|
|
|
arc << FakeFloor.Sectors
|
|
|
|
<< Midtex.Floor.AttachedLines
|
|
|
|
<< Midtex.Floor.AttachedSectors
|
|
|
|
<< Midtex.Ceiling.AttachedLines
|
|
|
|
<< Midtex.Ceiling.AttachedSectors
|
|
|
|
<< Linked.Floor.Sectors
|
|
|
|
<< Linked.Ceiling.Sectors;
|
|
|
|
}
|
|
|
|
|
|
|
|
FArchive &operator<< (FArchive &arc, side_t::part &p)
|
|
|
|
{
|
|
|
|
arc << p.xOffset << p.yOffset << p.interpolation << p.texture
|
|
|
|
<< p.xScale << p.yScale;// << p.Light;
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
FArchive &operator<< (FArchive &arc, sector_t::splane &p)
|
|
|
|
{
|
|
|
|
arc << p.xform.xOffs << p.xform.yOffs << p.xform.xScale << p.xform.yScale
|
|
|
|
<< p.xform.Angle << p.xform.baseyOffs << p.xform.baseAngle
|
|
|
|
<< p.Flags << p.Light << p.Texture << p.TexZ << p.alpha;
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// ArchiveSubsectors
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
void RecalculateDrawnSubsectors();
|
|
|
|
|
|
|
|
void P_SerializeSubsectors(FArchive &arc)
|
|
|
|
{
|
|
|
|
int num_verts, num_subs, num_nodes;
|
|
|
|
BYTE by;
|
|
|
|
|
|
|
|
if (arc.IsStoring())
|
|
|
|
{
|
|
|
|
if (hasglnodes)
|
|
|
|
{
|
|
|
|
arc << numvertexes << numsubsectors << numnodes; // These are only for verification
|
|
|
|
for(int i=0;i<numsubsectors;i+=8)
|
|
|
|
{
|
|
|
|
by = 0;
|
|
|
|
for(int j=0;j<8;j++)
|
|
|
|
{
|
|
|
|
if (i+j<numsubsectors && (subsectors[i+j].flags & SSECF_DRAWN))
|
|
|
|
{
|
|
|
|
by |= (1<<j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
arc << by;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int v = 0;
|
|
|
|
arc << v << v << v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
arc << num_verts << num_subs << num_nodes;
|
|
|
|
if (num_verts != numvertexes ||
|
|
|
|
num_subs != numsubsectors ||
|
|
|
|
num_nodes != numnodes)
|
|
|
|
{
|
|
|
|
// Nodes don't match - we can't use this info
|
|
|
|
for(int i=0;i<num_subs;i+=8)
|
|
|
|
{
|
|
|
|
// Skip the subsector info.
|
|
|
|
arc << by;
|
|
|
|
}
|
|
|
|
if (hasglnodes)
|
|
|
|
{
|
|
|
|
RecalculateDrawnSubsectors();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(int i=0;i<numsubsectors;i+=8)
|
|
|
|
{
|
|
|
|
arc << by;
|
|
|
|
for(int j=0;j<8;j++)
|
|
|
|
{
|
|
|
|
if ((by & (1<<j)) && i+j<numsubsectors)
|
|
|
|
{
|
|
|
|
subsectors[i+j].flags |= SSECF_DRAWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FArchive &FArchive::WriteObject (DObject *obj)
|
|
|
|
{
|
|
|
|
player_t *player;
|
|
|
|
BYTE id[2];
|
|
|
|
|
|
|
|
if (obj == NULL)
|
|
|
|
{
|
|
|
|
id[0] = NULL_OBJ;
|
|
|
|
Write (id, 1);
|
|
|
|
}
|
|
|
|
else if (obj == (DObject*)~0)
|
|
|
|
{
|
|
|
|
id[0] = M1_OBJ;
|
|
|
|
Write (id, 1);
|
|
|
|
}
|
|
|
|
else if (obj->ObjectFlags & OF_EuthanizeMe)
|
|
|
|
{
|
|
|
|
// Objects that want to die are not saved to the archive, but
|
|
|
|
// we leave the pointers to them alone.
|
|
|
|
id[0] = NULL_OBJ;
|
|
|
|
Write (id, 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PClass *type = obj->GetClass();
|
|
|
|
DWORD *classarcid;
|
|
|
|
|
|
|
|
if (type == RUNTIME_CLASS(DObject))
|
|
|
|
{
|
|
|
|
//I_Error ("Tried to save an instance of DObject.\n"
|
|
|
|
// "This should not happen.\n");
|
|
|
|
id[0] = NULL_OBJ;
|
|
|
|
Write (id, 1);
|
|
|
|
}
|
|
|
|
else if (NULL == (classarcid = ClassToArchive.CheckKey(type)))
|
|
|
|
{
|
|
|
|
// No instances of this class have been written out yet.
|
|
|
|
// Write out the class, then write out the object. If this
|
|
|
|
// is an actor controlled by a player, make note of that
|
|
|
|
// so that it can be overridden when moving around in a hub.
|
|
|
|
if (obj->IsKindOf (RUNTIME_CLASS (AActor)) &&
|
|
|
|
(player = static_cast<AActor *>(obj)->player) &&
|
|
|
|
player->mo == obj)
|
|
|
|
{
|
|
|
|
id[0] = NEW_PLYR_CLS_OBJ;
|
|
|
|
id[1] = (BYTE)(player - players);
|
|
|
|
Write (id, 2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
id[0] = NEW_CLS_OBJ;
|
|
|
|
Write (id, 1);
|
|
|
|
}
|
|
|
|
WriteClass (type);
|
|
|
|
// Printf ("Make class %s (%u)\n", type->Name, m_File->Tell());
|
|
|
|
MapObject (obj);
|
|
|
|
obj->SerializeUserVars (*this);
|
|
|
|
obj->Serialize (*this);
|
|
|
|
obj->CheckIfSerialized ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// An instance of this class has already been saved. If
|
|
|
|
// this object has already been written, save a reference
|
|
|
|
// to the saved object. Otherwise, save a reference to the
|
|
|
|
// class, then save the object. Again, if this is a player-
|
|
|
|
// controlled actor, remember that.
|
|
|
|
DWORD *objarcid = ObjectToArchive.CheckKey(obj);
|
|
|
|
|
|
|
|
if (objarcid == NULL)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (obj->IsKindOf (RUNTIME_CLASS (AActor)) &&
|
|
|
|
(player = static_cast<AActor *>(obj)->player) &&
|
|
|
|
player->mo == obj)
|
|
|
|
{
|
|
|
|
id[0] = NEW_PLYR_OBJ;
|
|
|
|
id[1] = (BYTE)(player - players);
|
|
|
|
Write (id, 2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
id[0] = NEW_OBJ;
|
|
|
|
Write (id, 1);
|
|
|
|
}
|
|
|
|
WriteCount (*classarcid);
|
|
|
|
// Printf ("Reuse class %s (%u)\n", type->Name, m_File->Tell());
|
|
|
|
MapObject (obj);
|
|
|
|
obj->SerializeUserVars (*this);
|
|
|
|
obj->Serialize (*this);
|
|
|
|
obj->CheckIfSerialized ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
id[0] = OLD_OBJ;
|
|
|
|
Write (id, 1);
|
|
|
|
WriteCount (*objarcid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AActor::Serialize(FArchive &arc)
|
|
|
|
{
|
|
|
|
Super::Serialize(arc);
|
|
|
|
|
|
|
|
if (arc.IsStoring())
|
|
|
|
{
|
|
|
|
arc.WriteSprite(sprite);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprite = arc.ReadSprite();
|
|
|
|
}
|
|
|
|
|
|
|
|
arc << __Pos
|
|
|
|
<< Angles.Yaw
|
|
|
|
<< Angles.Pitch
|
|
|
|
<< Angles.Roll
|
|
|
|
<< frame
|
|
|
|
<< Scale
|
|
|
|
<< RenderStyle
|
|
|
|
<< renderflags
|
|
|
|
<< picnum
|
|
|
|
<< floorpic
|
|
|
|
<< ceilingpic
|
|
|
|
<< TIDtoHate
|
|
|
|
<< LastLookPlayerNumber
|
|
|
|
<< LastLookActor
|
|
|
|
<< effects
|
|
|
|
<< Alpha
|
|
|
|
<< fillcolor
|
|
|
|
<< Sector
|
|
|
|
<< floorz
|
|
|
|
<< ceilingz
|
|
|
|
<< dropoffz
|
|
|
|
<< floorsector
|
|
|
|
<< ceilingsector
|
|
|
|
<< radius
|
|
|
|
<< Height
|
|
|
|
<< projectilepassheight
|
|
|
|
<< Vel
|
|
|
|
<< tics
|
|
|
|
<< state
|
|
|
|
<< DamageVal;
|
|
|
|
if (DamageVal == 0x40000000 || DamageVal == -1)
|
|
|
|
{
|
|
|
|
DamageVal = -1;
|
|
|
|
DamageFunc = GetDefault()->DamageFunc;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DamageFunc = nullptr;
|
|
|
|
}
|
|
|
|
P_SerializeTerrain(arc, floorterrain);
|
|
|
|
arc << projectileKickback
|
|
|
|
<< flags
|
|
|
|
<< flags2
|
|
|
|
<< flags3
|
|
|
|
<< flags4
|
|
|
|
<< flags5
|
|
|
|
<< flags6
|
|
|
|
<< flags7
|
|
|
|
<< weaponspecial
|
|
|
|
<< special1
|
|
|
|
<< special2
|
|
|
|
<< specialf1
|
|
|
|
<< specialf2
|
|
|
|
<< health
|
|
|
|
<< movedir
|
|
|
|
<< visdir
|
|
|
|
<< movecount
|
|
|
|
<< strafecount
|
|
|
|
<< target
|
|
|
|
<< lastenemy
|
|
|
|
<< LastHeard
|
|
|
|
<< reactiontime
|
|
|
|
<< threshold
|
|
|
|
<< player
|
|
|
|
<< SpawnPoint
|
|
|
|
<< SpawnAngle
|
|
|
|
<< StartHealth
|
|
|
|
<< skillrespawncount
|
|
|
|
<< tracer
|
|
|
|
<< Floorclip
|
|
|
|
<< tid
|
|
|
|
<< special;
|
|
|
|
if (P_IsACSSpecial(special))
|
|
|
|
{
|
|
|
|
P_SerializeACSScriptNumber(arc, args[0], false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
arc << args[0];
|
|
|
|
}
|
|
|
|
arc << args[1] << args[2] << args[3] << args[4];
|
|
|
|
arc << accuracy << stamina;
|
|
|
|
arc << goal
|
|
|
|
<< waterlevel
|
|
|
|
<< MinMissileChance
|
|
|
|
<< SpawnFlags
|
|
|
|
<< Inventory
|
|
|
|
<< InventoryID;
|
|
|
|
arc << FloatBobPhase
|
|
|
|
<< Translation
|
|
|
|
<< SeeSound
|
|
|
|
<< AttackSound
|
|
|
|
<< PainSound
|
|
|
|
<< DeathSound
|
|
|
|
<< ActiveSound
|
|
|
|
<< UseSound
|
|
|
|
<< BounceSound
|
|
|
|
<< WallBounceSound
|
|
|
|
<< CrushPainSound
|
|
|
|
<< Speed
|
|
|
|
<< FloatSpeed
|
|
|
|
<< Mass
|
|
|
|
<< PainChance
|
|
|
|
<< SpawnState
|
|
|
|
<< SeeState
|
|
|
|
<< MeleeState
|
|
|
|
<< MissileState
|
|
|
|
<< MaxDropOffHeight
|
|
|
|
<< MaxStepHeight
|
|
|
|
<< BounceFlags
|
|
|
|
<< bouncefactor
|
|
|
|
<< wallbouncefactor
|
|
|
|
<< bouncecount
|
|
|
|
<< maxtargetrange
|
|
|
|
<< meleethreshold
|
|
|
|
<< meleerange
|
|
|
|
<< DamageType;
|
|
|
|
arc << DamageTypeReceived;
|
|
|
|
arc << PainType
|
|
|
|
<< DeathType;
|
|
|
|
arc << Gravity
|
|
|
|
<< FastChaseStrafeCount
|
|
|
|
<< master
|
|
|
|
<< smokecounter
|
|
|
|
<< BlockingMobj
|
|
|
|
<< BlockingLine
|
|
|
|
<< VisibleToTeam // [BB]
|
|
|
|
<< pushfactor
|
|
|
|
<< Species
|
|
|
|
<< Score;
|
|
|
|
arc << DesignatedTeam;
|
|
|
|
arc << lastpush << lastbump
|
|
|
|
<< PainThreshold
|
|
|
|
<< DamageFactor;
|
|
|
|
arc << DamageMultiply;
|
|
|
|
arc << WeaveIndexXY << WeaveIndexZ
|
|
|
|
<< PoisonDamageReceived << PoisonDurationReceived << PoisonPeriodReceived << Poisoner
|
|
|
|
<< PoisonDamage << PoisonDuration << PoisonPeriod;
|
|
|
|
arc << PoisonDamageType << PoisonDamageTypeReceived;
|
|
|
|
arc << ConversationRoot << Conversation;
|
|
|
|
arc << FriendPlayer;
|
|
|
|
arc << TeleFogSourceType
|
|
|
|
<< TeleFogDestType;
|
|
|
|
arc << RipperLevel
|
|
|
|
<< RipLevelMin
|
|
|
|
<< RipLevelMax;
|
|
|
|
arc << DefThreshold;
|
|
|
|
if (SaveVersion >= 4549)
|
|
|
|
{
|
|
|
|
arc << SpriteAngle;
|
|
|
|
arc << SpriteRotation;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SaveVersion >= 4550)
|
|
|
|
{
|
|
|
|
arc << alternative;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
FString tagstr;
|
|
|
|
if (arc.IsStoring() && Tag != NULL && Tag->Len() > 0) tagstr = *Tag;
|
|
|
|
arc << tagstr;
|
|
|
|
if (arc.IsLoading())
|
|
|
|
{
|
|
|
|
if (tagstr.Len() == 0) Tag = NULL;
|
|
|
|
else Tag = mStringPropertyData.Alloc(tagstr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arc.IsLoading ())
|
|
|
|
{
|
|
|
|
touching_sectorlist = NULL;
|
|
|
|
LinkToWorld(false, Sector);
|
|
|
|
|
|
|
|
AddToHash ();
|
|
|
|
SetShade (fillcolor);
|
|
|
|
if (player)
|
|
|
|
{
|
|
|
|
if (playeringame[player - players] &&
|
|
|
|
player->cls != NULL &&
|
|
|
|
!(flags4 & MF4_NOSKIN) &&
|
|
|
|
state->sprite == GetDefaultByType (player->cls)->SpawnState->sprite)
|
|
|
|
{ // Give player back the skin
|
|
|
|
sprite = skins[player->userinfo.GetSkin()].sprite;
|
|
|
|
}
|
|
|
|
if (Speed == 0)
|
|
|
|
{
|
|
|
|
Speed = GetDefault()->Speed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ClearInterpolation();
|
|
|
|
UpdateWaterLevel(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FArchive &operator<< (FArchive &arc, sector_t *&sec)
|
|
|
|
{
|
|
|
|
return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors));
|
|
|
|
}
|
|
|
|
|
|
|
|
FArchive &operator<< (FArchive &arc, const sector_t *&sec)
|
|
|
|
{
|
|
|
|
return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors));
|
|
|
|
}
|
|
|
|
|
|
|
|
FArchive &operator<< (FArchive &arc, line_t *&line)
|
|
|
|
{
|
|
|
|
return arc.SerializePointer (lines, (BYTE **)&line, sizeof(*lines));
|
|
|
|
}
|
|
|
|
|
|
|
|
FArchive &operator<< (FArchive &arc, vertex_t *&vert)
|
|
|
|
{
|
|
|
|
return arc.SerializePointer (vertexes, (BYTE **)&vert, sizeof(*vertexes));
|
|
|
|
}
|
|
|
|
|
|
|
|
FArchive &operator<< (FArchive &arc, side_t *&side)
|
|
|
|
{
|
|
|
|
return arc.SerializePointer (sides, (BYTE **)&side, sizeof(*sides));
|
|
|
|
}
|
|
|
|
|
|
|
|
FArchive &operator<<(FArchive &arc, DAngle &ang)
|
|
|
|
{
|
|
|
|
arc << ang.Degrees;
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
FArchive &operator<<(FArchive &arc, DVector3 &vec)
|
|
|
|
{
|
|
|
|
arc << vec.X << vec.Y << vec.Z;
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
FArchive &operator<<(FArchive &arc, DVector2 &vec)
|
|
|
|
{
|
|
|
|
arc << vec.X << vec.Y;
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FArchive &operator<< (FArchive &arc, FState *&state)
|
|
|
|
{
|
|
|
|
PClassActor *info;
|
|
|
|
|
|
|
|
if (arc.IsStoring ())
|
|
|
|
{
|
|
|
|
if (state == NULL)
|
|
|
|
{
|
|
|
|
arc.UserWriteClass (RUNTIME_CLASS(AActor));
|
|
|
|
arc.WriteCount (NULL_STATE_INDEX);
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
info = FState::StaticFindStateOwner (state);
|
|
|
|
|
|
|
|
if (info != NULL)
|
|
|
|
{
|
|
|
|
arc.UserWriteClass (info);
|
|
|
|
arc.WriteCount ((DWORD)(state - info->OwnedStates));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* this was never working as intended.
|
|
|
|
I_Error ("Cannot find owner for state %p:\n"
|
|
|
|
"%s %c%c %3d [%p] -> %p", state,
|
|
|
|
sprites[state->sprite].name,
|
|
|
|
state->GetFrame() + 'A',
|
|
|
|
state->GetFullbright() ? '*' : ' ',
|
|
|
|
state->GetTics(),
|
|
|
|
state->GetAction(),
|
|
|
|
state->GetNextState());
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PClassActor *info;
|
|
|
|
DWORD ofs;
|
|
|
|
|
|
|
|
arc.UserReadClass<PClassActor>(info);
|
|
|
|
ofs = arc.ReadCount ();
|
|
|
|
if (ofs == NULL_STATE_INDEX && info == RUNTIME_CLASS(AActor))
|
|
|
|
{
|
|
|
|
state = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
state = info->OwnedStates + ofs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
2016-09-19 08:47:59 +00:00
|
|
|
void DObject::Serialize(FArchive &arc)
|
2016-09-19 08:34:54 +00:00
|
|
|
{
|
|
|
|
ObjectFlags |= OF_SerialSuccess;
|
|
|
|
}
|
2016-09-19 08:47:59 +00:00
|
|
|
|
|
|
|
|