- cleaned up switch code and fixed several problems:

* savegames stored an index in the switch table and performed no validation when loading a savegame.
  * setting of a random switch animation duration was broken.
  * separated the 2 values stored in the Time variable into 2 separate variables.
  * defining a switch with one texture already belonging to another switch could leave broken definitions in the switch table.
- added function for serializing switch and door animation pointers.
- bumped min. savegame versions due to changes to DButtonThinker and removed all current savegame compatibility code.


SVN r3030 (trunk)
This commit is contained in:
Christoph Oelckers 2010-12-12 15:43:35 +00:00
parent e257c4cb64
commit 0715b7dfc6
17 changed files with 194 additions and 344 deletions

View file

@ -835,11 +835,9 @@ FArchive &operator<< (FArchive &arc, userinfo_t &info)
{ {
arc.Read (&info.netname, sizeof(info.netname)); arc.Read (&info.netname, sizeof(info.netname));
} }
arc << info.team << info.aimdist << info.color << info.skin << info.gender << info.neverswitch; arc << info.team << info.aimdist << info.color
if (SaveVersion >= 2193) << info.skin << info.gender << info.neverswitch
{ << info.colorset;
arc << info.colorset;
}
return arc; return arc;
} }

View file

@ -540,11 +540,6 @@ void DObject::SerializeUserVars(FArchive &arc)
DWORD count, j; DWORD count, j;
int *varloc; int *varloc;
if (SaveVersion < 1933)
{
return;
}
symt = &GetClass()->Symbols; symt = &GetClass()->Symbols;
if (arc.IsStoring()) if (arc.IsStoring())

View file

@ -291,7 +291,11 @@ template<> inline FArchive &operator<< <FFont> (FArchive &arc, FFont* &font)
} }
struct FStrifeDialogueNode; struct FStrifeDialogueNode;
struct FSwitchDef;
struct FDoorAnimation;
template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node); template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node);
template<> FArchive &operator<< (FArchive &arc, FSwitchDef* &sw);
template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &da);

View file

@ -55,16 +55,8 @@ void DEarthquake::Serialize (FArchive &arc)
{ {
Super::Serialize (arc); Super::Serialize (arc);
arc << m_Spot << m_Intensity << m_Countdown arc << m_Spot << m_Intensity << m_Countdown
<< m_TremorRadius << m_DamageRadius; << m_TremorRadius << m_DamageRadius
<< m_QuakeSFX;
if (SaveVersion >= 1912)
{
arc << m_QuakeSFX;
}
else
{
m_QuakeSFX = "world/quake";
}
} }
//========================================================================== //==========================================================================

View file

@ -70,11 +70,6 @@ void ASkyViewpoint::Serialize (FArchive &arc)
{ {
Super::Serialize (arc); Super::Serialize (arc);
arc << bInSkybox << bAlways << Mate; arc << bInSkybox << bAlways << Mate;
if (SaveVersion < 2992)
{
fixed_t eatme;
arc << eatme;
}
} }
void ASkyViewpoint::Destroy () void ASkyViewpoint::Destroy ()

View file

@ -638,14 +638,7 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec)
void DAnimatedDoor::Serialize (FArchive &arc) void DAnimatedDoor::Serialize (FArchive &arc)
{ {
Super::Serialize (arc); Super::Serialize (arc);
FTextureID basetex;
if (arc.IsStoring())
{
basetex = m_DoorAnim->BaseTexture;
}
arc << m_Line1 << m_Line2 arc << m_Line1 << m_Line2
<< m_Frame << m_Frame
<< m_Timer << m_Timer
@ -653,20 +646,8 @@ void DAnimatedDoor::Serialize (FArchive &arc)
<< m_Status << m_Status
<< m_Speed << m_Speed
<< m_Delay << m_Delay
<< basetex; << m_DoorAnim
if (SaveVersion < 2336) << m_SetBlocking1 << m_SetBlocking2;
{
m_SetBlocking1 = m_SetBlocking2 = true;
}
else
{
arc << m_SetBlocking1 << m_SetBlocking2;
}
if (arc.IsLoading())
{
m_DoorAnim = TexMan.FindAnimatedDoor (basetex);
}
} }
DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim) DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim)

View file

