1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010-2019 EDuke32 developers and contributors
4 Copyright (C) 2019 sirlemonhead, Nuke.YKT
5
6 This file is part of PCExhumed.
7
8 PCExhumed is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License version 2
10 as published by the Free Software Foundation.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
16 See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22 //-------------------------------------------------------------------------
23
24 #include "engine.h"
25 #include "exhumed.h"
26 #include "move.h"
27 #include "init.h"
28 #include "lighting.h"
29 #include "ramses.h"
30 #include "bubbles.h"
31 #include "object.h"
32 #include "player.h"
33 #include "view.h"
34 #include "status.h"
35 #include "runlist.h"
36 #include "items.h"
37 #include "sound.h"
38 #include "trigdat.h"
39 #include "anims.h"
40 #include "random.h"
41 #include "bullet.h"
42 #include "save.h"
43 #include <string.h>
44 #include <assert.h>
45 #ifndef __WATCOMC__
46 //#include <cmath>
47 #else
48 #include <stdlib.h>
49 //#include <math.h>
50 #endif
51
52 #define kMaxPushBlocks 100
53 #define kMaxChunks 75
54
55 short NearCount = -1;
56 short NearSector[kMaxSectors] = { 0 };
57
58 short nPushBlocks;
59 BlockInfo sBlockInfo[kMaxPushBlocks];
60
61 // TODO - moveme?
62 short overridesect;
63 short nBodySprite[50];
64 int hihit, sprceiling, sprfloor, lohit;
65
66 short nChunkSprite[kMaxChunks];
67
68
lsqrt(int a1)69 signed int lsqrt(int a1)
70 {
71 int v1;
72 int v2;
73 signed int result;
74
75 v1 = a1;
76 v2 = a1 - 0x40000000;
77
78 result = 0;
79
80 if (v2 >= 0)
81 {
82 result = 32768;
83 v1 = v2;
84 }
85 if (v1 - ((result << 15) + 0x10000000) >= 0)
86 {
87 v1 -= (result << 15) + 0x10000000;
88 result += 16384;
89 }
90 if (v1 - ((result << 14) + 0x4000000) >= 0)
91 {
92 v1 -= (result << 14) + 0x4000000;
93 result += 8192;
94 }
95 if (v1 - ((result << 13) + 0x1000000) >= 0)
96 {
97 v1 -= (result << 13) + 0x1000000;
98 result += 4096;
99 }
100 if (v1 - ((result << 12) + 0x400000) >= 0)
101 {
102 v1 -= (result << 12) + 0x400000;
103 result += 2048;
104 }
105 if (v1 - ((result << 11) + 0x100000) >= 0)
106 {
107 v1 -= (result << 11) + 0x100000;
108 result += 1024;
109 }
110 if (v1 - ((result << 10) + 0x40000) >= 0)
111 {
112 v1 -= (result << 10) + 0x40000;
113 result += 512;
114 }
115 if (v1 - ((result << 9) + 0x10000) >= 0)
116 {
117 v1 -= (result << 9) + 0x10000;
118 result += 256;
119 }
120 if (v1 - ((result << 8) + 0x4000) >= 0)
121 {
122 v1 -= (result << 8) + 0x4000;
123 result += 128;
124 }
125 if (v1 - ((result << 7) + 4096) >= 0)
126 {
127 v1 -= (result << 7) + 4096;
128 result += 64;
129 }
130 if (v1 - ((result << 6) + 1024) >= 0)
131 {
132 v1 -= (result << 6) + 1024;
133 result += 32;
134 }
135 if (v1 - (32 * result + 256) >= 0)
136 {
137 v1 -= 32 * result + 256;
138 result += 16;
139 }
140 if (v1 - (16 * result + 64) >= 0)
141 {
142 v1 -= 16 * result + 64;
143 result += 8;
144 }
145 if (v1 - (8 * result + 16) >= 0)
146 {
147 v1 -= 8 * result + 16;
148 result += 4;
149 }
150 if (v1 - (4 * result + 4) >= 0)
151 {
152 v1 -= 4 * result + 4;
153 result += 2;
154 }
155 if (v1 - (2 * result + 1) >= 0)
156 result += 1;
157
158 return result;
159 }
160
MoveThings()161 void MoveThings()
162 {
163 UndoFlashes();
164 DoLights();
165
166 if (nFreeze)
167 {
168 if (nFreeze == 1 || nFreeze == 2) {
169 DoSpiritHead();
170 }
171 }
172 else
173 {
174 runlist_ExecObjects();
175 runlist_CleanRunRecs();
176 }
177
178 MoveStatus();
179 DoBubbleMachines();
180 DoDrips();
181 DoMovingSects();
182 DoRegenerates();
183
184 if (nCameraDist >= 0)
185 {
186 nCameraDist = min(nCameraDist + (((int32_t)totalclock - nCameraClock) << 10), 65536);
187 nCameraClock = (int32_t)totalclock;
188 }
189
190 if (levelnum == kMap20)
191 {
192 DoFinale();
193 if (lCountDown < 1800 && nDronePitch < 2400 && !lFinaleStart)
194 {
195 nDronePitch += 64;
196 BendAmbientSound();
197 }
198 }
199 }
200
ResetMoveFifo()201 void ResetMoveFifo()
202 {
203 localclock = (int)totalclock;
204 movefifoend = 0;
205 movefifopos = 0;
206 }
207
208 // not used
clipwall()209 void clipwall()
210 {
211
212 }
213
BuildNear(int x,int y,int walldist,int nSector)214 void BuildNear(int x, int y, int walldist, int nSector)
215 {
216 NearSector[0] = nSector;
217 NearCount = 1;
218
219 int i = 0;
220
221 while (i < NearCount)
222 {
223 short nSector = NearSector[i];
224
225 short nWall = sector[nSector].wallptr;
226 short nWallCount = sector[nSector].wallnum;
227
228 while (1)
229 {
230 nWallCount--;
231 if (nWallCount < 0)
232 {
233 i++;
234 break;
235 }
236
237 short nNextSector = wall[nWall].nextsector;
238
239 if (nNextSector >= 0)
240 {
241 int j = 0;
242 for (; j < NearCount; j++)
243 {
244 // loc_14F4D:
245 if (nNextSector == NearSector[j])
246 break;
247 }
248
249 if (j >= NearCount)
250 {
251 vec2_t pos = { x, y };
252 if (clipinsidebox(&pos, nWall, walldist))
253 {
254 NearSector[NearCount] = wall[nWall].nextsector;
255 NearCount++;
256 }
257 }
258 }
259
260 nWall++;
261 }
262 }
263 }
264
BelowNear(short nSprite)265 int BelowNear(short nSprite)
266 {
267 short nSector = sprite[nSprite].sectnum;
268 int z = sprite[nSprite].z;
269
270 int var_24, z2;
271
272 if ((lohit & 0xC000) == 0xC000)
273 {
274 var_24 = lohit & 0xC000;
275 z2 = sprite[lohit & 0x3FFF].z;
276 }
277 else
278 {
279 var_24 = 0x20000;
280 z2 = sector[nSector].floorz + SectDepth[nSector];
281
282 if (NearCount > 0)
283 {
284 short edx;
285
286 for (int i = 0; i < NearCount; i++)
287 {
288 int nSect2 = NearSector[i];
289
290 while (nSect2 >= 0)
291 {
292 edx = nSect2;
293 nSect2 = SectBelow[nSect2];
294 }
295
296 int ecx = sector[edx].floorz + SectDepth[edx];
297 int eax = ecx - z;
298
299 if (eax < 0 && eax >= -5120)
300 {
301 z2 = ecx;
302 nSector = edx;
303 }
304 }
305 }
306 }
307
308 if (z2 < sprite[nSprite].z)
309 {
310 sprite[nSprite].z = z2;
311 overridesect = nSector;
312 sprite[nSprite].zvel = 0;
313
314 bTouchFloor = kTrue;
315
316 return var_24;
317 }
318 else
319 {
320 return 0;
321 }
322 }
323
movespritez(short nSprite,int z,int height,int UNUSED (flordist),int clipdist)324 int movespritez(short nSprite, int z, int height, int UNUSED(flordist), int clipdist)
325 {
326 spritetype* pSprite = &sprite[nSprite];
327 short nSector = pSprite->sectnum;
328 assert(nSector >= 0 && nSector < kMaxSectors);
329
330 overridesect = nSector;
331 short edi = nSector;
332
333 // backup cstat
334 uint16_t cstat = pSprite->cstat;
335
336 pSprite->cstat &= ~CSTAT_SPRITE_BLOCK;
337
338 int nRet = 0;
339
340 short nSectFlags = SectFlag[nSector];
341
342 if (nSectFlags & kSectUnderwater) {
343 z >>= 1;
344 }
345
346 int spriteZ = pSprite->z;
347 int floorZ = sector[nSector].floorz;
348
349 int ebp = spriteZ + z;
350 int eax = sector[nSector].ceilingz + (height >> 1);
351
352 if ((nSectFlags & kSectUnderwater) && ebp < eax) {
353 ebp = eax;
354 }
355
356 // loc_151E7:
357 while (ebp > sector[pSprite->sectnum].floorz && SectBelow[pSprite->sectnum] >= 0)
358 {
359 edi = SectBelow[pSprite->sectnum];
360
361 mychangespritesect(nSprite, edi);
362 }
363
364 if (edi != nSector)
365 {
366 pSprite->z = ebp;
367
368 if (SectFlag[edi] & kSectUnderwater)
369 {
370 if (nSprite == PlayerList[nLocalPlayer].nSprite) {
371 D3PlayFX(StaticSound[kSoundBubbleLow], nSprite);
372 }
373
374 if (pSprite->statnum <= 107) {
375 pSprite->hitag = 0;
376 }
377 }
378 }
379 else
380 {
381 while ((ebp < sector[pSprite->sectnum].ceilingz) && (SectAbove[pSprite->sectnum] >= 0))
382 {
383 edi = SectAbove[pSprite->sectnum];
384
385 mychangespritesect(nSprite, edi);
386 }
387 }
388
389 // This function will keep the player from falling off cliffs when you're too close to the edge.
390 // This function finds the highest and lowest z coordinates that your clipping BOX can get to.
391 getzrange_old(pSprite->x, pSprite->y, pSprite->z - 256, pSprite->sectnum,
392 &sprceiling, &hihit, &sprfloor, &lohit, 128, CLIPMASK0);
393
394 int mySprfloor = sprfloor;
395
396 if ((lohit & 0xC000) != 0xC000) {
397 mySprfloor += SectDepth[pSprite->sectnum];
398 }
399
400 if (ebp > mySprfloor)
401 {
402 if (z > 0)
403 {
404 bTouchFloor = kTrue;
405
406 if ((lohit & 0xC000) == 0xC000)
407 {
408 // Path A
409 short nFloorSprite = lohit & 0x3FFF;
410
411 if (pSprite->statnum == 100 && sprite[nFloorSprite].statnum != 0 && sprite[nFloorSprite].statnum < 100)
412 {
413 short nDamage = (z >> 9);
414 if (nDamage)
415 {
416 runlist_DamageEnemy(nFloorSprite, nSprite, nDamage << 1);
417 }
418
419 pSprite->zvel = -z;
420 }
421 else
422 {
423 if (sprite[nFloorSprite].statnum == 0 || sprite[nFloorSprite].statnum > 199)
424 {
425 nRet |= 0x20000;
426 }
427 else
428 {
429 nRet |= lohit;
430 }
431
432 pSprite->zvel = 0;
433 }
434 }
435 else
436 {
437 // Path B
438 if (SectBelow[pSprite->sectnum] == -1)
439 {
440 nRet |= 0x20000;
441
442 short nSectDamage = SectDamage[pSprite->sectnum];
443
444 if (nSectDamage != 0)
445 {
446 if (pSprite->hitag < 15)
447 {
448 IgniteSprite(nSprite);
449 pSprite->hitag = 20;
450 }
451 nSectDamage >>= 2;
452 nSectDamage = nSectDamage - (nSectDamage>>2);
453 if (nSectDamage) {
454 runlist_DamageEnemy(nSprite, -1, nSectDamage);
455 }
456 }
457
458 pSprite->zvel = 0;
459 }
460 }
461 }
462
463 // loc_1543B:
464 ebp = mySprfloor;
465 pSprite->z = mySprfloor;
466 }
467 else
468 {
469 if ((ebp - height) < sprceiling && ((hihit & 0xC000) == 0xC000 || SectAbove[pSprite->sectnum] == -1))
470 {
471 ebp = sprceiling + height;
472 nRet |= 0x10000;
473 }
474 }
475
476 if (spriteZ <= floorZ && ebp > floorZ)
477 {
478 if ((SectDepth[nSector] != 0) || (edi != nSector && (SectFlag[edi] & kSectUnderwater)))
479 {
480 assert(nSector >= 0 && nSector < kMaxSectors);
481 BuildSplash(nSprite, nSector);
482 }
483 }
484
485 pSprite->cstat = cstat; // restore cstat
486 pSprite->z = ebp;
487
488 if (pSprite->statnum == 100)
489 {
490 BuildNear(pSprite->x, pSprite->y, clipdist + (clipdist / 2), pSprite->sectnum);
491 nRet |= BelowNear(nSprite);
492 }
493
494 return nRet;
495 }
496
GetSpriteHeight(int nSprite)497 int GetSpriteHeight(int nSprite)
498 {
499 return tilesiz[sprite[nSprite].picnum].y * sprite[nSprite].yrepeat * 4;
500 }
501
movesprite(short nSprite,int dx,int dy,int dz,int UNUSED (ceildist),int flordist,unsigned int clipmask)502 int movesprite(short nSprite, int dx, int dy, int dz, int UNUSED(ceildist), int flordist, unsigned int clipmask)
503 {
504 spritetype *pSprite = &sprite[nSprite];
505 bTouchFloor = kFalse;
506
507 int x = pSprite->x;
508 int y = pSprite->y;
509 int z = pSprite->z;
510
511 int nSpriteHeight = GetSpriteHeight(nSprite);
512
513 int nClipDist = (int8_t)pSprite->clipdist << 2;
514
515 short nSector = pSprite->sectnum;
516 assert(nSector >= 0 && nSector < kMaxSectors);
517
518 int floorZ = sector[nSector].floorz;
519
520 int nRet = 0;
521
522 if ((SectFlag[nSector] & kSectUnderwater) || (floorZ < z))
523 {
524 dx >>= 1;
525 dy >>= 1;
526 }
527
528 nRet |= movespritez(nSprite, dz, nSpriteHeight, flordist, nClipDist);
529
530 nSector = pSprite->sectnum; // modified in movespritez so re-grab this variable
531
532 if (pSprite->statnum == 100)
533 {
534 short nPlayer = GetPlayerFromSprite(nSprite);
535
536 int varA = 0;
537 int varB = 0;
538
539 CheckSectorFloor(overridesect, pSprite->z, &varB, &varA);
540
541 if (varB || varA)
542 {
543 nXDamage[nPlayer] = varB;
544 nYDamage[nPlayer] = varA;
545 }
546
547 dx += nXDamage[nPlayer];
548 dy += nYDamage[nPlayer];
549 }
550 else
551 {
552 CheckSectorFloor(overridesect, pSprite->z, &dx, &dy);
553 }
554
555 nRet |= (uint16_t)clipmove_old(&pSprite->x, &pSprite->y, &pSprite->z, &nSector, dx, dy, nClipDist, nSpriteHeight, flordist, clipmask);
556
557 if ((nSector != pSprite->sectnum) && nSector >= 0)
558 {
559 if (nRet & 0x20000) {
560 dz = 0;
561 }
562
563 if ((sector[nSector].floorz - z) < (dz + flordist))
564 {
565 pSprite->x = x;
566 pSprite->y = y;
567 }
568 else
569 {
570 mychangespritesect(nSprite, nSector);
571
572 if (pSprite->pal < 5 && !pSprite->hitag)
573 {
574 pSprite->pal = sector[pSprite->sectnum].ceilingpal;
575 }
576 }
577 }
578
579 return nRet;
580 }
581
Gravity(short nSprite)582 void Gravity(short nSprite)
583 {
584 short nSector = sprite[nSprite].sectnum;
585
586 if (SectFlag[nSector] & kSectUnderwater)
587 {
588 if (sprite[nSprite].statnum != 100)
589 {
590 if (sprite[nSprite].zvel <= 1024)
591 {
592 if (sprite[nSprite].zvel < 2048) {
593 sprite[nSprite].zvel += 512;
594 }
595 }
596 else
597 {
598 sprite[nSprite].zvel -= 64;
599 }
600 }
601 else
602 {
603 if (sprite[nSprite].zvel > 0)
604 {
605 sprite[nSprite].zvel -= 64;
606 if (sprite[nSprite].zvel < 0) {
607 sprite[nSprite].zvel = 0;
608 }
609 }
610 else if (sprite[nSprite].zvel < 0)
611 {
612 sprite[nSprite].zvel += 64;
613 if (sprite[nSprite].zvel > 0) {
614 sprite[nSprite].zvel = 0;
615 }
616 }
617 }
618 }
619 else
620 {
621 sprite[nSprite].zvel += 512;
622 if (sprite[nSprite].zvel > 16384) {
623 sprite[nSprite].zvel = 16384;
624 }
625 }
626 }
627
MoveCreature(short nSprite)628 int MoveCreature(short nSprite)
629 {
630 return movesprite(nSprite, sprite[nSprite].xvel << 8, sprite[nSprite].yvel << 8, sprite[nSprite].zvel, 15360, -5120, CLIPMASK0);
631 }
632
MoveCreatureWithCaution(int nSprite)633 int MoveCreatureWithCaution(int nSprite)
634 {
635 int x = sprite[nSprite].x;
636 int y = sprite[nSprite].y;
637 int z = sprite[nSprite].z;
638 short nSectorPre = sprite[nSprite].sectnum;
639
640 int ecx = MoveCreature(nSprite);
641
642 short nSector = sprite[nSprite].sectnum;
643
644 if (nSector != nSectorPre)
645 {
646 int zDiff = sector[nSectorPre].floorz - sector[nSector].floorz;
647 if (zDiff < 0) {
648 zDiff = -zDiff;
649 }
650
651 if (zDiff > 15360 || (SectFlag[nSector] & kSectUnderwater) || (SectBelow[nSector] > -1 && SectFlag[SectBelow[nSector]]) || SectDamage[nSector])
652 {
653 sprite[nSprite].x = x;
654 sprite[nSprite].y = y;
655 sprite[nSprite].z = z;
656
657 mychangespritesect(nSprite, nSectorPre);
658
659 sprite[nSprite].ang = (sprite[nSprite].ang + 256) & kAngleMask;
660 sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 2;
661 sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 2;
662 return 0;
663 }
664 }
665
666 return ecx;
667 }
668
GetAngleToSprite(int nSprite1,int nSprite2)669 int GetAngleToSprite(int nSprite1, int nSprite2)
670 {
671 if (nSprite1 < 0 || nSprite2 < 0)
672 return -1;
673
674 return GetMyAngle(sprite[nSprite2].x - sprite[nSprite1].x, sprite[nSprite2].y - sprite[nSprite1].y);
675 }
676
PlotCourseToSprite(int nSprite1,int nSprite2)677 int PlotCourseToSprite(int nSprite1, int nSprite2)
678 {
679 if (nSprite1 < 0 || nSprite2 < 0)
680 return -1;
681
682 int x = sprite[nSprite2].x - sprite[nSprite1].x;
683 int y = sprite[nSprite2].y - sprite[nSprite1].y;
684
685 sprite[nSprite1].ang = GetMyAngle(x, y);
686
687 uint32_t x2 = klabs(x);
688 uint32_t y2 = klabs(y);
689
690 uint32_t diff = x2 * x2 + y2 * y2;
691
692 if (diff > INT_MAX)
693 {
694 OSD_Printf("%s %d: overflow\n", EDUKE32_FUNCTION, __LINE__);
695 diff = INT_MAX;
696 }
697
698 return ksqrt(diff);
699 }
700
FindPlayer(int nSprite,int nDistance)701 int FindPlayer(int nSprite, int nDistance)
702 {
703 int var_18 = 0;
704 if (nSprite >= 0)
705 var_18 = 1;
706
707 if (nSprite < 0)
708 nSprite = -nSprite;
709
710 if (nDistance < 0)
711 nDistance = 100;
712
713 int x = sprite[nSprite].x;
714 int y = sprite[nSprite].y;
715 short nSector = sprite[nSprite].sectnum;
716
717 int z = sprite[nSprite].z - GetSpriteHeight(nSprite);
718
719 nDistance <<= 8;
720
721 short nPlayerSprite;
722 int i = 0;
723
724 while (1)
725 {
726 if (i >= nTotalPlayers)
727 return -1;
728
729 nPlayerSprite = PlayerList[i].nSprite;
730
731 if ((sprite[nPlayerSprite].cstat & 0x101) && (!(sprite[nPlayerSprite].cstat & 0x8000)))
732 {
733 int v9 = klabs(sprite[nPlayerSprite].x - x);
734
735 if (v9 < nDistance)
736 {
737 int v10 = klabs(sprite[nPlayerSprite].y - y);
738
739 if (v10 < nDistance && cansee(sprite[nPlayerSprite].x, sprite[nPlayerSprite].y, sprite[nPlayerSprite].z - 7680, sprite[nPlayerSprite].sectnum, x, y, z, nSector))
740 {
741 break;
742 }
743 }
744 }
745
746 i++;
747 }
748
749 if (var_18) {
750 PlotCourseToSprite(nSprite, nPlayerSprite);
751 }
752
753 return nPlayerSprite;
754 }
755
CheckSectorFloor(short nSector,int z,int * x,int * y)756 void CheckSectorFloor(short nSector, int z, int *x, int *y)
757 {
758 short nSpeed = SectSpeed[nSector];
759
760 if (!nSpeed) {
761 return;
762 }
763
764 short nFlag = SectFlag[nSector];
765 short nAng = nFlag & kAngleMask;
766
767 if (z >= sector[nSector].floorz)
768 {
769 *x += (Cos(nAng) << 3) * nSpeed;
770 *y += (sintable[nAng] << 3) * nSpeed; // no anglemask in original code
771 }
772 else if (nFlag & 0x800)
773 {
774 *x += (Cos(nAng) << 4) * nSpeed;
775 *y += (sintable[nAng] << 4) * nSpeed; // no anglemask in original code
776 }
777 }
778
GetUpAngle(short nSprite1,int nVal,short nSprite2,int ecx)779 int GetUpAngle(short nSprite1, int nVal, short nSprite2, int ecx)
780 {
781 int x = sprite[nSprite2].x - sprite[nSprite1].x;
782 int y = sprite[nSprite2].y - sprite[nSprite1].y;
783
784 int ebx = (sprite[nSprite2].z + ecx) - (sprite[nSprite1].z + nVal);
785 int edx = (sprite[nSprite2].z + ecx) - (sprite[nSprite1].z + nVal);
786
787 ebx >>= 4;
788 edx >>= 8;
789
790 ebx = -ebx;
791
792 ebx -= edx;
793
794 int nSqrt = lsqrt(x * x + y * y);
795
796 return GetMyAngle(nSqrt, ebx);
797 }
798
InitPushBlocks()799 void InitPushBlocks()
800 {
801 nPushBlocks = 0;
802 }
803
GrabPushBlock()804 int GrabPushBlock()
805 {
806 if (nPushBlocks >= kMaxPushBlocks) {
807 return -1;
808 }
809
810 return nPushBlocks++;
811 }
812
CreatePushBlock(int nSector)813 void CreatePushBlock(int nSector)
814 {
815 int nBlock = GrabPushBlock();
816 int i;
817
818 int startwall = sector[nSector].wallptr;
819 int nWalls = sector[nSector].wallnum;
820
821 int xSum = 0;
822 int ySum = 0;
823
824 for (i = 0; i < nWalls; i++)
825 {
826 xSum += wall[startwall + i].x;
827 ySum += wall[startwall + i].y;
828 }
829
830 int xAvg = xSum / nWalls;
831 int yAvg = ySum / nWalls;
832
833 sBlockInfo[nBlock].x = xAvg;
834 sBlockInfo[nBlock].y = yAvg;
835
836 int nSprite = insertsprite(nSector, 0);
837
838 sBlockInfo[nBlock].nSprite = nSprite;
839
840 sprite[nSprite].x = xAvg;
841 sprite[nSprite].y = yAvg;
842 sprite[nSprite].z = sector[nSector].floorz - 256;
843 sprite[nSprite].cstat = 0x8000;
844
845 int var_28 = 0;
846
847 for (i = 0; i < nWalls; i++)
848 {
849 uint32_t xDiff = klabs(xAvg - wall[startwall + i].x);
850 uint32_t yDiff = klabs(yAvg - wall[startwall + i].y);
851
852 uint32_t sqrtNum = xDiff * xDiff + yDiff * yDiff;
853
854 if (sqrtNum > INT_MAX)
855 {
856 OSD_Printf("%s %d: overflow\n", EDUKE32_FUNCTION, __LINE__);
857 sqrtNum = INT_MAX;
858 }
859
860 int nSqrt = ksqrt(sqrtNum);
861 if (nSqrt > var_28) {
862 var_28 = nSqrt;
863 }
864 }
865
866 sBlockInfo[nBlock].walldist = var_28;
867
868 sprite[nSprite].clipdist = (var_28 & 0xFF) << 2;
869 sector[nSector].extra = nBlock;
870 }
871
MoveSector(short nSector,int nAngle,int * nXVel,int * nYVel)872 void MoveSector(short nSector, int nAngle, int *nXVel, int *nYVel)
873 {
874 int i;
875
876 if (nSector == -1) {
877 return;
878 }
879
880 int nXVect, nYVect;
881
882 if (nAngle < 0)
883 {
884 nXVect = *nXVel;
885 nYVect = *nYVel;
886 nAngle = GetMyAngle(nXVect, nYVect);
887 }
888 else
889 {
890 nXVect = Sin(nAngle + 512) << 6;
891 nYVect = Sin(nAngle) << 6;
892 }
893
894 short nBlock = sector[nSector].extra;
895 short nSectFlag = SectFlag[nSector];
896
897 sectortype *pSector = §or[nSector];
898 int nFloorZ = sector[nSector].floorz;
899 int startwall = sector[nSector].wallptr;
900 int nWalls = sector[nSector].wallnum;
901
902 walltype *pStartWall = &wall[startwall];
903 short nNextSector = wall[startwall].nextsector;
904
905 BlockInfo *pBlockInfo = &sBlockInfo[nBlock];
906
907 int x = sBlockInfo[nBlock].x;
908 int x_b = sBlockInfo[nBlock].x;
909
910 int y = sBlockInfo[nBlock].y;
911 int y_b = sBlockInfo[nBlock].y;
912
913 short nSectorB = nSector;
914
915 int nZVal;
916 int z;
917
918 int bUnderwater = nSectFlag & kSectUnderwater;
919
920 if (nSectFlag & kSectUnderwater)
921 {
922 nZVal = sector[nSector].ceilingz;
923 z = sector[nNextSector].ceilingz + 256;
924
925 sector[nSector].ceilingz = sector[nNextSector].ceilingz;
926 }
927 else
928 {
929 nZVal = sector[nSector].floorz;
930 z = sector[nNextSector].floorz - 256;
931
932 sector[nSector].floorz = sector[nNextSector].floorz;
933 }
934
935 clipmove_old((int32_t*)&x, (int32_t*)&y, (int32_t*)&z, &nSectorB, nXVect, nYVect, pBlockInfo->walldist, 0, 0, CLIPMASK1);
936
937 int yvect = y - y_b;
938 int xvect = x - x_b;
939
940 if (nSectorB != nNextSector && nSectorB != nSector)
941 {
942 yvect = 0;
943 xvect = 0;
944 }
945 else
946 {
947 if (!bUnderwater)
948 {
949 z = nZVal;
950 x = x_b;
951 y = y_b;
952
953 clipmove_old((int32_t*)&x, (int32_t*)&y, (int32_t*)&z, &nSectorB, nXVect, nYVect, pBlockInfo->walldist, 0, 0, CLIPMASK1);
954
955 int ebx = x;
956 int ecx = x_b;
957 int edx = y;
958 int eax = xvect;
959 int esi = y_b;
960
961 if (eax < 0) {
962 eax = -eax;
963 }
964
965 ebx -= ecx;
966 ecx = eax;
967 eax = ebx;
968 edx -= esi;
969
970 if (eax < 0) {
971 eax = -eax;
972 }
973
974 if (ecx > eax)
975 {
976 xvect = ebx;
977 }
978
979 eax = yvect;
980 if (eax < 0) {
981 eax = -eax;
982 }
983
984 ebx = eax;
985 eax = edx;
986
987 if (eax < 0) {
988 eax = -eax;
989 }
990
991 if (ebx > eax) {
992 yvect = edx;
993 }
994 }
995 }
996
997 // GREEN
998 if (yvect || xvect)
999 {
1000 for (i = headspritesect[nSector]; i != -1; i = nextspritesect[i])
1001 {
1002 if (sprite[i].statnum < 99)
1003 {
1004 sprite[i].x += xvect;
1005 sprite[i].y += yvect;
1006 }
1007 else
1008 {
1009 z = sprite[i].z;
1010
1011 if ((nSectFlag & kSectUnderwater) || z != nZVal || sprite[i].cstat & 0x8000)
1012 {
1013 x = sprite[i].x;
1014 y = sprite[i].y;
1015 nSectorB = nSector;
1016
1017 clipmove_old((int32_t*)&x, (int32_t*)&y, (int32_t*)&z, &nSectorB, -xvect, -yvect, 4 * sprite[i].clipdist, 0, 0, CLIPMASK0);
1018
1019 if (nSectorB >= 0 && nSectorB < kMaxSectors && nSectorB != nSector) {
1020 mychangespritesect(i, nSectorB);
1021 }
1022 }
1023 }
1024 }
1025
1026 for (i = headspritesect[nNextSector]; i != -1; i = nextspritesect[i])
1027 {
1028 if (sprite[i].statnum >= 99)
1029 {
1030 x = sprite[i].x;
1031 y = sprite[i].y;
1032 z = sprite[i].z;
1033 nSectorB = nNextSector;
1034
1035 clipmove_old((int32_t*)&x, (int32_t*)&y, (int32_t*)&z, &nSectorB,
1036 -xvect - (Sin(nAngle + 512) * (4 * sprite[i].clipdist)),
1037 -yvect - (Sin(nAngle) * (4 * sprite[i].clipdist)),
1038 4 * sprite[i].clipdist, 0, 0, CLIPMASK0);
1039
1040
1041 if (nSectorB != nNextSector && (nSectorB == nSector || nNextSector == nSector))
1042 {
1043 if (nSectorB != nSector || nFloorZ >= sprite[i].z)
1044 {
1045 if (nSectorB >= 0 && nSectorB < kMaxSectors) {
1046 mychangespritesect(i, nSectorB);
1047 }
1048 }
1049 else
1050 {
1051 movesprite(i,
1052 (xvect << 14) + Sin(nAngle + 512) * sprite[i].clipdist,
1053 (yvect << 14) + Sin(nAngle) * sprite[i].clipdist,
1054 0, 0, 0, CLIPMASK0);
1055 }
1056 }
1057 }
1058 }
1059
1060 for (int i = 0; i < nWalls; i++)
1061 {
1062 dragpoint(startwall, xvect + pStartWall->x, yvect + pStartWall->y, 0);
1063 pStartWall++;
1064 startwall++;
1065 }
1066
1067 pBlockInfo->x += xvect;
1068 pBlockInfo->y += yvect;
1069 }
1070
1071 // loc_163DD
1072 xvect <<= 14;
1073 yvect <<= 14;
1074
1075 if (!(nSectFlag & kSectUnderwater))
1076 {
1077 for (i = headspritesect[nSector]; i != -1; i = nextspritesect[i])
1078 {
1079 if (sprite[i].statnum >= 99 && nZVal == sprite[i].z && !(sprite[i].cstat & 0x8000))
1080 {
1081 nSectorB = nSector;
1082 clipmove_old(&sprite[i].x, &sprite[i].y, &sprite[i].z, &nSectorB, xvect, yvect, 4 * sprite[i].clipdist, 5120, -5120, CLIPMASK0);
1083 }
1084 }
1085 }
1086
1087 if (nSectFlag & kSectUnderwater) {
1088 pSector->ceilingz = nZVal;
1089 }
1090 else {
1091 pSector->floorz = nZVal;
1092 }
1093
1094 *nXVel = xvect;
1095 *nYVel = yvect;
1096
1097 /*
1098 Update player position variables, in case the player sprite was moved by a sector.
1099 Otherwise these can be out of sync when used in sound code (before being updated in PlayerFunc()).
1100 Can cause local player sounds to play off-centre.
1101 TODO: Might need to be done elsewhere too?
1102 */
1103 int nPlayerSprite = PlayerList[nLocalPlayer].nSprite;
1104 initx = sprite[nPlayerSprite].x;
1105 inity = sprite[nPlayerSprite].y;
1106 initz = sprite[nPlayerSprite].z;
1107 inita = sprite[nPlayerSprite].ang;
1108 initsect = sprite[nPlayerSprite].sectnum;
1109 }
1110
SetQuake(short nSprite,int nVal)1111 void SetQuake(short nSprite, int nVal)
1112 {
1113 int x = sprite[nSprite].x;
1114 int y = sprite[nSprite].y;
1115
1116 nVal *= 256;
1117
1118 for (int i = 0; i < nTotalPlayers; i++)
1119 {
1120 int nPlayerSprite = PlayerList[i].nSprite;
1121
1122 uint32_t xDiff = klabs((int32_t)((sprite[nPlayerSprite].x - x) >> 8));
1123 uint32_t yDiff = klabs((int32_t)((sprite[nPlayerSprite].y - y) >> 8));
1124
1125 uint32_t sqrtNum = xDiff * xDiff + yDiff * yDiff;
1126
1127 if (sqrtNum > INT_MAX)
1128 {
1129 OSD_Printf("%s %d: overflow\n", EDUKE32_FUNCTION, __LINE__);
1130 sqrtNum = INT_MAX;
1131 }
1132
1133 int nSqrt = ksqrt(sqrtNum);
1134
1135 int eax = nVal;
1136
1137 if (nSqrt)
1138 {
1139 eax = eax / nSqrt;
1140
1141 if (eax >= 256)
1142 {
1143 if (eax > 3840) {
1144 eax = 3840;
1145 }
1146 }
1147 else
1148 {
1149 eax = 0;
1150 }
1151 }
1152
1153 if (eax > nQuake[i]) {
1154 nQuake[i] = eax;
1155 }
1156 }
1157 }
1158
AngleChase(int nSprite,int nSprite2,int ebx,int ecx,int push1)1159 int AngleChase(int nSprite, int nSprite2, int ebx, int ecx, int push1)
1160 {
1161 int nClipType = sprite[nSprite].statnum != 107;
1162
1163 /* bjd - need to handle cliptype to clipmask change that occured in later build engine version */
1164 if (nClipType == 1) {
1165 nClipType = CLIPMASK1;
1166 }
1167 else {
1168 nClipType = CLIPMASK0;
1169 }
1170
1171 short nAngle;
1172
1173 if (nSprite2 < 0)
1174 {
1175 sprite[nSprite].zvel = 0;
1176 nAngle = sprite[nSprite].ang;
1177 }
1178 else
1179 {
1180 int nHeight = tilesiz[sprite[nSprite2].picnum].y * sprite[nSprite2].yrepeat * 2;
1181
1182 int nMyAngle = GetMyAngle(sprite[nSprite2].x - sprite[nSprite].x, sprite[nSprite2].y - sprite[nSprite].y);
1183
1184 uint32_t xDiff = klabs(sprite[nSprite2].x - sprite[nSprite].x);
1185 uint32_t yDiff = klabs(sprite[nSprite2].y - sprite[nSprite].y);
1186
1187 uint32_t sqrtNum = xDiff * xDiff + yDiff * yDiff;
1188
1189 if (sqrtNum > INT_MAX)
1190 {
1191 OSD_Printf("%s %d: overflow\n", EDUKE32_FUNCTION, __LINE__);
1192 sqrtNum = INT_MAX;
1193 }
1194
1195 int nSqrt = ksqrt(sqrtNum);
1196
1197 int var_18 = GetMyAngle(nSqrt, ((sprite[nSprite2].z - nHeight) - sprite[nSprite].z) >> 8);
1198
1199 int nAngDelta = AngleDelta(sprite[nSprite].ang, nMyAngle, 1024);
1200 int nAngDelta2 = klabs(nAngDelta);
1201
1202 if (nAngDelta2 > 63)
1203 {
1204 nAngDelta2 = klabs(nAngDelta >> 6);
1205
1206 ebx /= nAngDelta2;
1207
1208 if (ebx < 5) {
1209 ebx = 5;
1210 }
1211 }
1212
1213 int nAngDeltaC = klabs(nAngDelta);
1214
1215 if (nAngDeltaC > push1)
1216 {
1217 if (nAngDelta >= 0)
1218 nAngDelta = push1;
1219 else
1220 nAngDelta = -push1;
1221 }
1222
1223 nAngle = (nAngDelta + sprite[nSprite].ang) & kAngleMask;
1224 int nAngDeltaD = AngleDelta(sprite[nSprite].zvel, var_18, 24);
1225
1226 sprite[nSprite].zvel = (sprite[nSprite].zvel + nAngDeltaD) & kAngleMask;
1227 }
1228
1229 sprite[nSprite].ang = nAngle;
1230
1231 int eax = klabs(Cos(sprite[nSprite].zvel));
1232
1233 int x = ((Cos(nAngle) * ebx) >> 14) * eax;
1234 int y = ((Sin(nAngle) * ebx) >> 14) * eax;
1235
1236 int xshift = x >> 8;
1237 int yshift = y >> 8;
1238
1239 uint32_t sqrtNum = xshift * xshift + yshift * yshift;
1240
1241 if (sqrtNum > INT_MAX)
1242 {
1243 OSD_Printf("%s %d: overflow\n", EDUKE32_FUNCTION, __LINE__);
1244 sqrtNum = INT_MAX;
1245 }
1246
1247 int z = Sin(sprite[nSprite].zvel) * ksqrt(sqrtNum);
1248
1249 return movesprite(nSprite, x >> 2, y >> 2, (z >> 13) + (Sin(ecx) >> 5), 0, 0, nClipType);
1250 }
1251
GetWallNormal(short nWall)1252 int GetWallNormal(short nWall)
1253 {
1254 nWall &= kMaxWalls-1;
1255
1256 int nWall2 = wall[nWall].point2;
1257
1258 int nAngle = GetMyAngle(wall[nWall2].x - wall[nWall].x, wall[nWall2].y - wall[nWall].y);
1259 return (nAngle + 512) & kAngleMask;
1260 }
1261
WheresMyMouth(int nPlayer,int * x,int * y,int * z,short * sectnum)1262 void WheresMyMouth(int nPlayer, int *x, int *y, int *z, short *sectnum)
1263 {
1264 int nSprite = PlayerList[nPlayer].nSprite;
1265
1266 *x = sprite[nSprite].x;
1267 *y = sprite[nSprite].y;
1268
1269 int height = GetSpriteHeight(nSprite) / 2;
1270
1271 *z = sprite[nSprite].z - height;
1272 *sectnum = sprite[nSprite].sectnum;
1273
1274 clipmove_old((int32_t*)x, (int32_t*)y, (int32_t*)z, sectnum,
1275 Cos(sprite[nSprite].ang) << 7,
1276 Sin(sprite[nSprite].ang) << 7,
1277 5120, 1280, 1280, CLIPMASK1);
1278 }
1279
InitChunks()1280 void InitChunks()
1281 {
1282 nCurChunkNum = 0;
1283 memset(nChunkSprite, -1, sizeof(nChunkSprite));
1284 memset(nBodyGunSprite, -1, sizeof(nBodyGunSprite));
1285 memset(nBodySprite, -1, sizeof(nBodySprite));
1286 nCurBodyNum = 0;
1287 nCurBodyGunNum = 0;
1288 nBodyTotal = 0;
1289 nChunkTotal = 0;
1290 }
1291
GrabBodyGunSprite()1292 int GrabBodyGunSprite()
1293 {
1294 int nSprite = nBodyGunSprite[nCurBodyGunNum];
1295
1296 if (nSprite == -1)
1297 {
1298 nSprite = insertsprite(0, 899);
1299 nBodyGunSprite[nCurBodyGunNum] = nSprite;
1300
1301 sprite[nSprite].lotag = -1;
1302 sprite[nSprite].owner = -1;
1303 }
1304 else
1305 {
1306 int nAnim = sprite[nSprite].owner;
1307
1308 if (nAnim != -1) {
1309 DestroyAnim(nAnim);
1310 }
1311
1312 sprite[nSprite].lotag = -1;
1313 sprite[nSprite].owner = -1;
1314 }
1315
1316 nCurBodyGunNum++;
1317 if (nCurBodyGunNum >= 50) { // TODO - enum/define
1318 nCurBodyGunNum = 0;
1319 }
1320
1321 sprite[nSprite].cstat = 0;
1322
1323 return nSprite;
1324 }
1325
GrabBody()1326 int GrabBody()
1327 {
1328 int nSprite;
1329
1330 do
1331 {
1332 nSprite = nBodySprite[nCurBodyNum];
1333
1334 if (nSprite == -1)
1335 {
1336 nSprite = insertsprite(0, 899);
1337 nBodySprite[nCurBodyNum] = nSprite;
1338 sprite[nSprite].cstat = 0x8000;
1339 }
1340
1341 nCurBodyNum++;
1342 if (nCurBodyNum >= 50) {
1343 nCurBodyNum = 0;
1344 }
1345 } while (sprite[nSprite].cstat & 0x101);
1346
1347 if (nBodyTotal < 50) {
1348 nBodyTotal++;
1349 }
1350
1351 sprite[nSprite].cstat = 0;
1352 return nSprite;
1353 }
1354
GrabChunkSprite()1355 int GrabChunkSprite()
1356 {
1357 int nSprite = nChunkSprite[nCurChunkNum];
1358
1359 if (nSprite == -1)
1360 {
1361 nSprite = insertsprite(0, 899);
1362 nChunkSprite[nCurChunkNum] = nSprite;
1363 }
1364 else if (sprite[nSprite].statnum)
1365 {
1366 // TODO MonoOut("too many chunks being used at once!\n");
1367 return -1;
1368 }
1369
1370 changespritestat(nSprite, 899);
1371
1372 nCurChunkNum++;
1373 if (nCurChunkNum >= kMaxChunks)
1374 nCurChunkNum = 0;
1375
1376 if (nChunkTotal < kMaxChunks)
1377 nChunkTotal++;
1378
1379 sprite[nSprite].cstat = 0x80;
1380
1381 return nSprite;
1382 }
1383
BuildCreatureChunk(int nVal,int nPic)1384 int BuildCreatureChunk(int nVal, int nPic)
1385 {
1386 int var_14;
1387
1388 int nSprite = GrabChunkSprite();
1389
1390 if (nSprite == -1) {
1391 return -1;
1392 }
1393
1394 if (nVal & 0x4000)
1395 {
1396 nVal &= 0x3FFF;
1397 var_14 = 1;
1398 }
1399 else
1400 {
1401 var_14 = 0;
1402 }
1403
1404 nVal &= 0xFFFF;
1405
1406 sprite[nSprite].x = sprite[nVal].x;
1407 sprite[nSprite].y = sprite[nVal].y;
1408 sprite[nSprite].z = sprite[nVal].z;
1409
1410 mychangespritesect(nSprite, sprite[nVal].sectnum);
1411
1412 sprite[nSprite].cstat = 0x80;
1413 sprite[nSprite].shade = -12;
1414 sprite[nSprite].pal = 0;
1415
1416 sprite[nSprite].xvel = (RandomSize(5) - 16) << 7;
1417 sprite[nSprite].yvel = (RandomSize(5) - 16) << 7;
1418 sprite[nSprite].zvel = (-(RandomSize(8) + 512)) << 3;
1419
1420 if (var_14)
1421 {
1422 sprite[nSprite].xvel *= 4;
1423 sprite[nSprite].yvel *= 4;
1424 sprite[nSprite].zvel *= 2;
1425 }
1426
1427 sprite[nSprite].xrepeat = 64;
1428 sprite[nSprite].yrepeat = 64;
1429 sprite[nSprite].xoffset = 0;
1430 sprite[nSprite].yoffset = 0;
1431 sprite[nSprite].picnum = nPic;
1432 sprite[nSprite].lotag = runlist_HeadRun() + 1;
1433 sprite[nSprite].clipdist = 40;
1434
1435 // GrabTimeSlot(3);
1436
1437 sprite[nSprite].extra = -1;
1438 sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nSprite | 0xD0000);
1439 sprite[nSprite].hitag = runlist_AddRunRec(NewRun, nSprite | 0xD0000);
1440
1441 return nSprite | 0xD0000;
1442 }
1443
FuncCreatureChunk(int a,int UNUSED (b),int nRun)1444 void FuncCreatureChunk(int a, int UNUSED(b), int nRun)
1445 {
1446 int nSprite = RunData[nRun].nVal;
1447 assert(nSprite >= 0 && nSprite < kMaxSprites);
1448
1449 int nMessage = a & 0x7F0000;
1450
1451 if (nMessage != 0x20000)
1452 return;
1453
1454 Gravity(nSprite);
1455
1456 int nSector = sprite[nSprite].sectnum;
1457 sprite[nSprite].pal = sector[nSector].ceilingpal;
1458
1459 int nVal = movesprite(nSprite, sprite[nSprite].xvel << 10, sprite[nSprite].yvel << 10, sprite[nSprite].zvel, 2560, -2560, CLIPMASK1);
1460
1461 if (sprite[nSprite].z >= sector[nSector].floorz)
1462 {
1463 // re-grab this variable as it may have changed in movesprite(). Note the check above is against the value *before* movesprite so don't change it.
1464 nSector = sprite[nSprite].sectnum;
1465
1466 sprite[nSprite].xvel = 0;
1467 sprite[nSprite].yvel = 0;
1468 sprite[nSprite].zvel = 0;
1469 sprite[nSprite].z = sector[nSector].floorz;
1470 }
1471 else
1472 {
1473 if (!nVal)
1474 return;
1475
1476 short nAngle;
1477
1478 if (nVal & 0x20000)
1479 {
1480 sprite[nSprite].cstat = 0x8000;
1481 }
1482 else
1483 {
1484 if ((nVal & 0x3C000) == 0x10000)
1485 {
1486 sprite[nSprite].xvel >>= 1;
1487 sprite[nSprite].yvel >>= 1;
1488 sprite[nSprite].zvel = -sprite[nSprite].zvel;
1489 return;
1490 }
1491 else if ((nVal & 0x3C000) == 0xC000)
1492 {
1493 nAngle = sprite[nVal & 0x3FFF].ang;
1494 }
1495 else if ((nVal & 0x3C000) == 0x8000)
1496 {
1497 nAngle = GetWallNormal(nVal & 0x3FFF);
1498 }
1499 else
1500 {
1501 return;
1502 }
1503
1504 // loc_16E0C
1505 int nSqrt = lsqrt(((sprite[nSprite].yvel >> 10) * (sprite[nSprite].yvel >> 10)
1506 + (sprite[nSprite].xvel >> 10) * (sprite[nSprite].xvel >> 10)) >> 8);
1507
1508 sprite[nSprite].xvel = Cos(nAngle) * (nSqrt >> 1);
1509 sprite[nSprite].yvel = Sin(nAngle) * (nSqrt >> 1);
1510 return;
1511 }
1512 }
1513
1514 runlist_DoSubRunRec(sprite[nSprite].owner);
1515 runlist_FreeRun(sprite[nSprite].lotag - 1);
1516 runlist_SubRunRec(sprite[nSprite].hitag);
1517
1518 changespritestat(nSprite, 0);
1519 sprite[nSprite].hitag = 0;
1520 sprite[nSprite].lotag = 0;
1521 }
1522
UpdateEnemy(short * nEnemy)1523 short UpdateEnemy(short *nEnemy)
1524 {
1525 if (*nEnemy >= 0)
1526 {
1527 if (!(sprite[*nEnemy].cstat & 0x101)) {
1528 *nEnemy = -1;
1529 }
1530 }
1531
1532 return *nEnemy;
1533 }
1534
1535 class MoveLoadSave : public LoadSave
1536 {
1537 public:
1538 virtual void Load();
1539 virtual void Save();
1540 };
1541
Load()1542 void MoveLoadSave::Load()
1543 {
1544 Read(&NearCount, sizeof(NearCount));
1545 Read(NearSector, sizeof(NearSector[0]) * NearCount);
1546 Read(&nPushBlocks, sizeof(nPushBlocks));
1547 Read(sBlockInfo, sizeof(sBlockInfo[0]) * nPushBlocks);
1548 Read(&overridesect, sizeof(overridesect));
1549
1550 Read(&nCurBodyNum, sizeof(nCurBodyNum));
1551 Read(nBodySprite, sizeof(nBodySprite[0]) * nCurBodyNum);
1552 Read(&nBodyTotal, sizeof(nBodyTotal));
1553
1554 Read(&hihit, sizeof(hihit));
1555 Read(&sprceiling, sizeof(sprceiling));
1556 Read(&sprfloor, sizeof(sprfloor));
1557 Read(&lohit, sizeof(lohit));
1558
1559 Read(&nCurChunkNum, sizeof(nCurChunkNum));
1560 Read(nChunkSprite, sizeof(nChunkSprite[0]) * nCurChunkNum);
1561 }
1562
Save()1563 void MoveLoadSave::Save()
1564 {
1565 Write(&NearCount, sizeof(NearCount));
1566 Write(NearSector, sizeof(NearSector[0]) * NearCount);
1567 Write(&nPushBlocks, sizeof(nPushBlocks));
1568 Write(sBlockInfo, sizeof(sBlockInfo[0]) * nPushBlocks);
1569 Write(&overridesect, sizeof(overridesect));
1570
1571 Write(&nCurBodyNum, sizeof(nCurBodyNum));
1572 Write(nBodySprite, sizeof(nBodySprite[0]) * nCurBodyNum);
1573 Write(&nBodyTotal, sizeof(nBodyTotal));
1574
1575 Write(&hihit, sizeof(hihit));
1576 Write(&sprceiling, sizeof(sprceiling));
1577 Write(&sprfloor, sizeof(sprfloor));
1578 Write(&lohit, sizeof(lohit));
1579
1580 Write(&nCurChunkNum, sizeof(nCurChunkNum));
1581 Write(nChunkSprite, sizeof(nChunkSprite[0]) * nCurChunkNum);
1582 }
1583
1584 static MoveLoadSave* myLoadSave;
1585
MoveLoadSaveConstruct()1586 void MoveLoadSaveConstruct()
1587 {
1588 myLoadSave = new MoveLoadSave();
1589 }
1590