/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see .
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "Precompiled.h"
#include "globaldata.h"
#include "i_system.h"
#include "z_zone.h"
#include "p_local.h"
// State.
#include "doomstat.h"
#include "r_state.h"
// Pads ::g->save_p to a 4-byte boundary
// so that the load/save works on SGI&Gecko.
//
// P_ArchivePlayers
//
void P_ArchivePlayers (void)
{
int i;
int j;
player_t* dest;
for (i=0 ; iplayeringame[i])
continue;
PADSAVEP();
dest = (player_t *)::g->save_p;
memcpy (dest,&::g->players[i],sizeof(player_t));
::g->save_p += sizeof(player_t);
for (j=0 ; jpsprites[j].state)
{
dest->psprites[j].state
= (state_t *)(dest->psprites[j].state-::g->states);
}
}
}
}
//
// P_UnArchivePlayers
//
void P_UnArchivePlayers (void)
{
int i;
int j;
for (i=0 ; iplayeringame[i])
continue;
PADSAVEP();
memcpy (&::g->players[i],::g->save_p, sizeof(player_t));
::g->save_p += sizeof(player_t);
// will be set when unarc thinker
::g->players[i].mo = NULL;
::g->players[i].message = NULL;
::g->players[i].attacker = NULL;
for (j=0 ; jplayers[i]. psprites[j].state)
{
::g->players[i]. psprites[j].state
= &::g->states[ (int)::g->players[i].psprites[j].state ];
}
}
}
}
//
// P_ArchiveWorld
//
void P_ArchiveWorld (void)
{
int i;
int j;
sector_t* sec;
line_t* li;
side_t* si;
short* put;
put = (short *)::g->save_p;
// do ::g->sectors
for (i=0, sec = ::g->sectors ; i < ::g->numsectors ; i++,sec++)
{
*put++ = sec->floorheight >> FRACBITS;
*put++ = sec->ceilingheight >> FRACBITS;
*put++ = sec->floorpic;
*put++ = sec->ceilingpic;
*put++ = sec->lightlevel;
*put++ = sec->special; // needed?
*put++ = sec->tag; // needed?
}
// do ::g->lines
for (i=0, li = ::g->lines ; i < ::g->numlines ; i++,li++)
{
*put++ = li->flags;
*put++ = li->special;
*put++ = li->tag;
for (j=0 ; j<2 ; j++)
{
if (li->sidenum[j] == -1)
continue;
si = &::g->sides[li->sidenum[j]];
*put++ = si->textureoffset >> FRACBITS;
*put++ = si->rowoffset >> FRACBITS;
*put++ = si->toptexture;
*put++ = si->bottomtexture;
*put++ = si->midtexture;
}
}
// Doom 2 level 30 requires some global pointers, wheee!
*put++ = ::g->braintargeton;
*put++ = ::g->easy;
::g->save_p = (byte *)put;
}
//
// P_UnArchiveWorld
//
void P_UnArchiveWorld (void)
{
int i;
int j;
sector_t* sec;
line_t* li;
side_t* si;
short* get;
get = (short *)::g->save_p;
// do ::g->sectors
for (i=0, sec = ::g->sectors ; i < ::g->numsectors ; i++,sec++)
{
sec->floorheight = *get++ << FRACBITS;
sec->ceilingheight = *get++ << FRACBITS;
sec->floorpic = *get++;
sec->ceilingpic = *get++;
sec->lightlevel = *get++;
sec->special = *get++; // needed?
sec->tag = *get++; // needed?
sec->specialdata = 0;
sec->soundtarget = 0;
}
// do ::g->lines
for (i=0, li = ::g->lines ; i < ::g->numlines ; i++,li++)
{
li->flags = *get++;
li->special = *get++;
li->tag = *get++;
for (j=0 ; j<2 ; j++)
{
if (li->sidenum[j] == -1)
continue;
si = &::g->sides[li->sidenum[j]];
si->textureoffset = *get++ << FRACBITS;
si->rowoffset = *get++ << FRACBITS;
si->toptexture = *get++;
si->bottomtexture = *get++;
si->midtexture = *get++;
}
}
// Doom 2 level 30 requires some global pointers, wheee!
::g->braintargeton = *get++;
::g->easy = *get++;
::g->save_p = (byte *)get;
}
//
// Thinkers
//
int GetMOIndex( mobj_t* findme ) {
thinker_t* th;
mobj_t* mobj;
int index = 0;
for (th = ::g->thinkercap.next ; th != &::g->thinkercap ; th=th->next)
{
if (th->function.acp1 == (actionf_p1)P_MobjThinker) {
index++;
mobj = (mobj_t*)th;
if ( mobj == findme ) {
return index;
}
}
}
return 0;
}
mobj_t* GetMO( int index ) {
thinker_t* th;
int testindex = 0;
if ( !index ) {
return NULL;
}
for (th = ::g->thinkercap.next ; th != &::g->thinkercap ; th=th->next)
{
if (th->function.acp1 == (actionf_p1)P_MobjThinker) {
testindex++;
if ( testindex == index ) {
return (mobj_t*)th;
}
}
}
return NULL;
}
//
// P_ArchiveThinkers
//
void P_ArchiveThinkers (void)
{
thinker_t* th;
mobj_t* mobj;
ceiling_t* ceiling;
vldoor_t* door;
floormove_t* floor;
plat_t* plat;
fireflicker_t* fire;
lightflash_t* flash;
strobe_t* strobe;
glow_t* glow;
int i;
// save off the current thinkers
//I_Printf( "Savegame on leveltime %d\n====================\n", ::g->leveltime );
for (th = ::g->thinkercap.next ; th != &::g->thinkercap ; th=th->next)
{
//mobj_t* test = (mobj_t*)th;
//I_Printf( "%3d: %x == function\n", index++, th->function.acp1 );
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
{
*::g->save_p++ = tc_mobj;
PADSAVEP();
mobj = (mobj_t *)::g->save_p;
memcpy (mobj, th, sizeof(*mobj));
::g->save_p += sizeof(*mobj);
mobj->state = (state_t *)(mobj->state - ::g->states);
if (mobj->player)
mobj->player = (player_t *)((mobj->player-::g->players) + 1);
// Save out 'target'
int moIndex = GetMOIndex( mobj->target );
*::g->save_p++ = moIndex >> 8;
*::g->save_p++ = moIndex;
// Save out 'tracer'
moIndex = GetMOIndex( mobj->tracer );
*::g->save_p++ = moIndex >> 8;
*::g->save_p++ = moIndex;
moIndex = GetMOIndex( mobj->snext );
*::g->save_p++ = moIndex >> 8;
*::g->save_p++ = moIndex;
moIndex = GetMOIndex( mobj->sprev );
*::g->save_p++ = moIndex >> 8;
*::g->save_p++ = moIndex;
// Is this the head of a sector list?
if ( mobj->subsector->sector->thinglist == (mobj_t*)th ) {
*::g->save_p++ = 1;
}
else {
*::g->save_p++ = 0;
}
moIndex = GetMOIndex( mobj->bnext );
*::g->save_p++ = moIndex >> 8;
*::g->save_p++ = moIndex;
moIndex = GetMOIndex( mobj->bprev );
*::g->save_p++ = moIndex >> 8;
*::g->save_p++ = moIndex;
// Is this the head of a block list?
int blockx = (mobj->x - ::g->bmaporgx)>>MAPBLOCKSHIFT;
int blocky = (mobj->y - ::g->bmaporgy)>>MAPBLOCKSHIFT;
if ( blockx >= 0 && blockx < ::g->bmapwidth && blocky >= 0 && blocky < ::g->bmapheight
&& (mobj_t*)th == ::g->blocklinks[blocky*::g->bmapwidth+blockx] ) {
*::g->save_p++ = 1;
}
else {
*::g->save_p++ = 0;
}
continue;
}
if (th->function.acv == (actionf_v)NULL)
{
for (i = 0; i < MAXCEILINGS;i++)
if (::g->activeceilings[i] == (ceiling_t *)th)
break;
if (isave_p++ = tc_ceiling;
PADSAVEP();
ceiling = (ceiling_t *)::g->save_p;
memcpy (ceiling, th, sizeof(*ceiling));
::g->save_p += sizeof(*ceiling);
ceiling->sector = (sector_t *)(ceiling->sector - ::g->sectors);
}
continue;
}
if (th->function.acp1 == (actionf_p1)T_MoveCeiling)
{
*::g->save_p++ = tc_ceiling;
PADSAVEP();
ceiling = (ceiling_t *)::g->save_p;
memcpy (ceiling, th, sizeof(*ceiling));
::g->save_p += sizeof(*ceiling);
ceiling->sector = (sector_t *)(ceiling->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_VerticalDoor)
{
*::g->save_p++ = tc_door;
PADSAVEP();
door = (vldoor_t *)::g->save_p;
memcpy (door, th, sizeof(*door));
::g->save_p += sizeof(*door);
door->sector = (sector_t *)(door->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_MoveFloor)
{
*::g->save_p++ = tc_floor;
PADSAVEP();
floor = (floormove_t *)::g->save_p;
memcpy (floor, th, sizeof(*floor));
::g->save_p += sizeof(*floor);
floor->sector = (sector_t *)(floor->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_PlatRaise)
{
*::g->save_p++ = tc_plat;
PADSAVEP();
plat = (plat_t *)::g->save_p;
memcpy (plat, th, sizeof(*plat));
::g->save_p += sizeof(*plat);
plat->sector = (sector_t *)(plat->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_FireFlicker)
{
*::g->save_p++ = tc_fire;
PADSAVEP();
fire = (fireflicker_t *)::g->save_p;
memcpy (fire, th, sizeof(*fire));
::g->save_p += sizeof(*fire);
fire->sector = (sector_t *)(fire->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_LightFlash)
{
*::g->save_p++ = tc_flash;
PADSAVEP();
flash = (lightflash_t *)::g->save_p;
memcpy (flash, th, sizeof(*flash));
::g->save_p += sizeof(*flash);
flash->sector = (sector_t *)(flash->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_StrobeFlash)
{
*::g->save_p++ = tc_strobe;
PADSAVEP();
strobe = (strobe_t *)::g->save_p;
memcpy (strobe, th, sizeof(*strobe));
::g->save_p += sizeof(*strobe);
strobe->sector = (sector_t *)(strobe->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_Glow)
{
*::g->save_p++ = tc_glow;
PADSAVEP();
glow = (glow_t *)::g->save_p;
memcpy (glow, th, sizeof(*glow));
::g->save_p += sizeof(*glow);
glow->sector = (sector_t *)(glow->sector - ::g->sectors);
continue;
}
}
// add a terminating marker
*::g->save_p++ = tc_end;
sector_t* sec;
short* put = (short *)::g->save_p;
for (i=0, sec = ::g->sectors ; i < ::g->numsectors ; i++,sec++) {
*put++ = (short)GetMOIndex( sec->soundtarget );
}
::g->save_p = (byte *)put;
// add a terminating marker
*::g->save_p++ = tc_end;
}
//
// P_UnArchiveThinkers
//
void P_UnArchiveThinkers (void)
{
byte tclass;
thinker_t* currentthinker;
thinker_t* next;
mobj_t* mobj;
ceiling_t* ceiling;
vldoor_t* door;
floormove_t* floor;
plat_t* plat;
fireflicker_t* fire;
lightflash_t* flash;
strobe_t* strobe;
glow_t* glow;
thinker_t* th;
int count = 0;
sector_t* ss = NULL;
int mo_index = 0;
int mo_targets[1024];
int mo_tracers[1024];
int mo_snext[1024];
int mo_sprev[1024];
bool mo_shead[1024];
int mo_bnext[1024];
int mo_bprev[1024];
bool mo_bhead[1024];
// remove all the current thinkers
currentthinker = ::g->thinkercap.next;
while (currentthinker != &::g->thinkercap)
{
next = currentthinker->next;
if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
P_RemoveMobj ((mobj_t *)currentthinker);
else
Z_Free(currentthinker);
currentthinker = next;
}
P_InitThinkers ();
// read in saved thinkers
while (1)
{
tclass = *::g->save_p++;
switch (tclass)
{
case tc_end:
// clear sector thing lists
ss = ::g->sectors;
for (int i=0 ; i < ::g->numsectors ; i++, ss++) {
ss->thinglist = NULL;
}
// clear blockmap thing lists
count = sizeof(*::g->blocklinks) * ::g->bmapwidth * ::g->bmapheight;
memset (::g->blocklinks, 0, count);
// Doom 2 level 30 requires some global pointers, wheee!
::g->numbraintargets = 0;
// fixup mobj_t pointers now that all thinkers have been restored
mo_index = 0;
for (th = ::g->thinkercap.next ; th != &::g->thinkercap ; th=th->next) {
if (th->function.acp1 == (actionf_p1)P_MobjThinker) {
mobj = (mobj_t*)th;
mobj->target = GetMO( mo_targets[mo_index] );
mobj->tracer = GetMO( mo_tracers[mo_index] );
mobj->snext = GetMO( mo_snext[mo_index] );
mobj->sprev = GetMO( mo_sprev[mo_index] );
if ( mo_shead[mo_index] ) {
mobj->subsector->sector->thinglist = mobj;
}
mobj->bnext = GetMO( mo_bnext[mo_index] );
mobj->bprev = GetMO( mo_bprev[mo_index] );
if ( mo_bhead[mo_index] ) {
// Is this the head of a block list?
int blockx = (mobj->x - ::g->bmaporgx)>>MAPBLOCKSHIFT;
int blocky = (mobj->y - ::g->bmaporgy)>>MAPBLOCKSHIFT;
if ( blockx >= 0 && blockx < ::g->bmapwidth && blocky >= 0 && blocky < ::g->bmapheight ) {
::g->blocklinks[blocky*::g->bmapwidth+blockx] = mobj;
}
}
// Doom 2 level 30 requires some global pointers, wheee!
if ( mobj->type == MT_BOSSTARGET ) {
::g->braintargets[::g->numbraintargets] = mobj;
::g->numbraintargets++;
}
mo_index++;
}
}
int i;
sector_t* sec;
short* get;
get = (short *)::g->save_p;
for (i=0, sec = ::g->sectors ; i < ::g->numsectors ; i++,sec++)
{
sec->soundtarget = GetMO( *get++ );
}
::g->save_p = (byte *)get;
tclass = *::g->save_p++;
if ( tclass != tc_end ) {
I_Error( "Savegame error after loading sector soundtargets." );
}
// print the current thinkers
//I_Printf( "Loadgame on leveltime %d\n====================\n", ::g->leveltime );
for (th = ::g->thinkercap.next ; th != &::g->thinkercap ; th=th->next)
{
//mobj_t* test = (mobj_t*)th;
//I_Printf( "%3d: %x == function\n", index++, th->function.acp1 );
}
return; // end of list
case tc_mobj:
PADSAVEP();
mobj = (mobj_t*)DoomLib::Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL);
memcpy (mobj, ::g->save_p, sizeof(*mobj));
::g->save_p += sizeof(*mobj);
mobj->state = &::g->states[(int)mobj->state];
mobj->target = NULL;
mobj->tracer = NULL;
if (mobj->player)
{
mobj->player = &::g->players[(int)mobj->player-1];
mobj->player->mo = mobj;
}
P_SetThingPosition (mobj);
mobj->info = &mobjinfo[mobj->type];
mobj->floorz = mobj->subsector->sector->floorheight;
mobj->ceilingz = mobj->subsector->sector->ceilingheight;
mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
// Read in 'target' and store for fixup
int a, b, foundIndex;
a = *::g->save_p++;
b = *::g->save_p++;
foundIndex = (a << 8) + b;
mo_targets[mo_index] = foundIndex;
// Read in 'tracer' and store for fixup
a = *::g->save_p++;
b = *::g->save_p++;
foundIndex = (a << 8) + b;
mo_tracers[mo_index] = foundIndex;
// Read in 'snext' and store for fixup
a = *::g->save_p++;
b = *::g->save_p++;
foundIndex = (a << 8) + b;
mo_snext[mo_index] = foundIndex;
// Read in 'sprev' and store for fixup
a = *::g->save_p++;
b = *::g->save_p++;
foundIndex = (a << 8) + b;
mo_sprev[mo_index] = foundIndex;
foundIndex = *::g->save_p++;
mo_shead[mo_index] = foundIndex == 1;
// Read in 'bnext' and store for fixup
a = *::g->save_p++;
b = *::g->save_p++;
foundIndex = (a << 8) + b;
mo_bnext[mo_index] = foundIndex;
// Read in 'bprev' and store for fixup
a = *::g->save_p++;
b = *::g->save_p++;
foundIndex = (a << 8) + b;
mo_bprev[mo_index] = foundIndex;
foundIndex = *::g->save_p++;
mo_bhead[mo_index] = foundIndex == 1;
mo_index++;
P_AddThinker (&mobj->thinker);
break;
case tc_ceiling:
PADSAVEP();
ceiling = (ceiling_t*)DoomLib::Z_Malloc(sizeof(*ceiling), PU_LEVEL, NULL);
memcpy (ceiling, ::g->save_p, sizeof(*ceiling));
::g->save_p += sizeof(*ceiling);
ceiling->sector = &::g->sectors[(int)ceiling->sector];
ceiling->sector->specialdata = ceiling;
if (ceiling->thinker.function.acp1)
ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling;
P_AddThinker (&ceiling->thinker);
P_AddActiveCeiling(ceiling);
break;
case tc_door:
PADSAVEP();
door = (vldoor_t*)DoomLib::Z_Malloc(sizeof(*door), PU_LEVEL, NULL);
memcpy (door, ::g->save_p, sizeof(*door));
::g->save_p += sizeof(*door);
door->sector = &::g->sectors[(int)door->sector];
door->sector->specialdata = door;
door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
P_AddThinker (&door->thinker);
break;
case tc_floor:
PADSAVEP();
floor = (floormove_t*)DoomLib::Z_Malloc (sizeof(*floor), PU_LEVEL, NULL);
memcpy (floor, ::g->save_p, sizeof(*floor));
::g->save_p += sizeof(*floor);
floor->sector = &::g->sectors[(int)floor->sector];
floor->sector->specialdata = floor;
floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor;
P_AddThinker (&floor->thinker);
break;
case tc_plat:
PADSAVEP();
plat = (plat_t*)DoomLib::Z_Malloc (sizeof(*plat), PU_LEVEL, NULL);
memcpy (plat, ::g->save_p, sizeof(*plat));
::g->save_p += sizeof(*plat);
plat->sector = &::g->sectors[(int)plat->sector];
plat->sector->specialdata = plat;
if (plat->thinker.function.acp1)
plat->thinker.function.acp1 = (actionf_p1)T_PlatRaise;
P_AddThinker (&plat->thinker);
P_AddActivePlat(plat);
break;
case tc_fire:
PADSAVEP();
fire = (fireflicker_t*)DoomLib::Z_Malloc (sizeof(*fire), PU_LEVEL, NULL);
memcpy (fire, ::g->save_p, sizeof(*fire));
::g->save_p += sizeof(*fire);
fire->sector = &::g->sectors[(int)fire->sector];
fire->thinker.function.acp1 = (actionf_p1)T_FireFlicker;
P_AddThinker (&fire->thinker);
break;
case tc_flash:
PADSAVEP();
flash = (lightflash_t*)DoomLib::Z_Malloc (sizeof(*flash), PU_LEVEL, NULL);
memcpy (flash, ::g->save_p, sizeof(*flash));
::g->save_p += sizeof(*flash);
flash->sector = &::g->sectors[(int)flash->sector];
flash->thinker.function.acp1 = (actionf_p1)T_LightFlash;
P_AddThinker (&flash->thinker);
break;
case tc_strobe:
PADSAVEP();
strobe = (strobe_t*)DoomLib::Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL);
memcpy (strobe, ::g->save_p, sizeof(*strobe));
::g->save_p += sizeof(*strobe);
strobe->sector = &::g->sectors[(int)strobe->sector];
strobe->thinker.function.acp1 = (actionf_p1)T_StrobeFlash;
P_AddThinker (&strobe->thinker);
break;
case tc_glow:
PADSAVEP();
glow = (glow_t*)DoomLib::Z_Malloc (sizeof(*glow), PU_LEVEL, NULL);
memcpy (glow, ::g->save_p, sizeof(*glow));
::g->save_p += sizeof(*glow);
glow->sector = &::g->sectors[(int)glow->sector];
glow->thinker.function.acp1 = (actionf_p1)T_Glow;
P_AddThinker (&glow->thinker);
break;
default:
I_Error ("Unknown tclass %i in savegame",tclass);
}
}
}
//
// P_ArchiveSpecials
//
//
// Things to handle:
//
// T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list
// T_VerticalDoor, (vldoor_t: sector_t * swizzle),
// T_MoveFloor, (floormove_t: sector_t * swizzle),
// T_LightFlash, (lightflash_t: sector_t * swizzle),
// T_StrobeFlash, (strobe_t: sector_t *),
// T_Glow, (glow_t: sector_t *),
// T_PlatRaise, (plat_t: sector_t *), - active list
//
void P_ArchiveSpecials (void)
{
thinker_t* th;
ceiling_t* ceiling;
vldoor_t* door;
floormove_t* floor;
plat_t* plat;
lightflash_t* flash;
strobe_t* strobe;
glow_t* glow;
int i;
// save off the current thinkers
for (th = ::g->thinkercap.next ; th != &::g->thinkercap ; th=th->next)
{
if (th->function.acv == (actionf_v)NULL)
{
for (i = 0; i < MAXCEILINGS;i++)
if (::g->activeceilings[i] == (ceiling_t *)th)
break;
if (isave_p++ = tc_ceiling;
PADSAVEP();
ceiling = (ceiling_t *)::g->save_p;
memcpy (ceiling, th, sizeof(*ceiling));
::g->save_p += sizeof(*ceiling);
ceiling->sector = (sector_t *)(ceiling->sector - ::g->sectors);
}
continue;
}
if (th->function.acp1 == (actionf_p1)T_MoveCeiling)
{
*::g->save_p++ = tc_ceiling;
PADSAVEP();
ceiling = (ceiling_t *)::g->save_p;
memcpy (ceiling, th, sizeof(*ceiling));
::g->save_p += sizeof(*ceiling);
ceiling->sector = (sector_t *)(ceiling->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_VerticalDoor)
{
*::g->save_p++ = tc_door;
PADSAVEP();
door = (vldoor_t *)::g->save_p;
memcpy (door, th, sizeof(*door));
::g->save_p += sizeof(*door);
door->sector = (sector_t *)(door->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_MoveFloor)
{
*::g->save_p++ = tc_floor;
PADSAVEP();
floor = (floormove_t *)::g->save_p;
memcpy (floor, th, sizeof(*floor));
::g->save_p += sizeof(*floor);
floor->sector = (sector_t *)(floor->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_PlatRaise)
{
*::g->save_p++ = tc_plat;
PADSAVEP();
plat = (plat_t *)::g->save_p;
memcpy (plat, th, sizeof(*plat));
::g->save_p += sizeof(*plat);
plat->sector = (sector_t *)(plat->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_LightFlash)
{
*::g->save_p++ = tc_flash;
PADSAVEP();
flash = (lightflash_t *)::g->save_p;
memcpy (flash, th, sizeof(*flash));
::g->save_p += sizeof(*flash);
flash->sector = (sector_t *)(flash->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_StrobeFlash)
{
*::g->save_p++ = tc_strobe;
PADSAVEP();
strobe = (strobe_t *)::g->save_p;
memcpy (strobe, th, sizeof(*strobe));
::g->save_p += sizeof(*strobe);
strobe->sector = (sector_t *)(strobe->sector - ::g->sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_Glow)
{
*::g->save_p++ = tc_glow;
PADSAVEP();
glow = (glow_t *)::g->save_p;
memcpy (glow, th, sizeof(*glow));
::g->save_p += sizeof(*glow);
glow->sector = (sector_t *)(glow->sector - ::g->sectors);
continue;
}
}
// add a terminating marker
*::g->save_p++ = tc_endspecials;
}
//
// P_UnArchiveSpecials
//
void P_UnArchiveSpecials (void)
{
byte tclass;
ceiling_t* ceiling;
vldoor_t* door;
floormove_t* floor;
plat_t* plat;
lightflash_t* flash;
strobe_t* strobe;
glow_t* glow;
// read in saved thinkers
while (1)
{
tclass = *::g->save_p++;
switch (tclass)
{
case tc_endspecials:
return; // end of list
case tc_ceiling:
PADSAVEP();
ceiling = (ceiling_t*)DoomLib::Z_Malloc(sizeof(*ceiling), PU_LEVEL, NULL);
memcpy (ceiling, ::g->save_p, sizeof(*ceiling));
::g->save_p += sizeof(*ceiling);
ceiling->sector = &::g->sectors[(int)ceiling->sector];
ceiling->sector->specialdata = ceiling;
if (ceiling->thinker.function.acp1)
ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling;
P_AddThinker (&ceiling->thinker);
P_AddActiveCeiling(ceiling);
break;
case tc_door:
PADSAVEP();
door = (vldoor_t*)DoomLib::Z_Malloc(sizeof(*door), PU_LEVEL, NULL);
memcpy (door, ::g->save_p, sizeof(*door));
::g->save_p += sizeof(*door);
door->sector = &::g->sectors[(int)door->sector];
door->sector->specialdata = door;
door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
P_AddThinker (&door->thinker);
break;
case tc_floor:
PADSAVEP();
floor = (floormove_t*)DoomLib::Z_Malloc (sizeof(*floor), PU_LEVEL, NULL);
memcpy (floor, ::g->save_p, sizeof(*floor));
::g->save_p += sizeof(*floor);
floor->sector = &::g->sectors[(int)floor->sector];
floor->sector->specialdata = floor;
floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor;
P_AddThinker (&floor->thinker);
break;
case tc_plat:
PADSAVEP();
plat = (plat_t*)DoomLib::Z_Malloc (sizeof(*plat), PU_LEVEL, NULL);
memcpy (plat, ::g->save_p, sizeof(*plat));
::g->save_p += sizeof(*plat);
plat->sector = &::g->sectors[(int)plat->sector];
plat->sector->specialdata = plat;
if (plat->thinker.function.acp1)
plat->thinker.function.acp1 = (actionf_p1)T_PlatRaise;
P_AddThinker (&plat->thinker);
P_AddActivePlat(plat);
break;
case tc_flash:
PADSAVEP();
flash = (lightflash_t*)DoomLib::Z_Malloc (sizeof(*flash), PU_LEVEL, NULL);
memcpy (flash, ::g->save_p, sizeof(*flash));
::g->save_p += sizeof(*flash);
flash->sector = &::g->sectors[(int)flash->sector];
flash->thinker.function.acp1 = (actionf_p1)T_LightFlash;
P_AddThinker (&flash->thinker);
break;
case tc_strobe:
PADSAVEP();
strobe = (strobe_t*)DoomLib::Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL);
memcpy (strobe, ::g->save_p, sizeof(*strobe));
::g->save_p += sizeof(*strobe);
strobe->sector = &::g->sectors[(int)strobe->sector];
strobe->thinker.function.acp1 = (actionf_p1)T_StrobeFlash;
P_AddThinker (&strobe->thinker);
break;
case tc_glow:
PADSAVEP();
glow = (glow_t*)DoomLib::Z_Malloc (sizeof(*glow), PU_LEVEL, NULL);
memcpy (glow, ::g->save_p, sizeof(*glow));
::g->save_p += sizeof(*glow);
glow->sector = &::g->sectors[(int)glow->sector];
glow->thinker.function.acp1 = (actionf_p1)T_Glow;
P_AddThinker (&glow->thinker);
break;
default:
I_Error ("P_UnarchiveSpecials:Unknown tclass %i "
"in savegame",tclass);
}
}
}