@ -258,18 +258,9 @@ void AActor::Serialize (FArchive &arc)
<< args[0] << args[1] << args[2] << args[3] << args[4] << args[0] << args[1] << args[2] << args[3] << args[4]
<< goal << goal
<< waterlevel << waterlevel
<< MinMissileChance; << MinMissileChance
if (SaveVersion >= 2826) << SpawnFlags
{ << Inventory
arc << SpawnFlags;
}
else
{
WORD w;
arc << w;
SpawnFlags = w;
}
arc << Inventory
<< InventoryID << InventoryID
<< id << id
<< FloatBobPhase << FloatBobPhase
@ -281,12 +272,9 @@ void AActor::Serialize (FArchive &arc)
<< ActiveSound << ActiveSound
<< UseSound << UseSound
<< BounceSound << BounceSound
<< WallBounceSound; << WallBounceSound
if (SaveVersion >= 2234) << CrushPainSound
{ << Speed
arc << CrushPainSound;
}
arc << Speed
<< FloatSpeed << FloatSpeed
<< Mass << Mass
<< PainChance << PainChance
@ -313,83 +301,14 @@ void AActor::Serialize (FArchive &arc)
<< pushfactor << pushfactor
<< Species << Species
<< Score << Score
<< Tag; << Tag
if (SaveVersion >= 1904) << lastpush << lastbump
{ << PainThreshold
arc << lastpush << lastbump; << DamageFactor
} << WeaveIndexXY << WeaveIndexZ
<< PoisonDamageReceived << PoisonDurationReceived << PoisonPeriodReceived << Poisoner
if (SaveVersion >= 1900) << PoisonDamage << PoisonDuration << PoisonPeriod
{ << ConversationRoot << Conversation;
arc << PainThreshold;
}
if (SaveVersion >= 1914)
{
arc << DamageFactor;
}
if (SaveVersion > 2036)
{
arc << WeaveIndexXY << WeaveIndexZ;
}
else
{
int index;
if (SaveVersion < 2036)
{
index = special2;
}
else
{
arc << index;
}
// A_BishopMissileWeave and A_CStaffMissileSlither stored the weaveXY
// value in different parts of the index.
if (this->IsKindOf(PClass::FindClass("BishopFX")))
{
WeaveIndexXY = index >> 16;
WeaveIndexZ = index;
}
else
{
WeaveIndexXY = index;
WeaveIndexZ = 0;
}
}
if (SaveVersion >= 2450)
{
arc << PoisonDamageReceived << PoisonDurationReceived << PoisonPeriodReceived << Poisoner;
arc << PoisonDamage << PoisonDuration << PoisonPeriod;
}
// Skip past uservar array in old savegames
if (SaveVersion < 1933)
{
int foo;
for (int i = 0; i < 10; ++i)
arc << foo;
}
if (SaveVersion > 2560)
{
arc << ConversationRoot << Conversation;
}
else // old code which uses relative indexing.
{
int convnum;
convnum = arc.ReadCount();
if (GetConversation(GetClass()->TypeName) == -1)
{
Conversation = NULL;
ConversationRoot = -1;
}
else
{
// This cannot be restored anymore.
I_Error("Cannot load old savegames with active dialogues");
}
}
if (arc.IsLoading ()) if (arc.IsLoading ())
{ {

View file

@ -861,15 +861,7 @@ void P_MovePsprites (player_t *player)
FArchive &operator<< (FArchive &arc, pspdef_t &def) FArchive &operator<< (FArchive &arc, pspdef_t &def)
{ {
arc << def.state << def.tics << def.sx << def.sy; arc << def.state << def.tics << def.sx << def.sy
if (SaveVersion >= 2295) << def.sprite << def.frame;
{
arc << def.sprite << def.frame;
}
else
{
def.sprite = def.state->sprite;
def.frame = def.state->Frame;
}
return arc; return arc;
} }

View file

@ -347,16 +347,8 @@ void P_SerializeWorld (FArchive &arc)
<< sec->interpolations[0] << sec->interpolations[0]
<< sec->interpolations[1] << sec->interpolations[1]
<< sec->interpolations[2] << sec->interpolations[2]
<< sec->interpolations[3]; << sec->interpolations[3]
<< sec->SeqName;
if (SaveVersion < 2492)
{
sec->SeqName = NAME_None;
}
else
{
arc << sec->SeqName;
}
sec->e->Serialize(arc); sec->e->Serialize(arc);
if (arc.IsStoring ()) if (arc.IsStoring ())
@ -444,15 +436,7 @@ FArchive &operator<< (FArchive &arc, sector_t::splane &p)
{ {
arc << p.xform.xoffs << p.xform.yoffs << p.xform.xscale << p.xform.yscale arc << p.xform.xoffs << p.xform.yoffs << p.xform.xscale << p.xform.yscale
<< p.xform.angle << p.xform.base_yoffs << p.xform.base_angle << p.xform.angle << p.xform.base_yoffs << p.xform.base_angle
<< p.Flags << p.Light << p.Texture << p.TexZ; << p.Flags << p.Light << p.Texture << p.TexZ << p.alpha;
if (SaveVersion >= 2992)
{
arc << p.alpha;
}
else
{
p.alpha = FRACUNIT;
}
return arc; return arc;
} }
@ -614,15 +598,6 @@ void P_SerializeSubsectors(FArchive &arc)
} }
else else
{ {
if (SaveVersion < 2609)
{
if (hasglnodes)
{
RecalculateDrawnSubsectors();
}
return;
}
arc << num_verts << num_subs << num_nodes; arc << num_verts << num_subs << num_nodes;
if (num_verts != numvertexes || if (num_verts != numvertexes ||
num_subs != numsubsectors || num_subs != numsubsectors ||

View file

@ -56,18 +56,19 @@ class DActiveButton : public DThinker
DECLARE_CLASS (DActiveButton, DThinker) DECLARE_CLASS (DActiveButton, DThinker)
public: public:
DActiveButton (); DActiveButton ();
DActiveButton (side_t *, int, WORD switchnum, fixed_t x, fixed_t y, bool flippable); DActiveButton (side_t *, int, FSwitchDef *, fixed_t x, fixed_t y, bool flippable);
void Serialize (FArchive &arc); void Serialize (FArchive &arc);
void Tick (); void Tick ();
side_t *m_Side; side_t *m_Side;
SBYTE m_Part; SBYTE m_Part;
WORD m_SwitchDef; bool bFlippable;
WORD m_Frame; bool bReturning;
WORD m_Timer; FSwitchDef *m_SwitchDef;
bool bFlippable; SDWORD m_Frame;
fixed_t m_X, m_Y; // Location of timer sound DWORD m_Timer;
fixed_t m_X, m_Y; // Location of timer sound
protected: protected:
bool AdvanceFrame (); bool AdvanceFrame ();
@ -81,8 +82,7 @@ protected:
// //
//========================================================================== //==========================================================================
static bool P_StartButton (side_t *side, int Where, int switchnum, static bool P_StartButton (side_t *side, int Where, FSwitchDef *Switch, fixed_t x, fixed_t y, bool useagain)
fixed_t x, fixed_t y, bool useagain)
{ {
DActiveButton *button; DActiveButton *button;
TThinkerIterator<DActiveButton> iterator; TThinkerIterator<DActiveButton> iterator;
@ -97,7 +97,7 @@ static bool P_StartButton (side_t *side, int Where, int switchnum,
} }
} }
new DActiveButton (side, Where, switchnum, x, y, useagain); new DActiveButton (side, Where, Switch, x, y, useagain);
return true; return true;
} }
@ -168,15 +168,15 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno)
if (open.range <= 0) if (open.range <= 0)
goto onesided; goto onesided;
if ((TexMan.FindSwitch (side->GetTexture(side_t::top))) != -1) if ((TexMan.FindSwitch (side->GetTexture(side_t::top))) != NULL)
{ {
return (user->z + user->height >= open.top); return (user->z + user->height >= open.top);
} }
else if ((TexMan.FindSwitch (side->GetTexture(side_t::bottom))) != -1) else if ((TexMan.FindSwitch (side->GetTexture(side_t::bottom))) != NULL)
{ {
return (user->z <= open.bottom); return (user->z <= open.bottom);
} }
else if ((line->flags & (ML_3DMIDTEX)) || (TexMan.FindSwitch (side->GetTexture(side_t::mid))) != -1) else if ((line->flags & (ML_3DMIDTEX)) || (TexMan.FindSwitch (side->GetTexture(side_t::mid))) != NULL)
{ {
// 3DMIDTEX lines will force a mid texture check if no switch is found on this line // 3DMIDTEX lines will force a mid texture check if no switch is found on this line
// to keep compatibility with Eternity's implementation. // to keep compatibility with Eternity's implementation.
@ -202,18 +202,17 @@ bool P_ChangeSwitchTexture (side_t *side, int useAgain, BYTE special, bool *ques
{ {
int texture; int texture;
int sound; int sound;
int i;
FSwitchDef *Switch; FSwitchDef *Switch;
if ((i = TexMan.FindSwitch (side->GetTexture(side_t::top))) != -1) if ((Switch = TexMan.FindSwitch (side->GetTexture(side_t::top))) != NULL)
{ {
texture = side_t::top; texture = side_t::top;
} }
else if ((i = TexMan.FindSwitch (side->GetTexture(side_t::bottom))) != -1) else if ((Switch = TexMan.FindSwitch (side->GetTexture(side_t::bottom))) != NULL)
{ {
texture = side_t::bottom; texture = side_t::bottom;
} }
else if ((i = TexMan.FindSwitch (side->GetTexture(side_t::mid))) != -1) else if ((Switch = TexMan.FindSwitch (side->GetTexture(side_t::mid))) != NULL)
{ {
texture = side_t::mid; texture = side_t::mid;
} }
@ -225,7 +224,6 @@ bool P_ChangeSwitchTexture (side_t *side, int useAgain, BYTE special, bool *ques
} }
return false; return false;
} }
Switch = TexMan.GetSwitch(i);
// EXIT SWITCH? // EXIT SWITCH?
if (Switch->Sound != 0) if (Switch->Sound != 0)
@ -252,10 +250,10 @@ bool P_ChangeSwitchTexture (side_t *side, int useAgain, BYTE special, bool *ques
pt[0] = line->v1->x + (line->dx >> 1); pt[0] = line->v1->x + (line->dx >> 1);
pt[1] = line->v1->y + (line->dy >> 1); pt[1] = line->v1->y + (line->dy >> 1);
side->SetTexture(texture, Switch->u[0].Texture); side->SetTexture(texture, Switch->frames[0].Texture);
if (useAgain || Switch->NumFrames > 1) if (useAgain || Switch->NumFrames > 1)
{ {
playsound = P_StartButton (side, texture, i, pt[0], pt[1], !!useAgain); playsound = P_StartButton (side, texture, Switch, pt[0], pt[1], !!useAgain);
} }
else else
{ {
@ -289,9 +287,11 @@ DActiveButton::DActiveButton ()
m_X = 0; m_X = 0;
m_Y = 0; m_Y = 0;
bFlippable = false; bFlippable = false;
bReturning = false;
m_Frame = 0;
} }
DActiveButton::DActiveButton (side_t *side, int Where, WORD switchnum, DActiveButton::DActiveButton (side_t *side, int Where, FSwitchDef *Switch,
fixed_t x, fixed_t y, bool useagain) fixed_t x, fixed_t y, bool useagain)
{ {
m_Side = side; m_Side = side;
@ -299,9 +299,10 @@ DActiveButton::DActiveButton (side_t *side, int Where, WORD switchnum,
m_X = x; m_X = x;
m_Y = y; m_Y = y;
bFlippable = useagain; bFlippable = useagain;
bReturning = false;
m_SwitchDef = switchnum; m_SwitchDef = Switch;
m_Frame = 65535; m_Frame = -1;
AdvanceFrame (); AdvanceFrame ();
} }
@ -313,18 +314,8 @@ DActiveButton::DActiveButton (side_t *side, int Where, WORD switchnum,
void DActiveButton::Serialize (FArchive &arc) void DActiveButton::Serialize (FArchive &arc)
{ {
SDWORD sidenum;
Super::Serialize (arc); Super::Serialize (arc);
if (arc.IsStoring ()) arc << m_Side << m_Part << m_SwitchDef << m_Frame << m_Timer << bFlippable << m_X << m_Y << bReturning;
{
sidenum = m_Side ? SDWORD(m_Side - sides) : -1;
}
arc << sidenum << m_Part << m_SwitchDef << m_Frame << m_Timer << bFlippable << m_X << m_Y;
if (arc.IsLoading ())
{
m_Side = sidenum >= 0 ? sides + sidenum : NULL;
}
} }
//========================================================================== //==========================================================================
@ -335,16 +326,23 @@ void DActiveButton::Serialize (FArchive &arc)
void DActiveButton::Tick () void DActiveButton::Tick ()
{ {
if (m_SwitchDef == NULL)
{
// We lost our definition due to a bad savegame.
Destroy();
return;
}
FSwitchDef *def = bReturning? m_SwitchDef->PairDef : m_SwitchDef;
if (--m_Timer == 0) if (--m_Timer == 0)
{ {
FSwitchDef *def = TexMan.GetSwitch(m_SwitchDef);
if (m_Frame == def->NumFrames - 1) if (m_Frame == def->NumFrames - 1)
{ {
m_SwitchDef = def->PairIndex; bReturning = true;
if (m_SwitchDef != 65535) def = m_SwitchDef->PairDef;
if (def != NULL)
{ {
def = TexMan.GetSwitch(def->PairIndex); m_Frame = -1;
m_Frame = 65535;
S_Sound (m_X, m_Y, 0, CHAN_VOICE|CHAN_LISTENERZ, S_Sound (m_X, m_Y, 0, CHAN_VOICE|CHAN_LISTENERZ,
def->Sound != 0 ? FSoundID(def->Sound) : FSoundID("switches/normbutn"), def->Sound != 0 ? FSoundID(def->Sound) : FSoundID("switches/normbutn"),
1, ATTN_STATIC); 1, ATTN_STATIC);
@ -358,7 +356,7 @@ void DActiveButton::Tick ()
} }
bool killme = AdvanceFrame (); bool killme = AdvanceFrame ();
m_Side->SetTexture(m_Part, def->u[m_Frame].Texture); m_Side->SetTexture(m_Part, def->frames[m_Frame].Texture);
if (killme) if (killme)
{ {
@ -376,7 +374,7 @@ void DActiveButton::Tick ()
bool DActiveButton::AdvanceFrame () bool DActiveButton::AdvanceFrame ()
{ {
bool ret = false; bool ret = false;
FSwitchDef *def = TexMan.GetSwitch(m_SwitchDef); FSwitchDef *def = bReturning? m_SwitchDef->PairDef : m_SwitchDef;
if (++m_Frame == def->NumFrames - 1) if (++m_Frame == def->NumFrames - 1)
{ {
@ -391,17 +389,10 @@ bool DActiveButton::AdvanceFrame ()
} }
else else
{ {
if (def->u[m_Frame].Time & 0xffff0000) m_Timer = def->frames[m_Frame].TimeMin;
if (def->frames[m_Frame].TimeRnd != 0)
{ {
int t = pr_switchanim(); m_Timer += pr_switchanim(def->frames[m_Frame].TimeRnd);
m_Timer = (WORD)((((t | (pr_switchanim() << 8))
% def->u[m_Frame].Time) >> 16)
+ (def->u[m_Frame].Time & 0xffff));
}
else
{
m_Timer = (WORD)def->u[m_Frame].Time;
} }
} }
return ret; return ret;

View file

@ -432,10 +432,6 @@ void APlayerPawn::Serialize (FArchive &arc)
<< MorphWeapon << MorphWeapon
<< DamageFade << DamageFade
<< PlayerFlags; << PlayerFlags;
if (SaveVersion < 2435)
{
DamageFade.a = 255;
}
} }
//=========================================================================== //===========================================================================
@ -2554,33 +2550,9 @@ void player_t::Serialize (FArchive &arc)
<< poisoncount << poisoncount
<< poisoner << poisoner
<< attacker << attacker
<< extralight; << extralight
if (SaveVersion < 1858) << fixedcolormap << fixedlightlevel
{ << morphTics
int fixedmap;
arc << fixedmap;
fixedcolormap = NOFIXEDCOLORMAP;
fixedlightlevel = -1;
if (fixedmap >= NUMCOLORMAPS)
{
fixedcolormap = fixedmap - NUMCOLORMAPS;
}
else if (fixedmap > 0)
{
fixedlightlevel = fixedmap;
}
}
else if (SaveVersion < 1893)
{
int ll;
arc << fixedcolormap << ll;
fixedlightlevel = ll;
}
else
{
arc << fixedcolormap << fixedlightlevel;
}
arc << morphTics
<< MorphedPlayerClass << MorphedPlayerClass
<< MorphStyle << MorphStyle
<< MorphExitFlash << MorphExitFlash

View file

@ -826,16 +826,7 @@ void DPolyobjInterpolation::Serialize(FArchive &arc)
arc << po << oldverts; arc << po << oldverts;
poly = polyobjs + po; poly = polyobjs + po;
if (SaveVersion >= 2448) arc << oldcx << oldcy;
{
arc << oldcx << oldcy;
}
else
{
// This will glitch if an old savegame is loaded but at least it'll allow loading it.
oldcx = poly->CenterSpot.x;
oldcy = poly->CenterSpot.y;
}
if (arc.IsLoading()) bakverts.Resize(oldverts.Size()); if (arc.IsLoading()) bakverts.Resize(oldverts.Size());
} }

View file

@ -2016,10 +2016,6 @@ void AAmbientSound::Serialize (FArchive &arc)
{ {
Super::Serialize (arc); Super::Serialize (arc);
arc << bActive << NextCheck; arc << bActive << NextCheck;
if (SaveVersion < 2798)
{
NextCheck += level.maptime;
}
} }
//========================================================================== //==========================================================================

View file

@ -63,8 +63,6 @@ void FTextureManager::InitSwitchList ()
{ {
const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny;
int lump = Wads.CheckNumForName ("SWITCHES"); int lump = Wads.CheckNumForName ("SWITCHES");
FSwitchDef **origMap;
int i, j;
if (lump != -1) if (lump != -1)
{ {
@ -87,46 +85,19 @@ void FTextureManager::InitSwitchList ()
{ {
def1 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef)); def1 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef));
def2 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef)); def2 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef));
def1->PreTexture = def2->u[0].Texture = CheckForTexture (list_p /* .name1 */, FTexture::TEX_Wall, texflags); def1->PreTexture = def2->frames[0].Texture = CheckForTexture (list_p /* .name1 */, FTexture::TEX_Wall, texflags);
def2->PreTexture = def1->u[0].Texture = CheckForTexture (list_p + 9, FTexture::TEX_Wall, texflags); def2->PreTexture = def1->frames[0].Texture = CheckForTexture (list_p + 9, FTexture::TEX_Wall, texflags);
def1->Sound = def2->Sound = 0; def1->Sound = def2->Sound = 0;
def1->NumFrames = def2->NumFrames = 1; def1->NumFrames = def2->NumFrames = 1;
def1->u[0].Time = def2->u[0].Time = 0; def1->frames[0].TimeMin = def2->frames[0].TimeMin = 0;
def2->PairIndex = AddSwitchDef (def1); def1->frames[0].TimeRnd = def2->frames[0].TimeRnd = 0;
def1->PairIndex = AddSwitchDef (def2); AddSwitchPair(def1, def2);
} }
} }
} }
mSwitchDefs.ShrinkToFit (); mSwitchDefs.ShrinkToFit ();
qsort (&mSwitchDefs[0], mSwitchDefs.Size(), sizeof(FSwitchDef *), SortSwitchDefs);
// Sort mSwitchDefs for quick searching
origMap = new FSwitchDef *[mSwitchDefs.Size ()];
for (i = 0; i < (int)mSwitchDefs.Size (); i++)
{
origMap[i] = mSwitchDefs[i];
}
qsort (&mSwitchDefs[0], i, sizeof(FSwitchDef *), SortSwitchDefs);
// Correct the PairIndex of each switch def, since the sorting broke them
for (i = (int)(mSwitchDefs.Size () - 1); i >= 0; i--)
{
FSwitchDef *def = mSwitchDefs[i];
if (def->PairIndex != 65535)
{
for (j = (int)(mSwitchDefs.Size () - 1); j >= 0; j--)
{
if (mSwitchDefs[j] == origMap[def->PairIndex])
{
def->PairIndex = (WORD)j;
break;
}
}
}
}
delete[] origMap;
} }
//========================================================================== //==========================================================================
@ -228,18 +199,18 @@ void FTextureManager::ProcessSwitchDef (FScanner &sc)
def2 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef)); def2 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef));
def2->Sound = def1->Sound; def2->Sound = def1->Sound;
def2->NumFrames = 1; def2->NumFrames = 1;
def2->u[0].Time = 0; def2->frames[0].TimeMin = 0;
def2->u[0].Texture = picnum; def2->frames[0].TimeRnd = 0;
def2->frames[0].Texture = picnum;
} }
def1->PreTexture = picnum; def1->PreTexture = picnum;
def2->PreTexture = def1->u[def1->NumFrames-1].Texture; def2->PreTexture = def1->frames[def1->NumFrames-1].Texture;
if (def1->PreTexture == def2->PreTexture) if (def1->PreTexture == def2->PreTexture)
{ {
sc.ScriptError ("The on state for switch %s must end with a texture other than %s", picname.GetChars(), picname.GetChars()); sc.ScriptError ("The on state for switch %s must end with a texture other than %s", picname.GetChars(), picname.GetChars());
} }
def2->PairIndex = AddSwitchDef (def1); AddSwitchPair(def1, def2);
def1->PairIndex = AddSwitchDef (def2);
def1->QuestPanel = def2->QuestPanel = quest; def1->QuestPanel = def2->QuestPanel = quest;
} }
@ -286,7 +257,8 @@ FSwitchDef *FTextureManager::ParseSwitchDef (FScanner &sc, bool ignoreBad)
if (sc.Compare ("tics")) if (sc.Compare ("tics"))
{ {
sc.MustGetNumber (); sc.MustGetNumber ();
thisframe.Time = sc.Number & 65535; thisframe.TimeMin = sc.Number & 65535;
thisframe.TimeRnd = 0;
} }
else if (sc.Compare ("rand")) else if (sc.Compare ("rand"))
{ {
@ -300,11 +272,13 @@ FSwitchDef *FTextureManager::ParseSwitchDef (FScanner &sc, bool ignoreBad)
{ {
swapvalues (min, max); swapvalues (min, max);
} }
thisframe.Time = ((max - min + 1) << 16) | min; thisframe.TimeMin = min;
thisframe.TimeRnd = (max - min + 1);
} }
else else
{ {
thisframe.Time = 0; // Shush, GCC. thisframe.TimeMin = 0; // Shush, GCC.
thisframe.TimeRnd = 0;
sc.ScriptError ("Must specify a duration for switch frame"); sc.ScriptError ("Must specify a duration for switch frame");
} }
frames.Push(thisframe); frames.Push(thisframe);
@ -324,11 +298,11 @@ FSwitchDef *FTextureManager::ParseSwitchDef (FScanner &sc, bool ignoreBad)
return NULL; return NULL;
} }
def = (FSwitchDef *)M_Malloc (myoffsetof (FSwitchDef, u[0]) + frames.Size()*sizeof(frames[0])); def = (FSwitchDef *)M_Malloc (myoffsetof (FSwitchDef, frames[0]) + frames.Size()*sizeof(frames[0]));
def->Sound = sound; def->Sound = sound;
def->NumFrames = frames.Size(); def->NumFrames = frames.Size();
memcpy (&def->u[0], &frames[0], frames.Size() * sizeof(frames[0])); memcpy (&def->frames[0], &frames[0], frames.Size() * sizeof(frames[0]));
def->PairIndex = 65535; def->PairDef = NULL;
return def; return def;
} }
@ -338,20 +312,54 @@ FSwitchDef *FTextureManager::ParseSwitchDef (FScanner &sc, bool ignoreBad)
// //
//========================================================================== //==========================================================================
WORD FTextureManager::AddSwitchDef (FSwitchDef *def) void FTextureManager::AddSwitchPair (FSwitchDef *def1, FSwitchDef *def2)
{ {
unsigned int i; unsigned int i;
FSwitchDef *sw1 = NULL;
FSwitchDef *sw2 = NULL;
unsigned int index1 = -1, index2 = -1;
for (i = mSwitchDefs.Size (); i-- > 0; ) for (i = mSwitchDefs.Size (); i-- > 0; )
{ {
if (mSwitchDefs[i]->PreTexture == def->PreTexture) if (mSwitchDefs[i]->PreTexture == def1->PreTexture)
{ {
M_Free (mSwitchDefs[i]); index1 = i;
mSwitchDefs[i] = def; sw1 = mSwitchDefs[index1];
return (WORD)i; if (index2 != -1) break;
}
if (mSwitchDefs[i]->PreTexture == def2->PreTexture)
{
index2 = i;
sw2 = mSwitchDefs[index2];
if (index1 != -1) break;
} }
} }
return (WORD)mSwitchDefs.Push (def);
def1->PairDef = def2;
def2->PairDef = def1;
if (sw1 != NULL && sw2 != NULL && sw1->PairDef == sw2 && sw2->PairDef == sw1)
{
//We are replacing an existing pair so we can safely delete the old definitions
M_Free(sw1);
M_Free(sw2);
mSwitchDefs[index1] = def1;
mSwitchDefs[index2] = def2;
}
else
{
// This new switch will not or only partially replace an existing pair.
// We should not break up an old pair if the new one only redefined one
// of the two textures. These paired definitions will only be used
// as the return animation so their names don't matter. Better clear them to be safe.
if (sw1 != NULL) sw1->PreTexture.SetInvalid();
if (sw2 != NULL) sw2->PreTexture.SetInvalid();
sw1 = NULL;
sw2 = NULL;
unsigned int pos = mSwitchDefs.Reserve(2);
mSwitchDefs[pos] = def1;
mSwitchDefs[pos+1] = def2;
}
} }
//========================================================================== //==========================================================================
@ -360,7 +368,7 @@ WORD FTextureManager::AddSwitchDef (FSwitchDef *def)
// //
//========================================================================== //==========================================================================
int FTextureManager::FindSwitch (FTextureID texture) FSwitchDef *FTextureManager::FindSwitch (FTextureID texture)
{ {
int mid, low, high; int mid, low, high;
@ -373,7 +381,7 @@ int FTextureManager::FindSwitch (FTextureID texture)
mid = (high + low) / 2; mid = (high + low) / 2;
if (mSwitchDefs[mid]->PreTexture == texture) if (mSwitchDefs[mid]->PreTexture == texture)
{ {
return mid; return mSwitchDefs[mid];
} }
else if (texture < mSwitchDefs[mid]->PreTexture) else if (texture < mSwitchDefs[mid]->PreTexture)
{ {
@ -385,6 +393,27 @@ int FTextureManager::FindSwitch (FTextureID texture)
} }
} while (low <= high); } while (low <= high);
} }
return -1; return NULL;
}
//==========================================================================
//
// operator<<
//
//==========================================================================
template<> FArchive &operator<< (FArchive &arc, FSwitchDef* &Switch)
{
if (arc.IsStoring())
{
arc << Switch->PreTexture;
}
else
{
FTextureID tex;
arc << tex;
Switch = TexMan.FindSwitch(tex);
}
return arc;
} }

