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(&sectors[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 &sectors[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