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 = &sector[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