DEADSOFTWARE

portability: avoid errors on some compilers
[flatwaifu.git] / src / save.c
1 /* Copyright (C) 1996-1997 Aleksey Volynskov
2 * Copyright (C) 2011 Rambo
3 * Copyright (C) 2020 SovietPony
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
18 #include "save.h"
20 #include "dots.h"
21 #include "fx.h"
22 #include "game.h"
23 #include "items.h"
24 #include "monster.h"
25 #include "player.h"
26 #include "smoke.h"
27 #include "switch.h"
28 #include "view.h"
29 #include "weapons.h"
31 #include "render.h"
32 #include "music.h"
33 #include <string.h>
34 #include <assert.h>
36 #include "common/streams.h"
37 #include "common/files.h"
39 static void DOT_savegame (Stream *h) {
40 int i, n;
41 for (i = n = 0; i < MAXDOT; ++i) {
42 if (dot[i].t) {
43 ++n;
44 }
45 }
46 stream_write32(n, h);
47 for (i = 0; i < MAXDOT; ++i) {
48 if (dot[i].t) {
49 stream_write32(dot[i].o.x, h);
50 stream_write32(dot[i].o.y, h);
51 stream_write32(dot[i].o.xv, h);
52 stream_write32(dot[i].o.yv, h);
53 stream_write32(dot[i].o.vx, h);
54 stream_write32(dot[i].o.vy, h);
55 stream_write32(dot[i].o.r, h);
56 stream_write32(dot[i].o.h, h);
57 stream_write8(dot[i].c, h);
58 stream_write8(dot[i].t, h);
59 }
60 }
61 }
63 static void DOT_loadgame (Stream *h) {
64 int i, n;
65 n = stream_read32(h);
66 for (i = 0; i < n; i++) {
67 dot[i].o.x = stream_read32(h);
68 dot[i].o.y = stream_read32(h);
69 dot[i].o.xv = stream_read32(h);
70 dot[i].o.yv = stream_read32(h);
71 dot[i].o.vx = stream_read32(h);
72 dot[i].o.vy = stream_read32(h);
73 dot[i].o.r = stream_read32(h);
74 dot[i].o.h = stream_read32(h);
75 dot[i].c = stream_read8(h);
76 dot[i].t = stream_read8(h);
77 }
78 }
80 static void FX_savegame (Stream *h) {
81 int i, n;
82 for (i = n = 0; i < MAXFX; ++i) {
83 if (fx[i].t) {
84 ++n;
85 }
86 }
87 stream_write32(n, h);
88 for (i = 0; i < MAXFX; ++i) {
89 if (fx[i].t) {
90 stream_write32(fx[i].x, h);
91 stream_write32(fx[i].y, h);
92 stream_write32(fx[i].xv, h);
93 stream_write32(fx[i].yv, h);
94 stream_write8(fx[i].t, h);
95 stream_write8(fx[i].s, h);
96 }
97 }
98 }
100 static void FX_loadgame (Stream *h) {
101 int i, n;
102 n = stream_read32(h);
103 for (i = 0; i < n; i++) {
104 fx[i].x = stream_read32(h);
105 fx[i].y = stream_read32(h);
106 fx[i].xv = stream_read32(h);
107 fx[i].yv = stream_read32(h);
108 fx[i].t = stream_read8(h);
109 fx[i].s = stream_read8(h);
113 static void G_savegame (Stream *h) {
114 int i = 0;
115 stream_write8(_2pl, h);
116 stream_write8(g_dm, h);
117 stream_write8(g_exit, h);
118 stream_write8(g_map, h);
119 stream_write32(g_time, h);
120 stream_write32(dm_pl1p, h);
121 stream_write32(dm_pl2p, h);
122 stream_write32(dm_pnum, h);
123 while (i < dm_pnum) {
124 stream_write32(dm_pos[i].x, h);
125 stream_write32(dm_pos[i].y, h);
126 stream_write8(dm_pos[i].d, h);
127 i += 1;
129 stream_write8(cheat, h);
130 stream_write(g_music, 8, 1, h);
133 static void G_loadgame (Stream *h) {
134 int i = 0;
135 _2pl = stream_read8(h);
136 g_dm = stream_read8(h);
137 g_exit = stream_read8(h);
138 g_map = stream_read8(h);
139 g_time = stream_read32(h);
140 dm_pl1p = stream_read32(h);
141 dm_pl2p = stream_read32(h);
142 dm_pnum = stream_read32(h);
143 while (i < dm_pnum) {
144 dm_pos[i].x = stream_read32(h);
145 dm_pos[i].y = stream_read32(h);
146 dm_pos[i].d = stream_read8(h);
147 i += 1;
149 cheat = stream_read8(h);
150 stream_read(g_music, 8, 1, h);
151 MUS_load(g_music);
154 static void IT_savegame (Stream *h) {
155 int i, n;
156 for (n = MAXITEM - 1; n >= 0 && it[n].t == 0; n--) {
157 // empty
159 n += 1;
160 stream_write32(n, h);
161 for (i = 0; i < n; i++) {
162 stream_write32(it[i].o.x, h);
163 stream_write32(it[i].o.y, h);
164 stream_write32(it[i].o.xv, h);
165 stream_write32(it[i].o.yv, h);
166 stream_write32(it[i].o.vx, h);
167 stream_write32(it[i].o.vy, h);
168 stream_write32(it[i].o.r, h);
169 stream_write32(it[i].o.h, h);
170 stream_write32(it[i].t, h);
171 stream_write32(it[i].s, h);
173 stream_write32(itm_rtime, h);
176 static void IT_loadgame (Stream *h) {
177 int i, n;
178 n = stream_read32(h);
179 for (i = 0; i < n; i++) {
180 it[i].o.x = stream_read32(h);
181 it[i].o.y = stream_read32(h);
182 it[i].o.xv = stream_read32(h);
183 it[i].o.yv = stream_read32(h);
184 it[i].o.vx = stream_read32(h);
185 it[i].o.vy = stream_read32(h);
186 it[i].o.r = stream_read32(h);
187 it[i].o.h = stream_read32(h);
188 it[i].t = stream_read32(h);
189 it[i].s = stream_read32(h);
191 itm_rtime = stream_read32(h);
194 static void MN_savegame (Stream *h) {
195 int i, n;
196 for (n = MAXMN - 1; n >= 0 && mn[n].t == 0; n--) {
197 // empty
199 n += 1;
200 stream_write32(n, h);
201 for (i = 0; i < n; i++) {
202 stream_write32(mn[i].o.x, h);
203 stream_write32(mn[i].o.y, h);
204 stream_write32(mn[i].o.xv, h);
205 stream_write32(mn[i].o.yv, h);
206 stream_write32(mn[i].o.vx, h);
207 stream_write32(mn[i].o.vy, h);
208 stream_write32(mn[i].o.r, h);
209 stream_write32(mn[i].o.h, h);
210 stream_write8(mn[i].t, h);
211 stream_write8(mn[i].d, h);
212 stream_write8(mn[i].st, h);
213 stream_write8(mn[i].ftime, h);
214 stream_write32(mn[i].fobj, h);
215 stream_write32(mn[i].s, h);
216 stream_write32(0, h); // mn[i].ap useless, changed after load
217 stream_write32(mn[i].aim, h);
218 stream_write32(mn[i].life, h);
219 stream_write32(mn[i].pain, h);
220 stream_write32(mn[i].ac, h);
221 stream_write32(mn[i].tx, h);
222 stream_write32(mn[i].ty, h);
223 stream_write32(mn[i].ammo, h);
224 stream_write16(mn[i].atm, h);
226 stream_write32(mnum, h);
227 stream_write32(gsndt, h);
230 static void MN_loadgame (Stream *h) {
231 int i, n, c;
232 n = stream_read32(h);
233 for (i = 0; i < n; i++) {
234 mn[i].o.x = stream_read32(h);
235 mn[i].o.y = stream_read32(h);
236 mn[i].o.xv = stream_read32(h);
237 mn[i].o.yv = stream_read32(h);
238 mn[i].o.vx = stream_read32(h);
239 mn[i].o.vy = stream_read32(h);
240 mn[i].o.r = stream_read32(h);
241 mn[i].o.h = stream_read32(h);
242 mn[i].t = stream_read8(h);
243 mn[i].d = stream_read8(h);
244 mn[i].st = stream_read8(h);
245 mn[i].ftime = stream_read8(h);
246 mn[i].fobj = stream_read32(h);
247 mn[i].s = stream_read32(h);
248 mn[i].ap = NULL; stream_read32(h); // useless, changed after loading
249 mn[i].aim = stream_read32(h);
250 mn[i].life = stream_read32(h);
251 mn[i].pain = stream_read32(h);
252 mn[i].ac = stream_read32(h);
253 mn[i].tx = stream_read32(h);
254 mn[i].ty = stream_read32(h);
255 mn[i].ammo = stream_read32(h);
256 mn[i].atm = stream_read16(h);
258 mnum = stream_read32(h);
259 gsndt = stream_read32(h);
260 for (n = 0; n < MAXMN; n++) {
261 if (mn[n].t) {
262 c = mn[n].ac;
263 setst(n, mn[n].st);
264 mn[n].ac = c;
269 static void PL_save_player (player_t *p, Stream *h) {
270 stream_write32(p->o.x, h);
271 stream_write32(p->o.y, h);
272 stream_write32(p->o.xv, h);
273 stream_write32(p->o.yv, h);
274 stream_write32(p->o.vx, h);
275 stream_write32(p->o.vy, h);
276 stream_write32(p->o.r, h);
277 stream_write32(p->o.h, h);
278 stream_write32(p->looky, h);
279 stream_write32(p->st, h);
280 stream_write32(p->s, h);
281 stream_write32(p->life, h);
282 stream_write32(p->armor, h);
283 stream_write32(p->hit, h);
284 stream_write32(p->hito, h);
285 stream_write32(p->pain, h);
286 stream_write32(p->air, h);
287 stream_write32(p->invl, h);
288 stream_write32(p->suit, h);
289 stream_write8(p->d, h);
290 stream_write32(p->frag, h);
291 stream_write32(p->ammo, h);
292 stream_write32(p->shel, h);
293 stream_write32(p->rock, h);
294 stream_write32(p->cell, h);
295 stream_write32(p->fuel, h);
296 stream_write32(p->kills, h);
297 stream_write32(p->secrets, h);
298 stream_write8(p->fire, h);
299 stream_write8(p->cwpn, h);
300 stream_write8(p->csnd, h);
301 stream_write8(p->amul, h);
302 stream_write16(p->wpns, h);
303 stream_write8(p->wpn, h);
304 stream_write8(p->f, h);
305 stream_write8(p->drawst, h);
306 stream_write8(p->color, h);
307 stream_write32(p->id, h);
308 stream_write8(p->keys, h);
309 stream_write8(p->lives, h);
310 // k* not saved
313 static void PL_savegame (Stream *h) {
314 PL_save_player(&pl1, h);
315 if (_2pl) {
316 PL_save_player(&pl2, h);
318 stream_write32(PL_JUMP, h);
319 stream_write32(PL_RUN, h);
320 stream_write8(p_immortal, h);
323 static void PL_load_player (player_t *p, Stream *h) {
324 p->o.x = stream_read32(h);
325 p->o.y = stream_read32(h);
326 p->o.xv = stream_read32(h);
327 p->o.yv = stream_read32(h);
328 p->o.vx = stream_read32(h);
329 p->o.vy = stream_read32(h);
330 p->o.r = stream_read32(h);
331 p->o.h = stream_read32(h);
332 p->looky = stream_read32(h);
333 p->st = stream_read32(h);
334 p->s = stream_read32(h);
335 p->life = stream_read32(h);
336 p->armor = stream_read32(h);
337 p->hit = stream_read32(h);
338 p->hito = stream_read32(h);
339 p->pain = stream_read32(h);
340 p->air = stream_read32(h);
341 p->invl = stream_read32(h);
342 p->suit = stream_read32(h);
343 p->d = stream_read8(h);
344 p->frag = stream_read32(h);
345 p->ammo = stream_read32(h);
346 p->shel = stream_read32(h);
347 p->rock = stream_read32(h);
348 p->cell = stream_read32(h);
349 p->fuel = stream_read32(h);
350 p->kills = stream_read32(h);
351 p->secrets = stream_read32(h);
352 p->fire = stream_read8(h);
353 p->cwpn = stream_read8(h);
354 p->csnd = stream_read8(h);
355 p->amul = stream_read8(h);
356 p->wpns = stream_read16(h);
357 p->wpn = stream_read8(h);
358 p->f = stream_read8(h);
359 p->drawst = stream_read8(h);
360 p->color = stream_read8(h);
361 p->id = stream_read32(h);
362 p->keys = stream_read8(h);
363 p->lives = stream_read8(h);
364 // k* not saved
367 static void PL_loadgame (Stream *h) {
368 PL_load_player(&pl1, h);
369 if (_2pl) {
370 PL_load_player(&pl2, h);
372 PL_JUMP = stream_read32(h);
373 PL_RUN = stream_read32(h);
374 p_immortal = stream_read8(h);
377 static void SMK_savegame (Stream *h) {
378 int i, n;
379 for (i = n = 0; i < MAXSMOK; ++i) {
380 if (sm[i].t) {
381 ++n;
384 stream_write32(n, h);
385 for (i = 0; i < MAXSMOK; ++i) {
386 if (sm[i].t) {
387 stream_write32(sm[i].x, h);
388 stream_write32(sm[i].y, h);
389 stream_write32(sm[i].xv, h);
390 stream_write32(sm[i].xv, h);
391 stream_write8(sm[i].t, h);
392 stream_write8(sm[i].s, h);
393 stream_write16(sm[i].o, h);
398 static void SMK_loadgame (Stream *h) {
399 int i, n;
400 n = stream_read32(h);
401 for (i = 0; i < n; ++i) {
402 sm[i].x = stream_read32(h);
403 sm[i].y = stream_read32(h);
404 sm[i].xv = stream_read32(h);
405 sm[i].xv = stream_read32(h);
406 sm[i].t = stream_read8(h);
407 sm[i].s = stream_read8(h);
408 sm[i].o = stream_read16(h);
412 static void SW_savegame (Stream *h) {
413 int i, n;
414 for (n = MAXSW - 1; n >= 0 && sw[n].t == 0; n--) {
415 // empty
417 n += 1;
418 stream_write32(n, h);
419 for (i = 0; i < n; i++) {
420 stream_write8(sw[i].x, h);
421 stream_write8(sw[i].y, h);
422 stream_write8(sw[i].t, h);
423 stream_write8(sw[i].tm, h);
424 stream_write8(sw[i].a, h);
425 stream_write8(sw[i].b, h);
426 stream_write8(sw[i].c, h);
427 stream_write8(sw[i].d, h);
428 stream_write8(sw[i].f, h);
430 stream_write32(sw_secrets, h);
433 static void SW_loadgame (Stream *h) {
434 int i, n;
435 n = stream_read32(h);
436 for (i = 0; i < n; i++) {
437 sw[i].x = stream_read8(h);
438 sw[i].y = stream_read8(h);
439 sw[i].t = stream_read8(h);
440 sw[i].tm = stream_read8(h);
441 sw[i].a = stream_read8(h);
442 sw[i].b = stream_read8(h);
443 sw[i].c = stream_read8(h);
444 sw[i].d = stream_read8(h);
445 sw[i].f = stream_read8(h);
447 sw_secrets = stream_read32(h);
450 static void W_savegame (Stream* h) {
451 char s[8];
452 int i;
453 stream_write32(sky_type, h);
454 for(i = 1; i < 256; ++i) {
455 R_get_name(i, s);
456 stream_write(s, 8, 1, h);
458 for (i = 0; i < 256; i++) {
459 stream_write32(walf[i], h);
461 for (i = 0; i < 256; i++) {
462 stream_write8(R_get_swp(i), h);
464 stream_write(fldb, FLDW*FLDH, 1, h);
465 stream_write(fld, FLDW*FLDH, 1, h);
466 stream_write(fldf, FLDW*FLDH, 1, h);
469 static void W_loadgame (Stream *h) {
470 int i;
471 char s[8];
472 sky_type = stream_read32(h);
473 R_loadsky(sky_type);
474 R_begin_load();
475 for (i = 1; i < 256; ++i) {
476 stream_read(s, 8, 1, h);
477 if (s[0]) {
478 R_load(s);
481 R_end_load();
482 for (i = 0; i < 256; i++) {
483 stream_read32(h); // useless
485 for (i = 0; i < 256; i++) {
486 walf[i] = stream_read8(h);
488 stream_read(fldb, FLDW*FLDH, 1, h);
489 stream_read(fld, FLDW*FLDH, 1, h);
490 stream_read(fldf, FLDW*FLDH, 1, h);
493 static void WP_savegame (Stream *h) {
494 int i, n;
495 for (n = MAXWPN - 1; n >= 0 && wp[n].t == 0; n--) {
496 // empty
498 n += 1;
499 stream_write32(n, h);
500 for (i = 0; i < n; i++) {
501 stream_write32(wp[i].o.x, h);
502 stream_write32(wp[i].o.y, h);
503 stream_write32(wp[i].o.xv, h);
504 stream_write32(wp[i].o.yv, h);
505 stream_write32(wp[i].o.vx, h);
506 stream_write32(wp[i].o.vy, h);
507 stream_write32(wp[i].o.r, h);
508 stream_write32(wp[i].o.h, h);
509 stream_write8(wp[i].t, h);
510 stream_write8(wp[i].s, h);
511 stream_write32(wp[i].own, h);
512 stream_write16(wp[i].target, h);
516 static void WP_loadgame (Stream *h) {
517 int i, n;
518 n = stream_read32(h);
519 for (i = 0; i < n; i++) {
520 wp[i].o.x = stream_read32(h);
521 wp[i].o.y = stream_read32(h);
522 wp[i].o.xv = stream_read32(h);
523 wp[i].o.yv = stream_read32(h);
524 wp[i].o.vx = stream_read32(h);
525 wp[i].o.vy = stream_read32(h);
526 wp[i].o.r = stream_read32(h);
527 wp[i].o.h = stream_read32(h);
528 wp[i].t = stream_read8(h);
529 wp[i].s = stream_read8(h);
530 wp[i].own = stream_read32(h);
531 wp[i].target = stream_read16(h);
535 void SAVE_save (Stream *w, const char name[24]) {
536 assert(w != NULL);
537 stream_write(name, 24, 1, w); // slot name
538 stream_write16(3, w); // version
539 G_savegame(w);
540 W_savegame(w);
541 DOT_savegame(w);
542 SMK_savegame(w);
543 FX_savegame(w);
544 IT_savegame(w);
545 MN_savegame(w);
546 PL_savegame(w);
547 SW_savegame(w);
548 WP_savegame(w);
551 void SAVE_load (Stream *h) {
552 int16_t version;
553 stream_setpos(h, 24); // skip name
554 version = stream_read16(h);
555 if (version == 3) {
556 G_loadgame(h);
557 W_loadgame(h);
558 DOT_loadgame(h);
559 SMK_loadgame(h);
560 FX_loadgame(h);
561 IT_loadgame(h);
562 MN_loadgame(h);
563 PL_loadgame(h);
564 SW_loadgame(h);
565 WP_loadgame(h);
569 int SAVE_getname (Stream *r, char name[24]) {
570 int16_t version;
571 stream_read(name, 24, 1, r);
572 version = stream_read16(r);
573 return version == 3;