Rev 4990 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4990 | Rev 5069 | ||
---|---|---|---|
1 | //-------------------------------------------------------------------------
|
1 | //-------------------------------------------------------------------------
|
2 | /*
|
2 | /*
|
3 | Copyright (C) 2010 EDuke32 developers and contributors
|
3 | Copyright (C) 2010 EDuke32 developers and contributors
|
4 | 4 | ||
5 | This file is part of EDuke32.
|
5 | This file is part of EDuke32.
|
6 | 6 | ||
7 | EDuke32 is free software; you can redistribute it and/or
|
7 | EDuke32 is free software; you can redistribute it and/or
|
8 | modify it under the terms of the GNU General Public License version 2
|
8 | modify it under the terms of the GNU General Public License version 2
|
9 | as published by the Free Software Foundation.
|
9 | as published by the Free Software Foundation.
|
10 | 10 | ||
11 | This program is distributed in the hope that it will be useful,
|
11 | This program is distributed in the hope that it will be useful,
|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
14 | 14 | ||
15 | See the GNU General Public License for more details.
|
15 | See the GNU General Public License for more details.
|
16 | 16 | ||
17 | You should have received a copy of the GNU General Public License
|
17 | You should have received a copy of the GNU General Public License
|
18 | along with this program; if not, write to the Free Software
|
18 | along with this program; if not, write to the Free Software
|
19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
20 | */
|
20 | */
|
21 | //-------------------------------------------------------------------------
|
21 | //-------------------------------------------------------------------------
|
22 | 22 | ||
23 | #include "duke3d.h"
|
23 | #include "duke3d.h"
|
24 | #include "premap.h"
|
24 | #include "premap.h"
|
25 | #include "menus.h" // menutext
|
25 | #include "menus.h" // menutext
|
26 | #include "prlights.h"
|
26 | #include "prlights.h"
|
27 | #include "savegame.h"
|
27 | #include "savegame.h"
|
28 | #ifdef LUNATIC
|
28 | #ifdef LUNATIC
|
29 | # include "lunatic_game.h"
|
29 | # include "lunatic_game.h"
|
30 | static int32_t g_savedOK; |
30 | static int32_t g_savedOK; |
31 | const char *g_failedVarname; |
31 | const char *g_failedVarname; |
32 | #endif
|
32 | #endif
|
33 | 33 | ||
34 | extern char *bitptr; |
34 | extern char *bitptr; |
35 | 35 | ||
36 | uint8_t g_oldverSavegame[MAXSAVEGAMES]; |
36 | uint8_t g_oldverSavegame[MAXSAVEGAMES]; |
37 | 37 | ||
38 | #define BITPTR_POINTER 1
|
38 | #define BITPTR_POINTER 1
|
39 | 39 | ||
40 | // For storing pointers in files.
|
40 | // For storing pointers in files.
|
41 | // back_p==0: ptr -> "small int"
|
41 | // back_p==0: ptr -> "small int"
|
42 | // back_p==1: "small int" -> ptr
|
42 | // back_p==1: "small int" -> ptr
|
43 | //
|
43 | //
|
44 | // mode: see enum in savegame.h
|
44 | // mode: see enum in savegame.h
|
45 | void G_Util_PtrToIdx(void *ptr, int32_t count, const void *base, int32_t mode) |
45 | void G_Util_PtrToIdx(void *ptr, int32_t const count, const void *base, int32_t const mode) |
46 | {
|
46 | {
|
47 | intptr_t *iptr = (intptr_t *)ptr; |
47 | intptr_t *iptr = (intptr_t *)ptr; |
48 | intptr_t const ibase = (intptr_t)base; |
48 | intptr_t const ibase = (intptr_t)base; |
49 | int32_t const onlynon0_p = mode&P2I_ONLYNON0_BIT; |
49 | int32_t const onlynon0_p = mode&P2I_ONLYNON0_BIT; |
50 | 50 | ||
51 | // TODO: convert to proper offsets/indices for (a step towards) cross-
|
51 | // TODO: convert to proper offsets/indices for (a step towards) cross-
|
52 | // compatibility between 32- and 64-bit systems in the netplay.
|
52 | // compatibility between 32- and 64-bit systems in the netplay.
|
53 | // REMEMBER to bump BYTEVERSION then.
|
53 | // REMEMBER to bump BYTEVERSION then.
|
54 | 54 | ||
55 | // WARNING: C std doesn't say that bit pattern of NULL is necessarily 0!
|
55 | // WARNING: C std doesn't say that bit pattern of NULL is necessarily 0!
|
56 | if ((mode & P2I_BACK_BIT) == 0) |
56 | if ((mode & P2I_BACK_BIT) == 0) |
57 | {
|
57 | {
|
58 | for (int i = 0; i < count; i++) |
58 | for (int i = 0; i < count; i++) |
59 | if (!onlynon0_p || iptr[i]) |
59 | if (!onlynon0_p || iptr[i]) |
60 | iptr[i] -= ibase; |
60 | iptr[i] -= ibase; |
61 | }
|
61 | }
|
62 | else
|
62 | else
|
63 | {
|
63 | {
|
64 | for (int i = 0; i < count; i++) |
64 | for (int i = 0; i < count; i++) |
65 | if (!onlynon0_p || iptr[i]) |
65 | if (!onlynon0_p || iptr[i]) |
66 | iptr[i] += ibase; |
66 | iptr[i] += ibase; |
67 | }
|
67 | }
|
68 | }
|
68 | }
|
69 | 69 | ||
70 | void G_Util_PtrToIdx2(void *ptr, int32_t count, size_t stride, const void *base, int32_t mode) |
70 | void G_Util_PtrToIdx2(void *ptr, int32_t const count, size_t const stride, const void *base, int32_t const mode) |
71 | {
|
71 | {
|
72 | uint8_t *iptr = (uint8_t *)ptr; |
72 | uint8_t *iptr = (uint8_t *)ptr; |
73 | intptr_t const ibase = (intptr_t)base; |
73 | intptr_t const ibase = (intptr_t)base; |
74 | int32_t const onlynon0_p = mode&P2I_ONLYNON0_BIT; |
74 | int32_t const onlynon0_p = mode&P2I_ONLYNON0_BIT; |
75 | 75 | ||
76 | if ((mode & P2I_BACK_BIT) == 0) |
76 | if ((mode & P2I_BACK_BIT) == 0) |
77 | {
|
77 | {
|
78 | for (int i = 0; i < count; ++i) |
78 | for (int i = 0; i < count; ++i) |
79 | {
|
79 | {
|
80 | if (!onlynon0_p || *(intptr_t *)iptr) |
80 | if (!onlynon0_p || *(intptr_t *)iptr) |
81 | *(intptr_t *)iptr -= ibase; |
81 | *(intptr_t *)iptr -= ibase; |
82 | 82 | ||
83 | iptr += stride; |
83 | iptr += stride; |
84 | }
|
84 | }
|
85 | }
|
85 | }
|
86 | else
|
86 | else
|
87 | {
|
87 | {
|
88 | for (int i = 0; i < count; ++i) |
88 | for (int i = 0; i < count; ++i) |
89 | {
|
89 | {
|
90 | if (!onlynon0_p || *(intptr_t *)iptr) |
90 | if (!onlynon0_p || *(intptr_t *)iptr) |
91 | *(intptr_t *)iptr += ibase; |
91 | *(intptr_t *)iptr += ibase; |
92 | 92 | ||
93 | iptr += stride; |
93 | iptr += stride; |
94 | }
|
94 | }
|
95 | }
|
95 | }
|
96 | }
|
96 | }
|
97 | 97 | ||
98 | // TODO: sync with TROR special interpolations? (e.g. upper floor of subway)
|
98 | // TODO: sync with TROR special interpolations? (e.g. upper floor of subway)
|
99 | void G_ResetInterpolations(void) |
99 | void G_ResetInterpolations(void) |
100 | {
|
100 | {
|
101 | int32_t k, i; |
101 | int32_t k, i; |
102 | 102 | ||
103 | g_numInterpolations = 0; |
103 | g_numInterpolations = 0; |
104 | startofdynamicinterpolations = 0; |
104 | startofdynamicinterpolations = 0; |
105 | 105 | ||
106 | k = headspritestat[STAT_EFFECTOR]; |
106 | k = headspritestat[STAT_EFFECTOR]; |
107 | while (k >= 0) |
107 | while (k >= 0) |
108 | {
|
108 | {
|
109 | switch (sprite[k].lotag) |
109 | switch (sprite[k].lotag) |
110 | {
|
110 | {
|
111 | case SE_31_FLOOR_RISE_FALL: |
111 | case SE_31_FLOOR_RISE_FALL: |
112 | G_SetInterpolation(§or[sprite[k].sectnum].floorz); |
112 | G_SetInterpolation(§or[sprite[k].sectnum].floorz); |
113 | break; |
113 | break; |
114 | case SE_32_CEILING_RISE_FALL: |
114 | case SE_32_CEILING_RISE_FALL: |
115 | G_SetInterpolation(§or[sprite[k].sectnum].ceilingz); |
115 | G_SetInterpolation(§or[sprite[k].sectnum].ceilingz); |
116 | break; |
116 | break; |
117 | case SE_17_WARP_ELEVATOR: |
117 | case SE_17_WARP_ELEVATOR: |
118 | case SE_25_PISTON: |
118 | case SE_25_PISTON: |
119 | G_SetInterpolation(§or[sprite[k].sectnum].floorz); |
119 | G_SetInterpolation(§or[sprite[k].sectnum].floorz); |
120 | G_SetInterpolation(§or[sprite[k].sectnum].ceilingz); |
120 | G_SetInterpolation(§or[sprite[k].sectnum].ceilingz); |
121 | break; |
121 | break; |
122 | case SE_0_ROTATING_SECTOR: |
122 | case SE_0_ROTATING_SECTOR: |
123 | case SE_5: |
123 | case SE_5: |
124 | case SE_6_SUBWAY: |
124 | case SE_6_SUBWAY: |
125 | case SE_11_SWINGING_DOOR: |
125 | case SE_11_SWINGING_DOOR: |
126 | case SE_14_SUBWAY_CAR: |
126 | case SE_14_SUBWAY_CAR: |
127 | case SE_15_SLIDING_DOOR: |
127 | case SE_15_SLIDING_DOOR: |
128 | case SE_16_REACTOR: |
128 | case SE_16_REACTOR: |
129 | case SE_26: |
129 | case SE_26: |
130 | case SE_30_TWO_WAY_TRAIN: |
130 | case SE_30_TWO_WAY_TRAIN: |
131 | Sect_SetInterpolation(sprite[k].sectnum); |
131 | Sect_SetInterpolation(sprite[k].sectnum); |
132 | break; |
132 | break; |
133 | }
|
133 | }
|
134 | 134 | ||
135 | k = nextspritestat[k]; |
135 | k = nextspritestat[k]; |
136 | }
|
136 | }
|
137 | 137 | ||
138 | for (i=g_numInterpolations-1; i>=0; i--) bakipos[i] = *curipos[i]; |
138 | for (i=g_numInterpolations-1; i>=0; i--) bakipos[i] = *curipos[i]; |
139 | for (i = g_animateCount-1; i>=0; i--) |
139 | for (i = g_animateCount-1; i>=0; i--) |
140 | G_SetInterpolation(animateptr[i]); |
140 | G_SetInterpolation(animateptr[i]); |
141 | }
|
141 | }
|
142 | 142 | ||
143 | void ReadSaveGameHeaders(void) |
143 | void ReadSaveGameHeaders(void) |
144 | {
|
144 | {
|
145 | char fn[16]; |
145 | char fn[16]; |
146 | int32_t fil, i; |
146 | int32_t fil, i; |
147 | 147 | ||
148 | savehead_t h;
|
148 | savehead_t h;
|
149 | 149 | ||
150 | EDUKE32_STATIC_ASSERT(sizeof(h.savename) == sizeof(ud.savegame[0])); |
150 | EDUKE32_STATIC_ASSERT(sizeof(h.savename) == sizeof(ud.savegame[0])); |
151 | 151 | ||
152 | Bstrcpy(fn, "dukesav0.esv"); |
152 | Bstrcpy(fn, "dukesav0.esv"); |
153 | 153 | ||
154 | for (i=0; i<MAXSAVEGAMES; i++) |
154 | for (i=0; i<MAXSAVEGAMES; i++) |
155 | {
|
155 | {
|
156 | int32_t k; |
156 | int32_t k; |
157 | 157 | ||
158 | fn[7] = i + '0'; |
158 | fn[7] = i + '0'; |
159 | fil = kopen4loadfrommod(fn, 0); |
159 | fil = kopen4loadfrommod(fn, 0); |
160 | if (fil == -1) |
160 | if (fil == -1) |
161 | {
|
161 | {
|
162 | Bmemset(ud.savegame[i], 0, sizeof(ud.savegame[i])); |
162 | Bmemset(ud.savegame[i], 0, sizeof(ud.savegame[i])); |
163 | continue; |
163 | continue; |
164 | }
|
164 | }
|
165 | 165 | ||
166 | k = sv_loadheader(fil, i, &h); |
166 | k = sv_loadheader(fil, i, &h); |
167 | if (k) |
167 | if (k) |
168 | {
|
168 | {
|
169 | // old version, signal to menu code
|
169 | // old version, signal to menu code
|
170 | if (k==2 || k==3) |
170 | if (k==2 || k==3) |
171 | g_oldverSavegame[i] = 1; |
171 | g_oldverSavegame[i] = 1; |
172 | // else h.savename is all zeros (fatal failure, like wrong header
|
172 | // else h.savename is all zeros (fatal failure, like wrong header
|
173 | // magic or too short header)
|
173 | // magic or too short header)
|
174 | }
|
174 | }
|
175 | 175 | ||
176 | Bmemcpy(ud.savegame[i], h.savename, sizeof(ud.savegame[i])); |
176 | Bmemcpy(ud.savegame[i], h.savename, sizeof(ud.savegame[i])); |
177 | 177 | ||
178 | kclose(fil); |
178 | kclose(fil); |
179 | }
|
179 | }
|
180 | }
|
180 | }
|
181 | 181 | ||
182 | int32_t G_LoadSaveHeaderNew(int32_t spot, savehead_t *saveh) |
182 | int32_t G_LoadSaveHeaderNew(int32_t spot, savehead_t *saveh) |
183 | {
|
183 | {
|
184 | char fn[16]; |
184 | char fn[16]; |
185 | int32_t fil, screenshotofs, i; |
185 | int32_t fil, screenshotofs, i; |
186 | 186 | ||
187 | Bassert(spot < MAXSAVEGAMES); |
187 | Bassert(spot < MAXSAVEGAMES); |
188 | 188 | ||
189 | Bstrcpy(fn, "dukesav0.esv"); |
189 | Bstrcpy(fn, "dukesav0.esv"); |
190 | fn[7] = spot + '0'; |
190 | fn[7] = spot + '0'; |
191 | 191 | ||
192 | fil = kopen4loadfrommod(fn, 0); |
192 | fil = kopen4loadfrommod(fn, 0); |
193 | if (fil == -1) |
193 | if (fil == -1) |
194 | return -1; |
194 | return -1; |
195 | 195 | ||
196 | i = sv_loadheader(fil, spot, saveh); |
196 | i = sv_loadheader(fil, spot, saveh); |
197 | if (i && (i != 2 && i != 3)) |
197 | if (i && (i != 2 && i != 3)) |
198 | goto corrupt; |
198 | goto corrupt; |
199 | 199 | ||
200 | if (kread(fil, &screenshotofs, 4) != 4) |
200 | if (kread(fil, &screenshotofs, 4) != 4) |
201 | goto corrupt; |
201 | goto corrupt; |
202 | 202 | ||
203 | walock[TILE_LOADSHOT] = 255; |
203 | walock[TILE_LOADSHOT] = 255; |
204 | if (waloff[TILE_LOADSHOT] == 0) |
204 | if (waloff[TILE_LOADSHOT] == 0) |
205 | allocache(&waloff[TILE_LOADSHOT], 320*200, &walock[TILE_LOADSHOT]); |
205 | allocache(&waloff[TILE_LOADSHOT], 320*200, &walock[TILE_LOADSHOT]); |
206 | tilesiz[TILE_LOADSHOT].x = 200; |
206 | tilesiz[TILE_LOADSHOT].x = 200; |
207 | tilesiz[TILE_LOADSHOT].y = 320; |
207 | tilesiz[TILE_LOADSHOT].y = 320; |
208 | if (screenshotofs) |
208 | if (screenshotofs) |
209 | {
|
209 | {
|
210 | if (kdfread((char *)waloff[TILE_LOADSHOT], 320, 200, fil) != 200) |
210 | if (kdfread((char *)waloff[TILE_LOADSHOT], 320, 200, fil) != 200) |
211 | {
|
211 | {
|
212 | OSD_Printf("G_LoadSaveHeaderNew(%d): failed reading screenshot\n", spot); |
212 | OSD_Printf("G_LoadSaveHeaderNew(%d): failed reading screenshot\n", spot); |
213 | goto corrupt; |
213 | goto corrupt; |
214 | }
|
214 | }
|
215 | }
|
215 | }
|
216 | else
|
216 | else
|
217 | {
|
217 | {
|
218 | Bmemset((char *)waloff[TILE_LOADSHOT], 0, 320*200); |
218 | Bmemset((char *)waloff[TILE_LOADSHOT], 0, 320*200); |
219 | }
|
219 | }
|
220 | invalidatetile(TILE_LOADSHOT, 0, 255); |
220 | invalidatetile(TILE_LOADSHOT, 0, 255); |
221 | 221 | ||
222 | kclose(fil); |
222 | kclose(fil); |
223 | return 0; |
223 | return 0; |
224 | 224 | ||
225 | corrupt:
|
225 | corrupt:
|
226 | kclose(fil); |
226 | kclose(fil); |
227 | return 1; |
227 | return 1; |
228 | }
|
228 | }
|
229 | 229 | ||
230 | 230 | ||
231 | static void sv_postudload(); |
231 | static void sv_postudload(); |
232 | 232 | ||
233 | // XXX: keyboard input 'blocked' after load fail? (at least ESC?)
|
233 | // XXX: keyboard input 'blocked' after load fail? (at least ESC?)
|
234 | int32_t G_LoadPlayer(int32_t spot) |
234 | int32_t G_LoadPlayer(int32_t spot) |
235 | {
|
235 | {
|
236 | char fn[16]; |
236 | char fn[16]; |
237 | int32_t fil, i; |
237 | int32_t fil, i; |
238 | 238 | ||
239 | savehead_t h;
|
239 | savehead_t h;
|
240 | 240 | ||
241 | Bassert(spot < MAXSAVEGAMES); |
241 | Bassert(spot < MAXSAVEGAMES); |
242 | 242 | ||
243 | Bstrcpy(fn, "dukesav0.esv"); |
243 | Bstrcpy(fn, "dukesav0.esv"); |
244 | fn[7] = spot + '0'; |
244 | fn[7] = spot + '0'; |
245 | 245 | ||
246 | fil = kopen4loadfrommod(fn, 0); |
246 | fil = kopen4loadfrommod(fn, 0); |
247 | if (fil == -1) |
247 | if (fil == -1) |
248 | return -1; |
248 | return -1; |
249 | 249 | ||
250 | ready2send = 0; |
250 | ready2send = 0; |
251 | 251 | ||
252 | i = sv_loadheader(fil, spot, &h); |
252 | i = sv_loadheader(fil, spot, &h); |
253 | if ((i && i != 2) || h.numplayers != ud.multimode) |
253 | if ((i && i != 2) || h.numplayers != ud.multimode) |
254 | {
|
254 | {
|
255 | if (i == 2 || i == 3) |
255 | if (i == 2 || i == 3) |
256 | P_DoQuote(QUOTE_SAVE_BAD_VERSION, g_player[myconnectindex].ps); |
256 | P_DoQuote(QUOTE_SAVE_BAD_VERSION, g_player[myconnectindex].ps); |
257 | else if (h.numplayers!=ud.multimode) |
257 | else if (h.numplayers!=ud.multimode) |
258 | P_DoQuote(QUOTE_SAVE_BAD_PLAYERS, g_player[myconnectindex].ps); |
258 | P_DoQuote(QUOTE_SAVE_BAD_PLAYERS, g_player[myconnectindex].ps); |
259 | 259 | ||
260 | kclose(fil); |
260 | kclose(fil); |
261 | ototalclock = totalclock; |
261 | ototalclock = totalclock; |
262 | ready2send = 1; |
262 | ready2send = 1; |
263 | 263 | ||
264 | return 1; |
264 | return 1; |
265 | }
|
265 | }
|
266 | 266 | ||
267 | // some setup first
|
267 | // some setup first
|
268 | ud.multimode = h.numplayers; |
268 | ud.multimode = h.numplayers; |
269 | 269 | ||
270 | if (numplayers > 1) |
270 | if (numplayers > 1) |
271 | {
|
271 | {
|
272 | pub = NUMPAGES; |
272 | pub = NUMPAGES; |
273 | pus = NUMPAGES; |
273 | pus = NUMPAGES; |
274 | G_UpdateScreenArea(); |
274 | G_UpdateScreenArea(); |
275 | G_DrawBackground(); |
275 | G_DrawBackground(); |
276 | menutext(160,100, 0,0, "LOADING..."); |
276 | menutext(160,100, 0,0, "LOADING..."); |
277 | nextpage(); |
277 | nextpage(); |
278 | }
|
278 | }
|
279 | 279 | ||
280 | Net_WaitForServer(); |
280 | Net_WaitForServer(); |
281 | 281 | ||
282 | FX_StopAllSounds(); |
282 | FX_StopAllSounds(); |
283 | S_ClearSoundLocks(); |
283 | S_ClearSoundLocks(); |
284 | 284 | ||
285 | if (spot >= 0 && numplayers==1) |
285 | if (spot >= 0 && numplayers==1) |
286 | {
|
286 | {
|
287 | Bmemcpy(ud.savegame[spot], h.savename, sizeof(ud.savegame[0])); |
287 | Bmemcpy(ud.savegame[spot], h.savename, sizeof(ud.savegame[0])); |
288 | ud.savegame[spot][sizeof(ud.savegame[0])-1] = 0; |
288 | ud.savegame[spot][sizeof(ud.savegame[0])-1] = 0; |
289 | }
|
289 | }
|
290 | 290 | ||
291 | // non-"m_" fields will be loaded from svgm_udnetw
|
291 | // non-"m_" fields will be loaded from svgm_udnetw
|
292 | ud.m_volume_number = h.volnum; |
292 | ud.m_volume_number = h.volnum; |
293 | ud.m_level_number = h.levnum; |
293 | ud.m_level_number = h.levnum; |
294 | ud.m_player_skill = h.skill; |
294 | ud.m_player_skill = h.skill; |
295 | 295 | ||
296 | {
|
296 | {
|
297 | // NOTE: Bmemcpy needed for SAVEGAME_MUSIC.
|
297 | // NOTE: Bmemcpy needed for SAVEGAME_MUSIC.
|
298 | EDUKE32_STATIC_ASSERT(sizeof(boardfilename) == sizeof(h.boardfn)); |
298 | EDUKE32_STATIC_ASSERT(sizeof(boardfilename) == sizeof(h.boardfn)); |
299 | Bmemcpy(boardfilename, h.boardfn, sizeof(boardfilename)); |
299 | Bmemcpy(boardfilename, h.boardfn, sizeof(boardfilename)); |
300 | }
|
300 | }
|
301 | 301 | ||
302 | E_MapArt_Setup(h.boardfn); // XXX: Better after the following filename tweaking? |
302 | E_MapArt_Setup(h.boardfn); // XXX: Better after the following filename tweaking? |
303 | 303 | ||
304 | if (boardfilename[0]) |
304 | if (boardfilename[0]) |
305 | Bstrcpy(currentboardfilename, boardfilename); |
305 | Bstrcpy(currentboardfilename, boardfilename); |
306 | else if (MapInfo[h.volnum*MAXLEVELS + h.levnum].filename) |
306 | else if (MapInfo[h.volnum*MAXLEVELS + h.levnum].filename) |
307 | Bstrcpy(currentboardfilename, MapInfo[h.volnum*MAXLEVELS + h.levnum].filename); |
307 | Bstrcpy(currentboardfilename, MapInfo[h.volnum*MAXLEVELS + h.levnum].filename); |
308 | 308 | ||
309 | if (currentboardfilename[0]) |
309 | if (currentboardfilename[0]) |
310 | {
|
310 | {
|
311 | append_ext_UNSAFE(currentboardfilename, ".mhk"); |
311 | append_ext_UNSAFE(currentboardfilename, ".mhk"); |
312 | loadmaphack(currentboardfilename); |
312 | loadmaphack(currentboardfilename); |
313 | }
|
313 | }
|
314 | 314 | ||
315 | Bmemcpy(currentboardfilename, boardfilename, BMAX_PATH); |
315 | Bmemcpy(currentboardfilename, boardfilename, BMAX_PATH); |
316 | 316 | ||
317 | if (i == 2) |
317 | if (i == 2) |
318 | {
|
318 | {
|
319 | G_NewGame_EnterLevel(); |
319 | G_NewGame_EnterLevel(); |
320 | }
|
320 | }
|
321 | else
|
321 | else
|
322 | {
|
322 | {
|
323 | // read the rest...
|
323 | // read the rest...
|
324 | i = sv_loadsnapshot(fil, spot, &h); |
324 | i = sv_loadsnapshot(fil, spot, &h); |
325 | if (i) |
325 | if (i) |
326 | {
|
326 | {
|
327 | // in theory, we could load into an initial dump first and trivially
|
327 | // in theory, we could load into an initial dump first and trivially
|
328 | // recover if things go wrong...
|
328 | // recover if things go wrong...
|
329 | Bsprintf(tempbuf, "Loading save game file \"%s\" failed (code %d), cannot recover.", fn, i); |
329 | Bsprintf(tempbuf, "Loading save game file \"%s\" failed (code %d), cannot recover.", fn, i); |
330 | G_GameExit(tempbuf); |
330 | G_GameExit(tempbuf); |
331 | }
|
331 | }
|
332 | }
|
332 | }
|
333 | sv_postudload(); // ud.m_XXX = ud.XXX |
333 | sv_postudload(); // ud.m_XXX = ud.XXX |
334 | 334 | ||
335 | VM_OnEvent(EVENT_LOADGAME, g_player[myconnectindex].ps->i, myconnectindex); |
335 | VM_OnEvent(EVENT_LOADGAME, g_player[myconnectindex].ps->i, myconnectindex); |
336 | 336 | ||
337 | return 0; |
337 | return 0; |
338 | }
|
338 | }
|
339 | 339 | ||
340 | ////////// TIMER SAVING/RESTORING //////////
|
340 | ////////// TIMER SAVING/RESTORING //////////
|
341 | 341 | ||
342 | static struct { |
342 | static struct { |
343 | int32_t totalclock, totalclocklock; // engine |
343 | int32_t totalclock, totalclocklock; // engine |
344 | int32_t ototalclock, lockclock; // game |
344 | int32_t ototalclock, lockclock; // game |
345 | } g_timers; |
345 | } g_timers; |
346 | 346 | ||
347 | static void G_SaveTimers(void) |
347 | static void G_SaveTimers(void) |
348 | {
|
348 | {
|
349 | g_timers.totalclock = totalclock; |
349 | g_timers.totalclock = totalclock; |
350 | g_timers.totalclocklock = totalclocklock; |
350 | g_timers.totalclocklock = totalclocklock; |
351 | g_timers.ototalclock = ototalclock; |
351 | g_timers.ototalclock = ototalclock; |
352 | g_timers.lockclock = lockclock; |
352 | g_timers.lockclock = lockclock; |
353 | }
|
353 | }
|
354 | 354 | ||
355 | static void G_RestoreTimers(void) |
355 | static void G_RestoreTimers(void) |
356 | {
|
356 | {
|
357 | sampletimer(); |
357 | sampletimer(); |
358 | 358 | ||
359 | totalclock = g_timers.totalclock; |
359 | totalclock = g_timers.totalclock; |
360 | totalclocklock = g_timers.totalclocklock; |
360 | totalclocklock = g_timers.totalclocklock; |
361 | ototalclock = g_timers.ototalclock; |
361 | ototalclock = g_timers.ototalclock; |
362 | lockclock = g_timers.lockclock; |
362 | lockclock = g_timers.lockclock; |
363 | }
|
363 | }
|
364 | 364 | ||
365 | //////////
|
365 | //////////
|
366 | 366 | ||
367 | #ifdef __ANDROID__
|
367 | #ifdef __ANDROID__
|
368 | static void G_SavePalette(void) |
368 | static void G_SavePalette(void) |
369 | {
|
369 | {
|
370 | int32_t pfil; |
370 | int32_t pfil; |
371 | 371 | ||
372 | if ((pfil = kopen4load("palette.dat", 0)) != -1) |
372 | if ((pfil = kopen4load("palette.dat", 0)) != -1) |
373 | {
|
373 | {
|
374 | int len = kfilelength(pfil); |
374 | int len = kfilelength(pfil); |
375 | 375 | ||
376 | FILE *fil = fopen("palette.dat", "rb"); |
376 | FILE *fil = fopen("palette.dat", "rb"); |
377 | 377 | ||
378 | if (!fil) |
378 | if (!fil) |
379 | {
|
379 | {
|
380 | fil = fopen("palette.dat", "wb"); |
380 | fil = fopen("palette.dat", "wb"); |
381 | 381 | ||
382 | if (fil) |
382 | if (fil) |
383 | {
|
383 | {
|
384 | char *buf = (char *) Xaligned_alloc(16, len); |
384 | char *buf = (char *) Xaligned_alloc(16, len); |
385 | 385 | ||
386 | kread(pfil, buf, len); |
386 | kread(pfil, buf, len); |
387 | fwrite(buf, len, 1, fil); |
387 | fwrite(buf, len, 1, fil); |
388 | fclose(fil); |
388 | fclose(fil); |
389 | }
|
389 | }
|
390 | }
|
390 | }
|
391 | else fclose(fil); |
391 | else fclose(fil); |
392 | }
|
392 | }
|
393 | }
|
393 | }
|
394 | #endif
|
394 | #endif
|
395 | 395 | ||
396 | int32_t G_SavePlayer(int32_t spot) |
396 | int32_t G_SavePlayer(int32_t spot) |
397 | {
|
397 | {
|
398 | char fn[16]; |
398 | char fn[16]; |
399 | FILE *fil; |
399 | FILE *fil; |
400 | 400 | ||
401 | #ifdef __ANDROID__
|
401 | #ifdef __ANDROID__
|
402 | G_SavePalette(); |
402 | G_SavePalette(); |
403 | #endif
|
403 | #endif
|
404 | 404 | ||
405 | Bassert(spot < MAXSAVEGAMES); |
405 | Bassert(spot < MAXSAVEGAMES); |
406 | 406 | ||
407 | G_SaveTimers(); |
407 | G_SaveTimers(); |
408 | 408 | ||
409 | Bstrcpy(fn, "dukesav0.esv"); |
409 | Bstrcpy(fn, "dukesav0.esv"); |
410 | fn[7] = spot + '0'; |
410 | fn[7] = spot + '0'; |
411 | 411 | ||
412 | // Bstrcpy(mpfn, "edukA_00.esv");
|
412 | // Bstrcpy(mpfn, "edukA_00.esv");
|
413 | 413 | ||
414 | Net_WaitForServer(); |
414 | Net_WaitForServer(); |
415 | ready2send = 0; |
415 | ready2send = 0; |
416 | 416 | ||
417 | {
|
417 | {
|
418 | char temp[BMAX_PATH]; |
418 | char temp[BMAX_PATH]; |
419 | 419 | ||
420 | if (G_ModDirSnprintf(temp, sizeof(temp), "%s", fn)) |
420 | if (G_ModDirSnprintf(temp, sizeof(temp), "%s", fn)) |
421 | {
|
421 | {
|
422 | OSD_Printf("G_SavePlayer: file name \"%s\" too long\n", fn); |
422 | OSD_Printf("G_SavePlayer: file name \"%s\" too long\n", fn); |
423 | return -1; |
423 | return -1; |
424 | }
|
424 | }
|
425 | 425 | ||
426 | errno = 0; |
426 | errno = 0; |
427 | fil = fopen(temp, "wb"); |
427 | fil = fopen(temp, "wb"); |
428 | if (!fil) |
428 | if (!fil) |
429 | {
|
429 | {
|
430 | OSD_Printf("G_SavePlayer: failed opening \"%s\" for writing: %s\n", |
430 | OSD_Printf("G_SavePlayer: failed opening \"%s\" for writing: %s\n", |
431 | temp, strerror(errno)); |
431 | temp, strerror(errno)); |
432 | return -1; |
432 | return -1; |
433 | }
|
433 | }
|
434 | }
|
434 | }
|
435 | 435 | ||
436 | #ifdef POLYMER
|
436 | #ifdef POLYMER
|
437 | if (getrendermode() == REND_POLYMER) |
437 | if (getrendermode() == REND_POLYMER) |
438 | polymer_resetlights(); |
438 | polymer_resetlights(); |
439 | #endif
|
439 | #endif
|
440 | 440 | ||
441 | VM_OnEvent(EVENT_SAVEGAME, g_player[myconnectindex].ps->i, myconnectindex); |
441 | VM_OnEvent(EVENT_SAVEGAME, g_player[myconnectindex].ps->i, myconnectindex); |
442 | 442 | ||
443 | // SAVE!
|
443 | // SAVE!
|
444 | sv_saveandmakesnapshot(fil, spot, 0, 0, 0); |
444 | sv_saveandmakesnapshot(fil, spot, 0, 0, 0); |
445 | 445 | ||
446 | fclose(fil); |
446 | fclose(fil); |
447 | 447 | ||
448 | if (!g_netServer && ud.multimode < 2) |
448 | if (!g_netServer && ud.multimode < 2) |
449 | {
|
449 | {
|
450 | #ifdef LUNATIC
|
450 | #ifdef LUNATIC
|
451 | if (!g_savedOK) |
451 | if (!g_savedOK) |
452 | Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "^10Failed Saving Game"); |
452 | Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "^10Failed Saving Game"); |
453 | else
|
453 | else
|
454 | #endif
|
454 | #endif
|
455 | Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "Game Saved"); |
455 | Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "Game Saved"); |
456 | P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); |
456 | P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); |
457 | }
|
457 | }
|
458 | 458 | ||
459 | ready2send = 1; |
459 | ready2send = 1; |
460 | Net_WaitForServer(); |
460 | Net_WaitForServer(); |
461 | 461 | ||
462 | G_RestoreTimers(); |
462 | G_RestoreTimers(); |
463 | ototalclock = totalclock; |
463 | ototalclock = totalclock; |
464 | 464 | ||
465 | return 0; |
465 | return 0; |
466 | }
|
466 | }
|
467 | 467 | ||
468 | void G_LoadPlayerMaybeMulti(int32_t slot) |
468 | void G_LoadPlayerMaybeMulti(int32_t slot) |
469 | {
|
469 | {
|
470 | if (g_netServer || ud.multimode > 1) |
470 | if (g_netServer || ud.multimode > 1) |
471 | {
|
471 | {
|
472 | Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "Multiplayer Loading Not Yet Supported"); |
472 | Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "Multiplayer Loading Not Yet Supported"); |
473 | P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); |
473 | P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); |
474 | 474 | ||
475 | // G_LoadPlayer(-1-g_lastSaveSlot);
|
475 | // G_LoadPlayer(-1-g_lastSaveSlot);
|
476 | // g_player[myconnectindex].ps->gm = MODE_GAME;
|
476 | // g_player[myconnectindex].ps->gm = MODE_GAME;
|
477 | }
|
477 | }
|
478 | else
|
478 | else
|
479 | {
|
479 | {
|
480 | int32_t c = G_LoadPlayer(slot); |
480 | int32_t c = G_LoadPlayer(slot); |
481 | if (c == 0) |
481 | if (c == 0) |
482 | g_player[myconnectindex].ps->gm = MODE_GAME; |
482 | g_player[myconnectindex].ps->gm = MODE_GAME; |
483 | }
|
483 | }
|
484 | }
|
484 | }
|
485 | 485 | ||
486 | void G_SavePlayerMaybeMulti(int32_t slot) |
486 | void G_SavePlayerMaybeMulti(int32_t slot) |
487 | {
|
487 | {
|
488 | Bassert(slot >= 0); |
488 | Bassert(slot >= 0); |
489 | 489 | ||
490 | CONFIG_WriteSetup(2); |
490 | CONFIG_WriteSetup(2); |
491 | 491 | ||
492 | if (g_netServer || ud.multimode > 1) |
492 | if (g_netServer || ud.multimode > 1) |
493 | {
|
493 | {
|
494 | Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "Multiplayer Saving Not Yet Supported"); |
494 | Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "Multiplayer Saving Not Yet Supported"); |
495 | P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); |
495 | P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); |
496 | // G_SavePlayer(-1-slot);
|
496 | // G_SavePlayer(-1-slot);
|
497 | }
|
497 | }
|
498 | else
|
498 | else
|
499 | {
|
499 | {
|
500 | G_SavePlayer(slot); |
500 | G_SavePlayer(slot); |
501 | }
|
501 | }
|
502 | }
|
502 | }
|
503 | 503 | ||
504 | ////////// GENERIC SAVING/LOADING SYSTEM //////////
|
504 | ////////// GENERIC SAVING/LOADING SYSTEM //////////
|
505 | 505 | ||
506 | typedef struct dataspec_ |
506 | typedef struct dataspec_ |
507 | {
|
507 | {
|
508 | uint32_t flags; |
508 | uint32_t flags; |
509 | void *ptr; |
509 | void *ptr; |
510 | uint32_t size; |
510 | uint32_t size; |
511 | intptr_t cnt; |
511 | intptr_t cnt; |
512 | } dataspec_t; |
512 | } dataspec_t; |
513 | 513 | ||
514 | #define SV_DEFAULTCOMPRTHRES 8
|
514 | #define SV_DEFAULTCOMPRTHRES 8
|
515 | static uint8_t savegame_diffcompress; // 0:none, 1:Ken's LZW in cache1d.c |
515 | static uint8_t savegame_diffcompress; // 0:none, 1:Ken's LZW in cache1d.c |
516 | static uint8_t savegame_comprthres; |
516 | static uint8_t savegame_comprthres; |
517 | 517 | ||
518 | 518 | ||
519 | #define DS_DYNAMIC 1 // dereference .ptr one more time
|
519 | #define DS_DYNAMIC 1 // dereference .ptr one more time
|
520 | #define DS_STRING 2
|
520 | #define DS_STRING 2
|
521 | #define DS_CMP 4
|
521 | #define DS_CMP 4
|
522 | // 8
|
522 | // 8
|
523 | #define DS_CNT(x) ((sizeof(x))<<3) // .cnt is pointer to...
|
523 | #define DS_CNT(x) ((sizeof(x))<<3) // .cnt is pointer to...
|
524 | #define DS_CNT16 16
|
524 | #define DS_CNT16 16
|
525 | #define DS_CNT32 32
|
525 | #define DS_CNT32 32
|
526 | #define DS_CNTMASK (8|DS_CNT16|DS_CNT32|64)
|
526 | #define DS_CNTMASK (8|DS_CNT16|DS_CNT32|64)
|
527 | // 64
|
527 | // 64
|
528 | #define DS_LOADFN 128 // .ptr is function that is run when loading
|
528 | #define DS_LOADFN 128 // .ptr is function that is run when loading
|
529 | #define DS_SAVEFN 256 // .ptr is function that is run when saving
|
529 | #define DS_SAVEFN 256 // .ptr is function that is run when saving
|
530 | #define DS_NOCHK 1024 // don't check for diffs (and don't write out in dump) since assumed constant throughout demo
|
530 | #define DS_NOCHK 1024 // don't check for diffs (and don't write out in dump) since assumed constant throughout demo
|
531 | #define DS_PROTECTFN 512
|
531 | #define DS_PROTECTFN 512
|
532 | #define DS_END (0x70000000)
|
532 | #define DS_END (0x70000000)
|
533 | 533 | ||
534 | static int32_t ds_getcnt(const dataspec_t *sp) |
534 | static int32_t ds_getcnt(const dataspec_t *sp) |
535 | {
|
535 | {
|
536 | int rv = -1; |
536 | int rv = -1; |
537 | 537 | ||
538 | switch (sp->flags & DS_CNTMASK) |
538 | switch (sp->flags & DS_CNTMASK) |
539 | {
|
539 | {
|
540 | case 0: rv = sp->cnt; break; |
540 | case 0: rv = sp->cnt; break; |
541 | case DS_CNT16: rv = *((int16_t *)sp->cnt); break; |
541 | case DS_CNT16: rv = *((int16_t *)sp->cnt); break; |
542 | case DS_CNT32: rv = *((int32_t *)sp->cnt); break; |
542 | case DS_CNT32: rv = *((int32_t *)sp->cnt); break; |
543 | }
|
543 | }
|
544 | 544 | ||
545 | return rv; |
545 | return rv; |
546 | }
|
546 | }
|
547 | 547 | ||
548 | static inline void ds_get(const dataspec_t *sp, void **ptr, int32_t *cnt) |
548 | static inline void ds_get(const dataspec_t *sp, void **ptr, int32_t *cnt) |
549 | {
|
549 | {
|
550 | *cnt = ds_getcnt(sp); |
550 | *cnt = ds_getcnt(sp); |
551 | *ptr = (sp->flags&DS_DYNAMIC) ? *((void **)sp->ptr) : sp->ptr; |
551 | *ptr = (sp->flags&DS_DYNAMIC) ? *((void **)sp->ptr) : sp->ptr; |
552 | }
|
552 | }
|
553 | 553 | ||
554 | // write state to file and/or to dump
|
554 | // write state to file and/or to dump
|
555 | static uint8_t *writespecdata(const dataspec_t *spec, FILE *fil, uint8_t *dump) |
555 | static uint8_t *writespecdata(const dataspec_t *spec, FILE *fil, uint8_t *dump) |
556 | {
|
556 | {
|
557 | int32_t cnt; |
557 | int32_t cnt; |
558 | void *ptr; |
558 | void *ptr; |
559 | const dataspec_t *sp=spec; |
559 | const dataspec_t *sp=spec; |
560 | 560 | ||
561 | for (; sp->flags!=DS_END; sp++) |
561 | for (; sp->flags!=DS_END; sp++) |
562 | {
|
562 | {
|
563 | if (sp->flags&(DS_SAVEFN|DS_LOADFN)) |
563 | if (sp->flags&(DS_SAVEFN|DS_LOADFN)) |
564 | {
|
564 | {
|
565 | if (sp->flags&DS_SAVEFN) |
565 | if (sp->flags&DS_SAVEFN) |
566 | (*(void (*)(void))sp->ptr)(); |
566 | (*(void (*)(void))sp->ptr)(); |
567 | continue; |
567 | continue; |
568 | }
|
568 | }
|
569 | 569 | ||
570 | if (!fil && (sp->flags&(DS_NOCHK|DS_CMP|DS_STRING))) |
570 | if (!fil && (sp->flags&(DS_NOCHK|DS_CMP|DS_STRING))) |
571 | continue; |
571 | continue; |
572 | 572 | ||
573 | if (sp->flags&DS_STRING) |
573 | if (sp->flags&DS_STRING) |
574 | {
|
574 | {
|
575 | fwrite(sp->ptr, Bstrlen((const char *)sp->ptr), 1, fil); // not null-terminated! |
575 | fwrite(sp->ptr, Bstrlen((const char *)sp->ptr), 1, fil); // not null-terminated! |
576 | continue; |
576 | continue; |
577 | }
|
577 | }
|
578 | 578 | ||
579 | ds_get(sp, &ptr, &cnt); |
579 | ds_get(sp, &ptr, &cnt); |
580 | if (cnt < 0) { OSD_Printf("wsd: cnt=%d, f=0x%x.\n",cnt,sp->flags); continue; } |
580 | if (cnt < 0) { OSD_Printf("wsd: cnt=%d, f=0x%x.\n",cnt,sp->flags); continue; } |
581 | 581 | ||
582 | if (fil) |
582 | if (fil) |
583 | {
|
583 | {
|
584 | if (((sp->flags&DS_CNTMASK)==0 && sp->size*cnt<=savegame_comprthres) |
584 | if (((sp->flags&DS_CNTMASK)==0 && sp->size*cnt<=savegame_comprthres) |
585 | || (sp->flags&DS_CMP)) |
585 | || (sp->flags&DS_CMP)) |
586 | fwrite(ptr, sp->size, cnt, fil); |
586 | fwrite(ptr, sp->size, cnt, fil); |
587 | else
|
587 | else
|
588 | dfwrite((void *)ptr, sp->size, cnt, fil); |
588 | dfwrite((void *)ptr, sp->size, cnt, fil); |
589 | }
|
589 | }
|
590 | 590 | ||
591 | if (dump && (sp->flags&(DS_NOCHK|DS_CMP))==0) |
591 | if (dump && (sp->flags&(DS_NOCHK|DS_CMP))==0) |
592 | {
|
592 | {
|
593 | Bmemcpy(dump, ptr, sp->size*cnt); |
593 | Bmemcpy(dump, ptr, sp->size*cnt); |
594 | dump += sp->size*cnt; |
594 | dump += sp->size*cnt; |
595 | }
|
595 | }
|
596 | }
|
596 | }
|
597 | return dump; |
597 | return dump; |
598 | }
|
598 | }
|
599 | 599 | ||
600 | // let havedump=dumpvar&&*dumpvar
|
600 | // let havedump=dumpvar&&*dumpvar
|
601 | // (fil>=0 && havedump): first restore dump from file, then restore state from dump
|
601 | // (fil>=0 && havedump): first restore dump from file, then restore state from dump
|
602 | // (fil<0 && havedump): only restore state from dump
|
602 | // (fil<0 && havedump): only restore state from dump
|
603 | // (fil>=0 && !havedump): only restore state from file
|
603 | // (fil>=0 && !havedump): only restore state from file
|
604 | static int32_t readspecdata(const dataspec_t *spec, int32_t fil, uint8_t **dumpvar) |
604 | static int32_t readspecdata(const dataspec_t *spec, int32_t fil, uint8_t **dumpvar) |
605 | {
|
605 | {
|
606 | int32_t cnt, i, j; |
606 | int32_t cnt, i, j; |
607 | void *ptr; |
607 | void *ptr; |
608 | uint8_t *dump=dumpvar?*dumpvar:NULL, *mem; |
608 | uint8_t *dump=dumpvar?*dumpvar:NULL, *mem; |
609 | const dataspec_t *sp=spec; |
609 | const dataspec_t *sp=spec; |
610 | static char cmpstrbuf[32]; |
610 | static char cmpstrbuf[32]; |
611 | 611 | ||
612 | for (; sp->flags!=DS_END; sp++) |
612 | for (; sp->flags!=DS_END; sp++) |
613 | {
|
613 | {
|
614 | if (fil < 0 && sp->flags&(DS_NOCHK|DS_STRING|DS_CMP)) // we're updating |
614 | if (fil < 0 && sp->flags&(DS_NOCHK|DS_STRING|DS_CMP)) // we're updating |
615 | continue; |
615 | continue; |
616 | 616 | ||
617 | if (sp->flags&(DS_LOADFN|DS_SAVEFN)) |
617 | if (sp->flags&(DS_LOADFN|DS_SAVEFN)) |
618 | {
|
618 | {
|
619 | if (sp->flags&DS_LOADFN) |
619 | if (sp->flags&DS_LOADFN) |
620 | (*(void (*)())sp->ptr)(); |
620 | (*(void (*)())sp->ptr)(); |
621 | continue; |
621 | continue; |
622 | }
|
622 | }
|
623 | 623 | ||
624 | if (sp->flags&(DS_STRING|DS_CMP)) // DS_STRING and DS_CMP is for static data only |
624 | if (sp->flags&(DS_STRING|DS_CMP)) // DS_STRING and DS_CMP is for static data only |
625 | {
|
625 | {
|
626 | if (sp->flags&(DS_STRING)) |
626 | if (sp->flags&(DS_STRING)) |
627 | i = Bstrlen((const char *)sp->ptr); |
627 | i = Bstrlen((const char *)sp->ptr); |
628 | else
|
628 | else
|
629 | i = sp->size*sp->cnt; |
629 | i = sp->size*sp->cnt; |
630 | 630 | ||
631 | j=kread(fil, cmpstrbuf, i); |
631 | j=kread(fil, cmpstrbuf, i); |
632 | if (j!=i || Bmemcmp(sp->ptr, cmpstrbuf, i)) |
632 | if (j!=i || Bmemcmp(sp->ptr, cmpstrbuf, i)) |
633 | {
|
633 | {
|
634 | OSD_Printf("rsd: spec=%s, idx=%d:\n", (char *)spec->ptr, (int32_t)(sp-spec)); |
634 | OSD_Printf("rsd: spec=%s, idx=%d:\n", (char *)spec->ptr, (int32_t)(sp-spec)); |
635 | if (j!=i) |
635 | if (j!=i) |
636 | OSD_Printf(" kread returned %d, expected %d.\n", j, i); |
636 | OSD_Printf(" kread returned %d, expected %d.\n", j, i); |
637 | else
|
637 | else
|
638 | OSD_Printf(" sp->ptr and cmpstrbuf not identical!\n"); |
638 | OSD_Printf(" sp->ptr and cmpstrbuf not identical!\n"); |
639 | return -1; |
639 | return -1; |
640 | }
|
640 | }
|
641 | continue; |
641 | continue; |
642 | }
|
642 | }
|
643 | 643 | ||
644 | ds_get(sp, &ptr, &cnt); |
644 | ds_get(sp, &ptr, &cnt); |
645 | if (cnt < 0) { OSD_Printf("rsd: cnt<0... wtf?\n"); return -1; } |
645 | if (cnt < 0) { OSD_Printf("rsd: cnt<0... wtf?\n"); return -1; } |
646 | 646 | ||
647 | if (fil>=0) |
647 | if (fil>=0) |
648 | {
|
648 | {
|
649 | mem = (dump && (sp->flags&DS_NOCHK)==0) ? dump : (uint8_t *)ptr; |
649 | mem = (dump && (sp->flags&DS_NOCHK)==0) ? dump : (uint8_t *)ptr; |
650 | 650 | ||
651 | if ((sp->flags&DS_CNTMASK)==0 && sp->size*cnt<=savegame_comprthres) |
651 | if ((sp->flags&DS_CNTMASK)==0 && sp->size*cnt<=savegame_comprthres) |
652 | {
|
652 | {
|
653 | i = kread(fil, mem, cnt*sp->size); |
653 | i = kread(fil, mem, cnt*sp->size); |
654 | j = cnt*sp->size; |
654 | j = cnt*sp->size; |
655 | }
|
655 | }
|
656 | else
|
656 | else
|
657 | {
|
657 | {
|
658 | i = kdfread(mem, sp->size, cnt, fil); |
658 | i = kdfread(mem, sp->size, cnt, fil); |
659 | j = cnt; |
659 | j = cnt; |
660 | }
|
660 | }
|
661 | if (i!=j) |
661 | if (i!=j) |
662 | {
|
662 | {
|
663 | OSD_Printf("rsd: spec=%s, idx=%d, mem=%p\n", (char *)spec->ptr, (int32_t)(sp-spec), mem); |
663 | OSD_Printf("rsd: spec=%s, idx=%d, mem=%p\n", (char *)spec->ptr, (int32_t)(sp-spec), mem); |
664 | OSD_Printf(" (%s): read %d, expected %d!\n", |
664 | OSD_Printf(" (%s): read %d, expected %d!\n", |
665 | ((sp->flags&DS_CNTMASK)==0 && sp->size*cnt<=savegame_comprthres)? |
665 | ((sp->flags&DS_CNTMASK)==0 && sp->size*cnt<=savegame_comprthres)? |
666 | "uncompressed":"compressed", i, j); |
666 | "uncompressed":"compressed", i, j); |
667 | 667 | ||
668 | if (i==-1) |
668 | if (i==-1) |
669 | OSD_Printf(" read: %s\n", strerror(errno)); |
669 | OSD_Printf(" read: %s\n", strerror(errno)); |
670 | return -1; |
670 | return -1; |
671 | }
|
671 | }
|
672 | }
|
672 | }
|
673 | 673 | ||
674 | if (dump && (sp->flags&DS_NOCHK)==0) |
674 | if (dump && (sp->flags&DS_NOCHK)==0) |
675 | {
|
675 | {
|
676 | Bmemcpy(ptr, dump, sp->size*cnt); |
676 | Bmemcpy(ptr, dump, sp->size*cnt); |
677 | dump += sp->size*cnt; |
677 | dump += sp->size*cnt; |
678 | }
|
678 | }
|
679 | }
|
679 | }
|
680 | 680 | ||
681 | if (dumpvar) |
681 | if (dumpvar) |
682 | *dumpvar = dump; |
682 | *dumpvar = dump; |
683 | return 0; |
683 | return 0; |
684 | }
|
684 | }
|
685 | 685 | ||
686 | #define UINT(bits) uint##bits##_t
|
686 | #define UINT(bits) uint##bits##_t
|
687 | #define BYTES(bits) (bits>>3)
|
687 | #define BYTES(bits) (bits>>3)
|
688 | #define VAL(bits,p) (*(UINT(bits) *)(p))
|
688 | #define VAL(bits,p) (*(UINT(bits) *)(p))
|
689 | 689 | ||
690 | static void docmpsd(const void *ptr, void *dump, uint32_t size, uint32_t cnt, uint8_t **diffvar) |
690 | static void docmpsd(const void *ptr, void *dump, uint32_t size, uint32_t cnt, uint8_t **diffvar) |
691 | {
|
691 | {
|
692 | uint8_t *retdiff = *diffvar; |
692 | uint8_t *retdiff = *diffvar; |
693 | 693 | ||
694 | // Hail to the C preprocessor, baby!
|
694 | // Hail to the C preprocessor, baby!
|
695 | #define CPSINGLEVAL(Datbits) \
|
695 | #define CPSINGLEVAL(Datbits) \
|
696 | if (VAL(Datbits, ptr) != VAL(Datbits, dump)) \
|
696 | if (VAL(Datbits, ptr) != VAL(Datbits, dump)) \
|
697 | { \
|
697 | { \
|
698 | VAL(Datbits, retdiff) = VAL(Datbits, dump) = VAL(Datbits, ptr); \
|
698 | VAL(Datbits, retdiff) = VAL(Datbits, dump) = VAL(Datbits, ptr); \
|
699 | *diffvar = retdiff+BYTES(Datbits); \
|
699 | *diffvar = retdiff+BYTES(Datbits); \
|
700 | }
|
700 | }
|
701 | 701 | ||
702 | if (cnt==1) |
702 | if (cnt==1) |
703 | switch (size) |
703 | switch (size) |
704 | {
|
704 | {
|
705 | case 8: CPSINGLEVAL(64); return; |
705 | case 8: CPSINGLEVAL(64); return; |
706 | case 4: CPSINGLEVAL(32); return; |
706 | case 4: CPSINGLEVAL(32); return; |
707 | case 2: CPSINGLEVAL(16); return; |
707 | case 2: CPSINGLEVAL(16); return; |
708 | case 1: CPSINGLEVAL(8); return; |
708 | case 1: CPSINGLEVAL(8); return; |
709 | }
|
709 | }
|
710 | 710 | ||
711 | #define CPELTS(Idxbits, Datbits) do \
|
711 | #define CPELTS(Idxbits, Datbits) do \
|
712 | { \
|
712 | { \
|
713 | for (i=0; i<nelts; i++) \
|
713 | for (i=0; i<nelts; i++) \
|
714 | { \
|
714 | { \
|
715 | if (*p!=*op) \
|
715 | if (*p!=*op) \
|
716 | { \
|
716 | { \
|
717 | *op = *p; \
|
717 | *op = *p; \
|
718 | VAL(Idxbits, retdiff) = i; \
|
718 | VAL(Idxbits, retdiff) = i; \
|
719 | retdiff += BYTES(Idxbits); \
|
719 | retdiff += BYTES(Idxbits); \
|
720 | VAL(Datbits, retdiff) = *p; \
|
720 | VAL(Datbits, retdiff) = *p; \
|
721 | retdiff += BYTES(Datbits); \
|
721 | retdiff += BYTES(Datbits); \
|
722 | } \
|
722 | } \
|
723 | p++; \
|
723 | p++; \
|
724 | op++; \
|
724 | op++; \
|
725 | } \
|
725 | } \
|
726 | VAL(Idxbits, retdiff) = -1; \
|
726 | VAL(Idxbits, retdiff) = -1; \
|
727 | retdiff += BYTES(Idxbits); \
|
727 | retdiff += BYTES(Idxbits); \
|
728 | } while (0)
|
728 | } while (0)
|
729 | 729 | ||
730 | #define CPDATA(Datbits) do \
|
730 | #define CPDATA(Datbits) do \
|
731 | { \
|
731 | { \
|
732 | const UINT(Datbits) *p=(UINT(Datbits) *)ptr; \
|
732 | const UINT(Datbits) *p=(UINT(Datbits) *)ptr; \
|
733 | UINT(Datbits) *op=(UINT(Datbits) *)dump; \
|
733 | UINT(Datbits) *op=(UINT(Datbits) *)dump; \
|
734 | uint32_t i, nelts=tabledivide32_noinline(size*cnt, BYTES(Datbits)); \
|
734 | uint32_t i, nelts=tabledivide32_noinline(size*cnt, BYTES(Datbits)); \
|
735 | if (nelts>65536) \
|
735 | if (nelts>65536) \
|
736 | CPELTS(32,Datbits); \
|
736 | CPELTS(32,Datbits); \
|
737 | else if (nelts>256) \
|
737 | else if (nelts>256) \
|
738 | CPELTS(16,Datbits); \
|
738 | CPELTS(16,Datbits); \
|
739 | else \
|
739 | else \
|
740 | CPELTS(8,Datbits); \
|
740 | CPELTS(8,Datbits); \
|
741 | } while (0)
|
741 | } while (0)
|
742 | 742 | ||
743 | if (size==8) |
743 | if (size==8) |
744 | CPDATA(64); |
744 | CPDATA(64); |
745 | else if ((size&3)==0) |
745 | else if ((size&3)==0) |
746 | CPDATA(32); |
746 | CPDATA(32); |
747 | else if ((size&1)==0) |
747 | else if ((size&1)==0) |
748 | CPDATA(16); |
748 | CPDATA(16); |
749 | else
|
749 | else
|
750 | CPDATA(8); |
750 | CPDATA(8); |
751 | 751 | ||
752 | *diffvar = retdiff; |
752 | *diffvar = retdiff; |
753 | return; |
753 | return; |
754 | 754 | ||
755 | #undef CPELTS
|
755 | #undef CPELTS
|
756 | #undef CPSINGLEVAL
|
756 | #undef CPSINGLEVAL
|
757 | #undef CPDATA
|
757 | #undef CPDATA
|
758 | }
|
758 | }
|
759 | 759 | ||
760 | // get the number of elements to be monitored for changes
|
760 | // get the number of elements to be monitored for changes
|
761 | static int32_t getnumvar(const dataspec_t *spec) |
761 | static int32_t getnumvar(const dataspec_t *spec) |
762 | {
|
762 | {
|
763 | int32_t n=0; |
763 | int32_t n=0; |
764 | for (; spec->flags!=DS_END; spec++) |
764 | for (; spec->flags!=DS_END; spec++) |
765 | n += (spec->flags&(DS_STRING|DS_CMP|DS_NOCHK|DS_SAVEFN|DS_LOADFN) ? 0 : 1); |
765 | n += (spec->flags&(DS_STRING|DS_CMP|DS_NOCHK|DS_SAVEFN|DS_LOADFN) ? 0 : 1); |
766 | return n; |
766 | return n; |
767 | }
|
767 | }
|
768 | 768 | ||
769 | // update dump at *dumpvar with new state and write diff to *diffvar
|
769 | // update dump at *dumpvar with new state and write diff to *diffvar
|
770 | static void cmpspecdata(const dataspec_t *spec, uint8_t **dumpvar, uint8_t **diffvar) |
770 | static void cmpspecdata(const dataspec_t *spec, uint8_t **dumpvar, uint8_t **diffvar) |
771 | {
|
771 | {
|
772 | void *ptr; |
772 | void *ptr; |
773 | uint8_t *dump=*dumpvar, *diff=*diffvar, *tmptr; |
773 | uint8_t *dump=*dumpvar, *diff=*diffvar, *tmptr; |
774 | const dataspec_t *sp=spec; |
774 | const dataspec_t *sp=spec; |
775 | int32_t cnt, eltnum=0, nbytes=(getnumvar(spec)+7)>>3, l=Bstrlen((const char *)spec->ptr); |
775 | int32_t cnt, eltnum=0, nbytes=(getnumvar(spec)+7)>>3, l=Bstrlen((const char *)spec->ptr); |
776 | 776 | ||
777 | Bmemcpy(diff, spec->ptr, l); |
777 | Bmemcpy(diff, spec->ptr, l); |
778 | diff+=l; |
778 | diff+=l; |
779 | 779 | ||
780 | while (nbytes--) |
780 | while (nbytes--) |
781 | *(diff++) = 0; // the bitmap of indices which elements of spec have changed go here |
781 | *(diff++) = 0; // the bitmap of indices which elements of spec have changed go here |
782 | 782 | ||
783 | for (sp++; sp->flags!=DS_END; sp++) |
783 | for (sp++; sp->flags!=DS_END; sp++) |
784 | {
|
784 | {
|
785 | if ((sp->flags&(DS_NOCHK|DS_STRING|DS_CMP))) |
785 | if ((sp->flags&(DS_NOCHK|DS_STRING|DS_CMP))) |
786 | continue; |
786 | continue; |
787 | 787 | ||
788 | if (sp->flags&(DS_LOADFN|DS_SAVEFN)) |
788 | if (sp->flags&(DS_LOADFN|DS_SAVEFN)) |
789 | {
|
789 | {
|
790 | if ((sp->flags&(DS_PROTECTFN))==0) |
790 | if ((sp->flags&(DS_PROTECTFN))==0) |
791 | (*(void (*)())sp->ptr)(); |
791 | (*(void (*)())sp->ptr)(); |
792 | continue; |
792 | continue; |
793 | }
|
793 | }
|
794 | 794 | ||
795 | ds_get(sp, &ptr, &cnt); |
795 | ds_get(sp, &ptr, &cnt); |
796 | if (cnt < 0) { OSD_Printf("csd: cnt=%d, f=0x%x\n", cnt, sp->flags); continue; } |
796 | if (cnt < 0) { OSD_Printf("csd: cnt=%d, f=0x%x\n", cnt, sp->flags); continue; } |
797 | 797 | ||
798 | tmptr = diff; |
798 | tmptr = diff; |
799 | docmpsd(ptr, dump, sp->size, cnt, &diff); |
799 | docmpsd(ptr, dump, sp->size, cnt, &diff); |
800 | if (diff != tmptr) |
800 | if (diff != tmptr) |
801 | (*diffvar + l)[eltnum>>3] |= 1<<(eltnum&7); |
801 | (*diffvar + l)[eltnum>>3] |= 1<<(eltnum&7); |
802 | dump += sp->size*cnt; |
802 | dump += sp->size*cnt; |
803 | eltnum++;
|
803 | eltnum++;
|
804 | }
|
804 | }
|
805 | 805 | ||
806 | *diffvar = diff; |
806 | *diffvar = diff; |
807 | *dumpvar = dump; |
807 | *dumpvar = dump; |
808 | return; |
808 | return; |
809 | }
|
809 | }
|
810 | 810 | ||
811 | #define VALOFS(bits,p,ofs) (*(((UINT(bits) *)(p)) + (ofs)))
|
811 | #define VALOFS(bits,p,ofs) (*(((UINT(bits) *)(p)) + (ofs)))
|
812 | 812 | ||
813 | // apply diff to dump, not to state! state is restored from dump afterwards.
|
813 | // apply diff to dump, not to state! state is restored from dump afterwards.
|
814 | static int32_t applydiff(const dataspec_t *spec, uint8_t **dumpvar, uint8_t **diffvar) |
814 | static int32_t applydiff(const dataspec_t *spec, uint8_t **dumpvar, uint8_t **diffvar) |
815 | {
|
815 | {
|
816 | uint8_t *dumptr=*dumpvar, *diffptr=*diffvar; |
816 | uint8_t *dumptr=*dumpvar, *diffptr=*diffvar; |
817 | const dataspec_t *sp=spec; |
817 | const dataspec_t *sp=spec; |
818 | int32_t cnt, eltnum=-1, nbytes=(getnumvar(spec)+7)>>3, l=Bstrlen((const char *)spec->ptr); |
818 | int32_t cnt, eltnum=-1, nbytes=(getnumvar(spec)+7)>>3, l=Bstrlen((const char *)spec->ptr); |
819 | 819 | ||
820 | if (Bmemcmp(diffptr, spec->ptr, l)) // check STRING magic (sync check) |
820 | if (Bmemcmp(diffptr, spec->ptr, l)) // check STRING magic (sync check) |
821 | return 1; |
821 | return 1; |
822 | 822 | ||
823 | diffptr += l+nbytes; |
823 | diffptr += l+nbytes; |
824 | 824 | ||
825 | for (sp++; sp->flags!=DS_END; sp++) |
825 | for (sp++; sp->flags!=DS_END; sp++) |
826 | {
|
826 | {
|
827 | if ((sp->flags&(DS_NOCHK|DS_STRING|DS_CMP|DS_LOADFN|DS_SAVEFN))) |
827 | if ((sp->flags&(DS_NOCHK|DS_STRING|DS_CMP|DS_LOADFN|DS_SAVEFN))) |
828 | continue; |
828 | continue; |
829 | 829 | ||
830 | cnt = ds_getcnt(sp); |
830 | cnt = ds_getcnt(sp); |
831 | if (cnt < 0) return 1; |
831 | if (cnt < 0) return 1; |
832 | 832 | ||
833 | eltnum++;
|
833 | eltnum++;
|
834 | if (((*diffvar + l)[eltnum>>3]&(1<<(eltnum&7))) == 0) |
834 | if (((*diffvar + l)[eltnum>>3]&(1<<(eltnum&7))) == 0) |
835 | {
|
835 | {
|
836 | dumptr += sp->size*cnt; |
836 | dumptr += sp->size*cnt; |
837 | continue; |
837 | continue; |
838 | }
|
838 | }
|
839 | 839 | ||
840 | // ----------
|
840 | // ----------
|
841 | #define CPSINGLEVAL(Datbits) \
|
841 | #define CPSINGLEVAL(Datbits) \
|
842 | VAL(Datbits, dumptr) = VAL(Datbits, diffptr); \
|
842 | VAL(Datbits, dumptr) = VAL(Datbits, diffptr); \
|
843 | diffptr += BYTES(Datbits); \
|
843 | diffptr += BYTES(Datbits); \
|
844 | dumptr += BYTES(Datbits)
|
844 | dumptr += BYTES(Datbits)
|
845 | 845 | ||
846 | if (cnt==1) |
846 | if (cnt==1) |
847 | {
|
847 | {
|
848 | switch (sp->size) |
848 | switch (sp->size) |
849 | {
|
849 | {
|
850 | case 8: CPSINGLEVAL(64); continue; |
850 | case 8: CPSINGLEVAL(64); continue; |
851 | case 4: CPSINGLEVAL(32); continue; |
851 | case 4: CPSINGLEVAL(32); continue; |
852 | case 2: CPSINGLEVAL(16); continue; |
852 | case 2: CPSINGLEVAL(16); continue; |
853 | case 1: CPSINGLEVAL(8); continue; |
853 | case 1: CPSINGLEVAL(8); continue; |
854 | }
|
854 | }
|
855 | }
|
855 | }
|
856 | 856 | ||
857 | #define CPELTS(Idxbits, Datbits) do \
|
857 | #define CPELTS(Idxbits, Datbits) do \
|
858 | { \
|
858 | { \
|
859 | UINT(Idxbits) idx; \
|
859 | UINT(Idxbits) idx; \
|
860 | goto readidx_##Idxbits##_##Datbits; \
|
860 | goto readidx_##Idxbits##_##Datbits; \
|
861 | do \
|
861 | do \
|
862 | { \
|
862 | { \
|
863 | VALOFS(Datbits, dumptr, idx) = VAL(Datbits, diffptr); \
|
863 | VALOFS(Datbits, dumptr, idx) = VAL(Datbits, diffptr); \
|
864 | diffptr += BYTES(Datbits); \
|
864 | diffptr += BYTES(Datbits); \
|
865 | readidx_##Idxbits##_##Datbits: \
|
865 | readidx_##Idxbits##_##Datbits: \
|
866 | idx = VAL(Idxbits, diffptr); \
|
866 | idx = VAL(Idxbits, diffptr); \
|
867 | diffptr += BYTES(Idxbits); \
|
867 | diffptr += BYTES(Idxbits); \
|
868 | } while ((int##Idxbits##_t)idx != -1); \
|
868 | } while ((int##Idxbits##_t)idx != -1); \
|
869 | } while (0)
|
869 | } while (0)
|
870 | 870 | ||
871 | #define CPDATA(Datbits) do \
|
871 | #define CPDATA(Datbits) do \
|
872 | { \
|
872 | { \
|
873 | uint32_t nelts=tabledivide32_noinline(sp->size*cnt, BYTES(Datbits)); \
|
873 | uint32_t nelts=tabledivide32_noinline(sp->size*cnt, BYTES(Datbits)); \
|
874 | if (nelts>65536) \
|
874 | if (nelts>65536) \
|
875 | CPELTS(32,Datbits); \
|
875 | CPELTS(32,Datbits); \
|
876 | else if (nelts>256) \
|
876 | else if (nelts>256) \
|
877 | CPELTS(16,Datbits); \
|
877 | CPELTS(16,Datbits); \
|
878 | else \
|
878 | else \
|
879 | CPELTS(8,Datbits); \
|
879 | CPELTS(8,Datbits); \
|
880 | } while (0)
|
880 | } while (0)
|
881 | 881 | ||
882 | if (sp->size==8) |
882 | if (sp->size==8) |
883 | CPDATA(64); |
883 | CPDATA(64); |
884 | else if ((sp->size&3)==0) |
884 | else if ((sp->size&3)==0) |
885 | CPDATA(32); |
885 | CPDATA(32); |
886 | else if ((sp->size&1)==0) |
886 | else if ((sp->size&1)==0) |
887 | CPDATA(16); |
887 | CPDATA(16); |
888 | else
|
888 | else
|
889 | CPDATA(8); |
889 | CPDATA(8); |
890 | dumptr += sp->size*cnt; |
890 | dumptr += sp->size*cnt; |
891 | // ----------
|
891 | // ----------
|
892 | 892 | ||
893 | #undef CPELTS
|
893 | #undef CPELTS
|
894 | #undef CPSINGLEVAL
|
894 | #undef CPSINGLEVAL
|
895 | #undef CPDATA
|
895 | #undef CPDATA
|
896 | }
|
896 | }
|
897 | 897 | ||
898 | *diffvar = diffptr; |
898 | *diffvar = diffptr; |
899 | *dumpvar = dumptr; |
899 | *dumpvar = dumptr; |
900 | return 0; |
900 | return 0; |
901 | }
|
901 | }
|
902 | 902 | ||
903 | #undef VAL
|
903 | #undef VAL
|
904 | #undef VALOFS
|
904 | #undef VALOFS
|
905 | #undef BYTES
|
905 | #undef BYTES
|
906 | #undef UINT
|
906 | #undef UINT
|
907 | 907 | ||
908 | // calculate size needed for dump
|
908 | // calculate size needed for dump
|
909 | static uint32_t calcsz(const dataspec_t *spec) |
909 | static uint32_t calcsz(const dataspec_t *spec) |
910 | {
|
910 | {
|
911 | const dataspec_t *sp=spec; |
911 | const dataspec_t *sp=spec; |
912 | int32_t cnt; |
912 | int32_t cnt; |
913 | uint32_t dasiz=0; |
913 | uint32_t dasiz=0; |
914 | 914 | ||
915 | for (; sp->flags!=DS_END; sp++) |
915 | for (; sp->flags!=DS_END; sp++) |
916 | {
|
916 | {
|
917 | // DS_STRINGs are used as sync checks in the diffs but not in the dump
|
917 | // DS_STRINGs are used as sync checks in the diffs but not in the dump
|
918 | if ((sp->flags&(DS_CMP|DS_NOCHK|DS_SAVEFN|DS_LOADFN|DS_STRING))) |
918 | if ((sp->flags&(DS_CMP|DS_NOCHK|DS_SAVEFN|DS_LOADFN|DS_STRING))) |
919 | continue; |
919 | continue; |
920 | 920 | ||
921 | cnt = ds_getcnt(sp); |
921 | cnt = ds_getcnt(sp); |
922 | if (cnt<=0) continue; |
922 | if (cnt<=0) continue; |
923 | 923 | ||
924 | dasiz += cnt*sp->size; |
924 | dasiz += cnt*sp->size; |
925 | }
|
925 | }
|
926 | 926 | ||
927 | return dasiz; |
927 | return dasiz; |
928 | }
|
928 | }
|
929 | 929 | ||
930 | #ifdef USE_OPENGL
|
930 | #ifdef USE_OPENGL
|
931 | static void sv_prespriteextsave(); |
931 | static void sv_prespriteextsave(); |
932 | static void sv_postspriteext(); |
932 | static void sv_postspriteext(); |
933 | #endif
|
933 | #endif
|
934 | #if !defined LUNATIC
|
934 | #if !defined LUNATIC
|
935 | static void sv_calcbitptrsize(); |
935 | static void sv_calcbitptrsize(); |
936 | static void sv_prescriptsave_once(); |
936 | static void sv_prescriptsave_once(); |
937 | static void sv_prescriptload_once(); |
937 | static void sv_prescriptload_once(); |
938 | static void sv_postscript_once(); |
938 | static void sv_postscript_once(); |
939 | #else
|
939 | #else
|
940 | // Recreate Lua state.
|
940 | // Recreate Lua state.
|
941 | // XXX: It may matter a great deal when this is run from if the Lua code refers
|
941 | // XXX: It may matter a great deal when this is run from if the Lua code refers
|
942 | // to C-side data at file scope. Such usage is strongly discouraged though.
|
942 | // to C-side data at file scope. Such usage is strongly discouraged though.
|
943 | static void sv_create_lua_state(void) |
943 | static void sv_create_lua_state(void) |
944 | {
|
944 | {
|
945 | El_CreateGameState(); |
945 | El_CreateGameState(); |
946 | G_PostCreateGameState(); |
946 | G_PostCreateGameState(); |
947 | }
|
947 | }
|
948 | #endif
|
948 | #endif
|
949 | static void sv_preactordatasave(); |
949 | static void sv_preactordatasave(); |
950 | static void sv_postactordata(); |
950 | static void sv_postactordata(); |
951 | static void sv_preanimateptrsave(); |
951 | static void sv_preanimateptrsave(); |
952 | static void sv_postanimateptr(); |
952 | static void sv_postanimateptr(); |
953 | static void sv_prequote(); |
953 | static void sv_prequote(); |
954 | static void sv_quotesave(); |
954 | static void sv_quotesave(); |
955 | static void sv_quoteload(); |
955 | static void sv_quoteload(); |
956 | static void sv_prequoteredef(); |
956 | static void sv_prequoteredef(); |
957 | static void sv_quoteredefsave(); |
957 | static void sv_quoteredefsave(); |
958 | static void sv_quoteredefload(); |
958 | static void sv_quoteredefload(); |
959 | static void sv_postquoteredef(); |
959 | static void sv_postquoteredef(); |
960 | static void sv_restsave(); |
960 | static void sv_restsave(); |
961 | static void sv_restload(); |
961 | static void sv_restload(); |
962 | 962 | ||
963 | #define SVARDATALEN \
|
963 | #define SVARDATALEN \
|
964 | ((sizeof(g_player[0].user_name)+sizeof(g_player[0].pcolor)+sizeof(g_player[0].pteam) \
|
964 | ((sizeof(g_player[0].user_name)+sizeof(g_player[0].pcolor)+sizeof(g_player[0].pteam) \
|
965 | +sizeof(g_player[0].frags)+sizeof(DukePlayer_t))*MAXPLAYERS)
|
965 | +sizeof(g_player[0].frags)+sizeof(DukePlayer_t))*MAXPLAYERS)
|
966 | 966 | ||
967 | #if !defined LUNATIC
|
967 | #if !defined LUNATIC
|
968 | static uint32_t savegame_bitptrsize; |
968 | static uint32_t savegame_bitptrsize; |
969 | #endif
|
969 | #endif
|
970 | static uint8_t savegame_quotedef[MAXQUOTES>>3]; |
970 | static uint8_t savegame_quotedef[MAXQUOTES>>3]; |
971 | static char(*savegame_quotes)[MAXQUOTELEN]; |
971 | static char(*savegame_quotes)[MAXQUOTELEN]; |
972 | static char(*savegame_quoteredefs)[MAXQUOTELEN]; |
972 | static char(*savegame_quoteredefs)[MAXQUOTELEN]; |
973 | static uint8_t savegame_restdata[SVARDATALEN]; |
973 | static uint8_t savegame_restdata[SVARDATALEN]; |
974 | 974 | ||
975 | static const dataspec_t svgm_udnetw[] = |
975 | static const dataspec_t svgm_udnetw[] = |
976 | {
|
976 | {
|
977 | { DS_STRING, (void *)"blK:udnt", 0, 1 }, |
977 | { DS_STRING, (void *)"blK:udnt", 0, 1 }, |
978 | { 0, &ud.multimode, sizeof(ud.multimode), 1 }, |
978 | { 0, &ud.multimode, sizeof(ud.multimode), 1 }, |
979 | { 0, &g_numPlayerSprites, sizeof(g_numPlayerSprites), 1 }, |
979 | { 0, &g_numPlayerSprites, sizeof(g_numPlayerSprites), 1 }, |
980 | { 0, &g_playerSpawnPoints, sizeof(g_playerSpawnPoints), 1 }, |
980 | { 0, &g_playerSpawnPoints, sizeof(g_playerSpawnPoints), 1 }, |
981 | 981 | ||
982 | { DS_NOCHK, &ud.volume_number, sizeof(ud.volume_number), 1 }, |
982 | { DS_NOCHK, &ud.volume_number, sizeof(ud.volume_number), 1 }, |
983 | { DS_NOCHK, &ud.level_number, sizeof(ud.level_number), 1 }, |
983 | { DS_NOCHK, &ud.level_number, sizeof(ud.level_number), 1 }, |
984 | { DS_NOCHK, &ud.player_skill, sizeof(ud.player_skill), 1 }, |
984 | { DS_NOCHK, &ud.player_skill, sizeof(ud.player_skill), 1 }, |
985 | 985 | ||
986 | { DS_NOCHK, &ud.from_bonus, sizeof(ud.from_bonus), 1 }, |
986 | { DS_NOCHK, &ud.from_bonus, sizeof(ud.from_bonus), 1 }, |
987 | { DS_NOCHK, &ud.secretlevel, sizeof(ud.secretlevel), 1 }, |
987 | { DS_NOCHK, &ud.secretlevel, sizeof(ud.secretlevel), 1 }, |
988 | { DS_NOCHK, &ud.respawn_monsters, sizeof(ud.respawn_monsters), 1 }, |
988 | { DS_NOCHK, &ud.respawn_monsters, sizeof(ud.respawn_monsters), 1 }, |
989 | { DS_NOCHK, &ud.respawn_items, sizeof(ud.respawn_items), 1 }, |
989 | { DS_NOCHK, &ud.respawn_items, sizeof(ud.respawn_items), 1 }, |
990 | { DS_NOCHK, &ud.respawn_inventory, sizeof(ud.respawn_inventory), 1 }, |
990 | { DS_NOCHK, &ud.respawn_inventory, sizeof(ud.respawn_inventory), 1 }, |
991 | { 0, &ud.god, sizeof(ud.god), 1 }, |
991 | { 0, &ud.god, sizeof(ud.god), 1 }, |
992 | { 0, &ud.auto_run, sizeof(ud.auto_run), 1 }, |
992 | { 0, &ud.auto_run, sizeof(ud.auto_run), 1 }, |
993 | // { DS_NOCHK, &ud.crosshair, sizeof(ud.crosshair), 1 },
|
993 | // { DS_NOCHK, &ud.crosshair, sizeof(ud.crosshair), 1 },
|
994 | { DS_NOCHK, &ud.monsters_off, sizeof(ud.monsters_off), 1 }, |
994 | { DS_NOCHK, &ud.monsters_off, sizeof(ud.monsters_off), 1 }, |
995 | { DS_NOCHK, &ud.last_level, sizeof(ud.last_level), 1 }, |
995 | { DS_NOCHK, &ud.last_level, sizeof(ud.last_level), 1 }, |
996 | { 0, &ud.eog, sizeof(ud.eog), 1 }, |
996 | { 0, &ud.eog, sizeof(ud.eog), 1 }, |
997 | { DS_NOCHK, &ud.coop, sizeof(ud.coop), 1 }, |
997 | { DS_NOCHK, &ud.coop, sizeof(ud.coop), 1 }, |
998 | { DS_NOCHK, &ud.marker, sizeof(ud.marker), 1 }, |
998 | { DS_NOCHK, &ud.marker, sizeof(ud.marker), 1 }, |
999 | { DS_NOCHK, &ud.ffire, sizeof(ud.ffire), 1 }, |
999 | { DS_NOCHK, &ud.ffire, sizeof(ud.ffire), 1 }, |
1000 | { DS_NOCHK, &ud.noexits, sizeof(ud.noexits), 1 }, |
1000 | { DS_NOCHK, &ud.noexits, sizeof(ud.noexits), 1 }, |
1001 | { DS_NOCHK, &ud.playerai, sizeof(ud.playerai), 1 }, |
1001 | { DS_NOCHK, &ud.playerai, sizeof(ud.playerai), 1 }, |
1002 | { 0, &ud.pause_on, sizeof(ud.pause_on), 1 }, |
1002 | { 0, &ud.pause_on, sizeof(ud.pause_on), 1 }, |
1003 | { DS_NOCHK, ¤tboardfilename[0], BMAX_PATH, 1 }, |
1003 | { DS_NOCHK, ¤tboardfilename[0], BMAX_PATH, 1 }, |
1004 | // { DS_LOADFN, (void *)&sv_postudload, 0, 1 },
|
1004 | // { DS_LOADFN, (void *)&sv_postudload, 0, 1 },
|
1005 | { 0, connectpoint2, sizeof(connectpoint2), 1 }, |
1005 | { 0, connectpoint2, sizeof(connectpoint2), 1 }, |
1006 | { 0, &randomseed, sizeof(randomseed), 1 }, |
1006 | { 0, &randomseed, sizeof(randomseed), 1 }, |
1007 | { 0, &g_globalRandom, sizeof(g_globalRandom), 1 }, |
1007 | { 0, &g_globalRandom, sizeof(g_globalRandom), 1 }, |
1008 | #ifdef LUNATIC
|
1008 | #ifdef LUNATIC
|
1009 | // Save game tic count for Lunatic because it is exposed to userland. See
|
1009 | // Save game tic count for Lunatic because it is exposed to userland. See
|
1010 | // test/helixspawner.lua for an example.
|
1010 | // test/helixspawner.lua for an example.
|
1011 | { 0, &g_moveThingsCount, sizeof(g_moveThingsCount), 1 }, |
1011 | { 0, &g_moveThingsCount, sizeof(g_moveThingsCount), 1 }, |
1012 | #endif
|
1012 | #endif
|
1013 | // { 0, &lockclock_dummy, sizeof(lockclock), 1 },
|
1013 | // { 0, &lockclock_dummy, sizeof(lockclock), 1 },
|
1014 | { DS_END, 0, 0, 0 } |
1014 | { DS_END, 0, 0, 0 } |
1015 | }; |
1015 | }; |
1016 | 1016 | ||
1017 | #if !defined DEBUG_MAIN_ARRAYS
|
1017 | #if !defined DEBUG_MAIN_ARRAYS
|
1018 | # define DS_MAINAR DS_DYNAMIC
|
1018 | # define DS_MAINAR DS_DYNAMIC
|
1019 | #else
|
1019 | #else
|
1020 | # define DS_MAINAR 0
|
1020 | # define DS_MAINAR 0
|
1021 | #endif
|
1021 | #endif
|
1022 | 1022 | ||
1023 | static const dataspec_t svgm_secwsp[] = |
1023 | static const dataspec_t svgm_secwsp[] = |
1024 | {
|
1024 | {
|
1025 | { DS_STRING, (void *)"blK:swsp", 0, 1 }, |
1025 | { DS_STRING, (void *)"blK:swsp", 0, 1 }, |
1026 | { DS_NOCHK, &numwalls, sizeof(numwalls), 1 }, |
1026 | { DS_NOCHK, &numwalls, sizeof(numwalls), 1 }, |
1027 | { DS_MAINAR|DS_CNT(numwalls), &wall, sizeof(walltype), (intptr_t)&numwalls }, |
1027 | { DS_MAINAR|DS_CNT(numwalls), &wall, sizeof(walltype), (intptr_t)&numwalls }, |
1028 | { DS_NOCHK, &numsectors, sizeof(numsectors), 1 }, |
1028 | { DS_NOCHK, &numsectors, sizeof(numsectors), 1 }, |
1029 | { DS_MAINAR|DS_CNT(numsectors), §or, sizeof(sectortype), (intptr_t)&numsectors }, |
1029 | { DS_MAINAR|DS_CNT(numsectors), §or, sizeof(sectortype), (intptr_t)&numsectors }, |
1030 | { DS_MAINAR, &sprite, sizeof(spritetype), MAXSPRITES }, |
1030 | { DS_MAINAR, &sprite, sizeof(spritetype), MAXSPRITES }, |
1031 | #ifdef YAX_ENABLE
|
1031 | #ifdef YAX_ENABLE
|
1032 | { DS_NOCHK, &numyaxbunches, sizeof(numyaxbunches), 1 }, |
1032 | { DS_NOCHK, &numyaxbunches, sizeof(numyaxbunches), 1 }, |
1033 | # if !defined NEW_MAP_FORMAT
|
1033 | # if !defined NEW_MAP_FORMAT
|
1034 | { DS_CNT(numsectors), yax_bunchnum, sizeof(yax_bunchnum[0]), (intptr_t)&numsectors }, |
1034 | { DS_CNT(numsectors), yax_bunchnum, sizeof(yax_bunchnum[0]), (intptr_t)&numsectors }, |
1035 | { DS_CNT(numwalls), yax_nextwall, sizeof(yax_nextwall[0]), (intptr_t)&numwalls }, |
1035 | { DS_CNT(numwalls), yax_nextwall, sizeof(yax_nextwall[0]), (intptr_t)&numwalls }, |
1036 | # endif
|
1036 | # endif
|
1037 | { DS_LOADFN|DS_PROTECTFN, (void *)&sv_postyaxload, 0, 1 }, |
1037 | { DS_LOADFN|DS_PROTECTFN, (void *)&sv_postyaxload, 0, 1 }, |
1038 | #endif
|
1038 | #endif
|
1039 | { 0, &Numsprites, sizeof(Numsprites), 1 }, |
1039 | { 0, &Numsprites, sizeof(Numsprites), 1 }, |
1040 | { 0, &tailspritefree, sizeof(tailspritefree), 1 }, |
1040 | { 0, &tailspritefree, sizeof(tailspritefree), 1 }, |
1041 | { 0, &headspritesect[0], sizeof(headspritesect[0]), MAXSECTORS+1 }, |
1041 | { 0, &headspritesect[0], sizeof(headspritesect[0]), MAXSECTORS+1 }, |
1042 | { 0, &prevspritesect[0], sizeof(prevspritesect[0]), MAXSPRITES }, |
1042 | { 0, &prevspritesect[0], sizeof(prevspritesect[0]), MAXSPRITES }, |
1043 | { 0, &nextspritesect[0], sizeof(nextspritesect[0]), MAXSPRITES }, |
1043 | { 0, &nextspritesect[0], sizeof(nextspritesect[0]), MAXSPRITES }, |
1044 | { 0, &headspritestat[0], sizeof(headspritestat[0]), MAXSTATUS+1 }, |
1044 | { 0, &headspritestat[0], sizeof(headspritestat[0]), MAXSTATUS+1 }, |
1045 | { 0, &prevspritestat[0], sizeof(prevspritestat[0]), MAXSPRITES }, |
1045 | { 0, &prevspritestat[0], sizeof(prevspritestat[0]), MAXSPRITES }, |
1046 | { 0, &nextspritestat[0], sizeof(nextspritestat[0]), MAXSPRITES }, |
1046 | { 0, &nextspritestat[0], sizeof(nextspritestat[0]), MAXSPRITES }, |
1047 | #ifdef USE_OPENGL
|
1047 | #ifdef USE_OPENGL
|
1048 | { DS_SAVEFN, (void *)&sv_prespriteextsave, 0, 1 }, |
1048 | { DS_SAVEFN, (void *)&sv_prespriteextsave, 0, 1 }, |
1049 | #endif
|
1049 | #endif
|
1050 | { DS_MAINAR, &spriteext, sizeof(spriteext_t), MAXSPRITES }, |
1050 | { DS_MAINAR, &spriteext, sizeof(spriteext_t), MAXSPRITES }, |
1051 | #ifdef USE_OPENGL
|
1051 | #ifdef USE_OPENGL
|
1052 | { DS_SAVEFN|DS_LOADFN, (void *)&sv_postspriteext, 0, 1 }, |
1052 | { DS_SAVEFN|DS_LOADFN, (void *)&sv_postspriteext, 0, 1 }, |
1053 | #endif
|
1053 | #endif
|
1054 | { 0, &DynamicTileMap[0], sizeof(DynamicTileMap[0]), MAXTILES }, // NOCHK? |
1054 | { 0, &DynamicTileMap[0], sizeof(DynamicTileMap[0]), MAXTILES }, // NOCHK? |
1055 | { 0, &DynamicSoundMap[0], sizeof(DynamicSoundMap[0]), MAXSOUNDS }, // NOCHK? |
1055 | { 0, &DynamicSoundMap[0], sizeof(DynamicSoundMap[0]), MAXSOUNDS }, // NOCHK? |
1056 | { DS_NOCHK, &g_numCyclers, sizeof(g_numCyclers), 1 }, |
1056 | { DS_NOCHK, &g_numCyclers, sizeof(g_numCyclers), 1 }, |
1057 | { DS_CNT(g_numCyclers), &cyclers[0][0], sizeof(cyclers[0]), (intptr_t)&g_numCyclers }, |
1057 | { DS_CNT(g_numCyclers), &cyclers[0][0], sizeof(cyclers[0]), (intptr_t)&g_numCyclers }, |
1058 | { DS_NOCHK, &g_numAnimWalls, sizeof(g_numAnimWalls), 1 }, |
1058 | { DS_NOCHK, &g_numAnimWalls, sizeof(g_numAnimWalls), 1 }, |
1059 | { DS_CNT(g_numAnimWalls), &animwall, sizeof(animwall[0]), (intptr_t)&g_numAnimWalls }, |
1059 | { DS_CNT(g_numAnimWalls), &animwall, sizeof(animwall[0]), (intptr_t)&g_numAnimWalls }, |
1060 | { DS_NOCHK, &g_mirrorCount, sizeof(g_mirrorCount), 1 }, |
1060 | { DS_NOCHK, &g_mirrorCount, sizeof(g_mirrorCount), 1 }, |
1061 | { DS_NOCHK, &g_mirrorWall[0], sizeof(g_mirrorWall[0]), ARRAY_SIZE(g_mirrorWall) }, |
1061 | { DS_NOCHK, &g_mirrorWall[0], sizeof(g_mirrorWall[0]), ARRAY_SIZE(g_mirrorWall) }, |
1062 | { DS_NOCHK, &g_mirrorSector[0], sizeof(g_mirrorSector[0]), ARRAY_SIZE(g_mirrorSector) }, |
1062 | { DS_NOCHK, &g_mirrorSector[0], sizeof(g_mirrorSector[0]), ARRAY_SIZE(g_mirrorSector) }, |
1063 | // projectiles
|
1063 | // projectiles
|
1064 | { 0, &SpriteProjectile[0], sizeof(projectile_t), MAXSPRITES }, |
1064 | { 0, &SpriteProjectile[0], sizeof(projectile_t), MAXSPRITES }, |
1065 | { 0, &ProjectileData[0], sizeof(projectile_t), MAXTILES }, |
1065 | { 0, &ProjectileData[0], sizeof(projectile_t), MAXTILES }, |
1066 | { 0, &everyothertime, sizeof(everyothertime), 1 }, |
1066 | { 0, &everyothertime, sizeof(everyothertime), 1 }, |
1067 | { DS_END, 0, 0, 0 } |
1067 | { DS_END, 0, 0, 0 } |
1068 | }; |
1068 | }; |
1069 | 1069 | ||
1070 | static const dataspec_t svgm_script[] = |
1070 | static const dataspec_t svgm_script[] = |
1071 | {
|
1071 | {
|
1072 | { DS_STRING, (void *)"blK:scri", 0, 1 }, |
1072 | { DS_STRING, (void *)"blK:scri", 0, 1 }, |
1073 | #if !defined LUNATIC
|
1073 | #if !defined LUNATIC
|
1074 | { DS_NOCHK, &g_scriptSize, sizeof(g_scriptSize), 1 }, |
1074 | { DS_NOCHK, &g_scriptSize, sizeof(g_scriptSize), 1 }, |
1075 | { DS_SAVEFN|DS_LOADFN|DS_NOCHK, (void *)&sv_calcbitptrsize, 0, 1 }, |
1075 | { DS_SAVEFN|DS_LOADFN|DS_NOCHK, (void *)&sv_calcbitptrsize, 0, 1 }, |
1076 | { DS_DYNAMIC|DS_CNT(savegame_bitptrsize)|DS_NOCHK, &bitptr, sizeof(bitptr[0]), (intptr_t)&savegame_bitptrsize }, |
1076 | { DS_DYNAMIC|DS_CNT(savegame_bitptrsize)|DS_NOCHK, &bitptr, sizeof(bitptr[0]), (intptr_t)&savegame_bitptrsize }, |
1077 | 1077 | ||
1078 | { DS_SAVEFN|DS_NOCHK, (void *)&sv_prescriptsave_once, 0, 1 }, |
1078 | { DS_SAVEFN|DS_NOCHK, (void *)&sv_prescriptsave_once, 0, 1 }, |
1079 | #endif
|
1079 | #endif
|
1080 | { DS_NOCHK, &g_tile[0], sizeof(tiledata_t), MAXTILES }, |
1080 | { DS_NOCHK, &g_tile[0], sizeof(tiledata_t), MAXTILES }, |
1081 | #if !defined LUNATIC
|
1081 | #if !defined LUNATIC
|
1082 | { DS_LOADFN|DS_NOCHK, (void *)&sv_prescriptload_once, 0, 1 }, |
1082 | { DS_LOADFN|DS_NOCHK, (void *)&sv_prescriptload_once, 0, 1 }, |
1083 | { DS_DYNAMIC|DS_CNT(g_scriptSize)|DS_NOCHK, &script, sizeof(script[0]), (intptr_t)&g_scriptSize }, |
1083 | { DS_DYNAMIC|DS_CNT(g_scriptSize)|DS_NOCHK, &script, sizeof(script[0]), (intptr_t)&g_scriptSize }, |
1084 | // { DS_NOCHK, &apScriptGameEvent[0], sizeof(apScriptGameEvent[0]), MAXGAMEEVENTS },
|
1084 | // { DS_NOCHK, &apScriptGameEvent[0], sizeof(apScriptGameEvent[0]), MAXGAMEEVENTS },
|
1085 | { DS_SAVEFN|DS_LOADFN|DS_NOCHK, (void *)&sv_postscript_once, 0, 1 }, |
1085 | { DS_SAVEFN|DS_LOADFN|DS_NOCHK, (void *)&sv_postscript_once, 0, 1 }, |
1086 | #endif
|
1086 | #endif
|
1087 | { DS_SAVEFN, (void *)&sv_preactordatasave, 0, 1 }, |
1087 | { DS_SAVEFN, (void *)&sv_preactordatasave, 0, 1 }, |
1088 | { 0, &actor[0], sizeof(actor_t), MAXSPRITES }, |
1088 | { 0, &actor[0], sizeof(actor_t), MAXSPRITES }, |
1089 | { DS_SAVEFN|DS_LOADFN, (void *)&sv_postactordata, 0, 1 }, |
1089 | { DS_SAVEFN|DS_LOADFN, (void *)&sv_postactordata, 0, 1 }, |
1090 | #if defined LUNATIC
|
1090 | #if defined LUNATIC
|
1091 | { DS_LOADFN|DS_NOCHK, (void *)&sv_create_lua_state, 0, 1 }, |
1091 | { DS_LOADFN|DS_NOCHK, (void *)&sv_create_lua_state, 0, 1 }, |
1092 | #endif
|
1092 | #endif
|
1093 | { DS_END, 0, 0, 0 } |
1093 | { DS_END, 0, 0, 0 } |
1094 | }; |
1094 | }; |
1095 | 1095 | ||
1096 | static const dataspec_t svgm_anmisc[] = |
1096 | static const dataspec_t svgm_anmisc[] = |
1097 | {
|
1097 | {
|
1098 | { DS_STRING, (void *)"blK:anms", 0, 1 }, |
1098 | { DS_STRING, (void *)"blK:anms", 0, 1 }, |
1099 | { 0, &g_animateCount, sizeof(g_animateCount), 1 }, |
1099 | { 0, &g_animateCount, sizeof(g_animateCount), 1 }, |
1100 | { 0, &animatesect[0], sizeof(animatesect[0]), MAXANIMATES }, |
1100 | { 0, &animatesect[0], sizeof(animatesect[0]), MAXANIMATES }, |
1101 | { 0, &animategoal[0], sizeof(animategoal[0]), MAXANIMATES }, |
1101 | { 0, &animategoal[0], sizeof(animategoal[0]), MAXANIMATES }, |
1102 | { 0, &animatevel[0], sizeof(animatevel[0]), MAXANIMATES }, |
1102 | { 0, &animatevel[0], sizeof(animatevel[0]), MAXANIMATES }, |
1103 | { DS_SAVEFN, (void *)&sv_preanimateptrsave, 0, 1 }, |
1103 | { DS_SAVEFN, (void *)&sv_preanimateptrsave, 0, 1 }, |
1104 | { 0, &animateptr[0], sizeof(animateptr[0]), MAXANIMATES }, |
1104 | { 0, &animateptr[0], sizeof(animateptr[0]), MAXANIMATES }, |
1105 | { DS_SAVEFN|DS_LOADFN , (void *)&sv_postanimateptr, 0, 1 }, |
1105 | { DS_SAVEFN|DS_LOADFN , (void *)&sv_postanimateptr, 0, 1 }, |
1106 | { 0, &g_curViewscreen, sizeof(g_curViewscreen), 1 }, |
1106 | { 0, &g_curViewscreen, sizeof(g_curViewscreen), 1 }, |
1107 | { 0, &msx[0], sizeof(msx[0]), ARRAY_SIZE(msx) }, |
1107 | { 0, &msx[0], sizeof(msx[0]), ARRAY_SIZE(msx) }, |
1108 | { 0, &msy[0], sizeof(msy[0]), ARRAY_SIZE(msy) }, |
1108 | { 0, &msy[0], sizeof(msy[0]), ARRAY_SIZE(msy) }, |
1109 | { 0, &g_spriteDeleteQueuePos, sizeof(g_spriteDeleteQueuePos), 1 }, |
1109 | { 0, &g_spriteDeleteQueuePos, sizeof(g_spriteDeleteQueuePos), 1 }, |
1110 | { DS_NOCHK, &g_spriteDeleteQueueSize, sizeof(g_spriteDeleteQueueSize), 1 }, |
1110 | { DS_NOCHK, &g_spriteDeleteQueueSize, sizeof(g_spriteDeleteQueueSize), 1 }, |
1111 | { DS_CNT(g_spriteDeleteQueueSize), &SpriteDeletionQueue[0], sizeof(int16_t), (intptr_t)&g_spriteDeleteQueueSize }, |
1111 | { DS_CNT(g_spriteDeleteQueueSize), &SpriteDeletionQueue[0], sizeof(int16_t), (intptr_t)&g_spriteDeleteQueueSize }, |
1112 | { 0, &show2dsector[0], sizeof(uint8_t), MAXSECTORS>>3 }, |
1112 | { 0, &show2dsector[0], sizeof(uint8_t), MAXSECTORS>>3 }, |
1113 | { DS_NOCHK, &g_numClouds, sizeof(g_numClouds), 1 }, |
1113 | { DS_NOCHK, &g_numClouds, sizeof(g_numClouds), 1 }, |
1114 | { 0, &clouds[0], sizeof(clouds), 1 }, |
1114 | { 0, &clouds[0], sizeof(clouds), 1 }, |
1115 | { 0, &cloudx[0], sizeof(cloudx), 1 }, |
1115 | { 0, &cloudx[0], sizeof(cloudx), 1 }, |
1116 | { 0, &cloudy[0], sizeof(cloudy), 1 }, |
1116 | { 0, &cloudy[0], sizeof(cloudy), 1 }, |
1117 | { 0, &g_pskyidx, sizeof(g_pskyidx), 1 }, // DS_NOCHK? |
1117 | { 0, &g_pskyidx, sizeof(g_pskyidx), 1 }, // DS_NOCHK? |
1118 | { 0, &g_earthquakeTime, sizeof(g_earthquakeTime), 1 }, |
1118 | { 0, &g_earthquakeTime, sizeof(g_earthquakeTime), 1 }, |
1119 | 1119 | ||
1120 | { DS_SAVEFN|DS_LOADFN|DS_NOCHK, (void *)sv_prequote, 0, 1 }, |
1120 | { DS_SAVEFN|DS_LOADFN|DS_NOCHK, (void *)sv_prequote, 0, 1 }, |
1121 | { DS_SAVEFN, (void *)&sv_quotesave, 0, 1 }, |
1121 | { DS_SAVEFN, (void *)&sv_quotesave, 0, 1 }, |
1122 | { DS_NOCHK, &savegame_quotedef, sizeof(savegame_quotedef), 1 }, // quotes can change during runtime, but new quote numbers cannot be allocated |
1122 | { DS_NOCHK, &savegame_quotedef, sizeof(savegame_quotedef), 1 }, // quotes can change during runtime, but new quote numbers cannot be allocated |
1123 | { DS_DYNAMIC, &savegame_quotes, MAXQUOTELEN, MAXQUOTES }, |
1123 | { DS_DYNAMIC, &savegame_quotes, MAXQUOTELEN, MAXQUOTES }, |
1124 | { DS_LOADFN, (void *)&sv_quoteload, 0, 1 }, |
1124 | { DS_LOADFN, (void *)&sv_quoteload, 0, 1 }, |
1125 | 1125 | ||
1126 | { DS_NOCHK, &g_numQuoteRedefinitions, sizeof(g_numQuoteRedefinitions), 1 }, |
1126 | { DS_NOCHK, &g_numQuoteRedefinitions, sizeof(g_numQuoteRedefinitions), 1 }, |
1127 | { DS_NOCHK|DS_SAVEFN|DS_LOADFN, (void *)&sv_prequoteredef, 0, 1 }, |
1127 | { DS_NOCHK|DS_SAVEFN|DS_LOADFN, (void *)&sv_prequoteredef, 0, 1 }, |
1128 | { DS_NOCHK|DS_SAVEFN, (void *)&sv_quoteredefsave, 0, 1 }, // quote redefinitions replace quotes at runtime, but cannot be changed after CON compilation |
1128 | { DS_NOCHK|DS_SAVEFN, (void *)&sv_quoteredefsave, 0, 1 }, // quote redefinitions replace quotes at runtime, but cannot be changed after CON compilation |
1129 | { DS_NOCHK|DS_DYNAMIC|DS_CNT(g_numQuoteRedefinitions), &savegame_quoteredefs, MAXQUOTELEN, (intptr_t)&g_numQuoteRedefinitions }, |
1129 | { DS_NOCHK|DS_DYNAMIC|DS_CNT(g_numQuoteRedefinitions), &savegame_quoteredefs, MAXQUOTELEN, (intptr_t)&g_numQuoteRedefinitions }, |
1130 | { DS_NOCHK|DS_LOADFN, (void *)&sv_quoteredefload, 0, 1 }, |
1130 | { DS_NOCHK|DS_LOADFN, (void *)&sv_quoteredefload, 0, 1 }, |
1131 | { DS_NOCHK|DS_SAVEFN|DS_LOADFN, (void *)&sv_postquoteredef, 0, 1 }, |
1131 | { DS_NOCHK|DS_SAVEFN|DS_LOADFN, (void *)&sv_postquoteredef, 0, 1 }, |
1132 | #ifdef LUNATIC
|
1132 | #ifdef LUNATIC
|
1133 | { 0, g_playerWeapon, sizeof(weapondata_t), MAXPLAYERS*MAX_WEAPONS }, |
1133 | { 0, g_playerWeapon, sizeof(weapondata_t), MAXPLAYERS*MAX_WEAPONS }, |
1134 | #endif
|
1134 | #endif
|
1135 | { DS_SAVEFN, (void *)&sv_restsave, 0, 1 }, |
1135 | { DS_SAVEFN, (void *)&sv_restsave, 0, 1 }, |
1136 | { 0, savegame_restdata, 1, sizeof(savegame_restdata) }, // sz/cnt swapped for kdfread |
1136 | { 0, savegame_restdata, 1, sizeof(savegame_restdata) }, // sz/cnt swapped for kdfread |
1137 | { DS_LOADFN, (void *)&sv_restload, 0, 1 }, |
1137 | { DS_LOADFN, (void *)&sv_restload, 0, 1 }, |
1138 | 1138 | ||
1139 | { DS_STRING, (void *)"savegame_end", 0, 1 }, |
1139 | { DS_STRING, (void *)"savegame_end", 0, 1 }, |
1140 | { DS_END, 0, 0, 0 } |
1140 | { DS_END, 0, 0, 0 } |
1141 | }; |
1141 | }; |
1142 | 1142 | ||
1143 | #if !defined LUNATIC
|
1143 | #if !defined LUNATIC
|
1144 | static dataspec_t *svgm_vars=NULL; |
1144 | static dataspec_t *svgm_vars=NULL; |
1145 | #endif
|
1145 | #endif
|
1146 | static uint8_t *dosaveplayer2(FILE *fil, uint8_t *mem); |
1146 | static uint8_t *dosaveplayer2(FILE *fil, uint8_t *mem); |
1147 | static int32_t doloadplayer2(int32_t fil, uint8_t **memptr); |
1147 | static int32_t doloadplayer2(int32_t fil, uint8_t **memptr); |
1148 | static void postloadplayer(int32_t savegamep); |
1148 | static void postloadplayer(int32_t savegamep); |
1149 | 1149 | ||
1150 | // SVGM snapshot system
|
1150 | // SVGM snapshot system
|
1151 | static uint32_t svsnapsiz; |
1151 | static uint32_t svsnapsiz; |
1152 | static uint8_t *svsnapshot, *svinitsnap; |
1152 | static uint8_t *svsnapshot, *svinitsnap; |
1153 | static uint32_t svdiffsiz; |
1153 | static uint32_t svdiffsiz; |
1154 | static uint8_t *svdiff; |
1154 | static uint8_t *svdiff; |
1155 | 1155 | ||
1156 | #include "gamedef.h"
|
1156 | #include "gamedef.h"
|
1157 | 1157 | ||
1158 | #if !defined LUNATIC
|
1158 | #if !defined LUNATIC
|
1159 | # define SV_SKIPMASK (/*GAMEVAR_SYSTEM|*/GAMEVAR_READONLY|GAMEVAR_INTPTR| \
|
1159 | # define SV_SKIPMASK (/*GAMEVAR_SYSTEM|*/GAMEVAR_READONLY|GAMEVAR_INTPTR| \
|
1160 | GAMEVAR_SHORTPTR|GAMEVAR_CHARPTR /*|GAMEVAR_NORESET*/ |GAMEVAR_SPECIAL)
|
1160 | GAMEVAR_SHORTPTR|GAMEVAR_CHARPTR /*|GAMEVAR_NORESET*/ |GAMEVAR_SPECIAL)
|
1161 | // setup gamevar data spec for snapshotting and diffing... gamevars must be loaded when called
|
1161 | // setup gamevar data spec for snapshotting and diffing... gamevars must be loaded when called
|
1162 | static void sv_makevarspec() |
1162 | static void sv_makevarspec() |
1163 | {
|
1163 | {
|
1164 | static char *magic = "blK:vars"; |
1164 | static char *magic = "blK:vars"; |
1165 | int32_t i, j, numsavedvars=0, numsavedarrays=0, per; |
1165 | int32_t i, j, numsavedvars=0, numsavedarrays=0, per; |
1166 | 1166 | ||
1167 | for (i=0; i<g_gameVarCount; i++) |
1167 | for (i=0; i<g_gameVarCount; i++) |
1168 | numsavedvars += (aGameVars[i].dwFlags&SV_SKIPMASK) ? 0 : 1; |
1168 | numsavedvars += (aGameVars[i].dwFlags&SV_SKIPMASK) ? 0 : 1; |
1169 | 1169 | ||
1170 | for (i=0; i<g_gameArrayCount; i++) |
1170 | for (i=0; i<g_gameArrayCount; i++) |
1171 | numsavedarrays += !(aGameArrays[i].dwFlags & GAMEARRAY_READONLY); // SYSTEM_GAMEARRAY |
1171 | numsavedarrays += !(aGameArrays[i].dwFlags & GAMEARRAY_READONLY); // SYSTEM_GAMEARRAY |
1172 | 1172 | ||
1173 | Bfree(svgm_vars); |
1173 | Bfree(svgm_vars); |
1174 | svgm_vars = (dataspec_t *)Xmalloc((numsavedvars+numsavedarrays+2)*sizeof(dataspec_t)); |
1174 | svgm_vars = (dataspec_t *)Xmalloc((numsavedvars+numsavedarrays+2)*sizeof(dataspec_t)); |
1175 | 1175 | ||
1176 | svgm_vars[0].flags = DS_STRING; |
1176 | svgm_vars[0].flags = DS_STRING; |
1177 | svgm_vars[0].ptr = magic; |
1177 | svgm_vars[0].ptr = magic; |
1178 | svgm_vars[0].cnt = 1; |
1178 | svgm_vars[0].cnt = 1; |
1179 | 1179 | ||
1180 | j=1; |
1180 | j=1; |
1181 | for (i=0; i<g_gameVarCount; i++) |
1181 | for (i=0; i<g_gameVarCount; i++) |
1182 | {
|
1182 | {
|
1183 | if (aGameVars[i].dwFlags&SV_SKIPMASK) |
1183 | if (aGameVars[i].dwFlags&SV_SKIPMASK) |
1184 | continue; |
1184 | continue; |
1185 | 1185 | ||
1186 | per = aGameVars[i].dwFlags&GAMEVAR_USER_MASK; |
1186 | per = aGameVars[i].dwFlags&GAMEVAR_USER_MASK; |
1187 | 1187 | ||
1188 | svgm_vars[j].flags = 0; |
1188 | svgm_vars[j].flags = 0; |
1189 | svgm_vars[j].ptr = (per==0) ? &aGameVars[i].val.lValue : aGameVars[i].val.plValues; |
1189 | svgm_vars[j].ptr = (per==0) ? &aGameVars[i].val.lValue : aGameVars[i].val.plValues; |
1190 | svgm_vars[j].size = sizeof(intptr_t); |
1190 | svgm_vars[j].size = sizeof(intptr_t); |
1191 | svgm_vars[j].cnt = (per==0) ? 1 : (per==GAMEVAR_PERPLAYER ? MAXPLAYERS : MAXSPRITES); |
1191 | svgm_vars[j].cnt = (per==0) ? 1 : (per==GAMEVAR_PERPLAYER ? MAXPLAYERS : MAXSPRITES); |
1192 | j++;
|
1192 | j++;
|
1193 | }
|
1193 | }
|
1194 | 1194 | ||
1195 | for (i=0; i<g_gameArrayCount; i++) |
1195 | for (i=0; i<g_gameArrayCount; i++) |
1196 | {
|
1196 | {
|
1197 | // We must not update read-only SYSTEM_GAMEARRAY gamearrays: besides
|
1197 | // We must not update read-only SYSTEM_GAMEARRAY gamearrays: besides
|
1198 | // being questionable by itself, sizeof(...) may be e.g. 4 whereas the
|
1198 | // being questionable by itself, sizeof(...) may be e.g. 4 whereas the
|
1199 | // actual element type is int16_t (such as tilesizx[]/tilesizy[]).
|
1199 | // actual element type is int16_t (such as tilesizx[]/tilesizy[]).
|
1200 | if (aGameArrays[i].dwFlags & GAMEARRAY_READONLY) |
1200 | if (aGameArrays[i].dwFlags & GAMEARRAY_READONLY) |
1201 | continue; |
1201 | continue; |
1202 | 1202 | ||
1203 | svgm_vars[j].flags = 0; |
1203 | svgm_vars[j].flags = 0; |
1204 | svgm_vars[j].ptr = aGameArrays[i].plValues; |
1204 | svgm_vars[j].ptr = aGameArrays[i].plValues; |
1205 | svgm_vars[j].size = sizeof(aGameArrays[0].plValues[0]); |
1205 | svgm_vars[j].size = sizeof(aGameArrays[0].plValues[0]); |
1206 | svgm_vars[j].cnt = aGameArrays[i].size; // assumed constant throughout demo, i.e. no RESIZEARRAY |
1206 | svgm_vars[j].cnt = aGameArrays[i].size; // assumed constant throughout demo, i.e. no RESIZEARRAY |
1207 | j++;
|
1207 | j++;
|
1208 | }
|
1208 | }
|
1209 | 1209 | ||
1210 | svgm_vars[j].flags = DS_END; |
1210 | svgm_vars[j].flags = DS_END; |
1211 | svgm_vars[j].ptr = NULL; |
1211 | svgm_vars[j].ptr = NULL; |
1212 | svgm_vars[j].size = svgm_vars[j].cnt = 0; |
1212 | svgm_vars[j].size = svgm_vars[j].cnt = 0; |
1213 | }
|
1213 | }
|
1214 | #endif
|
1214 | #endif
|
1215 | 1215 | ||
1216 | void sv_freemem() |
1216 | void sv_freemem() |
1217 | {
|
1217 | {
|
1218 | DO_FREE_AND_NULL(svsnapshot); |
1218 | DO_FREE_AND_NULL(svsnapshot); |
1219 | DO_FREE_AND_NULL(svinitsnap); |
1219 | DO_FREE_AND_NULL(svinitsnap); |
1220 | DO_FREE_AND_NULL(svdiff); |
1220 | DO_FREE_AND_NULL(svdiff); |
1221 | }
|
1221 | }
|
1222 | 1222 | ||
1223 | static void SV_AllocSnap(int32_t allocinit) |
1223 | static void SV_AllocSnap(int32_t allocinit) |
1224 | {
|
1224 | {
|
1225 | sv_freemem(); |
1225 | sv_freemem(); |
1226 | 1226 | ||
1227 | svsnapshot = (uint8_t *)Xmalloc(svsnapsiz); |
1227 | svsnapshot = (uint8_t *)Xmalloc(svsnapsiz); |
1228 | if (allocinit) |
1228 | if (allocinit) |
1229 | svinitsnap = (uint8_t *)Xmalloc(svsnapsiz); |
1229 | svinitsnap = (uint8_t *)Xmalloc(svsnapsiz); |
1230 | svdiffsiz = svsnapsiz; // theoretically it's less than could be needed in the worst case, but practically it's overkill |
1230 | svdiffsiz = svsnapsiz; // theoretically it's less than could be needed in the worst case, but practically it's overkill |
1231 | svdiff = (uint8_t *)Xmalloc(svdiffsiz); |
1231 | svdiff = (uint8_t *)Xmalloc(svdiffsiz); |
1232 | }
|
1232 | }
|
1233 | 1233 | ||
1234 | EDUKE32_STATIC_ASSERT(sizeof(savehead_t) == SAVEHEAD_SIZE); |
1234 | EDUKE32_STATIC_ASSERT(sizeof(savehead_t) == SAVEHEAD_SIZE); |
1235 | 1235 | ||
1236 | // make snapshot only if spot < 0 (demo)
|
1236 | // make snapshot only if spot < 0 (demo)
|
1237 | int32_t sv_saveandmakesnapshot(FILE *fil, int8_t spot, int8_t recdiffsp, int8_t diffcompress, int8_t synccompress) |
1237 | int32_t sv_saveandmakesnapshot(FILE *fil, int8_t spot, int8_t recdiffsp, int8_t diffcompress, int8_t synccompress) |
1238 | {
|
1238 | {
|
1239 | savehead_t h;
|
1239 | savehead_t h;
|
1240 | 1240 | ||
1241 | // set a few savegame system globals
|
1241 | // set a few savegame system globals
|
1242 | savegame_comprthres = SV_DEFAULTCOMPRTHRES; |
1242 | savegame_comprthres = SV_DEFAULTCOMPRTHRES; |
1243 | savegame_diffcompress = diffcompress; |
1243 | savegame_diffcompress = diffcompress; |
1244 | 1244 | ||
1245 | // calculate total snapshot size
|
1245 | // calculate total snapshot size
|
1246 | #if !defined LUNATIC
|
1246 | #if !defined LUNATIC
|
1247 | sv_makevarspec(); |
1247 | sv_makevarspec(); |
1248 | svsnapsiz = calcsz(svgm_vars); |
1248 | svsnapsiz = calcsz(svgm_vars); |
1249 | #else
|
1249 | #else
|
1250 | svsnapsiz = 0; |
1250 | svsnapsiz = 0; |
1251 | #endif
|
1251 | #endif
|
1252 | svsnapsiz += calcsz(svgm_udnetw) + calcsz(svgm_secwsp) + calcsz(svgm_script) + calcsz(svgm_anmisc); |
1252 | svsnapsiz += calcsz(svgm_udnetw) + calcsz(svgm_secwsp) + calcsz(svgm_script) + calcsz(svgm_anmisc); |
1253 | 1253 | ||
1254 | 1254 | ||
1255 | // create header
|
1255 | // create header
|
1256 | Bmemcpy(h.headerstr, "EDuke32SAVE", 11); |
1256 | Bmemcpy(h.headerstr, "EDuke32SAVE", 11); |
1257 | h.majorver = SV_MAJOR_VER; |
1257 | h.majorver = SV_MAJOR_VER; |
1258 | h.minorver = SV_MINOR_VER; |
1258 | h.minorver = SV_MINOR_VER; |
1259 | h.ptrsize = sizeof(intptr_t); |
1259 | h.ptrsize = sizeof(intptr_t); |
1260 | h.bytever = BYTEVERSION; |
1260 | h.bytever = BYTEVERSION; |
1261 | 1261 | ||
1262 | h.comprthres = savegame_comprthres; |
1262 | h.comprthres = savegame_comprthres; |
1263 | h.recdiffsp = recdiffsp; |
1263 | h.recdiffsp = recdiffsp; |
1264 | h.diffcompress = savegame_diffcompress; |
1264 | h.diffcompress = savegame_diffcompress; |
1265 | h.synccompress = synccompress; |
1265 | h.synccompress = synccompress; |
1266 | 1266 | ||
1267 | h.reccnt = 0; |
1267 | h.reccnt = 0; |
1268 | h.snapsiz = svsnapsiz; |
1268 | h.snapsiz = svsnapsiz; |
1269 | 1269 | ||
1270 | // the following is kinda redundant, but we save it here to be able to quickly fetch
|
1270 | // the following is kinda redundant, but we save it here to be able to quickly fetch
|
1271 | // it in a savegame header read
|
1271 | // it in a savegame header read
|
1272 | h.numplayers = ud.multimode; |
1272 | h.numplayers = ud.multimode; |
1273 | h.volnum = ud.volume_number; |
1273 | h.volnum = ud.volume_number; |
1274 | h.levnum = ud.level_number; |
1274 | h.levnum = ud.level_number; |
1275 | h.skill = ud.player_skill; |
1275 | h.skill = ud.player_skill; |
1276 | 1276 | ||
1277 | if (currentboardfilename[0] != 0 && ud.level_number == 7 && ud.volume_number == 0) |
1277 | if (currentboardfilename[0] != 0 && ud.level_number == 7 && ud.volume_number == 0) |
1278 | {
|
1278 | {
|
1279 | const uint32_t BSZ = sizeof(h.boardfn); |
1279 | const uint32_t BSZ = sizeof(h.boardfn); |
1280 | EDUKE32_STATIC_ASSERT(BSZ == sizeof(currentboardfilename)); |
1280 | EDUKE32_STATIC_ASSERT(BSZ == sizeof(currentboardfilename)); |
1281 | 1281 | ||
1282 | Bstrncpy(h.boardfn, currentboardfilename, BSZ); |
1282 | Bstrncpy(h.boardfn, currentboardfilename, BSZ); |
1283 | 1283 | ||
1284 | // Shoehorn currently playing music into last bytes of board name buffer.
|
1284 | // Shoehorn currently playing music into last bytes of board name buffer.
|
1285 | // SAVEGAME_MUSIC.
|
1285 | // SAVEGAME_MUSIC.
|
1286 | if (g_musicIndex != (0*MAXLEVELS+7) && Bstrlen(h.boardfn) < BSZ-2) |
1286 | if (g_musicIndex != (0*MAXLEVELS+7) && Bstrlen(h.boardfn) < BSZ-2) |
1287 | {
|
1287 | {
|
1288 | h.boardfn[BSZ-2] = g_musicIndex / MAXLEVELS; |
1288 | h.boardfn[BSZ-2] = g_musicIndex / MAXLEVELS; |
1289 | h.boardfn[BSZ-1] = g_musicIndex % MAXLEVELS; |
1289 | h.boardfn[BSZ-1] = g_musicIndex % MAXLEVELS; |
1290 | }
|
1290 | }
|
1291 | }
|
1291 | }
|
1292 | 1292 | ||
1293 | if ((unsigned)spot < MAXSAVEGAMES) |
1293 | if ((unsigned)spot < MAXSAVEGAMES) |
1294 | {
|
1294 | {
|
1295 | // savegame
|
1295 | // savegame
|
1296 | Bstrncpyz(h.savename, ud.savegame[spot], sizeof(h.savename)); |
1296 | Bstrncpyz(h.savename, ud.savegame[spot], sizeof(h.savename)); |
1297 | #ifdef __ANDROID__
|
1297 | #ifdef __ANDROID__
|
1298 | Bstrncpyz(h.volname, EpisodeNames[ud.volume_number], sizeof(h.volname)); |
1298 | Bstrncpyz(h.volname, EpisodeNames[ud.volume_number], sizeof(h.volname)); |
1299 | Bstrncpyz(h.skillname, SkillNames[ud.player_skill], sizeof(h.skillname)); |
1299 | Bstrncpyz(h.skillname, SkillNames[ud.player_skill], sizeof(h.skillname)); |
1300 | #endif
|
1300 | #endif
|
1301 | }
|
1301 | }
|
1302 | else
|
1302 | else
|
1303 | {
|
1303 | {
|
1304 | // demo
|
1304 | // demo
|
1305 | 1305 | ||
1306 | const time_t t=time(NULL); |
1306 | const time_t t=time(NULL); |
1307 | struct tm *st; |
1307 | struct tm *st; |
1308 | 1308 | ||
1309 | Bstrncpyz(h.savename, "EDuke32 demo", sizeof(h.savename)); |
1309 | Bstrncpyz(h.savename, "EDuke32 demo", sizeof(h.savename)); |
1310 | if (t>=0 && (st = localtime(&t))) |
1310 | if (t>=0 && (st = localtime(&t))) |
1311 | Bsnprintf(h.savename, sizeof(h.savename), "Demo %04d%02d%02d %s", |
1311 | Bsnprintf(h.savename, sizeof(h.savename), "Demo %04d%02d%02d %s", |
1312 | st->tm_year+1900, st->tm_mon+1, st->tm_mday, s_buildRev); |
1312 | st->tm_year+1900, st->tm_mon+1, st->tm_mday, s_buildRev); |
1313 | }
|
1313 | }
|
1314 | 1314 | ||
1315 | 1315 | ||
1316 | // write header
|
1316 | // write header
|
1317 | fwrite(&h, sizeof(savehead_t), 1, fil); |
1317 | fwrite(&h, sizeof(savehead_t), 1, fil); |
1318 | 1318 | ||
1319 | // for savegames, the file offset after the screenshot goes here;
|
1319 | // for savegames, the file offset after the screenshot goes here;
|
1320 | // for demos, we keep it 0 to signify that we didn't save one
|
1320 | // for demos, we keep it 0 to signify that we didn't save one
|
1321 | fwrite("\0\0\0\0", 4, 1, fil); |
1321 | fwrite("\0\0\0\0", 4, 1, fil); |
1322 | if (spot >= 0 && waloff[TILE_SAVESHOT]) |
1322 | if (spot >= 0 && waloff[TILE_SAVESHOT]) |
1323 | {
|
1323 | {
|
1324 | int32_t ofs; |
1324 | int32_t ofs; |
1325 | 1325 | ||
1326 | // write the screenshot compressed
|
1326 | // write the screenshot compressed
|
1327 | dfwrite((char *)waloff[TILE_SAVESHOT], 320, 200, fil); |
1327 | dfwrite((char *)waloff[TILE_SAVESHOT], 320, 200, fil); |
1328 | 1328 | ||
1329 | // write the current file offset right after the header
|
1329 | // write the current file offset right after the header
|
1330 | ofs = ftell(fil); |
1330 | ofs = ftell(fil); |
1331 | fseek(fil, sizeof(savehead_t), SEEK_SET); |
1331 | fseek(fil, sizeof(savehead_t), SEEK_SET); |
1332 | fwrite(&ofs, 4, 1, fil); |
1332 | fwrite(&ofs, 4, 1, fil); |
1333 | fseek(fil, ofs, SEEK_SET); |
1333 | fseek(fil, ofs, SEEK_SET); |
1334 | }
|
1334 | }
|
1335 | 1335 | ||
1336 | #ifdef DEBUGGINGAIDS
|
1336 | #ifdef DEBUGGINGAIDS
|
1337 | OSD_Printf("sv_saveandmakesnapshot: snapshot size: %d bytes.\n", svsnapsiz); |
1337 | OSD_Printf("sv_saveandmakesnapshot: snapshot size: %d bytes.\n", svsnapsiz); |
1338 | #endif
|
1338 | #endif
|
1339 | 1339 | ||
1340 | if (spot >= 0) |
1340 | if (spot >= 0) |
1341 | {
|
1341 | {
|
1342 | // savegame
|
1342 | // savegame
|
1343 | dosaveplayer2(fil, NULL); |
1343 | dosaveplayer2(fil, NULL); |
1344 | #ifdef LUNATIC
|
1344 | #ifdef LUNATIC
|
1345 | if (!g_savedOK) |
1345 | if (!g_savedOK) |
1346 | {
|
1346 | {
|
1347 | OSD_Printf("sv_saveandmakesnapshot: failed serializing Lunatic gamevar \"%s\".\n", |
1347 | OSD_Printf("sv_saveandmakesnapshot: failed serializing Lunatic gamevar \"%s\".\n", |
1348 | g_failedVarname); |
1348 | g_failedVarname); |
1349 | g_failedVarname = NULL; |
1349 | g_failedVarname = NULL; |
1350 | return 1; |
1350 | return 1; |
1351 | }
|
1351 | }
|
1352 | #endif
|
1352 | #endif
|
1353 | }
|
1353 | }
|
1354 | else
|
1354 | else
|
1355 | {
|
1355 | {
|
1356 | uint8_t *p; |
1356 | uint8_t *p; |
1357 | 1357 | ||
1358 | // demo
|
1358 | // demo
|
1359 | SV_AllocSnap(0); |
1359 | SV_AllocSnap(0); |
1360 | 1360 | ||
1361 | p = dosaveplayer2(fil, svsnapshot); |
1361 | p = dosaveplayer2(fil, svsnapshot); |
1362 | if (p != svsnapshot+svsnapsiz) |
1362 | if (p != svsnapshot+svsnapsiz) |
1363 | {
|
1363 | {
|
1364 | OSD_Printf("sv_saveandmakesnapshot: ptr-(snapshot end)=%d!\n", (int32_t)(p-(svsnapshot+svsnapsiz))); |
1364 | OSD_Printf("sv_saveandmakesnapshot: ptr-(snapshot end)=%d!\n", (int32_t)(p-(svsnapshot+svsnapsiz))); |
1365 | return 1; |
1365 | return 1; |
1366 | }
|
1366 | }
|
1367 | }
|
1367 | }
|
1368 | 1368 | ||
1369 | g_oldverSavegame[spot] = 0; |
1369 | g_oldverSavegame[spot] = 0; |
1370 | 1370 | ||
1371 | return 0; |
1371 | return 0; |
1372 | }
|
1372 | }
|
1373 | 1373 | ||
1374 | EDUKE32_STATIC_ASSERT(sizeof(savehead_t) == SAVEHEAD_SIZE); |
1374 | EDUKE32_STATIC_ASSERT(sizeof(savehead_t) == SAVEHEAD_SIZE); |
1375 | 1375 | ||
1376 | // if file is not an EDuke32 savegame/demo, h->headerstr will be all zeros
|
1376 | // if file is not an EDuke32 savegame/demo, h->headerstr will be all zeros
|
1377 | int32_t sv_loadheader(int32_t fil, int32_t spot, savehead_t *h) |
1377 | int32_t sv_loadheader(int32_t fil, int32_t spot, savehead_t *h) |
1378 | {
|
1378 | {
|
1379 | int32_t havedemo = (spot < 0); |
1379 | int32_t havedemo = (spot < 0); |
1380 | 1380 | ||
1381 | if (kread(fil, h, sizeof(savehead_t)) != sizeof(savehead_t)) |
1381 | if (kread(fil, h, sizeof(savehead_t)) != sizeof(savehead_t)) |
1382 | {
|
1382 | {
|
1383 | OSD_Printf("%s %d header corrupt.\n", havedemo ? "Demo":"Savegame", havedemo ? -spot : spot); |
1383 | OSD_Printf("%s %d header corrupt.\n", havedemo ? "Demo":"Savegame", havedemo ? -spot : spot); |
1384 | Bmemset(h->headerstr, 0, sizeof(h->headerstr)); |
1384 | Bmemset(h->headerstr, 0, sizeof(h->headerstr)); |
1385 | return -1; |
1385 | return -1; |
1386 | }
|
1386 | }
|
1387 | 1387 | ||
1388 | if (Bmemcmp(h->headerstr, "EDuke32SAVE", 11)) |
1388 | if (Bmemcmp(h->headerstr, "EDuke32SAVE", 11)) |
1389 | {
|
1389 | {
|
1390 | h->headerstr[sizeof(h->headerstr)-1] = 0; |
1390 | h->headerstr[sizeof(h->headerstr)-1] = 0; |
1391 | OSD_Printf("%s %d header reads \"%s\", expected \"EDuke32SAVE\".\n", |
1391 | OSD_Printf("%s %d header reads \"%s\", expected \"EDuke32SAVE\".\n", |
1392 | havedemo ? "Demo":"Savegame", havedemo ? -spot : spot, h->headerstr); |
1392 | havedemo ? "Demo":"Savegame", havedemo ? -spot : spot, h->headerstr); |
1393 | Bmemset(h->headerstr, 0, sizeof(h->headerstr)); |
1393 | Bmemset(h->headerstr, 0, sizeof(h->headerstr)); |
1394 | return 1; |
1394 | return 1; |
1395 | }
|
1395 | }
|
1396 | 1396 | ||
1397 | if (h->majorver != SV_MAJOR_VER || h->minorver != SV_MINOR_VER || h->bytever != BYTEVERSION) |
1397 | if (h->majorver != SV_MAJOR_VER || h->minorver != SV_MINOR_VER || h->bytever != BYTEVERSION) |
1398 | {
|
1398 | {
|
1399 | if (havedemo) |
1399 | if (havedemo) |
1400 | OSD_Printf("Incompatible demo version. Expected %d.%d.%d, found %d.%d.%d\n", |
1400 | OSD_Printf("Incompatible demo version. Expected %d.%d.%d, found %d.%d.%d\n", |
1401 | SV_MAJOR_VER, SV_MINOR_VER, BYTEVERSION, |
1401 | SV_MAJOR_VER, SV_MINOR_VER, BYTEVERSION, |
1402 | h->majorver, h->minorver, h->bytever); |
1402 | h->majorver, h->minorver, h->bytever); |
1403 | return 2; |
1403 | return 2; |
1404 | }
|
1404 | }
|
1405 | 1405 | ||
1406 | if (h->ptrsize != sizeof(intptr_t)) |
1406 | if (h->ptrsize != sizeof(intptr_t)) |
1407 | {
|
1407 | {
|
1408 | if (havedemo) |
1408 | if (havedemo) |
1409 | OSD_Printf("Demo incompatible. Expected pointer size %d, found %d\n", |
1409 | OSD_Printf("Demo incompatible. Expected pointer size %d, found %d\n", |
1410 | (int32_t)sizeof(intptr_t), h->ptrsize); |
1410 | (int32_t)sizeof(intptr_t), h->ptrsize); |
1411 | return 3; |
1411 | return 3; |
1412 | }
|
1412 | }
|
1413 | 1413 | ||
1414 | return 0; |
1414 | return 0; |
1415 | }
|
1415 | }
|
1416 | 1416 | ||
1417 | int32_t sv_loadsnapshot(int32_t fil, int32_t spot, savehead_t *h) |
1417 | int32_t sv_loadsnapshot(int32_t fil, int32_t spot, savehead_t *h) |
1418 | {
|
1418 | {
|
1419 | uint8_t *p; |
1419 | uint8_t *p; |
1420 | int32_t i; |
1420 | int32_t i; |
1421 | 1421 | ||
1422 | if (spot < 0) |
1422 | if (spot < 0) |
1423 | {
|
1423 | {
|
1424 | // demo
|
1424 | // demo
|
1425 | i = sv_loadheader(fil, spot, h); |
1425 | i = sv_loadheader(fil, spot, h); |
1426 | if (i) |
1426 | if (i) |
1427 | return i; |
1427 | return i; |
1428 | 1428 | ||
1429 | // Used to be in doloadplayer2(), now redundant for savegames since
|
1429 | // Used to be in doloadplayer2(), now redundant for savegames since
|
1430 | // we checked before. Multiplayer demos need still to be taken care of.
|
1430 | // we checked before. Multiplayer demos need still to be taken care of.
|
1431 | if (h->numplayers != numplayers) |
1431 | if (h->numplayers != numplayers) |
1432 | return 9; |
1432 | return 9; |
1433 | }
|
1433 | }
|
1434 | // else (if savegame), we just read the header and are now at offset sizeof(savehead_t)
|
1434 | // else (if savegame), we just read the header and are now at offset sizeof(savehead_t)
|
1435 | 1435 | ||
1436 | #ifdef DEBUGGINGAIDS
|
1436 | #ifdef DEBUGGINGAIDS
|
1437 | OSD_Printf("sv_loadsnapshot: snapshot size: %d bytes.\n", h->snapsiz); |
1437 | OSD_Printf("sv_loadsnapshot: snapshot size: %d bytes.\n", h->snapsiz); |
1438 | #endif
|
1438 | #endif
|
1439 | 1439 | ||
1440 | if (kread(fil, &i, 4) != 4) |
1440 | if (kread(fil, &i, 4) != 4) |
1441 | {
|
1441 | {
|
1442 | OSD_Printf("sv_snapshot: couldn't read 4 bytes after header.\n"); |
1442 | OSD_Printf("sv_snapshot: couldn't read 4 bytes after header.\n"); |
1443 | return 7; |
1443 | return 7; |
1444 | }
|
1444 | }
|
1445 | if (i > 0) |
1445 | if (i > 0) |
1446 | {
|
1446 | {
|
1447 | if (klseek(fil, i, SEEK_SET) != i) |
1447 | if (klseek(fil, i, SEEK_SET) != i) |
1448 | {
|
1448 | {
|
1449 | OSD_Printf("sv_snapshot: failed skipping over the screenshot.\n"); |
1449 | OSD_Printf("sv_snapshot: failed skipping over the screenshot.\n"); |
1450 | return 8; |
1450 | return 8; |
1451 | }
|
1451 | }
|
1452 | }
|
1452 | }
|
1453 | 1453 | ||
1454 | savegame_comprthres = h->comprthres; |
1454 | savegame_comprthres = h->comprthres; |
1455 | 1455 | ||
1456 | if (spot >= 0) |
1456 | if (spot >= 0) |
1457 | {
|
1457 | {
|
1458 | // savegame
|
1458 | // savegame
|
1459 | i = doloadplayer2(fil, NULL); |
1459 | i = doloadplayer2(fil, NULL); |
1460 | if (i) |
1460 | if (i) |
1461 | {
|
1461 | {
|
1462 | OSD_Printf("sv_loadsnapshot: doloadplayer2() returned %d.\n", i); |
1462 | OSD_Printf("sv_loadsnapshot: doloadplayer2() returned %d.\n", i); |
1463 | return 5; |
1463 | return 5; |
1464 | }
|
1464 | }
|
1465 | }
|
1465 | }
|
1466 | else
|
1466 | else
|
1467 | {
|
1467 | {
|
1468 | // demo
|
1468 | // demo
|
1469 | savegame_diffcompress = h->diffcompress; |
1469 | savegame_diffcompress = h->diffcompress; |
1470 | 1470 | ||
1471 | svsnapsiz = h->snapsiz; |
1471 | svsnapsiz = h->snapsiz; |
1472 | 1472 | ||
1473 | SV_AllocSnap(1); |
1473 | SV_AllocSnap(1); |
1474 | 1474 | ||
1475 | p = svsnapshot; |
1475 | p = svsnapshot; |
1476 | i = doloadplayer2(fil, &p); |
1476 | i = doloadplayer2(fil, &p); |
1477 | if (i) |
1477 | if (i) |
1478 | {
|
1478 | {
|
1479 | OSD_Printf("sv_loadsnapshot: doloadplayer2() returned %d.\n", i); |
1479 | OSD_Printf("sv_loadsnapshot: doloadplayer2() returned %d.\n", i); |
1480 | sv_freemem(); |
1480 | sv_freemem(); |
1481 | return 5; |
1481 | return 5; |
1482 | }
|
1482 | }
|
1483 | 1483 | ||
1484 | if (p != svsnapshot+svsnapsiz) |
1484 | if (p != svsnapshot+svsnapsiz) |
1485 | {
|
1485 | {
|
1486 | OSD_Printf("sv_loadsnapshot: internal error: p-(snapshot end)=%d!\n", |
1486 | OSD_Printf("sv_loadsnapshot: internal error: p-(snapshot end)=%d!\n", |
1487 | (int32_t)(p-(svsnapshot+svsnapsiz))); |
1487 | (int32_t)(p-(svsnapshot+svsnapsiz))); |
1488 | sv_freemem(); |
1488 | sv_freemem(); |
1489 | return 6; |
1489 | return 6; |
1490 | }
|
1490 | }
|
1491 | 1491 | ||
1492 | Bmemcpy(svinitsnap, svsnapshot, svsnapsiz); |
1492 | Bmemcpy(svinitsnap, svsnapshot, svsnapsiz); |
1493 | }
|
1493 | }
|
1494 | 1494 | ||
1495 | postloadplayer((spot >= 0)); |
1495 | postloadplayer((spot >= 0)); |
1496 | 1496 | ||
1497 | return 0; |
1497 | return 0; |
1498 | }
|
1498 | }
|
1499 | 1499 | ||
1500 | 1500 | ||
1501 | uint32_t sv_writediff(FILE *fil) |
1501 | uint32_t sv_writediff(FILE *fil) |
1502 | {
|
1502 | {
|
1503 | uint8_t *p=svsnapshot, *d=svdiff; |
1503 | uint8_t *p=svsnapshot, *d=svdiff; |
1504 | uint32_t diffsiz; |
1504 | uint32_t diffsiz; |
1505 | 1505 | ||
1506 | cmpspecdata(svgm_udnetw, &p, &d); |
1506 | cmpspecdata(svgm_udnetw, &p, &d); |
1507 | cmpspecdata(svgm_secwsp, &p, &d); |
1507 | cmpspecdata(svgm_secwsp, &p, &d); |
1508 | cmpspecdata(svgm_script, &p, &d); |
1508 | cmpspecdata(svgm_script, &p, &d); |
1509 | cmpspecdata(svgm_anmisc, &p, &d); |
1509 | cmpspecdata(svgm_anmisc, &p, &d); |
1510 | #if !defined LUNATIC
|
1510 | #if !defined LUNATIC
|
1511 | cmpspecdata(svgm_vars, &p, &d); |
1511 | cmpspecdata(svgm_vars, &p, &d); |
1512 | #endif
|
1512 | #endif
|
1513 | 1513 | ||
1514 | if (p != svsnapshot+svsnapsiz) |
1514 | if (p != svsnapshot+svsnapsiz) |
1515 | OSD_Printf("sv_writediff: dump+siz=%p, p=%p!\n", svsnapshot+svsnapsiz, p); |
1515 | OSD_Printf("sv_writediff: dump+siz=%p, p=%p!\n", svsnapshot+svsnapsiz, p); |
1516 | 1516 | ||
1517 | diffsiz = d-svdiff; |
1517 | diffsiz = d-svdiff; |
1518 | 1518 | ||
1519 | fwrite("dIfF",4,1,fil); |
1519 | fwrite("dIfF",4,1,fil); |
1520 | fwrite(&diffsiz, sizeof(diffsiz), 1, fil); |
1520 | fwrite(&diffsiz, sizeof(diffsiz), 1, fil); |
1521 | if (savegame_diffcompress) |
1521 | if (savegame_diffcompress) |
1522 | dfwrite(svdiff, 1, diffsiz, fil); // cnt and sz swapped |
1522 | dfwrite(svdiff, 1, diffsiz, fil); // cnt and sz swapped |
1523 | else
|
1523 | else
|
1524 | fwrite(svdiff, 1, diffsiz, fil); |
1524 | fwrite(svdiff, 1, diffsiz, fil); |
1525 | 1525 | ||
1526 | return diffsiz; |
1526 | return diffsiz; |
1527 | }
|
1527 | }
|
1528 | 1528 | ||
1529 | int32_t sv_readdiff(int32_t fil) |
1529 | int32_t sv_readdiff(int32_t fil) |
1530 | {
|
1530 | {
|
1531 | uint8_t *p=svsnapshot, *d=svdiff, i=0; //, tbuf[4]; |
1531 | uint8_t *p=svsnapshot, *d=svdiff, i=0; //, tbuf[4]; |
1532 | int32_t diffsiz; |
1532 | int32_t diffsiz; |
1533 | 1533 | ||
1534 | #if 0 // handled by the caller
|
1534 | #if 0 // handled by the caller
|
1535 | if (kread(fil, tbuf, 4)!=4) |
1535 | if (kread(fil, tbuf, 4)!=4) |
1536 | return -1; |
1536 | return -1; |
1537 | if (Bmemcmp(tbuf, "dIfF", 4)) |
1537 | if (Bmemcmp(tbuf, "dIfF", 4)) |
1538 | return 4; |
1538 | return 4; |
1539 | #endif
|
1539 | #endif
|
1540 | if (kread(fil, &diffsiz, sizeof(uint32_t))!=sizeof(uint32_t)) |
1540 | if (kread(fil, &diffsiz, sizeof(uint32_t))!=sizeof(uint32_t)) |
1541 | return -1; |
1541 | return -1; |
1542 | if (savegame_diffcompress) |
1542 | if (savegame_diffcompress) |
1543 | {
|
1543 | {
|
1544 | if (kdfread(svdiff, 1, diffsiz, fil) != diffsiz) // cnt and sz swapped |
1544 | if (kdfread(svdiff, 1, diffsiz, fil) != diffsiz) // cnt and sz swapped |
1545 | return -2; |
1545 | return -2; |
1546 | }
|
1546 | }
|
1547 | else
|
1547 | else
|
1548 | {
|
1548 | {
|
1549 | if (kread(fil, svdiff, diffsiz) != diffsiz) |
1549 | if (kread(fil, svdiff, diffsiz) != diffsiz) |
1550 | return -2; |
1550 | return -2; |
1551 | }
|
1551 | }
|
1552 | 1552 | ||
1553 | if (applydiff(svgm_udnetw, &p, &d)) return -3; |
1553 | if (applydiff(svgm_udnetw, &p, &d)) return -3; |
1554 | if (applydiff(svgm_secwsp, &p, &d)) return -4; |
1554 | if (applydiff(svgm_secwsp, &p, &d)) return -4; |
1555 | if (applydiff(svgm_script, &p, &d)) return -5; |
1555 | if (applydiff(svgm_script, &p, &d)) return -5; |
1556 | if (applydiff(svgm_anmisc, &p, &d)) return -6; |
1556 | if (applydiff(svgm_anmisc, &p, &d)) return -6; |
1557 | #if !defined LUNATIC
|
1557 | #if !defined LUNATIC
|
1558 | if (applydiff(svgm_vars, &p, &d)) return -7; |
1558 | if (applydiff(svgm_vars, &p, &d)) return -7; |
1559 | #endif
|
1559 | #endif
|
1560 | 1560 | ||
1561 | if (p!=svsnapshot+svsnapsiz) |
1561 | if (p!=svsnapshot+svsnapsiz) |
1562 | i|=1; |
1562 | i|=1; |
1563 | if (d!=svdiff+diffsiz) |
1563 | if (d!=svdiff+diffsiz) |
1564 | i|=2; |
1564 | i|=2; |
1565 | if (i) |
1565 | if (i) |
1566 | OSD_Printf("sv_readdiff: p=%p, svsnapshot+svsnapsiz=%p; d=%p, svdiff+diffsiz=%p", |
1566 | OSD_Printf("sv_readdiff: p=%p, svsnapshot+svsnapsiz=%p; d=%p, svdiff+diffsiz=%p", |
1567 | p, svsnapshot+svsnapsiz, d, svdiff+diffsiz); |
1567 | p, svsnapshot+svsnapsiz, d, svdiff+diffsiz); |
1568 | return i; |
1568 | return i; |
1569 | }
|
1569 | }
|
1570 | 1570 | ||
1571 | // SVGM data description
|
1571 | // SVGM data description
|
1572 | static void sv_postudload() |
1572 | static void sv_postudload() |
1573 | {
|
1573 | {
|
1574 | // Bmemcpy(&boardfilename[0], ¤tboardfilename[0], BMAX_PATH); // DON'T do this in demos!
|
1574 | // Bmemcpy(&boardfilename[0], ¤tboardfilename[0], BMAX_PATH); // DON'T do this in demos!
|
1575 | #if 1
|
1575 | #if 1
|
1576 | ud.m_level_number = ud.level_number; |
1576 | ud.m_level_number = ud.level_number; |
1577 | ud.m_volume_number = ud.volume_number; |
1577 | ud.m_volume_number = ud.volume_number; |
1578 | ud.m_player_skill = ud.player_skill; |
1578 | ud.m_player_skill = ud.player_skill; |
1579 | ud.m_respawn_monsters = ud.respawn_monsters; |
1579 | ud.m_respawn_monsters = ud.respawn_monsters; |
1580 | ud.m_respawn_items = ud.respawn_items; |
1580 | ud.m_respawn_items = ud.respawn_items; |
1581 | ud.m_respawn_inventory = ud.respawn_inventory; |
1581 | ud.m_respawn_inventory = ud.respawn_inventory; |
1582 | ud.m_monsters_off = ud.monsters_off; |
1582 | ud.m_monsters_off = ud.monsters_off; |
1583 | ud.m_coop = ud.coop; |
1583 | ud.m_coop = ud.coop; |
1584 | ud.m_marker = ud.marker; |
1584 | ud.m_marker = ud.marker; |
1585 | ud.m_ffire = ud.ffire; |
1585 | ud.m_ffire = ud.ffire; |
1586 | ud.m_noexits = ud.noexits; |
1586 | ud.m_noexits = ud.noexits; |
1587 | #endif
|
1587 | #endif
|
1588 | }
|
1588 | }
|
1589 | //static int32_t lockclock_dummy;
|
1589 | //static int32_t lockclock_dummy;
|
1590 | 1590 | ||
1591 | #ifdef USE_OPENGL
|
1591 | #ifdef USE_OPENGL
|
1592 | static void sv_prespriteextsave() |
1592 | static void sv_prespriteextsave() |
1593 | {
|
1593 | {
|
1594 | int32_t i; |
1594 | int32_t i; |
1595 | for (i=0; i<MAXSPRITES; i++) |
1595 | for (i=0; i<MAXSPRITES; i++) |
1596 | if (spriteext[i].mdanimtims) |
1596 | if (spriteext[i].mdanimtims) |
1597 | {
|
1597 | {
|
1598 | spriteext[i].mdanimtims -= mdtims; |
1598 | spriteext[i].mdanimtims -= mdtims; |
1599 | if (spriteext[i].mdanimtims==0) |
1599 | if (spriteext[i].mdanimtims==0) |
1600 | spriteext[i].mdanimtims++; |
1600 | spriteext[i].mdanimtims++; |
1601 | }
|
1601 | }
|
1602 | }
|
1602 | }
|
1603 | static void sv_postspriteext() |
1603 | static void sv_postspriteext() |
1604 | {
|
1604 | {
|
1605 | int32_t i; |
1605 | int32_t i; |
1606 | for (i=0; i<MAXSPRITES; i++) |
1606 | for (i=0; i<MAXSPRITES; i++) |
1607 | if (spriteext[i].mdanimtims) |
1607 | if (spriteext[i].mdanimtims) |
1608 | spriteext[i].mdanimtims += mdtims; |
1608 | spriteext[i].mdanimtims += mdtims; |
1609 | }
|
1609 | }
|
1610 | #endif
|
1610 | #endif
|
1611 | 1611 | ||
1612 | #ifdef YAX_ENABLE
|
1612 | #ifdef YAX_ENABLE
|
1613 | void sv_postyaxload(void) |
1613 | void sv_postyaxload(void) |
1614 | {
|
1614 | {
|
1615 | yax_update(numyaxbunches>0 ? 2 : 1); |
1615 | yax_update(numyaxbunches>0 ? 2 : 1); |
1616 | }
|
1616 | }
|
1617 | #endif
|
1617 | #endif
|
1618 | 1618 | ||
1619 | #if !defined LUNATIC
|
1619 | #if !defined LUNATIC
|
1620 | static void sv_calcbitptrsize() |
1620 | static void sv_calcbitptrsize() |
1621 | {
|
1621 | {
|
1622 | savegame_bitptrsize = (g_scriptSize+7)>>3; |
1622 | savegame_bitptrsize = (g_scriptSize+7)>>3; |
1623 | }
|
1623 | }
|
1624 | static void sv_prescriptsave_once() |
1624 | static void sv_prescriptsave_once() |
1625 | {
|
1625 | {
|
1626 | int32_t i; |
1626 | int32_t i; |
1627 | for (i=0; i<g_scriptSize; i++) |
1627 | for (i=0; i<g_scriptSize; i++) |
1628 | if (bitptr[i>>3]&(BITPTR_POINTER<<(i&7))) |
1628 | if (bitptr[i>>3]&(BITPTR_POINTER<<(i&7))) |
1629 | script[i] = (intptr_t *)script[i] - script; |
1629 | script[i] = (intptr_t *)script[i] - script; |
1630 | 1630 | ||
1631 | G_Util_PtrToIdx2(&g_tile[0].execPtr, MAXTILES, sizeof(tiledata_t), script, P2I_FWD_NON0); |
1631 | G_Util_PtrToIdx2(&g_tile[0].execPtr, MAXTILES, sizeof(tiledata_t), script, P2I_FWD_NON0); |
1632 | G_Util_PtrToIdx2(&g_tile[0].loadPtr, MAXTILES, sizeof(tiledata_t), script, P2I_FWD_NON0); |
1632 | G_Util_PtrToIdx2(&g_tile[0].loadPtr, MAXTILES, sizeof(tiledata_t), script, P2I_FWD_NON0); |
1633 | }
|
1633 | }
|
1634 | static void sv_prescriptload_once() |
1634 | static void sv_prescriptload_once() |
1635 | {
|
1635 | {
|
1636 | if (script) |
1636 | if (script) |
1637 | Bfree(script); |
1637 | Bfree(script); |
1638 | script = (intptr_t *)Xmalloc(g_scriptSize * sizeof(script[0])); |
1638 | script = (intptr_t *)Xmalloc(g_scriptSize * sizeof(script[0])); |
1639 | }
|
1639 | }
|
1640 | static void sv_postscript_once() |
1640 | static void sv_postscript_once() |
1641 | {
|
1641 | {
|
1642 | int32_t i; |
1642 | int32_t i; |
1643 | 1643 | ||
1644 | G_Util_PtrToIdx2(&g_tile[0].execPtr, MAXTILES, sizeof(tiledata_t), script, P2I_BACK_NON0); |
1644 | G_Util_PtrToIdx2(&g_tile[0].execPtr, MAXTILES, sizeof(tiledata_t), script, P2I_BACK_NON0); |
1645 | G_Util_PtrToIdx2(&g_tile[0].loadPtr, MAXTILES, sizeof(tiledata_t), script, P2I_BACK_NON0); |
1645 | G_Util_PtrToIdx2(&g_tile[0].loadPtr, MAXTILES, sizeof(tiledata_t), script, P2I_BACK_NON0); |
1646 | 1646 | ||
1647 | for (i=0; i<g_scriptSize; i++) |
1647 | for (i=0; i<g_scriptSize; i++) |
1648 | if (bitptr[i>>3]&(BITPTR_POINTER<<(i&7))) |
1648 | if (bitptr[i>>3]&(BITPTR_POINTER<<(i&7))) |
1649 | script[i] = (intptr_t)(script + script[i]); |
1649 | script[i] = (intptr_t)(script + script[i]); |
1650 | }
|
1650 | }
|
1651 | #endif
|
1651 | #endif
|
1652 | 1652 | ||
1653 | static void sv_preactordatasave() |
1653 | static void sv_preactordatasave() |
1654 | {
|
1654 | {
|
1655 | int32_t i; |
1655 | int32_t i; |
1656 | 1656 | ||
1657 | for (i=0; i<MAXSPRITES; i++) |
1657 | for (i=0; i<MAXSPRITES; i++) |
1658 | {
|
1658 | {
|
1659 | actor[i].lightptr = NULL; |
1659 | actor[i].lightptr = NULL; |
1660 | actor[i].lightId = -1; |
1660 | actor[i].lightId = -1; |
1661 | }
|
1661 | }
|
1662 | }
|
1662 | }
|
1663 | 1663 | ||
1664 | static void sv_postactordata() |
1664 | static void sv_postactordata() |
1665 | {
|
1665 | {
|
1666 | int32_t i; |
1666 | int32_t i; |
1667 | 1667 | ||
1668 | for (i=0; i<MAXSPRITES; i++) |
1668 | for (i=0; i<MAXSPRITES; i++) |
1669 | {
|
1669 | {
|
1670 | actor[i].lightptr = NULL; |
1670 | actor[i].lightptr = NULL; |
1671 | actor[i].lightId = -1; |
1671 | actor[i].lightId = -1; |
1672 | }
|
1672 | }
|
1673 | }
|
1673 | }
|
1674 | 1674 | ||
1675 | static void sv_preanimateptrsave() |
1675 | static void sv_preanimateptrsave() |
1676 | {
|
1676 | {
|
1677 | G_Util_PtrToIdx(animateptr, g_animateCount, sector, P2I_FWD); |
1677 | G_Util_PtrToIdx(animateptr, g_animateCount, sector, P2I_FWD); |
1678 | }
|
1678 | }
|
1679 | static void sv_postanimateptr() |
1679 | static void sv_postanimateptr() |
1680 | {
|
1680 | {
|
1681 | G_Util_PtrToIdx(animateptr, g_animateCount, sector, P2I_BACK); |
1681 | G_Util_PtrToIdx(animateptr, g_animateCount, sector, P2I_BACK); |
1682 | }
|
1682 | }
|
1683 | static void sv_prequote() |
1683 | static void sv_prequote() |
1684 | {
|
1684 | {
|
1685 | if (!savegame_quotes) |
1685 | if (!savegame_quotes) |
1686 | {
|
1686 | {
|
1687 | void *ptr = Xcalloc(MAXQUOTES, MAXQUOTELEN); |
1687 | void *ptr = Xcalloc(MAXQUOTES, MAXQUOTELEN); |
1688 | savegame_quotes = (char(*)[MAXQUOTELEN])ptr; |
1688 | savegame_quotes = (char(*)[MAXQUOTELEN])ptr; |
1689 | }
|
1689 | }
|
1690 | }
|
1690 | }
|
1691 | static void sv_quotesave() |
1691 | static void sv_quotesave() |
1692 | {
|
1692 | {
|
1693 | int32_t i; |
1693 | int32_t i; |
1694 | Bmemset(savegame_quotedef, 0, sizeof(savegame_quotedef)); |
1694 | Bmemset(savegame_quotedef, 0, sizeof(savegame_quotedef)); |
1695 | for (i=0; i<MAXQUOTES; i++) |
1695 | for (i=0; i<MAXQUOTES; i++) |
1696 | if (ScriptQuotes[i]) |
1696 | if (ScriptQuotes[i]) |
1697 | {
|
1697 | {
|
1698 | savegame_quotedef[i>>3] |= 1<<(i&7); |
1698 | savegame_quotedef[i>>3] |= 1<<(i&7); |
1699 | Bmemcpy(savegame_quotes[i], ScriptQuotes[i], MAXQUOTELEN); |
1699 | Bmemcpy(savegame_quotes[i], ScriptQuotes[i], MAXQUOTELEN); |
1700 | }
|
1700 | }
|
1701 | }
|
1701 | }
|
1702 | static void sv_quoteload() |
1702 | static void sv_quoteload() |
1703 | {
|
1703 | {
|
1704 | int32_t i; |
1704 | int32_t i; |
1705 | for (i=0; i<MAXQUOTES; i++) |
1705 | for (i=0; i<MAXQUOTES; i++) |
1706 | {
|
1706 | {
|
1707 | if (savegame_quotedef[i>>3]&(1<<(i&7))) |
1707 | if (savegame_quotedef[i>>3]&(1<<(i&7))) |
1708 | {
|
1708 | {
|
1709 | C_AllocQuote(i); |
1709 | C_AllocQuote(i); |
1710 | Bmemcpy(ScriptQuotes[i], savegame_quotes[i], MAXQUOTELEN); |
1710 | Bmemcpy(ScriptQuotes[i], savegame_quotes[i], MAXQUOTELEN); |
1711 | }
|
1711 | }
|
1712 | }
|
1712 | }
|
1713 | }
|
1713 | }
|
1714 | static void sv_prequoteredef() |
1714 | static void sv_prequoteredef() |
1715 |