DEADSOFTWARE

save: use streams for saves
[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"
34 #include <string.h>
35 #ifdef UNIX
36 # include <sys/stat.h>
37 #endif
38 #include <assert.h>
39 #include "files.h"
41 #include "common/streams.h"
42 #include "common/files.h"
44 char savname[SAVE_MAX][SAVE_MAXLEN];
45 char savok[SAVE_MAX];
47 static void DOT_savegame (Writer *h) {
48 int i, n;
49 for (i = n = 0; i < MAXDOT; ++i) {
50 if (dot[i].t) {
51 ++n;
52 }
53 }
54 stream_write32(n, h);
55 for (i = 0; i < MAXDOT; ++i) {
56 if (dot[i].t) {
57 stream_write32(dot[i].o.x, h);
58 stream_write32(dot[i].o.y, h);
59 stream_write32(dot[i].o.xv, h);
60 stream_write32(dot[i].o.yv, h);
61 stream_write32(dot[i].o.vx, h);
62 stream_write32(dot[i].o.vy, h);
63 stream_write32(dot[i].o.r, h);
64 stream_write32(dot[i].o.h, h);
65 stream_write8(dot[i].c, h);
66 stream_write8(dot[i].t, h);
67 }
68 }
69 }
71 static void DOT_loadgame (Reader *h) {
72 int i, n;
73 n = stream_read32(h);
74 for (i = 0; i < n; i++) {
75 dot[i].o.x = stream_read32(h);
76 dot[i].o.y = stream_read32(h);
77 dot[i].o.xv = stream_read32(h);
78 dot[i].o.yv = stream_read32(h);
79 dot[i].o.vx = stream_read32(h);
80 dot[i].o.vy = stream_read32(h);
81 dot[i].o.r = stream_read32(h);
82 dot[i].o.h = stream_read32(h);
83 dot[i].c = stream_read8(h);
84 dot[i].t = stream_read8(h);
85 }
86 }
88 static void FX_savegame (Writer *h) {
89 int i, n;
90 for (i = n = 0; i < MAXFX; ++i) {
91 if (fx[i].t) {
92 ++n;
93 }
94 }
95 stream_write32(n, h);
96 for (i = 0; i < MAXFX; ++i) {
97 if (fx[i].t) {
98 stream_write32(fx[i].x, h);
99 stream_write32(fx[i].y, h);
100 stream_write32(fx[i].xv, h);
101 stream_write32(fx[i].yv, h);
102 stream_write8(fx[i].t, h);
103 stream_write8(fx[i].s, h);
108 static void FX_loadgame (Reader *h) {
109 int i, n;
110 n = stream_read32(h);
111 for (i = 0; i < n; i++) {
112 fx[i].x = stream_read32(h);
113 fx[i].y = stream_read32(h);
114 fx[i].xv = stream_read32(h);
115 fx[i].yv = stream_read32(h);
116 fx[i].t = stream_read8(h);
117 fx[i].s = stream_read8(h);
121 static void G_savegame (Writer *h) {
122 stream_write8(_2pl, h);
123 stream_write8(g_dm, h);
124 stream_write8(g_exit, h);
125 stream_write8(g_map, h);
126 stream_write32(g_time, h);
127 stream_write32(dm_pl1p, h);
128 stream_write32(dm_pl2p, h);
129 stream_write32(dm_pnum, h);
130 int i = 0;
131 while (i < dm_pnum) {
132 stream_write32(dm_pos[i].x, h);
133 stream_write32(dm_pos[i].y, h);
134 stream_write8(dm_pos[i].d, h);
135 i += 1;
137 stream_write8(cheat, h);
138 stream_write(g_music, 8, 1, h);
141 static void G_loadgame (Reader *h) {
142 _2pl = stream_read8(h);
143 g_dm = stream_read8(h);
144 g_exit = stream_read8(h);
145 g_map = stream_read8(h);
146 g_time = stream_read32(h);
147 dm_pl1p = stream_read32(h);
148 dm_pl2p = stream_read32(h);
149 dm_pnum = stream_read32(h);
150 int i = 0;
151 while (i < dm_pnum) {
152 dm_pos[i].x = stream_read32(h);
153 dm_pos[i].y = stream_read32(h);
154 dm_pos[i].d = stream_read8(h);
155 i += 1;
157 cheat = stream_read8(h);
158 stream_read(g_music, 8, 1, h);
159 MUS_load(g_music);
162 static void IT_savegame (Writer *h) {
163 int i, n;
164 for (n = MAXITEM - 1; n >= 0 && it[n].t == 0; n--) {
165 // empty
167 n += 1;
168 stream_write32(n, h);
169 for (i = 0; i < n; i++) {
170 stream_write32(it[i].o.x, h);
171 stream_write32(it[i].o.y, h);
172 stream_write32(it[i].o.xv, h);
173 stream_write32(it[i].o.yv, h);
174 stream_write32(it[i].o.vx, h);
175 stream_write32(it[i].o.vy, h);
176 stream_write32(it[i].o.r, h);
177 stream_write32(it[i].o.h, h);
178 stream_write32(it[i].t, h);
179 stream_write32(it[i].s, h);
181 stream_write32(itm_rtime, h);
184 static void IT_loadgame (Reader *h) {
185 int i, n;
186 n = stream_read32(h);
187 for (i = 0; i < n; i++) {
188 it[i].o.x = stream_read32(h);
189 it[i].o.y = stream_read32(h);
190 it[i].o.xv = stream_read32(h);
191 it[i].o.yv = stream_read32(h);
192 it[i].o.vx = stream_read32(h);
193 it[i].o.vy = stream_read32(h);
194 it[i].o.r = stream_read32(h);
195 it[i].o.h = stream_read32(h);
196 it[i].t = stream_read32(h);
197 it[i].s = stream_read32(h);
199 itm_rtime = stream_read32(h);
202 static void MN_savegame (Writer *h) {
203 int i, n;
204 for (n = MAXMN - 1; n >= 0 && mn[n].t == 0; n--) {
205 // empty
207 n += 1;
208 stream_write32(n, h);
209 for (i = 0; i < n; i++) {
210 stream_write32(mn[i].o.x, h);
211 stream_write32(mn[i].o.y, h);
212 stream_write32(mn[i].o.xv, h);
213 stream_write32(mn[i].o.yv, h);
214 stream_write32(mn[i].o.vx, h);
215 stream_write32(mn[i].o.vy, h);
216 stream_write32(mn[i].o.r, h);
217 stream_write32(mn[i].o.h, h);
218 stream_write8(mn[i].t, h);
219 stream_write8(mn[i].d, h);
220 stream_write8(mn[i].st, h);
221 stream_write8(mn[i].ftime, h);
222 stream_write32(mn[i].fobj, h);
223 stream_write32(mn[i].s, h);
224 stream_write32(0, h); // mn[i].ap useless, changed after load
225 stream_write32(mn[i].aim, h);
226 stream_write32(mn[i].life, h);
227 stream_write32(mn[i].pain, h);
228 stream_write32(mn[i].ac, h);
229 stream_write32(mn[i].tx, h);
230 stream_write32(mn[i].ty, h);
231 stream_write32(mn[i].ammo, h);
232 stream_write16(mn[i].atm, h);
234 stream_write32(mnum, h);
235 stream_write32(gsndt, h);
238 static void MN_loadgame (Reader *h) {
239 int i, n, c;
240 n = stream_read32(h);
241 for (i = 0; i < n; i++) {
242 mn[i].o.x = stream_read32(h);
243 mn[i].o.y = stream_read32(h);
244 mn[i].o.xv = stream_read32(h);
245 mn[i].o.yv = stream_read32(h);
246 mn[i].o.vx = stream_read32(h);
247 mn[i].o.vy = stream_read32(h);
248 mn[i].o.r = stream_read32(h);
249 mn[i].o.h = stream_read32(h);
250 mn[i].t = stream_read8(h);
251 mn[i].d = stream_read8(h);
252 mn[i].st = stream_read8(h);
253 mn[i].ftime = stream_read8(h);
254 mn[i].fobj = stream_read32(h);
255 mn[i].s = stream_read32(h);
256 mn[i].ap = NULL; stream_read32(h); // useless, changed after loading
257 mn[i].aim = stream_read32(h);
258 mn[i].life = stream_read32(h);
259 mn[i].pain = stream_read32(h);
260 mn[i].ac = stream_read32(h);
261 mn[i].tx = stream_read32(h);
262 mn[i].ty = stream_read32(h);
263 mn[i].ammo = stream_read32(h);
264 mn[i].atm = stream_read16(h);
266 mnum = stream_read32(h);
267 gsndt = stream_read32(h);
268 for (n = 0; n < MAXMN; n++) {
269 if (mn[n].t) {
270 c = mn[n].ac;
271 setst(n, mn[n].st);
272 mn[n].ac = c;
277 static void PL_save_player (player_t *p, Writer *h) {
278 stream_write32(p->o.x, h);
279 stream_write32(p->o.y, h);
280 stream_write32(p->o.xv, h);
281 stream_write32(p->o.yv, h);
282 stream_write32(p->o.vx, h);
283 stream_write32(p->o.vy, h);
284 stream_write32(p->o.r, h);
285 stream_write32(p->o.h, h);
286 stream_write32(p->looky, h);
287 stream_write32(p->st, h);
288 stream_write32(p->s, h);
289 stream_write32(p->life, h);
290 stream_write32(p->armor, h);
291 stream_write32(p->hit, h);
292 stream_write32(p->hito, h);
293 stream_write32(p->pain, h);
294 stream_write32(p->air, h);
295 stream_write32(p->invl, h);
296 stream_write32(p->suit, h);
297 stream_write8(p->d, h);
298 stream_write32(p->frag, h);
299 stream_write32(p->ammo, h);
300 stream_write32(p->shel, h);
301 stream_write32(p->rock, h);
302 stream_write32(p->cell, h);
303 stream_write32(p->fuel, h);
304 stream_write32(p->kills, h);
305 stream_write32(p->secrets, h);
306 stream_write8(p->fire, h);
307 stream_write8(p->cwpn, h);
308 stream_write8(p->csnd, h);
309 stream_write8(p->amul, h);
310 stream_write16(p->wpns, h);
311 stream_write8(p->wpn, h);
312 stream_write8(p->f, h);
313 stream_write8(p->drawst, h);
314 stream_write8(p->color, h);
315 stream_write32(p->id, h);
316 stream_write8(p->keys, h);
317 stream_write8(p->lives, h);
318 // k* not saved
321 static void PL_savegame (Writer *h) {
322 PL_save_player(&pl1, h);
323 if (_2pl) {
324 PL_save_player(&pl2, h);
326 stream_write32(PL_JUMP, h);
327 stream_write32(PL_RUN, h);
328 stream_write8(p_immortal, h);
331 static void PL_load_player (player_t *p, Reader *h) {
332 p->o.x = stream_read32(h);
333 p->o.y = stream_read32(h);
334 p->o.xv = stream_read32(h);
335 p->o.yv = stream_read32(h);
336 p->o.vx = stream_read32(h);
337 p->o.vy = stream_read32(h);
338 p->o.r = stream_read32(h);
339 p->o.h = stream_read32(h);
340 p->looky = stream_read32(h);
341 p->st = stream_read32(h);
342 p->s = stream_read32(h);
343 p->life = stream_read32(h);
344 p->armor = stream_read32(h);
345 p->hit = stream_read32(h);
346 p->hito = stream_read32(h);
347 p->pain = stream_read32(h);
348 p->air = stream_read32(h);
349 p->invl = stream_read32(h);
350 p->suit = stream_read32(h);
351 p->d = stream_read8(h);
352 p->frag = stream_read32(h);
353 p->ammo = stream_read32(h);
354 p->shel = stream_read32(h);
355 p->rock = stream_read32(h);
356 p->cell = stream_read32(h);
357 p->fuel = stream_read32(h);
358 p->kills = stream_read32(h);
359 p->secrets = stream_read32(h);
360 p->fire = stream_read8(h);
361 p->cwpn = stream_read8(h);
362 p->csnd = stream_read8(h);
363 p->amul = stream_read8(h);
364 p->wpns = stream_read16(h);
365 p->wpn = stream_read8(h);
366 p->f = stream_read8(h);
367 p->drawst = stream_read8(h);
368 p->color = stream_read8(h);
369 p->id = stream_read32(h);
370 p->keys = stream_read8(h);
371 p->lives = stream_read8(h);
372 // k* not saved
375 static void PL_loadgame (Reader *h) {
376 PL_load_player(&pl1, h);
377 if (_2pl) {
378 PL_load_player(&pl2, h);
380 PL_JUMP = stream_read32(h);
381 PL_RUN = stream_read32(h);
382 p_immortal = stream_read8(h);
385 static void SMK_savegame (Writer *h) {
386 int i, n;
387 for (i = n = 0; i < MAXSMOK; ++i) {
388 if (sm[i].t) {
389 ++n;
392 stream_write32(n, h);
393 for (i = 0; i < MAXSMOK; ++i) {
394 if (sm[i].t) {
395 stream_write32(sm[i].x, h);
396 stream_write32(sm[i].y, h);
397 stream_write32(sm[i].xv, h);
398 stream_write32(sm[i].xv, h);
399 stream_write8(sm[i].t, h);
400 stream_write8(sm[i].s, h);
401 stream_write16(sm[i].o, h);
406 static void SMK_loadgame (Reader *h) {
407 int i, n;
408 n = stream_read32(h);
409 for (i = 0; i < n; ++i) {
410 sm[i].x = stream_read32(h);
411 sm[i].y = stream_read32(h);
412 sm[i].xv = stream_read32(h);
413 sm[i].xv = stream_read32(h);
414 sm[i].t = stream_read8(h);
415 sm[i].s = stream_read8(h);
416 sm[i].o = stream_read16(h);
420 static void SW_savegame (Writer *h) {
421 int i, n;
422 for (n = MAXSW - 1; n >= 0 && sw[n].t == 0; n--) {
423 // empty
425 n += 1;
426 stream_write32(n, h);
427 for (i = 0; i < n; i++) {
428 stream_write8(sw[i].x, h);
429 stream_write8(sw[i].y, h);
430 stream_write8(sw[i].t, h);
431 stream_write8(sw[i].tm, h);
432 stream_write8(sw[i].a, h);
433 stream_write8(sw[i].b, h);
434 stream_write8(sw[i].c, h);
435 stream_write8(sw[i].d, h);
436 stream_write8(sw[i].f, h);
438 stream_write32(sw_secrets, h);
441 static void SW_loadgame (Reader *h) {
442 int i, n;
443 n = stream_read32(h);
444 for (i = 0; i < n; i++) {
445 sw[i].x = stream_read8(h);
446 sw[i].y = stream_read8(h);
447 sw[i].t = stream_read8(h);
448 sw[i].tm = stream_read8(h);
449 sw[i].a = stream_read8(h);
450 sw[i].b = stream_read8(h);
451 sw[i].c = stream_read8(h);
452 sw[i].d = stream_read8(h);
453 sw[i].f = stream_read8(h);
455 sw_secrets = stream_read32(h);
458 static void W_savegame (Writer* h) {
459 char s[8];
460 int i;
461 stream_write32(sky_type, h);
462 for(i = 1; i < 256; ++i) {
463 R_get_name(i, s);
464 stream_write(s, 8, 1, h);
466 for (i = 0; i < 256; i++) {
467 stream_write32(walf[i], h);
469 for (i = 0; i < 256; i++) {
470 stream_write8(R_get_swp(i), h);
472 stream_write(fldb, FLDW*FLDH, 1, h);
473 stream_write(fld, FLDW*FLDH, 1, h);
474 stream_write(fldf, FLDW*FLDH, 1, h);
477 static void W_loadgame (Reader *h) {
478 int i;
479 char s[8];
480 sky_type = stream_read32(h);
481 R_loadsky(sky_type);
482 R_begin_load();
483 for (i = 1; i < 256; ++i) {
484 stream_read(s, 8, 1, h);
485 if (s[0]) {
486 R_load(s);
489 R_end_load();
490 for (i = 0; i < 256; i++) {
491 stream_read32(h); // useless
493 for (i = 0; i < 256; i++) {
494 walf[i] = stream_read8(h);
496 stream_read(fldb, FLDW*FLDH, 1, h);
497 stream_read(fld, FLDW*FLDH, 1, h);
498 stream_read(fldf, FLDW*FLDH, 1, h);
501 static void WP_savegame (Writer *h) {
502 int i, n;
503 for (n = MAXWPN - 1; n >= 0 && wp[n].t == 0; n--) {
504 // empty
506 n += 1;
507 stream_write32(n, h);
508 for (i = 0; i < n; i++) {
509 stream_write32(wp[i].o.x, h);
510 stream_write32(wp[i].o.y, h);
511 stream_write32(wp[i].o.xv, h);
512 stream_write32(wp[i].o.yv, h);
513 stream_write32(wp[i].o.vx, h);
514 stream_write32(wp[i].o.vy, h);
515 stream_write32(wp[i].o.r, h);
516 stream_write32(wp[i].o.h, h);
517 stream_write8(wp[i].t, h);
518 stream_write8(wp[i].s, h);
519 stream_write32(wp[i].own, h);
520 stream_write16(wp[i].target, h);
524 static void WP_loadgame (Reader *h) {
525 int i, n;
526 n = stream_read32(h);
527 for (i = 0; i < n; i++) {
528 wp[i].o.x = stream_read32(h);
529 wp[i].o.y = stream_read32(h);
530 wp[i].o.xv = stream_read32(h);
531 wp[i].o.yv = stream_read32(h);
532 wp[i].o.vx = stream_read32(h);
533 wp[i].o.vy = stream_read32(h);
534 wp[i].o.r = stream_read32(h);
535 wp[i].o.h = stream_read32(h);
536 wp[i].t = stream_read8(h);
537 wp[i].s = stream_read8(h);
538 wp[i].own = stream_read32(h);
539 wp[i].target = stream_read16(h);
543 static char *getsavfpname (int n, int ro) {
544 static char fn[] = "savgame0.dat";
545 static char p[100];
546 fn[7] = n + '0';
547 #ifdef UNIX
548 char *e = getenv("HOME");
549 strncpy(p, e, 60);
550 strcat(p, "/.flatwaifu");
551 if (!ro) {
552 mkdir(p, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
554 strcat(p, "/");
555 strcat(p, fn);
556 #else
557 strcpy(p, fn);
558 #endif
559 return p;
562 void SAVE_save (Writer *w, const char name[24]) {
563 assert(w != NULL);
564 stream_write(name, 24, 1, w); // slot name
565 stream_write16(3, w); // version
566 G_savegame(w);
567 W_savegame(w);
568 DOT_savegame(w);
569 SMK_savegame(w);
570 FX_savegame(w);
571 IT_savegame(w);
572 MN_savegame(w);
573 PL_savegame(w);
574 SW_savegame(w);
575 WP_savegame(w);
578 void F_savegame (int n, char *s) {
579 FILE_Writer wr;
580 char *p = getsavfpname(n, 0);
581 if (FILE_OpenWriter(&wr, p)) {
582 SAVE_save(&wr.base, s);
583 FILE_CloseWriter(&wr);
587 void SAVE_load (Reader *h) {
588 int16_t version;
589 h->setpos(h, 24); // skip name
590 version = stream_read16(h);
591 if (version == 3) {
592 G_loadgame(h);
593 W_loadgame(h);
594 DOT_loadgame(h);
595 SMK_loadgame(h);
596 FX_loadgame(h);
597 IT_loadgame(h);
598 MN_loadgame(h);
599 PL_loadgame(h);
600 SW_loadgame(h);
601 WP_loadgame(h);
605 void F_getsavnames (void) {
606 int i;
607 char *p;
608 FILE_Reader rd;
609 int16_t version;
610 for (i = 0; i < 7; ++i) {
611 p = getsavfpname(i, 1);
612 memset(savname[i], 0, 24);
613 savok[i] = 0;
614 if (FILE_OpenReader(&rd, p)) {
615 version = -1;
616 stream_read(savname[i], 24, 1, &rd.base);
617 version = stream_read16(&rd.base);
618 savname[i][23] = 0;
619 savok[i] = version == 3;
620 FILE_CloseReader(&rd);
625 void F_loadgame (int n) {
626 FILE_Reader rd;
627 char *p = getsavfpname(n, 1);
628 if (FILE_OpenReader(&rd, p)) {
629 SAVE_load(&rd.base);
630 FILE_CloseReader(&rd);