Rev 4990 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5 | Plagman | 1 | //------------------------------------------------------------------------- |
2 | /* |
||
1652 | terminx | 3 | Copyright (C) 2010 EDuke32 developers and contributors |
5 | Plagman | 4 | |
1652 | terminx | 5 | This file is part of EDuke32. |
5 | Plagman | 6 | |
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 |
||
9 | as published by the Free Software Foundation. |
||
10 | |||
11 | This program is distributed in the hope that it will be useful, |
||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
||
14 | |||
15 | See the GNU General Public License for more details. |
||
16 | |||
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 |
||
4541 | hendricks2 | 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
5 | Plagman | 20 | */ |
21 | //------------------------------------------------------------------------- |
||
22 | |||
23 | #include "duke3d.h" |
||
1677 | terminx | 24 | #include "premap.h" |
2207 | helixhorne | 25 | #include "menus.h" // menutext |
1660 | terminx | 26 | #include "prlights.h" |
1950 | helixhorne | 27 | #include "savegame.h" |
3796 | helixhorne | 28 | #ifdef LUNATIC |
29 | # include "lunatic_game.h" |
||
30 | static int32_t g_savedOK; |
||
31 | const char *g_failedVarname; |
||
32 | #endif |
||
5 | Plagman | 33 | |
983 | hnt_ts | 34 | extern char *bitptr; |
35 | |||
4472 | hendricks2 | 36 | uint8_t g_oldverSavegame[MAXSAVEGAMES]; |
3156 | helixhorne | 37 | |
984 | terminx | 38 | #define BITPTR_POINTER 1 |
39 | |||
1950 | helixhorne | 40 | // For storing pointers in files. |
41 | // back_p==0: ptr -> "small int" |
||
42 | // back_p==1: "small int" -> ptr |
||
43 | // |
||
44 | // mode: see enum in savegame.h |
||
5069 | terminx | 45 | void G_Util_PtrToIdx(void *ptr, int32_t const count, const void *base, int32_t const mode) |
1950 | helixhorne | 46 | { |
3177 | helixhorne | 47 | intptr_t *iptr = (intptr_t *)ptr; |
4990 | terminx | 48 | intptr_t const ibase = (intptr_t)base; |
49 | int32_t const onlynon0_p = mode&P2I_ONLYNON0_BIT; |
||
1950 | helixhorne | 50 | |
51 | // TODO: convert to proper offsets/indices for (a step towards) cross- |
||
52 | // compatibility between 32- and 64-bit systems in the netplay. |
||
53 | // REMEMBER to bump BYTEVERSION then. |
||
54 | |||
4990 | terminx | 55 | // WARNING: C std doesn't say that bit pattern of NULL is necessarily 0! |
56 | if ((mode & P2I_BACK_BIT) == 0) |
||
57 | { |
||
58 | for (int i = 0; i < count; i++) |
||
59 | if (!onlynon0_p || iptr[i]) |
||
1950 | helixhorne | 60 | iptr[i] -= ibase; |
4990 | terminx | 61 | } |
62 | else |
||
63 | { |
||
64 | for (int i = 0; i < count; i++) |
||
65 | if (!onlynon0_p || iptr[i]) |
||
1950 | helixhorne | 66 | iptr[i] += ibase; |
4990 | terminx | 67 | } |
1950 | helixhorne | 68 | } |
69 | |||
5069 | terminx | 70 | void G_Util_PtrToIdx2(void *ptr, int32_t const count, size_t const stride, const void *base, int32_t const mode) |
3102 | terminx | 71 | { |
3150 | helixhorne | 72 | uint8_t *iptr = (uint8_t *)ptr; |
4990 | terminx | 73 | intptr_t const ibase = (intptr_t)base; |
74 | int32_t const onlynon0_p = mode&P2I_ONLYNON0_BIT; |
||
3102 | terminx | 75 | |
4990 | terminx | 76 | if ((mode & P2I_BACK_BIT) == 0) |
3102 | terminx | 77 | { |
4990 | terminx | 78 | for (int i = 0; i < count; ++i) |
3102 | terminx | 79 | { |
4990 | terminx | 80 | if (!onlynon0_p || *(intptr_t *)iptr) |
3102 | terminx | 81 | *(intptr_t *)iptr -= ibase; |
4990 | terminx | 82 | |
83 | iptr += stride; |
||
84 | } |
||
85 | } |
||
86 | else |
||
87 | { |
||
88 | for (int i = 0; i < count; ++i) |
||
89 | { |
||
90 | if (!onlynon0_p || *(intptr_t *)iptr) |
||
3102 | terminx | 91 | *(intptr_t *)iptr += ibase; |
4990 | terminx | 92 | |
93 | iptr += stride; |
||
3102 | terminx | 94 | } |
95 | } |
||
96 | } |
||
97 | |||
1949 | helixhorne | 98 | // TODO: sync with TROR special interpolations? (e.g. upper floor of subway) |
99 | void G_ResetInterpolations(void) |
||
100 | { |
||
101 | int32_t k, i; |
||
102 | |||
103 | g_numInterpolations = 0; |
||
104 | startofdynamicinterpolations = 0; |
||
105 | |||
106 | k = headspritestat[STAT_EFFECTOR]; |
||
107 | while (k >= 0) |
||
108 | { |
||
109 | switch (sprite[k].lotag) |
||
110 | { |
||
2970 | helixhorne | 111 | case SE_31_FLOOR_RISE_FALL: |
1949 | helixhorne | 112 | G_SetInterpolation(§or[sprite[k].sectnum].floorz); |
113 | break; |
||
2970 | helixhorne | 114 | case SE_32_CEILING_RISE_FALL: |
1949 | helixhorne | 115 | G_SetInterpolation(§or[sprite[k].sectnum].ceilingz); |
116 | break; |
||
2970 | helixhorne | 117 | case SE_17_WARP_ELEVATOR: |
118 | case SE_25_PISTON: |
||
1949 | helixhorne | 119 | G_SetInterpolation(§or[sprite[k].sectnum].floorz); |
120 | G_SetInterpolation(§or[sprite[k].sectnum].ceilingz); |
||
121 | break; |
||
3008 | helixhorne | 122 | case SE_0_ROTATING_SECTOR: |
123 | case SE_5: |
||
124 | case SE_6_SUBWAY: |
||
125 | case SE_11_SWINGING_DOOR: |
||
126 | case SE_14_SUBWAY_CAR: |
||
127 | case SE_15_SLIDING_DOOR: |
||
2970 | helixhorne | 128 | case SE_16_REACTOR: |
129 | case SE_26: |
||
130 | case SE_30_TWO_WAY_TRAIN: |
||
1949 | helixhorne | 131 | Sect_SetInterpolation(sprite[k].sectnum); |
132 | break; |
||
133 | } |
||
134 | |||
135 | k = nextspritestat[k]; |
||
136 | } |
||
137 | |||
138 | for (i=g_numInterpolations-1; i>=0; i--) bakipos[i] = *curipos[i]; |
||
139 | for (i = g_animateCount-1; i>=0; i--) |
||
140 | G_SetInterpolation(animateptr[i]); |
||
141 | } |
||
142 | |||
1143 | terminx | 143 | void ReadSaveGameHeaders(void) |
398 | terminx | 144 | { |
2207 | helixhorne | 145 | char fn[16]; |
146 | int32_t fil, i; |
||
147 | |||
148 | savehead_t h; |
||
149 | |||
3975 | helixhorne | 150 | EDUKE32_STATIC_ASSERT(sizeof(h.savename) == sizeof(ud.savegame[0])); |
151 | |||
2207 | helixhorne | 152 | Bstrcpy(fn, "dukesav0.esv"); |
153 | |||
4472 | hendricks2 | 154 | for (i=0; i<MAXSAVEGAMES; i++) |
2207 | helixhorne | 155 | { |
156 | int32_t k; |
||
157 | |||
158 | fn[7] = i + '0'; |
||
159 | fil = kopen4loadfrommod(fn, 0); |
||
160 | if (fil == -1) |
||
161 | { |
||
162 | Bmemset(ud.savegame[i], 0, sizeof(ud.savegame[i])); |
||
163 | continue; |
||
164 | } |
||
165 | |||
166 | k = sv_loadheader(fil, i, &h); |
||
167 | if (k) |
||
168 | { |
||
3156 | helixhorne | 169 | // old version, signal to menu code |
2207 | helixhorne | 170 | if (k==2 || k==3) |
3156 | helixhorne | 171 | g_oldverSavegame[i] = 1; |
2207 | helixhorne | 172 | // else h.savename is all zeros (fatal failure, like wrong header |
173 | // magic or too short header) |
||
174 | } |
||
175 | |||
176 | Bmemcpy(ud.savegame[i], h.savename, sizeof(ud.savegame[i])); |
||
177 | |||
178 | kclose(fil); |
||
179 | } |
||
180 | } |
||
181 | |||
182 | int32_t G_LoadSaveHeaderNew(int32_t spot, savehead_t *saveh) |
||
183 | { |
||
184 | char fn[16]; |
||
2210 | helixhorne | 185 | int32_t fil, screenshotofs, i; |
2207 | helixhorne | 186 | |
4472 | hendricks2 | 187 | Bassert(spot < MAXSAVEGAMES); |
188 | |||
2207 | helixhorne | 189 | Bstrcpy(fn, "dukesav0.esv"); |
190 | fn[7] = spot + '0'; |
||
191 | |||
192 | fil = kopen4loadfrommod(fn, 0); |
||
193 | if (fil == -1) |
||
194 | return -1; |
||
195 | |||
2210 | helixhorne | 196 | i = sv_loadheader(fil, spot, saveh); |
197 | if (i && (i != 2 && i != 3)) |
||
2207 | helixhorne | 198 | goto corrupt; |
199 | |||
200 | if (kread(fil, &screenshotofs, 4) != 4) |
||
201 | goto corrupt; |
||
202 | |||
203 | walock[TILE_LOADSHOT] = 255; |
||
204 | if (waloff[TILE_LOADSHOT] == 0) |
||
205 | allocache(&waloff[TILE_LOADSHOT], 320*200, &walock[TILE_LOADSHOT]); |
||
4623 | terminx | 206 | tilesiz[TILE_LOADSHOT].x = 200; |
207 | tilesiz[TILE_LOADSHOT].y = 320; |
||
2207 | helixhorne | 208 | if (screenshotofs) |
209 | { |
||
210 | if (kdfread((char *)waloff[TILE_LOADSHOT], 320, 200, fil) != 200) |
||
2210 | helixhorne | 211 | { |
212 | OSD_Printf("G_LoadSaveHeaderNew(%d): failed reading screenshot\n", spot); |
||
2207 | helixhorne | 213 | goto corrupt; |
2210 | helixhorne | 214 | } |
2207 | helixhorne | 215 | } |
216 | else |
||
217 | { |
||
218 | Bmemset((char *)waloff[TILE_LOADSHOT], 0, 320*200); |
||
219 | } |
||
220 | invalidatetile(TILE_LOADSHOT, 0, 255); |
||
221 | |||
222 | kclose(fil); |
||
223 | return 0; |
||
224 | |||
225 | corrupt: |
||
226 | kclose(fil); |
||
227 | return 1; |
||
228 | } |
||
229 | |||
5 | Plagman | 230 | |
2207 | helixhorne | 231 | static void sv_postudload(); |
232 | |||
3789 | helixhorne | 233 | // XXX: keyboard input 'blocked' after load fail? (at least ESC?) |
1205 | terminx | 234 | int32_t G_LoadPlayer(int32_t spot) |
5 | Plagman | 235 | { |
2207 | helixhorne | 236 | char fn[16]; |
237 | int32_t fil, i; |
||
238 | |||
239 | savehead_t h; |
||
240 | |||
4472 | hendricks2 | 241 | Bassert(spot < MAXSAVEGAMES); |
242 | |||
2207 | helixhorne | 243 | Bstrcpy(fn, "dukesav0.esv"); |
244 | fn[7] = spot + '0'; |
||
245 | |||
246 | fil = kopen4loadfrommod(fn, 0); |
||
247 | if (fil == -1) |
||
248 | return -1; |
||
249 | |||
250 | ready2send = 0; |
||
251 | |||
252 | i = sv_loadheader(fil, spot, &h); |
||
4610 | terminx | 253 | if ((i && i != 2) || h.numplayers != ud.multimode) |
2207 | helixhorne | 254 | { |
255 | if (i == 2 || i == 3) |
||
256 | P_DoQuote(QUOTE_SAVE_BAD_VERSION, g_player[myconnectindex].ps); |
||
257 | else if (h.numplayers!=ud.multimode) |
||
258 | P_DoQuote(QUOTE_SAVE_BAD_PLAYERS, g_player[myconnectindex].ps); |
||
259 | |||
260 | kclose(fil); |
||
261 | ototalclock = totalclock; |
||
262 | ready2send = 1; |
||
263 | |||
264 | return 1; |
||
265 | } |
||
266 | |||
267 | // some setup first |
||
268 | ud.multimode = h.numplayers; |
||
269 | |||
270 | if (numplayers > 1) |
||
271 | { |
||
272 | pub = NUMPAGES; |
||
273 | pus = NUMPAGES; |
||
274 | G_UpdateScreenArea(); |
||
275 | G_DrawBackground(); |
||
276 | menutext(160,100, 0,0, "LOADING..."); |
||
277 | nextpage(); |
||
278 | } |
||
279 | |||
280 | Net_WaitForServer(); |
||
281 | |||
282 | FX_StopAllSounds(); |
||
283 | S_ClearSoundLocks(); |
||
284 | |||
285 | if (spot >= 0 && numplayers==1) |
||
286 | { |
||
287 | Bmemcpy(ud.savegame[spot], h.savename, sizeof(ud.savegame[0])); |
||
288 | ud.savegame[spot][sizeof(ud.savegame[0])-1] = 0; |
||
289 | } |
||
290 | |||
291 | // non-"m_" fields will be loaded from svgm_udnetw |
||
292 | ud.m_volume_number = h.volnum; |
||
293 | ud.m_level_number = h.levnum; |
||
294 | ud.m_player_skill = h.skill; |
||
295 | |||
4589 | helixhorne | 296 | { |
297 | // NOTE: Bmemcpy needed for SAVEGAME_MUSIC. |
||
298 | EDUKE32_STATIC_ASSERT(sizeof(boardfilename) == sizeof(h.boardfn)); |
||
299 | Bmemcpy(boardfilename, h.boardfn, sizeof(boardfilename)); |
||
300 | } |
||
301 | |||
4257 | helixhorne | 302 | E_MapArt_Setup(h.boardfn); // XXX: Better after the following filename tweaking? |
2207 | helixhorne | 303 | |
304 | if (boardfilename[0]) |
||
305 | Bstrcpy(currentboardfilename, boardfilename); |
||
306 | else if (MapInfo[h.volnum*MAXLEVELS + h.levnum].filename) |
||
307 | Bstrcpy(currentboardfilename, MapInfo[h.volnum*MAXLEVELS + h.levnum].filename); |
||
308 | |||
309 | if (currentboardfilename[0]) |
||
310 | { |
||
3735 | helixhorne | 311 | append_ext_UNSAFE(currentboardfilename, ".mhk"); |
2207 | helixhorne | 312 | loadmaphack(currentboardfilename); |
313 | } |
||
314 | |||
315 | Bmemcpy(currentboardfilename, boardfilename, BMAX_PATH); |
||
316 | |||
4596 | terminx | 317 | if (i == 2) |
2207 | helixhorne | 318 | { |
4596 | terminx | 319 | G_NewGame_EnterLevel(); |
2207 | helixhorne | 320 | } |
4596 | terminx | 321 | else |
322 | { |
||
323 | // read the rest... |
||
324 | i = sv_loadsnapshot(fil, spot, &h); |
||
325 | if (i) |
||
326 | { |
||
327 | // in theory, we could load into an initial dump first and trivially |
||
328 | // recover if things go wrong... |
||
329 | Bsprintf(tempbuf, "Loading save game file \"%s\" failed (code %d), cannot recover.", fn, i); |
||
330 | G_GameExit(tempbuf); |
||
331 | } |
||
332 | } |
||
2207 | helixhorne | 333 | sv_postudload(); // ud.m_XXX = ud.XXX |
334 | |||
4745 | terminx | 335 | VM_OnEvent(EVENT_LOADGAME, g_player[myconnectindex].ps->i, myconnectindex); |
2688 | hendricks2 | 336 | |
2207 | helixhorne | 337 | return 0; |
338 | } |
||
339 | |||
4450 | helixhorne | 340 | ////////// TIMER SAVING/RESTORING ////////// |
5 | Plagman | 341 | |
4450 | helixhorne | 342 | static struct { |
343 | int32_t totalclock, totalclocklock; // engine |
||
344 | int32_t ototalclock, lockclock; // game |
||
345 | } g_timers; |
||
346 | |||
347 | static void G_SaveTimers(void) |
||
348 | { |
||
349 | g_timers.totalclock = totalclock; |
||
350 | g_timers.totalclocklock = totalclocklock; |
||
351 | g_timers.ototalclock = ototalclock; |
||
352 | g_timers.lockclock = lockclock; |
||
353 | } |
||
354 | |||
355 | static void G_RestoreTimers(void) |
||
356 | { |
||
357 | sampletimer(); |
||
358 | |||
359 | totalclock = g_timers.totalclock; |
||
360 | totalclocklock = g_timers.totalclocklock; |
||
361 | ototalclock = g_timers.ototalclock; |
||
362 | lockclock = g_timers.lockclock; |
||
363 | } |
||
364 | |||
365 | ////////// |
||
366 | |||
4990 | terminx | 367 | #ifdef __ANDROID__ |
368 | static void G_SavePalette(void) |
||
369 | { |
||
370 | int32_t pfil; |
||
371 | |||
372 | if ((pfil = kopen4load("palette.dat", 0)) != -1) |
||
373 | { |
||
374 | int len = kfilelength(pfil); |
||
375 | |||
376 | FILE *fil = fopen("palette.dat", "rb"); |
||
377 | |||
378 | if (!fil) |
||
379 | { |
||
380 | fil = fopen("palette.dat", "wb"); |
||
381 | |||
382 | if (fil) |
||
383 | { |
||
384 | char *buf = (char *) Xaligned_alloc(16, len); |
||
385 | |||
386 | kread(pfil, buf, len); |
||
387 | fwrite(buf, len, 1, fil); |
||
388 | fclose(fil); |
||
389 | } |
||
390 | } |
||
391 | else fclose(fil); |
||
392 | } |
||
393 | } |
||
394 | #endif |
||
395 | |||
1205 | terminx | 396 | int32_t G_SavePlayer(int32_t spot) |
5 | Plagman | 397 | { |
2207 | helixhorne | 398 | char fn[16]; |
399 | FILE *fil; |
||
400 | |||
4990 | terminx | 401 | #ifdef __ANDROID__ |
402 | G_SavePalette(); |
||
403 | #endif |
||
404 | |||
4472 | hendricks2 | 405 | Bassert(spot < MAXSAVEGAMES); |
406 | |||
4450 | helixhorne | 407 | G_SaveTimers(); |
408 | |||
2207 | helixhorne | 409 | Bstrcpy(fn, "dukesav0.esv"); |
410 | fn[7] = spot + '0'; |
||
411 | |||
412 | // Bstrcpy(mpfn, "edukA_00.esv"); |
||
413 | |||
414 | Net_WaitForServer(); |
||
415 | ready2send = 0; |
||
416 | |||
417 | { |
||
418 | char temp[BMAX_PATH]; |
||
419 | |||
2997 | helixhorne | 420 | if (G_ModDirSnprintf(temp, sizeof(temp), "%s", fn)) |
421 | { |
||
422 | OSD_Printf("G_SavePlayer: file name \"%s\" too long\n", fn); |
||
423 | return -1; |
||
424 | } |
||
2207 | helixhorne | 425 | |
2393 | helixhorne | 426 | errno = 0; |
2207 | helixhorne | 427 | fil = fopen(temp, "wb"); |
428 | if (!fil) |
||
2393 | helixhorne | 429 | { |
2538 | hendricks2 | 430 | OSD_Printf("G_SavePlayer: failed opening \"%s\" for writing: %s\n", |
2393 | helixhorne | 431 | temp, strerror(errno)); |
2998 | helixhorne | 432 | return -1; |
2393 | helixhorne | 433 | } |
2207 | helixhorne | 434 | } |
435 | |||
2236 | helixhorne | 436 | #ifdef POLYMER |
3784 | terminx | 437 | if (getrendermode() == REND_POLYMER) |
2236 | helixhorne | 438 | polymer_resetlights(); |
439 | #endif |
||
440 | |||
4745 | terminx | 441 | VM_OnEvent(EVENT_SAVEGAME, g_player[myconnectindex].ps->i, myconnectindex); |
2688 | hendricks2 | 442 | |
2207 | helixhorne | 443 | // SAVE! |
2218 | helixhorne | 444 | sv_saveandmakesnapshot(fil, spot, 0, 0, 0); |
2207 | helixhorne | 445 | |
446 | fclose(fil); |
||
447 | |||
448 | if (!g_netServer && ud.multimode < 2) |
||
449 | { |
||
3796 | helixhorne | 450 | #ifdef LUNATIC |
451 | if (!g_savedOK) |
||
452 | Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "^10Failed Saving Game"); |
||
453 | else |
||
454 | #endif |
||
455 | Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "Game Saved"); |
||
2207 | helixhorne | 456 | P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); |
457 | } |
||
458 | |||
459 | ready2send = 1; |
||
460 | Net_WaitForServer(); |
||
461 | |||
4450 | helixhorne | 462 | G_RestoreTimers(); |
2207 | helixhorne | 463 | ototalclock = totalclock; |
464 | |||
465 | return 0; |
||
466 | } |
||
467 | |||
2999 | helixhorne | 468 | void G_LoadPlayerMaybeMulti(int32_t slot) |
469 | { |
||
470 | if (g_netServer || ud.multimode > 1) |
||
471 | { |
||
472 | Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "Multiplayer Loading Not Yet Supported"); |
||
473 | P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); |
||
5 | Plagman | 474 | |
2999 | helixhorne | 475 | // G_LoadPlayer(-1-g_lastSaveSlot); |
476 | // g_player[myconnectindex].ps->gm = MODE_GAME; |
||
477 | } |
||
478 | else |
||
479 | { |
||
480 | int32_t c = G_LoadPlayer(slot); |
||
481 | if (c == 0) |
||
482 | g_player[myconnectindex].ps->gm = MODE_GAME; |
||
483 | } |
||
484 | } |
||
485 | |||
486 | void G_SavePlayerMaybeMulti(int32_t slot) |
||
487 | { |
||
488 | Bassert(slot >= 0); |
||
489 | |||
3636 | terminx | 490 | CONFIG_WriteSetup(2); |
3579 | hendricks2 | 491 | |
2999 | helixhorne | 492 | if (g_netServer || ud.multimode > 1) |
493 | { |
||
494 | Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "Multiplayer Saving Not Yet Supported"); |
||
495 | P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); |
||
496 | // G_SavePlayer(-1-slot); |
||
497 | } |
||
498 | else |
||
499 | { |
||
500 | G_SavePlayer(slot); |
||
501 | } |
||
502 | } |
||
503 | |||
1595 | helixhorne | 504 | ////////// GENERIC SAVING/LOADING SYSTEM ////////// |
505 | |||
506 | typedef struct dataspec_ |
||
507 | { |
||
508 | uint32_t flags; |
||
509 | void *ptr; |
||
510 | uint32_t size; |
||
511 | intptr_t cnt; |
||
512 | } dataspec_t; |
||
513 | |||
514 | #define SV_DEFAULTCOMPRTHRES 8 |
||
515 | static uint8_t savegame_diffcompress; // 0:none, 1:Ken's LZW in cache1d.c |
||
516 | static uint8_t savegame_comprthres; |
||
517 | |||
518 | |||
519 | #define DS_DYNAMIC 1 // dereference .ptr one more time |
||
520 | #define DS_STRING 2 |
||
521 | #define DS_CMP 4 |
||
522 | // 8 |
||
523 | #define DS_CNT(x) ((sizeof(x))<<3) // .cnt is pointer to... |
||
524 | #define DS_CNT16 16 |
||
525 | #define DS_CNT32 32 |
||
526 | #define DS_CNTMASK (8|DS_CNT16|DS_CNT32|64) |
||
527 | // 64 |
||
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 |
||
1799 | helixhorne | 530 | #define DS_NOCHK 1024 // don't check for diffs (and don't write out in dump) since assumed constant throughout demo |
1882 | helixhorne | 531 | #define DS_PROTECTFN 512 |
1595 | helixhorne | 532 | #define DS_END (0x70000000) |
533 | |||
534 | static int32_t ds_getcnt(const dataspec_t *sp) |
||
535 | { |
||
4990 | terminx | 536 | int rv = -1; |
537 | |||
538 | switch (sp->flags & DS_CNTMASK) |
||
1595 | helixhorne | 539 | { |
4990 | terminx | 540 | case 0: rv = sp->cnt; break; |
541 | case DS_CNT16: rv = *((int16_t *)sp->cnt); break; |
||
542 | case DS_CNT32: rv = *((int32_t *)sp->cnt); break; |
||
1595 | helixhorne | 543 | } |
4990 | terminx | 544 | |
545 | return rv; |
||
1595 | helixhorne | 546 | } |
547 | |||
4990 | terminx | 548 | static inline void ds_get(const dataspec_t *sp, void **ptr, int32_t *cnt) |
1595 | helixhorne | 549 | { |
550 | *cnt = ds_getcnt(sp); |
||
4990 | terminx | 551 | *ptr = (sp->flags&DS_DYNAMIC) ? *((void **)sp->ptr) : sp->ptr; |
1595 | helixhorne | 552 | } |
553 | |||
554 | // write state to file and/or to dump |
||
555 | static uint8_t *writespecdata(const dataspec_t *spec, FILE *fil, uint8_t *dump) |
||
556 | { |
||
557 | int32_t cnt; |
||
2234 | helixhorne | 558 | void *ptr; |
1595 | helixhorne | 559 | const dataspec_t *sp=spec; |
560 | |||
561 | for (; sp->flags!=DS_END; sp++) |
||
562 | { |
||
563 | if (sp->flags&(DS_SAVEFN|DS_LOADFN)) |
||
564 | { |
||
565 | if (sp->flags&DS_SAVEFN) |
||
2207 | helixhorne | 566 | (*(void (*)(void))sp->ptr)(); |
1595 | helixhorne | 567 | continue; |
568 | } |
||
569 | |||
570 | if (!fil && (sp->flags&(DS_NOCHK|DS_CMP|DS_STRING))) |
||
571 | continue; |
||
572 | |||
573 | if (sp->flags&DS_STRING) |
||
574 | { |
||
3177 | helixhorne | 575 | fwrite(sp->ptr, Bstrlen((const char *)sp->ptr), 1, fil); // not null-terminated! |
1595 | helixhorne | 576 | continue; |
577 | } |
||
578 | |||
579 | ds_get(sp, &ptr, &cnt); |
||
580 | if (cnt < 0) { OSD_Printf("wsd: cnt=%d, f=0x%x.\n",cnt,sp->flags); continue; } |
||
581 | |||
582 | if (fil) |
||
583 | { |
||
2158 | helixhorne | 584 | if (((sp->flags&DS_CNTMASK)==0 && sp->size*cnt<=savegame_comprthres) |
1599 | terminx | 585 | || (sp->flags&DS_CMP)) |
1595 | helixhorne | 586 | fwrite(ptr, sp->size, cnt, fil); |
587 | else |
||
588 | dfwrite((void *)ptr, sp->size, cnt, fil); |
||
589 | } |
||
590 | |||
591 | if (dump && (sp->flags&(DS_NOCHK|DS_CMP))==0) |
||
592 | { |
||
593 | Bmemcpy(dump, ptr, sp->size*cnt); |
||
594 | dump += sp->size*cnt; |
||
595 | } |
||
596 | } |
||
597 | return dump; |
||
598 | } |
||
599 | |||
600 | // let havedump=dumpvar&&*dumpvar |
||
601 | // (fil>=0 && havedump): first restore dump from file, then restore state from dump |
||
602 | // (fil<0 && havedump): only restore state from dump |
||
603 | // (fil>=0 && !havedump): only restore state from file |
||
604 | static int32_t readspecdata(const dataspec_t *spec, int32_t fil, uint8_t **dumpvar) |
||
605 | { |
||
606 | int32_t cnt, i, j; |
||
607 | void *ptr; |
||
608 | uint8_t *dump=dumpvar?*dumpvar:NULL, *mem; |
||
609 | const dataspec_t *sp=spec; |
||
610 | static char cmpstrbuf[32]; |
||
611 | |||
612 | for (; sp->flags!=DS_END; sp++) |
||
613 | { |
||
614 | if (fil < 0 && sp->flags&(DS_NOCHK|DS_STRING|DS_CMP)) // we're updating |
||
615 | continue; |
||
616 | |||
617 | if (sp->flags&(DS_LOADFN|DS_SAVEFN)) |
||
618 | { |
||
619 | if (sp->flags&DS_LOADFN) |
||
2566 | helixhorne | 620 | (*(void (*)())sp->ptr)(); |
1595 | helixhorne | 621 | continue; |
622 | } |
||
623 | |||
624 | if (sp->flags&(DS_STRING|DS_CMP)) // DS_STRING and DS_CMP is for static data only |
||
625 | { |
||
626 | if (sp->flags&(DS_STRING)) |
||
3177 | helixhorne | 627 | i = Bstrlen((const char *)sp->ptr); |
1595 | helixhorne | 628 | else |
629 | i = sp->size*sp->cnt; |
||
630 | |||
631 | j=kread(fil, cmpstrbuf, i); |
||
632 | if (j!=i || Bmemcmp(sp->ptr, cmpstrbuf, i)) |
||
633 | { |
||
2212 | helixhorne | 634 | OSD_Printf("rsd: spec=%s, idx=%d:\n", (char *)spec->ptr, (int32_t)(sp-spec)); |
1595 | helixhorne | 635 | if (j!=i) |
2207 | helixhorne | 636 | OSD_Printf(" kread returned %d, expected %d.\n", j, i); |
1595 | helixhorne | 637 | else |
2207 | helixhorne | 638 | OSD_Printf(" sp->ptr and cmpstrbuf not identical!\n"); |
1595 | helixhorne | 639 | return -1; |
640 | } |
||
641 | continue; |
||
642 | } |
||
643 | |||
2234 | helixhorne | 644 | ds_get(sp, &ptr, &cnt); |
1595 | helixhorne | 645 | if (cnt < 0) { OSD_Printf("rsd: cnt<0... wtf?\n"); return -1; } |
646 | |||
647 | if (fil>=0) |
||
648 | { |
||
3177 | helixhorne | 649 | mem = (dump && (sp->flags&DS_NOCHK)==0) ? dump : (uint8_t *)ptr; |
1595 | helixhorne | 650 | |
2158 | helixhorne | 651 | if ((sp->flags&DS_CNTMASK)==0 && sp->size*cnt<=savegame_comprthres) |
1595 | helixhorne | 652 | { |
653 | i = kread(fil, mem, cnt*sp->size); |
||
654 | j = cnt*sp->size; |
||
655 | } |
||
656 | else |
||
657 | { |
||
658 | i = kdfread(mem, sp->size, cnt, fil); |
||
659 | j = cnt; |
||
660 | } |
||
661 | if (i!=j) |
||
662 | { |
||
2212 | helixhorne | 663 | OSD_Printf("rsd: spec=%s, idx=%d, mem=%p\n", (char *)spec->ptr, (int32_t)(sp-spec), mem); |
2207 | helixhorne | 664 | OSD_Printf(" (%s): read %d, expected %d!\n", |
2158 | helixhorne | 665 | ((sp->flags&DS_CNTMASK)==0 && sp->size*cnt<=savegame_comprthres)? |
2207 | helixhorne | 666 | "uncompressed":"compressed", i, j); |
1599 | terminx | 667 | |
1595 | helixhorne | 668 | if (i==-1) |
2190 | helixhorne | 669 | OSD_Printf(" read: %s\n", strerror(errno)); |
1595 | helixhorne | 670 | return -1; |
671 | } |
||
672 | } |
||
673 | |||
674 | if (dump && (sp->flags&DS_NOCHK)==0) |
||
675 | { |
||
676 | Bmemcpy(ptr, dump, sp->size*cnt); |
||
677 | dump += sp->size*cnt; |
||
678 | } |
||
679 | } |
||
680 | |||
681 | if (dumpvar) |
||
682 | *dumpvar = dump; |
||
683 | return 0; |
||
684 | } |
||
685 | |||
686 | #define UINT(bits) uint##bits##_t |
||
687 | #define BYTES(bits) (bits>>3) |
||
688 | #define VAL(bits,p) (*(UINT(bits) *)(p)) |
||
689 | |||
690 | static void docmpsd(const void *ptr, void *dump, uint32_t size, uint32_t cnt, uint8_t **diffvar) |
||
691 | { |
||
692 | uint8_t *retdiff = *diffvar; |
||
693 | |||
694 | // Hail to the C preprocessor, baby! |
||
1599 | terminx | 695 | #define CPSINGLEVAL(Datbits) \ |
1595 | helixhorne | 696 | if (VAL(Datbits, ptr) != VAL(Datbits, dump)) \ |
697 | { \ |
||
698 | VAL(Datbits, retdiff) = VAL(Datbits, dump) = VAL(Datbits, ptr); \ |
||
699 | *diffvar = retdiff+BYTES(Datbits); \ |
||
700 | } |
||
701 | |||
702 | if (cnt==1) |
||
703 | switch (size) |
||
704 | { |
||
705 | case 8: CPSINGLEVAL(64); return; |
||
706 | case 4: CPSINGLEVAL(32); return; |
||
707 | case 2: CPSINGLEVAL(16); return; |
||
708 | case 1: CPSINGLEVAL(8); return; |
||
709 | } |
||
710 | |||
1599 | terminx | 711 | #define CPELTS(Idxbits, Datbits) do \ |
1595 | helixhorne | 712 | { \ |
713 | for (i=0; i<nelts; i++) \ |
||
714 | { \ |
||
715 | if (*p!=*op) \ |
||
716 | { \ |
||
3180 | helixhorne | 717 | *op = *p; \ |
1595 | helixhorne | 718 | VAL(Idxbits, retdiff) = i; \ |
719 | retdiff += BYTES(Idxbits); \ |
||
720 | VAL(Datbits, retdiff) = *p; \ |
||
721 | retdiff += BYTES(Datbits); \ |
||
722 | } \ |
||
723 | p++; \ |
||
724 | op++; \ |
||
725 | } \ |
||
726 | VAL(Idxbits, retdiff) = -1; \ |
||
727 | retdiff += BYTES(Idxbits); \ |
||
728 | } while (0) |
||
729 | |||
1599 | terminx | 730 | #define CPDATA(Datbits) do \ |
1595 | helixhorne | 731 | { \ |
3177 | helixhorne | 732 | const UINT(Datbits) *p=(UINT(Datbits) *)ptr; \ |
733 | UINT(Datbits) *op=(UINT(Datbits) *)dump; \ |
||
4658 | terminx | 734 | uint32_t i, nelts=tabledivide32_noinline(size*cnt, BYTES(Datbits)); \ |
3177 | helixhorne | 735 | if (nelts>65536) \ |
736 | CPELTS(32,Datbits); \ |
||
737 | else if (nelts>256) \ |
||
738 | CPELTS(16,Datbits); \ |
||
739 | else \ |
||
740 | CPELTS(8,Datbits); \ |
||
1595 | helixhorne | 741 | } while (0) |
742 | |||
743 | if (size==8) |
||
744 | CPDATA(64); |
||
745 | else if ((size&3)==0) |
||
746 | CPDATA(32); |
||
747 | else if ((size&1)==0) |
||
748 | CPDATA(16); |
||
749 | else |
||
750 | CPDATA(8); |
||
751 | |||
752 | *diffvar = retdiff; |
||
753 | return; |
||
754 | |||
1599 | terminx | 755 | #undef CPELTS |
756 | #undef CPSINGLEVAL |
||
757 | #undef CPDATA |
||
1595 | helixhorne | 758 | } |
759 | |||
760 | // get the number of elements to be monitored for changes |
||
761 | static int32_t getnumvar(const dataspec_t *spec) |
||
762 | { |
||
763 | int32_t n=0; |
||
1599 | terminx | 764 | for (; spec->flags!=DS_END; spec++) |
1595 | helixhorne | 765 | n += (spec->flags&(DS_STRING|DS_CMP|DS_NOCHK|DS_SAVEFN|DS_LOADFN) ? 0 : 1); |
766 | return n; |
||
767 | } |
||
768 | |||
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) |
||
771 | { |
||
2234 | helixhorne | 772 | void *ptr; |
1595 | helixhorne | 773 | uint8_t *dump=*dumpvar, *diff=*diffvar, *tmptr; |
774 | const dataspec_t *sp=spec; |
||
3177 | helixhorne | 775 | int32_t cnt, eltnum=0, nbytes=(getnumvar(spec)+7)>>3, l=Bstrlen((const char *)spec->ptr); |
1595 | helixhorne | 776 | |
777 | Bmemcpy(diff, spec->ptr, l); |
||
778 | diff+=l; |
||
779 | |||
780 | while (nbytes--) |
||
781 | *(diff++) = 0; // the bitmap of indices which elements of spec have changed go here |
||
782 | |||
783 | for (sp++; sp->flags!=DS_END; sp++) |
||
784 | { |
||
785 | if ((sp->flags&(DS_NOCHK|DS_STRING|DS_CMP))) |
||
786 | continue; |
||
787 | |||
1927 | helixhorne | 788 | if (sp->flags&(DS_LOADFN|DS_SAVEFN)) |
1595 | helixhorne | 789 | { |
1927 | helixhorne | 790 | if ((sp->flags&(DS_PROTECTFN))==0) |
2207 | helixhorne | 791 | (*(void (*)())sp->ptr)(); |
1595 | helixhorne | 792 | continue; |
793 | } |
||
794 | |||
795 | ds_get(sp, &ptr, &cnt); |
||
796 | if (cnt < 0) { OSD_Printf("csd: cnt=%d, f=0x%x\n", cnt, sp->flags); continue; } |
||
797 | |||
798 | tmptr = diff; |
||
799 | docmpsd(ptr, dump, sp->size, cnt, &diff); |
||
800 | if (diff != tmptr) |
||
801 | (*diffvar + l)[eltnum>>3] |= 1<<(eltnum&7); |
||
802 | dump += sp->size*cnt; |
||
803 | eltnum++; |
||
804 | } |
||
805 | |||
806 | *diffvar = diff; |
||
807 | *dumpvar = dump; |
||
808 | return; |
||
809 | } |
||
810 | |||
811 | #define VALOFS(bits,p,ofs) (*(((UINT(bits) *)(p)) + (ofs))) |
||
812 | |||
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) |
||
815 | { |
||
816 | uint8_t *dumptr=*dumpvar, *diffptr=*diffvar; |
||
817 | const dataspec_t *sp=spec; |
||
3177 | helixhorne | 818 | int32_t cnt, eltnum=-1, nbytes=(getnumvar(spec)+7)>>3, l=Bstrlen((const char *)spec->ptr); |
1595 | helixhorne | 819 | |
820 | if (Bmemcmp(diffptr, spec->ptr, l)) // check STRING magic (sync check) |
||
821 | return 1; |
||
2185 | helixhorne | 822 | |
1595 | helixhorne | 823 | diffptr += l+nbytes; |
824 | |||
825 | for (sp++; sp->flags!=DS_END; sp++) |
||
826 | { |
||
827 | if ((sp->flags&(DS_NOCHK|DS_STRING|DS_CMP|DS_LOADFN|DS_SAVEFN))) |
||
828 | continue; |
||
829 | |||
830 | cnt = ds_getcnt(sp); |
||
831 | if (cnt < 0) return 1; |
||
832 | |||
833 | eltnum++; |
||
834 | if (((*diffvar + l)[eltnum>>3]&(1<<(eltnum&7))) == 0) |
||
835 | { |
||
836 | dumptr += sp->size*cnt; |
||
837 | continue; |
||
838 | } |
||
839 | |||
840 | // ---------- |
||
1599 | terminx | 841 | #define CPSINGLEVAL(Datbits) \ |
1595 | helixhorne | 842 | VAL(Datbits, dumptr) = VAL(Datbits, diffptr); \ |
843 | diffptr += BYTES(Datbits); \ |
||
844 | dumptr += BYTES(Datbits) |
||
845 | |||
846 | if (cnt==1) |
||
847 | { |
||
848 | switch (sp->size) |
||
849 | { |
||
850 | case 8: CPSINGLEVAL(64); continue; |
||
851 | case 4: CPSINGLEVAL(32); continue; |
||
852 | case 2: CPSINGLEVAL(16); continue; |
||
853 | case 1: CPSINGLEVAL(8); continue; |
||
854 | } |
||
855 | } |
||
856 | |||
1599 | terminx | 857 | #define CPELTS(Idxbits, Datbits) do \ |
1595 | helixhorne | 858 | { \ |
859 | UINT(Idxbits) idx; \ |
||
860 | goto readidx_##Idxbits##_##Datbits; \ |
||
861 | do \ |
||
862 | { \ |
||
863 | VALOFS(Datbits, dumptr, idx) = VAL(Datbits, diffptr); \ |
||
864 | diffptr += BYTES(Datbits); \ |
||
865 | readidx_##Idxbits##_##Datbits: \ |
||
866 | idx = VAL(Idxbits, diffptr); \ |
||
867 | diffptr += BYTES(Idxbits); \ |
||
868 | } while ((int##Idxbits##_t)idx != -1); \ |
||
869 | } while (0) |
||
870 | |||
1599 | terminx | 871 | #define CPDATA(Datbits) do \ |
1595 | helixhorne | 872 | { \ |
4658 | terminx | 873 | uint32_t nelts=tabledivide32_noinline(sp->size*cnt, BYTES(Datbits)); \ |
1595 | helixhorne | 874 | if (nelts>65536) \ |
875 | CPELTS(32,Datbits); \ |
||
876 | else if (nelts>256) \ |
||
877 | CPELTS(16,Datbits); \ |
||
878 | else \ |
||
879 | CPELTS(8,Datbits); \ |
||
880 | } while (0) |
||
881 | |||
882 | if (sp->size==8) |
||
883 | CPDATA(64); |
||
884 | else if ((sp->size&3)==0) |
||
885 | CPDATA(32); |
||
886 | else if ((sp->size&1)==0) |
||
887 | CPDATA(16); |
||
888 | else |
||
889 | CPDATA(8); |
||
890 | dumptr += sp->size*cnt; |
||
891 | // ---------- |
||
892 | |||
1599 | terminx | 893 | #undef CPELTS |
894 | #undef CPSINGLEVAL |
||
895 | #undef CPDATA |
||
1595 | helixhorne | 896 | } |
897 | |||
898 | *diffvar = diffptr; |
||
899 | *dumpvar = dumptr; |
||
900 | return 0; |
||
901 | } |
||
902 | |||
903 | #undef VAL |
||
904 | #undef VALOFS |
||
905 | #undef BYTES |
||
906 | #undef UINT |
||
907 | |||
908 | // calculate size needed for dump |
||
909 | static uint32_t calcsz(const dataspec_t *spec) |
||
910 | { |
||
911 | const dataspec_t *sp=spec; |
||
912 | int32_t cnt; |
||
913 | uint32_t dasiz=0; |
||
914 | |||
915 | for (; sp->flags!=DS_END; sp++) |
||
916 | { |
||
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))) |
||
919 | continue; |
||
920 | |||
921 | cnt = ds_getcnt(sp); |
||
922 | if (cnt<=0) continue; |
||
923 | |||
924 | dasiz += cnt*sp->size; |
||
925 | } |
||
926 | |||
927 | return dasiz; |
||
928 | } |
||
929 | |||
1820 | terminx | 930 | #ifdef USE_OPENGL |
1596 | plagman | 931 | static void sv_prespriteextsave(); |
932 | static void sv_postspriteext(); |
||
1810 | plagman | 933 | #endif |
3456 | helixhorne | 934 | #if !defined LUNATIC |
1596 | plagman | 935 | static void sv_calcbitptrsize(); |
936 | static void sv_prescriptsave_once(); |
||
1598 | helixhorne | 937 | static void sv_prescriptload_once(); |
1596 | plagman | 938 | static void sv_postscript_once(); |
3857 | helixhorne | 939 | #else |
940 | // Recreate Lua state. |
||
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. |
||
943 | static void sv_create_lua_state(void) |
||
944 | { |
||
945 | El_CreateGameState(); |
||
946 | G_PostCreateGameState(); |
||
947 | } |
||
3456 | helixhorne | 948 | #endif |
1596 | plagman | 949 | static void sv_preactordatasave(); |
950 | static void sv_postactordata(); |
||
951 | static void sv_preanimateptrsave(); |
||
952 | static void sv_postanimateptr(); |
||
953 | static void sv_prequote(); |
||
954 | static void sv_quotesave(); |
||
955 | static void sv_quoteload(); |
||
956 | static void sv_prequoteredef(); |
||
957 | static void sv_quoteredefsave(); |
||
958 | static void sv_quoteredefload(); |
||
959 | static void sv_postquoteredef(); |
||
960 | static void sv_restsave(); |
||
961 | static void sv_restload(); |
||
962 | |||
963 | #define SVARDATALEN \ |
||
964 | ((sizeof(g_player[0].user_name)+sizeof(g_player[0].pcolor)+sizeof(g_player[0].pteam) \ |
||
3257 | helixhorne | 965 | +sizeof(g_player[0].frags)+sizeof(DukePlayer_t))*MAXPLAYERS) |
1596 | plagman | 966 | |
3857 | helixhorne | 967 | #if !defined LUNATIC |
1596 | plagman | 968 | static uint32_t savegame_bitptrsize; |
3857 | helixhorne | 969 | #endif |
1596 | plagman | 970 | static uint8_t savegame_quotedef[MAXQUOTES>>3]; |
1599 | terminx | 971 | static char(*savegame_quotes)[MAXQUOTELEN]; |
972 | static char(*savegame_quoteredefs)[MAXQUOTELEN]; |
||
1596 | plagman | 973 | static uint8_t savegame_restdata[SVARDATALEN]; |
974 | |||
975 | static const dataspec_t svgm_udnetw[] = |
||
976 | { |
||
3177 | helixhorne | 977 | { DS_STRING, (void *)"blK:udnt", 0, 1 }, |
1596 | plagman | 978 | { 0, &ud.multimode, sizeof(ud.multimode), 1 }, |
979 | { 0, &g_numPlayerSprites, sizeof(g_numPlayerSprites), 1 }, |
||
980 | { 0, &g_playerSpawnPoints, sizeof(g_playerSpawnPoints), 1 }, |
||
981 | |||
982 | { DS_NOCHK, &ud.volume_number, sizeof(ud.volume_number), 1 }, |
||
983 | { DS_NOCHK, &ud.level_number, sizeof(ud.level_number), 1 }, |
||
984 | { DS_NOCHK, &ud.player_skill, sizeof(ud.player_skill), 1 }, |
||
985 | |||
986 | { DS_NOCHK, &ud.from_bonus, sizeof(ud.from_bonus), 1 }, |
||
987 | { DS_NOCHK, &ud.secretlevel, sizeof(ud.secretlevel), 1 }, |
||
988 | { DS_NOCHK, &ud.respawn_monsters, sizeof(ud.respawn_monsters), 1 }, |
||
989 | { DS_NOCHK, &ud.respawn_items, sizeof(ud.respawn_items), 1 }, |
||
990 | { DS_NOCHK, &ud.respawn_inventory, sizeof(ud.respawn_inventory), 1 }, |
||
991 | { 0, &ud.god, sizeof(ud.god), 1 }, |
||
992 | { 0, &ud.auto_run, sizeof(ud.auto_run), 1 }, |
||
993 | // { DS_NOCHK, &ud.crosshair, sizeof(ud.crosshair), 1 }, |
||
994 | { DS_NOCHK, &ud.monsters_off, sizeof(ud.monsters_off), 1 }, |
||
995 | { DS_NOCHK, &ud.last_level, sizeof(ud.last_level), 1 }, |
||
996 | { 0, &ud.eog, sizeof(ud.eog), 1 }, |
||
997 | { DS_NOCHK, &ud.coop, sizeof(ud.coop), 1 }, |
||
998 | { DS_NOCHK, &ud.marker, sizeof(ud.marker), 1 }, |
||
999 | { DS_NOCHK, &ud.ffire, sizeof(ud.ffire), 1 }, |
||
1000 | { DS_NOCHK, &ud.noexits, sizeof(ud.noexits), 1 }, |
||
1001 | { DS_NOCHK, &ud.playerai, sizeof(ud.playerai), 1 }, |
||
1598 | helixhorne | 1002 | { 0, &ud.pause_on, sizeof(ud.pause_on), 1 }, |
1596 | plagman | 1003 | { DS_NOCHK, ¤tboardfilename[0], BMAX_PATH, 1 }, |
2207 | helixhorne | 1004 | // { DS_LOADFN, (void *)&sv_postudload, 0, 1 }, |
1596 | plagman | 1005 | { 0, connectpoint2, sizeof(connectpoint2), 1 }, |
1006 | { 0, &randomseed, sizeof(randomseed), 1 }, |
||
1007 | { 0, &g_globalRandom, sizeof(g_globalRandom), 1 }, |
||
3929 | helixhorne | 1008 | #ifdef LUNATIC |
1009 | // Save game tic count for Lunatic because it is exposed to userland. See |
||
1010 | // test/helixspawner.lua for an example. |
||
1011 | { 0, &g_moveThingsCount, sizeof(g_moveThingsCount), 1 }, |
||
1012 | #endif |
||
1596 | plagman | 1013 | // { 0, &lockclock_dummy, sizeof(lockclock), 1 }, |
1014 | { DS_END, 0, 0, 0 } |
||
1015 | }; |
||
1016 | |||
2270 | helixhorne | 1017 | #if !defined DEBUG_MAIN_ARRAYS |
1018 | # define DS_MAINAR DS_DYNAMIC |
||
1019 | #else |
||
1020 | # define DS_MAINAR 0 |
||
1021 | #endif |
||
1022 | |||
1596 | plagman | 1023 | static const dataspec_t svgm_secwsp[] = |
1024 | { |
||
3177 | helixhorne | 1025 | { DS_STRING, (void *)"blK:swsp", 0, 1 }, |
1596 | plagman | 1026 | { DS_NOCHK, &numwalls, sizeof(numwalls), 1 }, |
2270 | helixhorne | 1027 | { DS_MAINAR|DS_CNT(numwalls), &wall, sizeof(walltype), (intptr_t)&numwalls }, |
1596 | plagman | 1028 | { DS_NOCHK, &numsectors, sizeof(numsectors), 1 }, |
2270 | helixhorne | 1029 | { DS_MAINAR|DS_CNT(numsectors), §or, sizeof(sectortype), (intptr_t)&numsectors }, |
1030 | { DS_MAINAR, &sprite, sizeof(spritetype), MAXSPRITES }, |
||
1882 | helixhorne | 1031 | #ifdef YAX_ENABLE |
1032 | { DS_NOCHK, &numyaxbunches, sizeof(numyaxbunches), 1 }, |
||
3658 | helixhorne | 1033 | # if !defined NEW_MAP_FORMAT |
1882 | helixhorne | 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 }, |
||
3658 | helixhorne | 1036 | # endif |
1882 | helixhorne | 1037 | { DS_LOADFN|DS_PROTECTFN, (void *)&sv_postyaxload, 0, 1 }, |
1038 | #endif |
||
2483 | helixhorne | 1039 | { 0, &Numsprites, sizeof(Numsprites), 1 }, |
2470 | helixhorne | 1040 | { 0, &tailspritefree, sizeof(tailspritefree), 1 }, |
1596 | plagman | 1041 | { 0, &headspritesect[0], sizeof(headspritesect[0]), MAXSECTORS+1 }, |
1042 | { 0, &prevspritesect[0], sizeof(prevspritesect[0]), MAXSPRITES }, |
||
1043 | { 0, &nextspritesect[0], sizeof(nextspritesect[0]), MAXSPRITES }, |
||
1044 | { 0, &headspritestat[0], sizeof(headspritestat[0]), MAXSTATUS+1 }, |
||
1045 | { 0, &prevspritestat[0], sizeof(prevspritestat[0]), MAXSPRITES }, |
||
1046 | { 0, &nextspritestat[0], sizeof(nextspritestat[0]), MAXSPRITES }, |
||
1820 | terminx | 1047 | #ifdef USE_OPENGL |
1596 | plagman | 1048 | { DS_SAVEFN, (void *)&sv_prespriteextsave, 0, 1 }, |
1049 | #endif |
||
2270 | helixhorne | 1050 | { DS_MAINAR, &spriteext, sizeof(spriteext_t), MAXSPRITES }, |
1820 | terminx | 1051 | #ifdef USE_OPENGL |
1596 | plagman | 1052 | { DS_SAVEFN|DS_LOADFN, (void *)&sv_postspriteext, 0, 1 }, |
1053 | #endif |
||
1054 | { 0, &DynamicTileMap[0], sizeof(DynamicTileMap[0]), MAXTILES }, // NOCHK? |
||
3834 | hendricks2 | 1055 | { 0, &DynamicSoundMap[0], sizeof(DynamicSoundMap[0]), MAXSOUNDS }, // NOCHK? |
1596 | plagman | 1056 | { DS_NOCHK, &g_numCyclers, sizeof(g_numCyclers), 1 }, |
1057 | { DS_CNT(g_numCyclers), &cyclers[0][0], sizeof(cyclers[0]), (intptr_t)&g_numCyclers }, |
||
1058 | { DS_NOCHK, &g_numAnimWalls, sizeof(g_numAnimWalls), 1 }, |
||
1059 | { DS_CNT(g_numAnimWalls), &animwall, sizeof(animwall[0]), (intptr_t)&g_numAnimWalls }, |
||
1060 | { DS_NOCHK, &g_mirrorCount, sizeof(g_mirrorCount), 1 }, |
||
4385 | terminx | 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) }, |
||
1596 | plagman | 1063 | // projectiles |
1064 | { 0, &SpriteProjectile[0], sizeof(projectile_t), MAXSPRITES }, |
||
3151 | helixhorne | 1065 | { 0, &ProjectileData[0], sizeof(projectile_t), MAXTILES }, |
1596 | plagman | 1066 | { 0, &everyothertime, sizeof(everyothertime), 1 }, |
1067 | { DS_END, 0, 0, 0 } |
||
1068 | }; |
||
1069 | |||
1070 | static const dataspec_t svgm_script[] = |
||
1071 | { |
||
3177 | helixhorne | 1072 | { DS_STRING, (void *)"blK:scri", 0, 1 }, |
3456 | helixhorne | 1073 | #if !defined LUNATIC |
1596 | plagman | 1074 | { DS_NOCHK, &g_scriptSize, sizeof(g_scriptSize), 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 }, |
||
1077 | |||
1078 | { DS_SAVEFN|DS_NOCHK, (void *)&sv_prescriptsave_once, 0, 1 }, |
||
3456 | helixhorne | 1079 | #endif |
3151 | helixhorne | 1080 | { DS_NOCHK, &g_tile[0], sizeof(tiledata_t), MAXTILES }, |
3456 | helixhorne | 1081 | #if !defined LUNATIC |
1598 | helixhorne | 1082 | { DS_LOADFN|DS_NOCHK, (void *)&sv_prescriptload_once, 0, 1 }, |
1596 | plagman | 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 }, |
||
1085 | { DS_SAVEFN|DS_LOADFN|DS_NOCHK, (void *)&sv_postscript_once, 0, 1 }, |
||
3456 | helixhorne | 1086 | #endif |
1596 | plagman | 1087 | { DS_SAVEFN, (void *)&sv_preactordatasave, 0, 1 }, |
1677 | terminx | 1088 | { 0, &actor[0], sizeof(actor_t), MAXSPRITES }, |
1596 | plagman | 1089 | { DS_SAVEFN|DS_LOADFN, (void *)&sv_postactordata, 0, 1 }, |
3857 | helixhorne | 1090 | #if defined LUNATIC |
1091 | { DS_LOADFN|DS_NOCHK, (void *)&sv_create_lua_state, 0, 1 }, |
||
1092 | #endif |
||
1596 | plagman | 1093 | { DS_END, 0, 0, 0 } |
1094 | }; |
||
1095 | |||
1096 | static const dataspec_t svgm_anmisc[] = |
||
1097 | { |
||
3177 | helixhorne | 1098 | { DS_STRING, (void *)"blK:anms", 0, 1 }, |
1596 | plagman | 1099 | { 0, &g_animateCount, sizeof(g_animateCount), 1 }, |
1100 | { 0, &animatesect[0], sizeof(animatesect[0]), MAXANIMATES }, |
||
1101 | { 0, &animategoal[0], sizeof(animategoal[0]), MAXANIMATES }, |
||
1102 | { 0, &animatevel[0], sizeof(animatevel[0]), MAXANIMATES }, |
||
1103 | { DS_SAVEFN, (void *)&sv_preanimateptrsave, 0, 1 }, |
||
1104 | { 0, &animateptr[0], sizeof(animateptr[0]), MAXANIMATES }, |
||
1105 | { DS_SAVEFN|DS_LOADFN , (void *)&sv_postanimateptr, 0, 1 }, |
||
4220 | helixhorne | 1106 | { 0, &g_curViewscreen, sizeof(g_curViewscreen), 1 }, |
4385 | terminx | 1107 | { 0, &msx[0], sizeof(msx[0]), ARRAY_SIZE(msx) }, |
1108 | { 0, &msy[0], sizeof(msy[0]), ARRAY_SIZE(msy) }, |
||
1598 | helixhorne | 1109 | { 0, &g_spriteDeleteQueuePos, sizeof(g_spriteDeleteQueuePos), 1 }, |
1110 | { DS_NOCHK, &g_spriteDeleteQueueSize, sizeof(g_spriteDeleteQueueSize), 1 }, |
||
1111 | { DS_CNT(g_spriteDeleteQueueSize), &SpriteDeletionQueue[0], sizeof(int16_t), (intptr_t)&g_spriteDeleteQueueSize }, |
||
1596 | plagman | 1112 | { 0, &show2dsector[0], sizeof(uint8_t), MAXSECTORS>>3 }, |
1113 | { DS_NOCHK, &g_numClouds, sizeof(g_numClouds), 1 }, |
||
1114 | { 0, &clouds[0], sizeof(clouds), 1 }, |
||
1115 | { 0, &cloudx[0], sizeof(cloudx), 1 }, |
||
1116 | { 0, &cloudy[0], sizeof(cloudy), 1 }, |
||
3976 | helixhorne | 1117 | { 0, &g_pskyidx, sizeof(g_pskyidx), 1 }, // DS_NOCHK? |
1596 | plagman | 1118 | { 0, &g_earthquakeTime, sizeof(g_earthquakeTime), 1 }, |
1119 | |||
1120 | { DS_SAVEFN|DS_LOADFN|DS_NOCHK, (void *)sv_prequote, 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 |
||
1123 | { DS_DYNAMIC, &savegame_quotes, MAXQUOTELEN, MAXQUOTES }, |
||
1124 | { DS_LOADFN, (void *)&sv_quoteload, 0, 1 }, |
||
1125 | |||
1126 | { DS_NOCHK, &g_numQuoteRedefinitions, sizeof(g_numQuoteRedefinitions), 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 |
||
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 }, |
||
1131 | { DS_NOCHK|DS_SAVEFN|DS_LOADFN, (void *)&sv_postquoteredef, 0, 1 }, |
||
3883 | helixhorne | 1132 | #ifdef LUNATIC |
1133 | { 0, g_playerWeapon, sizeof(weapondata_t), MAXPLAYERS*MAX_WEAPONS }, |
||
1134 | #endif |
||
1596 | plagman | 1135 | { DS_SAVEFN, (void *)&sv_restsave, 0, 1 }, |
1136 | { 0, savegame_restdata, 1, sizeof(savegame_restdata) }, // sz/cnt swapped for kdfread |
||
1137 | { DS_LOADFN, (void *)&sv_restload, 0, 1 }, |
||
1138 | |||
3177 | helixhorne | 1139 | { DS_STRING, (void *)"savegame_end", 0, 1 }, |
1596 | plagman | 1140 | { DS_END, 0, 0, 0 } |
1141 | }; |
||
1142 | |||
3789 | helixhorne | 1143 | #if !defined LUNATIC |
1595 | helixhorne | 1144 | static dataspec_t *svgm_vars=NULL; |
3789 | helixhorne | 1145 | #endif |
2207 | helixhorne | 1146 | static uint8_t *dosaveplayer2(FILE *fil, uint8_t *mem); |
1147 | static int32_t doloadplayer2(int32_t fil, uint8_t **memptr); |
||
1148 | static void postloadplayer(int32_t savegamep); |
||
1595 | helixhorne | 1149 | |
1150 | // SVGM snapshot system |
||
1151 | static uint32_t svsnapsiz; |
||
1152 | static uint8_t *svsnapshot, *svinitsnap; |
||
1153 | static uint32_t svdiffsiz; |
||
1154 | static uint8_t *svdiff; |
||
1155 | |||
1156 | #include "gamedef.h" |
||
1157 | |||
3789 | helixhorne | 1158 | #if !defined LUNATIC |
1159 | # define SV_SKIPMASK (/*GAMEVAR_SYSTEM|*/GAMEVAR_READONLY|GAMEVAR_INTPTR| \ |
||
1160 | GAMEVAR_SHORTPTR|GAMEVAR_CHARPTR /*|GAMEVAR_NORESET*/ |GAMEVAR_SPECIAL) |
||
1595 | helixhorne | 1161 | // setup gamevar data spec for snapshotting and diffing... gamevars must be loaded when called |
1162 | static void sv_makevarspec() |
||
1163 | { |
||
1164 | static char *magic = "blK:vars"; |
||
4191 | helixhorne | 1165 | int32_t i, j, numsavedvars=0, numsavedarrays=0, per; |
1595 | helixhorne | 1166 | |
1167 | for (i=0; i<g_gameVarCount; i++) |
||
1168 | numsavedvars += (aGameVars[i].dwFlags&SV_SKIPMASK) ? 0 : 1; |
||
1169 | |||
4191 | helixhorne | 1170 | for (i=0; i<g_gameArrayCount; i++) |
1171 | numsavedarrays += !(aGameArrays[i].dwFlags & GAMEARRAY_READONLY); // SYSTEM_GAMEARRAY |
||
1172 | |||
3808 | helixhorne | 1173 | Bfree(svgm_vars); |
4491 | helixhorne | 1174 | svgm_vars = (dataspec_t *)Xmalloc((numsavedvars+numsavedarrays+2)*sizeof(dataspec_t)); |
1595 | helixhorne | 1175 | |
1176 | svgm_vars[0].flags = DS_STRING; |
||
1177 | svgm_vars[0].ptr = magic; |
||
1178 | svgm_vars[0].cnt = 1; |
||
1179 | |||
1180 | j=1; |
||
1181 | for (i=0; i<g_gameVarCount; i++) |
||
1182 | { |
||
1183 | if (aGameVars[i].dwFlags&SV_SKIPMASK) |
||
1184 | continue; |
||
1185 | |||
1186 | per = aGameVars[i].dwFlags&GAMEVAR_USER_MASK; |
||
1187 | |||
1188 | svgm_vars[j].flags = 0; |
||
1189 | svgm_vars[j].ptr = (per==0) ? &aGameVars[i].val.lValue : aGameVars[i].val.plValues; |
||
1190 | svgm_vars[j].size = sizeof(intptr_t); |
||
1191 | svgm_vars[j].cnt = (per==0) ? 1 : (per==GAMEVAR_PERPLAYER ? MAXPLAYERS : MAXSPRITES); |
||
1192 | j++; |
||
1193 | } |
||
1194 | |||
1195 | for (i=0; i<g_gameArrayCount; i++) |
||
1196 | { |
||
4191 | helixhorne | 1197 | // We must not update read-only SYSTEM_GAMEARRAY gamearrays: besides |
1198 | // being questionable by itself, sizeof(...) may be e.g. 4 whereas the |
||
1199 | // actual element type is int16_t (such as tilesizx[]/tilesizy[]). |
||
1200 | if (aGameArrays[i].dwFlags & GAMEARRAY_READONLY) |
||
1201 | continue; |
||
1202 | |||
1595 | helixhorne | 1203 | svgm_vars[j].flags = 0; |
1204 | svgm_vars[j].ptr = aGameArrays[i].plValues; |
||
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 |
||
1207 | j++; |
||
1208 | } |
||
1209 | |||
1210 | svgm_vars[j].flags = DS_END; |
||
4191 | helixhorne | 1211 | svgm_vars[j].ptr = NULL; |
1212 | svgm_vars[j].size = svgm_vars[j].cnt = 0; |
||
3789 | helixhorne | 1213 | } |
3415 | helixhorne | 1214 | #endif |
1595 | helixhorne | 1215 | |
1216 | void sv_freemem() |
||
1217 | { |
||
4990 | terminx | 1218 | DO_FREE_AND_NULL(svsnapshot); |
1219 | DO_FREE_AND_NULL(svinitsnap); |
||
1220 | DO_FREE_AND_NULL(svdiff); |
||
1595 | helixhorne | 1221 | } |
1222 | |||
4491 | helixhorne | 1223 | static void SV_AllocSnap(int32_t allocinit) |
1595 | helixhorne | 1224 | { |
1225 | sv_freemem(); |
||
1226 | |||
4491 | helixhorne | 1227 | svsnapshot = (uint8_t *)Xmalloc(svsnapsiz); |
1595 | helixhorne | 1228 | if (allocinit) |
4491 | helixhorne | 1229 | svinitsnap = (uint8_t *)Xmalloc(svsnapsiz); |
1595 | helixhorne | 1230 | svdiffsiz = svsnapsiz; // theoretically it's less than could be needed in the worst case, but practically it's overkill |
4491 | helixhorne | 1231 | svdiff = (uint8_t *)Xmalloc(svdiffsiz); |
1595 | helixhorne | 1232 | } |
1233 | |||
4990 | terminx | 1234 | EDUKE32_STATIC_ASSERT(sizeof(savehead_t) == SAVEHEAD_SIZE); |
2207 | helixhorne | 1235 | |
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) |
||
1595 | helixhorne | 1238 | { |
2207 | helixhorne | 1239 | savehead_t h; |
1595 | helixhorne | 1240 | |
2207 | helixhorne | 1241 | // set a few savegame system globals |
1595 | helixhorne | 1242 | savegame_comprthres = SV_DEFAULTCOMPRTHRES; |
2207 | helixhorne | 1243 | savegame_diffcompress = diffcompress; |
1595 | helixhorne | 1244 | |
2207 | helixhorne | 1245 | // calculate total snapshot size |
3789 | helixhorne | 1246 | #if !defined LUNATIC |
1595 | helixhorne | 1247 | sv_makevarspec(); |
1248 | svsnapsiz = calcsz(svgm_vars); |
||
3789 | helixhorne | 1249 | #else |
1250 | svsnapsiz = 0; |
||
1251 | #endif |
||
1595 | helixhorne | 1252 | svsnapsiz += calcsz(svgm_udnetw) + calcsz(svgm_secwsp) + calcsz(svgm_script) + calcsz(svgm_anmisc); |
1253 | |||
1254 | |||
2207 | helixhorne | 1255 | // create header |
1256 | Bmemcpy(h.headerstr, "EDuke32SAVE", 11); |
||
1257 | h.majorver = SV_MAJOR_VER; |
||
1258 | h.minorver = SV_MINOR_VER; |
||
1259 | h.ptrsize = sizeof(intptr_t); |
||
1260 | h.bytever = BYTEVERSION; |
||
1261 | |||
1262 | h.comprthres = savegame_comprthres; |
||
1263 | h.recdiffsp = recdiffsp; |
||
1264 | h.diffcompress = savegame_diffcompress; |
||
1265 | h.synccompress = synccompress; |
||
1266 | |||
1267 | h.reccnt = 0; |
||
1268 | h.snapsiz = svsnapsiz; |
||
1269 | |||
1270 | // the following is kinda redundant, but we save it here to be able to quickly fetch |
||
1271 | // it in a savegame header read |
||
1272 | h.numplayers = ud.multimode; |
||
1273 | h.volnum = ud.volume_number; |
||
1274 | h.levnum = ud.level_number; |
||
1275 | h.skill = ud.player_skill; |
||
1276 | |||
4589 | helixhorne | 1277 | if (currentboardfilename[0] != 0 && ud.level_number == 7 && ud.volume_number == 0) |
1278 | { |
||
1279 | const uint32_t BSZ = sizeof(h.boardfn); |
||
1280 | EDUKE32_STATIC_ASSERT(BSZ == sizeof(currentboardfilename)); |
||
1281 | |||
1282 | Bstrncpy(h.boardfn, currentboardfilename, BSZ); |
||
1283 | |||
1284 | // Shoehorn currently playing music into last bytes of board name buffer. |
||
1285 | // SAVEGAME_MUSIC. |
||
1286 | if (g_musicIndex != (0*MAXLEVELS+7) && Bstrlen(h.boardfn) < BSZ-2) |
||
1287 | { |
||
1288 | h.boardfn[BSZ-2] = g_musicIndex / MAXLEVELS; |
||
1289 | h.boardfn[BSZ-1] = g_musicIndex % MAXLEVELS; |
||
1290 | } |
||
1291 | } |
||
1292 | |||
4472 | hendricks2 | 1293 | if ((unsigned)spot < MAXSAVEGAMES) |
1595 | helixhorne | 1294 | { |
2207 | helixhorne | 1295 | // savegame |
2559 | helixhorne | 1296 | Bstrncpyz(h.savename, ud.savegame[spot], sizeof(h.savename)); |
4990 | terminx | 1297 | #ifdef __ANDROID__ |
1298 | Bstrncpyz(h.volname, EpisodeNames[ud.volume_number], sizeof(h.volname)); |
||
1299 | Bstrncpyz(h.skillname, SkillNames[ud.player_skill], sizeof(h.skillname)); |
||
1300 | #endif |
||
1595 | helixhorne | 1301 | } |
2207 | helixhorne | 1302 | else |
1303 | { |
||
1304 | // demo |
||
1595 | helixhorne | 1305 | |
2207 | helixhorne | 1306 | const time_t t=time(NULL); |
1307 | struct tm *st; |
||
1595 | helixhorne | 1308 | |
4133 | helixhorne | 1309 | Bstrncpyz(h.savename, "EDuke32 demo", sizeof(h.savename)); |
2207 | helixhorne | 1310 | if (t>=0 && (st = localtime(&t))) |
4133 | helixhorne | 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); |
||
2207 | helixhorne | 1313 | } |
1314 | |||
1315 | |||
1316 | // write header |
||
1317 | fwrite(&h, sizeof(savehead_t), 1, fil); |
||
1318 | |||
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 |
||
1321 | fwrite("\0\0\0\0", 4, 1, fil); |
||
1322 | if (spot >= 0 && waloff[TILE_SAVESHOT]) |
||
1323 | { |
||
1324 | int32_t ofs; |
||
1325 | |||
1326 | // write the screenshot compressed |
||
1327 | dfwrite((char *)waloff[TILE_SAVESHOT], 320, 200, fil); |
||
1328 | |||
1329 | // write the current file offset right after the header |
||
1330 | ofs = ftell(fil); |
||
1331 | fseek(fil, sizeof(savehead_t), SEEK_SET); |
||
1332 | fwrite(&ofs, 4, 1, fil); |
||
1333 | fseek(fil, ofs, SEEK_SET); |
||
1334 | } |
||
1335 | |||
1336 | #ifdef DEBUGGINGAIDS |
||
1337 | OSD_Printf("sv_saveandmakesnapshot: snapshot size: %d bytes.\n", svsnapsiz); |
||
1338 | #endif |
||
1339 | |||
1340 | if (spot >= 0) |
||
1341 | { |
||
1342 | // savegame |
||
1343 | dosaveplayer2(fil, NULL); |
||
3796 | helixhorne | 1344 | #ifdef LUNATIC |
1345 | if (!g_savedOK) |
||
1346 | { |
||
3914 | helixhorne | 1347 | OSD_Printf("sv_saveandmakesnapshot: failed serializing Lunatic gamevar \"%s\".\n", |
3796 | helixhorne | 1348 | g_failedVarname); |
1349 | g_failedVarname = NULL; |
||
1350 | return 1; |
||
1351 | } |
||
1352 | #endif |
||
2207 | helixhorne | 1353 | } |
1354 | else |
||
1355 | { |
||
1356 | uint8_t *p; |
||
1357 | |||
1358 | // demo |
||
4491 | helixhorne | 1359 | SV_AllocSnap(0); |
2207 | helixhorne | 1360 | |
1361 | p = dosaveplayer2(fil, svsnapshot); |
||
1362 | if (p != svsnapshot+svsnapsiz) |
||
1363 | { |
||
1364 | OSD_Printf("sv_saveandmakesnapshot: ptr-(snapshot end)=%d!\n", (int32_t)(p-(svsnapshot+svsnapsiz))); |
||
1365 | return 1; |
||
1366 | } |
||
1367 | } |
||
1368 | |||
3156 | helixhorne | 1369 | g_oldverSavegame[spot] = 0; |
1370 | |||
1595 | helixhorne | 1371 | return 0; |
1372 | } |
||
1373 | |||
4990 | terminx | 1374 | EDUKE32_STATIC_ASSERT(sizeof(savehead_t) == SAVEHEAD_SIZE); |
3644 | helixhorne | 1375 | |
2207 | helixhorne | 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) |
||
1595 | helixhorne | 1378 | { |
2207 | helixhorne | 1379 | int32_t havedemo = (spot < 0); |
1595 | helixhorne | 1380 | |
2207 | helixhorne | 1381 | if (kread(fil, h, sizeof(savehead_t)) != sizeof(savehead_t)) |
1595 | helixhorne | 1382 | { |
2207 | helixhorne | 1383 | OSD_Printf("%s %d header corrupt.\n", havedemo ? "Demo":"Savegame", havedemo ? -spot : spot); |
1384 | Bmemset(h->headerstr, 0, sizeof(h->headerstr)); |
||
1385 | return -1; |
||
1386 | } |
||
1387 | |||
1388 | if (Bmemcmp(h->headerstr, "EDuke32SAVE", 11)) |
||
1389 | { |
||
1390 | h->headerstr[sizeof(h->headerstr)-1] = 0; |
||
1391 | OSD_Printf("%s %d header reads \"%s\", expected \"EDuke32SAVE\".\n", |
||
1392 | havedemo ? "Demo":"Savegame", havedemo ? -spot : spot, h->headerstr); |
||
1393 | Bmemset(h->headerstr, 0, sizeof(h->headerstr)); |
||
1595 | helixhorne | 1394 | return 1; |
1395 | } |
||
1396 | |||
2207 | helixhorne | 1397 | if (h->majorver != SV_MAJOR_VER || h->minorver != SV_MINOR_VER || h->bytever != BYTEVERSION) |
1595 | helixhorne | 1398 | { |
2207 | helixhorne | 1399 | if (havedemo) |
1400 | OSD_Printf("Incompatible demo version. Expected %d.%d.%d, found %d.%d.%d\n", |
||
1401 | SV_MAJOR_VER, SV_MINOR_VER, BYTEVERSION, |
||
1402 | h->majorver, h->minorver, h->bytever); |
||
1595 | helixhorne | 1403 | return 2; |
1404 | } |
||
2207 | helixhorne | 1405 | |
1406 | if (h->ptrsize != sizeof(intptr_t)) |
||
1595 | helixhorne | 1407 | { |
2207 | helixhorne | 1408 | if (havedemo) |
1409 | OSD_Printf("Demo incompatible. Expected pointer size %d, found %d\n", |
||
1410 | (int32_t)sizeof(intptr_t), h->ptrsize); |
||
1595 | helixhorne | 1411 | return 3; |
1412 | } |
||
1413 | |||
2207 | helixhorne | 1414 | return 0; |
1415 | } |
||
1595 | helixhorne | 1416 | |
2207 | helixhorne | 1417 | int32_t sv_loadsnapshot(int32_t fil, int32_t spot, savehead_t *h) |
1418 | { |
||
1419 | uint8_t *p; |
||
1420 | int32_t i; |
||
1595 | helixhorne | 1421 | |
2207 | helixhorne | 1422 | if (spot < 0) |
1423 | { |
||
1424 | // demo |
||
1425 | i = sv_loadheader(fil, spot, h); |
||
1426 | if (i) |
||
1427 | return i; |
||
1595 | helixhorne | 1428 | |
2207 | helixhorne | 1429 | // Used to be in doloadplayer2(), now redundant for savegames since |
1430 | // we checked before. Multiplayer demos need still to be taken care of. |
||
1431 | if (h->numplayers != numplayers) |
||
1432 | return 9; |
||
1433 | } |
||
1434 | // else (if savegame), we just read the header and are now at offset sizeof(savehead_t) |
||
1595 | helixhorne | 1435 | |
2207 | helixhorne | 1436 | #ifdef DEBUGGINGAIDS |
1437 | OSD_Printf("sv_loadsnapshot: snapshot size: %d bytes.\n", h->snapsiz); |
||
1438 | #endif |
||
1439 | |||
1440 | if (kread(fil, &i, 4) != 4) |
||
1595 | helixhorne | 1441 | { |
2207 | helixhorne | 1442 | OSD_Printf("sv_snapshot: couldn't read 4 bytes after header.\n"); |
1443 | return 7; |
||
1595 | helixhorne | 1444 | } |
2207 | helixhorne | 1445 | if (i > 0) |
1446 | { |
||
1447 | if (klseek(fil, i, SEEK_SET) != i) |
||
1448 | { |
||
1449 | OSD_Printf("sv_snapshot: failed skipping over the screenshot.\n"); |
||
1450 | return 8; |
||
1451 | } |
||
1452 | } |
||
1595 | helixhorne | 1453 | |
2212 | helixhorne | 1454 | savegame_comprthres = h->comprthres; |
1455 | |||
2207 | helixhorne | 1456 | if (spot >= 0) |
1595 | helixhorne | 1457 | { |
2207 | helixhorne | 1458 | // savegame |
1459 | i = doloadplayer2(fil, NULL); |
||
1460 | if (i) |
||
1461 | { |
||
1462 | OSD_Printf("sv_loadsnapshot: doloadplayer2() returned %d.\n", i); |
||
1463 | return 5; |
||
1464 | } |
||
1595 | helixhorne | 1465 | } |
2207 | helixhorne | 1466 | else |
1467 | { |
||
1468 | // demo |
||
1469 | savegame_diffcompress = h->diffcompress; |
||
1595 | helixhorne | 1470 | |
2207 | helixhorne | 1471 | svsnapsiz = h->snapsiz; |
1595 | helixhorne | 1472 | |
4491 | helixhorne | 1473 | SV_AllocSnap(1); |
1595 | helixhorne | 1474 | |
2207 | helixhorne | 1475 | p = svsnapshot; |
1476 | i = doloadplayer2(fil, &p); |
||
1477 | if (i) |
||
1478 | { |
||
1479 | OSD_Printf("sv_loadsnapshot: doloadplayer2() returned %d.\n", i); |
||
1480 | sv_freemem(); |
||
1481 | return 5; |
||
1482 | } |
||
1483 | |||
1484 | if (p != svsnapshot+svsnapsiz) |
||
1485 | { |
||
1486 | OSD_Printf("sv_loadsnapshot: internal error: p-(snapshot end)=%d!\n", |
||
1487 | (int32_t)(p-(svsnapshot+svsnapsiz))); |
||
1488 | sv_freemem(); |
||
1489 | return 6; |
||
1490 | } |
||
1491 | |||
1492 | Bmemcpy(svinitsnap, svsnapshot, svsnapsiz); |
||
1595 | helixhorne | 1493 | } |
1494 | |||
2207 | helixhorne | 1495 | postloadplayer((spot >= 0)); |
1496 | |||
1595 | helixhorne | 1497 | return 0; |
1498 | } |
||
1499 | |||
2207 | helixhorne | 1500 | |
1595 | helixhorne | 1501 | uint32_t sv_writediff(FILE *fil) |
1502 | { |
||
1503 | uint8_t *p=svsnapshot, *d=svdiff; |
||
1504 | uint32_t diffsiz; |
||
1505 | |||
1506 | cmpspecdata(svgm_udnetw, &p, &d); |
||
1507 | cmpspecdata(svgm_secwsp, &p, &d); |
||
1508 | cmpspecdata(svgm_script, &p, &d); |
||
1509 | cmpspecdata(svgm_anmisc, &p, &d); |
||
3789 | helixhorne | 1510 | #if !defined LUNATIC |
1595 | helixhorne | 1511 | cmpspecdata(svgm_vars, &p, &d); |
3789 | helixhorne | 1512 | #endif |
1595 | helixhorne | 1513 | |
1514 | if (p != svsnapshot+svsnapsiz) |
||
1515 | OSD_Printf("sv_writediff: dump+siz=%p, p=%p!\n", svsnapshot+svsnapsiz, p); |
||
1516 | |||
1517 | diffsiz = d-svdiff; |
||
1518 | |||
1519 | fwrite("dIfF",4,1,fil); |
||
1520 | fwrite(&diffsiz, sizeof(diffsiz), 1, fil); |
||
1521 | if (savegame_diffcompress) |
||
1522 | dfwrite(svdiff, 1, diffsiz, fil); // cnt and sz swapped |
||
1523 | else |
||
1524 | fwrite(svdiff, 1, diffsiz, fil); |
||
1525 | |||
1526 | return diffsiz; |
||
1527 | } |
||
1528 | |||
1529 | int32_t sv_readdiff(int32_t fil) |
||
1530 | { |
||
1531 | uint8_t *p=svsnapshot, *d=svdiff, i=0; //, tbuf[4]; |
||
1599 | terminx | 1532 | int32_t diffsiz; |
1595 | helixhorne | 1533 | |
1534 | #if 0 // handled by the caller |
||
1599 | terminx | 1535 | if (kread(fil, tbuf, 4)!=4) |
1536 | return -1; |
||
1537 | if (Bmemcmp(tbuf, "dIfF", 4)) |
||
1538 | return 4; |
||
1595 | helixhorne | 1539 | #endif |
1599 | terminx | 1540 | if (kread(fil, &diffsiz, sizeof(uint32_t))!=sizeof(uint32_t)) |
1541 | return -1; |
||
1595 | helixhorne | 1542 | if (savegame_diffcompress) |
1543 | { |
||
1544 | if (kdfread(svdiff, 1, diffsiz, fil) != diffsiz) // cnt and sz swapped |
||
1545 | return -2; |
||
1546 | } |
||
1547 | else |
||
1548 | { |
||
1549 | if (kread(fil, svdiff, diffsiz) != diffsiz) |
||
1550 | return -2; |
||
1551 | } |
||
1552 | |||
1599 | terminx | 1553 | if (applydiff(svgm_udnetw, &p, &d)) return -3; |
1554 | if (applydiff(svgm_secwsp, &p, &d)) return -4; |
||
1555 | if (applydiff(svgm_script, &p, &d)) return -5; |
||
1556 | if (applydiff(svgm_anmisc, &p, &d)) return -6; |
||
3789 | helixhorne | 1557 | #if !defined LUNATIC |
1599 | terminx | 1558 | if (applydiff(svgm_vars, &p, &d)) return -7; |
3789 | helixhorne | 1559 | #endif |
1595 | helixhorne | 1560 | |
1599 | terminx | 1561 | if (p!=svsnapshot+svsnapsiz) |
1562 | i|=1; |
||
1563 | if (d!=svdiff+diffsiz) |
||
1564 | i|=2; |
||
1565 | if (i) |
||
1566 | OSD_Printf("sv_readdiff: p=%p, svsnapshot+svsnapsiz=%p; d=%p, svdiff+diffsiz=%p", |
||
1567 | p, svsnapshot+svsnapsiz, d, svdiff+diffsiz); |
||
1568 | return i; |
||
1595 | helixhorne | 1569 | } |
1570 | |||
1571 | // SVGM data description |
||
1572 | static void sv_postudload() |
||
1573 | { |
||
2207 | helixhorne | 1574 | // Bmemcpy(&boardfilename[0], ¤tboardfilename[0], BMAX_PATH); // DON'T do this in demos! |
1575 | #if 1 |
||
1595 | helixhorne | 1576 | ud.m_level_number = ud.level_number; |
1577 | ud.m_volume_number = ud.volume_number; |
||
1578 | ud.m_player_skill = ud.player_skill; |
||
1579 | ud.m_respawn_monsters = ud.respawn_monsters; |
||
1580 | ud.m_respawn_items = ud.respawn_items; |
||
1581 | ud.m_respawn_inventory = ud.respawn_inventory; |
||
1582 | ud.m_monsters_off = ud.monsters_off; |
||
1583 | ud.m_coop = ud.coop; |
||
1584 | ud.m_marker = ud.marker; |
||
1585 | ud.m_ffire = ud.ffire; |
||
1586 | ud.m_noexits = ud.noexits; |
||
1598 | helixhorne | 1587 | #endif |
1595 | helixhorne | 1588 | } |
1589 | //static int32_t lockclock_dummy; |
||
1590 | |||
1820 | terminx | 1591 | #ifdef USE_OPENGL |
1595 | helixhorne | 1592 | static void sv_prespriteextsave() |
1593 | { |
||
1594 | int32_t i; |
||
1595 | for (i=0; i<MAXSPRITES; i++) |
||
1596 | if (spriteext[i].mdanimtims) |
||
1597 | { |
||
1598 | spriteext[i].mdanimtims -= mdtims; |
||
1599 | if (spriteext[i].mdanimtims==0) |
||
1600 | spriteext[i].mdanimtims++; |
||
1601 | } |
||
1602 | } |
||
1603 | static void sv_postspriteext() |
||
1604 | { |
||
1605 | int32_t i; |
||
1606 | for (i=0; i<MAXSPRITES; i++) |
||
1607 | if (spriteext[i].mdanimtims) |
||
1608 | spriteext[i].mdanimtims += mdtims; |
||
1609 | } |
||
1610 | #endif |
||
1611 | |||
1882 | helixhorne | 1612 | #ifdef YAX_ENABLE |
2449 | helixhorne | 1613 | void sv_postyaxload(void) |
1882 | helixhorne | 1614 | { |
1615 | yax_update(numyaxbunches>0 ? 2 : 1); |
||
1616 | } |
||
1617 | #endif |
||
1618 | |||
3456 | helixhorne | 1619 | #if !defined LUNATIC |
1595 | helixhorne | 1620 | static void sv_calcbitptrsize() |
1621 | { |
||
1622 | savegame_bitptrsize = (g_scriptSize+7)>>3; |
||
1623 | } |
||
1624 | static void sv_prescriptsave_once() |
||
1625 | { |
||
1626 | int32_t i; |
||
1627 | for (i=0; i<g_scriptSize; i++) |
||
1628 | if (bitptr[i>>3]&(BITPTR_POINTER<<(i&7))) |
||
2200 | helixhorne | 1629 | script[i] = (intptr_t *)script[i] - script; |
1950 | helixhorne | 1630 | |
3102 | terminx | 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); |
||
1595 | helixhorne | 1633 | } |
1598 | helixhorne | 1634 | static void sv_prescriptload_once() |
1635 | { |
||
1636 | if (script) |
||
1637 | Bfree(script); |
||
4491 | helixhorne | 1638 | script = (intptr_t *)Xmalloc(g_scriptSize * sizeof(script[0])); |
1598 | helixhorne | 1639 | } |
1595 | helixhorne | 1640 | static void sv_postscript_once() |
1641 | { |
||
1642 | int32_t i; |
||
1950 | helixhorne | 1643 | |
3102 | terminx | 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); |
||
1950 | helixhorne | 1646 | |
1595 | helixhorne | 1647 | for (i=0; i<g_scriptSize; i++) |
1648 | if (bitptr[i>>3]&(BITPTR_POINTER<<(i&7))) |
||
2200 | helixhorne | 1649 | script[i] = (intptr_t)(script + script[i]); |
1595 | helixhorne | 1650 | } |
3456 | helixhorne | 1651 | #endif |
2185 | helixhorne | 1652 | |
1595 | helixhorne | 1653 | static void sv_preactordatasave() |
1654 | { |
||
1655 | int32_t i; |
||
2451 | helixhorne | 1656 | |
1595 | helixhorne | 1657 | for (i=0; i<MAXSPRITES; i++) |
1658 | { |
||
1910 | helixhorne | 1659 | actor[i].lightptr = NULL; |
1660 | actor[i].lightId = -1; |
||
1595 | helixhorne | 1661 | } |
1662 | } |
||
2185 | helixhorne | 1663 | |
1595 | helixhorne | 1664 | static void sv_postactordata() |
1665 | { |
||
1666 | int32_t i; |
||
1667 | |||
1668 | for (i=0; i<MAXSPRITES; i++) |
||
1669 | { |
||
1910 | helixhorne | 1670 | actor[i].lightptr = NULL; |
1671 | actor[i].lightId = -1; |
||
1595 | helixhorne | 1672 | } |
1673 | } |
||
1674 | |||
1675 | static void sv_preanimateptrsave() |
||
1676 | { |
||
1950 | helixhorne | 1677 | G_Util_PtrToIdx(animateptr, g_animateCount, sector, P2I_FWD); |
1595 | helixhorne | 1678 | } |
1679 | static void sv_postanimateptr() |
||
1680 | { |
||
1950 | helixhorne | 1681 | G_Util_PtrToIdx(animateptr, g_animateCount, sector, P2I_BACK); |
1595 | helixhorne | 1682 | } |
1683 | static void sv_prequote() |
||
1684 | { |
||
1685 | if (!savegame_quotes) |
||
4530 | terminx | 1686 | { |
1687 | void *ptr = Xcalloc(MAXQUOTES, MAXQUOTELEN); |
||
1688 | savegame_quotes = (char(*)[MAXQUOTELEN])ptr; |
||
1689 | } |
||
1595 | helixhorne | 1690 | } |
1691 | static void sv_quotesave() |
||
1692 | { |
||
1693 | int32_t i; |
||
1694 | Bmemset(savegame_quotedef, 0, sizeof(savegame_quotedef)); |
||
1695 | for (i=0; i<MAXQUOTES; i++) |
||
1696 | if (ScriptQuotes[i]) |
||
1697 | { |
||
1698 | savegame_quotedef[i>>3] |= 1<<(i&7); |
||
1699 | Bmemcpy(savegame_quotes[i], ScriptQuotes[i], MAXQUOTELEN); |
||
1700 | } |
||
1701 | } |
||
1702 | static void sv_quoteload() |
||
1703 | { |
||
1704 | int32_t i; |
||
1705 | for (i=0; i<MAXQUOTES; i++) |
||
1706 | { |
||
1707 | if (savegame_quotedef[i>>3]&(1<<(i&7))) |
||
1708 | { |
||
3356 | helixhorne | 1709 | C_AllocQuote(i); |
1595 | helixhorne | 1710 | Bmemcpy(ScriptQuotes[i], savegame_quotes[i], MAXQUOTELEN); |
1711 | } |
||
1712 | } |
||
1713 | } |
||
1714 | static void sv_prequoteredef() |
||
1715 | { |
||
1716 | // "+1" needed for dfwrite which doesn't handle the src==NULL && cnt==0 case |
||
4530 | terminx | 1717 | void *ptr = Xcalloc(g_numQuoteRedefinitions+1, MAXQUOTELEN); |
1718 | savegame_quoteredefs = (char(*)[MAXQUOTELEN])ptr; |
||
1595 | helixhorne | 1719 | } |
1720 | static void sv_quoteredefsave() |
||
1721 | { |
||
1722 | int32_t i; |
||
1723 | for (i=0; i<g_numQuoteRedefinitions; i++) |
||
1724 | if (ScriptQuoteRedefinitions[i]) |
||
1725 | Bmemcpy(savegame_quoteredefs[i], ScriptQuoteRedefinitions[i], MAXQUOTELEN); |
||
1726 | } |
||
1727 | static void sv_quoteredefload() |
||
1728 | { |
||
1729 | int32_t i; |
||
1730 | for (i=0; i<g_numQuoteRedefinitions; i++) |
||
1731 | { |
||
1732 | if (!ScriptQuoteRedefinitions[i]) |
||
4491 | helixhorne | 1733 | ScriptQuoteRedefinitions[i] = (char *)Xcalloc(1,MAXQUOTELEN); |
1595 | helixhorne | 1734 | Bmemcpy(ScriptQuoteRedefinitions[i], savegame_quoteredefs[i], MAXQUOTELEN); |
1735 | } |
||
1736 | } |
||
1737 | static void sv_postquoteredef() |
||
1738 | { |
||
1739 | Bfree(savegame_quoteredefs), savegame_quoteredefs=NULL; |
||
1740 | } |
||
1741 | static void sv_restsave() |
||
1742 | { |
||
1743 | int32_t i; |
||
1744 | uint8_t *mem = savegame_restdata; |
||
1745 | DukePlayer_t dummy_ps; |
||
1746 | |||
1747 | Bmemset(&dummy_ps, 0, sizeof(DukePlayer_t)); |
||
1748 | |||
1599 | terminx | 1749 | #define CPDAT(ptr,sz) Bmemcpy(mem, ptr, sz), mem+=sz |
1595 | helixhorne | 1750 | for (i=0; i<MAXPLAYERS; i++) |
1751 | { |
||
1752 | CPDAT(g_player[i].user_name, 32); |
||
1753 | CPDAT(&g_player[i].pcolor, sizeof(g_player[0].pcolor)); |
||
1754 | CPDAT(&g_player[i].pteam, sizeof(g_player[0].pteam)); |
||
1755 | CPDAT(&g_player[i].frags[0], sizeof(g_player[0].frags)); |
||
1756 | if (g_player[i].ps) |
||
1757 | CPDAT(g_player[i].ps, sizeof(DukePlayer_t)); |
||
1758 | else |
||
1759 | CPDAT(&dummy_ps, sizeof(DukePlayer_t)); |
||
1760 | } |
||
2207 | helixhorne | 1761 | |
3257 | helixhorne | 1762 | Bassert((savegame_restdata+SVARDATALEN)-mem == 0); |
1599 | terminx | 1763 | #undef CPDAT |
1595 | helixhorne | 1764 | } |
1765 | static void sv_restload() |
||
1766 | { |
||
1767 | int32_t i; |
||
1768 | uint8_t *mem = savegame_restdata; |
||
1769 | DukePlayer_t dummy_ps; |
||
1770 | |||
1599 | terminx | 1771 | #define CPDAT(ptr,sz) Bmemcpy(ptr, mem, sz), mem+=sz |
1595 | helixhorne | 1772 | for (i=0; i<MAXPLAYERS; i++) |
1773 | { |
||
1774 | CPDAT(g_player[i].user_name, 32); |
||
1775 | CPDAT(&g_player[i].pcolor, sizeof(g_player[0].pcolor)); |
||
1776 | CPDAT(&g_player[i].pteam, sizeof(g_player[0].pteam)); |
||
1777 | CPDAT(&g_player[i].frags[0], sizeof(g_player[0].frags)); |
||
1778 | if (g_player[i].ps) |
||
1779 | CPDAT(g_player[i].ps, sizeof(DukePlayer_t)); |
||
1780 | else |
||
1781 | CPDAT(&dummy_ps, sizeof(DukePlayer_t)); |
||
1782 | } |
||
1599 | terminx | 1783 | #undef CPDAT |
1595 | helixhorne | 1784 | } |
1785 | |||
2200 | helixhorne | 1786 | #ifdef DEBUGGINGAIDS |
2218 | helixhorne | 1787 | # define PRINTSIZE(name) do { if (mem) OSD_Printf(name ": %d\n", (int32_t)(mem-tmem)); \ |
1788 | OSD_Printf(name ": %d ms\n", getticks()-t); t=getticks(); tmem=mem; } while (0) |
||
2200 | helixhorne | 1789 | #else |
2218 | helixhorne | 1790 | # define PRINTSIZE(name) do { } while (0) |
2200 | helixhorne | 1791 | #endif |
1595 | helixhorne | 1792 | |
3796 | helixhorne | 1793 | #ifdef LUNATIC |
4119 | helixhorne | 1794 | // <levelnum>: if we're not serializing for a mapstate, -1 |
1795 | // otherwise, the linearized level number |
||
1796 | LUNATIC_CB const char *(*El_SerializeGamevars)(int32_t *slenptr, int32_t levelnum); |
||
3796 | helixhorne | 1797 | #endif |
1798 | |||
2207 | helixhorne | 1799 | static uint8_t *dosaveplayer2(FILE *fil, uint8_t *mem) |
1595 | helixhorne | 1800 | { |
2218 | helixhorne | 1801 | #ifdef DEBUGGINGAIDS |
1595 | helixhorne | 1802 | uint8_t *tmem = mem; |
2218 | helixhorne | 1803 | int32_t t=getticks(); |
1804 | #endif |
||
1595 | helixhorne | 1805 | mem=writespecdata(svgm_udnetw, fil, mem); // user settings, players & net |
2200 | helixhorne | 1806 | PRINTSIZE("ud"); |
1595 | helixhorne | 1807 | mem=writespecdata(svgm_secwsp, fil, mem); // sector, wall, sprite |
2200 | helixhorne | 1808 | PRINTSIZE("sws"); |
3891 | helixhorne | 1809 | #ifdef LUNATIC |
3796 | helixhorne | 1810 | { |
3891 | helixhorne | 1811 | // Serialize Lunatic gamevars. When loading, the restoration code must |
1812 | // be present before Lua state creation in svgm_script, so save it |
||
1813 | // right before, too. |
||
3796 | helixhorne | 1814 | int32_t slen, slen_ext; |
4119 | helixhorne | 1815 | const char *svcode = El_SerializeGamevars(&slen, -1); |
3796 | helixhorne | 1816 | |
1817 | if (slen < 0) |
||
1818 | { |
||
1819 | // Serialization failed. |
||
1820 | g_savedOK = 0; |
||
1821 | g_failedVarname = svcode; |
||
1822 | return mem; |
||
1823 | } |
||
1824 | |||
1825 | fwrite("\0\1LunaGVAR\3\4", 12, 1, fil); |
||
1826 | slen_ext = B_LITTLE32(slen); |
||
1827 | fwrite(&slen_ext, sizeof(slen_ext), 1, fil); |
||
3891 | helixhorne | 1828 | dfwrite(svcode, 1, slen, fil); // cnt and sz swapped |
3796 | helixhorne | 1829 | |
1830 | g_savedOK = 1; |
||
1831 | } |
||
3789 | helixhorne | 1832 | #endif |
3891 | helixhorne | 1833 | mem=writespecdata(svgm_script, fil, mem); // script |
1834 | PRINTSIZE("script"); |
||
1835 | mem=writespecdata(svgm_anmisc, fil, mem); // animates, quotes & misc. |
||
1836 | PRINTSIZE("animisc"); |
||
1595 | helixhorne | 1837 | |
3891 | helixhorne | 1838 | #if !defined LUNATIC |
1839 | Gv_WriteSave(fil, 1); // gamevars |
||
1840 | mem=writespecdata(svgm_vars, 0, mem); |
||
1841 | PRINTSIZE("vars"); |
||
1842 | #endif |
||
1843 | |||
1595 | helixhorne | 1844 | return mem; |
1845 | } |
||
1846 | |||
3891 | helixhorne | 1847 | #ifdef LUNATIC |
1848 | char *g_elSavecode = NULL; |
||
1595 | helixhorne | 1849 | |
3891 | helixhorne | 1850 | static int32_t El_ReadSaveCode(int32_t fil) |
1851 | { |
||
1852 | // Read Lua code to restore gamevar values from the savegame. |
||
1853 | // It will be run from Lua with its state creation later on. |
||
1854 | |||
1855 | char header[12]; |
||
1856 | int32_t slen; |
||
1857 | |||
1858 | if (kread(fil, header, 12) != 12) |
||
1859 | { |
||
1860 | OSD_Printf("doloadplayer2: failed reading Lunatic gamevar header.\n"); |
||
1861 | return -100; |
||
1862 | } |
||
1863 | |||
1864 | if (Bmemcmp(header, "\0\1LunaGVAR\3\4", 12)) |
||
1865 | { |
||
1866 | OSD_Printf("doloadplayer2: Lunatic gamevar header doesn't match.\n"); |
||
1867 | return -101; |
||
1868 | } |
||
1869 | |||
1870 | if (kread(fil, &slen, sizeof(slen)) != sizeof(slen)) |
||
1871 | { |
||
1872 | OSD_Printf("doloadplayer2: failed reading Lunatic gamevar string size.\n"); |
||
1873 | return -102; |
||
1874 | } |
||
1875 | |||
1876 | slen = B_LITTLE32(slen); |
||
1877 | if (slen < 0) |
||
1878 | { |
||
1879 | OSD_Printf("doloadplayer2: invalid Lunatic gamevar string size %d.\n", slen); |
||
1880 | return -103; |
||
1881 | } |
||
1882 | |||
1883 | if (slen > 0) |
||
1884 | { |
||
4491 | helixhorne | 1885 | char *svcode = (char *)Xmalloc(slen+1); |
3891 | helixhorne | 1886 | |
1887 | if (kdfread(svcode, 1, slen, fil) != slen) // cnt and sz swapped |
||
1888 | { |
||
1889 | OSD_Printf("doloadplayer2: failed reading Lunatic gamevar restoration code.\n"); |
||
1890 | Bfree(svcode); |
||
1891 | return -104; |
||
1892 | } |
||
1893 | |||
1894 | svcode[slen] = 0; |
||
1895 | g_elSavecode = svcode; |
||
1896 | } |
||
1897 | |||
1898 | return 0; |
||
1899 | } |
||
1900 | |||
1901 | void El_FreeSaveCode(void) |
||
1902 | { |
||
1903 | // Free Lunatic gamevar savegame restoration Lua code. |
||
1904 | Bfree(g_elSavecode); |
||
1905 | g_elSavecode = NULL; |
||
1906 | } |
||
1907 | #endif |
||
1908 | |||
2207 | helixhorne | 1909 | static int32_t doloadplayer2(int32_t fil, uint8_t **memptr) |
1595 | helixhorne | 1910 | { |
2218 | helixhorne | 1911 | uint8_t *mem = memptr ? *memptr : NULL; |
1912 | #ifdef DEBUGGINGAIDS |
||
1913 | uint8_t *tmem=mem; |
||
1914 | int32_t t=getticks(); |
||
1915 | #endif |
||
2207 | helixhorne | 1916 | if (readspecdata(svgm_udnetw, fil, &mem)) return -2; |
2200 | helixhorne | 1917 | PRINTSIZE("ud"); |
1595 | helixhorne | 1918 | if (readspecdata(svgm_secwsp, fil, &mem)) return -4; |
2200 | helixhorne | 1919 | PRINTSIZE("sws"); |
3891 | helixhorne | 1920 | #ifdef LUNATIC |
1921 | { |
||
1922 | int32_t ret = El_ReadSaveCode(fil); |
||
1923 | if (ret < 0) |
||
1924 | return ret; |
||
1925 | } |
||
1926 | #endif |
||
1595 | helixhorne | 1927 | if (readspecdata(svgm_script, fil, &mem)) return -5; |
2200 | helixhorne | 1928 | PRINTSIZE("script"); |
1595 | helixhorne | 1929 | if (readspecdata(svgm_anmisc, fil, &mem)) return -6; |
2200 | helixhorne | 1930 | PRINTSIZE("animisc"); |
1595 | helixhorne | 1931 | |
3789 | helixhorne | 1932 | #if !defined LUNATIC |
1595 | helixhorne | 1933 | if (Gv_ReadSave(fil, 1)) return -7; |
1934 | |||
2190 | helixhorne | 1935 | if (mem) |
2200 | helixhorne | 1936 | { |
2207 | helixhorne | 1937 | int32_t i; |
1938 | |||
2200 | helixhorne | 1939 | sv_makevarspec(); |
2190 | helixhorne | 1940 | for (i=1; svgm_vars[i].flags!=DS_END; i++) |
1941 | { |
||
1942 | Bmemcpy(mem, svgm_vars[i].ptr, svgm_vars[i].size*svgm_vars[i].cnt); // careful! works because there are no DS_DYNAMIC's! |
||
1943 | mem += svgm_vars[i].size*svgm_vars[i].cnt; |
||
1944 | } |
||
2200 | helixhorne | 1945 | } |
2218 | helixhorne | 1946 | PRINTSIZE("vars"); |
3789 | helixhorne | 1947 | #endif |
1595 | helixhorne | 1948 | |
1949 | if (memptr) |
||
1950 | *memptr = mem; |
||
1951 | return 0; |
||
1952 | } |
||
1953 | |||
1954 | int32_t sv_updatestate(int32_t frominit) |
||
1955 | { |
||
1956 | uint8_t *p = svsnapshot, *pbeg=p; |
||
1957 | |||
1958 | if (frominit) |
||
1959 | Bmemcpy(svsnapshot, svinitsnap, svsnapsiz); |
||
1960 | |||
1961 | if (readspecdata(svgm_udnetw, -1, &p)) return -2; |
||
1962 | if (readspecdata(svgm_secwsp, -1, &p)) return -4; |
||
1963 | if (readspecdata(svgm_script, -1, &p)) return -5; |
||
1964 | if (readspecdata(svgm_anmisc, -1, &p)) return -6; |
||
1965 | |||
3789 | helixhorne | 1966 | #if !defined LUNATIC |
1595 | helixhorne | 1967 | if (readspecdata(svgm_vars, -1, &p)) return -8; |
3789 | helixhorne | 1968 | #endif |
1595 | helixhorne | 1969 | |
1970 | if (p != pbeg+svsnapsiz) |
||
2200 | helixhorne | 1971 | { |
1595 | helixhorne | 1972 | OSD_Printf("sv_updatestate: ptr-(snapshot end)=%d\n", (int32_t)(p-(pbeg+svsnapsiz))); |
2200 | helixhorne | 1973 | return -9; |
1974 | } |
||
1595 | helixhorne | 1975 | |
1976 | if (frominit) |
||
2207 | helixhorne | 1977 | postloadplayer(0); |
1978 | #ifdef POLYMER |
||
3346 | terminx | 1979 | if (getrendermode() == REND_POLYMER) |
2207 | helixhorne | 1980 | polymer_resetlights(); // must do it after polymer_loadboard() !!! |
1981 | #endif |
||
1595 | helixhorne | 1982 | |
1983 | return 0; |
||
1984 | } |
||
1985 | |||
2207 | helixhorne | 1986 | static void postloadplayer(int32_t savegamep) |
1595 | helixhorne | 1987 | { |
1988 | int32_t i; |
||
2207 | helixhorne | 1989 | |
1595 | helixhorne | 1990 | //1 |
1991 | if (g_player[myconnectindex].ps->over_shoulder_on != 0) |
||
1992 | { |
||
3405 | helixhorne | 1993 | CAMERADIST = 0; |
1994 | CAMERACLOCK = 0; |
||
1595 | helixhorne | 1995 | g_player[myconnectindex].ps->over_shoulder_on = 1; |
1996 | } |
||
1997 | |||
2207 | helixhorne | 1998 | //2 |
1595 | helixhorne | 1999 | screenpeek = myconnectindex; |
2207 | helixhorne | 2000 | |
2001 | //2.5 |
||
2002 | if (savegamep) |
||
2003 | { |
||
4589 | helixhorne | 2004 | int32_t musicIdx = (ud.volume_number*MAXLEVELS) + ud.level_number; |
2005 | |||
2207 | helixhorne | 2006 | Bmemset(gotpic, 0, sizeof(gotpic)); |
2007 | S_ClearSoundLocks(); |
||
2008 | G_CacheMapData(); |
||
2009 | |||
2010 | if (boardfilename[0] != 0 && ud.level_number == 7 && ud.volume_number == 0) |
||
2011 | { |
||
4589 | helixhorne | 2012 | const uint32_t BSZ = sizeof(boardfilename); |
2207 | helixhorne | 2013 | char levname[BMAX_PATH]; |
2014 | |||
2015 | G_SetupFilenameBasedMusic(levname, boardfilename, ud.level_number); |
||
4589 | helixhorne | 2016 | |
2017 | // Potentially extract the custom music volume/level from |
||
2018 | // boardfilename[] stored with SAVEGAME_MUSIC. |
||
2019 | if (Bstrlen(boardfilename) < BSZ-2) |
||
2020 | { |
||
2021 | int32_t mi = MAXLEVELS*boardfilename[BSZ-2] + boardfilename[BSZ-1]; |
||
2022 | |||
2023 | if (mi != 0 && (unsigned)mi < MUS_FIRST_SPECIAL) |
||
2024 | musicIdx = mi; |
||
2025 | } |
||
2207 | helixhorne | 2026 | } |
2027 | |||
2028 | if (ud.config.MusicToggle) |
||
2029 | { |
||
4589 | helixhorne | 2030 | if (MapInfo[musicIdx].musicfn != NULL && |
2031 | (musicIdx != g_musicIndex /* || MapInfo[MUS_LOADING].musicfn */)) |
||
2207 | helixhorne | 2032 | { |
2033 | S_StopMusic(); |
||
4589 | helixhorne | 2034 | |
2035 | g_musicIndex = musicIdx; |
||
4948 | hendricks2 | 2036 | S_PlayMusic(MapInfo[g_musicIndex].musicfn); |
2207 | helixhorne | 2037 | } |
2038 | |||
2039 | S_PauseMusic(0); |
||
2040 | } |
||
2041 | |||
2042 | g_player[myconnectindex].ps->gm = MODE_GAME; |
||
2043 | ud.recstat = 0; |
||
2044 | |||
2045 | if (g_player[myconnectindex].ps->jetpack_on) |
||
2046 | A_PlaySound(DUKE_JETPACK_IDLE, g_player[myconnectindex].ps->i); |
||
2047 | } |
||
2048 | |||
1595 | helixhorne | 2049 | //3 |
2050 | P_UpdateScreenPal(g_player[myconnectindex].ps); |
||
2306 | helixhorne | 2051 | g_restorePalette = -1; |
2207 | helixhorne | 2052 | |
2053 | //3.5 |
||
2054 | if (savegamep) |
||
1595 | helixhorne | 2055 | { |
3156 | helixhorne | 2056 | for (SPRITES_OF(STAT_FX, i)) |
3083 | terminx | 2057 | if (sprite[i].picnum == MUSICANDSFX) |
2058 | { |
||
2059 | T2 = ud.config.SoundToggle; |
||
2060 | T1 = 0; |
||
2061 | } |
||
2062 | |||
2207 | helixhorne | 2063 | G_UpdateScreenArea(); |
2064 | FX_SetReverb(0); |
||
1595 | helixhorne | 2065 | } |
2207 | helixhorne | 2066 | |
2067 | //4 |
||
2068 | if (savegamep) |
||
1595 | helixhorne | 2069 | { |
2235 | helixhorne | 2070 | if (ud.lockout) |
2207 | helixhorne | 2071 | { |
2072 | for (i=0; i<g_numAnimWalls; i++) |
||
2297 | helixhorne | 2073 | switch (DYNAMICTILEMAP(wall[animwall[i].wallnum].picnum)) |
2207 | helixhorne | 2074 | { |
2075 | case FEMPIC1__STATIC: |
||
2076 | wall[animwall[i].wallnum].picnum = BLANKSCREEN; |
||
2077 | break; |
||
2078 | case FEMPIC2__STATIC: |
||
2079 | case FEMPIC3__STATIC: |
||
2080 | wall[animwall[i].wallnum].picnum = SCREENBREAK6; |
||
2081 | break; |
||
2082 | } |
||
2083 | } |
||
2235 | helixhorne | 2084 | #if 0 |
2085 | else |
||
2086 | { |
||
2087 | for (i=0; i<g_numAnimWalls; i++) |
||
2088 | if (wall[animwall[i].wallnum].extra >= 0) |
||
2089 | wall[animwall[i].wallnum].picnum = wall[animwall[i].wallnum].extra; |
||
2090 | } |
||
2091 | #endif |
||
1595 | helixhorne | 2092 | } |
2093 | |||
2094 | //5 |
||
1949 | helixhorne | 2095 | G_ResetInterpolations(); |
1595 | helixhorne | 2096 | |
2097 | //6 |
||
2098 | g_showShareware = 0; |
||
2207 | helixhorne | 2099 | if (savegamep) |
2100 | everyothertime = 0; |
||
2190 | helixhorne | 2101 | |
2207 | helixhorne | 2102 | //7 |
1595 | helixhorne | 2103 | for (i=0; i<MAXPLAYERS; i++) |
2190 | helixhorne | 2104 | g_player[i].playerquitflag = 1; |
1595 | helixhorne | 2105 | |
2207 | helixhorne | 2106 | // ---------- |
2107 | |||
2108 | //7.5 |
||
2109 | if (savegamep) |
||
2110 | { |
||
2111 | ready2send = 1; |
||
2112 | G_ClearFIFO(); |
||
2113 | Net_WaitForServer(); |
||
2114 | } |
||
2115 | |||
2116 | //8 |
||
2117 | // if (savegamep) ? |
||
3929 | helixhorne | 2118 | #ifdef LUNATIC |
2119 | G_ResetTimers(1); |
||
2120 | #else |
||
2121 | G_ResetTimers(0); |
||
2122 | #endif |
||
1595 | helixhorne | 2123 | |
2124 | #ifdef POLYMER |
||
2207 | helixhorne | 2125 | //9 |
3346 | terminx | 2126 | if (getrendermode() == REND_POLYMER) |
1596 | plagman | 2127 | polymer_loadboard(); |
1595 | helixhorne | 2128 | #elif 0 |
3346 | terminx | 2129 | if (getrendermode() == REND_POLYMER) |
1595 | helixhorne | 2130 | { |
2131 | int32_t i = 0; |
||
2132 | |||
2133 | polymer_loadboard(); |
||
2134 | while (i < MAXSPRITES) |
||
2135 | { |
||
1625 | terminx | 2136 | if (actor[i].lightptr) |
1595 | helixhorne | 2137 | { |
1625 | terminx | 2138 | polymer_deletelight(actor[i].lightId); |
2139 | actor[i].lightptr = NULL; |
||
2140 | actor[i].lightId = -1; |
||
1595 | helixhorne | 2141 | } |
2142 | i++; |
||
2143 | } |
||
2144 | } |
||
2145 | #endif |
||
2207 | helixhorne | 2146 | // this light pointer nulling needs to be outside the getrendermode check |
2147 | // because we might be loading the savegame using another renderer but |
||
2148 | // change to Polymer later |
||
2149 | for (i=0; i<MAXSPRITES; i++) |
||
2150 | { |
||
2151 | actor[i].lightptr = NULL; |
||
2152 | actor[i].lightId = -1; |
||
2153 | } |
||
1595 | helixhorne | 2154 | } |
2155 | |||
2156 | ////////// END GENERIC SAVING/LOADING SYSTEM ////////// |
||
4990 | terminx | 2157 | |
2158 | #ifdef __ANDROID__ |
||
2159 | #include <jni.h> |
||
2160 | #include <android/log.h> |
||
2161 | |||
2162 | #ifndef LOGI |
||
2163 | #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO,"DUKE", __VA_ARGS__)) |
||
2164 | #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "DUKE", __VA_ARGS__)) |
||
2165 | #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR,"DUKE", __VA_ARGS__)) |
||
2166 | #endif |
||
2167 | |||
2168 | char const * G_GetStringFromSavegame(const char *filename, int type) |
||
2169 | { |
||
2170 | LOGI("getSavegameText %s", filename); |
||
2171 | int32_t fil = kopen4load(filename, 0); |
||
2172 | |||
2173 | if (fil == -1) |
||
2174 | { |
||
2175 | LOGE("couldn't load %s", filename); |
||
2176 | return ""; |
||
2177 | } |
||
2178 | |||
2179 | savehead_t saveh; |
||
2180 | |||
2181 | int32_t i = sv_loadheader(fil, 0, &saveh); |
||
2182 | |||
2183 | if (i && (i != 2 && i != 3)) |
||
2184 | goto corrupt; |
||
2185 | |||
2186 | kclose(fil); |
||
2187 | |||
2188 | static char tempbuf[64]; |
||
2189 | |||
2190 | switch (type) |
||
2191 | { |
||
2192 | case 0: Bstrncpyz(tempbuf, saveh.savename, sizeof(saveh.savename) - 1); break; |
||
2193 | case 1: Bstrncpyz(tempbuf, saveh.volname, sizeof(saveh.volname) - 1); break; |
||
2194 | case 2: Bstrncpyz(tempbuf, saveh.skillname, sizeof(saveh.skillname) - 1); break; |
||
2195 | } |
||
2196 | return tempbuf; |
||
2197 | |||
2198 | corrupt: |
||
2199 | kclose(fil); |
||
2200 | LOGE("couldn't load %s", filename); |
||
2201 | return ""; |
||
2202 | } |
||
2203 | |||
2204 | int32_t G_GetScreenshotFromSavegame(const char *filename, char *pal, char *data) |
||
2205 | { |
||
2206 | LOGI("getSavegameScreenshot %s", filename); |
||
2207 | |||
2208 | int32_t fil = kopen4load(filename, 0); |
||
2209 | |||
2210 | if (fil == -1) |
||
2211 | return -1; |
||
2212 | |||
2213 | savehead_t saveh; |
||
2214 | |||
2215 | int32_t i = sv_loadheader(fil, 0, &saveh); |
||
2216 | |||
2217 | if (i && (i != 2 && i != 3)) |
||
2218 | goto corrupt; |
||
2219 | |||
2220 | int32_t screenshotofs; |
||
2221 | |||
2222 | if (kread(fil, &screenshotofs, 4) != 4) |
||
2223 | goto corrupt; |
||
2224 | |||
2225 | if (screenshotofs) |
||
2226 | { |
||
2227 | if (kdfread(data, 320, 200, fil) != 200) |
||
2228 | { |
||
2229 | // OSD_Printf("G_LoadSaveHeaderNew(%d): failed reading screenshot\n", spot); |
||
2230 | goto corrupt; |
||
2231 | } |
||
2232 | } |
||
2233 | else |
||
2234 | { |
||
2235 | kclose(fil); |
||
2236 | return -1; |
||
2237 | } |
||
2238 | |||
2239 | kclose(fil); |
||
2240 | |||
2241 | char pstr[BMAX_PATH]; |
||
2242 | |||
2243 | Bstrcpy(pstr, filename); |
||
2244 | Bcorrectfilename(pstr, 1); |
||
2245 | Bstrcat(pstr, "palette.dat"); |
||
2246 | |||
2247 | int32_t pfil; |
||
2248 | |||
2249 | if ((pfil = kopen4load(pstr, 0)) == -1) |
||
2250 | { |
||
2251 | LOGE("couldn't load %s", pstr); |
||
2252 | return -1; |
||
2253 | } |
||
2254 | |||
2255 | kread(pfil, pal, 768); |
||
2256 | kclose(pfil); |
||
2257 | |||
2258 | return 0; |
||
2259 | |||
2260 | corrupt: |
||
2261 | kclose(fil); |
||
2262 | return 1; |
||
2263 | } |
||
2264 | #endif |