1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1993-1996 by id Software, Inc.
4 // Copyright (C) 1998-2000 by DooM Legacy Team.
5 // Copyright (C) 1999-2020 by Sonic Team Junior.
6 //
7 // This program is free software distributed under the
8 // terms of the GNU General Public License, version 2.
9 // See the 'LICENSE' file for more details.
10 //-----------------------------------------------------------------------------
11 /// \file p_saveg.c
12 /// \brief Archiving: SaveGame I/O
13
14 #include "doomdef.h"
15 #include "byteptr.h"
16 #include "d_main.h"
17 #include "doomstat.h"
18 #include "g_game.h"
19 #include "m_random.h"
20 #include "m_misc.h"
21 #include "p_local.h"
22 #include "p_setup.h"
23 #include "p_saveg.h"
24 #include "r_data.h"
25 #include "r_textures.h"
26 #include "r_things.h"
27 #include "r_skins.h"
28 #include "r_state.h"
29 #include "w_wad.h"
30 #include "y_inter.h"
31 #include "z_zone.h"
32 #include "r_main.h"
33 #include "r_sky.h"
34 #include "p_polyobj.h"
35 #include "lua_script.h"
36 #include "p_slopes.h"
37
38 savedata_t savedata;
39 UINT8 *save_p;
40
41 // Block UINT32s to attempt to ensure that the correct data is
42 // being sent and received
43 #define ARCHIVEBLOCK_MISC 0x7FEEDEED
44 #define ARCHIVEBLOCK_PLAYERS 0x7F448008
45 #define ARCHIVEBLOCK_WORLD 0x7F8C08C0
46 #define ARCHIVEBLOCK_POBJS 0x7F928546
47 #define ARCHIVEBLOCK_THINKERS 0x7F37037C
48 #define ARCHIVEBLOCK_SPECIALS 0x7F228378
49
50 // Note: This cannot be bigger
51 // than an UINT16
52 typedef enum
53 {
54 // RFLAGPOINT = 0x01,
55 // BFLAGPOINT = 0x02,
56 CAPSULE = 0x04,
57 AWAYVIEW = 0x08,
58 FIRSTAXIS = 0x10,
59 SECONDAXIS = 0x20,
60 FOLLOW = 0x40,
61 DRONE = 0x80,
62 } player_saveflags;
63
P_ArchivePlayer(void)64 static inline void P_ArchivePlayer(void)
65 {
66 const player_t *player = &players[consoleplayer];
67 INT16 skininfo = player->skin + (botskin<<5);
68 SINT8 pllives = player->lives;
69 if (pllives < startinglivesbalance[numgameovers]) // Bump up to 3 lives if the player
70 pllives = startinglivesbalance[numgameovers]; // has less than that.
71
72 WRITEUINT16(save_p, skininfo);
73 WRITEUINT8(save_p, numgameovers);
74 WRITESINT8(save_p, pllives);
75 WRITEUINT32(save_p, player->score);
76 WRITEINT32(save_p, player->continues);
77 }
78
P_UnArchivePlayer(void)79 static inline void P_UnArchivePlayer(void)
80 {
81 INT16 skininfo = READUINT16(save_p);
82 savedata.skin = skininfo & ((1<<5) - 1);
83 savedata.botskin = skininfo >> 5;
84
85 savedata.numgameovers = READUINT8(save_p);
86 savedata.lives = READSINT8(save_p);
87 savedata.score = READUINT32(save_p);
88 savedata.continues = READINT32(save_p);
89 }
90
P_NetArchivePlayers(void)91 static void P_NetArchivePlayers(void)
92 {
93 INT32 i, j;
94 UINT16 flags;
95 // size_t q;
96
97 WRITEUINT32(save_p, ARCHIVEBLOCK_PLAYERS);
98
99 for (i = 0; i < MAXPLAYERS; i++)
100 {
101 WRITESINT8(save_p, (SINT8)adminplayers[i]);
102
103 if (!playeringame[i])
104 continue;
105
106 flags = 0;
107
108 // no longer send ticcmds
109
110 WRITESTRINGN(save_p, player_names[i], MAXPLAYERNAME);
111 WRITEINT16(save_p, players[i].angleturn);
112 WRITEINT16(save_p, players[i].oldrelangleturn);
113 WRITEANGLE(save_p, players[i].aiming);
114 WRITEANGLE(save_p, players[i].drawangle);
115 WRITEANGLE(save_p, players[i].viewrollangle);
116 WRITEANGLE(save_p, players[i].awayviewaiming);
117 WRITEINT32(save_p, players[i].awayviewtics);
118 WRITEINT16(save_p, players[i].rings);
119 WRITEINT16(save_p, players[i].spheres);
120
121 WRITESINT8(save_p, players[i].pity);
122 WRITEINT32(save_p, players[i].currentweapon);
123 WRITEINT32(save_p, players[i].ringweapons);
124
125 WRITEUINT16(save_p, players[i].ammoremoval);
126 WRITEUINT32(save_p, players[i].ammoremovaltimer);
127 WRITEINT32(save_p, players[i].ammoremovaltimer);
128
129 for (j = 0; j < NUMPOWERS; j++)
130 WRITEUINT16(save_p, players[i].powers[j]);
131
132 WRITEUINT8(save_p, players[i].playerstate);
133 WRITEUINT32(save_p, players[i].pflags);
134 WRITEUINT8(save_p, players[i].panim);
135 WRITEUINT8(save_p, players[i].spectator);
136
137 WRITEUINT16(save_p, players[i].flashpal);
138 WRITEUINT16(save_p, players[i].flashcount);
139
140 WRITEUINT8(save_p, players[i].skincolor);
141 WRITEINT32(save_p, players[i].skin);
142 WRITEUINT32(save_p, players[i].availabilities);
143 WRITEUINT32(save_p, players[i].score);
144 WRITEFIXED(save_p, players[i].dashspeed);
145 WRITESINT8(save_p, players[i].lives);
146 WRITESINT8(save_p, players[i].continues);
147 WRITESINT8(save_p, players[i].xtralife);
148 WRITEUINT8(save_p, players[i].gotcontinue);
149 WRITEFIXED(save_p, players[i].speed);
150 WRITEUINT8(save_p, players[i].secondjump);
151 WRITEUINT8(save_p, players[i].fly1);
152 WRITEUINT8(save_p, players[i].scoreadd);
153 WRITEUINT32(save_p, players[i].glidetime);
154 WRITEUINT8(save_p, players[i].climbing);
155 WRITEINT32(save_p, players[i].deadtimer);
156 WRITEUINT32(save_p, players[i].exiting);
157 WRITEUINT8(save_p, players[i].homing);
158 WRITEUINT32(save_p, players[i].dashmode);
159 WRITEUINT32(save_p, players[i].skidtime);
160
161 ////////////////////////////
162 // Conveyor Belt Movement //
163 ////////////////////////////
164 WRITEFIXED(save_p, players[i].cmomx); // Conveyor momx
165 WRITEFIXED(save_p, players[i].cmomy); // Conveyor momy
166 WRITEFIXED(save_p, players[i].rmomx); // "Real" momx (momx - cmomx)
167 WRITEFIXED(save_p, players[i].rmomy); // "Real" momy (momy - cmomy)
168
169 /////////////////////
170 // Race Mode Stuff //
171 /////////////////////
172 WRITEINT16(save_p, players[i].numboxes);
173 WRITEINT16(save_p, players[i].totalring);
174 WRITEUINT32(save_p, players[i].realtime);
175 WRITEUINT8(save_p, players[i].laps);
176
177 ////////////////////
178 // CTF Mode Stuff //
179 ////////////////////
180 WRITEINT32(save_p, players[i].ctfteam);
181 WRITEUINT16(save_p, players[i].gotflag);
182
183 WRITEINT32(save_p, players[i].weapondelay);
184 WRITEINT32(save_p, players[i].tossdelay);
185
186 WRITEUINT32(save_p, players[i].starposttime);
187 WRITEINT16(save_p, players[i].starpostx);
188 WRITEINT16(save_p, players[i].starposty);
189 WRITEINT16(save_p, players[i].starpostz);
190 WRITEINT32(save_p, players[i].starpostnum);
191 WRITEANGLE(save_p, players[i].starpostangle);
192 WRITEFIXED(save_p, players[i].starpostscale);
193
194 WRITEANGLE(save_p, players[i].angle_pos);
195 WRITEANGLE(save_p, players[i].old_angle_pos);
196
197 WRITEINT32(save_p, players[i].flyangle);
198 WRITEUINT32(save_p, players[i].drilltimer);
199 WRITEINT32(save_p, players[i].linkcount);
200 WRITEUINT32(save_p, players[i].linktimer);
201 WRITEINT32(save_p, players[i].anotherflyangle);
202 WRITEUINT32(save_p, players[i].nightstime);
203 WRITEUINT32(save_p, players[i].bumpertime);
204 WRITEINT32(save_p, players[i].drillmeter);
205 WRITEUINT8(save_p, players[i].drilldelay);
206 WRITEUINT8(save_p, players[i].bonustime);
207 WRITEFIXED(save_p, players[i].oldscale);
208 WRITEUINT8(save_p, players[i].mare);
209 WRITEUINT8(save_p, players[i].marelap);
210 WRITEUINT8(save_p, players[i].marebonuslap);
211 WRITEUINT32(save_p, players[i].marebegunat);
212 WRITEUINT32(save_p, players[i].startedtime);
213 WRITEUINT32(save_p, players[i].finishedtime);
214 WRITEUINT32(save_p, players[i].lapbegunat);
215 WRITEUINT32(save_p, players[i].lapstartedtime);
216 WRITEINT16(save_p, players[i].finishedspheres);
217 WRITEINT16(save_p, players[i].finishedrings);
218 WRITEUINT32(save_p, players[i].marescore);
219 WRITEUINT32(save_p, players[i].lastmarescore);
220 WRITEUINT32(save_p, players[i].totalmarescore);
221 WRITEUINT8(save_p, players[i].lastmare);
222 WRITEUINT8(save_p, players[i].lastmarelap);
223 WRITEUINT8(save_p, players[i].lastmarebonuslap);
224 WRITEUINT8(save_p, players[i].totalmarelap);
225 WRITEUINT8(save_p, players[i].totalmarebonuslap);
226 WRITEINT32(save_p, players[i].maxlink);
227 WRITEUINT8(save_p, players[i].texttimer);
228 WRITEUINT8(save_p, players[i].textvar);
229
230 if (players[i].capsule)
231 flags |= CAPSULE;
232
233 if (players[i].awayviewmobj)
234 flags |= AWAYVIEW;
235
236 if (players[i].axis1)
237 flags |= FIRSTAXIS;
238
239 if (players[i].axis2)
240 flags |= SECONDAXIS;
241
242 if (players[i].followmobj)
243 flags |= FOLLOW;
244
245 if (players[i].drone)
246 flags |= DRONE;
247
248 WRITEINT16(save_p, players[i].lastsidehit);
249 WRITEINT16(save_p, players[i].lastlinehit);
250
251 WRITEUINT32(save_p, players[i].losstime);
252
253 WRITEUINT8(save_p, players[i].timeshit);
254
255 WRITEINT32(save_p, players[i].onconveyor);
256
257 WRITEUINT32(save_p, players[i].jointime);
258 WRITEUINT32(save_p, players[i].quittime);
259
260 WRITEUINT16(save_p, flags);
261
262 if (flags & CAPSULE)
263 WRITEUINT32(save_p, players[i].capsule->mobjnum);
264
265 if (flags & FIRSTAXIS)
266 WRITEUINT32(save_p, players[i].axis1->mobjnum);
267
268 if (flags & SECONDAXIS)
269 WRITEUINT32(save_p, players[i].axis2->mobjnum);
270
271 if (flags & AWAYVIEW)
272 WRITEUINT32(save_p, players[i].awayviewmobj->mobjnum);
273
274 if (flags & FOLLOW)
275 WRITEUINT32(save_p, players[i].followmobj->mobjnum);
276
277 if (flags & DRONE)
278 WRITEUINT32(save_p, players[i].drone->mobjnum);
279
280 WRITEFIXED(save_p, players[i].camerascale);
281 WRITEFIXED(save_p, players[i].shieldscale);
282
283 WRITEUINT8(save_p, players[i].charability);
284 WRITEUINT8(save_p, players[i].charability2);
285 WRITEUINT32(save_p, players[i].charflags);
286 WRITEUINT32(save_p, (UINT32)players[i].thokitem);
287 WRITEUINT32(save_p, (UINT32)players[i].spinitem);
288 WRITEUINT32(save_p, (UINT32)players[i].revitem);
289 WRITEUINT32(save_p, (UINT32)players[i].followitem);
290 WRITEFIXED(save_p, players[i].actionspd);
291 WRITEFIXED(save_p, players[i].mindash);
292 WRITEFIXED(save_p, players[i].maxdash);
293 WRITEFIXED(save_p, players[i].normalspeed);
294 WRITEFIXED(save_p, players[i].runspeed);
295 WRITEUINT8(save_p, players[i].thrustfactor);
296 WRITEUINT8(save_p, players[i].accelstart);
297 WRITEUINT8(save_p, players[i].acceleration);
298 WRITEFIXED(save_p, players[i].jumpfactor);
299 WRITEFIXED(save_p, players[i].height);
300 WRITEFIXED(save_p, players[i].spinheight);
301 }
302 }
303
P_NetUnArchivePlayers(void)304 static void P_NetUnArchivePlayers(void)
305 {
306 INT32 i, j;
307 UINT16 flags;
308
309 if (READUINT32(save_p) != ARCHIVEBLOCK_PLAYERS)
310 I_Error("Bad $$$.sav at archive block Players");
311
312 for (i = 0; i < MAXPLAYERS; i++)
313 {
314 adminplayers[i] = (INT32)READSINT8(save_p);
315
316 // Do NOT memset player struct to 0
317 // other areas may initialize data elsewhere
318 //memset(&players[i], 0, sizeof (player_t));
319 if (!playeringame[i])
320 continue;
321
322 // NOTE: sending tics should (hopefully) no longer be necessary
323
324 READSTRINGN(save_p, player_names[i], MAXPLAYERNAME);
325 players[i].angleturn = READINT16(save_p);
326 players[i].oldrelangleturn = READINT16(save_p);
327 players[i].aiming = READANGLE(save_p);
328 players[i].drawangle = READANGLE(save_p);
329 players[i].viewrollangle = READANGLE(save_p);
330 players[i].awayviewaiming = READANGLE(save_p);
331 players[i].awayviewtics = READINT32(save_p);
332 players[i].rings = READINT16(save_p);
333 players[i].spheres = READINT16(save_p);
334
335 players[i].pity = READSINT8(save_p);
336 players[i].currentweapon = READINT32(save_p);
337 players[i].ringweapons = READINT32(save_p);
338
339 players[i].ammoremoval = READUINT16(save_p);
340 players[i].ammoremovaltimer = READUINT32(save_p);
341 players[i].ammoremovalweapon = READINT32(save_p);
342
343 for (j = 0; j < NUMPOWERS; j++)
344 players[i].powers[j] = READUINT16(save_p);
345
346 players[i].playerstate = READUINT8(save_p);
347 players[i].pflags = READUINT32(save_p);
348 players[i].panim = READUINT8(save_p);
349 players[i].spectator = READUINT8(save_p);
350
351 players[i].flashpal = READUINT16(save_p);
352 players[i].flashcount = READUINT16(save_p);
353
354 players[i].skincolor = READUINT8(save_p);
355 players[i].skin = READINT32(save_p);
356 players[i].availabilities = READUINT32(save_p);
357 players[i].score = READUINT32(save_p);
358 players[i].dashspeed = READFIXED(save_p); // dashing speed
359 players[i].lives = READSINT8(save_p);
360 players[i].continues = READSINT8(save_p); // continues that player has acquired
361 players[i].xtralife = READSINT8(save_p); // Ring Extra Life counter
362 players[i].gotcontinue = READUINT8(save_p); // got continue from stage
363 players[i].speed = READFIXED(save_p); // Player's speed (distance formula of MOMX and MOMY values)
364 players[i].secondjump = READUINT8(save_p);
365 players[i].fly1 = READUINT8(save_p); // Tails flying
366 players[i].scoreadd = READUINT8(save_p); // Used for multiple enemy attack bonus
367 players[i].glidetime = READUINT32(save_p); // Glide counter for thrust
368 players[i].climbing = READUINT8(save_p); // Climbing on the wall
369 players[i].deadtimer = READINT32(save_p); // End game if game over lasts too long
370 players[i].exiting = READUINT32(save_p); // Exitlevel timer
371 players[i].homing = READUINT8(save_p); // Are you homing?
372 players[i].dashmode = READUINT32(save_p); // counter for dashmode ability
373 players[i].skidtime = READUINT32(save_p); // Skid timer
374
375 ////////////////////////////
376 // Conveyor Belt Movement //
377 ////////////////////////////
378 players[i].cmomx = READFIXED(save_p); // Conveyor momx
379 players[i].cmomy = READFIXED(save_p); // Conveyor momy
380 players[i].rmomx = READFIXED(save_p); // "Real" momx (momx - cmomx)
381 players[i].rmomy = READFIXED(save_p); // "Real" momy (momy - cmomy)
382
383 /////////////////////
384 // Race Mode Stuff //
385 /////////////////////
386 players[i].numboxes = READINT16(save_p); // Number of item boxes obtained for Race Mode
387 players[i].totalring = READINT16(save_p); // Total number of rings obtained for Race Mode
388 players[i].realtime = READUINT32(save_p); // integer replacement for leveltime
389 players[i].laps = READUINT8(save_p); // Number of laps (optional)
390
391 ////////////////////
392 // CTF Mode Stuff //
393 ////////////////////
394 players[i].ctfteam = READINT32(save_p); // 1 == Red, 2 == Blue
395 players[i].gotflag = READUINT16(save_p); // 1 == Red, 2 == Blue Do you have the flag?
396
397 players[i].weapondelay = READINT32(save_p);
398 players[i].tossdelay = READINT32(save_p);
399
400 players[i].starposttime = READUINT32(save_p);
401 players[i].starpostx = READINT16(save_p);
402 players[i].starposty = READINT16(save_p);
403 players[i].starpostz = READINT16(save_p);
404 players[i].starpostnum = READINT32(save_p);
405 players[i].starpostangle = READANGLE(save_p);
406 players[i].starpostscale = READFIXED(save_p);
407
408 players[i].angle_pos = READANGLE(save_p);
409 players[i].old_angle_pos = READANGLE(save_p);
410
411 players[i].flyangle = READINT32(save_p);
412 players[i].drilltimer = READUINT32(save_p);
413 players[i].linkcount = READINT32(save_p);
414 players[i].linktimer = READUINT32(save_p);
415 players[i].anotherflyangle = READINT32(save_p);
416 players[i].nightstime = READUINT32(save_p);
417 players[i].bumpertime = READUINT32(save_p);
418 players[i].drillmeter = READINT32(save_p);
419 players[i].drilldelay = READUINT8(save_p);
420 players[i].bonustime = (boolean)READUINT8(save_p);
421 players[i].oldscale = READFIXED(save_p);
422 players[i].mare = READUINT8(save_p);
423 players[i].marelap = READUINT8(save_p);
424 players[i].marebonuslap = READUINT8(save_p);
425 players[i].marebegunat = READUINT32(save_p);
426 players[i].startedtime = READUINT32(save_p);
427 players[i].finishedtime = READUINT32(save_p);
428 players[i].lapbegunat = READUINT32(save_p);
429 players[i].lapstartedtime = READUINT32(save_p);
430 players[i].finishedspheres = READINT16(save_p);
431 players[i].finishedrings = READINT16(save_p);
432 players[i].marescore = READUINT32(save_p);
433 players[i].lastmarescore = READUINT32(save_p);
434 players[i].totalmarescore = READUINT32(save_p);
435 players[i].lastmare = READUINT8(save_p);
436 players[i].lastmarelap = READUINT8(save_p);
437 players[i].lastmarebonuslap = READUINT8(save_p);
438 players[i].totalmarelap = READUINT8(save_p);
439 players[i].totalmarebonuslap = READUINT8(save_p);
440 players[i].maxlink = READINT32(save_p);
441 players[i].texttimer = READUINT8(save_p);
442 players[i].textvar = READUINT8(save_p);
443
444 players[i].lastsidehit = READINT16(save_p);
445 players[i].lastlinehit = READINT16(save_p);
446
447 players[i].losstime = READUINT32(save_p);
448
449 players[i].timeshit = READUINT8(save_p);
450
451 players[i].onconveyor = READINT32(save_p);
452
453 players[i].jointime = READUINT32(save_p);
454 players[i].quittime = READUINT32(save_p);
455
456 flags = READUINT16(save_p);
457
458 if (flags & CAPSULE)
459 players[i].capsule = (mobj_t *)(size_t)READUINT32(save_p);
460
461 if (flags & FIRSTAXIS)
462 players[i].axis1 = (mobj_t *)(size_t)READUINT32(save_p);
463
464 if (flags & SECONDAXIS)
465 players[i].axis2 = (mobj_t *)(size_t)READUINT32(save_p);
466
467 if (flags & AWAYVIEW)
468 players[i].awayviewmobj = (mobj_t *)(size_t)READUINT32(save_p);
469
470 if (flags & FOLLOW)
471 players[i].followmobj = (mobj_t *)(size_t)READUINT32(save_p);
472
473 if (flags & DRONE)
474 players[i].drone = (mobj_t *)(size_t)READUINT32(save_p);
475
476 players[i].camerascale = READFIXED(save_p);
477 players[i].shieldscale = READFIXED(save_p);
478
479 //SetPlayerSkinByNum(i, players[i].skin);
480 players[i].charability = READUINT8(save_p);
481 players[i].charability2 = READUINT8(save_p);
482 players[i].charflags = READUINT32(save_p);
483 players[i].thokitem = (mobjtype_t)READUINT32(save_p);
484 players[i].spinitem = (mobjtype_t)READUINT32(save_p);
485 players[i].revitem = (mobjtype_t)READUINT32(save_p);
486 players[i].followitem = (mobjtype_t)READUINT32(save_p);
487 players[i].actionspd = READFIXED(save_p);
488 players[i].mindash = READFIXED(save_p);
489 players[i].maxdash = READFIXED(save_p);
490 players[i].normalspeed = READFIXED(save_p);
491 players[i].runspeed = READFIXED(save_p);
492 players[i].thrustfactor = READUINT8(save_p);
493 players[i].accelstart = READUINT8(save_p);
494 players[i].acceleration = READUINT8(save_p);
495 players[i].jumpfactor = READFIXED(save_p);
496 players[i].height = READFIXED(save_p);
497 players[i].spinheight = READFIXED(save_p);
498
499 players[i].viewheight = 41*players[i].height/48; // scale cannot be factored in at this point
500 }
501 }
502
503 ///
504 /// Colormaps
505 ///
506
507 static extracolormap_t *net_colormaps = NULL;
508 static UINT32 num_net_colormaps = 0;
509 static UINT32 num_ffloors = 0; // for loading
510
511 // Copypasta from r_data.c AddColormapToList
512 // But also check for equality and return the matching index
CheckAddNetColormapToList(extracolormap_t * extra_colormap)513 static UINT32 CheckAddNetColormapToList(extracolormap_t *extra_colormap)
514 {
515 extracolormap_t *exc, *exc_prev = NULL;
516 UINT32 i = 0;
517
518 if (!net_colormaps)
519 {
520 net_colormaps = R_CopyColormap(extra_colormap, false);
521 net_colormaps->next = 0;
522 net_colormaps->prev = 0;
523 num_net_colormaps = i+1;
524 return i;
525 }
526
527 for (exc = net_colormaps; exc; exc_prev = exc, exc = exc->next)
528 {
529 if (R_CheckEqualColormaps(exc, extra_colormap, true, true, true))
530 return i;
531 i++;
532 }
533
534 exc_prev->next = R_CopyColormap(extra_colormap, false);
535 extra_colormap->prev = exc_prev;
536 extra_colormap->next = 0;
537
538 num_net_colormaps = i+1;
539 return i;
540 }
541
GetNetColormapFromList(UINT32 index)542 static extracolormap_t *GetNetColormapFromList(UINT32 index)
543 {
544 // For loading, we have to be tricky:
545 // We load the sectors BEFORE knowing the colormap values
546 // So if an index doesn't exist, fill our list with dummy colormaps
547 // until we get the index we want
548 // Then when we load the color data, we set up the dummy colormaps
549
550 extracolormap_t *exc, *last_exc = NULL;
551 UINT32 i = 0;
552
553 if (!net_colormaps) // initialize our list
554 net_colormaps = R_CreateDefaultColormap(false);
555
556 for (exc = net_colormaps; exc; last_exc = exc, exc = exc->next)
557 {
558 if (i++ == index)
559 return exc;
560 }
561
562
563 // LET'S HOPE that index is a sane value, because we create up to [index]
564 // entries in net_colormaps. At this point, we don't know
565 // what the total colormap count is
566 if (index >= numsectors*3 + num_ffloors)
567 // if every sector had a unique colormap change AND a fade color thinker which has two colormap entries
568 // AND every ffloor had a fade FOF thinker with one colormap entry
569 I_Error("Colormap %d from server is too high for sectors %d", index, (UINT32)numsectors);
570
571 // our index doesn't exist, so just make the entry
572 for (; i <= index; i++)
573 {
574 exc = R_CreateDefaultColormap(false);
575 if (last_exc)
576 last_exc->next = exc;
577 exc->prev = last_exc;
578 exc->next = NULL;
579 last_exc = exc;
580 }
581 return exc;
582 }
583
ClearNetColormaps(void)584 static void ClearNetColormaps(void)
585 {
586 // We're actually Z_Freeing each entry here,
587 // so don't call this in P_NetUnArchiveColormaps (where entries will be used in-game)
588 extracolormap_t *exc, *exc_next;
589
590 for (exc = net_colormaps; exc; exc = exc_next)
591 {
592 exc_next = exc->next;
593 Z_Free(exc);
594 }
595 num_net_colormaps = 0;
596 num_ffloors = 0;
597 net_colormaps = NULL;
598 }
599
P_NetArchiveColormaps(void)600 static void P_NetArchiveColormaps(void)
601 {
602 // We save and then we clean up our colormap mess
603 extracolormap_t *exc, *exc_next;
604 UINT32 i = 0;
605 WRITEUINT32(save_p, num_net_colormaps); // save for safety
606
607 for (exc = net_colormaps; i < num_net_colormaps; i++, exc = exc_next)
608 {
609 // We must save num_net_colormaps worth of data
610 // So fill non-existent entries with default.
611 if (!exc)
612 exc = R_CreateDefaultColormap(false);
613
614 WRITEUINT8(save_p, exc->fadestart);
615 WRITEUINT8(save_p, exc->fadeend);
616 WRITEUINT8(save_p, exc->flags);
617
618 WRITEINT32(save_p, exc->rgba);
619 WRITEINT32(save_p, exc->fadergba);
620
621 #ifdef EXTRACOLORMAPLUMPS
622 WRITESTRINGN(save_p, exc->lumpname, 9);
623 #endif
624
625 exc_next = exc->next;
626 Z_Free(exc); // don't need anymore
627 }
628
629 num_net_colormaps = 0;
630 num_ffloors = 0;
631 net_colormaps = NULL;
632 }
633
P_NetUnArchiveColormaps(void)634 static void P_NetUnArchiveColormaps(void)
635 {
636 // When we reach this point, we already populated our list with
637 // dummy colormaps. Now that we are loading the color data,
638 // set up the dummies.
639 extracolormap_t *exc, *existing_exc, *exc_next = NULL;
640 UINT32 i = 0;
641
642 num_net_colormaps = READUINT32(save_p);
643
644 for (exc = net_colormaps; i < num_net_colormaps; i++, exc = exc_next)
645 {
646 UINT8 fadestart, fadeend, flags;
647 INT32 rgba, fadergba;
648 #ifdef EXTRACOLORMAPLUMPS
649 char lumpname[9];
650 #endif
651
652 fadestart = READUINT8(save_p);
653 fadeend = READUINT8(save_p);
654 flags = READUINT8(save_p);
655
656 rgba = READINT32(save_p);
657 fadergba = READINT32(save_p);
658
659 #ifdef EXTRACOLORMAPLUMPS
660 READSTRINGN(save_p, lumpname, 9);
661
662 if (lumpname[0])
663 {
664 if (!exc)
665 // no point making a new entry since nothing points to it,
666 // but we needed to read the data so now continue
667 continue;
668
669 exc_next = exc->next; // this gets overwritten during our operations here, so get it now
670 existing_exc = R_ColormapForName(lumpname);
671 *exc = *existing_exc;
672 R_AddColormapToList(exc); // see HACK note below on why we're adding duplicates
673 continue;
674 }
675 #endif
676
677 if (!exc)
678 // no point making a new entry since nothing points to it,
679 // but we needed to read the data so now continue
680 continue;
681
682 exc_next = exc->next; // this gets overwritten during our operations here, so get it now
683
684 exc->fadestart = fadestart;
685 exc->fadeend = fadeend;
686 exc->flags = flags;
687
688 exc->rgba = rgba;
689 exc->fadergba = fadergba;
690
691 #ifdef EXTRACOLORMAPLUMPS
692 exc->lump = LUMPERROR;
693 exc->lumpname[0] = 0;
694 #endif
695
696 existing_exc = R_GetColormapFromListByValues(rgba, fadergba, fadestart, fadeend, flags);
697
698 if (existing_exc)
699 exc->colormap = existing_exc->colormap;
700 else
701 // CONS_Debug(DBG_RENDER, "Creating Colormap: rgba(%d,%d,%d,%d) fadergba(%d,%d,%d,%d)\n",
702 // R_GetRgbaR(rgba), R_GetRgbaG(rgba), R_GetRgbaB(rgba), R_GetRgbaA(rgba),
703 // R_GetRgbaR(fadergba), R_GetRgbaG(fadergba), R_GetRgbaB(fadergba), R_GetRgbaA(fadergba));
704 exc->colormap = R_CreateLightTable(exc);
705
706 // HACK: If this dummy is a duplicate, we're going to add it
707 // to the extra_colormaps list anyway. I think this is faster
708 // than going through every loaded sector and correcting their
709 // colormap address to the pre-existing one, PER net_colormap entry
710 R_AddColormapToList(exc);
711
712 if (i < num_net_colormaps-1 && !exc_next)
713 exc_next = R_CreateDefaultColormap(false);
714 }
715
716 // if we still have a valid net_colormap after iterating up to num_net_colormaps,
717 // some sector had a colormap index higher than num_net_colormaps. We done goofed or $$$ was corrupted.
718 // In any case, add them to the colormap list too so that at least the sectors' colormap
719 // addresses are valid and accounted properly
720 if (exc_next)
721 {
722 existing_exc = R_GetDefaultColormap();
723 for (exc = exc_next; exc; exc = exc->next)
724 {
725 exc->colormap = existing_exc->colormap; // all our dummies are default values
726 R_AddColormapToList(exc);
727 }
728 }
729
730 // Don't need these anymore
731 num_net_colormaps = 0;
732 num_ffloors = 0;
733 net_colormaps = NULL;
734 }
735
P_NetArchiveWaypoints(void)736 static void P_NetArchiveWaypoints(void)
737 {
738 INT32 i, j;
739
740 for (i = 0; i < NUMWAYPOINTSEQUENCES; i++)
741 {
742 WRITEUINT16(save_p, numwaypoints[i]);
743 for (j = 0; j < numwaypoints[i]; j++)
744 WRITEUINT32(save_p, waypoints[i][j] ? waypoints[i][j]->mobjnum : 0);
745 }
746 }
747
P_NetUnArchiveWaypoints(void)748 static void P_NetUnArchiveWaypoints(void)
749 {
750 INT32 i, j;
751 UINT32 mobjnum;
752
753 for (i = 0; i < NUMWAYPOINTSEQUENCES; i++)
754 {
755 numwaypoints[i] = READUINT16(save_p);
756 for (j = 0; j < numwaypoints[i]; j++)
757 {
758 mobjnum = READUINT32(save_p);
759 waypoints[i][j] = (mobjnum == 0) ? NULL : P_FindNewPosition(mobjnum);
760 }
761 }
762 }
763
764 ///
765 /// World Archiving
766 ///
767
768 #define SD_FLOORHT 0x01
769 #define SD_CEILHT 0x02
770 #define SD_FLOORPIC 0x04
771 #define SD_CEILPIC 0x08
772 #define SD_LIGHT 0x10
773 #define SD_SPECIAL 0x20
774 #define SD_DIFF2 0x40
775 #define SD_FFLOORS 0x80
776
777 // diff2 flags
778 #define SD_FXOFFS 0x01
779 #define SD_FYOFFS 0x02
780 #define SD_CXOFFS 0x04
781 #define SD_CYOFFS 0x08
782 #define SD_FLOORANG 0x10
783 #define SD_CEILANG 0x20
784 #define SD_TAG 0x40
785 #define SD_DIFF3 0x80
786
787 // diff3 flags
788 #define SD_TAGLIST 0x01
789 #define SD_COLORMAP 0x02
790 #define SD_CRUMBLESTATE 0x04
791
792 #define LD_FLAG 0x01
793 #define LD_SPECIAL 0x02
794 #define LD_CLLCOUNT 0x04
795 #define LD_S1TEXOFF 0x08
796 #define LD_S1TOPTEX 0x10
797 #define LD_S1BOTTEX 0x20
798 #define LD_S1MIDTEX 0x40
799 #define LD_DIFF2 0x80
800
801 // diff2 flags
802 #define LD_S2TEXOFF 0x01
803 #define LD_S2TOPTEX 0x02
804 #define LD_S2BOTTEX 0x04
805 #define LD_S2MIDTEX 0x08
806 #define LD_ARGS 0x10
807 #define LD_STRINGARGS 0x20
808 #define LD_EXECUTORDELAY 0x40
809
P_AreArgsEqual(const line_t * li,const line_t * spawnli)810 static boolean P_AreArgsEqual(const line_t *li, const line_t *spawnli)
811 {
812 UINT8 i;
813 for (i = 0; i < NUMLINEARGS; i++)
814 if (li->args[i] != spawnli->args[i])
815 return false;
816
817 return true;
818 }
819
P_AreStringArgsEqual(const line_t * li,const line_t * spawnli)820 static boolean P_AreStringArgsEqual(const line_t *li, const line_t *spawnli)
821 {
822 UINT8 i;
823 for (i = 0; i < NUMLINESTRINGARGS; i++)
824 {
825 if (!li->stringargs[i])
826 return !spawnli->stringargs[i];
827
828 if (strcmp(li->stringargs[i], spawnli->stringargs[i]))
829 return false;
830 }
831
832 return true;
833 }
834
835 #define FD_FLAGS 0x01
836 #define FD_ALPHA 0x02
837
838 // Check if any of the sector's FOFs differ from how they spawned
CheckFFloorDiff(const sector_t * ss)839 static boolean CheckFFloorDiff(const sector_t *ss)
840 {
841 ffloor_t *rover;
842
843 for (rover = ss->ffloors; rover; rover = rover->next)
844 {
845 if (rover->flags != rover->spawnflags
846 || rover->alpha != rover->spawnalpha)
847 {
848 return true; // we found an FOF that changed!
849 // don't bother checking for more, we do that later
850 }
851 }
852 return false;
853 }
854
855 // Special case: save the stats of all modified ffloors along with their ffloor "number"s
856 // we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed
ArchiveFFloors(const sector_t * ss)857 static void ArchiveFFloors(const sector_t *ss)
858 {
859 size_t j = 0; // ss->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc
860 ffloor_t *rover;
861 UINT8 fflr_diff;
862 for (rover = ss->ffloors; rover; rover = rover->next)
863 {
864 fflr_diff = 0; // reset diff flags
865 if (rover->flags != rover->spawnflags)
866 fflr_diff |= FD_FLAGS;
867 if (rover->alpha != rover->spawnalpha)
868 fflr_diff |= FD_ALPHA;
869
870 if (fflr_diff)
871 {
872 WRITEUINT16(save_p, j); // save ffloor "number"
873 WRITEUINT8(save_p, fflr_diff);
874 if (fflr_diff & FD_FLAGS)
875 WRITEUINT32(save_p, rover->flags);
876 if (fflr_diff & FD_ALPHA)
877 WRITEINT16(save_p, rover->alpha);
878 }
879 j++;
880 }
881 WRITEUINT16(save_p, 0xffff);
882 }
883
UnArchiveFFloors(const sector_t * ss)884 static void UnArchiveFFloors(const sector_t *ss)
885 {
886 UINT16 j = 0; // number of current ffloor in loop
887 UINT16 fflr_i; // saved ffloor "number" of next modified ffloor
888 UINT16 fflr_diff; // saved ffloor diff
889 ffloor_t *rover;
890
891 rover = ss->ffloors;
892 if (!rover) // it is assumed sectors[i].ffloors actually exists, but just in case...
893 I_Error("Sector does not have any ffloors!");
894
895 fflr_i = READUINT16(save_p); // get first modified ffloor's number ready
896 for (;;) // for some reason the usual for (rover = x; ...) thing doesn't work here?
897 {
898 if (fflr_i == 0xffff) // end of modified ffloors list, let's stop already
899 break;
900 // should NEVER need to be checked
901 //if (rover == NULL)
902 //break;
903 if (j != fflr_i) // this ffloor was not modified
904 {
905 j++;
906 rover = rover->next;
907 continue;
908 }
909
910 fflr_diff = READUINT8(save_p);
911
912 if (fflr_diff & FD_FLAGS)
913 rover->flags = READUINT32(save_p);
914 if (fflr_diff & FD_ALPHA)
915 rover->alpha = READINT16(save_p);
916
917 fflr_i = READUINT16(save_p); // get next ffloor "number" ready
918
919 j++;
920 rover = rover->next;
921 }
922 }
923
ArchiveSectors(void)924 static void ArchiveSectors(void)
925 {
926 size_t i, j;
927 const sector_t *ss = sectors;
928 const sector_t *spawnss = spawnsectors;
929 UINT8 diff, diff2, diff3;
930
931 for (i = 0; i < numsectors; i++, ss++, spawnss++)
932 {
933 diff = diff2 = diff3 = 0;
934 if (ss->floorheight != spawnss->floorheight)
935 diff |= SD_FLOORHT;
936 if (ss->ceilingheight != spawnss->ceilingheight)
937 diff |= SD_CEILHT;
938 //
939 // flats
940 //
941 if (ss->floorpic != spawnss->floorpic)
942 diff |= SD_FLOORPIC;
943 if (ss->ceilingpic != spawnss->ceilingpic)
944 diff |= SD_CEILPIC;
945
946 if (ss->lightlevel != spawnss->lightlevel)
947 diff |= SD_LIGHT;
948 if (ss->special != spawnss->special)
949 diff |= SD_SPECIAL;
950
951 if (ss->floor_xoffs != spawnss->floor_xoffs)
952 diff2 |= SD_FXOFFS;
953 if (ss->floor_yoffs != spawnss->floor_yoffs)
954 diff2 |= SD_FYOFFS;
955 if (ss->ceiling_xoffs != spawnss->ceiling_xoffs)
956 diff2 |= SD_CXOFFS;
957 if (ss->ceiling_yoffs != spawnss->ceiling_yoffs)
958 diff2 |= SD_CYOFFS;
959 if (ss->floorpic_angle != spawnss->floorpic_angle)
960 diff2 |= SD_FLOORANG;
961 if (ss->ceilingpic_angle != spawnss->ceilingpic_angle)
962 diff2 |= SD_CEILANG;
963
964 if (!Tag_Compare(&ss->tags, &spawnss->tags))
965 diff2 |= SD_TAG;
966
967 if (ss->extra_colormap != spawnss->extra_colormap)
968 diff3 |= SD_COLORMAP;
969 if (ss->crumblestate)
970 diff3 |= SD_CRUMBLESTATE;
971
972 if (ss->ffloors && CheckFFloorDiff(ss))
973 diff |= SD_FFLOORS;
974
975 if (diff3)
976 diff2 |= SD_DIFF3;
977
978 if (diff2)
979 diff |= SD_DIFF2;
980
981 if (diff)
982 {
983 WRITEUINT16(save_p, i);
984 WRITEUINT8(save_p, diff);
985 if (diff & SD_DIFF2)
986 WRITEUINT8(save_p, diff2);
987 if (diff2 & SD_DIFF3)
988 WRITEUINT8(save_p, diff3);
989 if (diff & SD_FLOORHT)
990 WRITEFIXED(save_p, ss->floorheight);
991 if (diff & SD_CEILHT)
992 WRITEFIXED(save_p, ss->ceilingheight);
993 if (diff & SD_FLOORPIC)
994 WRITEMEM(save_p, levelflats[ss->floorpic].name, 8);
995 if (diff & SD_CEILPIC)
996 WRITEMEM(save_p, levelflats[ss->ceilingpic].name, 8);
997 if (diff & SD_LIGHT)
998 WRITEINT16(save_p, ss->lightlevel);
999 if (diff & SD_SPECIAL)
1000 WRITEINT16(save_p, ss->special);
1001 if (diff2 & SD_FXOFFS)
1002 WRITEFIXED(save_p, ss->floor_xoffs);
1003 if (diff2 & SD_FYOFFS)
1004 WRITEFIXED(save_p, ss->floor_yoffs);
1005 if (diff2 & SD_CXOFFS)
1006 WRITEFIXED(save_p, ss->ceiling_xoffs);
1007 if (diff2 & SD_CYOFFS)
1008 WRITEFIXED(save_p, ss->ceiling_yoffs);
1009 if (diff2 & SD_FLOORANG)
1010 WRITEANGLE(save_p, ss->floorpic_angle);
1011 if (diff2 & SD_CEILANG)
1012 WRITEANGLE(save_p, ss->ceilingpic_angle);
1013 if (diff2 & SD_TAG)
1014 {
1015 WRITEUINT32(save_p, ss->tags.count);
1016 for (j = 0; j < ss->tags.count; j++)
1017 WRITEINT16(save_p, ss->tags.tags[j]);
1018 }
1019
1020 if (diff3 & SD_COLORMAP)
1021 WRITEUINT32(save_p, CheckAddNetColormapToList(ss->extra_colormap));
1022 // returns existing index if already added, or appends to net_colormaps and returns new index
1023 if (diff3 & SD_CRUMBLESTATE)
1024 WRITEINT32(save_p, ss->crumblestate);
1025 if (diff & SD_FFLOORS)
1026 ArchiveFFloors(ss);
1027 }
1028 }
1029
1030 WRITEUINT16(save_p, 0xffff);
1031 }
1032
UnArchiveSectors(void)1033 static void UnArchiveSectors(void)
1034 {
1035 UINT16 i, j;
1036 UINT8 diff, diff2, diff3;
1037 for (;;)
1038 {
1039 i = READUINT16(save_p);
1040
1041 if (i == 0xffff)
1042 break;
1043
1044 if (i > numsectors)
1045 I_Error("Invalid sector number %u from server (expected end at %s)", i, sizeu1(numsectors));
1046
1047 diff = READUINT8(save_p);
1048 if (diff & SD_DIFF2)
1049 diff2 = READUINT8(save_p);
1050 else
1051 diff2 = 0;
1052 if (diff2 & SD_DIFF3)
1053 diff3 = READUINT8(save_p);
1054 else
1055 diff3 = 0;
1056
1057 if (diff & SD_FLOORHT)
1058 sectors[i].floorheight = READFIXED(save_p);
1059 if (diff & SD_CEILHT)
1060 sectors[i].ceilingheight = READFIXED(save_p);
1061 if (diff & SD_FLOORPIC)
1062 {
1063 sectors[i].floorpic = P_AddLevelFlatRuntime((char *)save_p);
1064 save_p += 8;
1065 }
1066 if (diff & SD_CEILPIC)
1067 {
1068 sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)save_p);
1069 save_p += 8;
1070 }
1071 if (diff & SD_LIGHT)
1072 sectors[i].lightlevel = READINT16(save_p);
1073 if (diff & SD_SPECIAL)
1074 sectors[i].special = READINT16(save_p);
1075
1076 if (diff2 & SD_FXOFFS)
1077 sectors[i].floor_xoffs = READFIXED(save_p);
1078 if (diff2 & SD_FYOFFS)
1079 sectors[i].floor_yoffs = READFIXED(save_p);
1080 if (diff2 & SD_CXOFFS)
1081 sectors[i].ceiling_xoffs = READFIXED(save_p);
1082 if (diff2 & SD_CYOFFS)
1083 sectors[i].ceiling_yoffs = READFIXED(save_p);
1084 if (diff2 & SD_FLOORANG)
1085 sectors[i].floorpic_angle = READANGLE(save_p);
1086 if (diff2 & SD_CEILANG)
1087 sectors[i].ceilingpic_angle = READANGLE(save_p);
1088 if (diff2 & SD_TAG)
1089 {
1090 size_t ncount = READUINT32(save_p);
1091
1092 // Remove entries from global lists.
1093 for (j = 0; j < sectors[i].tags.count; j++)
1094 Taggroup_Remove(tags_sectors, sectors[i].tags.tags[j], i);
1095
1096 // Reallocate if size differs.
1097 if (ncount != sectors[i].tags.count)
1098 {
1099 sectors[i].tags.count = ncount;
1100 sectors[i].tags.tags = Z_Realloc(sectors[i].tags.tags, ncount*sizeof(mtag_t), PU_LEVEL, NULL);
1101 }
1102
1103 for (j = 0; j < ncount; j++)
1104 sectors[i].tags.tags[j] = READINT16(save_p);
1105
1106 // Add new entries.
1107 for (j = 0; j < sectors[i].tags.count; j++)
1108 Taggroup_Remove(tags_sectors, sectors[i].tags.tags[j], i);
1109 }
1110
1111
1112 if (diff3 & SD_COLORMAP)
1113 sectors[i].extra_colormap = GetNetColormapFromList(READUINT32(save_p));
1114 if (diff3 & SD_CRUMBLESTATE)
1115 sectors[i].crumblestate = READINT32(save_p);
1116
1117 if (diff & SD_FFLOORS)
1118 UnArchiveFFloors(§ors[i]);
1119 }
1120 }
1121
ArchiveLines(void)1122 static void ArchiveLines(void)
1123 {
1124 size_t i;
1125 const line_t *li = lines;
1126 const line_t *spawnli = spawnlines;
1127 const side_t *si;
1128 const side_t *spawnsi;
1129 UINT8 diff, diff2; // no diff3
1130
1131 for (i = 0; i < numlines; i++, spawnli++, li++)
1132 {
1133 diff = diff2 = 0;
1134
1135 if (li->special != spawnli->special)
1136 diff |= LD_SPECIAL;
1137
1138 if (spawnli->special == 321 || spawnli->special == 322) // only reason li->callcount would be non-zero is if either of these are involved
1139 diff |= LD_CLLCOUNT;
1140
1141 if (!P_AreArgsEqual(li, spawnli))
1142 diff2 |= LD_ARGS;
1143
1144 if (!P_AreStringArgsEqual(li, spawnli))
1145 diff2 |= LD_STRINGARGS;
1146
1147 if (li->executordelay != spawnli->executordelay)
1148 diff2 |= LD_EXECUTORDELAY;
1149
1150 if (li->sidenum[0] != 0xffff)
1151 {
1152 si = &sides[li->sidenum[0]];
1153 spawnsi = &spawnsides[li->sidenum[0]];
1154 if (si->textureoffset != spawnsi->textureoffset)
1155 diff |= LD_S1TEXOFF;
1156 //SoM: 4/1/2000: Some textures are colormaps. Don't worry about invalid textures.
1157 if (si->toptexture != spawnsi->toptexture)
1158 diff |= LD_S1TOPTEX;
1159 if (si->bottomtexture != spawnsi->bottomtexture)
1160 diff |= LD_S1BOTTEX;
1161 if (si->midtexture != spawnsi->midtexture)
1162 diff |= LD_S1MIDTEX;
1163 }
1164 if (li->sidenum[1] != 0xffff)
1165 {
1166 si = &sides[li->sidenum[1]];
1167 spawnsi = &spawnsides[li->sidenum[1]];
1168 if (si->textureoffset != spawnsi->textureoffset)
1169 diff2 |= LD_S2TEXOFF;
1170 if (si->toptexture != spawnsi->toptexture)
1171 diff2 |= LD_S2TOPTEX;
1172 if (si->bottomtexture != spawnsi->bottomtexture)
1173 diff2 |= LD_S2BOTTEX;
1174 if (si->midtexture != spawnsi->midtexture)
1175 diff2 |= LD_S2MIDTEX;
1176 }
1177
1178 if (diff2)
1179 diff |= LD_DIFF2;
1180
1181 if (diff)
1182 {
1183 WRITEINT16(save_p, i);
1184 WRITEUINT8(save_p, diff);
1185 if (diff & LD_DIFF2)
1186 WRITEUINT8(save_p, diff2);
1187 if (diff & LD_FLAG)
1188 WRITEINT16(save_p, li->flags);
1189 if (diff & LD_SPECIAL)
1190 WRITEINT16(save_p, li->special);
1191 if (diff & LD_CLLCOUNT)
1192 WRITEINT16(save_p, li->callcount);
1193
1194 si = &sides[li->sidenum[0]];
1195 if (diff & LD_S1TEXOFF)
1196 WRITEFIXED(save_p, si->textureoffset);
1197 if (diff & LD_S1TOPTEX)
1198 WRITEINT32(save_p, si->toptexture);
1199 if (diff & LD_S1BOTTEX)
1200 WRITEINT32(save_p, si->bottomtexture);
1201 if (diff & LD_S1MIDTEX)
1202 WRITEINT32(save_p, si->midtexture);
1203
1204 si = &sides[li->sidenum[1]];
1205 if (diff2 & LD_S2TEXOFF)
1206 WRITEFIXED(save_p, si->textureoffset);
1207 if (diff2 & LD_S2TOPTEX)
1208 WRITEINT32(save_p, si->toptexture);
1209 if (diff2 & LD_S2BOTTEX)
1210 WRITEINT32(save_p, si->bottomtexture);
1211 if (diff2 & LD_S2MIDTEX)
1212 WRITEINT32(save_p, si->midtexture);
1213 if (diff2 & LD_ARGS)
1214 {
1215 UINT8 j;
1216 for (j = 0; j < NUMLINEARGS; j++)
1217 WRITEINT32(save_p, li->args[j]);
1218 }
1219 if (diff2 & LD_STRINGARGS)
1220 {
1221 UINT8 j;
1222 for (j = 0; j < NUMLINESTRINGARGS; j++)
1223 {
1224 size_t len, k;
1225
1226 if (!li->stringargs[j])
1227 {
1228 WRITEINT32(save_p, 0);
1229 continue;
1230 }
1231
1232 len = strlen(li->stringargs[j]);
1233 WRITEINT32(save_p, len);
1234 for (k = 0; k < len; k++)
1235 WRITECHAR(save_p, li->stringargs[j][k]);
1236 }
1237 }
1238 if (diff2 & LD_EXECUTORDELAY)
1239 WRITEINT32(save_p, li->executordelay);
1240 }
1241 }
1242 WRITEUINT16(save_p, 0xffff);
1243 }
1244
UnArchiveLines(void)1245 static void UnArchiveLines(void)
1246 {
1247 UINT16 i;
1248 line_t *li;
1249 side_t *si;
1250 UINT8 diff, diff2; // no diff3
1251
1252 for (;;)
1253 {
1254 i = READUINT16(save_p);
1255
1256 if (i == 0xffff)
1257 break;
1258 if (i > numlines)
1259 I_Error("Invalid line number %u from server", i);
1260
1261 diff = READUINT8(save_p);
1262 li = &lines[i];
1263
1264 if (diff & LD_DIFF2)
1265 diff2 = READUINT8(save_p);
1266 else
1267 diff2 = 0;
1268
1269 if (diff & LD_FLAG)
1270 li->flags = READINT16(save_p);
1271 if (diff & LD_SPECIAL)
1272 li->special = READINT16(save_p);
1273 if (diff & LD_CLLCOUNT)
1274 li->callcount = READINT16(save_p);
1275
1276 si = &sides[li->sidenum[0]];
1277 if (diff & LD_S1TEXOFF)
1278 si->textureoffset = READFIXED(save_p);
1279 if (diff & LD_S1TOPTEX)
1280 si->toptexture = READINT32(save_p);
1281 if (diff & LD_S1BOTTEX)
1282 si->bottomtexture = READINT32(save_p);
1283 if (diff & LD_S1MIDTEX)
1284 si->midtexture = READINT32(save_p);
1285
1286 si = &sides[li->sidenum[1]];
1287 if (diff2 & LD_S2TEXOFF)
1288 si->textureoffset = READFIXED(save_p);
1289 if (diff2 & LD_S2TOPTEX)
1290 si->toptexture = READINT32(save_p);
1291 if (diff2 & LD_S2BOTTEX)
1292 si->bottomtexture = READINT32(save_p);
1293 if (diff2 & LD_S2MIDTEX)
1294 si->midtexture = READINT32(save_p);
1295 if (diff2 & LD_ARGS)
1296 {
1297 UINT8 j;
1298 for (j = 0; j < NUMLINEARGS; j++)
1299 li->args[j] = READINT32(save_p);
1300 }
1301 if (diff2 & LD_STRINGARGS)
1302 {
1303 UINT8 j;
1304 for (j = 0; j < NUMLINESTRINGARGS; j++)
1305 {
1306 size_t len = READINT32(save_p);
1307 size_t k;
1308
1309 if (!len)
1310 {
1311 Z_Free(li->stringargs[j]);
1312 li->stringargs[j] = NULL;
1313 continue;
1314 }
1315
1316 li->stringargs[j] = Z_Realloc(li->stringargs[j], len + 1, PU_LEVEL, NULL);
1317 for (k = 0; k < len; k++)
1318 li->stringargs[j][k] = READCHAR(save_p);
1319 li->stringargs[j][len] = '\0';
1320 }
1321 }
1322 if (diff2 & LD_EXECUTORDELAY)
1323 li->executordelay = READINT32(save_p);
1324
1325 }
1326 }
1327
P_NetArchiveWorld(void)1328 static void P_NetArchiveWorld(void)
1329 {
1330 // initialize colormap vars because paranoia
1331 ClearNetColormaps();
1332
1333 WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD);
1334
1335 ArchiveSectors();
1336 ArchiveLines();
1337 R_ClearTextureNumCache(false);
1338 }
1339
P_NetUnArchiveWorld(void)1340 static void P_NetUnArchiveWorld(void)
1341 {
1342 UINT16 i;
1343
1344 if (READUINT32(save_p) != ARCHIVEBLOCK_WORLD)
1345 I_Error("Bad $$$.sav at archive block World");
1346
1347 // initialize colormap vars because paranoia
1348 ClearNetColormaps();
1349
1350 // count the level's ffloors so that colormap loading can have an upper limit
1351 for (i = 0; i < numsectors; i++)
1352 {
1353 ffloor_t *rover;
1354 for (rover = sectors[i].ffloors; rover; rover = rover->next)
1355 num_ffloors++;
1356 }
1357
1358 UnArchiveSectors();
1359 UnArchiveLines();
1360 }
1361
1362 //
1363 // Thinkers
1364 //
1365
1366 typedef enum
1367 {
1368 MD_SPAWNPOINT = 1,
1369 MD_POS = 1<<1,
1370 MD_TYPE = 1<<2,
1371 MD_MOM = 1<<3,
1372 MD_RADIUS = 1<<4,
1373 MD_HEIGHT = 1<<5,
1374 MD_FLAGS = 1<<6,
1375 MD_HEALTH = 1<<7,
1376 MD_RTIME = 1<<8,
1377 MD_STATE = 1<<9,
1378 MD_TICS = 1<<10,
1379 MD_SPRITE = 1<<11,
1380 MD_FRAME = 1<<12,
1381 MD_EFLAGS = 1<<13,
1382 MD_PLAYER = 1<<14,
1383 MD_MOVEDIR = 1<<15,
1384 MD_MOVECOUNT = 1<<16,
1385 MD_THRESHOLD = 1<<17,
1386 MD_LASTLOOK = 1<<18,
1387 MD_TARGET = 1<<19,
1388 MD_TRACER = 1<<20,
1389 MD_FRICTION = 1<<21,
1390 MD_MOVEFACTOR = 1<<22,
1391 MD_FLAGS2 = 1<<23,
1392 MD_FUSE = 1<<24,
1393 MD_WATERTOP = 1<<25,
1394 MD_WATERBOTTOM = 1<<26,
1395 MD_SCALE = 1<<27,
1396 MD_DSCALE = 1<<28,
1397 MD_BLUEFLAG = 1<<29,
1398 MD_REDFLAG = 1<<30,
1399 MD_MORE = 1<<31
1400 } mobj_diff_t;
1401
1402 typedef enum
1403 {
1404 MD2_CUSVAL = 1,
1405 MD2_CVMEM = 1<<1,
1406 MD2_SKIN = 1<<2,
1407 MD2_COLOR = 1<<3,
1408 MD2_SCALESPEED = 1<<4,
1409 MD2_EXTVAL1 = 1<<5,
1410 MD2_EXTVAL2 = 1<<6,
1411 MD2_HNEXT = 1<<7,
1412 MD2_HPREV = 1<<8,
1413 MD2_FLOORROVER = 1<<9,
1414 MD2_CEILINGROVER = 1<<10,
1415 MD2_SLOPE = 1<<11,
1416 MD2_COLORIZED = 1<<12,
1417 MD2_MIRRORED = 1<<13,
1418 MD2_ROLLANGLE = 1<<14,
1419 MD2_SHADOWSCALE = 1<<15,
1420 MD2_RENDERFLAGS = 1<<16,
1421 MD2_BLENDMODE = 1<<17,
1422 MD2_SPRITEXSCALE = 1<<18,
1423 MD2_SPRITEYSCALE = 1<<19,
1424 MD2_SPRITEXOFFSET = 1<<20,
1425 MD2_SPRITEYOFFSET = 1<<21,
1426 MD2_FLOORSPRITESLOPE = 1<<22,
1427 } mobj_diff2_t;
1428
1429 typedef enum
1430 {
1431 tc_mobj,
1432 tc_ceiling,
1433 tc_floor,
1434 tc_flash,
1435 tc_strobe,
1436 tc_glow,
1437 tc_fireflicker,
1438 tc_thwomp,
1439 tc_camerascanner,
1440 tc_elevator,
1441 tc_continuousfalling,
1442 tc_bouncecheese,
1443 tc_startcrumble,
1444 tc_marioblock,
1445 tc_marioblockchecker,
1446 tc_floatsector,
1447 tc_crushceiling,
1448 tc_scroll,
1449 tc_friction,
1450 tc_pusher,
1451 tc_laserflash,
1452 tc_lightfade,
1453 tc_executor,
1454 tc_raisesector,
1455 tc_noenemies,
1456 tc_eachtime,
1457 tc_disappear,
1458 tc_fade,
1459 tc_fadecolormap,
1460 tc_planedisplace,
1461 tc_dynslopeline,
1462 tc_dynslopevert,
1463 tc_polyrotate, // haleyjd 03/26/06: polyobjects
1464 tc_polymove,
1465 tc_polywaypoint,
1466 tc_polyslidedoor,
1467 tc_polyswingdoor,
1468 tc_polyflag,
1469 tc_polydisplace,
1470 tc_polyrotdisplace,
1471 tc_polyfade,
1472 tc_end
1473 } specials_e;
1474
SaveMobjnum(const mobj_t * mobj)1475 static inline UINT32 SaveMobjnum(const mobj_t *mobj)
1476 {
1477 if (mobj) return mobj->mobjnum;
1478 return 0;
1479 }
1480
SaveSector(const sector_t * sector)1481 static UINT32 SaveSector(const sector_t *sector)
1482 {
1483 if (sector) return (UINT32)(sector - sectors);
1484 return 0xFFFFFFFF;
1485 }
1486
SaveLine(const line_t * line)1487 static UINT32 SaveLine(const line_t *line)
1488 {
1489 if (line) return (UINT32)(line - lines);
1490 return 0xFFFFFFFF;
1491 }
1492
SavePlayer(const player_t * player)1493 static inline UINT32 SavePlayer(const player_t *player)
1494 {
1495 if (player) return (UINT32)(player - players);
1496 return 0xFFFFFFFF;
1497 }
1498
SaveSlope(const pslope_t * slope)1499 static UINT32 SaveSlope(const pslope_t *slope)
1500 {
1501 if (slope) return (UINT32)(slope->id);
1502 return 0xFFFFFFFF;
1503 }
1504
SaveMobjThinker(const thinker_t * th,const UINT8 type)1505 static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
1506 {
1507 const mobj_t *mobj = (const mobj_t *)th;
1508 UINT32 diff;
1509 UINT32 diff2;
1510
1511 // Ignore stationary hoops - these will be respawned from mapthings.
1512 if (mobj->type == MT_HOOP)
1513 return;
1514
1515 // These are NEVER saved.
1516 if (mobj->type == MT_HOOPCOLLIDE)
1517 return;
1518
1519 // This hoop has already been collected.
1520 if (mobj->type == MT_HOOPCENTER && mobj->threshold == 4242)
1521 return;
1522
1523 if (mobj->spawnpoint && mobj->info->doomednum != -1)
1524 {
1525 // spawnpoint is not modified but we must save it since it is an identifier
1526 diff = MD_SPAWNPOINT;
1527
1528 if ((mobj->x != mobj->spawnpoint->x << FRACBITS) ||
1529 (mobj->y != mobj->spawnpoint->y << FRACBITS) ||
1530 (mobj->angle != FixedAngle(mobj->spawnpoint->angle*FRACUNIT)) ||
1531 (mobj->pitch != FixedAngle(mobj->spawnpoint->pitch*FRACUNIT)) ||
1532 (mobj->roll != FixedAngle(mobj->spawnpoint->roll*FRACUNIT)) )
1533 diff |= MD_POS;
1534
1535 if (mobj->info->doomednum != mobj->spawnpoint->type)
1536 diff |= MD_TYPE;
1537 }
1538 else
1539 diff = MD_POS | MD_TYPE; // not a map spawned thing so make it from scratch
1540
1541 diff2 = 0;
1542
1543 // not the default but the most probable
1544 if (mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0)
1545 diff |= MD_MOM;
1546 if (mobj->radius != mobj->info->radius)
1547 diff |= MD_RADIUS;
1548 if (mobj->height != mobj->info->height)
1549 diff |= MD_HEIGHT;
1550 if (mobj->flags != mobj->info->flags)
1551 diff |= MD_FLAGS;
1552 if (mobj->flags2)
1553 diff |= MD_FLAGS2;
1554 if (mobj->health != mobj->info->spawnhealth)
1555 diff |= MD_HEALTH;
1556 if (mobj->reactiontime != mobj->info->reactiontime)
1557 diff |= MD_RTIME;
1558 if ((statenum_t)(mobj->state-states) != mobj->info->spawnstate)
1559 diff |= MD_STATE;
1560 if (mobj->tics != mobj->state->tics)
1561 diff |= MD_TICS;
1562 if (mobj->sprite != mobj->state->sprite)
1563 diff |= MD_SPRITE;
1564 if (mobj->sprite == SPR_PLAY && mobj->sprite2 != (mobj->state->frame&FF_FRAMEMASK))
1565 diff |= MD_SPRITE;
1566 if (mobj->frame != mobj->state->frame)
1567 diff |= MD_FRAME;
1568 if (mobj->anim_duration != (UINT16)mobj->state->var2)
1569 diff |= MD_FRAME;
1570 if (mobj->eflags)
1571 diff |= MD_EFLAGS;
1572 if (mobj->player)
1573 diff |= MD_PLAYER;
1574
1575 if (mobj->movedir)
1576 diff |= MD_MOVEDIR;
1577 if (mobj->movecount)
1578 diff |= MD_MOVECOUNT;
1579 if (mobj->threshold)
1580 diff |= MD_THRESHOLD;
1581 if (mobj->lastlook != -1)
1582 diff |= MD_LASTLOOK;
1583 if (mobj->target)
1584 diff |= MD_TARGET;
1585 if (mobj->tracer)
1586 diff |= MD_TRACER;
1587 if (mobj->friction != ORIG_FRICTION)
1588 diff |= MD_FRICTION;
1589 if (mobj->movefactor != FRACUNIT)
1590 diff |= MD_MOVEFACTOR;
1591 if (mobj->fuse)
1592 diff |= MD_FUSE;
1593 if (mobj->watertop)
1594 diff |= MD_WATERTOP;
1595 if (mobj->waterbottom)
1596 diff |= MD_WATERBOTTOM;
1597 if (mobj->scale != FRACUNIT)
1598 diff |= MD_SCALE;
1599 if (mobj->destscale != mobj->scale)
1600 diff |= MD_DSCALE;
1601 if (mobj->scalespeed != FRACUNIT/12)
1602 diff2 |= MD2_SCALESPEED;
1603
1604 if (mobj == redflag)
1605 diff |= MD_REDFLAG;
1606 if (mobj == blueflag)
1607 diff |= MD_BLUEFLAG;
1608
1609 if (mobj->cusval)
1610 diff2 |= MD2_CUSVAL;
1611 if (mobj->cvmem)
1612 diff2 |= MD2_CVMEM;
1613 if (mobj->color)
1614 diff2 |= MD2_COLOR;
1615 if (mobj->skin)
1616 diff2 |= MD2_SKIN;
1617 if (mobj->extravalue1)
1618 diff2 |= MD2_EXTVAL1;
1619 if (mobj->extravalue2)
1620 diff2 |= MD2_EXTVAL2;
1621 if (mobj->hnext)
1622 diff2 |= MD2_HNEXT;
1623 if (mobj->hprev)
1624 diff2 |= MD2_HPREV;
1625 if (mobj->floorrover)
1626 diff2 |= MD2_FLOORROVER;
1627 if (mobj->ceilingrover)
1628 diff2 |= MD2_CEILINGROVER;
1629 if (mobj->standingslope)
1630 diff2 |= MD2_SLOPE;
1631 if (mobj->colorized)
1632 diff2 |= MD2_COLORIZED;
1633 if (mobj->mirrored)
1634 diff2 |= MD2_MIRRORED;
1635 if (mobj->rollangle)
1636 diff2 |= MD2_ROLLANGLE;
1637 if (mobj->shadowscale)
1638 diff2 |= MD2_SHADOWSCALE;
1639 if (mobj->renderflags)
1640 diff2 |= MD2_RENDERFLAGS;
1641 if (mobj->blendmode != AST_TRANSLUCENT)
1642 diff2 |= MD2_BLENDMODE;
1643 if (mobj->spritexscale != FRACUNIT)
1644 diff2 |= MD2_SPRITEXSCALE;
1645 if (mobj->spriteyscale != FRACUNIT)
1646 diff2 |= MD2_SPRITEYSCALE;
1647 if (mobj->spritexoffset)
1648 diff2 |= MD2_SPRITEXOFFSET;
1649 if (mobj->spriteyoffset)
1650 diff2 |= MD2_SPRITEYOFFSET;
1651 if (mobj->floorspriteslope)
1652 {
1653 pslope_t *slope = mobj->floorspriteslope;
1654 if (slope->zangle || slope->zdelta || slope->xydirection
1655 || slope->o.x || slope->o.y || slope->o.z
1656 || slope->d.x || slope->d.y
1657 || slope->normal.x || slope->normal.y
1658 || (slope->normal.z != FRACUNIT))
1659 diff2 |= MD2_FLOORSPRITESLOPE;
1660 }
1661
1662 if (diff2 != 0)
1663 diff |= MD_MORE;
1664
1665 // Scrap all of that. If we're a hoop center, this is ALL we're saving.
1666 if (mobj->type == MT_HOOPCENTER)
1667 diff = MD_SPAWNPOINT;
1668
1669 WRITEUINT8(save_p, type);
1670 WRITEUINT32(save_p, diff);
1671 if (diff & MD_MORE)
1672 WRITEUINT32(save_p, diff2);
1673
1674 // save pointer, at load time we will search this pointer to reinitilize pointers
1675 WRITEUINT32(save_p, (size_t)mobj);
1676
1677 WRITEFIXED(save_p, mobj->z); // Force this so 3dfloor problems don't arise.
1678 WRITEFIXED(save_p, mobj->floorz);
1679 WRITEFIXED(save_p, mobj->ceilingz);
1680
1681 if (diff2 & MD2_FLOORROVER)
1682 {
1683 WRITEUINT32(save_p, SaveSector(mobj->floorrover->target));
1684 WRITEUINT16(save_p, P_GetFFloorID(mobj->floorrover));
1685 }
1686
1687 if (diff2 & MD2_CEILINGROVER)
1688 {
1689 WRITEUINT32(save_p, SaveSector(mobj->ceilingrover->target));
1690 WRITEUINT16(save_p, P_GetFFloorID(mobj->ceilingrover));
1691 }
1692
1693 if (diff & MD_SPAWNPOINT)
1694 {
1695 size_t z;
1696
1697 for (z = 0; z < nummapthings; z++)
1698 if (&mapthings[z] == mobj->spawnpoint)
1699 WRITEUINT16(save_p, z);
1700 if (mobj->type == MT_HOOPCENTER)
1701 return;
1702 }
1703
1704 if (diff & MD_TYPE)
1705 WRITEUINT32(save_p, mobj->type);
1706 if (diff & MD_POS)
1707 {
1708 WRITEFIXED(save_p, mobj->x);
1709 WRITEFIXED(save_p, mobj->y);
1710 WRITEANGLE(save_p, mobj->angle);
1711 WRITEANGLE(save_p, mobj->pitch);
1712 WRITEANGLE(save_p, mobj->roll);
1713 }
1714 if (diff & MD_MOM)
1715 {
1716 WRITEFIXED(save_p, mobj->momx);
1717 WRITEFIXED(save_p, mobj->momy);
1718 WRITEFIXED(save_p, mobj->momz);
1719 }
1720 if (diff & MD_RADIUS)
1721 WRITEFIXED(save_p, mobj->radius);
1722 if (diff & MD_HEIGHT)
1723 WRITEFIXED(save_p, mobj->height);
1724 if (diff & MD_FLAGS)
1725 WRITEUINT32(save_p, mobj->flags);
1726 if (diff & MD_FLAGS2)
1727 WRITEUINT32(save_p, mobj->flags2);
1728 if (diff & MD_HEALTH)
1729 WRITEINT32(save_p, mobj->health);
1730 if (diff & MD_RTIME)
1731 WRITEINT32(save_p, mobj->reactiontime);
1732 if (diff & MD_STATE)
1733 WRITEUINT16(save_p, mobj->state-states);
1734 if (diff & MD_TICS)
1735 WRITEINT32(save_p, mobj->tics);
1736 if (diff & MD_SPRITE) {
1737 WRITEUINT16(save_p, mobj->sprite);
1738 if (mobj->sprite == SPR_PLAY)
1739 WRITEUINT8(save_p, mobj->sprite2);
1740 }
1741 if (diff & MD_FRAME)
1742 {
1743 WRITEUINT32(save_p, mobj->frame);
1744 WRITEUINT16(save_p, mobj->anim_duration);
1745 }
1746 if (diff & MD_EFLAGS)
1747 WRITEUINT16(save_p, mobj->eflags);
1748 if (diff & MD_PLAYER)
1749 WRITEUINT8(save_p, mobj->player-players);
1750 if (diff & MD_MOVEDIR)
1751 WRITEANGLE(save_p, mobj->movedir);
1752 if (diff & MD_MOVECOUNT)
1753 WRITEINT32(save_p, mobj->movecount);
1754 if (diff & MD_THRESHOLD)
1755 WRITEINT32(save_p, mobj->threshold);
1756 if (diff & MD_LASTLOOK)
1757 WRITEINT32(save_p, mobj->lastlook);
1758 if (diff & MD_TARGET)
1759 WRITEUINT32(save_p, mobj->target->mobjnum);
1760 if (diff & MD_TRACER)
1761 WRITEUINT32(save_p, mobj->tracer->mobjnum);
1762 if (diff & MD_FRICTION)
1763 WRITEFIXED(save_p, mobj->friction);
1764 if (diff & MD_MOVEFACTOR)
1765 WRITEFIXED(save_p, mobj->movefactor);
1766 if (diff & MD_FUSE)
1767 WRITEINT32(save_p, mobj->fuse);
1768 if (diff & MD_WATERTOP)
1769 WRITEFIXED(save_p, mobj->watertop);
1770 if (diff & MD_WATERBOTTOM)
1771 WRITEFIXED(save_p, mobj->waterbottom);
1772 if (diff & MD_SCALE)
1773 WRITEFIXED(save_p, mobj->scale);
1774 if (diff & MD_DSCALE)
1775 WRITEFIXED(save_p, mobj->destscale);
1776 if (diff2 & MD2_SCALESPEED)
1777 WRITEFIXED(save_p, mobj->scalespeed);
1778 if (diff2 & MD2_CUSVAL)
1779 WRITEINT32(save_p, mobj->cusval);
1780 if (diff2 & MD2_CVMEM)
1781 WRITEINT32(save_p, mobj->cvmem);
1782 if (diff2 & MD2_SKIN)
1783 WRITEUINT8(save_p, (UINT8)((skin_t *)mobj->skin - skins));
1784 if (diff2 & MD2_COLOR)
1785 WRITEUINT16(save_p, mobj->color);
1786 if (diff2 & MD2_EXTVAL1)
1787 WRITEINT32(save_p, mobj->extravalue1);
1788 if (diff2 & MD2_EXTVAL2)
1789 WRITEINT32(save_p, mobj->extravalue2);
1790 if (diff2 & MD2_HNEXT)
1791 WRITEUINT32(save_p, mobj->hnext->mobjnum);
1792 if (diff2 & MD2_HPREV)
1793 WRITEUINT32(save_p, mobj->hprev->mobjnum);
1794 if (diff2 & MD2_SLOPE)
1795 WRITEUINT16(save_p, mobj->standingslope->id);
1796 if (diff2 & MD2_COLORIZED)
1797 WRITEUINT8(save_p, mobj->colorized);
1798 if (diff2 & MD2_MIRRORED)
1799 WRITEUINT8(save_p, mobj->mirrored);
1800 if (diff2 & MD2_ROLLANGLE)
1801 WRITEANGLE(save_p, mobj->rollangle);
1802 if (diff2 & MD2_SHADOWSCALE)
1803 WRITEFIXED(save_p, mobj->shadowscale);
1804 if (diff2 & MD2_RENDERFLAGS)
1805 WRITEUINT32(save_p, mobj->renderflags);
1806 if (diff2 & MD2_BLENDMODE)
1807 WRITEINT32(save_p, mobj->blendmode);
1808 if (diff2 & MD2_SPRITEXSCALE)
1809 WRITEFIXED(save_p, mobj->spritexscale);
1810 if (diff2 & MD2_SPRITEYSCALE)
1811 WRITEFIXED(save_p, mobj->spriteyscale);
1812 if (diff2 & MD2_SPRITEXOFFSET)
1813 WRITEFIXED(save_p, mobj->spritexoffset);
1814 if (diff2 & MD2_SPRITEYOFFSET)
1815 WRITEFIXED(save_p, mobj->spriteyoffset);
1816 if (diff2 & MD2_FLOORSPRITESLOPE)
1817 {
1818 pslope_t *slope = mobj->floorspriteslope;
1819
1820 WRITEFIXED(save_p, slope->zdelta);
1821 WRITEANGLE(save_p, slope->zangle);
1822 WRITEANGLE(save_p, slope->xydirection);
1823
1824 WRITEFIXED(save_p, slope->o.x);
1825 WRITEFIXED(save_p, slope->o.y);
1826 WRITEFIXED(save_p, slope->o.z);
1827
1828 WRITEFIXED(save_p, slope->d.x);
1829 WRITEFIXED(save_p, slope->d.y);
1830
1831 WRITEFIXED(save_p, slope->normal.x);
1832 WRITEFIXED(save_p, slope->normal.y);
1833 WRITEFIXED(save_p, slope->normal.z);
1834 }
1835
1836 WRITEUINT32(save_p, mobj->mobjnum);
1837 }
1838
SaveNoEnemiesThinker(const thinker_t * th,const UINT8 type)1839 static void SaveNoEnemiesThinker(const thinker_t *th, const UINT8 type)
1840 {
1841 const noenemies_t *ht = (const void *)th;
1842 WRITEUINT8(save_p, type);
1843 WRITEUINT32(save_p, SaveLine(ht->sourceline));
1844 }
1845
SaveBounceCheeseThinker(const thinker_t * th,const UINT8 type)1846 static void SaveBounceCheeseThinker(const thinker_t *th, const UINT8 type)
1847 {
1848 const bouncecheese_t *ht = (const void *)th;
1849 WRITEUINT8(save_p, type);
1850 WRITEUINT32(save_p, SaveLine(ht->sourceline));
1851 WRITEUINT32(save_p, SaveSector(ht->sector));
1852 WRITEFIXED(save_p, ht->speed);
1853 WRITEFIXED(save_p, ht->distance);
1854 WRITEFIXED(save_p, ht->floorwasheight);
1855 WRITEFIXED(save_p, ht->ceilingwasheight);
1856 WRITECHAR(save_p, ht->low);
1857 }
1858
SaveContinuousFallThinker(const thinker_t * th,const UINT8 type)1859 static void SaveContinuousFallThinker(const thinker_t *th, const UINT8 type)
1860 {
1861 const continuousfall_t *ht = (const void *)th;
1862 WRITEUINT8(save_p, type);
1863 WRITEUINT32(save_p, SaveSector(ht->sector));
1864 WRITEFIXED(save_p, ht->speed);
1865 WRITEINT32(save_p, ht->direction);
1866 WRITEFIXED(save_p, ht->floorstartheight);
1867 WRITEFIXED(save_p, ht->ceilingstartheight);
1868 WRITEFIXED(save_p, ht->destheight);
1869 }
1870
SaveMarioBlockThinker(const thinker_t * th,const UINT8 type)1871 static void SaveMarioBlockThinker(const thinker_t *th, const UINT8 type)
1872 {
1873 const mariothink_t *ht = (const void *)th;
1874 WRITEUINT8(save_p, type);
1875 WRITEUINT32(save_p, SaveSector(ht->sector));
1876 WRITEFIXED(save_p, ht->speed);
1877 WRITEINT32(save_p, ht->direction);
1878 WRITEFIXED(save_p, ht->floorstartheight);
1879 WRITEFIXED(save_p, ht->ceilingstartheight);
1880 WRITEINT16(save_p, ht->tag);
1881 }
1882
SaveMarioCheckThinker(const thinker_t * th,const UINT8 type)1883 static void SaveMarioCheckThinker(const thinker_t *th, const UINT8 type)
1884 {
1885 const mariocheck_t *ht = (const void *)th;
1886 WRITEUINT8(save_p, type);
1887 WRITEUINT32(save_p, SaveLine(ht->sourceline));
1888 WRITEUINT32(save_p, SaveSector(ht->sector));
1889 }
1890
SaveThwompThinker(const thinker_t * th,const UINT8 type)1891 static void SaveThwompThinker(const thinker_t *th, const UINT8 type)
1892 {
1893 const thwomp_t *ht = (const void *)th;
1894 WRITEUINT8(save_p, type);
1895 WRITEUINT32(save_p, SaveLine(ht->sourceline));
1896 WRITEUINT32(save_p, SaveSector(ht->sector));
1897 WRITEFIXED(save_p, ht->crushspeed);
1898 WRITEFIXED(save_p, ht->retractspeed);
1899 WRITEINT32(save_p, ht->direction);
1900 WRITEFIXED(save_p, ht->floorstartheight);
1901 WRITEFIXED(save_p, ht->ceilingstartheight);
1902 WRITEINT32(save_p, ht->delay);
1903 WRITEINT16(save_p, ht->tag);
1904 WRITEUINT16(save_p, ht->sound);
1905 }
1906
SaveFloatThinker(const thinker_t * th,const UINT8 type)1907 static void SaveFloatThinker(const thinker_t *th, const UINT8 type)
1908 {
1909 const floatthink_t *ht = (const void *)th;
1910 WRITEUINT8(save_p, type);
1911 WRITEUINT32(save_p, SaveLine(ht->sourceline));
1912 WRITEUINT32(save_p, SaveSector(ht->sector));
1913 WRITEINT16(save_p, ht->tag);
1914 }
1915
SaveEachTimeThinker(const thinker_t * th,const UINT8 type)1916 static void SaveEachTimeThinker(const thinker_t *th, const UINT8 type)
1917 {
1918 const eachtime_t *ht = (const void *)th;
1919 size_t i;
1920 WRITEUINT8(save_p, type);
1921 WRITEUINT32(save_p, SaveLine(ht->sourceline));
1922 for (i = 0; i < MAXPLAYERS; i++)
1923 {
1924 WRITECHAR(save_p, ht->playersInArea[i]);
1925 WRITECHAR(save_p, ht->playersOnArea[i]);
1926 }
1927 WRITECHAR(save_p, ht->triggerOnExit);
1928 }
1929
SaveRaiseThinker(const thinker_t * th,const UINT8 type)1930 static void SaveRaiseThinker(const thinker_t *th, const UINT8 type)
1931 {
1932 const raise_t *ht = (const void *)th;
1933 WRITEUINT8(save_p, type);
1934 WRITEINT16(save_p, ht->tag);
1935 WRITEUINT32(save_p, SaveSector(ht->sector));
1936 WRITEFIXED(save_p, ht->ceilingbottom);
1937 WRITEFIXED(save_p, ht->ceilingtop);
1938 WRITEFIXED(save_p, ht->basespeed);
1939 WRITEFIXED(save_p, ht->extraspeed);
1940 WRITEUINT8(save_p, ht->shaketimer);
1941 WRITEUINT8(save_p, ht->flags);
1942 }
1943
SaveCeilingThinker(const thinker_t * th,const UINT8 type)1944 static void SaveCeilingThinker(const thinker_t *th, const UINT8 type)
1945 {
1946 const ceiling_t *ht = (const void *)th;
1947 WRITEUINT8(save_p, type);
1948 WRITEUINT8(save_p, ht->type);
1949 WRITEUINT32(save_p, SaveSector(ht->sector));
1950 WRITEFIXED(save_p, ht->bottomheight);
1951 WRITEFIXED(save_p, ht->topheight);
1952 WRITEFIXED(save_p, ht->speed);
1953 WRITEFIXED(save_p, ht->oldspeed);
1954 WRITEFIXED(save_p, ht->delay);
1955 WRITEFIXED(save_p, ht->delaytimer);
1956 WRITEUINT8(save_p, ht->crush);
1957 WRITEINT32(save_p, ht->texture);
1958 WRITEINT32(save_p, ht->direction);
1959 WRITEINT32(save_p, ht->tag);
1960 WRITEINT32(save_p, ht->olddirection);
1961 WRITEFIXED(save_p, ht->origspeed);
1962 WRITEFIXED(save_p, ht->sourceline);
1963 }
1964
SaveFloormoveThinker(const thinker_t * th,const UINT8 type)1965 static void SaveFloormoveThinker(const thinker_t *th, const UINT8 type)
1966 {
1967 const floormove_t *ht = (const void *)th;
1968 WRITEUINT8(save_p, type);
1969 WRITEUINT8(save_p, ht->type);
1970 WRITEUINT8(save_p, ht->crush);
1971 WRITEUINT32(save_p, SaveSector(ht->sector));
1972 WRITEINT32(save_p, ht->direction);
1973 WRITEINT32(save_p, ht->texture);
1974 WRITEFIXED(save_p, ht->floordestheight);
1975 WRITEFIXED(save_p, ht->speed);
1976 WRITEFIXED(save_p, ht->origspeed);
1977 WRITEFIXED(save_p, ht->delay);
1978 WRITEFIXED(save_p, ht->delaytimer);
1979 }
1980
SaveLightflashThinker(const thinker_t * th,const UINT8 type)1981 static void SaveLightflashThinker(const thinker_t *th, const UINT8 type)
1982 {
1983 const lightflash_t *ht = (const void *)th;
1984 WRITEUINT8(save_p, type);
1985 WRITEUINT32(save_p, SaveSector(ht->sector));
1986 WRITEINT32(save_p, ht->maxlight);
1987 WRITEINT32(save_p, ht->minlight);
1988 }
1989
SaveStrobeThinker(const thinker_t * th,const UINT8 type)1990 static void SaveStrobeThinker(const thinker_t *th, const UINT8 type)
1991 {
1992 const strobe_t *ht = (const void *)th;
1993 WRITEUINT8(save_p, type);
1994 WRITEUINT32(save_p, SaveSector(ht->sector));
1995 WRITEINT32(save_p, ht->count);
1996 WRITEINT32(save_p, ht->minlight);
1997 WRITEINT32(save_p, ht->maxlight);
1998 WRITEINT32(save_p, ht->darktime);
1999 WRITEINT32(save_p, ht->brighttime);
2000 }
2001
SaveGlowThinker(const thinker_t * th,const UINT8 type)2002 static void SaveGlowThinker(const thinker_t *th, const UINT8 type)
2003 {
2004 const glow_t *ht = (const void *)th;
2005 WRITEUINT8(save_p, type);
2006 WRITEUINT32(save_p, SaveSector(ht->sector));
2007 WRITEINT32(save_p, ht->minlight);
2008 WRITEINT32(save_p, ht->maxlight);
2009 WRITEINT32(save_p, ht->direction);
2010 WRITEINT32(save_p, ht->speed);
2011 }
2012
SaveFireflickerThinker(const thinker_t * th,const UINT8 type)2013 static inline void SaveFireflickerThinker(const thinker_t *th, const UINT8 type)
2014 {
2015 const fireflicker_t *ht = (const void *)th;
2016 WRITEUINT8(save_p, type);
2017 WRITEUINT32(save_p, SaveSector(ht->sector));
2018 WRITEINT32(save_p, ht->count);
2019 WRITEINT32(save_p, ht->resetcount);
2020 WRITEINT32(save_p, ht->maxlight);
2021 WRITEINT32(save_p, ht->minlight);
2022 }
2023
SaveElevatorThinker(const thinker_t * th,const UINT8 type)2024 static void SaveElevatorThinker(const thinker_t *th, const UINT8 type)
2025 {
2026 const elevator_t *ht = (const void *)th;
2027 WRITEUINT8(save_p, type);
2028 WRITEUINT8(save_p, ht->type);
2029 WRITEUINT32(save_p, SaveSector(ht->sector));
2030 WRITEUINT32(save_p, SaveSector(ht->actionsector));
2031 WRITEINT32(save_p, ht->direction);
2032 WRITEFIXED(save_p, ht->floordestheight);
2033 WRITEFIXED(save_p, ht->ceilingdestheight);
2034 WRITEFIXED(save_p, ht->speed);
2035 WRITEFIXED(save_p, ht->origspeed);
2036 WRITEFIXED(save_p, ht->low);
2037 WRITEFIXED(save_p, ht->high);
2038 WRITEFIXED(save_p, ht->distance);
2039 WRITEFIXED(save_p, ht->delay);
2040 WRITEFIXED(save_p, ht->delaytimer);
2041 WRITEFIXED(save_p, ht->floorwasheight);
2042 WRITEFIXED(save_p, ht->ceilingwasheight);
2043 WRITEUINT32(save_p, SaveLine(ht->sourceline));
2044 }
2045
SaveCrumbleThinker(const thinker_t * th,const UINT8 type)2046 static void SaveCrumbleThinker(const thinker_t *th, const UINT8 type)
2047 {
2048 const crumble_t *ht = (const void *)th;
2049 WRITEUINT8(save_p, type);
2050 WRITEUINT32(save_p, SaveLine(ht->sourceline));
2051 WRITEUINT32(save_p, SaveSector(ht->sector));
2052 WRITEUINT32(save_p, SaveSector(ht->actionsector));
2053 WRITEUINT32(save_p, SavePlayer(ht->player)); // was dummy
2054 WRITEINT32(save_p, ht->direction);
2055 WRITEINT32(save_p, ht->origalpha);
2056 WRITEINT32(save_p, ht->timer);
2057 WRITEFIXED(save_p, ht->speed);
2058 WRITEFIXED(save_p, ht->floorwasheight);
2059 WRITEFIXED(save_p, ht->ceilingwasheight);
2060 WRITEUINT8(save_p, ht->flags);
2061 }
2062
SaveScrollThinker(const thinker_t * th,const UINT8 type)2063 static inline void SaveScrollThinker(const thinker_t *th, const UINT8 type)
2064 {
2065 const scroll_t *ht = (const void *)th;
2066 WRITEUINT8(save_p, type);
2067 WRITEFIXED(save_p, ht->dx);
2068 WRITEFIXED(save_p, ht->dy);
2069 WRITEINT32(save_p, ht->affectee);
2070 WRITEINT32(save_p, ht->control);
2071 WRITEFIXED(save_p, ht->last_height);
2072 WRITEFIXED(save_p, ht->vdx);
2073 WRITEFIXED(save_p, ht->vdy);
2074 WRITEINT32(save_p, ht->accel);
2075 WRITEINT32(save_p, ht->exclusive);
2076 WRITEUINT8(save_p, ht->type);
2077 }
2078
SaveFrictionThinker(const thinker_t * th,const UINT8 type)2079 static inline void SaveFrictionThinker(const thinker_t *th, const UINT8 type)
2080 {
2081 const friction_t *ht = (const void *)th;
2082 WRITEUINT8(save_p, type);
2083 WRITEINT32(save_p, ht->friction);
2084 WRITEINT32(save_p, ht->movefactor);
2085 WRITEINT32(save_p, ht->affectee);
2086 WRITEINT32(save_p, ht->referrer);
2087 WRITEUINT8(save_p, ht->roverfriction);
2088 }
2089
SavePusherThinker(const thinker_t * th,const UINT8 type)2090 static inline void SavePusherThinker(const thinker_t *th, const UINT8 type)
2091 {
2092 const pusher_t *ht = (const void *)th;
2093 WRITEUINT8(save_p, type);
2094 WRITEUINT8(save_p, ht->type);
2095 WRITEINT32(save_p, ht->x_mag);
2096 WRITEINT32(save_p, ht->y_mag);
2097 WRITEINT32(save_p, ht->magnitude);
2098 WRITEINT32(save_p, ht->radius);
2099 WRITEINT32(save_p, ht->x);
2100 WRITEINT32(save_p, ht->y);
2101 WRITEINT32(save_p, ht->z);
2102 WRITEINT32(save_p, ht->affectee);
2103 WRITEUINT8(save_p, ht->roverpusher);
2104 WRITEINT32(save_p, ht->referrer);
2105 WRITEINT32(save_p, ht->exclusive);
2106 WRITEINT32(save_p, ht->slider);
2107 }
2108
SaveLaserThinker(const thinker_t * th,const UINT8 type)2109 static void SaveLaserThinker(const thinker_t *th, const UINT8 type)
2110 {
2111 const laserthink_t *ht = (const void *)th;
2112 WRITEUINT8(save_p, type);
2113 WRITEINT16(save_p, ht->tag);
2114 WRITEUINT32(save_p, SaveLine(ht->sourceline));
2115 WRITEUINT8(save_p, ht->nobosses);
2116 }
2117
SaveLightlevelThinker(const thinker_t * th,const UINT8 type)2118 static void SaveLightlevelThinker(const thinker_t *th, const UINT8 type)
2119 {
2120 const lightlevel_t *ht = (const void *)th;
2121 WRITEUINT8(save_p, type);
2122 WRITEUINT32(save_p, SaveSector(ht->sector));
2123 WRITEINT16(save_p, ht->sourcelevel);
2124 WRITEINT16(save_p, ht->destlevel);
2125 WRITEFIXED(save_p, ht->fixedcurlevel);
2126 WRITEFIXED(save_p, ht->fixedpertic);
2127 WRITEINT32(save_p, ht->timer);
2128 }
2129
SaveExecutorThinker(const thinker_t * th,const UINT8 type)2130 static void SaveExecutorThinker(const thinker_t *th, const UINT8 type)
2131 {
2132 const executor_t *ht = (const void *)th;
2133 WRITEUINT8(save_p, type);
2134 WRITEUINT32(save_p, SaveLine(ht->line));
2135 WRITEUINT32(save_p, SaveMobjnum(ht->caller));
2136 WRITEUINT32(save_p, SaveSector(ht->sector));
2137 WRITEINT32(save_p, ht->timer);
2138 }
2139
SaveDisappearThinker(const thinker_t * th,const UINT8 type)2140 static void SaveDisappearThinker(const thinker_t *th, const UINT8 type)
2141 {
2142 const disappear_t *ht = (const void *)th;
2143 WRITEUINT8(save_p, type);
2144 WRITEUINT32(save_p, ht->appeartime);
2145 WRITEUINT32(save_p, ht->disappeartime);
2146 WRITEUINT32(save_p, ht->offset);
2147 WRITEUINT32(save_p, ht->timer);
2148 WRITEINT32(save_p, ht->affectee);
2149 WRITEINT32(save_p, ht->sourceline);
2150 WRITEINT32(save_p, ht->exists);
2151 }
2152
SaveFadeThinker(const thinker_t * th,const UINT8 type)2153 static void SaveFadeThinker(const thinker_t *th, const UINT8 type)
2154 {
2155 const fade_t *ht = (const void *)th;
2156 WRITEUINT8(save_p, type);
2157 WRITEUINT32(save_p, CheckAddNetColormapToList(ht->dest_exc));
2158 WRITEUINT32(save_p, ht->sectornum);
2159 WRITEUINT32(save_p, ht->ffloornum);
2160 WRITEINT32(save_p, ht->alpha);
2161 WRITEINT16(save_p, ht->sourcevalue);
2162 WRITEINT16(save_p, ht->destvalue);
2163 WRITEINT16(save_p, ht->destlightlevel);
2164 WRITEINT16(save_p, ht->speed);
2165 WRITEUINT8(save_p, (UINT8)ht->ticbased);
2166 WRITEINT32(save_p, ht->timer);
2167 WRITEUINT8(save_p, ht->doexists);
2168 WRITEUINT8(save_p, ht->dotranslucent);
2169 WRITEUINT8(save_p, ht->dolighting);
2170 WRITEUINT8(save_p, ht->docolormap);
2171 WRITEUINT8(save_p, ht->docollision);
2172 WRITEUINT8(save_p, ht->doghostfade);
2173 WRITEUINT8(save_p, ht->exactalpha);
2174 }
2175
SaveFadeColormapThinker(const thinker_t * th,const UINT8 type)2176 static void SaveFadeColormapThinker(const thinker_t *th, const UINT8 type)
2177 {
2178 const fadecolormap_t *ht = (const void *)th;
2179 WRITEUINT8(save_p, type);
2180 WRITEUINT32(save_p, SaveSector(ht->sector));
2181 WRITEUINT32(save_p, CheckAddNetColormapToList(ht->source_exc));
2182 WRITEUINT32(save_p, CheckAddNetColormapToList(ht->dest_exc));
2183 WRITEUINT8(save_p, (UINT8)ht->ticbased);
2184 WRITEINT32(save_p, ht->duration);
2185 WRITEINT32(save_p, ht->timer);
2186 }
2187
SavePlaneDisplaceThinker(const thinker_t * th,const UINT8 type)2188 static void SavePlaneDisplaceThinker(const thinker_t *th, const UINT8 type)
2189 {
2190 const planedisplace_t *ht = (const void *)th;
2191 WRITEUINT8(save_p, type);
2192 WRITEINT32(save_p, ht->affectee);
2193 WRITEINT32(save_p, ht->control);
2194 WRITEFIXED(save_p, ht->last_height);
2195 WRITEFIXED(save_p, ht->speed);
2196 WRITEUINT8(save_p, ht->type);
2197 }
2198
SaveDynamicSlopeThinker(const thinker_t * th,const UINT8 type)2199 static inline void SaveDynamicSlopeThinker(const thinker_t *th, const UINT8 type)
2200 {
2201 const dynplanethink_t* ht = (const void*)th;
2202
2203 WRITEUINT8(save_p, type);
2204 WRITEUINT8(save_p, ht->type);
2205 WRITEUINT32(save_p, SaveSlope(ht->slope));
2206 WRITEUINT32(save_p, SaveLine(ht->sourceline));
2207 WRITEFIXED(save_p, ht->extent);
2208
2209 WRITEMEM(save_p, ht->tags, sizeof(ht->tags));
2210 WRITEMEM(save_p, ht->vex, sizeof(ht->vex));
2211 }
2212
SavePolyrotatetThinker(const thinker_t * th,const UINT8 type)2213 static inline void SavePolyrotatetThinker(const thinker_t *th, const UINT8 type)
2214 {
2215 const polyrotate_t *ht = (const void *)th;
2216 WRITEUINT8(save_p, type);
2217 WRITEINT32(save_p, ht->polyObjNum);
2218 WRITEINT32(save_p, ht->speed);
2219 WRITEINT32(save_p, ht->distance);
2220 WRITEUINT8(save_p, ht->turnobjs);
2221 }
2222
SavePolymoveThinker(const thinker_t * th,const UINT8 type)2223 static void SavePolymoveThinker(const thinker_t *th, const UINT8 type)
2224 {
2225 const polymove_t *ht = (const void *)th;
2226 WRITEUINT8(save_p, type);
2227 WRITEINT32(save_p, ht->polyObjNum);
2228 WRITEINT32(save_p, ht->speed);
2229 WRITEFIXED(save_p, ht->momx);
2230 WRITEFIXED(save_p, ht->momy);
2231 WRITEINT32(save_p, ht->distance);
2232 WRITEANGLE(save_p, ht->angle);
2233 }
2234
SavePolywaypointThinker(const thinker_t * th,UINT8 type)2235 static void SavePolywaypointThinker(const thinker_t *th, UINT8 type)
2236 {
2237 const polywaypoint_t *ht = (const void *)th;
2238 WRITEUINT8(save_p, type);
2239 WRITEINT32(save_p, ht->polyObjNum);
2240 WRITEINT32(save_p, ht->speed);
2241 WRITEINT32(save_p, ht->sequence);
2242 WRITEINT32(save_p, ht->pointnum);
2243 WRITEINT32(save_p, ht->direction);
2244 WRITEUINT8(save_p, ht->returnbehavior);
2245 WRITEUINT8(save_p, ht->continuous);
2246 WRITEUINT8(save_p, ht->stophere);
2247 }
2248
SavePolyslidedoorThinker(const thinker_t * th,const UINT8 type)2249 static void SavePolyslidedoorThinker(const thinker_t *th, const UINT8 type)
2250 {
2251 const polyslidedoor_t *ht = (const void *)th;
2252 WRITEUINT8(save_p, type);
2253 WRITEINT32(save_p, ht->polyObjNum);
2254 WRITEINT32(save_p, ht->delay);
2255 WRITEINT32(save_p, ht->delayCount);
2256 WRITEINT32(save_p, ht->initSpeed);
2257 WRITEINT32(save_p, ht->speed);
2258 WRITEINT32(save_p, ht->initDistance);
2259 WRITEINT32(save_p, ht->distance);
2260 WRITEUINT32(save_p, ht->initAngle);
2261 WRITEUINT32(save_p, ht->angle);
2262 WRITEUINT32(save_p, ht->revAngle);
2263 WRITEFIXED(save_p, ht->momx);
2264 WRITEFIXED(save_p, ht->momy);
2265 WRITEUINT8(save_p, ht->closing);
2266 }
2267
SavePolyswingdoorThinker(const thinker_t * th,const UINT8 type)2268 static void SavePolyswingdoorThinker(const thinker_t *th, const UINT8 type)
2269 {
2270 const polyswingdoor_t *ht = (const void *)th;
2271 WRITEUINT8(save_p, type);
2272 WRITEINT32(save_p, ht->polyObjNum);
2273 WRITEINT32(save_p, ht->delay);
2274 WRITEINT32(save_p, ht->delayCount);
2275 WRITEINT32(save_p, ht->initSpeed);
2276 WRITEINT32(save_p, ht->speed);
2277 WRITEINT32(save_p, ht->initDistance);
2278 WRITEINT32(save_p, ht->distance);
2279 WRITEUINT8(save_p, ht->closing);
2280 }
2281
SavePolydisplaceThinker(const thinker_t * th,const UINT8 type)2282 static void SavePolydisplaceThinker(const thinker_t *th, const UINT8 type)
2283 {
2284 const polydisplace_t *ht = (const void *)th;
2285 WRITEUINT8(save_p, type);
2286 WRITEINT32(save_p, ht->polyObjNum);
2287 WRITEUINT32(save_p, SaveSector(ht->controlSector));
2288 WRITEFIXED(save_p, ht->dx);
2289 WRITEFIXED(save_p, ht->dy);
2290 WRITEFIXED(save_p, ht->oldHeights);
2291 }
2292
SavePolyrotdisplaceThinker(const thinker_t * th,const UINT8 type)2293 static void SavePolyrotdisplaceThinker(const thinker_t *th, const UINT8 type)
2294 {
2295 const polyrotdisplace_t *ht = (const void *)th;
2296 WRITEUINT8(save_p, type);
2297 WRITEINT32(save_p, ht->polyObjNum);
2298 WRITEUINT32(save_p, SaveSector(ht->controlSector));
2299 WRITEFIXED(save_p, ht->rotscale);
2300 WRITEUINT8(save_p, ht->turnobjs);
2301 WRITEFIXED(save_p, ht->oldHeights);
2302 }
2303
SavePolyfadeThinker(const thinker_t * th,const UINT8 type)2304 static void SavePolyfadeThinker(const thinker_t *th, const UINT8 type)
2305 {
2306 const polyfade_t *ht = (const void *)th;
2307 WRITEUINT8(save_p, type);
2308 WRITEINT32(save_p, ht->polyObjNum);
2309 WRITEINT32(save_p, ht->sourcevalue);
2310 WRITEINT32(save_p, ht->destvalue);
2311 WRITEUINT8(save_p, (UINT8)ht->docollision);
2312 WRITEUINT8(save_p, (UINT8)ht->doghostfade);
2313 WRITEUINT8(save_p, (UINT8)ht->ticbased);
2314 WRITEINT32(save_p, ht->duration);
2315 WRITEINT32(save_p, ht->timer);
2316 }
2317
P_NetArchiveThinkers(void)2318 static void P_NetArchiveThinkers(void)
2319 {
2320 const thinker_t *th;
2321 UINT32 i;
2322
2323 WRITEUINT32(save_p, ARCHIVEBLOCK_THINKERS);
2324
2325 for (i = 0; i < NUM_THINKERLISTS; i++)
2326 {
2327 UINT32 numsaved = 0;
2328 // save off the current thinkers
2329 for (th = thlist[i].next; th != &thlist[i]; th = th->next)
2330 {
2331 if (!(th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed
2332 || th->function.acp1 == (actionf_p1)P_NullPrecipThinker))
2333 numsaved++;
2334
2335 if (th->function.acp1 == (actionf_p1)P_MobjThinker)
2336 {
2337 SaveMobjThinker(th, tc_mobj);
2338 continue;
2339 }
2340 #ifdef PARANOIA
2341 else if (th->function.acp1 == (actionf_p1)P_NullPrecipThinker);
2342 #endif
2343 else if (th->function.acp1 == (actionf_p1)T_MoveCeiling)
2344 {
2345 SaveCeilingThinker(th, tc_ceiling);
2346 continue;
2347 }
2348 else if (th->function.acp1 == (actionf_p1)T_CrushCeiling)
2349 {
2350 SaveCeilingThinker(th, tc_crushceiling);
2351 continue;
2352 }
2353 else if (th->function.acp1 == (actionf_p1)T_MoveFloor)
2354 {
2355 SaveFloormoveThinker(th, tc_floor);
2356 continue;
2357 }
2358 else if (th->function.acp1 == (actionf_p1)T_LightningFlash)
2359 {
2360 SaveLightflashThinker(th, tc_flash);
2361 continue;
2362 }
2363 else if (th->function.acp1 == (actionf_p1)T_StrobeFlash)
2364 {
2365 SaveStrobeThinker(th, tc_strobe);
2366 continue;
2367 }
2368 else if (th->function.acp1 == (actionf_p1)T_Glow)
2369 {
2370 SaveGlowThinker(th, tc_glow);
2371 continue;
2372 }
2373 else if (th->function.acp1 == (actionf_p1)T_FireFlicker)
2374 {
2375 SaveFireflickerThinker(th, tc_fireflicker);
2376 continue;
2377 }
2378 else if (th->function.acp1 == (actionf_p1)T_MoveElevator)
2379 {
2380 SaveElevatorThinker(th, tc_elevator);
2381 continue;
2382 }
2383 else if (th->function.acp1 == (actionf_p1)T_ContinuousFalling)
2384 {
2385 SaveContinuousFallThinker(th, tc_continuousfalling);
2386 continue;
2387 }
2388 else if (th->function.acp1 == (actionf_p1)T_ThwompSector)
2389 {
2390 SaveThwompThinker(th, tc_thwomp);
2391 continue;
2392 }
2393 else if (th->function.acp1 == (actionf_p1)T_NoEnemiesSector)
2394 {
2395 SaveNoEnemiesThinker(th, tc_noenemies);
2396 continue;
2397 }
2398 else if (th->function.acp1 == (actionf_p1)T_EachTimeThinker)
2399 {
2400 SaveEachTimeThinker(th, tc_eachtime);
2401 continue;
2402 }
2403 else if (th->function.acp1 == (actionf_p1)T_RaiseSector)
2404 {
2405 SaveRaiseThinker(th, tc_raisesector);
2406 continue;
2407 }
2408 else if (th->function.acp1 == (actionf_p1)T_CameraScanner)
2409 {
2410 SaveElevatorThinker(th, tc_camerascanner);
2411 continue;
2412 }
2413 else if (th->function.acp1 == (actionf_p1)T_Scroll)
2414 {
2415 SaveScrollThinker(th, tc_scroll);
2416 continue;
2417 }
2418 else if (th->function.acp1 == (actionf_p1)T_Friction)
2419 {
2420 SaveFrictionThinker(th, tc_friction);
2421 continue;
2422 }
2423 else if (th->function.acp1 == (actionf_p1)T_Pusher)
2424 {
2425 SavePusherThinker(th, tc_pusher);
2426 continue;
2427 }
2428 else if (th->function.acp1 == (actionf_p1)T_BounceCheese)
2429 {
2430 SaveBounceCheeseThinker(th, tc_bouncecheese);
2431 continue;
2432 }
2433 else if (th->function.acp1 == (actionf_p1)T_StartCrumble)
2434 {
2435 SaveCrumbleThinker(th, tc_startcrumble);
2436 continue;
2437 }
2438 else if (th->function.acp1 == (actionf_p1)T_MarioBlock)
2439 {
2440 SaveMarioBlockThinker(th, tc_marioblock);
2441 continue;
2442 }
2443 else if (th->function.acp1 == (actionf_p1)T_MarioBlockChecker)
2444 {
2445 SaveMarioCheckThinker(th, tc_marioblockchecker);
2446 continue;
2447 }
2448 else if (th->function.acp1 == (actionf_p1)T_FloatSector)
2449 {
2450 SaveFloatThinker(th, tc_floatsector);
2451 continue;
2452 }
2453 else if (th->function.acp1 == (actionf_p1)T_LaserFlash)
2454 {
2455 SaveLaserThinker(th, tc_laserflash);
2456 continue;
2457 }
2458 else if (th->function.acp1 == (actionf_p1)T_LightFade)
2459 {
2460 SaveLightlevelThinker(th, tc_lightfade);
2461 continue;
2462 }
2463 else if (th->function.acp1 == (actionf_p1)T_ExecutorDelay)
2464 {
2465 SaveExecutorThinker(th, tc_executor);
2466 continue;
2467 }
2468 else if (th->function.acp1 == (actionf_p1)T_Disappear)
2469 {
2470 SaveDisappearThinker(th, tc_disappear);
2471 continue;
2472 }
2473 else if (th->function.acp1 == (actionf_p1)T_Fade)
2474 {
2475 SaveFadeThinker(th, tc_fade);
2476 continue;
2477 }
2478 else if (th->function.acp1 == (actionf_p1)T_FadeColormap)
2479 {
2480 SaveFadeColormapThinker(th, tc_fadecolormap);
2481 continue;
2482 }
2483 else if (th->function.acp1 == (actionf_p1)T_PlaneDisplace)
2484 {
2485 SavePlaneDisplaceThinker(th, tc_planedisplace);
2486 continue;
2487 }
2488 else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate)
2489 {
2490 SavePolyrotatetThinker(th, tc_polyrotate);
2491 continue;
2492 }
2493 else if (th->function.acp1 == (actionf_p1)T_PolyObjMove)
2494 {
2495 SavePolymoveThinker(th, tc_polymove);
2496 continue;
2497 }
2498 else if (th->function.acp1 == (actionf_p1)T_PolyObjWaypoint)
2499 {
2500 SavePolywaypointThinker(th, tc_polywaypoint);
2501 continue;
2502 }
2503 else if (th->function.acp1 == (actionf_p1)T_PolyDoorSlide)
2504 {
2505 SavePolyslidedoorThinker(th, tc_polyslidedoor);
2506 continue;
2507 }
2508 else if (th->function.acp1 == (actionf_p1)T_PolyDoorSwing)
2509 {
2510 SavePolyswingdoorThinker(th, tc_polyswingdoor);
2511 continue;
2512 }
2513 else if (th->function.acp1 == (actionf_p1)T_PolyObjFlag)
2514 {
2515 SavePolymoveThinker(th, tc_polyflag);
2516 continue;
2517 }
2518 else if (th->function.acp1 == (actionf_p1)T_PolyObjDisplace)
2519 {
2520 SavePolydisplaceThinker(th, tc_polydisplace);
2521 continue;
2522 }
2523 else if (th->function.acp1 == (actionf_p1)T_PolyObjRotDisplace)
2524 {
2525 SavePolyrotdisplaceThinker(th, tc_polyrotdisplace);
2526 continue;
2527 }
2528 else if (th->function.acp1 == (actionf_p1)T_PolyObjFade)
2529 {
2530 SavePolyfadeThinker(th, tc_polyfade);
2531 continue;
2532 }
2533 else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeLine)
2534 {
2535 SaveDynamicSlopeThinker(th, tc_dynslopeline);
2536 continue;
2537 }
2538 else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeVert)
2539 {
2540 SaveDynamicSlopeThinker(th, tc_dynslopevert);
2541 continue;
2542 }
2543 #ifdef PARANOIA
2544 else if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed) // wait garbage collection
2545 I_Error("unknown thinker type %p", th->function.acp1);
2546 #endif
2547 }
2548
2549 CONS_Debug(DBG_NETPLAY, "%u thinkers saved in list %d\n", numsaved, i);
2550
2551 WRITEUINT8(save_p, tc_end);
2552 }
2553 }
2554
2555 // Now save the pointers, tracer and target, but at load time we must
2556 // relink to this; the savegame contains the old position in the pointer
2557 // field copyed in the info field temporarily, but finally we just search
2558 // for the old position and relink to it.
P_FindNewPosition(UINT32 oldposition)2559 mobj_t *P_FindNewPosition(UINT32 oldposition)
2560 {
2561 thinker_t *th;
2562 mobj_t *mobj;
2563
2564 for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
2565 {
2566 if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
2567 continue;
2568
2569 mobj = (mobj_t *)th;
2570 if (mobj->mobjnum != oldposition)
2571 continue;
2572
2573 return mobj;
2574 }
2575 CONS_Debug(DBG_GAMELOGIC, "mobj not found\n");
2576 return NULL;
2577 }
2578
LoadMobj(UINT32 mobjnum)2579 static inline mobj_t *LoadMobj(UINT32 mobjnum)
2580 {
2581 if (mobjnum == 0) return NULL;
2582 return (mobj_t *)(size_t)mobjnum;
2583 }
2584
LoadSector(UINT32 sector)2585 static sector_t *LoadSector(UINT32 sector)
2586 {
2587 if (sector >= numsectors) return NULL;
2588 return §ors[sector];
2589 }
2590
LoadLine(UINT32 line)2591 static line_t *LoadLine(UINT32 line)
2592 {
2593 if (line >= numlines) return NULL;
2594 return &lines[line];
2595 }
2596
LoadPlayer(UINT32 player)2597 static inline player_t *LoadPlayer(UINT32 player)
2598 {
2599 if (player >= MAXPLAYERS) return NULL;
2600 return &players[player];
2601 }
2602
LoadSlope(UINT32 slopeid)2603 static inline pslope_t *LoadSlope(UINT32 slopeid)
2604 {
2605 pslope_t *p = slopelist;
2606 if (slopeid > slopecount) return NULL;
2607 do
2608 {
2609 if (p->id == slopeid)
2610 return p;
2611 } while ((p = p->next));
2612 return NULL;
2613 }
2614
LoadMobjThinker(actionf_p1 thinker)2615 static thinker_t* LoadMobjThinker(actionf_p1 thinker)
2616 {
2617 thinker_t *next;
2618 mobj_t *mobj;
2619 UINT32 diff;
2620 UINT32 diff2;
2621 INT32 i;
2622 fixed_t z, floorz, ceilingz;
2623 ffloor_t *floorrover = NULL, *ceilingrover = NULL;
2624
2625 diff = READUINT32(save_p);
2626 if (diff & MD_MORE)
2627 diff2 = READUINT32(save_p);
2628 else
2629 diff2 = 0;
2630
2631 next = (void *)(size_t)READUINT32(save_p);
2632
2633 z = READFIXED(save_p); // Force this so 3dfloor problems don't arise.
2634 floorz = READFIXED(save_p);
2635 ceilingz = READFIXED(save_p);
2636
2637 if (diff2 & MD2_FLOORROVER)
2638 {
2639 sector_t *sec = LoadSector(READUINT32(save_p));
2640 UINT16 id = READUINT16(save_p);
2641 floorrover = P_GetFFloorByID(sec, id);
2642 }
2643
2644 if (diff2 & MD2_CEILINGROVER)
2645 {
2646 sector_t *sec = LoadSector(READUINT32(save_p));
2647 UINT16 id = READUINT16(save_p);
2648 ceilingrover = P_GetFFloorByID(sec, id);
2649 }
2650
2651 if (diff & MD_SPAWNPOINT)
2652 {
2653 UINT16 spawnpointnum = READUINT16(save_p);
2654
2655 if (mapthings[spawnpointnum].type == 1705 || mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case
2656 {
2657 P_SpawnHoop(&mapthings[spawnpointnum]);
2658 return NULL;
2659 }
2660
2661 mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
2662
2663 mobj->spawnpoint = &mapthings[spawnpointnum];
2664 mapthings[spawnpointnum].mobj = mobj;
2665 }
2666 else
2667 mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
2668
2669 // declare this as a valid mobj as soon as possible.
2670 mobj->thinker.function.acp1 = thinker;
2671
2672 mobj->z = z;
2673 mobj->floorz = floorz;
2674 mobj->ceilingz = ceilingz;
2675 mobj->floorrover = floorrover;
2676 mobj->ceilingrover = ceilingrover;
2677
2678 if (diff & MD_TYPE)
2679 mobj->type = READUINT32(save_p);
2680 else
2681 {
2682 for (i = 0; i < NUMMOBJTYPES; i++)
2683 if (mobj->spawnpoint && mobj->spawnpoint->type == mobjinfo[i].doomednum)
2684 break;
2685 if (i == NUMMOBJTYPES)
2686 {
2687 if (mobj->spawnpoint)
2688 CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing type %d\n", mobj->spawnpoint->type);
2689 else
2690 CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing type NULL\n");
2691 I_Error("Savegame corrupted");
2692 }
2693 mobj->type = i;
2694 }
2695 mobj->info = &mobjinfo[mobj->type];
2696 if (diff & MD_POS)
2697 {
2698 mobj->x = READFIXED(save_p);
2699 mobj->y = READFIXED(save_p);
2700 mobj->angle = READANGLE(save_p);
2701 mobj->pitch = READANGLE(save_p);
2702 mobj->roll = READANGLE(save_p);
2703 }
2704 else
2705 {
2706 mobj->x = mobj->spawnpoint->x << FRACBITS;
2707 mobj->y = mobj->spawnpoint->y << FRACBITS;
2708 mobj->angle = FixedAngle(mobj->spawnpoint->angle*FRACUNIT);
2709 mobj->pitch = FixedAngle(mobj->spawnpoint->pitch*FRACUNIT);
2710 mobj->roll = FixedAngle(mobj->spawnpoint->roll*FRACUNIT);
2711 }
2712 if (diff & MD_MOM)
2713 {
2714 mobj->momx = READFIXED(save_p);
2715 mobj->momy = READFIXED(save_p);
2716 mobj->momz = READFIXED(save_p);
2717 } // otherwise they're zero, and the memset took care of it
2718
2719 if (diff & MD_RADIUS)
2720 mobj->radius = READFIXED(save_p);
2721 else
2722 mobj->radius = mobj->info->radius;
2723 if (diff & MD_HEIGHT)
2724 mobj->height = READFIXED(save_p);
2725 else
2726 mobj->height = mobj->info->height;
2727 if (diff & MD_FLAGS)
2728 mobj->flags = READUINT32(save_p);
2729 else
2730 mobj->flags = mobj->info->flags;
2731 if (diff & MD_FLAGS2)
2732 mobj->flags2 = READUINT32(save_p);
2733 if (diff & MD_HEALTH)
2734 mobj->health = READINT32(save_p);
2735 else
2736 mobj->health = mobj->info->spawnhealth;
2737 if (diff & MD_RTIME)
2738 mobj->reactiontime = READINT32(save_p);
2739 else
2740 mobj->reactiontime = mobj->info->reactiontime;
2741
2742 if (diff & MD_STATE)
2743 mobj->state = &states[READUINT16(save_p)];
2744 else
2745 mobj->state = &states[mobj->info->spawnstate];
2746 if (diff & MD_TICS)
2747 mobj->tics = READINT32(save_p);
2748 else
2749 mobj->tics = mobj->state->tics;
2750 if (diff & MD_SPRITE) {
2751 mobj->sprite = READUINT16(save_p);
2752 if (mobj->sprite == SPR_PLAY)
2753 mobj->sprite2 = READUINT8(save_p);
2754 }
2755 else {
2756 mobj->sprite = mobj->state->sprite;
2757 if (mobj->sprite == SPR_PLAY)
2758 mobj->sprite2 = mobj->state->frame&FF_FRAMEMASK;
2759 }
2760 if (diff & MD_FRAME)
2761 {
2762 mobj->frame = READUINT32(save_p);
2763 mobj->anim_duration = READUINT16(save_p);
2764 }
2765 else
2766 {
2767 mobj->frame = mobj->state->frame;
2768 mobj->anim_duration = (UINT16)mobj->state->var2;
2769 }
2770 if (diff & MD_EFLAGS)
2771 mobj->eflags = READUINT16(save_p);
2772 if (diff & MD_PLAYER)
2773 {
2774 i = READUINT8(save_p);
2775 mobj->player = &players[i];
2776 mobj->player->mo = mobj;
2777 }
2778 if (diff & MD_MOVEDIR)
2779 mobj->movedir = READANGLE(save_p);
2780 if (diff & MD_MOVECOUNT)
2781 mobj->movecount = READINT32(save_p);
2782 if (diff & MD_THRESHOLD)
2783 mobj->threshold = READINT32(save_p);
2784 if (diff & MD_LASTLOOK)
2785 mobj->lastlook = READINT32(save_p);
2786 else
2787 mobj->lastlook = -1;
2788 if (diff & MD_TARGET)
2789 mobj->target = (mobj_t *)(size_t)READUINT32(save_p);
2790 if (diff & MD_TRACER)
2791 mobj->tracer = (mobj_t *)(size_t)READUINT32(save_p);
2792 if (diff & MD_FRICTION)
2793 mobj->friction = READFIXED(save_p);
2794 else
2795 mobj->friction = ORIG_FRICTION;
2796 if (diff & MD_MOVEFACTOR)
2797 mobj->movefactor = READFIXED(save_p);
2798 else
2799 mobj->movefactor = FRACUNIT;
2800 if (diff & MD_FUSE)
2801 mobj->fuse = READINT32(save_p);
2802 if (diff & MD_WATERTOP)
2803 mobj->watertop = READFIXED(save_p);
2804 if (diff & MD_WATERBOTTOM)
2805 mobj->waterbottom = READFIXED(save_p);
2806 if (diff & MD_SCALE)
2807 mobj->scale = READFIXED(save_p);
2808 else
2809 mobj->scale = FRACUNIT;
2810 if (diff & MD_DSCALE)
2811 mobj->destscale = READFIXED(save_p);
2812 else
2813 mobj->destscale = mobj->scale;
2814 if (diff2 & MD2_SCALESPEED)
2815 mobj->scalespeed = READFIXED(save_p);
2816 else
2817 mobj->scalespeed = FRACUNIT/12;
2818 if (diff2 & MD2_CUSVAL)
2819 mobj->cusval = READINT32(save_p);
2820 if (diff2 & MD2_CVMEM)
2821 mobj->cvmem = READINT32(save_p);
2822 if (diff2 & MD2_SKIN)
2823 mobj->skin = &skins[READUINT8(save_p)];
2824 if (diff2 & MD2_COLOR)
2825 mobj->color = READUINT16(save_p);
2826 if (diff2 & MD2_EXTVAL1)
2827 mobj->extravalue1 = READINT32(save_p);
2828 if (diff2 & MD2_EXTVAL2)
2829 mobj->extravalue2 = READINT32(save_p);
2830 if (diff2 & MD2_HNEXT)
2831 mobj->hnext = (mobj_t *)(size_t)READUINT32(save_p);
2832 if (diff2 & MD2_HPREV)
2833 mobj->hprev = (mobj_t *)(size_t)READUINT32(save_p);
2834 if (diff2 & MD2_SLOPE)
2835 mobj->standingslope = P_SlopeById(READUINT16(save_p));
2836 if (diff2 & MD2_COLORIZED)
2837 mobj->colorized = READUINT8(save_p);
2838 if (diff2 & MD2_MIRRORED)
2839 mobj->mirrored = READUINT8(save_p);
2840 if (diff2 & MD2_ROLLANGLE)
2841 mobj->rollangle = READANGLE(save_p);
2842 if (diff2 & MD2_SHADOWSCALE)
2843 mobj->shadowscale = READFIXED(save_p);
2844 if (diff2 & MD2_RENDERFLAGS)
2845 mobj->renderflags = READUINT32(save_p);
2846 if (diff2 & MD2_BLENDMODE)
2847 mobj->blendmode = READINT32(save_p);
2848 else
2849 mobj->blendmode = AST_TRANSLUCENT;
2850 if (diff2 & MD2_SPRITEXSCALE)
2851 mobj->spritexscale = READFIXED(save_p);
2852 else
2853 mobj->spritexscale = FRACUNIT;
2854 if (diff2 & MD2_SPRITEYSCALE)
2855 mobj->spriteyscale = READFIXED(save_p);
2856 else
2857 mobj->spriteyscale = FRACUNIT;
2858 if (diff2 & MD2_SPRITEXOFFSET)
2859 mobj->spritexoffset = READFIXED(save_p);
2860 if (diff2 & MD2_SPRITEYOFFSET)
2861 mobj->spriteyoffset = READFIXED(save_p);
2862 if (diff2 & MD2_FLOORSPRITESLOPE)
2863 {
2864 pslope_t *slope = (pslope_t *)P_CreateFloorSpriteSlope(mobj);
2865
2866 slope->zdelta = READFIXED(save_p);
2867 slope->zangle = READANGLE(save_p);
2868 slope->xydirection = READANGLE(save_p);
2869
2870 slope->o.x = READFIXED(save_p);
2871 slope->o.y = READFIXED(save_p);
2872 slope->o.z = READFIXED(save_p);
2873
2874 slope->d.x = READFIXED(save_p);
2875 slope->d.y = READFIXED(save_p);
2876
2877 slope->normal.x = READFIXED(save_p);
2878 slope->normal.y = READFIXED(save_p);
2879 slope->normal.z = READFIXED(save_p);
2880 }
2881
2882 if (diff & MD_REDFLAG)
2883 {
2884 redflag = mobj;
2885 rflagpoint = mobj->spawnpoint;
2886 }
2887 if (diff & MD_BLUEFLAG)
2888 {
2889 blueflag = mobj;
2890 bflagpoint = mobj->spawnpoint;
2891 }
2892
2893 // set sprev, snext, bprev, bnext, subsector
2894 P_SetThingPosition(mobj);
2895
2896 mobj->mobjnum = READUINT32(save_p);
2897
2898 if (mobj->player)
2899 {
2900 if (mobj->eflags & MFE_VERTICALFLIP)
2901 mobj->player->viewz = mobj->z + mobj->height - mobj->player->viewheight;
2902 else
2903 mobj->player->viewz = mobj->player->mo->z + mobj->player->viewheight;
2904 }
2905
2906 mobj->info = (mobjinfo_t *)next; // temporarily, set when leave this function
2907
2908 return &mobj->thinker;
2909 }
2910
LoadNoEnemiesThinker(actionf_p1 thinker)2911 static thinker_t* LoadNoEnemiesThinker(actionf_p1 thinker)
2912 {
2913 noenemies_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
2914 ht->thinker.function.acp1 = thinker;
2915 ht->sourceline = LoadLine(READUINT32(save_p));
2916 return &ht->thinker;
2917 }
2918
LoadBounceCheeseThinker(actionf_p1 thinker)2919 static thinker_t* LoadBounceCheeseThinker(actionf_p1 thinker)
2920 {
2921 bouncecheese_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
2922 ht->thinker.function.acp1 = thinker;
2923 ht->sourceline = LoadLine(READUINT32(save_p));
2924 ht->sector = LoadSector(READUINT32(save_p));
2925 ht->speed = READFIXED(save_p);
2926 ht->distance = READFIXED(save_p);
2927 ht->floorwasheight = READFIXED(save_p);
2928 ht->ceilingwasheight = READFIXED(save_p);
2929 ht->low = READCHAR(save_p);
2930
2931 if (ht->sector)
2932 ht->sector->ceilingdata = ht;
2933
2934 return &ht->thinker;
2935 }
2936
LoadContinuousFallThinker(actionf_p1 thinker)2937 static thinker_t* LoadContinuousFallThinker(actionf_p1 thinker)
2938 {
2939 continuousfall_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
2940 ht->thinker.function.acp1 = thinker;
2941 ht->sector = LoadSector(READUINT32(save_p));
2942 ht->speed = READFIXED(save_p);
2943 ht->direction = READINT32(save_p);
2944 ht->floorstartheight = READFIXED(save_p);
2945 ht->ceilingstartheight = READFIXED(save_p);
2946 ht->destheight = READFIXED(save_p);
2947
2948 if (ht->sector)
2949 {
2950 ht->sector->ceilingdata = ht;
2951 ht->sector->floordata = ht;
2952 }
2953
2954 return &ht->thinker;
2955 }
2956
LoadMarioBlockThinker(actionf_p1 thinker)2957 static thinker_t* LoadMarioBlockThinker(actionf_p1 thinker)
2958 {
2959 mariothink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
2960 ht->thinker.function.acp1 = thinker;
2961 ht->sector = LoadSector(READUINT32(save_p));
2962 ht->speed = READFIXED(save_p);
2963 ht->direction = READINT32(save_p);
2964 ht->floorstartheight = READFIXED(save_p);
2965 ht->ceilingstartheight = READFIXED(save_p);
2966 ht->tag = READINT16(save_p);
2967
2968 if (ht->sector)
2969 {
2970 ht->sector->ceilingdata = ht;
2971 ht->sector->floordata = ht;
2972 }
2973
2974 return &ht->thinker;
2975 }
2976
LoadMarioCheckThinker(actionf_p1 thinker)2977 static thinker_t* LoadMarioCheckThinker(actionf_p1 thinker)
2978 {
2979 mariocheck_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
2980 ht->thinker.function.acp1 = thinker;
2981 ht->sourceline = LoadLine(READUINT32(save_p));
2982 ht->sector = LoadSector(READUINT32(save_p));
2983 return &ht->thinker;
2984 }
2985
LoadThwompThinker(actionf_p1 thinker)2986 static thinker_t* LoadThwompThinker(actionf_p1 thinker)
2987 {
2988 thwomp_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
2989 ht->thinker.function.acp1 = thinker;
2990 ht->sourceline = LoadLine(READUINT32(save_p));
2991 ht->sector = LoadSector(READUINT32(save_p));
2992 ht->crushspeed = READFIXED(save_p);
2993 ht->retractspeed = READFIXED(save_p);
2994 ht->direction = READINT32(save_p);
2995 ht->floorstartheight = READFIXED(save_p);
2996 ht->ceilingstartheight = READFIXED(save_p);
2997 ht->delay = READINT32(save_p);
2998 ht->tag = READINT16(save_p);
2999 ht->sound = READUINT16(save_p);
3000
3001 if (ht->sector)
3002 {
3003 ht->sector->ceilingdata = ht;
3004 ht->sector->floordata = ht;
3005 }
3006
3007 return &ht->thinker;
3008 }
3009
LoadFloatThinker(actionf_p1 thinker)3010 static thinker_t* LoadFloatThinker(actionf_p1 thinker)
3011 {
3012 floatthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3013 ht->thinker.function.acp1 = thinker;
3014 ht->sourceline = LoadLine(READUINT32(save_p));
3015 ht->sector = LoadSector(READUINT32(save_p));
3016 ht->tag = READINT16(save_p);
3017 return &ht->thinker;
3018 }
3019
LoadEachTimeThinker(actionf_p1 thinker)3020 static thinker_t* LoadEachTimeThinker(actionf_p1 thinker)
3021 {
3022 size_t i;
3023 eachtime_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3024 ht->thinker.function.acp1 = thinker;
3025 ht->sourceline = LoadLine(READUINT32(save_p));
3026 for (i = 0; i < MAXPLAYERS; i++)
3027 {
3028 ht->playersInArea[i] = READCHAR(save_p);
3029 ht->playersOnArea[i] = READCHAR(save_p);
3030 }
3031 ht->triggerOnExit = READCHAR(save_p);
3032 return &ht->thinker;
3033 }
3034
LoadRaiseThinker(actionf_p1 thinker)3035 static thinker_t* LoadRaiseThinker(actionf_p1 thinker)
3036 {
3037 raise_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3038 ht->thinker.function.acp1 = thinker;
3039 ht->tag = READINT16(save_p);
3040 ht->sector = LoadSector(READUINT32(save_p));
3041 ht->ceilingbottom = READFIXED(save_p);
3042 ht->ceilingtop = READFIXED(save_p);
3043 ht->basespeed = READFIXED(save_p);
3044 ht->extraspeed = READFIXED(save_p);
3045 ht->shaketimer = READUINT8(save_p);
3046 ht->flags = READUINT8(save_p);
3047 return &ht->thinker;
3048 }
3049
LoadCeilingThinker(actionf_p1 thinker)3050 static thinker_t* LoadCeilingThinker(actionf_p1 thinker)
3051 {
3052 ceiling_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3053 ht->thinker.function.acp1 = thinker;
3054 ht->type = READUINT8(save_p);
3055 ht->sector = LoadSector(READUINT32(save_p));
3056 ht->bottomheight = READFIXED(save_p);
3057 ht->topheight = READFIXED(save_p);
3058 ht->speed = READFIXED(save_p);
3059 ht->oldspeed = READFIXED(save_p);
3060 ht->delay = READFIXED(save_p);
3061 ht->delaytimer = READFIXED(save_p);
3062 ht->crush = READUINT8(save_p);
3063 ht->texture = READINT32(save_p);
3064 ht->direction = READINT32(save_p);
3065 ht->tag = READINT32(save_p);
3066 ht->olddirection = READINT32(save_p);
3067 ht->origspeed = READFIXED(save_p);
3068 ht->sourceline = READFIXED(save_p);
3069 if (ht->sector)
3070 ht->sector->ceilingdata = ht;
3071 return &ht->thinker;
3072 }
3073
LoadFloormoveThinker(actionf_p1 thinker)3074 static thinker_t* LoadFloormoveThinker(actionf_p1 thinker)
3075 {
3076 floormove_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3077 ht->thinker.function.acp1 = thinker;
3078 ht->type = READUINT8(save_p);
3079 ht->crush = READUINT8(save_p);
3080 ht->sector = LoadSector(READUINT32(save_p));
3081 ht->direction = READINT32(save_p);
3082 ht->texture = READINT32(save_p);
3083 ht->floordestheight = READFIXED(save_p);
3084 ht->speed = READFIXED(save_p);
3085 ht->origspeed = READFIXED(save_p);
3086 ht->delay = READFIXED(save_p);
3087 ht->delaytimer = READFIXED(save_p);
3088 if (ht->sector)
3089 ht->sector->floordata = ht;
3090 return &ht->thinker;
3091 }
3092
LoadLightflashThinker(actionf_p1 thinker)3093 static thinker_t* LoadLightflashThinker(actionf_p1 thinker)
3094 {
3095 lightflash_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3096 ht->thinker.function.acp1 = thinker;
3097 ht->sector = LoadSector(READUINT32(save_p));
3098 ht->maxlight = READINT32(save_p);
3099 ht->minlight = READINT32(save_p);
3100 if (ht->sector)
3101 ht->sector->lightingdata = ht;
3102 return &ht->thinker;
3103 }
3104
LoadStrobeThinker(actionf_p1 thinker)3105 static thinker_t* LoadStrobeThinker(actionf_p1 thinker)
3106 {
3107 strobe_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3108 ht->thinker.function.acp1 = thinker;
3109 ht->sector = LoadSector(READUINT32(save_p));
3110 ht->count = READINT32(save_p);
3111 ht->minlight = READINT32(save_p);
3112 ht->maxlight = READINT32(save_p);
3113 ht->darktime = READINT32(save_p);
3114 ht->brighttime = READINT32(save_p);
3115 if (ht->sector)
3116 ht->sector->lightingdata = ht;
3117 return &ht->thinker;
3118 }
3119
LoadGlowThinker(actionf_p1 thinker)3120 static thinker_t* LoadGlowThinker(actionf_p1 thinker)
3121 {
3122 glow_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3123 ht->thinker.function.acp1 = thinker;
3124 ht->sector = LoadSector(READUINT32(save_p));
3125 ht->minlight = READINT32(save_p);
3126 ht->maxlight = READINT32(save_p);
3127 ht->direction = READINT32(save_p);
3128 ht->speed = READINT32(save_p);
3129 if (ht->sector)
3130 ht->sector->lightingdata = ht;
3131 return &ht->thinker;
3132 }
3133
LoadFireflickerThinker(actionf_p1 thinker)3134 static thinker_t* LoadFireflickerThinker(actionf_p1 thinker)
3135 {
3136 fireflicker_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3137 ht->thinker.function.acp1 = thinker;
3138 ht->sector = LoadSector(READUINT32(save_p));
3139 ht->count = READINT32(save_p);
3140 ht->resetcount = READINT32(save_p);
3141 ht->maxlight = READINT32(save_p);
3142 ht->minlight = READINT32(save_p);
3143 if (ht->sector)
3144 ht->sector->lightingdata = ht;
3145 return &ht->thinker;
3146 }
3147
LoadElevatorThinker(actionf_p1 thinker,boolean setplanedata)3148 static thinker_t* LoadElevatorThinker(actionf_p1 thinker, boolean setplanedata)
3149 {
3150 elevator_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3151 ht->thinker.function.acp1 = thinker;
3152 ht->type = READUINT8(save_p);
3153 ht->sector = LoadSector(READUINT32(save_p));
3154 ht->actionsector = LoadSector(READUINT32(save_p));
3155 ht->direction = READINT32(save_p);
3156 ht->floordestheight = READFIXED(save_p);
3157 ht->ceilingdestheight = READFIXED(save_p);
3158 ht->speed = READFIXED(save_p);
3159 ht->origspeed = READFIXED(save_p);
3160 ht->low = READFIXED(save_p);
3161 ht->high = READFIXED(save_p);
3162 ht->distance = READFIXED(save_p);
3163 ht->delay = READFIXED(save_p);
3164 ht->delaytimer = READFIXED(save_p);
3165 ht->floorwasheight = READFIXED(save_p);
3166 ht->ceilingwasheight = READFIXED(save_p);
3167 ht->sourceline = LoadLine(READUINT32(save_p));
3168
3169 if (ht->sector && setplanedata)
3170 {
3171 ht->sector->ceilingdata = ht;
3172 ht->sector->floordata = ht;
3173 }
3174
3175 return &ht->thinker;
3176 }
3177
LoadCrumbleThinker(actionf_p1 thinker)3178 static thinker_t* LoadCrumbleThinker(actionf_p1 thinker)
3179 {
3180 crumble_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3181 ht->thinker.function.acp1 = thinker;
3182 ht->sourceline = LoadLine(READUINT32(save_p));
3183 ht->sector = LoadSector(READUINT32(save_p));
3184 ht->actionsector = LoadSector(READUINT32(save_p));
3185 ht->player = LoadPlayer(READUINT32(save_p));
3186 ht->direction = READINT32(save_p);
3187 ht->origalpha = READINT32(save_p);
3188 ht->timer = READINT32(save_p);
3189 ht->speed = READFIXED(save_p);
3190 ht->floorwasheight = READFIXED(save_p);
3191 ht->ceilingwasheight = READFIXED(save_p);
3192 ht->flags = READUINT8(save_p);
3193
3194 if (ht->sector)
3195 ht->sector->floordata = ht;
3196
3197 return &ht->thinker;
3198 }
3199
LoadScrollThinker(actionf_p1 thinker)3200 static thinker_t* LoadScrollThinker(actionf_p1 thinker)
3201 {
3202 scroll_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3203 ht->thinker.function.acp1 = thinker;
3204 ht->dx = READFIXED(save_p);
3205 ht->dy = READFIXED(save_p);
3206 ht->affectee = READINT32(save_p);
3207 ht->control = READINT32(save_p);
3208 ht->last_height = READFIXED(save_p);
3209 ht->vdx = READFIXED(save_p);
3210 ht->vdy = READFIXED(save_p);
3211 ht->accel = READINT32(save_p);
3212 ht->exclusive = READINT32(save_p);
3213 ht->type = READUINT8(save_p);
3214 return &ht->thinker;
3215 }
3216
LoadFrictionThinker(actionf_p1 thinker)3217 static inline thinker_t* LoadFrictionThinker(actionf_p1 thinker)
3218 {
3219 friction_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3220 ht->thinker.function.acp1 = thinker;
3221 ht->friction = READINT32(save_p);
3222 ht->movefactor = READINT32(save_p);
3223 ht->affectee = READINT32(save_p);
3224 ht->referrer = READINT32(save_p);
3225 ht->roverfriction = READUINT8(save_p);
3226 return &ht->thinker;
3227 }
3228
LoadPusherThinker(actionf_p1 thinker)3229 static thinker_t* LoadPusherThinker(actionf_p1 thinker)
3230 {
3231 pusher_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3232 ht->thinker.function.acp1 = thinker;
3233 ht->type = READUINT8(save_p);
3234 ht->x_mag = READINT32(save_p);
3235 ht->y_mag = READINT32(save_p);
3236 ht->magnitude = READINT32(save_p);
3237 ht->radius = READINT32(save_p);
3238 ht->x = READINT32(save_p);
3239 ht->y = READINT32(save_p);
3240 ht->z = READINT32(save_p);
3241 ht->affectee = READINT32(save_p);
3242 ht->roverpusher = READUINT8(save_p);
3243 ht->referrer = READINT32(save_p);
3244 ht->exclusive = READINT32(save_p);
3245 ht->slider = READINT32(save_p);
3246 ht->source = P_GetPushThing(ht->affectee);
3247 return &ht->thinker;
3248 }
3249
LoadLaserThinker(actionf_p1 thinker)3250 static inline thinker_t* LoadLaserThinker(actionf_p1 thinker)
3251 {
3252 laserthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3253 ht->thinker.function.acp1 = thinker;
3254 ht->tag = READINT16(save_p);
3255 ht->sourceline = LoadLine(READUINT32(save_p));
3256 ht->nobosses = READUINT8(save_p);
3257 return &ht->thinker;
3258 }
3259
LoadLightlevelThinker(actionf_p1 thinker)3260 static inline thinker_t* LoadLightlevelThinker(actionf_p1 thinker)
3261 {
3262 lightlevel_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3263 ht->thinker.function.acp1 = thinker;
3264 ht->sector = LoadSector(READUINT32(save_p));
3265 ht->sourcelevel = READINT16(save_p);
3266 ht->destlevel = READINT16(save_p);
3267 ht->fixedcurlevel = READFIXED(save_p);
3268 ht->fixedpertic = READFIXED(save_p);
3269 ht->timer = READINT32(save_p);
3270 if (ht->sector)
3271 ht->sector->lightingdata = ht;
3272 return &ht->thinker;
3273 }
3274
LoadExecutorThinker(actionf_p1 thinker)3275 static inline thinker_t* LoadExecutorThinker(actionf_p1 thinker)
3276 {
3277 executor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3278 ht->thinker.function.acp1 = thinker;
3279 ht->line = LoadLine(READUINT32(save_p));
3280 ht->caller = LoadMobj(READUINT32(save_p));
3281 ht->sector = LoadSector(READUINT32(save_p));
3282 ht->timer = READINT32(save_p);
3283 return &ht->thinker;
3284 }
3285
LoadDisappearThinker(actionf_p1 thinker)3286 static inline thinker_t* LoadDisappearThinker(actionf_p1 thinker)
3287 {
3288 disappear_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3289 ht->thinker.function.acp1 = thinker;
3290 ht->appeartime = READUINT32(save_p);
3291 ht->disappeartime = READUINT32(save_p);
3292 ht->offset = READUINT32(save_p);
3293 ht->timer = READUINT32(save_p);
3294 ht->affectee = READINT32(save_p);
3295 ht->sourceline = READINT32(save_p);
3296 ht->exists = READINT32(save_p);
3297 return &ht->thinker;
3298 }
3299
LoadFadeThinker(actionf_p1 thinker)3300 static inline thinker_t* LoadFadeThinker(actionf_p1 thinker)
3301 {
3302 sector_t *ss;
3303 fade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3304 ht->thinker.function.acp1 = thinker;
3305 ht->dest_exc = GetNetColormapFromList(READUINT32(save_p));
3306 ht->sectornum = READUINT32(save_p);
3307 ht->ffloornum = READUINT32(save_p);
3308 ht->alpha = READINT32(save_p);
3309 ht->sourcevalue = READINT16(save_p);
3310 ht->destvalue = READINT16(save_p);
3311 ht->destlightlevel = READINT16(save_p);
3312 ht->speed = READINT16(save_p);
3313 ht->ticbased = (boolean)READUINT8(save_p);
3314 ht->timer = READINT32(save_p);
3315 ht->doexists = READUINT8(save_p);
3316 ht->dotranslucent = READUINT8(save_p);
3317 ht->dolighting = READUINT8(save_p);
3318 ht->docolormap = READUINT8(save_p);
3319 ht->docollision = READUINT8(save_p);
3320 ht->doghostfade = READUINT8(save_p);
3321 ht->exactalpha = READUINT8(save_p);
3322
3323 ss = LoadSector(ht->sectornum);
3324 if (ss)
3325 {
3326 size_t j = 0; // ss->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc
3327 ffloor_t *rover;
3328 for (rover = ss->ffloors; rover; rover = rover->next)
3329 {
3330 if (j == ht->ffloornum)
3331 {
3332 ht->rover = rover;
3333 rover->fadingdata = ht;
3334 break;
3335 }
3336 j++;
3337 }
3338 }
3339 return &ht->thinker;
3340 }
3341
LoadFadeColormapThinker(actionf_p1 thinker)3342 static inline thinker_t* LoadFadeColormapThinker(actionf_p1 thinker)
3343 {
3344 fadecolormap_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3345 ht->thinker.function.acp1 = thinker;
3346 ht->sector = LoadSector(READUINT32(save_p));
3347 ht->source_exc = GetNetColormapFromList(READUINT32(save_p));
3348 ht->dest_exc = GetNetColormapFromList(READUINT32(save_p));
3349 ht->ticbased = (boolean)READUINT8(save_p);
3350 ht->duration = READINT32(save_p);
3351 ht->timer = READINT32(save_p);
3352 if (ht->sector)
3353 ht->sector->fadecolormapdata = ht;
3354 return &ht->thinker;
3355 }
3356
LoadPlaneDisplaceThinker(actionf_p1 thinker)3357 static inline thinker_t* LoadPlaneDisplaceThinker(actionf_p1 thinker)
3358 {
3359 planedisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3360 ht->thinker.function.acp1 = thinker;
3361
3362 ht->affectee = READINT32(save_p);
3363 ht->control = READINT32(save_p);
3364 ht->last_height = READFIXED(save_p);
3365 ht->speed = READFIXED(save_p);
3366 ht->type = READUINT8(save_p);
3367 return &ht->thinker;
3368 }
3369
LoadDynamicSlopeThinker(actionf_p1 thinker)3370 static inline thinker_t* LoadDynamicSlopeThinker(actionf_p1 thinker)
3371 {
3372 dynplanethink_t* ht = Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL);
3373 ht->thinker.function.acp1 = thinker;
3374
3375 ht->type = READUINT8(save_p);
3376 ht->slope = LoadSlope(READUINT32(save_p));
3377 ht->sourceline = LoadLine(READUINT32(save_p));
3378 ht->extent = READFIXED(save_p);
3379 READMEM(save_p, ht->tags, sizeof(ht->tags));
3380 READMEM(save_p, ht->vex, sizeof(ht->vex));
3381 return &ht->thinker;
3382 }
3383
LoadPolyrotatetThinker(actionf_p1 thinker)3384 static inline thinker_t* LoadPolyrotatetThinker(actionf_p1 thinker)
3385 {
3386 polyrotate_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3387 ht->thinker.function.acp1 = thinker;
3388 ht->polyObjNum = READINT32(save_p);
3389 ht->speed = READINT32(save_p);
3390 ht->distance = READINT32(save_p);
3391 ht->turnobjs = READUINT8(save_p);
3392 return &ht->thinker;
3393 }
3394
LoadPolymoveThinker(actionf_p1 thinker)3395 static thinker_t* LoadPolymoveThinker(actionf_p1 thinker)
3396 {
3397 polymove_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3398 ht->thinker.function.acp1 = thinker;
3399 ht->polyObjNum = READINT32(save_p);
3400 ht->speed = READINT32(save_p);
3401 ht->momx = READFIXED(save_p);
3402 ht->momy = READFIXED(save_p);
3403 ht->distance = READINT32(save_p);
3404 ht->angle = READANGLE(save_p);
3405 return &ht->thinker;
3406 }
3407
LoadPolywaypointThinker(actionf_p1 thinker)3408 static inline thinker_t* LoadPolywaypointThinker(actionf_p1 thinker)
3409 {
3410 polywaypoint_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3411 ht->thinker.function.acp1 = thinker;
3412 ht->polyObjNum = READINT32(save_p);
3413 ht->speed = READINT32(save_p);
3414 ht->sequence = READINT32(save_p);
3415 ht->pointnum = READINT32(save_p);
3416 ht->direction = READINT32(save_p);
3417 ht->returnbehavior = READUINT8(save_p);
3418 ht->continuous = READUINT8(save_p);
3419 ht->stophere = READUINT8(save_p);
3420 return &ht->thinker;
3421 }
3422
LoadPolyslidedoorThinker(actionf_p1 thinker)3423 static inline thinker_t* LoadPolyslidedoorThinker(actionf_p1 thinker)
3424 {
3425 polyslidedoor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3426 ht->thinker.function.acp1 = thinker;
3427 ht->polyObjNum = READINT32(save_p);
3428 ht->delay = READINT32(save_p);
3429 ht->delayCount = READINT32(save_p);
3430 ht->initSpeed = READINT32(save_p);
3431 ht->speed = READINT32(save_p);
3432 ht->initDistance = READINT32(save_p);
3433 ht->distance = READINT32(save_p);
3434 ht->initAngle = READUINT32(save_p);
3435 ht->angle = READUINT32(save_p);
3436 ht->revAngle = READUINT32(save_p);
3437 ht->momx = READFIXED(save_p);
3438 ht->momy = READFIXED(save_p);
3439 ht->closing = READUINT8(save_p);
3440 return &ht->thinker;
3441 }
3442
LoadPolyswingdoorThinker(actionf_p1 thinker)3443 static inline thinker_t* LoadPolyswingdoorThinker(actionf_p1 thinker)
3444 {
3445 polyswingdoor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3446 ht->thinker.function.acp1 = thinker;
3447 ht->polyObjNum = READINT32(save_p);
3448 ht->delay = READINT32(save_p);
3449 ht->delayCount = READINT32(save_p);
3450 ht->initSpeed = READINT32(save_p);
3451 ht->speed = READINT32(save_p);
3452 ht->initDistance = READINT32(save_p);
3453 ht->distance = READINT32(save_p);
3454 ht->closing = READUINT8(save_p);
3455 return &ht->thinker;
3456 }
3457
LoadPolydisplaceThinker(actionf_p1 thinker)3458 static inline thinker_t* LoadPolydisplaceThinker(actionf_p1 thinker)
3459 {
3460 polydisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3461 ht->thinker.function.acp1 = thinker;
3462 ht->polyObjNum = READINT32(save_p);
3463 ht->controlSector = LoadSector(READUINT32(save_p));
3464 ht->dx = READFIXED(save_p);
3465 ht->dy = READFIXED(save_p);
3466 ht->oldHeights = READFIXED(save_p);
3467 return &ht->thinker;
3468 }
3469
LoadPolyrotdisplaceThinker(actionf_p1 thinker)3470 static inline thinker_t* LoadPolyrotdisplaceThinker(actionf_p1 thinker)
3471 {
3472 polyrotdisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3473 ht->thinker.function.acp1 = thinker;
3474 ht->polyObjNum = READINT32(save_p);
3475 ht->controlSector = LoadSector(READUINT32(save_p));
3476 ht->rotscale = READFIXED(save_p);
3477 ht->turnobjs = READUINT8(save_p);
3478 ht->oldHeights = READFIXED(save_p);
3479 return &ht->thinker;
3480 }
3481
LoadPolyfadeThinker(actionf_p1 thinker)3482 static thinker_t* LoadPolyfadeThinker(actionf_p1 thinker)
3483 {
3484 polyfade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
3485 ht->thinker.function.acp1 = thinker;
3486 ht->polyObjNum = READINT32(save_p);
3487 ht->sourcevalue = READINT32(save_p);
3488 ht->destvalue = READINT32(save_p);
3489 ht->docollision = (boolean)READUINT8(save_p);
3490 ht->doghostfade = (boolean)READUINT8(save_p);
3491 ht->ticbased = (boolean)READUINT8(save_p);
3492 ht->duration = READINT32(save_p);
3493 ht->timer = READINT32(save_p);
3494 return &ht->thinker;
3495 }
3496
P_NetUnArchiveThinkers(void)3497 static void P_NetUnArchiveThinkers(void)
3498 {
3499 thinker_t *currentthinker;
3500 thinker_t *next;
3501 UINT8 tclass;
3502 UINT8 restoreNum = false;
3503 UINT32 i;
3504 UINT32 numloaded = 0;
3505
3506 if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS)
3507 I_Error("Bad $$$.sav at archive block Thinkers");
3508
3509 // remove all the current thinkers
3510 for (i = 0; i < NUM_THINKERLISTS; i++)
3511 {
3512 currentthinker = thlist[i].next;
3513 for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = next)
3514 {
3515 next = currentthinker->next;
3516
3517 if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
3518 P_RemoveSavegameMobj((mobj_t *)currentthinker); // item isn't saved, don't remove it
3519 else
3520 Z_Free(currentthinker);
3521 }
3522 }
3523
3524 // we don't want the removed mobjs to come back
3525 iquetail = iquehead = 0;
3526 P_InitThinkers();
3527
3528 // clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity
3529 for (i = 0; i < numsectors; i++)
3530 {
3531 sectors[i].floordata = sectors[i].ceilingdata = sectors[i].lightingdata = sectors[i].fadecolormapdata = NULL;
3532 }
3533
3534 // read in saved thinkers
3535 for (i = 0; i < NUM_THINKERLISTS; i++)
3536 {
3537 for (;;)
3538 {
3539 thinker_t* th = NULL;
3540 tclass = READUINT8(save_p);
3541
3542 if (tclass == tc_end)
3543 break; // leave the saved thinker reading loop
3544 numloaded++;
3545
3546 switch (tclass)
3547 {
3548 case tc_mobj:
3549 th = LoadMobjThinker((actionf_p1)P_MobjThinker);
3550 break;
3551
3552 case tc_ceiling:
3553 th = LoadCeilingThinker((actionf_p1)T_MoveCeiling);
3554 break;
3555
3556 case tc_crushceiling:
3557 th = LoadCeilingThinker((actionf_p1)T_CrushCeiling);
3558 break;
3559
3560 case tc_floor:
3561 th = LoadFloormoveThinker((actionf_p1)T_MoveFloor);
3562 break;
3563
3564 case tc_flash:
3565 th = LoadLightflashThinker((actionf_p1)T_LightningFlash);
3566 break;
3567
3568 case tc_strobe:
3569 th = LoadStrobeThinker((actionf_p1)T_StrobeFlash);
3570 break;
3571
3572 case tc_glow:
3573 th = LoadGlowThinker((actionf_p1)T_Glow);
3574 break;
3575
3576 case tc_fireflicker:
3577 th = LoadFireflickerThinker((actionf_p1)T_FireFlicker);
3578 break;
3579
3580 case tc_elevator:
3581 th = LoadElevatorThinker((actionf_p1)T_MoveElevator, true);
3582 break;
3583
3584 case tc_continuousfalling:
3585 th = LoadContinuousFallThinker((actionf_p1)T_ContinuousFalling);
3586 break;
3587
3588 case tc_thwomp:
3589 th = LoadThwompThinker((actionf_p1)T_ThwompSector);
3590 break;
3591
3592 case tc_noenemies:
3593 th = LoadNoEnemiesThinker((actionf_p1)T_NoEnemiesSector);
3594 break;
3595
3596 case tc_eachtime:
3597 th = LoadEachTimeThinker((actionf_p1)T_EachTimeThinker);
3598 break;
3599
3600 case tc_raisesector:
3601 th = LoadRaiseThinker((actionf_p1)T_RaiseSector);
3602 break;
3603
3604 case tc_camerascanner:
3605 th = LoadElevatorThinker((actionf_p1)T_CameraScanner, false);
3606 break;
3607
3608 case tc_bouncecheese:
3609 th = LoadBounceCheeseThinker((actionf_p1)T_BounceCheese);
3610 break;
3611
3612 case tc_startcrumble:
3613 th = LoadCrumbleThinker((actionf_p1)T_StartCrumble);
3614 break;
3615
3616 case tc_marioblock:
3617 th = LoadMarioBlockThinker((actionf_p1)T_MarioBlock);
3618 break;
3619
3620 case tc_marioblockchecker:
3621 th = LoadMarioCheckThinker((actionf_p1)T_MarioBlockChecker);
3622 break;
3623
3624 case tc_floatsector:
3625 th = LoadFloatThinker((actionf_p1)T_FloatSector);
3626 break;
3627
3628 case tc_laserflash:
3629 th = LoadLaserThinker((actionf_p1)T_LaserFlash);
3630 break;
3631
3632 case tc_lightfade:
3633 th = LoadLightlevelThinker((actionf_p1)T_LightFade);
3634 break;
3635
3636 case tc_executor:
3637 th = LoadExecutorThinker((actionf_p1)T_ExecutorDelay);
3638 restoreNum = true;
3639 break;
3640
3641 case tc_disappear:
3642 th = LoadDisappearThinker((actionf_p1)T_Disappear);
3643 break;
3644
3645 case tc_fade:
3646 th = LoadFadeThinker((actionf_p1)T_Fade);
3647 break;
3648
3649 case tc_fadecolormap:
3650 th = LoadFadeColormapThinker((actionf_p1)T_FadeColormap);
3651 break;
3652
3653 case tc_planedisplace:
3654 th = LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace);
3655 break;
3656 case tc_polyrotate:
3657 th = LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate);
3658 break;
3659
3660 case tc_polymove:
3661 th = LoadPolymoveThinker((actionf_p1)T_PolyObjMove);
3662 break;
3663
3664 case tc_polywaypoint:
3665 th = LoadPolywaypointThinker((actionf_p1)T_PolyObjWaypoint);
3666 break;
3667
3668 case tc_polyslidedoor:
3669 th = LoadPolyslidedoorThinker((actionf_p1)T_PolyDoorSlide);
3670 break;
3671
3672 case tc_polyswingdoor:
3673 th = LoadPolyswingdoorThinker((actionf_p1)T_PolyDoorSwing);
3674 break;
3675
3676 case tc_polyflag:
3677 th = LoadPolymoveThinker((actionf_p1)T_PolyObjFlag);
3678 break;
3679
3680 case tc_polydisplace:
3681 th = LoadPolydisplaceThinker((actionf_p1)T_PolyObjDisplace);
3682 break;
3683
3684 case tc_polyrotdisplace:
3685 th = LoadPolyrotdisplaceThinker((actionf_p1)T_PolyObjRotDisplace);
3686 break;
3687
3688 case tc_polyfade:
3689 th = LoadPolyfadeThinker((actionf_p1)T_PolyObjFade);
3690 break;
3691
3692 case tc_dynslopeline:
3693 th = LoadDynamicSlopeThinker((actionf_p1)T_DynamicSlopeLine);
3694 break;
3695
3696 case tc_dynslopevert:
3697 th = LoadDynamicSlopeThinker((actionf_p1)T_DynamicSlopeVert);
3698 break;
3699
3700 case tc_scroll:
3701 th = LoadScrollThinker((actionf_p1)T_Scroll);
3702 break;
3703
3704 case tc_friction:
3705 th = LoadFrictionThinker((actionf_p1)T_Friction);
3706 break;
3707
3708 case tc_pusher:
3709 th = LoadPusherThinker((actionf_p1)T_Pusher);
3710 break;
3711
3712 default:
3713 I_Error("P_UnarchiveSpecials: Unknown tclass %d in savegame", tclass);
3714 }
3715 if (th)
3716 P_AddThinker(i, th);
3717 }
3718
3719 CONS_Debug(DBG_NETPLAY, "%u thinkers loaded in list %d\n", numloaded, i);
3720 }
3721
3722 if (restoreNum)
3723 {
3724 executor_t *delay = NULL;
3725 UINT32 mobjnum;
3726 for (currentthinker = thlist[THINK_MAIN].next; currentthinker != &thlist[THINK_MAIN]; currentthinker = currentthinker->next)
3727 {
3728 if (currentthinker->function.acp1 != (actionf_p1)T_ExecutorDelay)
3729 continue;
3730 delay = (void *)currentthinker;
3731 if (!(mobjnum = (UINT32)(size_t)delay->caller))
3732 continue;
3733 delay->caller = P_FindNewPosition(mobjnum);
3734 }
3735 }
3736 }
3737
3738 ///////////////////////////////////////////////////////////////////////////////
3739 //
3740 // haleyjd 03/26/06: PolyObject saving code
3741 //
3742 #define PD_FLAGS 0x01
3743 #define PD_TRANS 0x02
3744
P_ArchivePolyObj(polyobj_t * po)3745 static inline void P_ArchivePolyObj(polyobj_t *po)
3746 {
3747 UINT8 diff = 0;
3748 WRITEINT32(save_p, po->id);
3749 WRITEANGLE(save_p, po->angle);
3750
3751 WRITEFIXED(save_p, po->spawnSpot.x);
3752 WRITEFIXED(save_p, po->spawnSpot.y);
3753
3754 if (po->flags != po->spawnflags)
3755 diff |= PD_FLAGS;
3756 if (po->translucency != po->spawntrans)
3757 diff |= PD_TRANS;
3758
3759 WRITEUINT8(save_p, diff);
3760
3761 if (diff & PD_FLAGS)
3762 WRITEINT32(save_p, po->flags);
3763 if (diff & PD_TRANS)
3764 WRITEINT32(save_p, po->translucency);
3765 }
3766
P_UnArchivePolyObj(polyobj_t * po)3767 static inline void P_UnArchivePolyObj(polyobj_t *po)
3768 {
3769 INT32 id;
3770 UINT32 angle;
3771 fixed_t x, y;
3772 UINT8 diff;
3773
3774 // nullify all polyobject thinker pointers;
3775 // the thinkers themselves will fight over who gets the field
3776 // when they first start to run.
3777 po->thinker = NULL;
3778
3779 id = READINT32(save_p);
3780
3781 angle = READANGLE(save_p);
3782
3783 x = READFIXED(save_p);
3784 y = READFIXED(save_p);
3785
3786 diff = READUINT8(save_p);
3787
3788 if (diff & PD_FLAGS)
3789 po->flags = READINT32(save_p);
3790 if (diff & PD_TRANS)
3791 po->translucency = READINT32(save_p);
3792
3793 // if the object is bad or isn't in the id hash, we can do nothing more
3794 // with it, so return now
3795 if (po->isBad || po != Polyobj_GetForNum(id))
3796 return;
3797
3798 // rotate and translate polyobject
3799 Polyobj_MoveOnLoad(po, angle, x, y);
3800 }
3801
P_ArchivePolyObjects(void)3802 static inline void P_ArchivePolyObjects(void)
3803 {
3804 INT32 i;
3805
3806 WRITEUINT32(save_p, ARCHIVEBLOCK_POBJS);
3807
3808 // save number of polyobjects
3809 WRITEINT32(save_p, numPolyObjects);
3810
3811 for (i = 0; i < numPolyObjects; ++i)
3812 P_ArchivePolyObj(&PolyObjects[i]);
3813 }
3814
P_UnArchivePolyObjects(void)3815 static inline void P_UnArchivePolyObjects(void)
3816 {
3817 INT32 i, numSavedPolys;
3818
3819 if (READUINT32(save_p) != ARCHIVEBLOCK_POBJS)
3820 I_Error("Bad $$$.sav at archive block Pobjs");
3821
3822 numSavedPolys = READINT32(save_p);
3823
3824 if (numSavedPolys != numPolyObjects)
3825 I_Error("P_UnArchivePolyObjects: polyobj count inconsistency\n");
3826
3827 for (i = 0; i < numSavedPolys; ++i)
3828 P_UnArchivePolyObj(&PolyObjects[i]);
3829 }
3830
P_FinishMobjs(void)3831 static inline void P_FinishMobjs(void)
3832 {
3833 thinker_t *currentthinker;
3834 mobj_t *mobj;
3835
3836 // put info field there real value
3837 for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ];
3838 currentthinker = currentthinker->next)
3839 {
3840 if (currentthinker->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
3841 continue;
3842
3843 mobj = (mobj_t *)currentthinker;
3844 mobj->info = &mobjinfo[mobj->type];
3845 }
3846 }
3847
P_RelinkPointers(void)3848 static void P_RelinkPointers(void)
3849 {
3850 thinker_t *currentthinker;
3851 mobj_t *mobj;
3852 UINT32 temp;
3853
3854 // use info field (value = oldposition) to relink mobjs
3855 for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ];
3856 currentthinker = currentthinker->next)
3857 {
3858 if (currentthinker->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
3859 continue;
3860
3861 mobj = (mobj_t *)currentthinker;
3862
3863 if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER)
3864 continue;
3865
3866 if (mobj->tracer)
3867 {
3868 temp = (UINT32)(size_t)mobj->tracer;
3869 mobj->tracer = NULL;
3870 if (!P_SetTarget(&mobj->tracer, P_FindNewPosition(temp)))
3871 CONS_Debug(DBG_GAMELOGIC, "tracer not found on %d\n", mobj->type);
3872 }
3873 if (mobj->target)
3874 {
3875 temp = (UINT32)(size_t)mobj->target;
3876 mobj->target = NULL;
3877 if (!P_SetTarget(&mobj->target, P_FindNewPosition(temp)))
3878 CONS_Debug(DBG_GAMELOGIC, "target not found on %d\n", mobj->type);
3879 }
3880 if (mobj->hnext)
3881 {
3882 temp = (UINT32)(size_t)mobj->hnext;
3883 mobj->hnext = NULL;
3884 if (!(mobj->hnext = P_FindNewPosition(temp)))
3885 CONS_Debug(DBG_GAMELOGIC, "hnext not found on %d\n", mobj->type);
3886 }
3887 if (mobj->hprev)
3888 {
3889 temp = (UINT32)(size_t)mobj->hprev;
3890 mobj->hprev = NULL;
3891 if (!(mobj->hprev = P_FindNewPosition(temp)))
3892 CONS_Debug(DBG_GAMELOGIC, "hprev not found on %d\n", mobj->type);
3893 }
3894 if (mobj->player && mobj->player->capsule)
3895 {
3896 temp = (UINT32)(size_t)mobj->player->capsule;
3897 mobj->player->capsule = NULL;
3898 if (!P_SetTarget(&mobj->player->capsule, P_FindNewPosition(temp)))
3899 CONS_Debug(DBG_GAMELOGIC, "capsule not found on %d\n", mobj->type);
3900 }
3901 if (mobj->player && mobj->player->axis1)
3902 {
3903 temp = (UINT32)(size_t)mobj->player->axis1;
3904 mobj->player->axis1 = NULL;
3905 if (!P_SetTarget(&mobj->player->axis1, P_FindNewPosition(temp)))
3906 CONS_Debug(DBG_GAMELOGIC, "axis1 not found on %d\n", mobj->type);
3907 }
3908 if (mobj->player && mobj->player->axis2)
3909 {
3910 temp = (UINT32)(size_t)mobj->player->axis2;
3911 mobj->player->axis2 = NULL;
3912 if (!P_SetTarget(&mobj->player->axis2, P_FindNewPosition(temp)))
3913 CONS_Debug(DBG_GAMELOGIC, "axis2 not found on %d\n", mobj->type);
3914 }
3915 if (mobj->player && mobj->player->awayviewmobj)
3916 {
3917 temp = (UINT32)(size_t)mobj->player->awayviewmobj;
3918 mobj->player->awayviewmobj = NULL;
3919 if (!P_SetTarget(&mobj->player->awayviewmobj, P_FindNewPosition(temp)))
3920 CONS_Debug(DBG_GAMELOGIC, "awayviewmobj not found on %d\n", mobj->type);
3921 }
3922 if (mobj->player && mobj->player->followmobj)
3923 {
3924 temp = (UINT32)(size_t)mobj->player->followmobj;
3925 mobj->player->followmobj = NULL;
3926 if (!P_SetTarget(&mobj->player->followmobj, P_FindNewPosition(temp)))
3927 CONS_Debug(DBG_GAMELOGIC, "followmobj not found on %d\n", mobj->type);
3928 }
3929 if (mobj->player && mobj->player->drone)
3930 {
3931 temp = (UINT32)(size_t)mobj->player->drone;
3932 mobj->player->drone = NULL;
3933 if (!P_SetTarget(&mobj->player->drone, P_FindNewPosition(temp)))
3934 CONS_Debug(DBG_GAMELOGIC, "drone not found on %d\n", mobj->type);
3935 }
3936 }
3937 }
3938
P_NetArchiveSpecials(void)3939 static inline void P_NetArchiveSpecials(void)
3940 {
3941 size_t i, z;
3942
3943 WRITEUINT32(save_p, ARCHIVEBLOCK_SPECIALS);
3944
3945 // itemrespawn queue for deathmatch
3946 i = iquetail;
3947 while (iquehead != i)
3948 {
3949 for (z = 0; z < nummapthings; z++)
3950 {
3951 if (&mapthings[z] == itemrespawnque[i])
3952 {
3953 WRITEUINT32(save_p, z);
3954 break;
3955 }
3956 }
3957 WRITEUINT32(save_p, itemrespawntime[i]);
3958 i = (i + 1) & (ITEMQUESIZE-1);
3959 }
3960
3961 // end delimiter
3962 WRITEUINT32(save_p, 0xffffffff);
3963
3964 // Sky number
3965 WRITEINT32(save_p, globallevelskynum);
3966
3967 // Current global weather type
3968 WRITEUINT8(save_p, globalweather);
3969
3970 if (metalplayback) // Is metal sonic running?
3971 {
3972 WRITEUINT8(save_p, 0x01);
3973 G_SaveMetal(&save_p);
3974 }
3975 else
3976 WRITEUINT8(save_p, 0x00);
3977 }
3978
P_NetUnArchiveSpecials(void)3979 static void P_NetUnArchiveSpecials(void)
3980 {
3981 size_t i;
3982 INT32 j;
3983
3984 if (READUINT32(save_p) != ARCHIVEBLOCK_SPECIALS)
3985 I_Error("Bad $$$.sav at archive block Specials");
3986
3987 // BP: added save itemrespawn queue for deathmatch
3988 iquetail = iquehead = 0;
3989 while ((i = READUINT32(save_p)) != 0xffffffff)
3990 {
3991 itemrespawnque[iquehead] = &mapthings[i];
3992 itemrespawntime[iquehead++] = READINT32(save_p);
3993 }
3994
3995 j = READINT32(save_p);
3996 if (j != globallevelskynum)
3997 P_SetupLevelSky(j, true);
3998
3999 globalweather = READUINT8(save_p);
4000
4001 if (globalweather)
4002 {
4003 if (curWeather == globalweather)
4004 curWeather = PRECIP_NONE;
4005
4006 P_SwitchWeather(globalweather);
4007 }
4008 else // PRECIP_NONE
4009 {
4010 if (curWeather != PRECIP_NONE)
4011 P_SwitchWeather(globalweather);
4012 }
4013
4014 if (READUINT8(save_p) == 0x01) // metal sonic
4015 G_LoadMetal(&save_p);
4016 }
4017
4018 // =======================================================================
4019 // Misc
4020 // =======================================================================
P_ArchiveMisc(INT16 mapnum)4021 static inline void P_ArchiveMisc(INT16 mapnum)
4022 {
4023 //lastmapsaved = mapnum;
4024 lastmaploaded = mapnum;
4025
4026 if (gamecomplete)
4027 mapnum |= 8192;
4028
4029 WRITEINT16(save_p, mapnum);
4030 WRITEUINT16(save_p, emeralds+357);
4031 WRITESTRINGN(save_p, timeattackfolder, sizeof(timeattackfolder));
4032 }
4033
P_UnArchiveSPGame(INT16 mapoverride)4034 static inline void P_UnArchiveSPGame(INT16 mapoverride)
4035 {
4036 char testname[sizeof(timeattackfolder)];
4037
4038 gamemap = READINT16(save_p);
4039
4040 if (mapoverride != 0)
4041 {
4042 gamemap = mapoverride;
4043 gamecomplete = 1;
4044 }
4045 else
4046 gamecomplete = 0;
4047
4048 // gamemap changed; we assume that its map header is always valid,
4049 // so make it so
4050 if(!mapheaderinfo[gamemap-1])
4051 P_AllocMapHeader(gamemap-1);
4052
4053 //lastmapsaved = gamemap;
4054 lastmaploaded = gamemap;
4055
4056 tokenlist = 0;
4057 token = 0;
4058
4059 savedata.emeralds = READUINT16(save_p)-357;
4060
4061 READSTRINGN(save_p, testname, sizeof(testname));
4062
4063 if (strcmp(testname, timeattackfolder))
4064 {
4065 if (modifiedgame)
4066 I_Error("Save game not for this modification.");
4067 else
4068 I_Error("This save file is for a particular mod, it cannot be used with the regular game.");
4069 }
4070
4071 memset(playeringame, 0, sizeof(*playeringame));
4072 playeringame[consoleplayer] = true;
4073 }
4074
P_NetArchiveMisc(boolean resending)4075 static void P_NetArchiveMisc(boolean resending)
4076 {
4077 INT32 i;
4078
4079 WRITEUINT32(save_p, ARCHIVEBLOCK_MISC);
4080
4081 if (resending)
4082 WRITEUINT32(save_p, gametic);
4083 WRITEINT16(save_p, gamemap);
4084 WRITEINT16(save_p, gamestate);
4085 WRITEINT16(save_p, gametype);
4086
4087 {
4088 UINT32 pig = 0;
4089 for (i = 0; i < MAXPLAYERS; i++)
4090 pig |= (playeringame[i] != 0)<<i;
4091 WRITEUINT32(save_p, pig);
4092 }
4093
4094 WRITEUINT32(save_p, P_GetRandSeed());
4095
4096 WRITEUINT32(save_p, tokenlist);
4097
4098 WRITEUINT32(save_p, leveltime);
4099 WRITEUINT32(save_p, ssspheres);
4100 WRITEINT16(save_p, lastmap);
4101 WRITEUINT16(save_p, bossdisabled);
4102
4103 WRITEUINT16(save_p, emeralds);
4104 {
4105 UINT8 globools = 0;
4106 if (stagefailed)
4107 globools |= 1;
4108 if (stoppedclock)
4109 globools |= (1<<1);
4110 WRITEUINT8(save_p, globools);
4111 }
4112
4113 WRITEUINT32(save_p, token);
4114 WRITEINT32(save_p, sstimer);
4115 WRITEUINT32(save_p, bluescore);
4116 WRITEUINT32(save_p, redscore);
4117
4118 WRITEUINT16(save_p, skincolor_redteam);
4119 WRITEUINT16(save_p, skincolor_blueteam);
4120 WRITEUINT16(save_p, skincolor_redring);
4121 WRITEUINT16(save_p, skincolor_bluering);
4122
4123 WRITEINT32(save_p, modulothing);
4124
4125 WRITEINT16(save_p, autobalance);
4126 WRITEINT16(save_p, teamscramble);
4127
4128 for (i = 0; i < MAXPLAYERS; i++)
4129 WRITEINT16(save_p, scrambleplayers[i]);
4130
4131 for (i = 0; i < MAXPLAYERS; i++)
4132 WRITEINT16(save_p, scrambleteams[i]);
4133
4134 WRITEINT16(save_p, scrambletotal);
4135 WRITEINT16(save_p, scramblecount);
4136
4137 WRITEUINT32(save_p, countdown);
4138 WRITEUINT32(save_p, countdown2);
4139
4140 WRITEFIXED(save_p, gravity);
4141
4142 WRITEUINT32(save_p, countdowntimer);
4143 WRITEUINT8(save_p, countdowntimeup);
4144
4145 WRITEUINT32(save_p, hidetime);
4146
4147 // Is it paused?
4148 if (paused)
4149 WRITEUINT8(save_p, 0x2f);
4150 else
4151 WRITEUINT8(save_p, 0x2e);
4152 }
4153
P_NetUnArchiveMisc(boolean reloading)4154 static inline boolean P_NetUnArchiveMisc(boolean reloading)
4155 {
4156 INT32 i;
4157
4158 if (READUINT32(save_p) != ARCHIVEBLOCK_MISC)
4159 I_Error("Bad $$$.sav at archive block Misc");
4160
4161 if (reloading)
4162 gametic = READUINT32(save_p);
4163
4164 gamemap = READINT16(save_p);
4165
4166 // gamemap changed; we assume that its map header is always valid,
4167 // so make it so
4168 if(!mapheaderinfo[gamemap-1])
4169 P_AllocMapHeader(gamemap-1);
4170
4171 // tell the sound code to reset the music since we're skipping what
4172 // normally sets this flag
4173 mapmusflags |= MUSIC_RELOADRESET;
4174
4175 G_SetGamestate(READINT16(save_p));
4176
4177 gametype = READINT16(save_p);
4178
4179 {
4180 UINT32 pig = READUINT32(save_p);
4181 for (i = 0; i < MAXPLAYERS; i++)
4182 {
4183 playeringame[i] = (pig & (1<<i)) != 0;
4184 // playerstate is set in unarchiveplayers
4185 }
4186 }
4187
4188 P_SetRandSeed(READUINT32(save_p));
4189
4190 tokenlist = READUINT32(save_p);
4191
4192 if (!P_LoadLevel(true, reloading))
4193 return false;
4194
4195 // get the time
4196 leveltime = READUINT32(save_p);
4197 ssspheres = READUINT32(save_p);
4198 lastmap = READINT16(save_p);
4199 bossdisabled = READUINT16(save_p);
4200
4201 emeralds = READUINT16(save_p);
4202 {
4203 UINT8 globools = READUINT8(save_p);
4204 stagefailed = !!(globools & 1);
4205 stoppedclock = !!(globools & (1<<1));
4206 }
4207
4208 token = READUINT32(save_p);
4209 sstimer = READINT32(save_p);
4210 bluescore = READUINT32(save_p);
4211 redscore = READUINT32(save_p);
4212
4213 skincolor_redteam = READUINT16(save_p);
4214 skincolor_blueteam = READUINT16(save_p);
4215 skincolor_redring = READUINT16(save_p);
4216 skincolor_bluering = READUINT16(save_p);
4217
4218 modulothing = READINT32(save_p);
4219
4220 autobalance = READINT16(save_p);
4221 teamscramble = READINT16(save_p);
4222
4223 for (i = 0; i < MAXPLAYERS; i++)
4224 scrambleplayers[i] = READINT16(save_p);
4225
4226 for (i = 0; i < MAXPLAYERS; i++)
4227 scrambleteams[i] = READINT16(save_p);
4228
4229 scrambletotal = READINT16(save_p);
4230 scramblecount = READINT16(save_p);
4231
4232 countdown = READUINT32(save_p);
4233 countdown2 = READUINT32(save_p);
4234
4235 gravity = READFIXED(save_p);
4236
4237 countdowntimer = (tic_t)READUINT32(save_p);
4238 countdowntimeup = (boolean)READUINT8(save_p);
4239
4240 hidetime = READUINT32(save_p);
4241
4242 // Is it paused?
4243 if (READUINT8(save_p) == 0x2f)
4244 paused = true;
4245
4246 return true;
4247 }
4248
P_ArchiveLuabanksAndConsistency(void)4249 static inline void P_ArchiveLuabanksAndConsistency(void)
4250 {
4251 UINT8 i, banksinuse = NUM_LUABANKS;
4252
4253 while (banksinuse && !luabanks[banksinuse-1])
4254 banksinuse--; // get the last used bank
4255
4256 if (banksinuse)
4257 {
4258 WRITEUINT8(save_p, 0xb7); // luabanks marker
4259 WRITEUINT8(save_p, banksinuse);
4260 for (i = 0; i < banksinuse; i++)
4261 WRITEINT32(save_p, luabanks[i]);
4262 }
4263
4264 WRITEUINT8(save_p, 0x1d); // consistency marker
4265 }
4266
P_UnArchiveLuabanksAndConsistency(void)4267 static inline boolean P_UnArchiveLuabanksAndConsistency(void)
4268 {
4269 switch (READUINT8(save_p))
4270 {
4271 case 0xb7:
4272 {
4273 UINT8 i, banksinuse = READUINT8(save_p);
4274 if (banksinuse > NUM_LUABANKS)
4275 return false;
4276 for (i = 0; i < banksinuse; i++)
4277 luabanks[i] = READINT32(save_p);
4278 if (READUINT8(save_p) != 0x1d)
4279 return false;
4280 }
4281 case 0x1d:
4282 break;
4283 default:
4284 return false;
4285 }
4286
4287 return true;
4288 }
4289
P_SaveGame(INT16 mapnum)4290 void P_SaveGame(INT16 mapnum)
4291 {
4292 P_ArchiveMisc(mapnum);
4293 P_ArchivePlayer();
4294 P_ArchiveLuabanksAndConsistency();
4295 }
4296
P_SaveNetGame(boolean resending)4297 void P_SaveNetGame(boolean resending)
4298 {
4299 thinker_t *th;
4300 mobj_t *mobj;
4301 INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise
4302
4303 CV_SaveNetVars(&save_p);
4304 P_NetArchiveMisc(resending);
4305
4306 // Assign the mobjnumber for pointer tracking
4307 for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
4308 {
4309 if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
4310 continue;
4311
4312 mobj = (mobj_t *)th;
4313 if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER)
4314 continue;
4315 mobj->mobjnum = i++;
4316 }
4317
4318 P_NetArchivePlayers();
4319 if (gamestate == GS_LEVEL)
4320 {
4321 P_NetArchiveWorld();
4322 P_ArchivePolyObjects();
4323 P_NetArchiveThinkers();
4324 P_NetArchiveSpecials();
4325 P_NetArchiveColormaps();
4326 P_NetArchiveWaypoints();
4327 }
4328 LUA_Archive();
4329
4330 P_ArchiveLuabanksAndConsistency();
4331 }
4332
P_LoadGame(INT16 mapoverride)4333 boolean P_LoadGame(INT16 mapoverride)
4334 {
4335 if (gamestate == GS_INTERMISSION)
4336 Y_EndIntermission();
4337 G_SetGamestate(GS_NULL); // should be changed in P_UnArchiveMisc
4338
4339 P_UnArchiveSPGame(mapoverride);
4340 P_UnArchivePlayer();
4341
4342 if (!P_UnArchiveLuabanksAndConsistency())
4343 return false;
4344
4345 // Only do this after confirming savegame is ok
4346 G_DeferedInitNew(false, G_BuildMapName(gamemap), savedata.skin, false, true);
4347 COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this
4348
4349 return true;
4350 }
4351
P_LoadNetGame(boolean reloading)4352 boolean P_LoadNetGame(boolean reloading)
4353 {
4354 CV_LoadNetVars(&save_p);
4355 if (!P_NetUnArchiveMisc(reloading))
4356 return false;
4357 P_NetUnArchivePlayers();
4358 if (gamestate == GS_LEVEL)
4359 {
4360 P_NetUnArchiveWorld();
4361 P_UnArchivePolyObjects();
4362 P_NetUnArchiveThinkers();
4363 P_NetUnArchiveSpecials();
4364 P_NetUnArchiveColormaps();
4365 P_NetUnArchiveWaypoints();
4366 P_RelinkPointers();
4367 P_FinishMobjs();
4368 }
4369 LUA_UnArchive();
4370
4371 // This is stupid and hacky, but maybe it'll work!
4372 P_SetRandSeed(P_GetInitSeed());
4373
4374 // The precipitation would normally be spawned in P_SetupLevel, which is called by
4375 // P_NetUnArchiveMisc above. However, that would place it up before P_NetUnArchiveThinkers,
4376 // so the thinkers would be deleted later. Therefore, P_SetupLevel will *not* spawn
4377 // precipitation when loading a netgame save. Instead, precip has to be spawned here.
4378 // This is done in P_NetUnArchiveSpecials now.
4379
4380 return P_UnArchiveLuabanksAndConsistency();
4381 }
4382