2006-04-13 20:47:06 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
2010-05-25 10:56:00 +00:00
|
|
|
Copyright (C) 2010 EDuke32 developers and contributors
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2010-05-25 10:56:00 +00:00
|
|
|
This file is part of EDuke32.
|
2006-04-13 20:47:06 +00:00
|
|
|
|
|
|
|
EDuke32 is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License version 2
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
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
|
2014-07-20 08:55:56 +00:00
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2006-04-13 20:47:06 +00:00
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
2019-09-21 18:59:54 +00:00
|
|
|
#include "ns.h" // Must come before everything else!
|
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
#include "duke3d.h"
|
2010-08-02 08:13:51 +00:00
|
|
|
#include "premap.h"
|
2010-06-23 04:20:46 +00:00
|
|
|
#include "prlights.h"
|
2011-07-29 22:07:49 +00:00
|
|
|
#include "savegame.h"
|
2020-02-23 08:55:49 +00:00
|
|
|
//#include "sjson.h"
|
2019-11-01 23:38:30 +00:00
|
|
|
#include "i_specialpaths.h"
|
|
|
|
#include "gamecontrol.h"
|
2019-11-05 19:48:34 +00:00
|
|
|
#include "version.h"
|
2019-11-14 20:07:43 +00:00
|
|
|
#include "savegamehelp.h"
|
2019-11-23 22:05:24 +00:00
|
|
|
#include "menu/menu.h"
|
2019-12-09 23:01:45 +00:00
|
|
|
#include "mapinfo.h"
|
2019-11-28 02:18:58 +00:00
|
|
|
#include "z_music.h"
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2019-09-21 20:53:00 +00:00
|
|
|
BEGIN_DUKE_NS
|
|
|
|
|
2011-07-29 22:07:49 +00:00
|
|
|
// For storing pointers in files.
|
|
|
|
// back_p==0: ptr -> "small int"
|
|
|
|
// back_p==1: "small int" -> ptr
|
|
|
|
//
|
|
|
|
// mode: see enum in savegame.h
|
2015-03-24 00:40:12 +00:00
|
|
|
void G_Util_PtrToIdx(void *ptr, int32_t const count, const void *base, int32_t const mode)
|
2011-07-29 22:07:49 +00:00
|
|
|
{
|
2012-11-15 14:28:36 +00:00
|
|
|
intptr_t *iptr = (intptr_t *)ptr;
|
2015-02-11 05:22:23 +00:00
|
|
|
intptr_t const ibase = (intptr_t)base;
|
|
|
|
int32_t const onlynon0_p = mode&P2I_ONLYNON0_BIT;
|
2011-07-29 22:07:49 +00:00
|
|
|
|
|
|
|
// TODO: convert to proper offsets/indices for (a step towards) cross-
|
|
|
|
// compatibility between 32- and 64-bit systems in the netplay.
|
|
|
|
// REMEMBER to bump BYTEVERSION then.
|
|
|
|
|
2015-02-11 05:22:23 +00:00
|
|
|
// WARNING: C std doesn't say that bit pattern of NULL is necessarily 0!
|
|
|
|
if ((mode & P2I_BACK_BIT) == 0)
|
|
|
|
{
|
2016-08-27 01:41:21 +00:00
|
|
|
for (bssize_t i = 0; i < count; i++)
|
2015-02-11 05:22:23 +00:00
|
|
|
if (!onlynon0_p || iptr[i])
|
2011-07-29 22:07:49 +00:00
|
|
|
iptr[i] -= ibase;
|
2015-02-11 05:22:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-08-27 01:41:21 +00:00
|
|
|
for (bssize_t i = 0; i < count; i++)
|
2015-02-11 05:22:23 +00:00
|
|
|
if (!onlynon0_p || iptr[i])
|
2011-07-29 22:07:49 +00:00
|
|
|
iptr[i] += ibase;
|
2015-02-11 05:22:23 +00:00
|
|
|
}
|
2011-07-29 22:07:49 +00:00
|
|
|
}
|
|
|
|
|
2015-03-24 00:40:12 +00:00
|
|
|
void G_Util_PtrToIdx2(void *ptr, int32_t const count, size_t const stride, const void *base, int32_t const mode)
|
2012-10-30 15:54:35 +00:00
|
|
|
{
|
2012-11-11 17:57:01 +00:00
|
|
|
uint8_t *iptr = (uint8_t *)ptr;
|
2015-02-11 05:22:23 +00:00
|
|
|
intptr_t const ibase = (intptr_t)base;
|
|
|
|
int32_t const onlynon0_p = mode&P2I_ONLYNON0_BIT;
|
2012-10-30 15:54:35 +00:00
|
|
|
|
2015-02-11 05:22:23 +00:00
|
|
|
if ((mode & P2I_BACK_BIT) == 0)
|
2012-10-30 15:54:35 +00:00
|
|
|
{
|
2016-08-27 01:41:21 +00:00
|
|
|
for (bssize_t i = 0; i < count; ++i)
|
2012-10-30 15:54:35 +00:00
|
|
|
{
|
2015-02-11 05:22:23 +00:00
|
|
|
if (!onlynon0_p || *(intptr_t *)iptr)
|
2012-10-30 15:54:35 +00:00
|
|
|
*(intptr_t *)iptr -= ibase;
|
2015-02-11 05:22:23 +00:00
|
|
|
|
|
|
|
iptr += stride;
|
2012-10-30 15:54:35 +00:00
|
|
|
}
|
2015-02-11 05:22:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-08-27 01:41:21 +00:00
|
|
|
for (bssize_t i = 0; i < count; ++i)
|
2015-02-11 05:22:23 +00:00
|
|
|
{
|
|
|
|
if (!onlynon0_p || *(intptr_t *)iptr)
|
|
|
|
*(intptr_t *)iptr += ibase;
|
2012-10-30 15:54:35 +00:00
|
|
|
|
2015-02-11 05:22:23 +00:00
|
|
|
iptr += stride;
|
|
|
|
}
|
2012-10-30 15:54:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-29 22:07:28 +00:00
|
|
|
// TODO: sync with TROR special interpolations? (e.g. upper floor of subway)
|
|
|
|
void G_ResetInterpolations(void)
|
|
|
|
{
|
|
|
|
int32_t k, i;
|
|
|
|
|
2016-08-27 01:42:01 +00:00
|
|
|
g_interpolationCnt = 0;
|
2011-07-29 22:07:28 +00:00
|
|
|
|
|
|
|
k = headspritestat[STAT_EFFECTOR];
|
|
|
|
while (k >= 0)
|
|
|
|
{
|
|
|
|
switch (sprite[k].lotag)
|
|
|
|
{
|
2012-08-26 22:16:08 +00:00
|
|
|
case SE_31_FLOOR_RISE_FALL:
|
2011-07-29 22:07:28 +00:00
|
|
|
G_SetInterpolation(§or[sprite[k].sectnum].floorz);
|
|
|
|
break;
|
2012-08-26 22:16:08 +00:00
|
|
|
case SE_32_CEILING_RISE_FALL:
|
2011-07-29 22:07:28 +00:00
|
|
|
G_SetInterpolation(§or[sprite[k].sectnum].ceilingz);
|
|
|
|
break;
|
2012-08-26 22:16:08 +00:00
|
|
|
case SE_17_WARP_ELEVATOR:
|
|
|
|
case SE_25_PISTON:
|
2011-07-29 22:07:28 +00:00
|
|
|
G_SetInterpolation(§or[sprite[k].sectnum].floorz);
|
|
|
|
G_SetInterpolation(§or[sprite[k].sectnum].ceilingz);
|
|
|
|
break;
|
2012-09-08 22:18:44 +00:00
|
|
|
case SE_0_ROTATING_SECTOR:
|
|
|
|
case SE_5:
|
|
|
|
case SE_6_SUBWAY:
|
|
|
|
case SE_11_SWINGING_DOOR:
|
|
|
|
case SE_14_SUBWAY_CAR:
|
|
|
|
case SE_15_SLIDING_DOOR:
|
2012-08-26 22:16:08 +00:00
|
|
|
case SE_16_REACTOR:
|
|
|
|
case SE_26:
|
|
|
|
case SE_30_TWO_WAY_TRAIN:
|
2011-07-29 22:07:28 +00:00
|
|
|
Sect_SetInterpolation(sprite[k].sectnum);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
k = nextspritestat[k];
|
|
|
|
}
|
|
|
|
|
2016-08-27 01:42:01 +00:00
|
|
|
for (i=g_interpolationCnt-1; i>=0; i--) bakipos[i] = *curipos[i];
|
|
|
|
for (i = g_animateCnt-1; i>=0; i--)
|
|
|
|
G_SetInterpolation(g_animatePtr[i]);
|
2011-07-29 22:07:28 +00:00
|
|
|
}
|
|
|
|
|
2019-11-30 18:23:54 +00:00
|
|
|
int32_t g_fakeSaveID = -1;
|
2017-12-18 11:24:53 +00:00
|
|
|
bool g_saveRequested;
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2018-03-08 03:55:21 +00:00
|
|
|
|
2020-01-21 20:51:05 +00:00
|
|
|
static FileReader *OpenSavegame()
|
2019-11-08 00:36:32 +00:00
|
|
|
{
|
2019-12-10 21:22:59 +00:00
|
|
|
auto file = ReadSavegameChunk("snapshot.dat");
|
2019-11-14 20:07:43 +00:00
|
|
|
if (!file.isOpen())
|
2019-11-08 00:36:32 +00:00
|
|
|
{
|
2019-11-14 20:07:43 +00:00
|
|
|
FinishSavegameRead();
|
|
|
|
return nullptr;
|
2019-11-08 00:36:32 +00:00
|
|
|
}
|
2019-11-14 20:07:43 +00:00
|
|
|
return new FileReader(std::move(file));
|
2019-11-08 00:36:32 +00:00
|
|
|
}
|
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
static void sv_postudload();
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2013-05-19 19:29:18 +00:00
|
|
|
// XXX: keyboard input 'blocked' after load fail? (at least ESC?)
|
2019-11-30 18:23:54 +00:00
|
|
|
int32_t G_LoadPlayer(FSaveGameNode *sv)
|
2011-12-25 15:34:06 +00:00
|
|
|
{
|
2019-12-09 23:31:55 +00:00
|
|
|
char workbuffer[BMAX_PATH];
|
|
|
|
|
2020-02-23 08:55:49 +00:00
|
|
|
#if 0
|
2019-11-30 18:23:54 +00:00
|
|
|
if (sv->bIsExt)
|
2019-07-31 03:39:30 +00:00
|
|
|
{
|
2019-08-07 22:36:16 +00:00
|
|
|
int volume = -1;
|
|
|
|
int level = -1;
|
|
|
|
int skill = -1;
|
|
|
|
|
2020-01-21 20:51:05 +00:00
|
|
|
auto fil = OpenSavegame();
|
2019-11-14 20:07:43 +00:00
|
|
|
if (!fil) return -1;
|
2019-08-07 22:36:16 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
savehead_t h;
|
2019-11-14 20:07:43 +00:00
|
|
|
int status = sv_loadheader(*fil, 0, &h);
|
2019-08-07 22:36:16 +00:00
|
|
|
if (status >= 0)
|
|
|
|
{
|
|
|
|
volume = h.volnum;
|
|
|
|
level = h.levnum;
|
|
|
|
skill = h.skill;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-14 20:07:43 +00:00
|
|
|
auto extfil = ReadSavegameChunk("ext.json");
|
2019-10-20 21:37:07 +00:00
|
|
|
if (!extfil.isOpen())
|
2019-07-31 03:39:30 +00:00
|
|
|
{
|
2019-11-14 20:07:43 +00:00
|
|
|
delete fil;
|
|
|
|
FinishSavegameRead();
|
2019-07-31 03:39:30 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-10-20 21:37:07 +00:00
|
|
|
auto text = extfil.ReadPadded(1);
|
2019-11-14 20:07:43 +00:00
|
|
|
extfil.Close();
|
2019-07-31 03:39:30 +00:00
|
|
|
|
2019-10-20 21:37:07 +00:00
|
|
|
if (text.Size() == 0)
|
2019-07-31 03:39:30 +00:00
|
|
|
{
|
2019-11-14 20:07:43 +00:00
|
|
|
delete fil;
|
|
|
|
FinishSavegameRead();
|
|
|
|
return -1;
|
2019-07-31 03:39:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sjson_context * ctx = sjson_create_context(0, 0, NULL);
|
2019-10-20 21:37:07 +00:00
|
|
|
sjson_node * root = sjson_decode(ctx, (const char *)text.Data());
|
2019-07-31 03:39:30 +00:00
|
|
|
|
2019-08-07 22:36:16 +00:00
|
|
|
if (volume == -1)
|
|
|
|
volume = sjson_get_int(root, "volume", volume);
|
|
|
|
if (level == -1)
|
|
|
|
level = sjson_get_int(root, "level", level);
|
|
|
|
if (skill == -1)
|
|
|
|
skill = sjson_get_int(root, "skill", skill);
|
2019-07-31 03:39:30 +00:00
|
|
|
|
|
|
|
if (volume == -1 || level == -1 || skill == -1)
|
|
|
|
{
|
|
|
|
sjson_destroy_context(ctx);
|
2019-11-14 20:07:43 +00:00
|
|
|
delete fil;
|
|
|
|
FinishSavegameRead();
|
|
|
|
return -1;
|
2019-07-31 03:39:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sjson_node * players = sjson_find_member(root, "players");
|
|
|
|
|
|
|
|
int numplayers = sjson_child_count(players);
|
|
|
|
|
|
|
|
if (numplayers != ud.multimode)
|
|
|
|
{
|
|
|
|
P_DoQuote(QUOTE_SAVE_BAD_PLAYERS, g_player[myconnectindex].ps);
|
|
|
|
|
|
|
|
sjson_destroy_context(ctx);
|
2019-11-14 20:07:43 +00:00
|
|
|
delete fil;
|
|
|
|
FinishSavegameRead();
|
|
|
|
return 1;
|
2019-07-31 03:39:30 +00:00
|
|
|
}
|
|
|
|
|
2019-08-07 22:36:16 +00:00
|
|
|
|
|
|
|
ud.returnvar[0] = level;
|
|
|
|
volume = VM_OnEventWithReturn(EVENT_VALIDATESTART, g_player[myconnectindex].ps->i, myconnectindex, volume);
|
|
|
|
level = ud.returnvar[0];
|
|
|
|
|
|
|
|
|
2019-07-31 03:39:30 +00:00
|
|
|
{
|
|
|
|
// CODEDUP from non-isExt branch, with simplifying assumptions
|
|
|
|
|
|
|
|
VM_OnEvent(EVENT_PRELOADGAME, g_player[screenpeek].ps->i, screenpeek);
|
|
|
|
|
|
|
|
ud.multimode = numplayers;
|
|
|
|
|
|
|
|
Net_WaitForServer();
|
|
|
|
|
|
|
|
FX_StopAllSounds();
|
|
|
|
S_ClearSoundLocks();
|
|
|
|
|
|
|
|
ud.m_volume_number = volume;
|
2019-11-09 18:15:03 +00:00
|
|
|
m_level_number = level;
|
2019-07-31 03:39:30 +00:00
|
|
|
ud.m_player_skill = skill;
|
|
|
|
|
|
|
|
boardfilename[0] = '\0';
|
|
|
|
|
|
|
|
int const mapIdx = volume*MAXLEVELS + level;
|
|
|
|
|
|
|
|
if (boardfilename[0])
|
2019-12-09 23:31:55 +00:00
|
|
|
strcpy(workbuffer, boardfilename);
|
2019-12-09 23:01:45 +00:00
|
|
|
else if (mapList[mapIdx].fileName.IsNotEmpty())
|
2019-12-09 23:31:55 +00:00
|
|
|
strcpy(workbuffer, mapList[mapIdx].fileName);
|
2019-07-31 03:39:30 +00:00
|
|
|
|
2019-10-19 23:43:26 +00:00
|
|
|
|
2019-12-09 23:31:55 +00:00
|
|
|
if (workbuffer[0])
|
2019-07-31 03:39:30 +00:00
|
|
|
{
|
2019-10-19 23:43:26 +00:00
|
|
|
// only setup art if map differs from previous
|
2019-12-09 23:31:55 +00:00
|
|
|
artSetupMapArt(workbuffer);
|
|
|
|
append_ext_UNSAFE(workbuffer, ".mhk");
|
|
|
|
engineLoadMHK(workbuffer);
|
2019-07-31 03:39:30 +00:00
|
|
|
}
|
|
|
|
// G_NewGame_EnterLevel();
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// CODEDUP from G_NewGame
|
|
|
|
|
|
|
|
auto & p0 = *g_player[0].ps;
|
|
|
|
|
|
|
|
ready2send = 0;
|
|
|
|
|
|
|
|
ud.from_bonus = 0;
|
|
|
|
ud.last_level = -1;
|
|
|
|
ud.level_number = level;
|
|
|
|
ud.player_skill = skill;
|
|
|
|
ud.secretlevel = 0;
|
|
|
|
ud.volume_number = volume;
|
|
|
|
|
|
|
|
#ifdef EDUKE32_TOUCH_DEVICES
|
|
|
|
p0.zoom = 360;
|
|
|
|
#else
|
|
|
|
p0.zoom = 768;
|
|
|
|
#endif
|
|
|
|
p0.gm = 0;
|
|
|
|
|
2019-11-23 22:05:24 +00:00
|
|
|
M_ClearMenus();
|
2019-07-31 03:39:30 +00:00
|
|
|
|
|
|
|
#if !defined LUNATIC
|
|
|
|
Gv_ResetVars();
|
|
|
|
Gv_InitWeaponPointers();
|
|
|
|
Gv_RefreshPointers();
|
|
|
|
#endif
|
|
|
|
Gv_ResetSystemDefaults();
|
|
|
|
|
|
|
|
for (int i=0; i < (MAXVOLUMES*MAXLEVELS); i++)
|
|
|
|
G_FreeMapState(i);
|
|
|
|
|
2019-11-09 18:15:03 +00:00
|
|
|
if (m_coop != 1)
|
2019-07-31 03:39:30 +00:00
|
|
|
p0.last_weapon = -1;
|
|
|
|
|
|
|
|
display_mirror = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int p = 0;
|
|
|
|
for (sjson_node * player = sjson_first_child(players); player != nullptr; player = player->next)
|
|
|
|
{
|
|
|
|
playerdata_t * playerData = &g_player[p];
|
|
|
|
DukePlayer_t * ps = playerData->ps;
|
|
|
|
auto pSprite = &sprite[ps->i];
|
|
|
|
|
|
|
|
pSprite->extra = sjson_get_int(player, "extra", -1);
|
|
|
|
ps->max_player_health = sjson_get_int(player, "max_player_health", -1);
|
|
|
|
|
|
|
|
sjson_node * gotweapon = sjson_find_member(player, "gotweapon");
|
|
|
|
int w_end = min<int>(MAX_WEAPONS, sjson_child_count(gotweapon));
|
|
|
|
ps->gotweapon = 0;
|
|
|
|
for (int w = 0; w < w_end; ++w)
|
|
|
|
{
|
|
|
|
sjson_node * ele = sjson_find_element(gotweapon, w);
|
|
|
|
if (ele->tag == SJSON_BOOL && ele->bool_)
|
|
|
|
ps->gotweapon |= 1<<w;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* bool flag_ammo_amount = */ sjson_get_int16s(ps->ammo_amount, MAX_WEAPONS, player, "ammo_amount");
|
|
|
|
/* bool flag_max_ammo_amount = */ sjson_get_int16s(ps->max_ammo_amount, MAX_WEAPONS, player, "max_ammo_amount");
|
|
|
|
/* bool flag_inv_amount = */ sjson_get_int16s(ps->inv_amount, GET_MAX, player, "inv_amount");
|
|
|
|
|
|
|
|
ps->max_shield_amount = sjson_get_int(player, "max_shield_amount", -1);
|
|
|
|
|
|
|
|
ps->curr_weapon = sjson_get_int(player, "curr_weapon", -1);
|
|
|
|
ps->subweapon = sjson_get_int(player, "subweapon", -1);
|
|
|
|
ps->inven_icon = sjson_get_int(player, "inven_icon", -1);
|
|
|
|
|
|
|
|
sjson_node * vars = sjson_find_member(player, "vars");
|
|
|
|
|
|
|
|
for (int j=0; j<g_gameVarCount; j++)
|
|
|
|
{
|
|
|
|
gamevar_t & var = aGameVars[j];
|
|
|
|
|
|
|
|
if (!(var.flags & GAMEVAR_SERIALIZE))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((var.flags & (GAMEVAR_PERPLAYER|GAMEVAR_PERACTOR)) != GAMEVAR_PERPLAYER)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Gv_SetVar(j, sjson_get_int(vars, var.szLabel, var.defaultValue), ps->i, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
sjson_node * vars = sjson_find_member(root, "vars");
|
|
|
|
|
|
|
|
for (int j=0; j<g_gameVarCount; j++)
|
|
|
|
{
|
|
|
|
gamevar_t & var = aGameVars[j];
|
|
|
|
|
|
|
|
if (!(var.flags & GAMEVAR_SERIALIZE))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (var.flags & (GAMEVAR_PERPLAYER|GAMEVAR_PERACTOR))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Gv_SetVar(j, sjson_get_int(vars, var.szLabel, var.defaultValue));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sjson_destroy_context(ctx);
|
|
|
|
|
|
|
|
|
|
|
|
if (G_EnterLevel(MODE_GAME|MODE_EOL))
|
|
|
|
G_BackToMenu();
|
|
|
|
|
|
|
|
|
|
|
|
// postloadplayer(1);
|
|
|
|
|
|
|
|
// sv_postudload();
|
|
|
|
|
|
|
|
|
|
|
|
VM_OnEvent(EVENT_LOADGAME, g_player[screenpeek].ps->i, screenpeek);
|
|
|
|
|
2019-11-14 20:07:43 +00:00
|
|
|
delete fil;
|
|
|
|
FinishSavegameRead();
|
|
|
|
return 0;
|
2019-07-31 03:39:30 +00:00
|
|
|
}
|
2020-02-23 08:55:49 +00:00
|
|
|
#endif
|
2019-07-31 03:39:30 +00:00
|
|
|
|
2020-01-21 20:51:05 +00:00
|
|
|
auto fil = OpenSavegame();
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2019-11-14 20:07:43 +00:00
|
|
|
if (!fil)
|
2011-12-25 15:34:06 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
ready2send = 0;
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
savehead_t h;
|
2019-11-14 20:07:43 +00:00
|
|
|
int status = sv_loadheader(*fil, 0, &h);
|
2018-10-25 23:31:45 +00:00
|
|
|
|
|
|
|
if (status < 0 || h.numplayers != ud.multimode)
|
2011-12-25 15:34:06 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
if (status == -4 || status == -3 || status == 1)
|
2011-12-25 15:34:06 +00:00
|
|
|
P_DoQuote(QUOTE_SAVE_BAD_VERSION, g_player[myconnectindex].ps);
|
2018-10-25 23:31:45 +00:00
|
|
|
else if (h.numplayers != ud.multimode)
|
2011-12-25 15:34:06 +00:00
|
|
|
P_DoQuote(QUOTE_SAVE_BAD_PLAYERS, g_player[myconnectindex].ps);
|
|
|
|
|
|
|
|
ototalclock = totalclock;
|
|
|
|
ready2send = 1;
|
|
|
|
|
2019-11-14 20:07:43 +00:00
|
|
|
delete fil;
|
|
|
|
FinishSavegameRead();
|
|
|
|
return 1;
|
2011-12-25 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
2017-12-02 09:24:55 +00:00
|
|
|
VM_OnEvent(EVENT_PRELOADGAME, g_player[screenpeek].ps->i, screenpeek);
|
2017-06-24 09:21:07 +00:00
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
// some setup first
|
|
|
|
ud.multimode = h.numplayers;
|
|
|
|
|
|
|
|
if (numplayers > 1)
|
|
|
|
{
|
|
|
|
pub = NUMPAGES;
|
|
|
|
pus = NUMPAGES;
|
|
|
|
G_UpdateScreenArea();
|
|
|
|
G_DrawBackground();
|
2017-06-19 23:07:18 +00:00
|
|
|
menutext_center(100, "Loading...");
|
2018-04-12 21:02:51 +00:00
|
|
|
videoNextPage();
|
2011-12-25 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Net_WaitForServer();
|
|
|
|
|
|
|
|
FX_StopAllSounds();
|
|
|
|
S_ClearSoundLocks();
|
|
|
|
|
|
|
|
// non-"m_" fields will be loaded from svgm_udnetw
|
|
|
|
ud.m_volume_number = h.volnum;
|
2019-11-09 18:15:03 +00:00
|
|
|
m_level_number = h.levnum;
|
2011-12-25 15:34:06 +00:00
|
|
|
ud.m_player_skill = h.skill;
|
|
|
|
|
2015-04-20 20:46:42 +00:00
|
|
|
// NOTE: Bmemcpy needed for SAVEGAME_MUSIC.
|
2019-12-11 00:10:59 +00:00
|
|
|
strcpy(boardfilename, currentLevel->fileName);
|
2014-09-07 18:10:15 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
int const mapIdx = h.volnum*MAXLEVELS + h.levnum;
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2019-12-09 23:31:55 +00:00
|
|
|
if (boardfilename[0])
|
|
|
|
strcpy(workbuffer, boardfilename);
|
|
|
|
else if (mapList[mapIdx].fileName.IsNotEmpty())
|
|
|
|
strcpy(workbuffer, mapList[mapIdx].fileName);
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2019-12-09 23:31:55 +00:00
|
|
|
|
|
|
|
if (workbuffer[0])
|
|
|
|
{
|
|
|
|
// only setup art if map differs from previous
|
|
|
|
artSetupMapArt(workbuffer);
|
|
|
|
append_ext_UNSAFE(workbuffer, ".mhk");
|
|
|
|
engineLoadMHK(workbuffer);
|
|
|
|
}
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2020-03-08 12:54:00 +00:00
|
|
|
if ((status = sv_loadsnapshot(*fil, 0, &h))) // read the rest...
|
2014-09-30 04:03:30 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
// in theory, we could load into an initial dump first and trivially
|
|
|
|
// recover if things go wrong...
|
2019-11-30 18:23:54 +00:00
|
|
|
Bsprintf(tempbuf, "Loading save game file \"%s\" failed (code %d), cannot recover.", sv->Filename.GetChars(), status);
|
2018-10-25 23:31:45 +00:00
|
|
|
G_GameExit(tempbuf);
|
2011-12-25 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
sv_postudload(); // ud.m_XXX = ud.XXX
|
2017-12-02 09:24:55 +00:00
|
|
|
VM_OnEvent(EVENT_LOADGAME, g_player[screenpeek].ps->i, screenpeek);
|
2017-12-17 02:03:55 +00:00
|
|
|
|
2019-11-14 20:07:43 +00:00
|
|
|
delete fil;
|
|
|
|
FinishSavegameRead();
|
|
|
|
return 0;
|
2011-12-25 15:34:06 +00:00
|
|
|
}
|
|
|
|
|
2014-04-19 22:42:21 +00:00
|
|
|
////////// TIMER SAVING/RESTORING //////////
|
|
|
|
|
|
|
|
static struct {
|
2020-01-29 11:35:51 +00:00
|
|
|
ClockTicks totalclock, totalclocklock; // engine
|
|
|
|
ClockTicks ototalclock, lockclock; // game
|
2014-04-19 22:42:21 +00:00
|
|
|
} g_timers;
|
|
|
|
|
|
|
|
static void G_SaveTimers(void)
|
|
|
|
{
|
2020-01-29 11:35:51 +00:00
|
|
|
g_timers.totalclock = totalclock;
|
|
|
|
g_timers.totalclocklock = totalclocklock;
|
|
|
|
g_timers.ototalclock = ototalclock;
|
|
|
|
g_timers.lockclock = lockclock;
|
2014-04-19 22:42:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void G_RestoreTimers(void)
|
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
totalclock = g_timers.totalclock;
|
2014-04-19 22:42:21 +00:00
|
|
|
totalclocklock = g_timers.totalclocklock;
|
2018-10-25 23:31:45 +00:00
|
|
|
ototalclock = g_timers.ototalclock;
|
|
|
|
lockclock = g_timers.lockclock;
|
2014-04-19 22:42:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2019-11-30 18:23:54 +00:00
|
|
|
bool G_SavePlayer(FSaveGameNode *sv)
|
2011-12-25 15:34:06 +00:00
|
|
|
{
|
2014-04-19 22:42:21 +00:00
|
|
|
G_SaveTimers();
|
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
Net_WaitForServer();
|
|
|
|
ready2send = 0;
|
|
|
|
|
2019-11-07 23:26:14 +00:00
|
|
|
FString fn;
|
|
|
|
|
|
|
|
errno = 0;
|
2019-11-08 01:02:54 +00:00
|
|
|
FileWriter *fil;
|
2019-11-07 23:26:14 +00:00
|
|
|
|
2019-11-30 18:23:54 +00:00
|
|
|
fil = WriteSavegameChunk("snapshot.dat");
|
|
|
|
// The above call cannot fail.
|
2019-11-07 23:26:14 +00:00
|
|
|
{
|
2019-11-14 20:07:43 +00:00
|
|
|
auto& fw = *fil;
|
2019-11-08 00:36:32 +00:00
|
|
|
|
2019-11-07 23:26:14 +00:00
|
|
|
// temporary hack
|
|
|
|
ud.user_map = G_HaveUserMap();
|
|
|
|
|
|
|
|
VM_OnEvent(EVENT_SAVEGAME, g_player[myconnectindex].ps->i, myconnectindex);
|
|
|
|
|
2020-02-23 08:55:49 +00:00
|
|
|
//portableBackupSave(sv->Filename, sv->SaveTitle, ud.last_stateless_volume, ud.last_stateless_level);
|
2019-11-07 23:26:14 +00:00
|
|
|
|
|
|
|
// SAVE!
|
2020-01-12 22:16:21 +00:00
|
|
|
sv_saveandmakesnapshot(fw, 0);
|
2019-11-26 23:41:26 +00:00
|
|
|
|
2019-11-07 23:26:14 +00:00
|
|
|
|
|
|
|
fw.Close();
|
2019-11-30 18:23:54 +00:00
|
|
|
bool res = FinishSavegameWrite();
|
2019-11-07 23:26:14 +00:00
|
|
|
|
|
|
|
if (!g_netServer && ud.multimode < 2)
|
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("Saved: %s\n", fn.GetChars());
|
2019-12-03 23:28:28 +00:00
|
|
|
quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Game Saved");
|
2019-11-07 23:26:14 +00:00
|
|
|
P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps);
|
|
|
|
}
|
|
|
|
|
|
|
|
ready2send = 1;
|
|
|
|
Net_WaitForServer();
|
|
|
|
|
|
|
|
G_RestoreTimers();
|
|
|
|
|
|
|
|
VM_OnEvent(EVENT_POSTSAVEGAME, g_player[myconnectindex].ps->i, myconnectindex);
|
|
|
|
|
2019-11-30 18:23:54 +00:00
|
|
|
return res;
|
2019-11-07 23:26:14 +00:00
|
|
|
}
|
2011-12-25 15:34:06 +00:00
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2019-11-30 18:23:54 +00:00
|
|
|
|
|
|
|
bool GameInterface::LoadGame(FSaveGameNode *sv)
|
2012-09-05 17:25:43 +00:00
|
|
|
{
|
|
|
|
if (g_netServer || ud.multimode > 1)
|
|
|
|
{
|
2019-12-03 23:28:28 +00:00
|
|
|
quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Multiplayer Loading Not Yet Supported");
|
2012-09-05 17:25:43 +00:00
|
|
|
P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps);
|
|
|
|
|
|
|
|
// g_player[myconnectindex].ps->gm = MODE_GAME;
|
2019-11-30 18:23:54 +00:00
|
|
|
return false;
|
2012-09-05 17:25:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-12-18 11:24:53 +00:00
|
|
|
int32_t c = G_LoadPlayer(sv);
|
2012-09-05 17:25:43 +00:00
|
|
|
if (c == 0)
|
|
|
|
g_player[myconnectindex].ps->gm = MODE_GAME;
|
2019-11-30 18:23:54 +00:00
|
|
|
return c == 0;
|
2012-09-05 17:25:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-30 18:23:54 +00:00
|
|
|
bool GameInterface::SaveGame(FSaveGameNode* sv)
|
2012-09-05 17:25:43 +00:00
|
|
|
{
|
|
|
|
if (g_netServer || ud.multimode > 1)
|
|
|
|
{
|
2019-12-03 23:28:28 +00:00
|
|
|
quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Multiplayer Saving Not Yet Supported");
|
2012-09-05 17:25:43 +00:00
|
|
|
P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps);
|
2019-11-30 18:23:54 +00:00
|
|
|
return false;
|
2012-09-05 17:25:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-11-30 18:23:54 +00:00
|
|
|
videoNextPage(); // no idea if this is needed here.
|
|
|
|
return G_SavePlayer(sv);
|
2012-09-05 17:25:43 +00:00
|
|
|
}
|
|
|
|
}
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
////////// GENERIC SAVING/LOADING SYSTEM //////////
|
|
|
|
|
|
|
|
typedef struct dataspec_
|
|
|
|
{
|
|
|
|
uint32_t flags;
|
2016-01-11 05:05:38 +00:00
|
|
|
void * const ptr;
|
2010-01-24 23:33:17 +00:00
|
|
|
uint32_t size;
|
|
|
|
intptr_t cnt;
|
|
|
|
} dataspec_t;
|
|
|
|
|
2016-01-11 05:05:38 +00:00
|
|
|
typedef struct dataspec_gv_
|
|
|
|
{
|
|
|
|
uint32_t flags;
|
|
|
|
void * ptr;
|
|
|
|
uint32_t size;
|
|
|
|
intptr_t cnt;
|
|
|
|
} dataspec_gv_t;
|
|
|
|
|
2010-01-24 23:33:17 +00:00
|
|
|
#define DS_DYNAMIC 1 // dereference .ptr one more time
|
|
|
|
#define DS_STRING 2
|
|
|
|
#define DS_CMP 4
|
|
|
|
// 8
|
|
|
|
#define DS_CNT(x) ((sizeof(x))<<3) // .cnt is pointer to...
|
|
|
|
#define DS_CNT16 16
|
|
|
|
#define DS_CNT32 32
|
|
|
|
#define DS_CNTMASK (8|DS_CNT16|DS_CNT32|64)
|
|
|
|
// 64
|
|
|
|
#define DS_LOADFN 128 // .ptr is function that is run when loading
|
|
|
|
#define DS_SAVEFN 256 // .ptr is function that is run when saving
|
2011-02-21 23:08:21 +00:00
|
|
|
#define DS_NOCHK 1024 // don't check for diffs (and don't write out in dump) since assumed constant throughout demo
|
2011-05-12 23:31:13 +00:00
|
|
|
#define DS_PROTECTFN 512
|
2010-01-24 23:33:17 +00:00
|
|
|
#define DS_END (0x70000000)
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
static int32_t ds_getcnt(const dataspec_t *spec)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
int cnt = -1;
|
2015-02-11 05:22:23 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
switch (spec->flags & DS_CNTMASK)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
case 0: cnt = spec->cnt; break;
|
|
|
|
case DS_CNT16: cnt = *((int16_t *)spec->cnt); break;
|
|
|
|
case DS_CNT32: cnt = *((int32_t *)spec->cnt); break;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
2015-02-11 05:22:23 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
return cnt;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
static inline void ds_get(const dataspec_t *spec, void **ptr, int32_t *cnt)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
*cnt = ds_getcnt(spec);
|
|
|
|
*ptr = (spec->flags & DS_DYNAMIC) ? *((void **)spec->ptr) : spec->ptr;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// write state to file and/or to dump
|
2019-11-07 23:26:14 +00:00
|
|
|
static uint8_t *writespecdata(const dataspec_t *spec, FileWriter *fil, uint8_t *dump)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
for (; spec->flags != DS_END; spec++)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
if (spec->flags & (DS_SAVEFN|DS_LOADFN))
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
if (spec->flags & DS_SAVEFN)
|
|
|
|
(*(void (*)(void))spec->ptr)();
|
2010-01-24 23:33:17 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (!fil && (spec->flags & (DS_NOCHK|DS_CMP|DS_STRING)))
|
2010-01-24 23:33:17 +00:00
|
|
|
continue;
|
2018-10-25 23:31:45 +00:00
|
|
|
else if (spec->flags & DS_STRING)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2019-11-07 23:26:14 +00:00
|
|
|
fil->Write(spec->ptr, Bstrlen((const char *)spec->ptr)); // not null-terminated!
|
2010-01-24 23:33:17 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
void * ptr;
|
|
|
|
int32_t cnt;
|
|
|
|
|
|
|
|
ds_get(spec, &ptr, &cnt);
|
|
|
|
|
|
|
|
if (cnt < 0)
|
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("wsd: cnt=%d, f=0x%x.\n", cnt, spec->flags);
|
2018-10-25 23:31:45 +00:00
|
|
|
continue;
|
|
|
|
}
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2015-03-29 02:40:27 +00:00
|
|
|
if (!ptr || !cnt)
|
|
|
|
continue;
|
|
|
|
|
2010-01-24 23:33:17 +00:00
|
|
|
if (fil)
|
|
|
|
{
|
2019-11-07 23:26:14 +00:00
|
|
|
fil->Write(ptr, spec->size * cnt);
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (dump && (spec->flags & (DS_NOCHK|DS_CMP)) == 0)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
Bmemcpy(dump, ptr, spec->size * cnt);
|
|
|
|
dump += spec->size * cnt;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return dump;
|
|
|
|
}
|
|
|
|
|
|
|
|
// let havedump=dumpvar&&*dumpvar
|
|
|
|
// (fil>=0 && havedump): first restore dump from file, then restore state from dump
|
|
|
|
// (fil<0 && havedump): only restore state from dump
|
|
|
|
// (fil>=0 && !havedump): only restore state from file
|
2019-10-20 19:04:55 +00:00
|
|
|
static int32_t readspecdata(const dataspec_t *spec, FileReader *fil, uint8_t **dumpvar)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
uint8_t * dump = dumpvar ? *dumpvar : NULL;
|
|
|
|
auto const sptr = spec;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
for (; spec->flags != DS_END; spec++)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2019-10-20 19:04:55 +00:00
|
|
|
if (fil == nullptr && spec->flags & (DS_NOCHK|DS_STRING|DS_CMP)) // we're updating
|
2010-01-24 23:33:17 +00:00
|
|
|
continue;
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (spec->flags & (DS_LOADFN|DS_SAVEFN))
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
if (spec->flags & DS_LOADFN)
|
|
|
|
(*(void (*)())spec->ptr)();
|
2010-01-24 23:33:17 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (spec->flags & (DS_STRING|DS_CMP)) // DS_STRING and DS_CMP is for static data only
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
static char cmpstrbuf[32];
|
|
|
|
int const siz = (spec->flags & DS_STRING) ? Bstrlen((const char *)spec->ptr) : spec->size * spec->cnt;
|
2019-10-20 19:04:55 +00:00
|
|
|
int const ksiz = fil->Read(cmpstrbuf, siz);
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (ksiz != siz || Bmemcmp(spec->ptr, cmpstrbuf, siz))
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("rsd: spec=%s, idx=%d:\n", (char *)sptr->ptr, (int32_t)(spec-sptr));
|
2018-10-25 23:31:45 +00:00
|
|
|
|
|
|
|
if (ksiz!=siz)
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf(" file read returned %d, expected %d.\n", ksiz, siz);
|
2010-01-24 23:33:17 +00:00
|
|
|
else
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf(" sp->ptr and cmpstrbuf not identical!\n");
|
2018-10-25 23:31:45 +00:00
|
|
|
|
2010-01-24 23:33:17 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
void * ptr;
|
|
|
|
int32_t cnt;
|
|
|
|
|
|
|
|
ds_get(spec, &ptr, &cnt);
|
|
|
|
|
|
|
|
if (cnt < 0)
|
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("rsd: cnt<0... wtf?\n");
|
2018-10-25 23:31:45 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2015-03-29 02:40:27 +00:00
|
|
|
if (!ptr || !cnt)
|
|
|
|
continue;
|
|
|
|
|
2019-11-08 00:04:27 +00:00
|
|
|
if (fil != nullptr && fil->isOpen())
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
auto const mem = (dump && (spec->flags & DS_NOCHK) == 0) ? dump : (uint8_t *)ptr;
|
2019-11-06 00:01:16 +00:00
|
|
|
int const siz = cnt * spec->size;
|
|
|
|
int const ksiz = fil->Read(mem, siz);
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (ksiz != siz)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("rsd: spec=%s, idx=%d, mem=%p\n", (char *)sptr->ptr, (int32_t)(spec - sptr), mem);
|
|
|
|
Printf(" : read %d, expected %d!\n",
|
2019-12-11 00:10:59 +00:00
|
|
|
ksiz, siz);
|
2010-02-23 18:13:46 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (ksiz == -1)
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf(" read: %s\n", strerror(errno));
|
2018-10-25 23:31:45 +00:00
|
|
|
|
2010-01-24 23:33:17 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (dump && (spec->flags & DS_NOCHK) == 0)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
Bmemcpy(ptr, dump, spec->size * cnt);
|
|
|
|
dump += spec->size * cnt;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dumpvar)
|
|
|
|
*dumpvar = dump;
|
2018-10-25 23:31:45 +00:00
|
|
|
|
2010-01-24 23:33:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define UINT(bits) uint##bits##_t
|
|
|
|
#define BYTES(bits) (bits>>3)
|
2016-01-11 05:05:38 +00:00
|
|
|
#define VAL(bits,p) (*(UINT(bits) const *)(p))
|
|
|
|
#define WVAL(bits,p) (*(UINT(bits) *)(p))
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
static void docmpsd(const void *ptr, void *dump, uint32_t size, uint32_t cnt, uint8_t **diffvar)
|
|
|
|
{
|
|
|
|
uint8_t *retdiff = *diffvar;
|
|
|
|
|
|
|
|
// Hail to the C preprocessor, baby!
|
2018-10-25 23:31:45 +00:00
|
|
|
#define CPSINGLEVAL(Datbits) \
|
|
|
|
if (VAL(Datbits, ptr) != VAL(Datbits, dump)) \
|
|
|
|
{ \
|
|
|
|
WVAL(Datbits, retdiff) = WVAL(Datbits, dump) = VAL(Datbits, ptr); \
|
|
|
|
*diffvar = retdiff + BYTES(Datbits); \
|
|
|
|
}
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (cnt == 1)
|
2010-01-24 23:33:17 +00:00
|
|
|
switch (size)
|
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
case 8: CPSINGLEVAL(64); return;
|
|
|
|
case 4: CPSINGLEVAL(32); return;
|
|
|
|
case 2: CPSINGLEVAL(16); return;
|
|
|
|
case 1: CPSINGLEVAL(8); return;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
#define CPELTS(Idxbits, Datbits) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
for (int i = 0; i < nelts; i++) \
|
|
|
|
{ \
|
|
|
|
if (*p != *op) \
|
|
|
|
{ \
|
|
|
|
*op = *p; \
|
|
|
|
WVAL(Idxbits, retdiff) = i; \
|
|
|
|
retdiff += BYTES(Idxbits); \
|
|
|
|
WVAL(Datbits, retdiff) = *p; \
|
|
|
|
retdiff += BYTES(Datbits); \
|
|
|
|
} \
|
|
|
|
p++; \
|
|
|
|
op++; \
|
|
|
|
} \
|
|
|
|
WVAL(Idxbits, retdiff) = -1; \
|
|
|
|
retdiff += BYTES(Idxbits); \
|
2010-01-24 23:33:17 +00:00
|
|
|
} while (0)
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
#define CPDATA(Datbits) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
auto p = (UINT(Datbits) const *)ptr; \
|
|
|
|
auto op = (UINT(Datbits) *)dump; \
|
|
|
|
int nelts = tabledivide32_noinline(size * cnt, BYTES(Datbits)); \
|
|
|
|
if (nelts > 65536) \
|
|
|
|
CPELTS(32, Datbits); \
|
|
|
|
else if (nelts > 256) \
|
|
|
|
CPELTS(16, Datbits); \
|
|
|
|
else \
|
|
|
|
CPELTS(8, Datbits); \
|
2010-01-24 23:33:17 +00:00
|
|
|
} while (0)
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (size == 8)
|
2010-01-24 23:33:17 +00:00
|
|
|
CPDATA(64);
|
2018-10-25 23:31:45 +00:00
|
|
|
else if ((size & 3) == 0)
|
2010-01-24 23:33:17 +00:00
|
|
|
CPDATA(32);
|
2018-10-25 23:31:45 +00:00
|
|
|
else if ((size & 1) == 0)
|
2010-01-24 23:33:17 +00:00
|
|
|
CPDATA(16);
|
|
|
|
else
|
|
|
|
CPDATA(8);
|
|
|
|
|
|
|
|
*diffvar = retdiff;
|
|
|
|
|
2010-02-23 18:13:46 +00:00
|
|
|
#undef CPELTS
|
|
|
|
#undef CPSINGLEVAL
|
|
|
|
#undef CPDATA
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// get the number of elements to be monitored for changes
|
|
|
|
static int32_t getnumvar(const dataspec_t *spec)
|
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
int n = 0;
|
|
|
|
for (; spec->flags != DS_END; spec++)
|
|
|
|
if (spec->flags & (DS_STRING|DS_CMP|DS_NOCHK|DS_SAVEFN|DS_LOADFN))
|
|
|
|
++n;
|
2010-01-24 23:33:17 +00:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
// update dump at *dumpvar with new state and write diff to *diffvar
|
|
|
|
static void cmpspecdata(const dataspec_t *spec, uint8_t **dumpvar, uint8_t **diffvar)
|
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
uint8_t * dump = *dumpvar;
|
|
|
|
uint8_t * diff = *diffvar;
|
|
|
|
int nbytes = (getnumvar(spec) + 7) >> 3;
|
|
|
|
int const slen = Bstrlen((const char *)spec->ptr);
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
Bmemcpy(diff, spec->ptr, slen);
|
|
|
|
diff += slen;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
while (nbytes--)
|
|
|
|
*(diff++) = 0; // the bitmap of indices which elements of spec have changed go here
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
int eltnum = 0;
|
|
|
|
|
|
|
|
for (spec++; spec->flags!=DS_END; spec++)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
if ((spec->flags&(DS_NOCHK|DS_STRING|DS_CMP)))
|
2010-01-24 23:33:17 +00:00
|
|
|
continue;
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (spec->flags&(DS_LOADFN|DS_SAVEFN))
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
if ((spec->flags&(DS_PROTECTFN))==0)
|
|
|
|
(*(void (*)())spec->ptr)();
|
2010-01-24 23:33:17 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
void * ptr;
|
|
|
|
int32_t cnt;
|
|
|
|
|
|
|
|
ds_get(spec, &ptr, &cnt);
|
|
|
|
|
|
|
|
if (cnt < 0)
|
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("csd: cnt=%d, f=0x%x\n", cnt, spec->flags);
|
2018-10-25 23:31:45 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t * const tmptr = diff;
|
|
|
|
|
|
|
|
docmpsd(ptr, dump, spec->size, cnt, &diff);
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
if (diff != tmptr)
|
2018-10-25 23:31:45 +00:00
|
|
|
(*diffvar + slen)[eltnum>>3] |= 1<<(eltnum&7);
|
|
|
|
|
|
|
|
dump += spec->size*cnt;
|
2010-01-24 23:33:17 +00:00
|
|
|
eltnum++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*diffvar = diff;
|
|
|
|
*dumpvar = dump;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define VALOFS(bits,p,ofs) (*(((UINT(bits) *)(p)) + (ofs)))
|
|
|
|
|
|
|
|
// apply diff to dump, not to state! state is restored from dump afterwards.
|
|
|
|
static int32_t applydiff(const dataspec_t *spec, uint8_t **dumpvar, uint8_t **diffvar)
|
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
uint8_t * dump = *dumpvar;
|
|
|
|
uint8_t * diff = *diffvar;
|
|
|
|
int const nbytes = (getnumvar(spec)+7)>>3;
|
|
|
|
int const slen = Bstrlen((const char *)spec->ptr);
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (Bmemcmp(diff, spec->ptr, slen)) // check STRING magic (sync check)
|
2010-01-24 23:33:17 +00:00
|
|
|
return 1;
|
2011-12-21 18:40:47 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
diff += slen+nbytes;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
int eltnum = -1;
|
|
|
|
for (spec++; spec->flags != DS_END; spec++)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
if ((spec->flags & (DS_NOCHK|DS_STRING|DS_CMP|DS_LOADFN|DS_SAVEFN)))
|
2010-01-24 23:33:17 +00:00
|
|
|
continue;
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
int const cnt = ds_getcnt(spec);
|
2010-01-24 23:33:17 +00:00
|
|
|
if (cnt < 0) return 1;
|
|
|
|
|
|
|
|
eltnum++;
|
2019-08-04 02:51:50 +00:00
|
|
|
if (((*diffvar+slen)[eltnum>>3] & pow2char[eltnum&7]) == 0)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
dump += spec->size * cnt;
|
2010-01-24 23:33:17 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------
|
2018-10-25 23:31:45 +00:00
|
|
|
#define CPSINGLEVAL(Datbits) \
|
|
|
|
WVAL(Datbits, dump) = VAL(Datbits, diff); \
|
|
|
|
diff += BYTES(Datbits); \
|
|
|
|
dump += BYTES(Datbits)
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
if (cnt == 1)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
switch (spec->size)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
case 8: CPSINGLEVAL(64); continue;
|
|
|
|
case 4: CPSINGLEVAL(32); continue;
|
|
|
|
case 2: CPSINGLEVAL(16); continue;
|
|
|
|
case 1: CPSINGLEVAL(8); continue;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
#define CPELTS(Idxbits, Datbits) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
UINT(Idxbits) idx; \
|
|
|
|
goto readidx_##Idxbits##_##Datbits; \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
VALOFS(Datbits, dump, idx) = VAL(Datbits, diff); \
|
|
|
|
diff += BYTES(Datbits); \
|
|
|
|
readidx_##Idxbits##_##Datbits: \
|
|
|
|
idx = VAL(Idxbits, diff); \
|
|
|
|
diff += BYTES(Idxbits); \
|
|
|
|
} while ((int##Idxbits##_t)idx != -1); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define CPDATA(Datbits) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
int const elts = tabledivide32_noinline(spec->size * cnt, BYTES(Datbits)); \
|
|
|
|
if (elts > 65536) \
|
|
|
|
CPELTS(32, Datbits); \
|
|
|
|
else if (elts > 256) \
|
|
|
|
CPELTS(16, Datbits); \
|
|
|
|
else \
|
|
|
|
CPELTS(8, Datbits); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
if (spec->size == 8)
|
2010-01-24 23:33:17 +00:00
|
|
|
CPDATA(64);
|
2018-10-25 23:31:45 +00:00
|
|
|
else if ((spec->size & 3) == 0)
|
2010-01-24 23:33:17 +00:00
|
|
|
CPDATA(32);
|
2018-10-25 23:31:45 +00:00
|
|
|
else if ((spec->size & 1) == 0)
|
2010-01-24 23:33:17 +00:00
|
|
|
CPDATA(16);
|
|
|
|
else
|
|
|
|
CPDATA(8);
|
2018-10-25 23:31:45 +00:00
|
|
|
dump += spec->size * cnt;
|
2010-01-24 23:33:17 +00:00
|
|
|
// ----------
|
|
|
|
|
2010-02-23 18:13:46 +00:00
|
|
|
#undef CPELTS
|
|
|
|
#undef CPSINGLEVAL
|
|
|
|
#undef CPDATA
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
*diffvar = diff;
|
|
|
|
*dumpvar = dump;
|
2010-01-24 23:33:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef VAL
|
|
|
|
#undef VALOFS
|
|
|
|
#undef BYTES
|
|
|
|
#undef UINT
|
|
|
|
|
|
|
|
// calculate size needed for dump
|
|
|
|
static uint32_t calcsz(const dataspec_t *spec)
|
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
uint32_t dasiz = 0;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
for (; spec->flags != DS_END; spec++)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
|
|
|
// DS_STRINGs are used as sync checks in the diffs but not in the dump
|
2018-10-25 23:31:45 +00:00
|
|
|
if ((spec->flags & (DS_CMP|DS_NOCHK|DS_SAVEFN|DS_LOADFN|DS_STRING)))
|
2010-01-24 23:33:17 +00:00
|
|
|
continue;
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
int const cnt = ds_getcnt(spec);
|
|
|
|
|
|
|
|
if (cnt <= 0)
|
|
|
|
continue;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
dasiz += cnt * spec->size;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return dasiz;
|
|
|
|
}
|
|
|
|
|
2020-03-04 23:26:37 +00:00
|
|
|
|
2010-01-25 01:11:34 +00:00
|
|
|
static void sv_postactordata();
|
|
|
|
static void sv_preanimateptrsave();
|
|
|
|
static void sv_postanimateptr();
|
|
|
|
static void sv_restsave();
|
|
|
|
static void sv_restload();
|
2015-03-24 00:40:55 +00:00
|
|
|
static void sv_preprojectilesave();
|
|
|
|
static void sv_postprojectilesave();
|
|
|
|
static void sv_preprojectileload();
|
|
|
|
static void sv_postprojectileload();
|
|
|
|
|
2018-09-28 04:27:48 +00:00
|
|
|
static projectile_t *savegame_projectiledata;
|
2018-10-25 23:31:45 +00:00
|
|
|
static uint8_t savegame_projectiles[MAXTILES >> 3];
|
|
|
|
static int32_t savegame_projectilecnt = 0;
|
2010-01-25 01:11:34 +00:00
|
|
|
|
|
|
|
#define SVARDATALEN \
|
|
|
|
((sizeof(g_player[0].user_name)+sizeof(g_player[0].pcolor)+sizeof(g_player[0].pteam) \
|
2012-12-09 13:24:32 +00:00
|
|
|
+sizeof(g_player[0].frags)+sizeof(DukePlayer_t))*MAXPLAYERS)
|
2010-01-25 01:11:34 +00:00
|
|
|
|
|
|
|
static uint8_t savegame_restdata[SVARDATALEN];
|
|
|
|
|
2016-01-11 05:05:38 +00:00
|
|
|
static char svgm_udnetw_string [] = "blK:udnt";
|
2010-01-25 01:11:34 +00:00
|
|
|
static const dataspec_t svgm_udnetw[] =
|
|
|
|
{
|
2016-01-11 05:05:38 +00:00
|
|
|
{ DS_STRING, (void *)svgm_udnetw_string, 0, 1 },
|
2010-01-25 01:11:34 +00:00
|
|
|
{ 0, &ud.multimode, sizeof(ud.multimode), 1 },
|
2016-08-27 01:42:01 +00:00
|
|
|
{ 0, &g_playerSpawnCnt, sizeof(g_playerSpawnCnt), 1 },
|
2010-01-25 01:11:34 +00:00
|
|
|
{ 0, &g_playerSpawnPoints, sizeof(g_playerSpawnPoints), 1 },
|
|
|
|
|
|
|
|
{ DS_NOCHK, &ud.volume_number, sizeof(ud.volume_number), 1 },
|
|
|
|
{ DS_NOCHK, &ud.level_number, sizeof(ud.level_number), 1 },
|
2017-12-01 06:19:15 +00:00
|
|
|
{ DS_NOCHK, &ud.user_map, sizeof(ud.user_map), 1 },
|
2010-01-25 01:11:34 +00:00
|
|
|
{ DS_NOCHK, &ud.player_skill, sizeof(ud.player_skill), 1 },
|
2017-12-01 06:19:15 +00:00
|
|
|
{ DS_NOCHK, &ud.music_episode, sizeof(ud.music_episode), 1 },
|
|
|
|
{ DS_NOCHK, &ud.music_level, sizeof(ud.music_level), 1 },
|
2010-01-25 01:11:34 +00:00
|
|
|
|
|
|
|
{ DS_NOCHK, &ud.from_bonus, sizeof(ud.from_bonus), 1 },
|
|
|
|
{ DS_NOCHK, &ud.secretlevel, sizeof(ud.secretlevel), 1 },
|
|
|
|
{ DS_NOCHK, &ud.respawn_monsters, sizeof(ud.respawn_monsters), 1 },
|
|
|
|
{ DS_NOCHK, &ud.respawn_items, sizeof(ud.respawn_items), 1 },
|
|
|
|
{ DS_NOCHK, &ud.respawn_inventory, sizeof(ud.respawn_inventory), 1 },
|
|
|
|
{ 0, &ud.god, sizeof(ud.god), 1 },
|
|
|
|
{ DS_NOCHK, &ud.monsters_off, sizeof(ud.monsters_off), 1 },
|
|
|
|
{ DS_NOCHK, &ud.last_level, sizeof(ud.last_level), 1 },
|
|
|
|
{ 0, &ud.eog, sizeof(ud.eog), 1 },
|
|
|
|
{ DS_NOCHK, &ud.coop, sizeof(ud.coop), 1 },
|
|
|
|
{ DS_NOCHK, &ud.marker, sizeof(ud.marker), 1 },
|
|
|
|
{ DS_NOCHK, &ud.ffire, sizeof(ud.ffire), 1 },
|
|
|
|
{ DS_NOCHK, &ud.noexits, sizeof(ud.noexits), 1 },
|
|
|
|
{ DS_NOCHK, &ud.playerai, sizeof(ud.playerai), 1 },
|
2010-02-13 21:46:42 +00:00
|
|
|
{ 0, &ud.pause_on, sizeof(ud.pause_on), 1 },
|
2010-01-25 01:11:34 +00:00
|
|
|
{ 0, connectpoint2, sizeof(connectpoint2), 1 },
|
|
|
|
{ 0, &randomseed, sizeof(randomseed), 1 },
|
|
|
|
{ 0, &g_globalRandom, sizeof(g_globalRandom), 1 },
|
|
|
|
// { 0, &lockclock_dummy, sizeof(lockclock), 1 },
|
|
|
|
{ DS_END, 0, 0, 0 }
|
|
|
|
};
|
|
|
|
|
Inreased debugging level for catching oob accesses to 'main' arrays.
If enabled, this makes the following arrays be allocated statically:
spriteext, spritesmooth, sector, wall, sprite, tsprite, while
necessarily disabling the clipshape feature (because it relies on
setting sector/wall to different malloc'd block temporarily).
To compile, pass DEBUGANYWAY=1 in addition to RELEASE=0 to 'make',
and it's really only useful with CC=clang, of course.
git-svn-id: https://svn.eduke32.com/eduke32@2270 1a8010ca-5511-0410-912e-c29ae57300e0
2012-01-19 23:17:34 +00:00
|
|
|
#if !defined DEBUG_MAIN_ARRAYS
|
|
|
|
# define DS_MAINAR DS_DYNAMIC
|
|
|
|
#else
|
|
|
|
# define DS_MAINAR 0
|
|
|
|
#endif
|
|
|
|
|
2016-01-11 05:05:38 +00:00
|
|
|
static char svgm_secwsp_string [] = "blK:swsp";
|
2010-01-25 01:11:34 +00:00
|
|
|
static const dataspec_t svgm_secwsp[] =
|
|
|
|
{
|
2016-01-11 05:05:38 +00:00
|
|
|
{ DS_STRING, (void *)svgm_secwsp_string, 0, 1 },
|
2016-08-27 01:42:01 +00:00
|
|
|
{ DS_NOCHK, &g_cyclerCnt, sizeof(g_cyclerCnt), 1 },
|
|
|
|
{ DS_CNT(g_cyclerCnt), &g_cyclers[0][0], sizeof(g_cyclers[0]), (intptr_t)&g_cyclerCnt },
|
|
|
|
{ DS_NOCHK, &g_animWallCnt, sizeof(g_animWallCnt), 1 },
|
|
|
|
{ DS_CNT(g_animWallCnt), &animwall, sizeof(animwall[0]), (intptr_t)&g_animWallCnt },
|
2010-01-25 01:11:34 +00:00
|
|
|
{ DS_NOCHK, &g_mirrorCount, sizeof(g_mirrorCount), 1 },
|
2014-03-22 09:25:15 +00:00
|
|
|
{ DS_NOCHK, &g_mirrorWall[0], sizeof(g_mirrorWall[0]), ARRAY_SIZE(g_mirrorWall) },
|
|
|
|
{ DS_NOCHK, &g_mirrorSector[0], sizeof(g_mirrorSector[0]), ARRAY_SIZE(g_mirrorSector) },
|
2010-01-25 01:11:34 +00:00
|
|
|
// projectiles
|
|
|
|
{ 0, &SpriteProjectile[0], sizeof(projectile_t), MAXSPRITES },
|
|
|
|
{ 0, &everyothertime, sizeof(everyothertime), 1 },
|
|
|
|
{ DS_END, 0, 0, 0 }
|
|
|
|
};
|
|
|
|
|
2016-01-11 05:05:38 +00:00
|
|
|
static char svgm_script_string [] = "blK:scri";
|
2010-01-25 01:11:34 +00:00
|
|
|
static const dataspec_t svgm_script[] =
|
|
|
|
{
|
2016-01-11 05:05:38 +00:00
|
|
|
{ DS_STRING, (void *)svgm_script_string, 0, 1 },
|
2015-03-24 00:40:55 +00:00
|
|
|
{ DS_SAVEFN, (void *) &sv_preprojectilesave, 0, 1 },
|
2018-10-03 00:43:31 +00:00
|
|
|
{ 0, savegame_projectiles, sizeof(uint8_t), MAXTILES >> 3 },
|
2015-03-24 00:40:55 +00:00
|
|
|
{ DS_LOADFN, (void *) &sv_preprojectileload, 0, 1 },
|
2018-10-25 23:31:45 +00:00
|
|
|
{ DS_DYNAMIC|DS_CNT(savegame_projectilecnt), &savegame_projectiledata, sizeof(projectile_t), (intptr_t)&savegame_projectilecnt },
|
2015-03-24 00:40:55 +00:00
|
|
|
{ DS_SAVEFN, (void *) &sv_postprojectilesave, 0, 1 },
|
|
|
|
{ DS_LOADFN, (void *) &sv_postprojectileload, 0, 1 },
|
2010-08-02 08:13:51 +00:00
|
|
|
{ 0, &actor[0], sizeof(actor_t), MAXSPRITES },
|
2010-01-25 01:11:34 +00:00
|
|
|
{ DS_SAVEFN|DS_LOADFN, (void *)&sv_postactordata, 0, 1 },
|
2013-06-07 10:18:17 +00:00
|
|
|
#if defined LUNATIC
|
|
|
|
{ DS_LOADFN|DS_NOCHK, (void *)&sv_create_lua_state, 0, 1 },
|
|
|
|
#endif
|
2010-01-25 01:11:34 +00:00
|
|
|
{ DS_END, 0, 0, 0 }
|
|
|
|
};
|
|
|
|
|
2016-01-11 05:05:38 +00:00
|
|
|
static char svgm_anmisc_string [] = "blK:anms";
|
|
|
|
static char svgm_end_string [] = "savegame_end";
|
|
|
|
|
2010-01-25 01:11:34 +00:00
|
|
|
static const dataspec_t svgm_anmisc[] =
|
|
|
|
{
|
2016-01-11 05:05:38 +00:00
|
|
|
{ DS_STRING, (void *)svgm_anmisc_string, 0, 1 },
|
2016-08-27 01:42:01 +00:00
|
|
|
{ 0, &g_animateCnt, sizeof(g_animateCnt), 1 },
|
|
|
|
{ 0, &g_animateSect[0], sizeof(g_animateSect[0]), MAXANIMATES },
|
|
|
|
{ 0, &g_animateGoal[0], sizeof(g_animateGoal[0]), MAXANIMATES },
|
|
|
|
{ 0, &g_animateVel[0], sizeof(g_animateVel[0]), MAXANIMATES },
|
2010-01-25 01:11:34 +00:00
|
|
|
{ DS_SAVEFN, (void *)&sv_preanimateptrsave, 0, 1 },
|
2016-08-27 01:42:01 +00:00
|
|
|
{ 0, &g_animatePtr[0], sizeof(g_animatePtr[0]), MAXANIMATES },
|
2010-01-25 01:11:34 +00:00
|
|
|
{ DS_SAVEFN|DS_LOADFN , (void *)&sv_postanimateptr, 0, 1 },
|
2013-12-26 19:45:12 +00:00
|
|
|
{ 0, &g_curViewscreen, sizeof(g_curViewscreen), 1 },
|
2016-01-21 19:35:30 +00:00
|
|
|
{ 0, &g_origins[0], sizeof(g_origins[0]), ARRAY_SIZE(g_origins) },
|
2010-02-13 21:46:42 +00:00
|
|
|
{ 0, &g_spriteDeleteQueuePos, sizeof(g_spriteDeleteQueuePos), 1 },
|
2016-08-27 01:40:35 +00:00
|
|
|
{ DS_NOCHK, &g_deleteQueueSize, sizeof(g_deleteQueueSize), 1 },
|
|
|
|
{ DS_CNT(g_deleteQueueSize), &SpriteDeletionQueue[0], sizeof(int16_t), (intptr_t)&g_deleteQueueSize },
|
2016-08-27 01:42:01 +00:00
|
|
|
{ DS_NOCHK, &g_cloudCnt, sizeof(g_cloudCnt), 1 },
|
|
|
|
{ 0, &g_cloudSect[0], sizeof(g_cloudSect), 1 },
|
|
|
|
{ 0, &g_cloudX, sizeof(g_cloudX), 1 },
|
|
|
|
{ 0, &g_cloudY, sizeof(g_cloudY), 1 },
|
Clean up parallaxed sky functionality, part 2.
- Rename sky_t members: yscale -> horizfrac, bits -> lognumtiles.
- Add default sky (8 tiles, horizfrac=32768 (i.e. 1/2 the scene horiz), offsets
all zero) and CLOUDYOCEAN sky (8 tiles, horizfrac=65536, offsets all zero)
to multipsky[].
- Get rid of "psky_t g_psky", merely maintaining a g_pskyidx instead. Set it up
at map load time so as to keep the behavior of the legacy per-map psky:
the last sector index with a matching psky ceiling wins.
- In mapstate_t, save g_pskyidx too, not (former) pskybits and pskyoffs[].
- Make on-map-load global psky setup consistent for the game and editor by
factoring it out into common.c: G_SetupGlobalPsky().
- Remove a couple of useless initializations, add some static assertions.
This commit is more likely to introduce subtle differences in behavior.
Specifically, getpsky() now always returns the default sky properties instead of
the global sky ones (but with all-zero offsets) when no match for a suiting
multi-psky is found. This is only likely to affect the yscale/horizfrac of
non-multi-pskies when a global non-default multi-psky has been set up.
Bump BYTEVERSION again.
git-svn-id: https://svn.eduke32.com/eduke32@3976 1a8010ca-5511-0410-912e-c29ae57300e0
2013-08-04 20:37:48 +00:00
|
|
|
{ 0, &g_pskyidx, sizeof(g_pskyidx), 1 }, // DS_NOCHK?
|
2010-01-25 01:11:34 +00:00
|
|
|
{ 0, &g_earthquakeTime, sizeof(g_earthquakeTime), 1 },
|
|
|
|
|
|
|
|
{ DS_SAVEFN, (void *)&sv_restsave, 0, 1 },
|
|
|
|
{ 0, savegame_restdata, 1, sizeof(savegame_restdata) }, // sz/cnt swapped for kdfread
|
|
|
|
{ DS_LOADFN, (void *)&sv_restload, 0, 1 },
|
|
|
|
|
2016-01-11 05:05:38 +00:00
|
|
|
{ DS_STRING, (void *)svgm_end_string, 0, 1 },
|
2010-01-25 01:11:34 +00:00
|
|
|
{ DS_END, 0, 0, 0 }
|
|
|
|
};
|
|
|
|
|
2016-01-11 05:05:38 +00:00
|
|
|
static dataspec_gv_t *svgm_vars=NULL;
|
2019-11-07 23:26:14 +00:00
|
|
|
static uint8_t *dosaveplayer2(FileWriter &fil, uint8_t *mem);
|
2019-10-20 19:04:55 +00:00
|
|
|
static int32_t doloadplayer2(FileReader &fil, uint8_t **memptr);
|
2011-12-25 15:34:06 +00:00
|
|
|
static void postloadplayer(int32_t savegamep);
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
// SVGM snapshot system
|
|
|
|
static uint32_t svsnapsiz;
|
2018-10-25 23:31:45 +00:00
|
|
|
static uint8_t *svsnapshot;
|
|
|
|
static uint8_t *svinitsnap;
|
2010-01-24 23:33:17 +00:00
|
|
|
static uint32_t svdiffsiz;
|
|
|
|
static uint8_t *svdiff;
|
|
|
|
|
|
|
|
#include "gamedef.h"
|
|
|
|
|
2013-05-19 19:29:18 +00:00
|
|
|
#if !defined LUNATIC
|
2018-03-07 04:21:31 +00:00
|
|
|
#define SV_SKIPMASK (/*GAMEVAR_SYSTEM|*/ GAMEVAR_READONLY | GAMEVAR_PTR_MASK | /*GAMEVAR_NORESET |*/ GAMEVAR_SPECIAL)
|
2016-01-11 05:06:10 +00:00
|
|
|
|
|
|
|
static char svgm_vars_string [] = "blK:vars";
|
2010-01-24 23:33:17 +00:00
|
|
|
// setup gamevar data spec for snapshotting and diffing... gamevars must be loaded when called
|
|
|
|
static void sv_makevarspec()
|
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
int vcnt = 0;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
for (int i = 0; i < g_gameVarCount; i++)
|
|
|
|
vcnt += (aGameVars[i].flags & SV_SKIPMASK) ? 0 : 1;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
for (int i=0; i<g_gameArrayCount; i++)
|
|
|
|
vcnt += !(aGameArrays[i].flags & (GAMEARRAY_SYSTEM|GAMEARRAY_READONLY)); // SYSTEM_GAMEARRAY
|
2013-12-06 18:56:39 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
svgm_vars = (dataspec_gv_t *)Xrealloc(svgm_vars, (vcnt + 2) * sizeof(dataspec_gv_t));
|
2013-05-24 13:54:32 +00:00
|
|
|
|
2010-01-24 23:33:17 +00:00
|
|
|
svgm_vars[0].flags = DS_STRING;
|
2018-10-25 23:31:45 +00:00
|
|
|
svgm_vars[0].ptr = svgm_vars_string;
|
|
|
|
svgm_vars[0].cnt = 1;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
vcnt = 1;
|
|
|
|
|
|
|
|
for (int i = 0; i < g_gameVarCount; i++)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
if (aGameVars[i].flags & SV_SKIPMASK)
|
2010-01-24 23:33:17 +00:00
|
|
|
continue;
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
unsigned const per = aGameVars[i].flags & GAMEVAR_USER_MASK;
|
|
|
|
|
|
|
|
svgm_vars[vcnt].flags = 0;
|
|
|
|
svgm_vars[vcnt].ptr = (per == 0) ? &aGameVars[i].global : aGameVars[i].pValues;
|
|
|
|
svgm_vars[vcnt].size = sizeof(intptr_t);
|
|
|
|
svgm_vars[vcnt].cnt = (per == 0) ? 1 : (per == GAMEVAR_PERPLAYER ? MAXPLAYERS : MAXSPRITES);
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
++vcnt;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
for (int i = 0; i < g_gameArrayCount; i++)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2013-12-06 18:56:39 +00:00
|
|
|
// We must not update read-only SYSTEM_GAMEARRAY gamearrays: besides
|
|
|
|
// being questionable by itself, sizeof(...) may be e.g. 4 whereas the
|
|
|
|
// actual element type is int16_t (such as tilesizx[]/tilesizy[]).
|
2017-07-08 19:41:43 +00:00
|
|
|
if (aGameArrays[i].flags & (GAMEARRAY_SYSTEM|GAMEARRAY_READONLY))
|
2013-12-06 18:56:39 +00:00
|
|
|
continue;
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
auto const pValues = aGameArrays[i].pValues;
|
|
|
|
|
|
|
|
svgm_vars[vcnt].flags = 0;
|
|
|
|
svgm_vars[vcnt].ptr = pValues;
|
2017-07-08 19:41:43 +00:00
|
|
|
|
|
|
|
if (aGameArrays[i].flags & GAMEARRAY_BITMAP)
|
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
svgm_vars[vcnt].size = (aGameArrays[i].size + 7) >> 3;
|
|
|
|
svgm_vars[vcnt].cnt = 1; // assumed constant throughout demo, i.e. no RESIZEARRAY
|
2017-07-08 19:41:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
svgm_vars[vcnt].size = pValues == NULL ? 0 : sizeof(aGameArrays[0].pValues[0]);
|
|
|
|
svgm_vars[vcnt].cnt = aGameArrays[i].size; // assumed constant throughout demo, i.e. no RESIZEARRAY
|
2017-07-08 19:41:43 +00:00
|
|
|
}
|
2018-10-25 23:31:45 +00:00
|
|
|
|
|
|
|
++vcnt;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
svgm_vars[vcnt].flags = DS_END;
|
|
|
|
svgm_vars[vcnt].ptr = NULL;
|
|
|
|
svgm_vars[vcnt].size = 0;
|
|
|
|
svgm_vars[vcnt].cnt = 0;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
2013-05-19 19:29:18 +00:00
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
void sv_freemem()
|
|
|
|
{
|
2015-02-11 05:22:23 +00:00
|
|
|
DO_FREE_AND_NULL(svsnapshot);
|
|
|
|
DO_FREE_AND_NULL(svinitsnap);
|
|
|
|
DO_FREE_AND_NULL(svdiff);
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
2014-05-30 00:02:19 +00:00
|
|
|
static void SV_AllocSnap(int32_t allocinit)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
|
|
|
sv_freemem();
|
|
|
|
|
2014-05-30 00:02:19 +00:00
|
|
|
svsnapshot = (uint8_t *)Xmalloc(svsnapsiz);
|
2010-01-24 23:33:17 +00:00
|
|
|
if (allocinit)
|
2014-05-30 00:02:19 +00:00
|
|
|
svinitsnap = (uint8_t *)Xmalloc(svsnapsiz);
|
2010-01-24 23:33:17 +00:00
|
|
|
svdiffsiz = svsnapsiz; // theoretically it's less than could be needed in the worst case, but practically it's overkill
|
2014-05-30 00:02:19 +00:00
|
|
|
svdiff = (uint8_t *)Xmalloc(svdiffsiz);
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
// make snapshot only if spot < 0 (demo)
|
2020-01-12 22:16:21 +00:00
|
|
|
int32_t sv_saveandmakesnapshot(FileWriter &fil, int8_t spot)
|
2011-12-25 15:34:06 +00:00
|
|
|
{
|
|
|
|
savehead_t h;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
// calculate total snapshot size
|
2013-05-19 19:29:18 +00:00
|
|
|
#if !defined LUNATIC
|
2010-01-24 23:33:17 +00:00
|
|
|
sv_makevarspec();
|
2016-01-11 05:05:38 +00:00
|
|
|
svsnapsiz = calcsz((const dataspec_t *)svgm_vars);
|
2013-05-19 19:29:18 +00:00
|
|
|
#else
|
|
|
|
svsnapsiz = 0;
|
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
svsnapsiz += calcsz(svgm_udnetw) + calcsz(svgm_secwsp) + calcsz(svgm_script) + calcsz(svgm_anmisc);
|
|
|
|
|
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
// create header
|
2019-11-02 21:22:57 +00:00
|
|
|
Bmemcpy(h.headerstr, "DEDSAVEGAME", 11);
|
2011-12-25 15:34:06 +00:00
|
|
|
h.majorver = SV_MAJOR_VER;
|
|
|
|
h.minorver = SV_MINOR_VER;
|
2018-10-25 23:31:45 +00:00
|
|
|
h.ptrsize = sizeof(intptr_t);
|
|
|
|
h.bytever = BYTEVERSION;
|
|
|
|
h.userbytever = ud.userbytever;
|
|
|
|
h.scriptcrc = g_scriptcrc;
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
h.reccnt = 0;
|
2011-12-25 15:34:06 +00:00
|
|
|
h.snapsiz = svsnapsiz;
|
|
|
|
|
|
|
|
// the following is kinda redundant, but we save it here to be able to quickly fetch
|
|
|
|
// it in a savegame header read
|
2018-10-25 23:31:45 +00:00
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
h.numplayers = ud.multimode;
|
2018-10-25 23:31:45 +00:00
|
|
|
h.volnum = ud.volume_number;
|
|
|
|
h.levnum = ud.level_number;
|
|
|
|
h.skill = ud.player_skill;
|
2014-09-07 18:10:15 +00:00
|
|
|
|
2017-12-18 11:24:53 +00:00
|
|
|
if (spot >= 0)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2011-12-25 15:34:06 +00:00
|
|
|
// savegame
|
2019-11-14 20:07:43 +00:00
|
|
|
auto fw = WriteSavegameChunk("header.dat");
|
|
|
|
fw->Write(&h, sizeof(savehead_t));
|
|
|
|
}
|
2011-12-25 15:34:06 +00:00
|
|
|
else
|
|
|
|
{
|
2019-12-11 00:10:59 +00:00
|
|
|
// demo (currently broken, needs a new format.)
|
2018-10-25 23:31:45 +00:00
|
|
|
const time_t t = time(NULL);
|
2019-12-11 00:10:59 +00:00
|
|
|
struct tm * st = localtime(&t);
|
|
|
|
FStringf demoname("Demo %04d%02d%02d %s", st->tm_year+1900, st->tm_mon+1, st->tm_mday, GetGitDescription());
|
2019-11-14 20:07:43 +00:00
|
|
|
fil.Write(&h, sizeof(savehead_t));
|
|
|
|
}
|
2011-12-25 15:34:06 +00:00
|
|
|
|
|
|
|
if (spot >= 0)
|
|
|
|
{
|
|
|
|
// savegame
|
|
|
|
dosaveplayer2(fil, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// demo
|
2014-05-30 00:02:19 +00:00
|
|
|
SV_AllocSnap(0);
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
uint8_t * const p = dosaveplayer2(fil, svsnapshot);
|
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
if (p != svsnapshot+svsnapsiz)
|
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("sv_saveandmakesnapshot: ptr-(snapshot end)=%d!\n", (int32_t)(p - (svsnapshot + svsnapsiz)));
|
2011-12-25 15:34:06 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
// if file is not an EDuke32 savegame/demo, h->headerstr will be all zeros
|
2019-11-14 20:07:43 +00:00
|
|
|
int32_t sv_loadheader(FileReader &fill, int32_t spot, savehead_t *h)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2019-11-14 20:07:43 +00:00
|
|
|
FileReader filc;
|
|
|
|
FileReader* filp = &fill;
|
2011-12-25 15:34:06 +00:00
|
|
|
int32_t havedemo = (spot < 0);
|
2019-11-14 20:07:43 +00:00
|
|
|
if (!havedemo)
|
|
|
|
{
|
|
|
|
filc = ReadSavegameChunk("header.dat");
|
|
|
|
filp = &filc;
|
|
|
|
}
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2019-11-14 20:07:43 +00:00
|
|
|
if (filp->Read(h, sizeof(savehead_t)) != sizeof(savehead_t))
|
2011-12-25 15:34:06 +00:00
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("%s %d header corrupt.\n", havedemo ? "Demo":"Savegame", havedemo ? -spot : spot);
|
2011-12-25 15:34:06 +00:00
|
|
|
Bmemset(h->headerstr, 0, sizeof(h->headerstr));
|
|
|
|
return -1;
|
|
|
|
}
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2019-11-02 21:22:57 +00:00
|
|
|
if (Bmemcmp(h->headerstr, "DEDSAVEGAME", 11)
|
2018-03-08 03:54:58 +00:00
|
|
|
)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-03-08 03:54:58 +00:00
|
|
|
char headerCstr[sizeof(h->headerstr) + 1];
|
|
|
|
Bmemcpy(headerCstr, h->headerstr, sizeof(h->headerstr));
|
|
|
|
headerCstr[sizeof(h->headerstr)] = '\0';
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("%s %d header reads \"%s\", expected \"DEDSAVEGAME\".\n",
|
2018-03-08 03:54:58 +00:00
|
|
|
havedemo ? "Demo":"Savegame", havedemo ? -spot : spot, headerCstr);
|
2011-12-25 15:34:06 +00:00
|
|
|
Bmemset(h->headerstr, 0, sizeof(h->headerstr));
|
2017-12-01 06:19:04 +00:00
|
|
|
return -2;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
2018-09-01 19:36:10 +00:00
|
|
|
if (h->majorver != SV_MAJOR_VER || h->minorver != SV_MINOR_VER || h->bytever != BYTEVERSION || h->userbytever != ud.userbytever || (apScript != NULL && h->scriptcrc != g_scriptcrc))
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-08-09 16:06:49 +00:00
|
|
|
#ifndef DEBUGGINGAIDS
|
2011-12-25 15:34:06 +00:00
|
|
|
if (havedemo)
|
2018-08-09 16:06:49 +00:00
|
|
|
#endif
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("Incompatible savegame. Expected version %d.%d.%d.%d.%0x, found %d.%d.%d.%d.%0x\n", SV_MAJOR_VER, SV_MINOR_VER, BYTEVERSION,
|
2018-08-09 16:06:49 +00:00
|
|
|
ud.userbytever, g_scriptcrc, h->majorver, h->minorver, h->bytever, h->userbytever, h->scriptcrc);
|
2017-12-01 06:19:04 +00:00
|
|
|
|
|
|
|
if (h->majorver == SV_MAJOR_VER && h->minorver == SV_MINOR_VER)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Bmemset(h->headerstr, 0, sizeof(h->headerstr));
|
|
|
|
return -3;
|
|
|
|
}
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2018-03-08 03:55:02 +00:00
|
|
|
if (h->getPtrSize() != sizeof(intptr_t))
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-08-09 16:06:49 +00:00
|
|
|
#ifndef DEBUGGINGAIDS
|
2011-12-25 15:34:06 +00:00
|
|
|
if (havedemo)
|
2018-08-09 16:06:49 +00:00
|
|
|
#endif
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("File incompatible. Expected pointer size %d, found %d\n",
|
2018-03-08 03:55:02 +00:00
|
|
|
(int32_t)sizeof(intptr_t), h->getPtrSize());
|
2017-12-01 06:19:04 +00:00
|
|
|
|
|
|
|
Bmemset(h->headerstr, 0, sizeof(h->headerstr));
|
|
|
|
return -4;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2019-10-20 19:04:55 +00:00
|
|
|
int32_t sv_loadsnapshot(FileReader &fil, int32_t spot, savehead_t *h)
|
2011-12-25 15:34:06 +00:00
|
|
|
{
|
|
|
|
uint8_t *p;
|
|
|
|
int32_t i;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
if (spot < 0)
|
|
|
|
{
|
|
|
|
// demo
|
|
|
|
i = sv_loadheader(fil, spot, h);
|
|
|
|
if (i)
|
|
|
|
return i;
|
|
|
|
|
|
|
|
// Used to be in doloadplayer2(), now redundant for savegames since
|
|
|
|
// we checked before. Multiplayer demos need still to be taken care of.
|
|
|
|
if (h->numplayers != numplayers)
|
|
|
|
return 9;
|
|
|
|
}
|
|
|
|
// else (if savegame), we just read the header and are now at offset sizeof(savehead_t)
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
#ifdef DEBUGGINGAIDS
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("sv_loadsnapshot: snapshot size: %d bytes.\n", h->snapsiz);
|
2011-12-25 15:34:06 +00:00
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
if (spot >= 0)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2011-12-25 15:34:06 +00:00
|
|
|
// savegame
|
|
|
|
i = doloadplayer2(fil, NULL);
|
|
|
|
if (i)
|
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("sv_loadsnapshot: doloadplayer2() returned %d.\n", i);
|
2011-12-25 15:34:06 +00:00
|
|
|
return 5;
|
|
|
|
}
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
2011-12-25 15:34:06 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
svsnapsiz = h->snapsiz;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2014-05-30 00:02:19 +00:00
|
|
|
SV_AllocSnap(1);
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
p = svsnapshot;
|
|
|
|
i = doloadplayer2(fil, &p);
|
|
|
|
if (i)
|
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("sv_loadsnapshot: doloadplayer2() returned %d.\n", i);
|
2011-12-25 15:34:06 +00:00
|
|
|
sv_freemem();
|
|
|
|
return 5;
|
|
|
|
}
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
if (p != svsnapshot+svsnapsiz)
|
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("sv_loadsnapshot: internal error: p-(snapshot end)=%d!\n",
|
2011-12-25 15:34:06 +00:00
|
|
|
(int32_t)(p-(svsnapshot+svsnapsiz)));
|
|
|
|
sv_freemem();
|
|
|
|
return 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bmemcpy(svinitsnap, svsnapshot, svsnapsiz);
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
postloadplayer((spot >= 0));
|
|
|
|
|
2010-01-24 23:33:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2019-11-07 23:26:14 +00:00
|
|
|
uint32_t sv_writediff(FileWriter *fil)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
uint8_t *p = svsnapshot;
|
|
|
|
uint8_t *d = svdiff;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
cmpspecdata(svgm_udnetw, &p, &d);
|
|
|
|
cmpspecdata(svgm_secwsp, &p, &d);
|
|
|
|
cmpspecdata(svgm_script, &p, &d);
|
|
|
|
cmpspecdata(svgm_anmisc, &p, &d);
|
2013-05-19 19:29:18 +00:00
|
|
|
#if !defined LUNATIC
|
2016-01-11 05:05:38 +00:00
|
|
|
cmpspecdata((const dataspec_t *)svgm_vars, &p, &d);
|
2013-05-19 19:29:18 +00:00
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
if (p != svsnapshot+svsnapsiz)
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("sv_writediff: dump+siz=%p, p=%p!\n", svsnapshot+svsnapsiz, p);
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
uint32_t const diffsiz = d - svdiff;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2019-11-07 23:26:14 +00:00
|
|
|
fil->Write("dIfF",4);
|
|
|
|
fil->Write(&diffsiz, sizeof(diffsiz));
|
2018-10-25 23:31:45 +00:00
|
|
|
|
2019-11-07 23:26:14 +00:00
|
|
|
fil->Write(svdiff, diffsiz);
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
return diffsiz;
|
|
|
|
}
|
|
|
|
|
2019-10-20 19:04:55 +00:00
|
|
|
int32_t sv_readdiff(FileReader &fil)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2010-02-23 18:13:46 +00:00
|
|
|
int32_t diffsiz;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2019-10-20 19:04:55 +00:00
|
|
|
if (fil.Read(&diffsiz, sizeof(uint32_t)) != sizeof(uint32_t))
|
2010-02-23 18:13:46 +00:00
|
|
|
return -1;
|
2018-10-25 23:31:45 +00:00
|
|
|
|
2019-11-06 00:01:16 +00:00
|
|
|
if (fil.Read(svdiff, diffsiz) != diffsiz)
|
2010-01-24 23:33:17 +00:00
|
|
|
return -2;
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
uint8_t *p = svsnapshot;
|
|
|
|
uint8_t *d = svdiff;
|
|
|
|
|
2010-02-23 18:13:46 +00:00
|
|
|
if (applydiff(svgm_udnetw, &p, &d)) return -3;
|
|
|
|
if (applydiff(svgm_secwsp, &p, &d)) return -4;
|
|
|
|
if (applydiff(svgm_script, &p, &d)) return -5;
|
|
|
|
if (applydiff(svgm_anmisc, &p, &d)) return -6;
|
2013-05-19 19:29:18 +00:00
|
|
|
#if !defined LUNATIC
|
2016-01-11 05:05:38 +00:00
|
|
|
if (applydiff((const dataspec_t *)svgm_vars, &p, &d)) return -7;
|
2013-05-19 19:29:18 +00:00
|
|
|
#endif
|
2010-02-23 18:13:46 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
int i = 0;
|
|
|
|
|
2010-02-23 18:13:46 +00:00
|
|
|
if (p!=svsnapshot+svsnapsiz)
|
|
|
|
i|=1;
|
|
|
|
if (d!=svdiff+diffsiz)
|
|
|
|
i|=2;
|
|
|
|
if (i)
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("sv_readdiff: p=%p, svsnapshot+svsnapsiz=%p; d=%p, svdiff+diffsiz=%p",
|
2010-02-23 18:13:46 +00:00
|
|
|
p, svsnapshot+svsnapsiz, d, svdiff+diffsiz);
|
|
|
|
return i;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SVGM data description
|
|
|
|
static void sv_postudload()
|
|
|
|
{
|
2011-12-25 15:34:06 +00:00
|
|
|
#if 1
|
2019-11-09 18:15:03 +00:00
|
|
|
m_level_number = ud.level_number;
|
2018-10-25 23:31:45 +00:00
|
|
|
ud.m_volume_number = ud.volume_number;
|
|
|
|
ud.m_player_skill = ud.player_skill;
|
|
|
|
ud.m_respawn_monsters = ud.respawn_monsters;
|
|
|
|
ud.m_respawn_items = ud.respawn_items;
|
2010-01-24 23:33:17 +00:00
|
|
|
ud.m_respawn_inventory = ud.respawn_inventory;
|
2018-10-25 23:31:45 +00:00
|
|
|
ud.m_monsters_off = ud.monsters_off;
|
2019-11-09 18:15:03 +00:00
|
|
|
m_coop = ud.coop;
|
|
|
|
m_marker = ud.marker;
|
|
|
|
m_ffire = ud.ffire;
|
|
|
|
m_noexits = ud.noexits;
|
2010-02-13 21:46:42 +00:00
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
//static int32_t lockclock_dummy;
|
|
|
|
|
|
|
|
static void sv_postactordata()
|
|
|
|
{
|
2017-06-23 03:59:39 +00:00
|
|
|
#ifdef POLYMER
|
2018-10-25 23:33:40 +00:00
|
|
|
for (auto & i : actor)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-10-25 23:33:40 +00:00
|
|
|
i.lightptr = NULL;
|
|
|
|
i.lightId = -1;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
2017-06-23 03:59:39 +00:00
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sv_preanimateptrsave()
|
|
|
|
{
|
2016-08-27 01:42:01 +00:00
|
|
|
G_Util_PtrToIdx(g_animatePtr, g_animateCnt, sector, P2I_FWD);
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
static void sv_postanimateptr()
|
|
|
|
{
|
2016-08-27 01:42:01 +00:00
|
|
|
G_Util_PtrToIdx(g_animatePtr, g_animateCnt, sector, P2I_BACK);
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
2015-03-24 00:40:55 +00:00
|
|
|
static void sv_preprojectilesave()
|
|
|
|
{
|
2018-09-28 04:27:48 +00:00
|
|
|
savegame_projectilecnt = 0;
|
2018-09-29 01:54:52 +00:00
|
|
|
Bmemset(savegame_projectiles, 0, sizeof(savegame_projectiles));
|
2018-09-28 04:27:48 +00:00
|
|
|
|
2018-10-25 23:33:40 +00:00
|
|
|
for (auto & i : g_tile)
|
|
|
|
if (i.proj)
|
2018-09-28 04:27:48 +00:00
|
|
|
savegame_projectilecnt++;
|
|
|
|
|
2018-09-29 01:54:52 +00:00
|
|
|
if (savegame_projectilecnt > 0)
|
2018-09-28 04:27:48 +00:00
|
|
|
savegame_projectiledata = (projectile_t *) Xrealloc(savegame_projectiledata, sizeof(projectile_t) * savegame_projectilecnt);
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
for (int i = 0, cnt = 0; i < MAXTILES; i++)
|
2015-03-24 00:40:55 +00:00
|
|
|
{
|
|
|
|
if (g_tile[i].proj)
|
|
|
|
{
|
2018-09-28 04:27:48 +00:00
|
|
|
savegame_projectiles[i>>3] |= 1<<(i&7);
|
|
|
|
Bmemcpy(&savegame_projectiledata[cnt++], g_tile[i].proj, sizeof(projectile_t));
|
2015-03-24 00:40:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sv_postprojectilesave()
|
|
|
|
{
|
2018-09-29 01:54:52 +00:00
|
|
|
DO_FREE_AND_NULL(savegame_projectiledata);
|
2015-03-24 00:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sv_preprojectileload()
|
|
|
|
{
|
2018-09-29 01:54:52 +00:00
|
|
|
savegame_projectilecnt = 0;
|
2015-05-16 11:56:49 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
for (int i = 0; i < MAXTILES; i++)
|
2018-09-28 04:27:48 +00:00
|
|
|
{
|
2019-08-04 02:51:50 +00:00
|
|
|
if (savegame_projectiles[i>>3] & pow2char[i&7])
|
2018-09-29 01:54:52 +00:00
|
|
|
savegame_projectilecnt++;
|
2018-09-28 04:27:48 +00:00
|
|
|
}
|
|
|
|
|
2018-09-29 01:54:52 +00:00
|
|
|
if (savegame_projectilecnt > 0)
|
|
|
|
savegame_projectiledata = (projectile_t *) Xrealloc(savegame_projectiledata, sizeof(projectile_t) * savegame_projectilecnt);
|
2015-03-24 00:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sv_postprojectileload()
|
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
for (int i = 0, cnt = 0; i < MAXTILES; i++)
|
2015-03-24 00:40:55 +00:00
|
|
|
{
|
2019-08-04 02:51:50 +00:00
|
|
|
if (savegame_projectiles[i>>3] & pow2char[i&7])
|
2015-03-24 00:40:55 +00:00
|
|
|
{
|
2015-05-16 11:56:49 +00:00
|
|
|
C_AllocProjectile(i);
|
2018-09-28 04:27:48 +00:00
|
|
|
Bmemcpy(g_tile[i].proj, &savegame_projectiledata[cnt++], sizeof(projectile_t));
|
2015-03-24 00:40:55 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-29 01:54:52 +00:00
|
|
|
|
|
|
|
DO_FREE_AND_NULL(savegame_projectiledata);
|
2015-03-24 00:40:55 +00:00
|
|
|
}
|
|
|
|
|
2010-01-24 23:33:17 +00:00
|
|
|
static void sv_restsave()
|
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
uint8_t * mem = savegame_restdata;
|
2010-01-24 23:33:17 +00:00
|
|
|
DukePlayer_t dummy_ps;
|
|
|
|
|
|
|
|
Bmemset(&dummy_ps, 0, sizeof(DukePlayer_t));
|
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
#define CPDAT(ptr,sz) do { Bmemcpy(mem, ptr, sz), mem+=sz ; } while (0)
|
|
|
|
for (int i = 0; i < MAXPLAYERS; i++)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
|
|
|
CPDAT(g_player[i].user_name, 32);
|
|
|
|
CPDAT(&g_player[i].pcolor, sizeof(g_player[0].pcolor));
|
|
|
|
CPDAT(&g_player[i].pteam, sizeof(g_player[0].pteam));
|
|
|
|
CPDAT(&g_player[i].frags[0], sizeof(g_player[0].frags));
|
2018-10-25 23:31:45 +00:00
|
|
|
CPDAT(g_player[i].ps ? g_player[i].ps : &dummy_ps, sizeof(DukePlayer_t));
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2018-10-25 23:31:45 +00:00
|
|
|
Bassert((savegame_restdata + SVARDATALEN) - mem == 0);
|
2010-02-23 18:13:46 +00:00
|
|
|
#undef CPDAT
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
static void sv_restload()
|
|
|
|
{
|
2018-10-25 23:31:45 +00:00
|
|
|
uint8_t * mem = savegame_restdata;
|
2010-01-24 23:33:17 +00:00
|
|
|
DukePlayer_t dummy_ps;
|
|
|
|
|
2010-02-23 18:13:46 +00:00
|
|
|
#define CPDAT(ptr,sz) Bmemcpy(ptr, mem, sz), mem+=sz
|
2018-10-25 23:31:45 +00:00
|
|
|
for (int i = 0; i < MAXPLAYERS; i++)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
|
|
|
CPDAT(g_player[i].user_name, 32);
|
|
|
|
CPDAT(&g_player[i].pcolor, sizeof(g_player[0].pcolor));
|
|
|
|
CPDAT(&g_player[i].pteam, sizeof(g_player[0].pteam));
|
|
|
|
CPDAT(&g_player[i].frags[0], sizeof(g_player[0].frags));
|
2018-10-25 23:31:45 +00:00
|
|
|
CPDAT(g_player[i].ps ? g_player[i].ps : &dummy_ps, sizeof(DukePlayer_t));
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
2010-02-23 18:13:46 +00:00
|
|
|
#undef CPDAT
|
2018-02-25 01:18:29 +00:00
|
|
|
|
2018-10-07 05:19:50 +00:00
|
|
|
if (g_player[myconnectindex].ps)
|
2019-10-21 22:05:21 +00:00
|
|
|
g_player[myconnectindex].ps->auto_aim = cl_autoaim;
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
2011-12-25 15:32:00 +00:00
|
|
|
#ifdef DEBUGGINGAIDS
|
2020-04-11 21:45:45 +00:00
|
|
|
# define PRINTSIZE(name) do { if (mem) Printf(name ": %d\n", (int32_t)(mem-tmem)); \
|
|
|
|
Printf(name ": %d ms\n", timerGetTicks()-t); t=timerGetTicks(); tmem=mem; } while (0)
|
2011-12-25 15:32:00 +00:00
|
|
|
#else
|
2011-12-28 20:33:54 +00:00
|
|
|
# define PRINTSIZE(name) do { } while (0)
|
2011-12-25 15:32:00 +00:00
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2013-05-20 19:31:42 +00:00
|
|
|
#ifdef LUNATIC
|
2013-10-27 21:12:22 +00:00
|
|
|
// <levelnum>: if we're not serializing for a mapstate, -1
|
|
|
|
// otherwise, the linearized level number
|
|
|
|
LUNATIC_CB const char *(*El_SerializeGamevars)(int32_t *slenptr, int32_t levelnum);
|
2013-05-20 19:31:42 +00:00
|
|
|
#endif
|
|
|
|
|
2019-11-07 23:26:14 +00:00
|
|
|
static uint8_t *dosaveplayer2(FileWriter &fil, uint8_t *mem)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2011-12-28 20:33:54 +00:00
|
|
|
#ifdef DEBUGGINGAIDS
|
2010-01-24 23:33:17 +00:00
|
|
|
uint8_t *tmem = mem;
|
2018-04-12 21:02:51 +00:00
|
|
|
int32_t t=timerGetTicks();
|
2011-12-28 20:33:54 +00:00
|
|
|
#endif
|
2019-11-07 23:26:14 +00:00
|
|
|
mem=writespecdata(svgm_udnetw, &fil, mem); // user settings, players & net
|
2011-12-25 15:32:00 +00:00
|
|
|
PRINTSIZE("ud");
|
2019-11-07 23:26:14 +00:00
|
|
|
mem=writespecdata(svgm_secwsp, &fil, mem); // sector, wall, sprite
|
2011-12-25 15:32:00 +00:00
|
|
|
PRINTSIZE("sws");
|
2019-11-07 23:26:14 +00:00
|
|
|
mem=writespecdata(svgm_script, &fil, mem); // script
|
2013-06-20 18:31:47 +00:00
|
|
|
PRINTSIZE("script");
|
2019-11-07 23:26:14 +00:00
|
|
|
mem=writespecdata(svgm_anmisc, &fil, mem); // animates, quotes & misc.
|
2013-06-20 18:31:47 +00:00
|
|
|
PRINTSIZE("animisc");
|
|
|
|
|
|
|
|
#if !defined LUNATIC
|
2016-08-27 01:40:35 +00:00
|
|
|
Gv_WriteSave(fil); // gamevars
|
2016-01-11 05:05:38 +00:00
|
|
|
mem=writespecdata((const dataspec_t *)svgm_vars, 0, mem);
|
2013-06-20 18:31:47 +00:00
|
|
|
PRINTSIZE("vars");
|
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-10-20 19:04:55 +00:00
|
|
|
static int32_t doloadplayer2(FileReader &fil, uint8_t **memptr)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2011-12-28 20:33:54 +00:00
|
|
|
uint8_t *mem = memptr ? *memptr : NULL;
|
|
|
|
#ifdef DEBUGGINGAIDS
|
|
|
|
uint8_t *tmem=mem;
|
2018-04-12 21:02:51 +00:00
|
|
|
int32_t t=timerGetTicks();
|
2011-12-28 20:33:54 +00:00
|
|
|
#endif
|
2019-10-20 19:04:55 +00:00
|
|
|
if (readspecdata(svgm_udnetw, &fil, &mem)) return -2;
|
2011-12-25 15:32:00 +00:00
|
|
|
PRINTSIZE("ud");
|
2019-10-20 19:04:55 +00:00
|
|
|
if (readspecdata(svgm_secwsp, &fil, &mem)) return -4;
|
2011-12-25 15:32:00 +00:00
|
|
|
PRINTSIZE("sws");
|
2019-10-20 19:04:55 +00:00
|
|
|
if (readspecdata(svgm_script, &fil, &mem)) return -5;
|
2011-12-25 15:32:00 +00:00
|
|
|
PRINTSIZE("script");
|
2019-10-20 19:04:55 +00:00
|
|
|
if (readspecdata(svgm_anmisc, &fil, &mem)) return -6;
|
2011-12-25 15:32:00 +00:00
|
|
|
PRINTSIZE("animisc");
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2013-05-19 19:29:18 +00:00
|
|
|
#if !defined LUNATIC
|
2017-10-31 02:09:25 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if ((i = Gv_ReadSave(fil))) return i;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2011-12-21 18:42:12 +00:00
|
|
|
if (mem)
|
2011-12-25 15:32:00 +00:00
|
|
|
{
|
2011-12-25 15:34:06 +00:00
|
|
|
int32_t i;
|
|
|
|
|
2011-12-25 15:32:00 +00:00
|
|
|
sv_makevarspec();
|
2011-12-21 18:42:12 +00:00
|
|
|
for (i=1; svgm_vars[i].flags!=DS_END; i++)
|
|
|
|
{
|
|
|
|
Bmemcpy(mem, svgm_vars[i].ptr, svgm_vars[i].size*svgm_vars[i].cnt); // careful! works because there are no DS_DYNAMIC's!
|
|
|
|
mem += svgm_vars[i].size*svgm_vars[i].cnt;
|
|
|
|
}
|
2011-12-25 15:32:00 +00:00
|
|
|
}
|
2011-12-28 20:33:54 +00:00
|
|
|
PRINTSIZE("vars");
|
2013-05-19 19:29:18 +00:00
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
if (memptr)
|
|
|
|
*memptr = mem;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t sv_updatestate(int32_t frominit)
|
|
|
|
{
|
|
|
|
uint8_t *p = svsnapshot, *pbeg=p;
|
|
|
|
|
|
|
|
if (frominit)
|
|
|
|
Bmemcpy(svsnapshot, svinitsnap, svsnapsiz);
|
|
|
|
|
2019-10-20 19:04:55 +00:00
|
|
|
if (readspecdata(svgm_udnetw, nullptr, &p)) return -2;
|
|
|
|
if (readspecdata(svgm_secwsp, nullptr, &p)) return -4;
|
|
|
|
if (readspecdata(svgm_script, nullptr, &p)) return -5;
|
|
|
|
if (readspecdata(svgm_anmisc, nullptr, &p)) return -6;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2013-05-19 19:29:18 +00:00
|
|
|
#if !defined LUNATIC
|
2019-10-20 19:04:55 +00:00
|
|
|
if (readspecdata((const dataspec_t *)svgm_vars, nullptr, &p)) return -8;
|
2013-05-19 19:29:18 +00:00
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
if (p != pbeg+svsnapsiz)
|
2011-12-25 15:32:00 +00:00
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("sv_updatestate: ptr-(snapshot end)=%d\n", (int32_t)(p-(pbeg+svsnapsiz)));
|
2011-12-25 15:32:00 +00:00
|
|
|
return -9;
|
|
|
|
}
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
if (frominit)
|
2011-12-25 15:34:06 +00:00
|
|
|
postloadplayer(0);
|
|
|
|
#ifdef POLYMER
|
2018-04-12 21:03:12 +00:00
|
|
|
if (videoGetRenderMode() == REND_POLYMER)
|
2011-12-25 15:34:06 +00:00
|
|
|
polymer_resetlights(); // must do it after polymer_loadboard() !!!
|
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
static void postloadplayer(int32_t savegamep)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
|
|
|
int32_t i;
|
2011-12-25 15:34:06 +00:00
|
|
|
|
2010-01-24 23:33:17 +00:00
|
|
|
//1
|
|
|
|
if (g_player[myconnectindex].ps->over_shoulder_on != 0)
|
|
|
|
{
|
2013-01-19 18:28:32 +00:00
|
|
|
CAMERADIST = 0;
|
|
|
|
CAMERACLOCK = 0;
|
2010-01-24 23:33:17 +00:00
|
|
|
g_player[myconnectindex].ps->over_shoulder_on = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//2
|
2011-12-25 15:34:06 +00:00
|
|
|
screenpeek = myconnectindex;
|
|
|
|
|
|
|
|
//2.5
|
|
|
|
if (savegamep)
|
|
|
|
{
|
2019-11-28 02:18:58 +00:00
|
|
|
Bmemset(gotpic, 0, sizeof(gotpic));
|
2011-12-25 15:34:06 +00:00
|
|
|
S_ClearSoundLocks();
|
|
|
|
G_CacheMapData();
|
2019-12-26 12:04:29 +00:00
|
|
|
Mus_ResumeSaved();
|
2011-12-25 15:34:06 +00:00
|
|
|
|
|
|
|
g_player[myconnectindex].ps->gm = MODE_GAME;
|
|
|
|
ud.recstat = 0;
|
|
|
|
|
|
|
|
if (g_player[myconnectindex].ps->jetpack_on)
|
|
|
|
A_PlaySound(DUKE_JETPACK_IDLE, g_player[myconnectindex].ps->i);
|
|
|
|
}
|
|
|
|
|
2010-01-24 23:33:17 +00:00
|
|
|
//3
|
|
|
|
P_UpdateScreenPal(g_player[myconnectindex].ps);
|
2012-02-02 17:34:16 +00:00
|
|
|
g_restorePalette = -1;
|
2011-12-25 15:34:06 +00:00
|
|
|
|
|
|
|
//3.5
|
|
|
|
if (savegamep)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2012-11-13 10:50:06 +00:00
|
|
|
for (SPRITES_OF(STAT_FX, i))
|
2012-10-14 22:13:49 +00:00
|
|
|
if (sprite[i].picnum == MUSICANDSFX)
|
|
|
|
{
|
2019-11-02 20:21:48 +00:00
|
|
|
T2(i) = SoundEnabled();
|
2016-08-27 01:40:35 +00:00
|
|
|
T1(i) = 0;
|
2012-10-14 22:13:49 +00:00
|
|
|
}
|
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
G_UpdateScreenArea();
|
|
|
|
FX_SetReverb(0);
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
2011-12-25 15:34:06 +00:00
|
|
|
|
|
|
|
//4
|
|
|
|
if (savegamep)
|
2010-01-24 23:33:17 +00:00
|
|
|
{
|
2018-11-18 18:13:55 +00:00
|
|
|
#ifndef EDUKE32_STANDALONE
|
2019-10-27 12:40:24 +00:00
|
|
|
if (adult_lockout)
|
2011-12-25 15:34:06 +00:00
|
|
|
{
|
2016-08-27 01:42:01 +00:00
|
|
|
for (i=0; i<g_animWallCnt; i++)
|
2012-01-28 14:38:23 +00:00
|
|
|
switch (DYNAMICTILEMAP(wall[animwall[i].wallnum].picnum))
|
2011-12-25 15:34:06 +00:00
|
|
|
{
|
|
|
|
case FEMPIC1__STATIC:
|
|
|
|
wall[animwall[i].wallnum].picnum = BLANKSCREEN;
|
|
|
|
break;
|
|
|
|
case FEMPIC2__STATIC:
|
|
|
|
case FEMPIC3__STATIC:
|
|
|
|
wall[animwall[i].wallnum].picnum = SCREENBREAK6;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-01-05 20:48:37 +00:00
|
|
|
#if 0
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i=0; i<g_numAnimWalls; i++)
|
|
|
|
if (wall[animwall[i].wallnum].extra >= 0)
|
|
|
|
wall[animwall[i].wallnum].picnum = wall[animwall[i].wallnum].extra;
|
|
|
|
}
|
2018-11-18 18:13:55 +00:00
|
|
|
#endif
|
2012-01-05 20:48:37 +00:00
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//5
|
2011-07-29 22:07:28 +00:00
|
|
|
G_ResetInterpolations();
|
2010-01-24 23:33:17 +00:00
|
|
|
|
|
|
|
//6
|
|
|
|
g_showShareware = 0;
|
2011-12-25 15:34:06 +00:00
|
|
|
if (savegamep)
|
|
|
|
everyothertime = 0;
|
2011-12-21 18:42:12 +00:00
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
//7
|
2010-01-24 23:33:17 +00:00
|
|
|
for (i=0; i<MAXPLAYERS; i++)
|
2011-12-21 18:42:12 +00:00
|
|
|
g_player[i].playerquitflag = 1;
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2011-12-25 15:34:06 +00:00
|
|
|
// ----------
|
|
|
|
|
|
|
|
//7.5
|
|
|
|
if (savegamep)
|
|
|
|
{
|
|
|
|
ready2send = 1;
|
|
|
|
G_ClearFIFO();
|
|
|
|
Net_WaitForServer();
|
|
|
|
}
|
|
|
|
|
|
|
|
//8
|
|
|
|
// if (savegamep) ?
|
2013-07-04 19:38:46 +00:00
|
|
|
#ifdef LUNATIC
|
|
|
|
G_ResetTimers(1);
|
|
|
|
#else
|
|
|
|
G_ResetTimers(0);
|
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2019-08-01 06:50:01 +00:00
|
|
|
#ifdef USE_STRUCT_TRACKERS
|
|
|
|
Bmemset(sectorchanged, 0, sizeof(sectorchanged));
|
|
|
|
Bmemset(spritechanged, 0, sizeof(spritechanged));
|
|
|
|
Bmemset(wallchanged, 0, sizeof(wallchanged));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef USE_OPENGL
|
|
|
|
Polymost_prepare_loadboard();
|
|
|
|
#endif
|
|
|
|
|
2010-01-24 23:33:17 +00:00
|
|
|
#ifdef POLYMER
|
2011-12-25 15:34:06 +00:00
|
|
|
//9
|
2018-04-12 21:03:12 +00:00
|
|
|
if (videoGetRenderMode() == REND_POLYMER)
|
2010-01-25 01:11:34 +00:00
|
|
|
polymer_loadboard();
|
2010-01-24 23:33:17 +00:00
|
|
|
|
2018-04-12 21:03:12 +00:00
|
|
|
// this light pointer nulling needs to be outside the videoGetRenderMode check
|
2011-12-25 15:34:06 +00:00
|
|
|
// because we might be loading the savegame using another renderer but
|
|
|
|
// change to Polymer later
|
|
|
|
for (i=0; i<MAXSPRITES; i++)
|
|
|
|
{
|
|
|
|
actor[i].lightptr = NULL;
|
|
|
|
actor[i].lightId = -1;
|
|
|
|
}
|
2017-06-23 03:59:39 +00:00
|
|
|
#endif
|
2010-01-24 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////// END GENERIC SAVING/LOADING SYSTEM //////////
|
2019-09-21 20:53:00 +00:00
|
|
|
END_DUKE_NS
|