2015-05-19 21:54:34 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
Copyright (C) 1997, 2005 - 3D Realms Entertainment
|
|
|
|
|
|
|
|
This file is part of Shadow Warrior version 1.2
|
|
|
|
|
|
|
|
Shadow Warrior 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 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program 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 this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
|
|
|
Original Source: 1997 - Frank Maddin and Jim Norwood
|
|
|
|
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
2019-10-09 16:09:05 +00:00
|
|
|
#include "ns.h"
|
|
|
|
|
2015-05-19 21:54:34 +00:00
|
|
|
#define MAIN
|
|
|
|
#define QUIET
|
|
|
|
#include "build.h"
|
|
|
|
|
|
|
|
#include "names2.h"
|
|
|
|
#include "panel.h"
|
|
|
|
#include "game.h"
|
|
|
|
#include "tags.h"
|
|
|
|
#include "lists.h"
|
2020-11-26 17:05:49 +00:00
|
|
|
#include "interpolate.h"
|
2020-05-01 12:11:08 +00:00
|
|
|
#include "interpso.h"
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2019-03-21 02:24:19 +00:00
|
|
|
#include "network.h"
|
2015-05-19 21:54:34 +00:00
|
|
|
#include "jsector.h"
|
|
|
|
#include "parent.h"
|
|
|
|
|
|
|
|
//#define FILE_TYPE 1
|
|
|
|
|
|
|
|
#include "weapon.h"
|
2020-08-05 15:07:19 +00:00
|
|
|
#include "misc.h"
|
2015-05-19 21:54:34 +00:00
|
|
|
#include "player.h"
|
2019-11-01 23:38:30 +00:00
|
|
|
#include "i_specialpaths.h"
|
2019-11-27 18:31:58 +00:00
|
|
|
#include "savegamehelp.h"
|
2020-04-12 06:07:48 +00:00
|
|
|
#include "raze_music.h"
|
2019-12-10 21:22:59 +00:00
|
|
|
#include "mapinfo.h"
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
//void TimerFunc(task * Task);
|
2019-10-09 16:09:05 +00:00
|
|
|
BEGIN_SW_NS
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2019-10-09 17:58:09 +00:00
|
|
|
// This cannot have a namespace declaration
|
|
|
|
#include "saveable.h"
|
|
|
|
|
2015-05-19 21:54:34 +00:00
|
|
|
/*
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
TO DO
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
*/
|
|
|
|
|
2020-09-17 22:33:18 +00:00
|
|
|
void InitLevelGlobals(void);
|
|
|
|
|
2015-05-19 21:54:34 +00:00
|
|
|
extern int lastUpdate;
|
|
|
|
extern char SaveGameDescr[10][80];
|
|
|
|
extern short Bunny_Count;
|
2020-09-09 18:32:24 +00:00
|
|
|
extern bool NewGame;
|
2015-05-19 21:54:34 +00:00
|
|
|
extern int GodMode;
|
2020-07-13 20:20:14 +00:00
|
|
|
extern int FinishTimer;
|
2020-09-09 18:28:05 +00:00
|
|
|
extern int FinishAnim;
|
2015-05-19 21:54:34 +00:00
|
|
|
extern int GameVersion;
|
|
|
|
//extern short Zombies;
|
|
|
|
|
2020-09-09 18:32:24 +00:00
|
|
|
extern bool serpwasseen;
|
|
|
|
extern bool sumowasseen;
|
|
|
|
extern bool zillawasseen;
|
2015-05-19 21:54:34 +00:00
|
|
|
extern short BossSpriteNum[3];
|
|
|
|
|
|
|
|
#define PANEL_SAVE 1
|
|
|
|
#define ANIM_SAVE 1
|
|
|
|
|
|
|
|
extern STATE s_NotRestored[];
|
|
|
|
|
2021-04-02 09:55:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, savedcodesym& w, savedcodesym* def)
|
|
|
|
{
|
|
|
|
static savedcodesym nul;
|
|
|
|
if (!def)
|
|
|
|
{
|
|
|
|
def = &nul;
|
|
|
|
if (arc.isReading()) w = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arc.BeginObject(keyname))
|
|
|
|
{
|
|
|
|
arc("module", w.module, def->module)
|
|
|
|
("index", w.index, def->index)
|
|
|
|
.EndObject();
|
|
|
|
}
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, saveddatasym& w, saveddatasym* def)
|
|
|
|
{
|
|
|
|
static saveddatasym nul;
|
|
|
|
if (!def)
|
|
|
|
{
|
|
|
|
def = &nul;
|
|
|
|
if (arc.isReading()) w = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arc.BeginObject(keyname))
|
|
|
|
{
|
|
|
|
arc("module", w.module, def->module)
|
|
|
|
("index", w.index, def->index)
|
|
|
|
("offset", w.offset, def->offset)
|
|
|
|
.EndObject();
|
|
|
|
}
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// todo: make sure all saveables are arrays so we can store indices instead of offsets
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
FSerializer& SerializeDataPtr(FSerializer& arc, const char* keyname, void*& w, size_t sizeOf)
|
|
|
|
{
|
|
|
|
saveddatasym sym;
|
|
|
|
if (arc.isWriting())
|
|
|
|
{
|
|
|
|
Saveable_FindDataSym(w, &sym);
|
|
|
|
arc(keyname, sym);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
arc(keyname, sym);
|
|
|
|
Saveable_RestoreDataSym(&sym, &w);
|
|
|
|
}
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
FSerializer& SerializeCodePtr(FSerializer& arc, const char* keyname, void** w)
|
|
|
|
{
|
|
|
|
savedcodesym sym;
|
|
|
|
if (arc.isWriting())
|
|
|
|
{
|
|
|
|
Saveable_FindCodeSym(*w, &sym);
|
|
|
|
arc(keyname, sym);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
arc(keyname, sym);
|
|
|
|
Saveable_RestoreCodeSym(&sym, w);
|
|
|
|
}
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Unfortunately this cannot be simplified with templates.
|
|
|
|
// This requires an explicit function for each pointer type.
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, PANEL_STATEp& w, PANEL_STATEp* def)
|
|
|
|
{
|
|
|
|
return SerializeDataPtr(arc, keyname, *(void**)&w, sizeof(PANEL_STATE));
|
|
|
|
}
|
|
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, STATEp& w, STATEp* def)
|
|
|
|
{
|
|
|
|
return SerializeDataPtr(arc, keyname, *(void**)&w, sizeof(STATE));
|
|
|
|
}
|
|
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, STATEp*& w, STATEp** def)
|
|
|
|
{
|
|
|
|
return SerializeDataPtr(arc, keyname, *(void**)&w, sizeof(STATEp));
|
|
|
|
}
|
|
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, ACTOR_ACTION_SETp& w, ACTOR_ACTION_SETp* def)
|
|
|
|
{
|
|
|
|
return SerializeDataPtr(arc, keyname, *(void**)&w, sizeof(ACTOR_ACTION_SET));
|
|
|
|
}
|
|
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, PERSONALITYp& w, PERSONALITYp* def)
|
|
|
|
{
|
|
|
|
return SerializeDataPtr(arc, keyname, *(void**)&w, sizeof(PERSONALITY));
|
|
|
|
}
|
|
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, ATTRIBUTEp& w, ATTRIBUTEp* def)
|
|
|
|
{
|
|
|
|
return SerializeDataPtr(arc, keyname, *(void**)&w, sizeof(ATTRIBUTE));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, PLAYERp& w, PLAYERp* def)
|
|
|
|
{
|
|
|
|
int ndx = w ? int(w - Player) : -1;
|
|
|
|
arc(keyname, ndx);
|
|
|
|
w = ndx == -1 ? nullptr : Player + ndx;
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, SECTOR_OBJECTp& w, SECTOR_OBJECTp* def)
|
|
|
|
{
|
|
|
|
int ndx = w ? int(w - SectorObject) : -1;
|
|
|
|
arc(keyname, ndx);
|
|
|
|
w = ndx == -1 ? nullptr : SectorObject;
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, ROTATOR& w, ROTATOR* def)
|
|
|
|
{
|
|
|
|
if (arc.BeginObject(keyname))
|
|
|
|
{
|
|
|
|
arc("pos", w.pos)
|
|
|
|
("open_dest", w.open_dest)
|
|
|
|
("tgt", w.tgt)
|
|
|
|
("speed", w.speed)
|
|
|
|
("orig_speed", w.orig_speed)
|
|
|
|
("vel", w.vel)
|
|
|
|
("origx", w.origX)
|
|
|
|
("origy", w.origY)
|
|
|
|
.EndObject();
|
|
|
|
}
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
static USER nuluser; // must be outside the function to evade C++'s retarded initialization rules for static function variables.
|
|
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, USER& w, USER* def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
{
|
|
|
|
def = &nuluser;
|
2021-04-02 10:00:38 +00:00
|
|
|
if (arc.isReading()) w.Clear();
|
2021-04-02 09:55:23 +00:00
|
|
|
}
|
|
|
|
if (arc.BeginObject(keyname))
|
|
|
|
{
|
|
|
|
arc("WallP", w.WallP, def->WallP)
|
|
|
|
("State", w.State, def->State)
|
|
|
|
("Rot", w.Rot, def->Rot)
|
|
|
|
("StateStart", w.StateStart, def->StateStart)
|
|
|
|
("StateEnd", w.StateEnd, def->StateEnd)
|
|
|
|
("StateFallOverride", w.StateFallOverride, def->StateFallOverride)
|
|
|
|
("ActorActionSet", w.ActorActionSet, def->ActorActionSet)
|
|
|
|
("Personality", w.Personality, def->Personality)
|
|
|
|
("Attrib", w.Attrib, def->Attrib)
|
|
|
|
("sop_parent", w.sop_parent, def->sop_parent)
|
|
|
|
("flags", w.Flags, def->Flags)
|
|
|
|
("flags2", w.Flags2, def->Flags2)
|
|
|
|
("Tics", w.Tics, def->Tics)
|
|
|
|
("RotNum", w.RotNum, def->RotNum)
|
|
|
|
("ID", w.ID, def->ID)
|
|
|
|
("Health", w.Health, def->Health)
|
|
|
|
("MaxHealth", w.MaxHealth, def->MaxHealth)
|
|
|
|
("LastDamage", w.LastDamage, def->LastDamage)
|
|
|
|
("PainThreshold", w.PainThreshold, def->PainThreshold)
|
|
|
|
("jump_speed", w.jump_speed, def->jump_speed)
|
|
|
|
("jump_grav", w.jump_grav, def->jump_grav)
|
|
|
|
("ceiling_dist", w.ceiling_dist, def->ceiling_dist)
|
|
|
|
("floor_dist", w.floor_dist, def->floor_dist)
|
|
|
|
("lo_step", w.lo_step, def->lo_step)
|
|
|
|
("hiz", w.hiz, def->hiz)
|
|
|
|
("loz", w.loz, def->loz)
|
|
|
|
("zclip", w.zclip, def->zclip)
|
|
|
|
("hi_sectp", w.hi_sectp, def->hi_sectp)
|
|
|
|
("lo_sectp", w.lo_sectp, def->lo_sectp)
|
|
|
|
("hi_sp", w.hi_sp, def->hi_sp)
|
|
|
|
("lo_sp", w.lo_sp, def->lo_sp)
|
|
|
|
("active_range", w.active_range, def->active_range)
|
|
|
|
("SpriteNum", w.SpriteNum, def->SpriteNum)
|
|
|
|
("Attach", w.Attach, def->Attach)
|
|
|
|
("SpriteP", w.SpriteP, def->SpriteP)
|
|
|
|
("PlayerP", w.PlayerP, def->PlayerP)
|
|
|
|
("Sibling", w.Sibling, def->Sibling)
|
|
|
|
("xchange", w.xchange, def->xchange)
|
|
|
|
("ychange", w.ychange, def->ychange)
|
|
|
|
("zchange", w.zchange, def->zchange)
|
|
|
|
("z_tgt", w.z_tgt, def->z_tgt)
|
|
|
|
("vel_tgt", w.vel_tgt, def->vel_tgt)
|
|
|
|
("vel_rate", w.vel_rate, def->vel_rate)
|
|
|
|
("speed", w.speed, def->speed)
|
|
|
|
("Counter", w.Counter, def->Counter)
|
|
|
|
("Counter2", w.Counter2, def->Counter2)
|
|
|
|
("Counter3", w.Counter3, def->Counter3)
|
|
|
|
("DamageTics", w.DamageTics, def->DamageTics)
|
|
|
|
("BladeDamageTics", w.BladeDamageTics, def->BladeDamageTics)
|
|
|
|
("WpnGoal", w.WpnGoal, def->WpnGoal)
|
|
|
|
("Radius", w.Radius, def->Radius)
|
|
|
|
("OverlapZ", w.OverlapZ, def->OverlapZ)
|
|
|
|
("flame", w.flame, def->flame)
|
|
|
|
("tgt_sp", w.tgt_sp, def->tgt_sp)
|
|
|
|
("scale_speed", w.scale_speed, def->scale_speed)
|
|
|
|
("scale_value", w.scale_value, def->scale_value)
|
|
|
|
("scale_tgt", w.scale_tgt, def->scale_tgt)
|
|
|
|
("DistCheck", w.DistCheck, def->DistCheck)
|
|
|
|
("Dist", w.Dist, def->Dist)
|
|
|
|
("TargetDist", w.TargetDist, def->TargetDist)
|
|
|
|
("WaitTics", w.WaitTics, def->WaitTics)
|
|
|
|
("track", w.track, def->track)
|
|
|
|
("point", w.point, def->point)
|
|
|
|
("track_dir", w.track_dir, def->track_dir)
|
|
|
|
("track_vel", w.track_vel, def->track_vel)
|
|
|
|
("slide_ang", w.slide_ang, def->slide_ang)
|
|
|
|
("slide_vel", w.slide_vel, def->slide_vel)
|
|
|
|
("slide_dec", w.slide_dec, def->slide_dec)
|
|
|
|
("motion_blur_dist", w.motion_blur_dist, def->motion_blur_dist)
|
|
|
|
("motion_blur_num", w.motion_blur_num, def->motion_blur_num)
|
|
|
|
("wait_active_check", w.wait_active_check, def->wait_active_check)
|
|
|
|
("inactive_time", w.inactive_time, def->inactive_time)
|
|
|
|
("sx", w.sx, def->sx)
|
|
|
|
("sy", w.sy, def->sy)
|
|
|
|
("sz", w.sz, def->sz)
|
|
|
|
("sang", w.sang, def->sang)
|
|
|
|
("spal", w.spal, def->spal)
|
|
|
|
("ret", w.ret, def->ret)
|
|
|
|
("Flag1", w.Flag1, def->Flag1)
|
|
|
|
("LastWeaponNum", w.LastWeaponNum, def->LastWeaponNum)
|
|
|
|
("WeaponNum", w.WeaponNum, def->WeaponNum)
|
|
|
|
("bounce", w.bounce, def->bounce)
|
|
|
|
("ShellNum", w.ShellNum, def->ShellNum)
|
|
|
|
("FlagOwner", w.FlagOwner, def->FlagOwner)
|
|
|
|
("Vis", w.Vis, def->Vis)
|
|
|
|
("DidAlert", w.DidAlert, def->DidAlert)
|
|
|
|
("filler", w.filler, def->filler)
|
|
|
|
("wallshade", w.WallShade)
|
|
|
|
("rotator", w.rotator)
|
|
|
|
("oz", w.oz, def->oz);
|
|
|
|
|
|
|
|
SerializeCodePtr(arc, "ActorActionFunc", (void**)&w.ActorActionFunc);
|
|
|
|
arc.EndObject();
|
|
|
|
|
|
|
|
if (arc.isReading())
|
|
|
|
{
|
|
|
|
w.oangdiff = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return arc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void SerializeUser(FSerializer& arc)
|
|
|
|
{
|
|
|
|
FixedBitArray<MAXSPRITES> hitlist;
|
|
|
|
|
|
|
|
if (arc.isWriting())
|
|
|
|
{
|
|
|
|
for (int i = 0; i < MAXSPRITES; i++)
|
|
|
|
{
|
|
|
|
hitlist.Set(i, !!User[i].Data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (int i = 0; i < MAXSPRITES; i++)
|
|
|
|
{
|
|
|
|
User[i].Clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
arc("usermap", hitlist);
|
|
|
|
arc.SparseArray("user", User, MAXSPRITES, hitlist);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void GameInterface::SerializeGameState(FSerializer& arc)
|
|
|
|
{
|
|
|
|
Saveable_Init();
|
|
|
|
|
|
|
|
if (arc.BeginObject("state"))
|
|
|
|
{
|
|
|
|
SerializeUser(arc);
|
|
|
|
|
|
|
|
arc.EndObject();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-11-17 17:02:17 +00:00
|
|
|
int PanelSpriteToNdx(PLAYERp pp, PANEL_SPRITEp psprite)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
short ndx = 0;
|
|
|
|
PANEL_SPRITEp psp=NULL, next=NULL;
|
|
|
|
|
|
|
|
TRAVERSE(&pp->PanelSpriteList, psp, next)
|
|
|
|
{
|
|
|
|
if (psp == psprite)
|
|
|
|
return ndx;
|
|
|
|
|
|
|
|
ndx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// special case for pointing to the list head
|
|
|
|
if ((LIST)psprite == (LIST)&pp->PanelSpriteList)
|
|
|
|
return 9999;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-17 17:02:17 +00:00
|
|
|
PANEL_SPRITEp PanelNdxToSprite(PLAYERp pp, int ndx)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
short count = 0;
|
|
|
|
PANEL_SPRITEp psp, next;
|
|
|
|
|
|
|
|
if (ndx == -1)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (ndx == 9999)
|
|
|
|
return (PANEL_SPRITEp)&pp->PanelSpriteList;
|
|
|
|
|
|
|
|
TRAVERSE(&pp->PanelSpriteList, psp, next)
|
|
|
|
{
|
|
|
|
if (count == ndx)
|
|
|
|
return psp;
|
|
|
|
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-05-19 22:09:25 +00:00
|
|
|
int SaveSymDataInfo(MFILE_WRITE fil, void *ptr)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
saveddatasym sym;
|
|
|
|
|
|
|
|
if (Saveable_FindDataSym(ptr, &sym))
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
|
2020-01-22 21:57:28 +00:00
|
|
|
assert(false);
|
2015-05-19 21:54:34 +00:00
|
|
|
fp = fopen("savegame symbols missing.txt", "a");
|
|
|
|
if (fp)
|
|
|
|
{
|
2020-01-05 17:49:19 +00:00
|
|
|
fprintf(fp,"data %p - reference variable xdim at %p\n",ptr, &xdim);
|
2015-05-19 21:54:34 +00:00
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
MWRITE(&sym, sizeof(sym), 1, fil);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-11-17 17:02:17 +00:00
|
|
|
|
2019-04-08 06:27:31 +00:00
|
|
|
static int SaveSymCodeInfo_raw(MFILE_WRITE fil, void *ptr)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
savedcodesym sym;
|
|
|
|
|
|
|
|
if (Saveable_FindCodeSym(ptr, &sym))
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
|
2020-01-22 21:57:28 +00:00
|
|
|
assert(false);
|
2015-05-19 21:54:34 +00:00
|
|
|
fp = fopen("savegame symbols missing.txt", "a");
|
|
|
|
if (fp)
|
|
|
|
{
|
2020-01-05 17:49:19 +00:00
|
|
|
fprintf(fp,"code %p - reference function SaveSymDataInfo at %p\n",ptr, SaveSymDataInfo);
|
2015-05-19 21:54:34 +00:00
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
MWRITE(&sym, sizeof(sym), 1, fil);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-04-08 06:27:31 +00:00
|
|
|
template <typename T>
|
|
|
|
static int SaveSymCodeInfo(MFILE_WRITE fil, T * ptr)
|
|
|
|
{
|
|
|
|
return SaveSymCodeInfo_raw(fil, (void *)ptr);
|
|
|
|
}
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2015-05-19 22:09:25 +00:00
|
|
|
int LoadSymDataInfo(MFILE_READ fil, void **ptr)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
saveddatasym sym;
|
|
|
|
|
|
|
|
MREAD(&sym, sizeof(sym), 1, fil);
|
|
|
|
|
|
|
|
return Saveable_RestoreDataSym(&sym, ptr);
|
|
|
|
}
|
2015-05-19 22:09:25 +00:00
|
|
|
int LoadSymCodeInfo(MFILE_READ fil, void **ptr)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
savedcodesym sym;
|
|
|
|
|
|
|
|
MREAD(&sym, sizeof(sym), 1, fil);
|
|
|
|
|
|
|
|
return Saveable_RestoreCodeSym(&sym, ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-12-02 23:01:04 +00:00
|
|
|
|
2020-10-07 16:32:57 +00:00
|
|
|
bool GameInterface::SaveGame()
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2015-05-19 22:09:25 +00:00
|
|
|
MFILE_WRITE fil;
|
2015-05-19 21:54:34 +00:00
|
|
|
int i,j;
|
|
|
|
short ndx;
|
|
|
|
PLAYER tp;
|
|
|
|
PLAYERp pp;
|
|
|
|
SECT_USERp sectu;
|
|
|
|
USER tu;
|
|
|
|
USERp u;
|
|
|
|
ANIM tanim;
|
|
|
|
ANIMp a;
|
|
|
|
PANEL_SPRITE tpanel_sprite;
|
|
|
|
PANEL_SPRITEp psp,cur,next;
|
|
|
|
SECTOR_OBJECTp sop;
|
2020-03-06 15:49:49 +00:00
|
|
|
int saveisshot=0;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
Saveable_Init();
|
2019-11-26 23:41:26 +00:00
|
|
|
|
|
|
|
|
2019-12-10 21:22:59 +00:00
|
|
|
// workaround until the level info here has been transitioned.
|
2019-11-27 18:31:58 +00:00
|
|
|
fil = WriteSavegameChunk("snapshot.sw");
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
MWRITE(&Skill,sizeof(Skill),1,fil);
|
|
|
|
|
|
|
|
MWRITE(&numplayers,sizeof(numplayers),1,fil);
|
|
|
|
|
|
|
|
//save players info
|
|
|
|
pp = &tp;
|
|
|
|
for (i = 0; i < numplayers; i++)
|
|
|
|
{
|
|
|
|
memcpy(&tp, &Player[i], sizeof(PLAYER));
|
|
|
|
|
|
|
|
// this does not point to global data - this is allocated link list based
|
|
|
|
// save this inside the structure
|
|
|
|
#if PANEL_SAVE
|
|
|
|
pp->CurWpn = (PANEL_SPRITEp)(intptr_t)PanelSpriteToNdx(&Player[i], pp->CurWpn);
|
|
|
|
for (ndx = 0; ndx < MAX_WEAPONS; ndx++)
|
|
|
|
pp->Wpn[ndx] = (PANEL_SPRITEp)(intptr_t)PanelSpriteToNdx(&Player[i], pp->Wpn[ndx]);
|
|
|
|
pp->Chops = (PANEL_SPRITEp)(intptr_t)PanelSpriteToNdx(&Player[i], pp->Chops);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
MWRITE(&tp, sizeof(PLAYER),1,fil);
|
|
|
|
|
|
|
|
//////
|
|
|
|
|
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->remote_sprite);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->remote.sop_control);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->sop_remote);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->sop);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->hi_sectp);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->lo_sectp);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->hi_sp);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->lo_sp);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->last_camera_sp);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->SpriteP);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->UnderSpriteP);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
saveisshot |= SaveSymCodeInfo(fil, pp->DoPlayerAction);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->sop_control);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, pp->sop_riding);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if PANEL_SAVE
|
|
|
|
// local copy
|
|
|
|
psp = &tpanel_sprite;
|
|
|
|
for (i = 0; i < numplayers; i++)
|
|
|
|
{
|
|
|
|
unsigned j;
|
|
|
|
pp = &Player[i];
|
|
|
|
ndx = 0;
|
|
|
|
|
|
|
|
TRAVERSE(&pp->PanelSpriteList, cur, next)
|
|
|
|
{
|
|
|
|
// this is a HEADER
|
|
|
|
MWRITE(&ndx, sizeof(ndx),1,fil);
|
|
|
|
|
|
|
|
memcpy(psp, cur, sizeof(PANEL_SPRITE));
|
|
|
|
|
|
|
|
// Panel Sprite - save in structure
|
|
|
|
psp->sibling = (PANEL_SPRITEp)(intptr_t)PanelSpriteToNdx(pp, cur->sibling);
|
|
|
|
MWRITE(psp, sizeof(PANEL_SPRITE),1,fil);
|
|
|
|
|
|
|
|
saveisshot |= SaveSymDataInfo(fil, psp->PlayerP);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, psp->State);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, psp->RetractState);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, psp->PresentState);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, psp->ActionState);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, psp->RestState);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymCodeInfo(fil, psp->PanelSpriteFunc);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
for (j = 0; j < SIZ(psp->over); j++)
|
|
|
|
{
|
|
|
|
saveisshot |= SaveSymDataInfo(fil, psp->over[j].State);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ndx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// store -1 when done for player
|
|
|
|
ndx = -1;
|
|
|
|
MWRITE(&ndx, sizeof(ndx),1,fil);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//Sector User information
|
|
|
|
for (i = 0; i < numsectors; i++)
|
|
|
|
{
|
|
|
|
sectu = SectUser[i];
|
|
|
|
ndx = i;
|
|
|
|
if (sectu)
|
|
|
|
{
|
|
|
|
// write header
|
|
|
|
MWRITE(&ndx,sizeof(ndx),1,fil);
|
|
|
|
|
|
|
|
MWRITE(sectu,sizeof(SECT_USER),1,fil);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// write trailer
|
|
|
|
ndx = -1;
|
|
|
|
MWRITE(&ndx,sizeof(ndx),1,fil);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Sector object
|
|
|
|
//
|
|
|
|
|
|
|
|
MWRITE(SectorObject, sizeof(SectorObject),1,fil);
|
|
|
|
|
|
|
|
for (ndx = 0; ndx < (short)SIZ(SectorObject); ndx++)
|
|
|
|
{
|
|
|
|
sop = &SectorObject[ndx];
|
|
|
|
|
|
|
|
saveisshot |= SaveSymCodeInfo(fil, sop->PreMoveAnimator);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymCodeInfo(fil, sop->PostMoveAnimator);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymCodeInfo(fil, sop->Animator);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, sop->controller);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, sop->sp_child);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MWRITE(SineWaveFloor, sizeof(SineWaveFloor),1,fil);
|
|
|
|
MWRITE(SineWall, sizeof(SineWall),1,fil);
|
|
|
|
MWRITE(SpringBoard, sizeof(SpringBoard),1,fil);
|
|
|
|
|
|
|
|
|
|
|
|
MWRITE(Track, sizeof(Track),1,fil);
|
|
|
|
for (i = 0; i < MAX_TRACKS; i++)
|
|
|
|
{
|
|
|
|
ASSERT(Track[i].TrackPoint);
|
|
|
|
if (Track[i].NumPoints == 0)
|
|
|
|
MWRITE(Track[i].TrackPoint, sizeof(TRACK_POINT),1,fil);
|
|
|
|
else
|
|
|
|
MWRITE(Track[i].TrackPoint, Track[i].NumPoints * sizeof(TRACK_POINT),1,fil);
|
|
|
|
}
|
|
|
|
|
2020-11-12 12:31:32 +00:00
|
|
|
MWRITE(&Player[myconnectindex].input,sizeof(Player[myconnectindex].input),1,fil);
|
2015-05-19 21:54:34 +00:00
|
|
|
MWRITE(&screenpeek,sizeof(screenpeek),1,fil);
|
2020-09-02 18:56:09 +00:00
|
|
|
MWRITE(&randomseed, sizeof(randomseed), 1, fil);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
// do all sector manipulation structures
|
|
|
|
|
|
|
|
#if ANIM_SAVE
|
|
|
|
#if 1
|
|
|
|
MWRITE(&AnimCnt,sizeof(AnimCnt),1,fil);
|
|
|
|
|
|
|
|
for (i = 0, a = &tanim; i < AnimCnt; i++)
|
|
|
|
{
|
|
|
|
intptr_t offset;
|
|
|
|
memcpy(a,&Anim[i],sizeof(ANIM));
|
|
|
|
|
|
|
|
// maintain compatibility with sinking boat which points to user data
|
|
|
|
for (j=0; j<MAXSPRITES; j++)
|
|
|
|
{
|
2021-04-02 09:13:33 +00:00
|
|
|
if (User[j].Data())
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-04-02 09:13:33 +00:00
|
|
|
uint8_t* bp = (uint8_t*)User[j].Data();
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2015-05-19 21:58:29 +00:00
|
|
|
if ((uint8_t*)a->ptr >= bp && (uint8_t*)a->ptr < bp + sizeof(USER))
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2015-05-19 21:58:29 +00:00
|
|
|
offset = (intptr_t)((uint8_t*)a->ptr - bp); // offset from user data
|
2015-05-19 21:54:34 +00:00
|
|
|
a->ptr = (int *)-2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((intptr_t)a->ptr != -2)
|
|
|
|
{
|
|
|
|
for (j=0; j<numsectors; j++)
|
|
|
|
{
|
|
|
|
if (SectUser[j])
|
|
|
|
{
|
2015-05-19 21:58:29 +00:00
|
|
|
uint8_t* bp = (uint8_t*)SectUser[j];
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2015-05-19 21:58:29 +00:00
|
|
|
if ((uint8_t*)a->ptr >= bp && (uint8_t*)a->ptr < bp + sizeof(SECT_USER))
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2015-05-19 21:58:29 +00:00
|
|
|
offset = (intptr_t)((uint8_t*)a->ptr - bp); // offset from user data
|
2015-05-19 21:54:34 +00:00
|
|
|
a->ptr = (int *)-3;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MWRITE(a,sizeof(ANIM),1,fil);
|
|
|
|
|
|
|
|
if ((intptr_t)a->ptr == -2 || (intptr_t)a->ptr == -3)
|
|
|
|
{
|
|
|
|
MWRITE(&j, sizeof(j),1,fil);
|
|
|
|
MWRITE(&offset, sizeof(offset),1,fil);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
saveisshot |= SaveSymDataInfo(fil, a->ptr);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
saveisshot |= SaveSymCodeInfo(fil, a->callback);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
saveisshot |= SaveSymDataInfo(fil, a->callbackdata);
|
2020-01-05 17:49:19 +00:00
|
|
|
assert(!saveisshot);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
ndx = 0;
|
|
|
|
for (i = AnimCnt - 1, a = &tanim; i >= 0; i--)
|
|
|
|
{
|
|
|
|
// write header
|
|
|
|
MWRITE(&ndx,sizeof(ndx),1,fil);
|
|
|
|
|
|
|
|
memcpy(a,&Anim[i],sizeof(ANIM));
|
|
|
|
MWRITE(a,sizeof(ANIM),1,fil);
|
|
|
|
|
|
|
|
saveisshot |= SaveSymDataInfo(fil, a->ptr);
|
|
|
|
saveisshot |= SaveSymCodeInfo(fil, a->callback);
|
|
|
|
saveisshot |= SaveSymDataInfo(fil, a->callbackdata);
|
|
|
|
|
|
|
|
ndx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write trailer
|
|
|
|
ndx = -1;
|
|
|
|
MWRITE(&ndx,sizeof(ndx),1,fil);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
MWRITE(&NormalVisibility,sizeof(NormalVisibility),1,fil);
|
|
|
|
MWRITE(&MoveSkip2,sizeof(MoveSkip2),1,fil);
|
|
|
|
MWRITE(&MoveSkip4,sizeof(MoveSkip4),1,fil);
|
|
|
|
MWRITE(&MoveSkip8,sizeof(MoveSkip8),1,fil);
|
|
|
|
|
2020-05-01 12:11:08 +00:00
|
|
|
// SO interpolations
|
|
|
|
saveisshot |= so_writeinterpolations(fil);
|
|
|
|
assert(!saveisshot);
|
|
|
|
|
2015-05-19 21:54:34 +00:00
|
|
|
// mirror
|
|
|
|
MWRITE(mirror,sizeof(mirror),1,fil);
|
|
|
|
MWRITE(&mirrorcnt,sizeof(mirrorcnt),1,fil);
|
|
|
|
MWRITE(&mirrorinview,sizeof(mirrorinview),1,fil);
|
|
|
|
|
|
|
|
// queue
|
|
|
|
MWRITE(&StarQueueHead,sizeof(StarQueueHead),1,fil);
|
|
|
|
MWRITE(StarQueue,sizeof(StarQueue),1,fil);
|
|
|
|
MWRITE(&HoleQueueHead,sizeof(HoleQueueHead),1,fil);
|
|
|
|
MWRITE(HoleQueue,sizeof(HoleQueue),1,fil);
|
|
|
|
MWRITE(&WallBloodQueueHead,sizeof(WallBloodQueueHead),1,fil);
|
|
|
|
MWRITE(WallBloodQueue,sizeof(WallBloodQueue),1,fil);
|
|
|
|
MWRITE(&FloorBloodQueueHead,sizeof(FloorBloodQueueHead),1,fil);
|
|
|
|
MWRITE(FloorBloodQueue,sizeof(FloorBloodQueue),1,fil);
|
|
|
|
MWRITE(&GenericQueueHead,sizeof(GenericQueueHead),1,fil);
|
|
|
|
MWRITE(GenericQueue,sizeof(GenericQueue),1,fil);
|
|
|
|
MWRITE(&LoWangsQueueHead,sizeof(LoWangsQueueHead),1,fil);
|
|
|
|
MWRITE(LoWangsQueue,sizeof(LoWangsQueue),1,fil);
|
|
|
|
|
|
|
|
MWRITE(&PlayClock,sizeof(PlayClock),1,fil);
|
|
|
|
MWRITE(&TotalKillable,sizeof(TotalKillable),1,fil);
|
|
|
|
|
|
|
|
// game settings
|
|
|
|
MWRITE(&gNet,sizeof(gNet),1,fil);
|
|
|
|
|
|
|
|
MWRITE(&gs,sizeof(gs),1,fil);
|
|
|
|
|
|
|
|
MWRITE(&LevelSecrets,sizeof(LevelSecrets),1,fil);
|
|
|
|
|
|
|
|
MWRITE(&Bunny_Count,sizeof(Bunny_Count),1,fil);
|
|
|
|
|
|
|
|
MWRITE(&GodMode,sizeof(GodMode),1,fil);
|
|
|
|
|
2020-07-13 20:20:14 +00:00
|
|
|
MWRITE(&FinishTimer,sizeof(FinishTimer),1,fil);
|
|
|
|
MWRITE(&FinishAnim,sizeof(FinishAnim),1,fil);
|
|
|
|
|
2015-05-19 21:54:34 +00:00
|
|
|
MWRITE(&serpwasseen, sizeof(serpwasseen), 1, fil);
|
|
|
|
MWRITE(&sumowasseen, sizeof(sumowasseen), 1, fil);
|
|
|
|
MWRITE(&zillawasseen, sizeof(zillawasseen), 1, fil);
|
|
|
|
MWRITE(BossSpriteNum, sizeof(BossSpriteNum), 1, fil);
|
|
|
|
//MWRITE(&Zombies, sizeof(Zombies), 1, fil);
|
|
|
|
|
2020-07-21 19:32:38 +00:00
|
|
|
return !saveisshot;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-07 16:32:57 +00:00
|
|
|
bool GameInterface::LoadGame()
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2015-05-19 22:09:25 +00:00
|
|
|
MFILE_READ fil;
|
2015-05-19 21:54:34 +00:00
|
|
|
int i,j,saveisshot=0;
|
|
|
|
short ndx,SpriteNum,sectnum;
|
|
|
|
PLAYERp pp = NULL;
|
|
|
|
USERp u;
|
|
|
|
SECTOR_OBJECTp sop;
|
|
|
|
SECT_USERp sectu;
|
|
|
|
ANIMp a;
|
2020-03-06 15:49:49 +00:00
|
|
|
PANEL_SPRITEp psp,next;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2019-12-02 23:01:04 +00:00
|
|
|
|
2015-05-19 21:54:34 +00:00
|
|
|
Saveable_Init();
|
|
|
|
|
2019-11-27 18:31:58 +00:00
|
|
|
auto filr = ReadSavegameChunk("snapshot.sw");
|
2019-12-02 23:01:04 +00:00
|
|
|
if (!filr.isOpen()) return false;
|
2019-11-27 18:31:58 +00:00
|
|
|
fil = &filr;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
MREAD(&Skill,sizeof(Skill),1,fil);
|
|
|
|
|
|
|
|
MREAD(&numplayers, sizeof(numplayers),1,fil);
|
|
|
|
|
|
|
|
//save players
|
|
|
|
//MREAD(Player,sizeof(PLAYER), numplayers,fil);
|
|
|
|
|
|
|
|
//save players info
|
2020-08-23 19:24:31 +00:00
|
|
|
|
|
|
|
for (auto& pp : Player)
|
|
|
|
{
|
|
|
|
pp.cookieTime = 0;
|
|
|
|
memset(pp.cookieQuote, 0, sizeof(pp.cookieQuote));
|
|
|
|
}
|
|
|
|
|
2015-05-19 21:54:34 +00:00
|
|
|
for (i = 0; i < numplayers; i++)
|
|
|
|
{
|
|
|
|
pp = &Player[i];
|
|
|
|
|
|
|
|
MREAD(pp, sizeof(*pp), 1, fil);
|
|
|
|
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->remote_sprite);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->remote.sop_control);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->sop_remote);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->sop);
|
|
|
|
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->hi_sectp);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->lo_sectp);
|
|
|
|
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->hi_sp);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->lo_sp);
|
|
|
|
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->last_camera_sp);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->SpriteP);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->UnderSpriteP);
|
|
|
|
saveisshot |= LoadSymCodeInfo(fil, (void **)&pp->DoPlayerAction);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->sop_control);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&pp->sop_riding);
|
2019-12-02 23:01:04 +00:00
|
|
|
if (saveisshot) { MCLOSE_READ(fil); return false; }
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if PANEL_SAVE
|
|
|
|
for (i = 0; i < numplayers; i++)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
pp = &Player[i];
|
|
|
|
|
|
|
|
INITLIST(&pp->PanelSpriteList);
|
|
|
|
|
2020-09-09 17:52:52 +00:00
|
|
|
while (true)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
MREAD(&ndx, sizeof(ndx),1,fil);
|
|
|
|
|
|
|
|
if (ndx == -1)
|
|
|
|
break;
|
|
|
|
|
2019-04-08 06:25:59 +00:00
|
|
|
psp = (PANEL_SPRITEp)CallocMem(sizeof(PANEL_SPRITE), 1);
|
2015-05-19 21:54:34 +00:00
|
|
|
ASSERT(psp);
|
|
|
|
|
|
|
|
MREAD(psp, sizeof(PANEL_SPRITE),1,fil);
|
|
|
|
INSERT_TAIL(&pp->PanelSpriteList,psp);
|
|
|
|
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&psp->PlayerP);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&psp->State);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&psp->RetractState);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&psp->PresentState);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&psp->ActionState);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&psp->RestState);
|
|
|
|
saveisshot |= LoadSymCodeInfo(fil, (void **)&psp->PanelSpriteFunc);
|
2019-12-02 23:01:04 +00:00
|
|
|
if (saveisshot) { MCLOSE_READ(fil); return false; }
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
for (j = 0; j < (int)SIZ(psp->over); j++)
|
|
|
|
{
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&psp->over[j].State);
|
2019-12-02 23:01:04 +00:00
|
|
|
if (saveisshot) { MCLOSE_READ(fil); return false; }
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//Sector User information
|
|
|
|
for (i = 0; i < numsectors; i++)
|
|
|
|
{
|
|
|
|
MREAD(§num,sizeof(sectnum),1,fil);
|
|
|
|
if (sectnum != -1)
|
|
|
|
{
|
|
|
|
SectUser[sectnum] = sectu = (SECT_USERp)CallocMem(sizeof(SECT_USER), 1);
|
|
|
|
MREAD(sectu,sizeof(SECT_USER),1,fil);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MREAD(SectorObject, sizeof(SectorObject),1,fil);
|
|
|
|
|
|
|
|
for (ndx = 0; ndx < (short)SIZ(SectorObject); ndx++)
|
|
|
|
{
|
|
|
|
sop = &SectorObject[ndx];
|
|
|
|
|
|
|
|
saveisshot |= LoadSymCodeInfo(fil, (void **)&sop->PreMoveAnimator);
|
|
|
|
saveisshot |= LoadSymCodeInfo(fil, (void **)&sop->PostMoveAnimator);
|
|
|
|
saveisshot |= LoadSymCodeInfo(fil, (void **)&sop->Animator);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&sop->controller);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&sop->sp_child);
|
2019-12-02 23:01:04 +00:00
|
|
|
if (saveisshot) { MCLOSE_READ(fil); return false; }
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MREAD(SineWaveFloor, sizeof(SineWaveFloor),1,fil);
|
|
|
|
MREAD(SineWall, sizeof(SineWall),1,fil);
|
|
|
|
MREAD(SpringBoard, sizeof(SpringBoard),1,fil);
|
|
|
|
|
|
|
|
MREAD(Track, sizeof(Track),1,fil);
|
|
|
|
for (i = 0; i < MAX_TRACKS; i++)
|
|
|
|
{
|
|
|
|
if (Track[i].NumPoints == 0)
|
|
|
|
{
|
|
|
|
Track[i].TrackPoint = (TRACK_POINTp)CallocMem(sizeof(TRACK_POINT), 1);
|
|
|
|
MREAD(Track[i].TrackPoint, sizeof(TRACK_POINT),1,fil);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Track[i].TrackPoint = (TRACK_POINTp)CallocMem(Track[i].NumPoints * sizeof(TRACK_POINT), 1);
|
|
|
|
MREAD(Track[i].TrackPoint, Track[i].NumPoints * sizeof(TRACK_POINT),1,fil);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-12 12:31:32 +00:00
|
|
|
MREAD(&Player[myconnectindex].input,sizeof(Player[myconnectindex].input),1,fil);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
MREAD(&screenpeek,sizeof(screenpeek),1,fil);
|
2020-09-02 18:56:09 +00:00
|
|
|
MREAD(&randomseed, sizeof(randomseed), 1, fil);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
// do all sector manipulation structures
|
|
|
|
|
|
|
|
#if ANIM_SAVE
|
|
|
|
#if 1
|
|
|
|
MREAD(&AnimCnt,sizeof(AnimCnt),1,fil);
|
|
|
|
|
|
|
|
for (i = 0; i < AnimCnt; i++)
|
|
|
|
{
|
|
|
|
a = &Anim[i];
|
|
|
|
MREAD(a,sizeof(ANIM),1,fil);
|
|
|
|
|
|
|
|
if ((intptr_t)a->ptr == -2)
|
|
|
|
{
|
|
|
|
// maintain compatibility with sinking boat which points to user data
|
|
|
|
int offset;
|
|
|
|
MREAD(&j, sizeof(j),1,fil);
|
|
|
|
MREAD(&offset, sizeof(offset),1,fil);
|
2021-04-02 09:13:33 +00:00
|
|
|
a->ptr = (int *)(((char *)User[j].Data()) + offset);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
else if ((intptr_t)a->ptr == -3)
|
|
|
|
{
|
|
|
|
// maintain compatibility with sinking boat which points to user data
|
|
|
|
int offset;
|
|
|
|
MREAD(&j, sizeof(j),1,fil);
|
|
|
|
MREAD(&offset, sizeof(offset),1,fil);
|
|
|
|
a->ptr = (int *)(((char *)SectUser[j]) + offset);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&a->ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
saveisshot |= LoadSymCodeInfo(fil, (void **)&a->callback);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&a->callbackdata);
|
2019-12-02 23:01:04 +00:00
|
|
|
if (saveisshot) { MCLOSE_READ(fil); return false; }
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
AnimCnt = 0;
|
|
|
|
for (i = MAXANIM - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
a = &Anim[i];
|
|
|
|
|
|
|
|
MREAD(&ndx,sizeof(ndx),1,fil);
|
|
|
|
|
|
|
|
if (ndx == -1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
AnimCnt++;
|
|
|
|
|
|
|
|
MREAD(a,sizeof(ANIM),1,fil);
|
|
|
|
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&a->ptr);
|
|
|
|
saveisshot |= LoadSymCodeInfo(fil, (void **)&a->callback);
|
|
|
|
saveisshot |= LoadSymDataInfo(fil, (void **)&a->callbackdata);
|
2019-12-02 23:01:04 +00:00
|
|
|
if (saveisshot) { MCLOSE_READ(fil); return false; }
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
MREAD(&NormalVisibility,sizeof(NormalVisibility),1,fil);
|
|
|
|
|
|
|
|
MREAD(&MoveSkip2,sizeof(MoveSkip2),1,fil);
|
|
|
|
MREAD(&MoveSkip4,sizeof(MoveSkip4),1,fil);
|
|
|
|
MREAD(&MoveSkip8,sizeof(MoveSkip8),1,fil);
|
|
|
|
|
2020-05-01 12:11:08 +00:00
|
|
|
// SO interpolations
|
|
|
|
saveisshot |= so_readinterpolations(fil);
|
2020-05-21 14:25:41 +00:00
|
|
|
if (saveisshot) { MCLOSE_READ(fil); return false; }
|
2020-05-01 12:11:08 +00:00
|
|
|
|
2015-05-19 21:54:34 +00:00
|
|
|
// mirror
|
|
|
|
MREAD(mirror,sizeof(mirror),1,fil);
|
|
|
|
MREAD(&mirrorcnt,sizeof(mirrorcnt),1,fil);
|
|
|
|
MREAD(&mirrorinview,sizeof(mirrorinview),1,fil);
|
|
|
|
|
|
|
|
// queue
|
|
|
|
MREAD(&StarQueueHead,sizeof(StarQueueHead),1,fil);
|
|
|
|
MREAD(StarQueue,sizeof(StarQueue),1,fil);
|
|
|
|
MREAD(&HoleQueueHead,sizeof(HoleQueueHead),1,fil);
|
|
|
|
MREAD(HoleQueue,sizeof(HoleQueue),1,fil);
|
|
|
|
MREAD(&WallBloodQueueHead,sizeof(WallBloodQueueHead),1,fil);
|
|
|
|
MREAD(WallBloodQueue,sizeof(WallBloodQueue),1,fil);
|
|
|
|
MREAD(&FloorBloodQueueHead,sizeof(FloorBloodQueueHead),1,fil);
|
|
|
|
MREAD(FloorBloodQueue,sizeof(FloorBloodQueue),1,fil);
|
|
|
|
MREAD(&GenericQueueHead,sizeof(GenericQueueHead),1,fil);
|
|
|
|
MREAD(GenericQueue,sizeof(GenericQueue),1,fil);
|
|
|
|
MREAD(&LoWangsQueueHead,sizeof(LoWangsQueueHead),1,fil);
|
|
|
|
MREAD(LoWangsQueue,sizeof(LoWangsQueue),1,fil);
|
|
|
|
|
|
|
|
// init timing vars before PlayClock is read
|
|
|
|
MREAD(&PlayClock,sizeof(PlayClock),1,fil);
|
|
|
|
MREAD(&TotalKillable,sizeof(TotalKillable),1,fil);
|
|
|
|
|
|
|
|
// game settings
|
|
|
|
MREAD(&gNet,sizeof(gNet),1,fil);
|
|
|
|
|
2019-10-22 00:01:05 +00:00
|
|
|
MREAD(&gs,sizeof(gs),1,fil);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
MREAD(&LevelSecrets,sizeof(LevelSecrets),1,fil);
|
|
|
|
|
|
|
|
MREAD(&Bunny_Count,sizeof(Bunny_Count),1,fil);
|
|
|
|
|
|
|
|
MREAD(&GodMode,sizeof(GodMode),1,fil);
|
|
|
|
|
2020-07-13 20:20:14 +00:00
|
|
|
MREAD(&FinishTimer,sizeof(FinishTimer),1,fil);
|
|
|
|
MREAD(&FinishAnim,sizeof(FinishAnim),1,fil);
|
|
|
|
|
2015-05-19 21:54:34 +00:00
|
|
|
MREAD(&serpwasseen, sizeof(serpwasseen), 1, fil);
|
|
|
|
MREAD(&sumowasseen, sizeof(sumowasseen), 1, fil);
|
|
|
|
MREAD(&zillawasseen, sizeof(zillawasseen), 1, fil);
|
|
|
|
MREAD(BossSpriteNum, sizeof(BossSpriteNum), 1, fil);
|
|
|
|
//MREAD(&Zombies, sizeof(Zombies), 1, fil);
|
|
|
|
|
2015-05-19 22:09:25 +00:00
|
|
|
MCLOSE_READ(fil);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
//!!IMPORTANT - this POST stuff will not work here now becaus it does actual reads
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// POST processing of info MREAD in
|
|
|
|
//
|
|
|
|
|
|
|
|
#if PANEL_SAVE
|
|
|
|
for (i = 0; i < numplayers; i++)
|
|
|
|
{
|
|
|
|
pp = &Player[i];
|
|
|
|
TRAVERSE(&pp->PanelSpriteList, psp, next)
|
|
|
|
{
|
|
|
|
// dont need to set Next and Prev this was done
|
|
|
|
// when sprites were inserted
|
|
|
|
|
|
|
|
// sibling is the only PanelSprite (malloced ptr) in the PanelSprite struct
|
|
|
|
psp->sibling = PanelNdxToSprite(pp, (int)(intptr_t)psp->sibling);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-09-16 17:28:51 +00:00
|
|
|
DoTheCache();
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
// this is ok - just duplicating sector list with pointers
|
|
|
|
for (sop = SectorObject; sop < &SectorObject[SIZ(SectorObject)]; sop++)
|
|
|
|
{
|
|
|
|
for (i = 0; i < sop->num_sectors; i++)
|
|
|
|
sop->sectp[i] = §or[sop->sector[i]];
|
|
|
|
}
|
|
|
|
|
|
|
|
//!!Again this will not work here
|
|
|
|
//restore players info
|
|
|
|
for (i = 0; i < numplayers; i++)
|
|
|
|
{
|
|
|
|
#if PANEL_SAVE
|
|
|
|
pp->CurWpn = PanelNdxToSprite(pp, (int)(intptr_t)pp->CurWpn);
|
|
|
|
|
|
|
|
for (ndx = 0; ndx < MAX_WEAPONS; ndx++)
|
|
|
|
pp->Wpn[ndx] = PanelNdxToSprite(pp, (int)(intptr_t)pp->Wpn[ndx]);
|
|
|
|
|
|
|
|
pp->Chops = PanelNdxToSprite(pp, (int)(intptr_t)pp->Chops);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
int SavePlayClock = PlayClock;
|
|
|
|
InitTimingVars();
|
|
|
|
PlayClock = SavePlayClock;
|
|
|
|
}
|
|
|
|
InitNetVars();
|
|
|
|
|
|
|
|
screenpeek = myconnectindex;
|
|
|
|
|
2019-12-26 12:04:29 +00:00
|
|
|
Mus_ResumeSaved();
|
2019-10-22 00:01:05 +00:00
|
|
|
if (snd_ambience)
|
2015-05-19 21:54:34 +00:00
|
|
|
StartAmbientSound();
|
|
|
|
|
|
|
|
TRAVERSE_CONNECT(i)
|
|
|
|
{
|
|
|
|
Player[i].StartColor = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// this is not a new game
|
2020-09-09 17:52:52 +00:00
|
|
|
ShadowWarrior::NewGame = false;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
DoPlayerDivePalette(Player+myconnectindex);
|
|
|
|
DoPlayerNightVisionPalette(Player+myconnectindex);
|
|
|
|
|
2020-09-17 22:33:18 +00:00
|
|
|
InitLevelGlobals();
|
2019-12-02 23:01:04 +00:00
|
|
|
return true;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
2019-10-09 16:09:05 +00:00
|
|
|
END_SW_NS
|