1 /****************************************************************************
2             Witchaven
3 
4             WHFX.C
5 
6             Rafael Paiz
7 
8 ****************************************************************************/
9 
10 #include "effects.h"
11 #include "player.h"
12 #include "sound.h"
13 #include "objects.h"
14 #include "witchaven.h"
15 #include "input.h"
16 #include "view.h"
17 
18 #define LAVASIZ 128
19 #define LAVALOGSIZ 7
20 #define LAVAMAXDROPS 32
21 
22 #define WATERSIZ 128
23 #define WATERLOGSIZ 7
24 #define WATERMAXDROPS 16 // bjd - this was 1 but contradicts the way arrays sized with this define were accessed
25 
26 #define FLOORUNIT    16384L
27 
28 int justwarpedfx = 0;
29 int lastbat = -1;
30 
31 extern int justteleported;
32 
33 extern short lavadrylandsector[32];
34 extern short lavadrylandcnt;
35 
36 
37 static char lavabakpic[(LAVASIZ+2)*(LAVASIZ+2)], lavainc[LAVASIZ];
38 static int lavanumdrops, lavanumframes;
39 static int lavadropx[LAVAMAXDROPS], lavadropy[LAVAMAXDROPS];
40 static int lavadropsiz[LAVAMAXDROPS], lavadropsizlookup[LAVAMAXDROPS];
41 static int lavaradx[32][128], lavarady[32][128], lavaradcnt[32];
42 
43 static char waterbakpic[(WATERSIZ+2)*(WATERSIZ+2)], waterinc[WATERSIZ];
44 static int waternumdrops, waternumframes;
45 static int waterdropx[WATERMAXDROPS], waterdropy[WATERMAXDROPS];
46 static int waterdropsiz[WATERMAXDROPS], waterdropsizlookup[WATERMAXDROPS];
47 static int waterradx[32][128], waterrady[32][128], waterradcnt[32];
48 
49 extern short revolvesector[], revolveang[], revolveclip[], revolvecnt;
50 extern int revolvex[16][16], revolvey[16][16];
51 extern int revolvepivotx[], revolvepivoty[];
52 
53 extern short xpanningsectorlist[], xpanningsectorcnt;
54 extern short ypanningwalllist[], ypanningwallcnt;
55 extern short floorpanninglist[], floorpanningcnt;
56 extern short skypanlist[], skypancnt;
57 extern short crushsectorlist[], crushsectorcnt;
58 extern short crushsectoranim[], crushsectordone[];
59 extern short bobbingsectorcnt, bobbingsectorlist[];
60 extern short warpsectorlist[], warpsectorcnt;
61 
62 char revolvesyncstat;
63 short revolvesyncang, revolvesyncrotang;
64 int revolvesyncx, revolvesyncy;
65 
66 extern int mapon;
67 
68 
initlava()69 void initlava()
70 {
71     for (int x = -16; x <= 16; x++)
72     {
73         for (int y = -16; y <= 16; y++)
74         {
75             int r = ksqrt(x * x + y * y);
76             lavaradx[r][lavaradcnt[r]] = x;
77             lavarady[r][lavaradcnt[r]] = y;
78             lavaradcnt[r]++;
79         }
80     }
81 
82     for (int z = 0; z < 16; z++)
83         lavadropsizlookup[z] = 8 / (ksqrt(z) + 1);
84 
85     for (int z = 0; z < LAVASIZ; z++)
86         lavainc[z] = klabs((((z ^ 17) >> 4) & 7) - 4) + 12;
87 
88     lavanumdrops = 0;
89     lavanumframes = 0;
90 }
91 
movelava(char * dapic)92 void movelava(char* dapic)
93 {
94     char dat, * ptr;
95     int32_t x, y, z, zx, dalavadropsiz, dadropsizlookup;
96     intptr_t offs, offs2;
97     int32_t dalavax, dalavay;
98 
99     z = 3;
100     if (lavanumdrops + z >= LAVAMAXDROPS)
101         z = LAVAMAXDROPS - lavanumdrops - 1;
102 
103     while (z >= 0)
104     {
105         lavadropx[lavanumdrops] = (rand() & (LAVASIZ - 1));
106         lavadropy[lavanumdrops] = (rand() & (LAVASIZ - 1));
107         lavadropsiz[lavanumdrops] = 1;
108         lavanumdrops++;
109         z--;
110     }
111 
112     z = lavanumdrops - 1;
113     while (z >= 0)
114     {
115         dadropsizlookup = lavadropsizlookup[lavadropsiz[z]] * (((z & 1) << 1) - 1);
116         dalavadropsiz = lavadropsiz[z];
117         dalavax = lavadropx[z]; dalavay = lavadropy[z];
118         for (zx = lavaradcnt[lavadropsiz[z]] - 1; zx >= 0; zx--)
119         {
120             offs = (((lavaradx[dalavadropsiz][zx] + dalavax) & (LAVASIZ - 1)) << LAVALOGSIZ);
121             offs += ((lavarady[dalavadropsiz][zx] + dalavay) & (LAVASIZ - 1));
122             dapic[offs] += dadropsizlookup;
123 
124             if (dapic[offs] < 192)
125                 dapic[offs] = 192;
126         }
127 
128         lavadropsiz[z]++;
129         if (lavadropsiz[z] > 10)
130         {
131             lavanumdrops--;
132             lavadropx[z] = lavadropx[lavanumdrops];
133             lavadropy[z] = lavadropy[lavanumdrops];
134             lavadropsiz[z] = lavadropsiz[lavanumdrops];
135         }
136         z--;
137     }
138 
139     //Back up dapic with 1 pixel extra on each boundary
140     //(to prevent anding for wrap-around)
141     offs = ((intptr_t)dapic);
142     offs2 = (LAVASIZ + 2) + 1 + ((intptr_t)lavabakpic);
143     for (x = 0; x < LAVASIZ; x++)
144     {
145         copybuf((char*)offs, (char*)offs2, LAVASIZ >> 2);
146         offs += LAVASIZ;
147         offs2 += LAVASIZ + 2;
148     }
149     for (y = 0; y < LAVASIZ; y++)
150     {
151         lavabakpic[y + 1] = dapic[y + ((LAVASIZ - 1) << LAVALOGSIZ)];
152         lavabakpic[y + 1 + (LAVASIZ + 1) * (LAVASIZ + 2)] = dapic[y];
153     }
154     for (x = 0; x < LAVASIZ; x++)
155     {
156         lavabakpic[(x + 1) * (LAVASIZ + 2)] = dapic[(x << LAVALOGSIZ) + (LAVASIZ - 1)];
157         lavabakpic[(x + 1) * (LAVASIZ + 2) + (LAVASIZ + 1)] = dapic[x << LAVALOGSIZ];
158     }
159     lavabakpic[0] = dapic[LAVASIZ * LAVASIZ - 1];
160     lavabakpic[LAVASIZ + 1] = dapic[LAVASIZ * (LAVASIZ - 1)];
161     lavabakpic[(LAVASIZ + 2) * (LAVASIZ + 1)] = dapic[LAVASIZ - 1];
162     lavabakpic[(LAVASIZ + 2) * (LAVASIZ + 2) - 1] = dapic[0];
163 
164     for (z = (LAVASIZ + 2) * (LAVASIZ + 2) - 4; z >= 0; z -= 4)
165     {
166         lavabakpic[z + 0] &= 31;
167         lavabakpic[z + 1] &= 31;
168         lavabakpic[z + 2] &= 31;
169         lavabakpic[z + 3] &= 31;
170     }
171 
172     for (x = LAVASIZ - 1; x >= 0; x--)
173     {
174         offs = (x + 1) * (LAVASIZ + 2) + 1;
175         ptr = (char*)((x << LAVALOGSIZ) + (intptr_t)dapic);
176 
177         zx = ((x + lavanumframes) & (LAVASIZ - 1));
178 
179         offs2 = LAVASIZ - 1;
180         for (y = offs; y < offs + LAVASIZ; y++)
181         {
182             dat = lavainc[(offs2--) & zx];
183             dat += lavabakpic[y - (LAVASIZ + 2) - 1];
184             dat += lavabakpic[y - (LAVASIZ + 2)];
185             dat += lavabakpic[y - (LAVASIZ + 2) + 1];
186             dat += lavabakpic[y - 1];
187             dat += lavabakpic[y + 1];
188             dat += lavabakpic[y + (LAVASIZ + 2)];
189             dat += lavabakpic[y + (LAVASIZ + 2) - 1];
190             *ptr++ = (dat >> 3) + 192;
191         }
192     }
193 
194     lavanumframes++;
195 }
196 
initwater()197 void initwater()
198 {
199     for (int x = -16; x <= 16; x++)
200     {
201         for (int y = -16; y <= 16; y++)
202         {
203             int r = ksqrt(x * x + y * y);
204             waterradx[r][waterradcnt[r]] = x;
205             waterrady[r][waterradcnt[r]] = y;
206             waterradcnt[r]++;
207         }
208     }
209 
210     for (int z = 0; z < WATERMAXDROPS; z++)
211         waterdropsizlookup[z] = 8 / (ksqrt(z) + 1);
212 
213     for (int z = 0; z < WATERSIZ; z++)
214         waterinc[z] = klabs((((z ^ 17) >> 4) & 7) - 4) + 12;
215 
216     waternumdrops = 0;
217     waternumframes = 0;
218 }
219 
movewater(char * dapic)220 void movewater(char* dapic)
221 {
222     char dat, * ptr;
223     int32_t x, y, z, zx, dawaterdropsiz, dadropsizlookup;
224     intptr_t offs, offs2;
225     int32_t dawaterx, dawatery;
226 
227     z = 3;
228     if (waternumdrops + z >= WATERMAXDROPS)
229         z = WATERMAXDROPS - waternumdrops - 1;
230 
231     while (z >= 0)
232     {
233         waterdropx[waternumdrops] = (rand() & (WATERSIZ - 1));
234         waterdropy[waternumdrops] = (rand() & (WATERSIZ - 1));
235         waterdropsiz[waternumdrops] = 1;
236         waternumdrops++;
237         z--;
238     }
239 
240     z = waternumdrops - 1;
241 
242     while (z >= 0)
243     {
244         dadropsizlookup = waterdropsizlookup[waterdropsiz[z]] * (((z & 1) << 1) - 1);
245         dawaterdropsiz = waterdropsiz[z];
246         dawaterx = waterdropx[z]; dawatery = waterdropy[z];
247         for (zx = waterradcnt[waterdropsiz[z]] - 1; zx >= 0; zx--)
248         {
249             offs = (((waterradx[dawaterdropsiz][zx] + dawaterx) & (WATERSIZ - 1)) << WATERLOGSIZ);
250             offs += ((waterrady[dawaterdropsiz][zx] + dawatery) & (WATERSIZ - 1));
251             dapic[offs] += dadropsizlookup;
252             if (dapic[offs] < 224) dapic[offs] = 224;
253         }
254 
255         waterdropsiz[z]++;
256         if (waterdropsiz[z] > 10)
257         {
258             waternumdrops--;
259             waterdropx[z] = waterdropx[waternumdrops];
260             waterdropy[z] = waterdropy[waternumdrops];
261             waterdropsiz[z] = waterdropsiz[waternumdrops];
262         }
263         z--;
264     }
265 
266     offs = ((intptr_t)dapic);
267     offs2 = (WATERSIZ + 2) + 1 + ((intptr_t)waterbakpic);
268 
269     for (x = 0; x < WATERSIZ; x++)
270     {
271         copybuf((char*)offs, (char*)offs2, WATERSIZ >> 2);
272         offs += WATERSIZ;
273         offs2 += WATERSIZ + 2;
274     }
275     for (y = 0; y < WATERSIZ; y++)
276     {
277         waterbakpic[y + 1] = dapic[y + ((WATERSIZ - 1) << WATERLOGSIZ)];
278         waterbakpic[y + 1 + (WATERSIZ + 1) * (WATERSIZ + 2)] = dapic[y];
279     }
280     for (x = 0; x < WATERSIZ; x++)
281     {
282         waterbakpic[(x + 1) * (WATERSIZ + 2)] = dapic[(x << WATERLOGSIZ) + (WATERSIZ - 1)];
283         waterbakpic[(x + 1) * (WATERSIZ + 2) + (WATERSIZ + 1)] = dapic[x << WATERLOGSIZ];
284     }
285 
286     waterbakpic[0] = dapic[WATERSIZ * WATERSIZ - 1];
287     waterbakpic[WATERSIZ + 1] = dapic[WATERSIZ * (WATERSIZ - 1)];
288     waterbakpic[(WATERSIZ + 2) * (WATERSIZ + 1)] = dapic[WATERSIZ - 1];
289     waterbakpic[(WATERSIZ + 2) * (WATERSIZ + 2) - 1] = dapic[0];
290 
291     for (z = (WATERSIZ + 2) * (WATERSIZ + 2) - 4; z >= 0; z -= 4)
292     {
293         waterbakpic[z + 0] &= 15;
294         waterbakpic[z + 1] &= 15;
295         waterbakpic[z + 2] &= 15;
296         waterbakpic[z + 3] &= 15;
297     }
298 
299     for (x = WATERSIZ - 1; x >= 0; x--)
300     {
301         offs = (x + 1) * (WATERSIZ + 2) + 1;
302         ptr = (char*)((x << WATERLOGSIZ) + (intptr_t)dapic);
303 
304         zx = ((x + waternumframes) & (WATERSIZ - 1));
305 
306         offs2 = WATERSIZ - 1;
307         for (y = offs; y < offs + WATERSIZ; y++)
308         {
309             dat = waterinc[(offs2--) & zx];
310             dat += waterbakpic[y - (WATERSIZ + 2) - 1];
311             dat += waterbakpic[y - (WATERSIZ + 2)];
312             dat += waterbakpic[y - (WATERSIZ + 2) + 1];
313             dat += waterbakpic[y - 1];
314             dat += waterbakpic[y + 1];
315             dat += waterbakpic[y + (WATERSIZ + 2) + 1];
316             dat += waterbakpic[y + (WATERSIZ + 2)];
317             dat += waterbakpic[y + (WATERSIZ + 2) - 1];
318             *ptr++ = (dat >> 3) + 223;
319         }
320     }
321 
322     waternumframes++;
323 }
324 
skypanfx()325 void skypanfx()
326 {
327     for (int i = 0; i < skypancnt; i++) {
328         sector[skypanlist[i]].ceilingxpanning = -((lockclock >> 2) & 255);
329     }
330 }
331 
panningfx()332 void panningfx()
333 {
334     Player* plr = &player[pyrn];
335 
336     //
337     // n ne e se s sw w nw
338     // 0  1 2  3 4  5 6  7
339     //
340     for (int i = 0; i < floorpanningcnt; i++)
341     {
342         short whichdir = sector[floorpanninglist[i]].lotag - 80;
343 
344         switch (whichdir)
345         {
346             case 0:
347             sector[floorpanninglist[i]].floorypanning = ((lockclock >> 2) & 255);
348             break;
349             case 1:
350             sector[floorpanninglist[i]].floorxpanning = -((lockclock >> 2) & 255);
351             sector[floorpanninglist[i]].floorypanning = ((lockclock >> 2) & 255);
352             break;
353             case 2:
354             sector[floorpanninglist[i]].floorxpanning = -((lockclock >> 2) & 255);
355             break;
356             case 3:
357             sector[floorpanninglist[i]].floorxpanning = -((lockclock >> 2) & 255);
358             sector[floorpanninglist[i]].floorypanning = -((lockclock >> 2) & 255);
359             break;
360             case 4:
361             sector[floorpanninglist[i]].floorypanning = -((lockclock >> 2) & 255);
362             break;
363             case 5:
364             sector[floorpanninglist[i]].floorxpanning = ((lockclock >> 2) & 255);
365             sector[floorpanninglist[i]].floorypanning = -((lockclock >> 2) & 255);
366             break;
367             case 6:
368             sector[floorpanninglist[i]].floorxpanning = ((lockclock >> 2) & 255);
369             break;
370             case 7:
371             sector[floorpanninglist[i]].floorxpanning = ((lockclock >> 2) & 255);
372             sector[floorpanninglist[i]].floorypanning = ((lockclock >> 2) & 255);
373             break;
374             default:
375             sector[floorpanninglist[i]].floorxpanning = 0;
376             sector[floorpanninglist[i]].floorypanning = 0;
377             break;
378         }
379     }
380 
381     for (int i = 0; i < xpanningsectorcnt; i++)
382     {
383         short dasector = xpanningsectorlist[i];
384         short startwall = sector[dasector].wallptr;
385         short endwall = startwall + sector[dasector].wallnum - 1;
386         for (int s = startwall; s <= endwall; s++)
387         {
388             wall[s].xpanning = ((lockclock >> 2) & 255);
389         }
390     }
391 
392     for (int i = 0; i < ypanningwallcnt; i++) {
393         wall[ypanningwalllist[i]].ypanning = ~(lockclock & 255);
394     }
395 }
396 
crushingfx()397 void crushingfx()
398 {
399     int j, s;
400     int32_t daz, goalz;
401 
402     for (int i = 0; i < crushsectorcnt; i++)
403     {
404         s = crushsectorlist[i];
405 
406         if (crushsectordone[s] == 1)
407         {
408             switch (crushsectoranim[s])
409             {
410                 case 1:
411                 if ((j = getanimationgoal(&sector[s].floorz)) < 0)
412                 {
413                     setanimation(&sector[s].floorz, sector[s].ceilingz, 64);
414                     crushsectordone[s] = 2;
415                 }
416                 break;
417                 case 2:
418                 if ((j = getanimationgoal(&sector[s].ceilingz)) < 0)
419                 {
420                     setanimation(&sector[s].ceilingz, sector[s].floorz, 64);
421                     crushsectordone[s] = 2;
422                 }
423                 break;
424                 case 3:
425                 if ((j = getanimationgoal(&sector[s].ceilingz)) < 0)
426                 {
427                     daz = (sector[s].ceilingz + sector[s].floorz) >> 1;
428                     setanimation(&sector[s].ceilingz, daz, 64);
429                     setanimation(&sector[s].floorz, daz, 64);
430                     crushsectordone[s] = 2;
431                 }
432                 break;
433             }
434         }
435 
436         if (crushsectordone[s] == 2)
437         {
438             switch (crushsectoranim[s])
439             {
440                 case 1:
441                 if ((j = getanimationgoal(&sector[s].floorz)) < 0)
442                 {
443                     goalz = sector[nextsectorneighborz(s, sector[s].floorz, 1, 1)].floorz;
444                     setanimation(&sector[s].floorz, goalz, 64);
445                     crushsectordone[s] = 1;
446                 }
447                 break;
448                 case 2:
449                 if ((j = getanimationgoal(&sector[s].ceilingz)) < 0)
450                 {
451                     goalz = sector[nextsectorneighborz(s, sector[s].ceilingz, -1, -1)].ceilingz;
452                     setanimation(&sector[s].ceilingz, goalz, 64);
453                     crushsectordone[s] = 1;
454                 }
455                 break;
456                 case 3:
457                 if ((j = getanimationgoal(&sector[s].ceilingz)) < 0)
458                 {
459                     goalz = sector[nextsectorneighborz(s, sector[s].ceilingz, -1, -1)].ceilingz;
460                     setanimation(&sector[s].ceilingz, goalz, 64);
461                     goalz = sector[nextsectorneighborz(s, sector[s].floorz, 1, 1)].floorz;
462                     setanimation(&sector[s].floorz, goalz, 64);
463                     crushsectordone[s] = 1;
464                 }
465                 break;
466             }
467         }
468     }
469 }
470 
revolvefx()471 void revolvefx()
472 {
473     int32_t dax, day;
474     Player* plr = &player[pyrn];
475 
476     for (int i = 0; i < revolvecnt; i++)
477     {
478         short startwall = sector[revolvesector[i]].wallptr;
479         short endwall = startwall + sector[revolvesector[i]].wallnum - 1;
480 
481         revolveang[i] = ((revolveang[i] + 2048 - (synctics << 1)) & kAngleMask);
482 
483         for (int k = startwall; k <= endwall; k++)
484         {
485             vec2_t pivot;
486             pivot.x = revolvepivotx[i];
487             pivot.y = revolvepivoty[i];
488 
489             vec2_t p;
490             p.x = revolvex[i][k - startwall];
491             p.y = revolvey[i][k - startwall];
492 
493             vec2_t p2;
494             rotatepoint(pivot, p, revolveang[i], &p2);
495 
496             dax = p2.x;
497             day = p2.y;
498 
499             dragpoint(k, dax, day, 0); // CHECKME - flags
500         }
501 
502         if (plr->sector == revolvesector[i])
503         {
504             revolvesyncang = plr->ang;
505             revolvesyncrotang = 0;
506             revolvesyncx = plr->x;
507             revolvesyncy = plr->y;
508             revolvesyncrotang = ((revolvesyncrotang + 2048 - (synctics << 1)) & kAngleMask);
509 
510             vec2_t pivot;
511             pivot.x = revolvepivotx[i];
512             pivot.y = revolvepivoty[i];
513 
514             vec2_t p;
515             p.x = revolvesyncx;
516             p.y = revolvesyncy;
517 
518             vec2_t p2;
519             p2.x = plr->x;
520             p2.y = plr->y;
521 
522             rotatepoint(pivot, p, revolvesyncrotang, &p2);
523 
524             plr->x = p2.x;
525             plr->y = p2.y;
526 
527             plr->ang = ((revolvesyncang + revolvesyncrotang) & kAngleMask);
528         }
529     }
530 }
531 
bobbingsector()532 void bobbingsector()
533 {
534     for (int i = 0; i < bobbingsectorcnt; i++)
535     {
536         int dasector = bobbingsectorlist[i];
537 
538         sector[dasector].floorz += Sin(lockclock << 4) >> 6;
539     }
540 }
541 
542 
543 #define NEXTLEVEL 1
544 #define ENDOFDEMO 2
545 
teleporter()546 void teleporter()
547 {
548     short dasector;
549     short startwall, endwall;
550     int i, j;
551     int s;
552     short daang;
553 
554     Player* plr = &player[pyrn];
555 
556     for (i = 0; i < warpsectorcnt; i++)
557     {
558         dasector = warpsectorlist[i];
559         j = ((lockclock & 127) >> 2);
560 
561         if (j >= 16) j = 31 - j;
562         {
563             sector[dasector].ceilingshade = j;
564             sector[dasector].floorshade = j;
565             startwall = sector[dasector].wallptr;
566             endwall = startwall + sector[dasector].wallnum - 1;
567             for (s = startwall; s <= endwall; s++)
568                 wall[s].shade = j;
569         }
570     }
571 
572     if (sector[plr->sector].lotag == 10)
573     {
574         if (plr->sector != plr->oldsector)
575         {
576             daang = (short)plr->ang;
577             warpfxsprite(plr->spritenum);
578             warp(&plr->x, &plr->y, &plr->z, &daang, &plr->sector);
579             warpfxsprite(plr->spritenum);
580             plr->ang = (int)daang;
581             justwarpedfx = 48;
582             //JSA PLUTO
583             playsound_loc(S_WARP, plr->x, plr->y);
584 
585             vec3_t pos;
586             pos.x = plr->x;
587             pos.y = plr->y;
588             pos.z = plr->z + (32 << 8);
589 
590             setsprite(plr->spritenum, &pos);
591         }
592     }
593 
594     if (sector[plr->sector].lotag == 4002)
595     {
596         if (plr->treasure[8] == 1)
597         {
598             plr->treasure[8] = 0;
599             if (plr->sector != plr->oldsector)
600             {
601                 switch (sector[plr->sector].hitag)
602                 {
603                     case NEXTLEVEL:
604                     justteleported = 1;
605                     mapon++;
606                     vel = 0;
607                     angvel = 0;
608                     svel = 0;
609                     playsound_loc(S_CHAINDOOR1, plr->x, plr->y);
610                     loadnewlevel(mapon);
611                     warpfxsprite(plr->spritenum);
612                     // cleans up the keys (ivorykey etc)
613                     plr->treasure[14] = plr->treasure[15] = plr->treasure[16] = plr->treasure[17] = 0;
614                     plr->treasure[4] = plr->treasure[5] = 0;
615                     SND_CheckLoops();
616                     break;
617                     case ENDOFDEMO:
618                     playsound_loc(S_THUNDER1, plr->x, plr->y);
619                     justteleported = 1;
620                     victory();
621                     SND_CheckLoops();
622                     break;
623                 }
624             }
625         }
626         else
627         {
628             // player need pentagram to teleport
629             StatusMessage(360, "ITEM NEEDED");
630         }
631     }
632 }
633 
warp(int32_t * x,int32_t * y,int32_t * z,short * daang,short * dasector)634 void warp(int32_t* x, int32_t* y, int32_t* z, short* daang, short* dasector)
635 {
636     short startwall, endwall, s;
637     int32_t i, dax, day;
638 
639     for (int i = 0; i < warpsectorcnt; i++)
640     {
641         if (sector[warpsectorlist[i]].hitag == sector[*dasector].hitag && warpsectorlist[i] != *dasector)
642         {
643             *dasector = warpsectorlist[i];
644             break;
645         }
646     }
647 
648     startwall = sector[*dasector].wallptr;
649     endwall = startwall + sector[*dasector].wallnum - 1;
650     dax = 0, day = 0;
651 
652     for (s = startwall; s <= endwall; s++)
653     {
654         dax += wall[s].x, day += wall[s].y;
655         if (wall[s].nextsector >= 0)
656         {
657             i = s;
658         }
659     }
660 
661     *x = dax / (endwall - startwall + 1);
662     *y = day / (endwall - startwall + 1);
663     *z = sector[*dasector].floorz - (32 << 8);
664     updatesector(*x, *y, dasector);
665     dax = ((wall[i].x + wall[wall[i].point2].x) >> 1);
666     day = ((wall[i].y + wall[wall[i].point2].y) >> 1);
667     *daang = getangle(dax - *x, day - *y);
668 }
669 
warpsprite(short spritenum)670 void warpsprite(short spritenum)
671 {
672     short dasectnum = sprite[spritenum].sectnum;
673 
674     warpfxsprite(spritenum);
675     warp(&sprite[spritenum].x, &sprite[spritenum].y, &sprite[spritenum].z, &sprite[spritenum].ang, &dasectnum);
676 
677     warpfxsprite(spritenum);
678 
679     vec3_t pos;
680     pos.x = sprite[spritenum].x;
681     pos.y = sprite[spritenum].y;
682     pos.z = sprite[spritenum].z;
683 
684     setsprite(spritenum, &pos);
685 }
686 
687 #define GRATEROT   16
688 #define GRATEVERT  512
689 
ironbars()690 void ironbars()
691 {
692     int32_t spritenum;
693     int32_t ironbarmove;
694 
695     for (int i = 0; i < ironbarscnt; i++)
696     {
697         if (ironbarsdone[i] == 1)
698         {
699             spritenum = ironbarsanim[i];
700 
701             switch (sprite[ironbarsanim[i]].hitag)
702             {
703                 case 1:
704                 {
705                     sprite[ironbarsanim[i]].ang += synctics << 1;
706                     if (sprite[ironbarsanim[i]].ang > 2047)
707                         sprite[ironbarsanim[i]].ang -= 2047;
708                     ironbarmove = ironbarsgoal[i] += synctics << 1;
709 
710                     vec3_t pos;
711                     pos.x = sprite[spritenum].x;
712                     pos.y = sprite[spritenum].y;
713                     pos.z = sprite[spritenum].z;
714 
715                     setsprite(spritenum, &pos);
716                     if (ironbarsgoal[i] > 512)
717                     {
718                         ironbarsgoal[i] = 0;
719                         sprite[ironbarsanim[i]].hitag = 2;
720                         ironbarsdone[i] = 0;
721                     }
722                     break;
723                 }
724                 case 2:
725                 {
726                     sprite[ironbarsanim[i]].ang -= synctics << 1;
727                     if (sprite[ironbarsanim[i]].ang < 0)
728                         sprite[ironbarsanim[i]].ang += 2047;
729                     ironbarsgoal[i] += synctics << 1;
730 
731                     vec3_t pos;
732                     pos.x = sprite[spritenum].x;
733                     pos.y = sprite[spritenum].y;
734                     pos.z = sprite[spritenum].z;
735 
736                     setsprite(spritenum, &pos);
737                     if (ironbarsgoal[i] > 512)
738                     {
739                         ironbarsgoal[i] = 0;
740                         sprite[ironbarsanim[i]].hitag = 1;
741                         ironbarsdone[i] = 0;
742                     }
743                     break;
744                 }
745                 case 3:
746                 {
747                     sprite[ironbarsanim[i]].z -= synctics << 4;
748                     if (sprite[ironbarsanim[i]].z < ironbarsgoal[i])
749                     {
750                         sprite[ironbarsanim[i]].z = ironbarsgoal[i];
751                         sprite[ironbarsanim[i]].hitag = 4;
752                         ironbarsdone[i] = 0;
753                         ironbarsgoal[i] = sprite[ironbarsanim[i]].z + 6000;
754                     }
755 
756                     vec3_t pos;
757                     pos.x = sprite[spritenum].x;
758                     pos.y = sprite[spritenum].y;
759                     pos.z = sprite[spritenum].z;
760 
761                     setsprite(spritenum, &pos);
762                     break;
763                 }
764                 case 4:
765                 {
766                     sprite[ironbarsanim[i]].z += synctics << 4;
767                     if (sprite[ironbarsanim[i]].z > ironbarsgoal[i])
768                     {
769                         sprite[ironbarsanim[i]].z = ironbarsgoal[i];
770                         sprite[ironbarsanim[i]].hitag = 3;
771                         ironbarsdone[i] = 0;
772                         ironbarsgoal[i] = sprite[ironbarsanim[i]].z - 6000;
773                     }
774 
775                     vec3_t pos;
776                     pos.x = sprite[spritenum].x;
777                     pos.y = sprite[spritenum].y;
778                     pos.z = sprite[spritenum].z;
779 
780                     setsprite(spritenum, &pos);
781                     break;
782                 }
783             }
784         }
785     }
786 }
787 
sectorsounds()788 void sectorsounds()
789 {
790     uint16_t sec;
791     int index;
792 
793     if (!SoundMode)
794         return;
795 
796     Player* plr = &player[pyrn];
797 
798     sec = sector[plr->sector].extra;
799 
800     if (sec)
801     {
802         if (sec & 32768)
803         {
804             // loop on/off sector
805             if (sec & 1)
806             {
807                 // turn loop on if lsb is 1
808                 index = ((sec ^ 32769) >> 1);
809                 if (ambsoundarray[index].hsound == -1)
810                     ambsoundarray[index].hsound = SND_PlaySound(ambsoundarray[index].soundnum, 0, 0, 0, -1);
811             }
812             else
813             {
814                 // turn loop off if lsb is 0 and its playing
815                 index = ((sec ^ 32768) >> 1);
816                 if (ambsoundarray[index].hsound != -1)
817                 {
818                     SND_StopLoop(ambsoundarray[index].hsound);
819                     ambsoundarray[index].hsound = -1;
820                 }
821             }
822         }
823         else
824         {
825             if (plr->z <= sector[plr->sector].floorz - (8 << 8))
826                 playsound_loc(sec, plr->x, plr->y);
827         }
828     }
829 }
830 
831 int scarytime=-1;
832 int scarysize=0;
833 
scary()834 void scary()
835 {
836     if (rand() > 32600 && rand() > 32600 && scarytime < 0)
837     {
838         scarytime = 180;
839         scarysize = 30;
840         SND_PlaySound(S_SCARYDUDE, 0, 0, 0, 0);
841     }
842 
843     if (scarytime >= 0)
844     {
845         scarytime -= synctics << 1;
846         scarysize += synctics << 1;
847         if (scarytime > 140 && scarytime < 180)
848             rotatesprite_fs(320 << 15, 200 << 15, scarysize << 9, 0, SCARY, 0, 0, 1 + 2);
849         if (scarytime > 120 && scarytime < 139)
850             rotatesprite_fs(320 << 15, 200 << 15, scarysize << 9, 0, SCARY + 1, 0, 0, 1 + 2);
851         if (scarytime > 100 && scarytime < 119)
852             rotatesprite_fs(320 << 15, 200 << 15, scarysize << 9, 0, SCARY + 2, 0, 0, 1 + 2);
853         if (scarytime > 0 && scarytime < 99)
854             rotatesprite_fs(320 << 15, 200 << 15, scarysize << 9, 0, SCARY + 3, 0, 0, 1 + 2);
855     }
856 }
857 
dofx()858 void dofx()
859 {
860     lavadryland();
861     scary();
862 
863     if (revolvecnt > 0)
864         revolvefx();
865 
866     panningfx();
867     teleporter();
868     bobbingsector();
869 
870     if (ironbarscnt > 0)
871         ironbars();
872 
873     if ((gotpic[ANILAVA >> 3] & (1 << (ANILAVA & 7))) > 0)
874     {
875         gotpic[ANILAVA >> 3] &= ~(1 << (ANILAVA & 7));
876         if (waloff[ANILAVA] != -1)
877         {
878             movelava((char*)waloff[ANILAVA]);
879         }
880     }
881 
882     if ((gotpic[HEALTHWATER >> 3] & (1 << (HEALTHWATER & 7))) > 0)
883     {
884         gotpic[HEALTHWATER >> 3] &= ~(1 << (HEALTHWATER & 7));
885         if (waloff[HEALTHWATER] != -1)
886         {
887             movewater((char*)waloff[HEALTHWATER]);
888         }
889     }
890 
891     thesplash();
892     thunder();
893     cracks();
894 }
895 
896 int thunderflash;
897 int thundertime;
898 
thunder()899 void thunder()
900 {
901     if (thunderflash == 0)
902     {
903         if ((gotpic[SKY >> 3] & (1 << (SKY & 7))) > 0)
904         {
905             gotpic[SKY >> 3] &= ~(1 << (SKY & 7));
906             if (waloff[SKY] != -1)
907             {
908                 visibility = 1024;
909                 if (rand() > 32700)
910                 {
911                     thunderflash = 1;
912                     thundertime = 120;
913                 }
914             }
915         }
916         else if ((gotpic[SKY2 >> 3] & (1 << (SKY2 & 7))) > 0)
917         {
918             gotpic[SKY2 >> 3] &= ~(1 << (SKY2 & 7));
919             if (waloff[SKY2] != -1)
920             {
921                 visibility = 768;
922                 if (rand() > 32700)
923                 {
924                     thunderflash = 1;
925                     thundertime = 120;
926                 }
927             }
928         }
929         else if ((gotpic[SKY3 >> 3] & (1 << (SKY3 & 7))) > 0)
930         {
931             gotpic[SKY3 >> 3] &= ~(1 << (SKY3 & 7));
932             if (waloff[SKY3] != -1)
933             {
934                 visibility = 512;
935                 if (rand() > 32700)
936                 {
937                     thunderflash = 1;
938                     thundertime = 120;
939                 }
940             }
941         }
942         else if ((gotpic[SKY4 >> 3] & (1 << (SKY4 & 7))) > 0)
943         {
944             gotpic[SKY4 >> 3] &= ~(1 << (SKY4 & 7));
945             if (waloff[SKY4] != -1)
946             {
947                 visibility = 512;
948                 if (rand() > 32700)
949                 {
950                     thunderflash = 1;
951                     thundertime = 120;
952                 }
953             }
954         }
955         else if ((gotpic[SKY5 >> 3] & (1 << (SKY5 & 7))) > 0)
956         {
957             gotpic[SKY5 >> 3] &= ~(1 << (SKY5 & 7));
958             if (waloff[SKY5] != -1)
959             {
960                 visibility = 1024;
961                 if (rand() > 32700)
962                 {
963                     thunderflash = 1;
964                     thundertime = 120;
965                 }
966             }
967         }
968         else if ((gotpic[SKY6 >> 3] & (1 << (SKY6 & 7))) > 0)
969         {
970             gotpic[SKY6 >> 3] &= ~(1 << (SKY6 & 7));
971             if (waloff[SKY6] != -1)
972             {
973                 visibility = 512;
974                 if (rand() > 32700)
975                 {
976                     thunderflash = 1;
977                     thundertime = 120;
978                 }
979             }
980         }
981         else if ((gotpic[SKY7 >> 3] & (1 << (SKY7 & 7))) > 0)
982         {
983             gotpic[SKY7 >> 3] &= ~(1 << (SKY7 & 7));
984             if (waloff[SKY7] != -1)
985             {
986                 visibility = 512;
987                 if (rand() > 32700)
988                 {
989                     thunderflash = 1;
990                     thundertime = 120;
991                 }
992             }
993         }
994         else if ((gotpic[SKY8 >> 3] & (1 << (SKY8 & 7))) > 0)
995         {
996             gotpic[SKY8 >> 3] &= ~(1 << (SKY8 & 7));
997             if (waloff[SKY8] != -1)
998             {
999                 visibility = 1024;
1000                 if (rand() > 32700)
1001                 {
1002                     thunderflash = 1;
1003                     thundertime = 120;
1004                 }
1005             }
1006         }
1007         else if ((gotpic[SKY9 >> 3] & (1 << (SKY9 & 7))) > 0)
1008         {
1009             gotpic[SKY9 >> 3] &= ~(1 << (SKY9 & 7));
1010             if (waloff[SKY9] != -1)
1011             {
1012                 visibility = 2048;
1013                 if (rand() > 32700)
1014                 {
1015                     thunderflash = 1;
1016                     thundertime = 120;
1017                 }
1018             }
1019         }
1020         else if ((gotpic[SKY10 >> 3] & (1 << (SKY10 & 7))) > 0)
1021         {
1022             gotpic[SKY10 >> 3] &= ~(1 << (SKY10 & 7));
1023             if (waloff[SKY10] != -1)
1024             {
1025                 visibility = 1024;
1026                 if (rand() > 32700)
1027                 {
1028                     thunderflash = 1;
1029                     thundertime = 120;
1030                 }
1031             }
1032         }
1033         else
1034             visibility = 1024;
1035     }
1036     else
1037     {
1038         thundertime -= synctics;
1039         if (thundertime < 0)
1040         {
1041             thunderflash = 0;
1042             brightness = gbrightness;
1043             setbrightness(brightness);
1044 
1045             SND_Sound(S_THUNDER1 + (rand() % 4));
1046             visibility = 1024;
1047         }
1048     }
1049 
1050     if (thunderflash == 1)
1051     {
1052         if (waloff[SKY] != -1)
1053         {
1054             int val = rand() % 4;
1055             brightness += val;
1056 
1057             switch (val)
1058             {
1059                 case 0:
1060                 visibility = 2048;
1061                 break;
1062                 case 1:
1063                 visibility = 1024;
1064                 break;
1065                 case 2:
1066                 visibility = 512;
1067                 break;
1068                 case 3:
1069                 visibility = 256;
1070                 break;
1071                 default:
1072                 visibility = 4096;
1073                 break;
1074             }
1075 
1076             if (brightness > 8) {
1077                 brightness = 0;
1078             }
1079 
1080             setbrightness(brightness);
1081         }
1082     }
1083 }
1084 
thesplash()1085 void thesplash()
1086 {
1087     Player* plr = &player[pyrn];
1088 
1089     if (sector[plr->sector].floorpicnum == WATER ||
1090         sector[plr->sector].floorpicnum == LAVA ||
1091         sector[plr->sector].floorpicnum == SLIME)
1092     {
1093         if (plr->sector != plr->oldsector)
1094         {
1095             if (sector[plr->sector].floorpicnum == WATER || sector[plr->sector].floorpicnum == SLIME)
1096                 makeasplash(SPLASHAROO, plr);
1097             else
1098                 makeasplash(LAVASPLASH, plr);
1099         }
1100     }
1101 }
1102 
makeasplash(int picnum,Player * plr)1103 void makeasplash(int picnum, Player* plr)
1104 {
1105     int32_t j = insertsprite(plr->sector, MASPLASH);
1106     sprite[j].x = plr->x;
1107     sprite[j].y = plr->y;
1108     sprite[j].z = sector[plr->sector].floorz + (tilesiz[picnum].y << 8);
1109     sprite[j].cstat = 0;        //Hitscan does not hit other bullets
1110     sprite[j].picnum = picnum;
1111     sprite[j].shade = 0;
1112     sprite[j].pal = 0;
1113     sprite[j].xrepeat = 64;
1114     sprite[j].yrepeat = 64;
1115     sprite[j].owner = 0;
1116     sprite[j].clipdist = 16;
1117     sprite[j].lotag = 8;
1118     sprite[j].hitag = 0;
1119 
1120     switch (picnum)
1121     {
1122         case SPLASHAROO:
1123         playsound_loc(S_SPLASH1 + (krand() % 3), sprite[j].x, sprite[j].y);
1124         break;
1125         case LAVASPLASH:
1126         break;
1127     }
1128 
1129     movesprite(j, (Cos(sprite[j].ang) * synctics) << 3, (((int)sintable[sprite[j].ang]) * synctics) << 3, 0, 4 << 8, 4 << 8, 0);
1130 }
1131 
makemonstersplash(int picnum,int i)1132 void makemonstersplash(int picnum, int i)
1133 {
1134     if (sprite[i].picnum == FISH)
1135         return;
1136 
1137     int32_t j = insertsprite(sprite[i].sectnum, MASPLASH);
1138     sprite[j].x = sprite[i].x;
1139     sprite[j].y = sprite[i].y;
1140     sprite[j].z = sector[sprite[i].sectnum].floorz + (tilesiz[picnum].y << 8);
1141     sprite[j].cstat = 0;        //Hitscan does not hit other bullets
1142     sprite[j].picnum = picnum;
1143     sprite[j].shade = 0;
1144 
1145     if (sector[sprite[i].sectnum].floorpal == 9)
1146         sprite[j].pal = 9;
1147     else
1148         sprite[j].pal = 0;
1149 
1150     sprite[j].xrepeat = 64;
1151     sprite[j].yrepeat = 64;
1152     sprite[j].owner = 0;
1153     sprite[j].clipdist = 16;
1154     sprite[j].lotag = 8;
1155     sprite[j].hitag = 0;
1156 
1157     switch (picnum)
1158     {
1159         case SPLASHAROO:
1160         if (rand() % 2)
1161         {
1162             if ((gotpic[WATER >> 3] & (1 << (WATER & 7))) > 0)
1163             {
1164                 gotpic[WATER >> 3] &= ~(1 << (WATER & 7));
1165                 if (waloff[WATER] != -1)
1166                 {
1167                     if (rand() % 2)
1168                     {
1169                         playsound_loc(S_SPLASH1 + (krand() % 3), sprite[j].x, sprite[j].y);
1170                     }
1171                 }
1172             }
1173         }
1174         if (rand() % 2)
1175         {
1176             if ((gotpic[SLIME >> 3] & (1 << (SLIME & 7))) > 0)
1177             {
1178                 gotpic[SLIME >> 3] &= ~(1 << (SLIME & 7));
1179                 if (waloff[SLIME] != -1)
1180                 {
1181                     if (rand() % 2)
1182                     {
1183                         playsound_loc(S_SPLASH1 + (krand() % 3), sprite[j].x, sprite[j].y);
1184                     }
1185                 }
1186             }
1187         }
1188         break;
1189         case LAVASPLASH:
1190         break;
1191     }
1192 }
1193 
bats(short k)1194 void bats(short k)
1195 {
1196     int32_t j = insertsprite(sprite[k].sectnum, FLOCK);
1197     sprite[j].x = sprite[k].x;
1198     sprite[j].y = sprite[k].y;
1199     sprite[j].z = sprite[k].z;
1200     sprite[j].cstat = 0;
1201     sprite[j].picnum = BAT;
1202     sprite[j].shade = 0;
1203     sprite[j].xrepeat = 64;
1204     sprite[j].yrepeat = 64;
1205     sprite[j].ang = Sin(sprite[k].ang + ((krand() & 128) - 256));
1206     sprite[j].owner = k;
1207     sprite[j].clipdist = 16;
1208     sprite[j].lotag = 128;
1209     sprite[j].hitag = k;
1210     sprite[j].extra = 0;
1211 
1212     newstatus(j, FLOCK);
1213 
1214     if (sprite[k].extra == 1)
1215         lastbat = j;
1216 }
1217 
cracks()1218 void cracks()
1219 {
1220     short datag;
1221     int32_t daz;
1222     int j, k;
1223 
1224     Player* plr = &player[pyrn];
1225 
1226     datag = sector[plr->sector].lotag;
1227 
1228     if (floorpanningcnt < 64)
1229     {
1230         if (datag >= 3500 && datag <= 3599)
1231         {
1232             sector[plr->sector].hitag = 0;
1233             daz = sector[plr->sector].floorz + (1024 * (sector[plr->sector].lotag - 3500));
1234             if ((j = setanimation(&sector[plr->sector].floorz, daz, 32)) >= 0)
1235             {
1236                 sector[plr->sector].floorpicnum = LAVA1;
1237                 sector[plr->sector].floorshade = -25;
1238                 SND_PlaySound(S_CRACKING, 0, 0, 0, 0);
1239             }
1240             sector[plr->sector].lotag = 80;
1241             floorpanninglist[floorpanningcnt++] = plr->sector;
1242         }
1243     }
1244 
1245     if (datag >= 5100 && datag <= 5199)
1246     {
1247         sector[plr->sector].hitag = 0;
1248 
1249         daz = sector[plr->sector].floorz + (1024 * (sector[plr->sector].lotag - 5100));
1250         sector[plr->sector].lotag = 0;
1251     }
1252 
1253     if (datag >= 5200 && datag <= 5299)
1254     {
1255         sector[plr->sector].hitag = 0;
1256 
1257         daz = sector[plr->sector].floorz + (1024 * (sector[plr->sector].lotag - 5200));
1258         sector[plr->sector].lotag = 0;
1259     }
1260 
1261     if (datag == 3001)
1262     {
1263         sector[plr->sector].lotag = 0;
1264 
1265         for (k = 0; k < MAXSPRITES; k++)
1266         {
1267             if (sector[plr->sector].hitag == sprite[k].hitag)
1268             {
1269                 sprite[k].lotag = 36;
1270                 sprite[k].zvel = (krand() & 1024) + 512;
1271                 newstatus(k, SHOVE);
1272             }
1273         }
1274     }
1275 }
1276 
lavadryland()1277 void lavadryland()
1278 {
1279     short k;
1280     short s;
1281     int32_t daz;
1282 
1283     Player* plr = &player[pyrn];
1284 
1285     for (k = 0; k<lavadrylandcnt; k++)
1286     {
1287         s = lavadrylandsector[k];
1288 
1289         if (plr->sector==s&&sector[s].lotag>0)
1290         {
1291             sector[s].hitag = 0;
1292 
1293             switch (sector[s].floorpicnum)
1294             {
1295                 case LAVA:
1296                 case ANILAVA:
1297                 case LAVA1:
1298                 sector[s].floorpicnum = COOLLAVA;
1299                 break;
1300                 case SLIME:
1301                 sector[s].floorpicnum = DRYSLIME;
1302                 break;
1303                 case WATER:
1304                 case HEALTHWATER:
1305                 sector[s].floorpicnum = DRYWATER;
1306                 break;
1307                 case LAVA2:
1308                 sector[s].floorpicnum = COOLLAVA2;
1309                 break;
1310             }
1311 
1312             daz = sector[s].floorz-(1024*(sector[s].lotag-900));
1313 
1314             sector[s].lotag = 0;
1315         }
1316     }
1317 }
1318 
warpfxsprite(int s)1319 void warpfxsprite(int s)
1320 {
1321     short daang;
1322     Player* plr = &player[pyrn];
1323 
1324     int32_t j = insertsprite(sprite[s].sectnum, WARPFX);
1325 
1326     sprite[j].x = sprite[s].x;
1327     sprite[j].y = sprite[s].y;
1328     sprite[j].z = sprite[s].z-(32<<8);
1329     sprite[j].cstat = 0;
1330     sprite[j].picnum = ANNIHILATE;
1331 
1332     if (s == plr->spritenum)
1333     {
1334         daang = plr->ang;
1335         sprite[j].ang = daang;
1336     }
1337     else
1338     {
1339         daang = sprite[s].ang;
1340         sprite[j].ang = daang;
1341     }
1342 
1343     sprite[j].xrepeat = 48;
1344     sprite[j].yrepeat = 48;
1345     sprite[j].clipdist = 16;
1346     sprite[j].extra = 0;
1347     sprite[j].shade = -31;
1348     sprite[j].xvel = ((krand()&256)-128);
1349     sprite[j].yvel = ((krand()&256)-128);
1350     sprite[j].zvel = ((krand()&256)-128);
1351     sprite[j].owner = s;
1352     sprite[j].lotag = 12;
1353     sprite[j].hitag = 0;
1354     sprite[j].pal = 0;
1355 
1356     int32_t daz = ((((int)sprite[j].zvel)*synctics)>>3);
1357 
1358     movesprite(j, (Cos(daang)*synctics)<<3, (Sin(daang)*synctics)<<3, daz, 4<<8, 4<<8, 1);
1359 }
1360