View file

@ -903,3 +903,24 @@ void FTextureManager::UpdateAnimations (DWORD mstime)
} }
} }
//==========================================================================
//
// operator<<
//
//==========================================================================
template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &Doorani)
{
if (arc.IsStoring())
{
arc << Doorani->BaseTexture;
}
else
{
FTextureID tex;
arc << tex;
Doorani = TexMan.FindAnimatedDoor(tex);
}
return arc;
}

View file

@ -85,15 +85,16 @@ struct FAnimDef
struct FSwitchDef struct FSwitchDef
{ {
FTextureID PreTexture; // texture to switch from FTextureID PreTexture; // texture to switch from
WORD PairIndex; // switch def to use to return to PreTexture FSwitchDef *PairDef; // switch def to use to return to PreTexture
WORD NumFrames; // # of animation frames WORD NumFrames; // # of animation frames
int Sound; // sound to play at start of animation. Changed to int to avoiud having to include s_sound here.
bool QuestPanel; // Special texture for Strife mission bool QuestPanel; // Special texture for Strife mission
int Sound; // sound to play at start of animation. Changed to int to avoiud having to include s_sound here.
struct frame // Array of times followed by array of textures struct frame // Array of times followed by array of textures
{ // actual length of each array is <NumFrames> { // actual length of each array is <NumFrames>
DWORD Time; WORD TimeMin;
WORD TimeRnd;
FTextureID Texture; FTextureID Texture;
} u[1]; } frames[1];
}; };
struct FDoorAnimation struct FDoorAnimation
@ -397,12 +398,7 @@ public:
void UpdateAnimations (DWORD mstime); void UpdateAnimations (DWORD mstime);
int GuesstimateNumTextures (); int GuesstimateNumTextures ();
int FindSwitch (FTextureID texture); FSwitchDef *FindSwitch (FTextureID texture);
FSwitchDef *GetSwitch (unsigned int index)
{
if (index < mSwitchDefs.Size()) return mSwitchDefs[index];
else return NULL;
}
FDoorAnimation *FindAnimatedDoor (FTextureID picnum); FDoorAnimation *FindAnimatedDoor (FTextureID picnum);
private: private:
@ -440,7 +436,7 @@ private:
void InitSwitchList (); void InitSwitchList ();
void ProcessSwitchDef (FScanner &sc); void ProcessSwitchDef (FScanner &sc);
FSwitchDef *ParseSwitchDef (FScanner &sc, bool ignoreBad); FSwitchDef *ParseSwitchDef (FScanner &sc, bool ignoreBad);
WORD AddSwitchDef (FSwitchDef *def); void AddSwitchPair (FSwitchDef *def1, FSwitchDef *def2);
struct TextureHash struct TextureHash
{ {

View file

@ -75,7 +75,7 @@
// SAVESIG should match SAVEVER. // SAVESIG should match SAVEVER.
// MINSAVEVER is the minimum level snapshot version that can be loaded. // MINSAVEVER is the minimum level snapshot version that can be loaded.
#define MINSAVEVER 1848 #define MINSAVEVER 3030
#if SVN_REVISION_NUMBER < MINSAVEVER #if SVN_REVISION_NUMBER < MINSAVEVER
// If we don't know the current revision write something very high to ensure that // If we don't know the current revision write something very high to ensure that
@ -85,8 +85,11 @@
static inline const char *MakeSaveSig() static inline const char *MakeSaveSig()
{ {
static char foo[] = { 'Z','D','O','O','M','S','A','V','E', static char foo[] = { 'Z','D','O','O','M','S','A','V','E',
#if SAVEVER > 99999
'0' + (SAVEVER / 100000),
#endif
#if SAVEVER > 9999 #if SAVEVER > 9999
'0' + (SAVEVER / 10000), '0' + ((SAVEVER / 10000) % 10),
#endif #endif
#if SAVEVER > 999 #if SAVEVER > 999
'0' + ((SAVEVER / 1000) % 10), '0' + ((SAVEVER / 1000) % 10),