1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010-2019 EDuke32 developers and contributors
4 Copyright (C) 2019 Nuke.YKT
5 
6 This file is part of NBlood.
7 
8 NBlood 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 #include <iostream>
24 
25 #include "build.h"
26 #include "pragmas.h"
27 #include "mmulti.h"
28 #include "common.h"
29 #include "common_game.h"
30 
31 #include "actor.h"
32 #include "ai.h"
33 #include "aibat.h"
34 #include "aibeast.h"
35 #include "aiboneel.h"
36 #include "aiburn.h"
37 #include "aicaleb.h"
38 #include "aicerber.h"
39 #include "aicult.h"
40 #include "aigarg.h"
41 #include "aighost.h"
42 #include "aigilbst.h"
43 #include "aihand.h"
44 #include "aihound.h"
45 #include "aiinnoc.h"
46 #include "aipod.h"
47 #include "airat.h"
48 #include "aispid.h"
49 #include "aitchern.h"
50 #include "aizomba.h"
51 #include "aizombf.h"
52 #ifdef NOONE_EXTENSIONS
53 #include "aiunicult.h"
54 #endif
55 #include "blood.h"
56 #include "callback.h"
57 #include "config.h"
58 #include "db.h"
59 #include "endgame.h"
60 #include "eventq.h"
61 #include "fx.h"
62 #include "gameutil.h"
63 #include "gib.h"
64 #include "globals.h"
65 #include "levels.h"
66 #include "loadsave.h"
67 #include "player.h"
68 #include "seq.h"
69 #include "sfx.h"
70 #include "sound.h"
71 #include "tile.h"
72 #include "trig.h"
73 #include "triggers.h"
74 #include "view.h"
75 #include "warp.h"
76 #include "weapon.h"
77 #ifdef NOONE_EXTENSIONS
78 #include "nnexts.h"
79 #endif
80 
81 VECTORDATA gVectorData[] = {
82 
83     // Tine
84     {
85         kDamageBullet,
86         17,
87         174762,
88         1152,
89         10240,
90         0,
91         1,
92         20480,
93         FX_NONE, FX_NONE, FX_NONE, -1,
94         FX_43, FX_5, FX_NONE, 500,
95         FX_NONE, FX_5, FX_NONE, 501,
96         FX_43, FX_6, FX_NONE, 502,
97         FX_43, FX_0, FX_NONE, 503,
98         FX_NONE, FX_4, FX_NONE, -1,
99         FX_NONE, FX_6, FX_7, 502,
100         FX_43, FX_6, FX_7, 502,
101         FX_NONE, FX_NONE, FX_NONE, 503,
102         FX_43, FX_NONE, FX_NONE, -1,
103         FX_NONE, FX_6, FX_NONE, 503,
104         FX_NONE, FX_6, FX_NONE, -1,
105         FX_NONE, FX_6, FX_NONE, 502,
106         FX_NONE, FX_NONE, FX_NONE, -1,
107         FX_NONE, FX_5, FX_NONE, -1,
108     },
109 
110     // Shell
111     {
112         kDamageBullet,
113         4,
114         65536,
115         0,
116         8192,
117         0,
118         1,
119         12288,
120         FX_NONE, FX_NONE, FX_NONE, -1,
121         FX_43, FX_5, FX_NONE, -1,
122         FX_NONE, FX_5, FX_NONE, 501,
123         FX_43, FX_6, FX_NONE, -1,
124         FX_43, FX_0, FX_NONE, -1,
125         FX_NONE, FX_4, FX_NONE, -1,
126         FX_NONE, FX_6, FX_NONE, -1,
127         FX_43, FX_6, FX_NONE, -1,
128         FX_NONE, FX_NONE, FX_NONE, -1,
129         FX_43, FX_NONE, FX_NONE, -1,
130         FX_NONE, FX_6, FX_NONE, -1,
131         FX_NONE, FX_6, FX_NONE, -1,
132         FX_NONE, FX_6, FX_NONE, -1,
133         FX_NONE, FX_NONE, FX_NONE, -1,
134         FX_NONE, FX_5, FX_NONE, -1,
135     },
136 
137     // Bullet
138     {
139         kDamageBullet,
140         7,
141         21845,
142         0,
143         32768,
144         0,
145         1,
146         12288,
147         FX_NONE, FX_NONE, FX_NONE, -1,
148         FX_43, FX_5, FX_7, 510,
149         FX_NONE, FX_5, FX_7, 511,
150         FX_43, FX_6, FX_NONE, 512,
151         FX_43, FX_0, FX_NONE, 513,
152         FX_NONE, FX_4, FX_NONE, -1,
153         FX_NONE, FX_6, FX_7, 512,
154         FX_43, FX_6, FX_7, 512,
155         FX_NONE, FX_NONE, FX_NONE, 513,
156         FX_43, FX_NONE, FX_NONE, 513,
157         FX_NONE, FX_6, FX_NONE, 513,
158         FX_NONE, FX_6, FX_NONE, 513,
159         FX_NONE, FX_6, FX_NONE, 513,
160         FX_NONE, FX_NONE, FX_NONE, -1,
161         FX_NONE, FX_5, FX_NONE, -1,
162 
163     },
164 
165     // Tommy AP
166     {
167         kDamageBullet,
168         20,
169         65536,
170         0,
171         16384,
172         0,
173         1,
174         20480,
175         FX_NONE, FX_NONE, FX_NONE, -1,
176         FX_43, FX_5, FX_7, 510,
177         FX_NONE, FX_5, FX_7, 511,
178         FX_43, FX_6, FX_NONE, 512,
179         FX_43, FX_0, FX_NONE, 513,
180         FX_NONE, FX_4, FX_NONE, -1,
181         FX_NONE, FX_6, FX_7, 512,
182         FX_43, FX_6, FX_7, 512,
183         FX_NONE, FX_NONE, FX_NONE, 513,
184         FX_43, FX_NONE, FX_NONE, 513,
185         FX_NONE, FX_6, FX_NONE, 513,
186         FX_NONE, FX_6, FX_NONE, 513,
187         FX_NONE, FX_6, FX_NONE, 513,
188         FX_NONE, FX_NONE, FX_NONE, -1,
189         FX_NONE, FX_5, FX_NONE, -1,
190     },
191 
192     // Shell AP
193     {
194         kDamageBullet,
195         6,
196         87381,
197         0,
198         12288,
199         0,
200         1,
201         6144,
202         FX_NONE, FX_NONE, FX_NONE, -1,
203         FX_43, FX_5, FX_NONE, -1,
204         FX_NONE, FX_5, FX_NONE, 501,
205         FX_43, FX_6, FX_NONE, -1,
206         FX_43, FX_0, FX_NONE, -1,
207         FX_NONE, FX_4, FX_NONE, -1,
208         FX_NONE, FX_6, FX_NONE, -1,
209         FX_43, FX_6, FX_NONE, -1,
210         FX_NONE, FX_NONE, FX_NONE, -1,
211         FX_43, FX_NONE, FX_NONE, -1,
212         FX_NONE, FX_6, FX_NONE, -1,
213         FX_NONE, FX_6, FX_NONE, -1,
214         FX_NONE, FX_6, FX_NONE, -1,
215         FX_NONE, FX_NONE, FX_NONE, -1,
216         FX_NONE, FX_5, FX_NONE, -1,
217     },
218 
219     // Tommy regular
220     {
221         kDamageBullet,
222         12,
223         65536,
224         0,
225         16384,
226         0,
227         1,
228         12288,
229         FX_NONE, FX_NONE, FX_NONE, -1,
230         FX_43, FX_5, FX_7, 510,
231         FX_NONE, FX_5, FX_7, 511,
232         FX_43, FX_6, FX_NONE, 512,
233         FX_43, FX_0, FX_NONE, 513,
234         FX_NONE, FX_4, FX_NONE, -1,
235         FX_NONE, FX_6, FX_7, 512,
236         FX_43, FX_6, FX_7, 512,
237         FX_NONE, FX_NONE, FX_NONE, 513,
238         FX_43, FX_NONE, FX_NONE, 513,
239         FX_NONE, FX_6, FX_NONE, 513,
240         FX_NONE, FX_6, FX_NONE, 513,
241         FX_NONE, FX_6, FX_NONE, 513,
242         FX_NONE, FX_NONE, FX_NONE, -1,
243         FX_NONE, FX_5, FX_NONE, -1,
244     },
245 
246     // Bat bite
247     {
248         kDamageBullet,
249         4,
250         0,
251         921,
252         0,
253         0,
254         1,
255         4096,
256         FX_NONE, FX_NONE, FX_NONE, -1,
257         FX_NONE, FX_5, FX_NONE, -1,
258         FX_NONE, FX_5, FX_NONE, -1,
259         FX_NONE, FX_6, FX_NONE, 502,
260         FX_NONE, FX_0, FX_NONE, 503,
261         FX_NONE, FX_4, FX_NONE, -1,
262         FX_NONE, FX_6, FX_NONE, 502,
263         FX_NONE, FX_6, FX_NONE, 502,
264         FX_NONE, FX_NONE, FX_NONE, -1,
265         FX_NONE, FX_NONE, FX_NONE, -1,
266         FX_NONE, FX_NONE, FX_NONE, -1,
267         FX_NONE, FX_NONE, FX_NONE, -1,
268         FX_NONE, FX_NONE, FX_NONE, 502,
269         FX_NONE, FX_NONE, FX_NONE, -1,
270         FX_NONE, FX_NONE, FX_NONE, -1,
271     },
272 
273     // Eel bite
274     {
275         kDamageBullet,
276         12,
277         0,
278         1177,
279         0,
280         0,
281         0,
282         0,
283         FX_NONE, FX_NONE, FX_NONE, -1,
284         FX_NONE, FX_5, FX_NONE, 500,
285         FX_NONE, FX_5, FX_NONE, 501,
286         FX_NONE, FX_6, FX_NONE, 502,
287         FX_NONE, FX_0, FX_NONE, 503,
288         FX_NONE, FX_4, FX_NONE, -1,
289         FX_NONE, FX_6, FX_NONE, 502,
290         FX_NONE, FX_6, FX_NONE, 502,
291         FX_NONE, FX_NONE, FX_NONE, -1,
292         FX_NONE, FX_NONE, FX_NONE, -1,
293         FX_NONE, FX_NONE, FX_NONE, -1,
294         FX_NONE, FX_NONE, FX_NONE, -1,
295         FX_NONE, FX_NONE, FX_NONE, 502,
296         FX_NONE, FX_NONE, FX_NONE, -1,
297         FX_NONE, FX_NONE, FX_NONE, -1,
298     },
299 
300     // Gill bite
301     {
302         kDamageBullet,
303         9,
304         0,
305         1177,
306         0,
307         0,
308         0,
309         0,
310         FX_NONE, FX_NONE, FX_NONE, -1,
311         FX_NONE, FX_5, FX_NONE, 500,
312         FX_NONE, FX_5, FX_NONE, 501,
313         FX_NONE, FX_6, FX_NONE, 502,
314         FX_NONE, FX_0, FX_NONE, 503,
315         FX_NONE, FX_4, FX_NONE, -1,
316         FX_NONE, FX_6, FX_NONE, 502,
317         FX_NONE, FX_6, FX_NONE, 502,
318         FX_NONE, FX_NONE, FX_NONE, -1,
319         FX_NONE, FX_NONE, FX_NONE, -1,
320         FX_NONE, FX_NONE, FX_NONE, -1,
321         FX_NONE, FX_NONE, FX_NONE, -1,
322         FX_NONE, FX_NONE, FX_NONE, 502,
323         FX_NONE, FX_NONE, FX_NONE, -1,
324         FX_NONE, FX_NONE, FX_NONE, -1,
325     },
326 
327     // Beast slash
328     {
329         kDamageExplode,
330         50,
331         43690,
332         1024,
333         8192,
334         0,
335         4,
336         32768,
337         FX_NONE, FX_NONE, FX_NONE, -1,
338         FX_NONE, FX_5, FX_NONE, 500,
339         FX_NONE, FX_5, FX_NONE, 501,
340         FX_NONE, FX_6, FX_NONE, 502,
341         FX_NONE, FX_0, FX_NONE, 503,
342         FX_NONE, FX_4, FX_NONE, -1,
343         FX_NONE, FX_6, FX_NONE, 502,
344         FX_NONE, FX_6, FX_NONE, 502,
345         FX_NONE, FX_NONE, FX_NONE, -1,
346         FX_NONE, FX_NONE, FX_NONE, -1,
347         FX_NONE, FX_NONE, FX_NONE, -1,
348         FX_NONE, FX_NONE, FX_NONE, -1,
349         FX_NONE, FX_NONE, FX_NONE, 502,
350         FX_NONE, FX_NONE, FX_NONE, -1,
351         FX_NONE, FX_NONE, FX_NONE, -1,
352     },
353 
354     // Axe
355     {
356         kDamageBullet,
357         18,
358         436906,
359         1024,
360         16384,
361         0,
362         2,
363         20480,
364         FX_NONE, FX_NONE, FX_NONE, -1,
365         FX_NONE, FX_5, FX_NONE, 500,
366         FX_NONE, FX_5, FX_NONE, 501,
367         FX_NONE, FX_6, FX_NONE, 502,
368         FX_NONE, FX_0, FX_NONE, 503,
369         FX_NONE, FX_4, FX_NONE, -1,
370         FX_NONE, FX_6, FX_NONE, 502,
371         FX_NONE, FX_6, FX_NONE, 502,
372         FX_NONE, FX_NONE, FX_NONE, -1,
373         FX_NONE, FX_NONE, FX_NONE, -1,
374         FX_NONE, FX_6, FX_NONE, -1,
375         FX_NONE, FX_6, FX_NONE, -1,
376         FX_NONE, FX_6, FX_NONE, 502,
377         FX_NONE, FX_NONE, FX_NONE, -1,
378         FX_NONE, FX_5, FX_NONE, -1,
379     },
380 
381     // Cleaver
382     {
383         kDamageBullet,
384         9,
385         218453,
386         1024,
387         0,
388         0,
389         1,
390         24576,
391         FX_NONE, FX_NONE, FX_NONE, -1,
392         FX_NONE, FX_5, FX_NONE, 500,
393         FX_NONE, FX_5, FX_NONE, 501,
394         FX_NONE, FX_6, FX_NONE, 502,
395         FX_NONE, FX_0, FX_NONE, 503,
396         FX_NONE, FX_4, FX_NONE, -1,
397         FX_NONE, FX_6, FX_NONE, 502,
398         FX_NONE, FX_6, FX_NONE, 502,
399         FX_NONE, FX_NONE, FX_NONE, -1,
400         FX_NONE, FX_NONE, FX_NONE, -1,
401         FX_NONE, FX_6, FX_NONE, -1,
402         FX_NONE, FX_6, FX_NONE, -1,
403         FX_NONE, FX_6, FX_NONE, 502,
404         FX_NONE, FX_NONE, FX_NONE, -1,
405         FX_NONE, FX_5, FX_NONE, -1,
406     },
407 
408     // Phantasm slash
409     {
410         kDamageBullet,
411         20,
412         436906,
413         1024,
414         16384,
415         0,
416         3,
417         24576,
418         FX_NONE, FX_NONE, FX_NONE, -1,
419         FX_NONE, FX_5, FX_NONE, 500,
420         FX_NONE, FX_5, FX_NONE, 501,
421         FX_NONE, FX_6, FX_NONE, 502,
422         FX_NONE, FX_0, FX_NONE, 503,
423         FX_NONE, FX_4, FX_NONE, -1,
424         FX_NONE, FX_6, FX_NONE, 502,
425         FX_NONE, FX_6, FX_NONE, 502,
426         FX_NONE, FX_NONE, FX_NONE, -1,
427         FX_NONE, FX_NONE, FX_NONE, -1,
428         FX_NONE, FX_6, FX_NONE, -1,
429         FX_NONE, FX_6, FX_NONE, -1,
430         FX_NONE, FX_6, FX_NONE, 502,
431         FX_NONE, FX_NONE, FX_NONE, -1,
432         FX_NONE, FX_5, FX_NONE, -1,
433     },
434 
435     // Gargoyle Slash
436     {
437         kDamageBullet,
438         16,
439         218453,
440         1024,
441         8192,
442         0,
443         4,
444         20480,
445         FX_NONE, FX_NONE, FX_NONE, -1,
446         FX_NONE, FX_5, FX_NONE, 500,
447         FX_NONE, FX_5, FX_NONE, 501,
448         FX_NONE, FX_6, FX_NONE, 502,
449         FX_NONE, FX_0, FX_NONE, 503,
450         FX_NONE, FX_4, FX_NONE, -1,
451         FX_NONE, FX_6, FX_NONE, 502,
452         FX_NONE, FX_6, FX_NONE, 502,
453         FX_NONE, FX_NONE, FX_NONE, -1,
454         FX_NONE, FX_NONE, FX_NONE, -1,
455         FX_NONE, FX_6, FX_NONE, -1,
456         FX_NONE, FX_6, FX_NONE, -1,
457         FX_NONE, FX_6, FX_NONE, 502,
458         FX_NONE, FX_NONE, FX_NONE, -1,
459         FX_NONE, FX_5, FX_NONE, -1,
460     },
461 
462     // Cerberus bite
463     {
464         kDamageBullet,
465         19,
466         218453,
467         614,
468         8192,
469         0,
470         2,
471         24576,
472         FX_NONE, FX_NONE, FX_NONE, -1,
473         FX_NONE, FX_5, FX_NONE, 500,
474         FX_NONE, FX_5, FX_NONE, 501,
475         FX_NONE, FX_6, FX_NONE, 502,
476         FX_NONE, FX_0, FX_NONE, 503,
477         FX_NONE, FX_4, FX_NONE, -1,
478         FX_NONE, FX_6, FX_NONE, 502,
479         FX_NONE, FX_6, FX_NONE, 502,
480         FX_NONE, FX_NONE, FX_NONE, -1,
481         FX_NONE, FX_NONE, FX_NONE, -1,
482         FX_NONE, FX_NONE, FX_NONE, -1,
483         FX_NONE, FX_NONE, FX_NONE, -1,
484         FX_NONE, FX_NONE, FX_NONE, 502,
485         FX_NONE, FX_NONE, FX_NONE, -1,
486         FX_NONE, FX_NONE, FX_NONE, -1,
487     },
488 
489     // Hound bite
490     {
491         kDamageBullet,
492         10,
493         218453,
494         614,
495         8192,
496         0,
497         2,
498         24576,
499         FX_NONE, FX_NONE, FX_NONE, -1,
500         FX_NONE, FX_5, FX_NONE, 500,
501         FX_NONE, FX_5, FX_NONE, 501,
502         FX_NONE, FX_6, FX_NONE, 502,
503         FX_NONE, FX_0, FX_NONE, 503,
504         FX_NONE, FX_4, FX_NONE, -1,
505         FX_NONE, FX_6, FX_NONE, 502,
506         FX_NONE, FX_6, FX_NONE, 502,
507         FX_NONE, FX_NONE, FX_NONE, -1,
508         FX_NONE, FX_NONE, FX_NONE, -1,
509         FX_NONE, FX_NONE, FX_NONE, -1,
510         FX_NONE, FX_NONE, FX_NONE, -1,
511         FX_NONE, FX_NONE, FX_NONE, 502,
512         FX_NONE, FX_NONE, FX_NONE, -1,
513         FX_NONE, FX_NONE, FX_NONE, -1,
514     },
515 
516     // Rat bite
517     {
518         kDamageBullet,
519         4,
520         0,
521         921,
522         0,
523         0,
524         1,
525         24576,
526         FX_NONE, FX_NONE, FX_NONE, -1,
527         FX_NONE, FX_5, FX_NONE, -1,
528         FX_NONE, FX_5, FX_NONE, -1,
529         FX_NONE, FX_6, FX_NONE, 502,
530         FX_NONE, FX_0, FX_NONE, 503,
531         FX_NONE, FX_4, FX_NONE, -1,
532         FX_NONE, FX_6, FX_NONE, 502,
533         FX_NONE, FX_6, FX_NONE, 502,
534         FX_NONE, FX_NONE, FX_NONE, -1,
535         FX_NONE, FX_NONE, FX_NONE, -1,
536         FX_NONE, FX_NONE, FX_NONE, -1,
537         FX_NONE, FX_NONE, FX_NONE, -1,
538         FX_NONE, FX_NONE, FX_NONE, 502,
539         FX_NONE, FX_NONE, FX_NONE, -1,
540         FX_NONE, FX_NONE, FX_NONE, -1,
541     },
542 
543     // Spider bite
544     {
545         kDamageBullet,
546         8,
547         0,
548         614,
549         0,
550         0,
551         1,
552         24576,
553         FX_NONE, FX_NONE, FX_NONE, -1,
554         FX_NONE, FX_5, FX_NONE, 500,
555         FX_NONE, FX_5, FX_NONE, 501,
556         FX_NONE, FX_6, FX_NONE, 502,
557         FX_NONE, FX_0, FX_NONE, 503,
558         FX_NONE, FX_4, FX_NONE, -1,
559         FX_NONE, FX_6, FX_NONE, 502,
560         FX_NONE, FX_6, FX_NONE, 502,
561         FX_NONE, FX_NONE, FX_NONE, -1,
562         FX_NONE, FX_NONE, FX_NONE, -1,
563         FX_NONE, FX_NONE, FX_NONE, -1,
564         FX_NONE, FX_NONE, FX_NONE, -1,
565         FX_NONE, FX_NONE, FX_NONE, 502,
566         FX_NONE, FX_NONE, FX_NONE, -1,
567         FX_NONE, FX_NONE, FX_NONE, -1,
568     },
569 
570     // Unk
571     {
572         kDamageBullet,
573         9,
574         0,
575         512,
576         0,
577         0,
578         0,
579         0,
580         FX_NONE, FX_NONE, FX_NONE, -1,
581         FX_NONE, FX_5, FX_NONE, 500,
582         FX_NONE, FX_5, FX_NONE, 501,
583         FX_NONE, FX_6, FX_NONE, 502,
584         FX_NONE, FX_0, FX_NONE, 503,
585         FX_NONE, FX_4, FX_NONE, -1,
586         FX_NONE, FX_6, FX_NONE, 502,
587         FX_NONE, FX_6, FX_NONE, 502,
588         FX_NONE, FX_NONE, FX_NONE, -1,
589         FX_NONE, FX_NONE, FX_NONE, -1,
590         FX_NONE, FX_NONE, FX_NONE, -1,
591         FX_NONE, FX_NONE, FX_NONE, -1,
592         FX_NONE, FX_NONE, FX_NONE, 502,
593         FX_NONE, FX_NONE, FX_NONE, -1,
594         FX_NONE, FX_NONE, FX_NONE, -1,
595     },
596 
597     {
598         (DAMAGE_TYPE)-1,
599         0,
600         0,
601         2560,
602         0,
603         0,
604         0,
605         0,
606         FX_NONE, FX_NONE, FX_NONE, -1,
607         FX_NONE, FX_34, FX_35, -1,
608         FX_NONE, FX_34, FX_35, -1,
609         FX_NONE, FX_34, FX_35, -1,
610         FX_NONE, FX_34, FX_35, -1,
611         FX_NONE, FX_NONE, FX_NONE, -1,
612         FX_NONE, FX_34, FX_35, -1,
613         FX_NONE, FX_34, FX_35, -1,
614         FX_NONE, FX_34, FX_35, -1,
615         FX_NONE, FX_34, FX_35, -1,
616         FX_NONE, FX_NONE, FX_NONE, -1,
617         FX_NONE, FX_NONE, FX_NONE, -1,
618         FX_NONE, FX_NONE, FX_NONE, -1,
619         FX_NONE, FX_NONE, FX_NONE, -1,
620         FX_NONE, FX_NONE, FX_NONE, -1,
621     },
622 
623     // Tchernobog burn vector
624     {
625         kDamageBurn,
626         2,
627         0,
628         0,
629         0,
630         15,
631         0,
632         0,
633         FX_NONE, FX_NONE, FX_NONE, -1,
634         FX_NONE, FX_NONE, FX_NONE, -1,
635         FX_NONE, FX_NONE, FX_NONE, -1,
636         FX_NONE, FX_NONE, FX_NONE, -1,
637         FX_NONE, FX_NONE, FX_NONE, -1,
638         FX_NONE, FX_NONE, FX_NONE, -1,
639         FX_NONE, FX_NONE, FX_NONE, -1,
640         FX_NONE, FX_NONE, FX_NONE, -1,
641         FX_NONE, FX_NONE, FX_NONE, -1,
642         FX_NONE, FX_NONE, FX_NONE, -1,
643         FX_NONE, FX_NONE, FX_NONE, -1,
644         FX_NONE, FX_NONE, FX_NONE, -1,
645         FX_NONE, FX_NONE, FX_NONE, -1,
646         FX_NONE, FX_NONE, FX_NONE, -1,
647         FX_NONE, FX_NONE, FX_NONE, -1,
648     },
649 
650     // Vodoo 1.0 vector
651     {
652         kDamageSpirit,
653         25,
654         0,
655         0,
656         0,
657         0,
658         0,
659         0,
660         FX_NONE, FX_NONE, FX_NONE, -1,
661         FX_NONE, FX_NONE, FX_NONE, -1,
662         FX_NONE, FX_NONE, FX_NONE, -1,
663         FX_NONE, FX_NONE, FX_NONE, -1,
664         FX_NONE, FX_NONE, FX_NONE, -1,
665         FX_NONE, FX_NONE, FX_NONE, -1,
666         FX_NONE, FX_NONE, FX_NONE, -1,
667         FX_NONE, FX_NONE, FX_NONE, -1,
668         FX_NONE, FX_NONE, FX_NONE, -1,
669         FX_NONE, FX_NONE, FX_NONE, -1,
670         FX_NONE, FX_NONE, FX_NONE, -1,
671         FX_NONE, FX_NONE, FX_NONE, -1,
672         FX_NONE, FX_NONE, FX_NONE, -1,
673         FX_NONE, FX_NONE, FX_NONE, -1,
674         FX_NONE, FX_NONE, FX_NONE, -1,
675     },
676 
677     // 22 kVectorGenDudePunch
678     {
679     kDamageFall,
680         37,
681         874762,
682         620,
683         0,
684         0,
685         0,
686         0,
687         FX_NONE, FX_NONE, FX_NONE, -1,
688         FX_NONE, FX_NONE, FX_NONE, 357,
689         FX_NONE, FX_NONE, FX_NONE, 357,
690         FX_NONE, FX_NONE, FX_NONE, 357,
691         FX_NONE, FX_NONE, FX_NONE, 357,
692         FX_NONE, FX_NONE, FX_NONE, 357,
693         FX_NONE, FX_NONE, FX_NONE, 357,
694         FX_NONE, FX_NONE, FX_NONE, 357,
695         FX_NONE, FX_NONE, FX_NONE, 357,
696         FX_NONE, FX_NONE, FX_NONE, 357,
697         FX_NONE, FX_NONE, FX_NONE, 357,
698         FX_NONE, FX_NONE, FX_NONE, 357,
699         FX_NONE, FX_NONE, FX_NONE, 357,
700         FX_NONE, FX_NONE, FX_NONE, 357,
701         FX_NONE, FX_NONE, FX_NONE, 357,
702     },
703 };
704 
705 ITEMDATA gItemData[] = {
706     {
707         0,
708         2552,
709         (char)-8,
710         0,
711         32,
712         32,
713         -1,
714     },
715     {
716         0,
717         2553,
718         (char)-8,
719         0,
720         32,
721         32,
722         -1,
723     },
724     {
725         0,
726         2554,
727         (char)-8,
728         0,
729         32,
730         32,
731         -1,
732     },
733     {
734         0,
735         2555,
736         (char)-8,
737         0,
738         32,
739         32,
740         -1,
741     },
742     {
743         0,
744         2556,
745         (char)-8,
746         0,
747         32,
748         32,
749         -1,
750     },
751     {
752         0,
753         2557,
754         (char)-8,
755         0,
756         32,
757         32,
758         -1,
759     },
760     {
761         0,
762         2558,
763         (char)-8,
764         0,
765         32,
766         32,
767         -1,
768     },
769     {
770         0,
771         519,
772         (char)-8,
773         0,
774         48,
775         48,
776         0,
777     },
778     {
779         0,
780         822,
781         (char)-8,
782         0,
783         40,
784         40,
785         -1,
786     },
787     {
788         0,
789         2169,
790         (char)-8,
791         0,
792         40,
793         40,
794         -1,
795     },
796     {
797         0,
798         2433,
799         (char)-8,
800         0,
801         40,
802         40,
803         -1,
804     },
805     {
806         0,
807         517,
808         (char)-8,
809         0,
810         40,
811         40,
812         -1,
813     },
814     {
815         0,
816         783,
817         (char)-8,
818         0,
819         40,
820         40,
821         -1,
822     },
823     {
824         0,
825         896,
826         (char)-8,
827         0,
828         40,
829         40,
830         -1,
831     },
832     {
833         0,
834         825,
835         (char)-8,
836         0,
837         40,
838         40,
839         -1,
840     },
841     {
842         0,
843         827,
844         (char)-8,
845         0,
846         40,
847         40,
848         4,
849     },
850     {
851         0,
852         828,
853         (char)-8,
854         0,
855         40,
856         40,
857         -1,
858     },
859     {
860         0,
861         829,
862         (char)-8,
863         0,
864         40,
865         40,
866         -1,
867     },
868     {
869         0,
870         830,
871         (char)-8,
872         0,
873         80,
874         64,
875         1,
876     },
877     {
878         0,
879         831,
880         (char)-8,
881         0,
882         40,
883         40,
884         -1,
885     },
886     {
887         0,
888         863,
889         (char)-8,
890         0,
891         40,
892         40,
893         -1,
894     },
895     {
896         0,
897         760,
898         (char)-8,
899         0,
900         40,
901         40,
902         2,
903     },
904     {
905         0,
906         836,
907         (char)-8,
908         0,
909         40,
910         40,
911         -1,
912     },
913     {
914         0,
915         851,
916         (char)-8,
917         0,
918         40,
919         40,
920         -1,
921     },
922     {
923         0,
924         2428,
925         (char)-8,
926         0,
927         40,
928         40,
929         -1,
930     },
931     {
932         0,
933         839,
934         (char)-8,
935         0,
936         40,
937         40,
938         3,
939     },
940     {
941         0,
942         768,
943         (char)-8,
944         0,
945         64,
946         64,
947         -1,
948     },
949     {
950         0,
951         840,
952         (char)-8,
953         0,
954         48,
955         48,
956         -1,
957     },
958     {
959         0,
960         841,
961         (char)-8,
962         0,
963         48,
964         48,
965         -1,
966     },
967     {
968         0,
969         842,
970         (char)-8,
971         0,
972         48,
973         48,
974         -1,
975     },
976     {
977         0,
978         843,
979         (char)-8,
980         0,
981         48,
982         48,
983         -1,
984     },
985     {
986         0,
987         683,
988         (char)-8,
989         0,
990         40,
991         40,
992         -1,
993     },
994     {
995         0,
996         521,
997         (char)-8,
998         0,
999         40,
1000         40,
1001         -1,
1002     },
1003     {
1004         0,
1005         604,
1006         (char)-8,
1007         0,
1008         40,
1009         40,
1010         -1,
1011     },
1012     {
1013         0,
1014         520,
1015         (char)-8,
1016         0,
1017         40,
1018         40,
1019         -1,
1020     },
1021     {
1022         0,
1023         803,
1024         (char)-8,
1025         0,
1026         40,
1027         40,
1028         -1,
1029     },
1030     {
1031         0,
1032         518,
1033         (char)-8,
1034         0,
1035         40,
1036         40,
1037         -1,
1038     },
1039     {
1040         0,
1041         522,
1042         (char)-8,
1043         0,
1044         40,
1045         40,
1046         -1,
1047     },
1048     {
1049         0,
1050         523,
1051         (char)-8,
1052         0,
1053         40,
1054         40,
1055         -1,
1056     },
1057     {
1058         0,
1059         837,
1060         (char)-8,
1061         0,
1062         80,
1063         64,
1064         -1,
1065     },
1066     {
1067         0,
1068         2628,
1069         (char)-8,
1070         0,
1071         64,
1072         64,
1073         -1,
1074     },
1075     {
1076         0,
1077         2586,
1078         (char)-8,
1079         0,
1080         64,
1081         64,
1082         -1,
1083     },
1084     {
1085         0,
1086         2578,
1087         (char)-8,
1088         0,
1089         64,
1090         64,
1091         -1,
1092     },
1093     {
1094         0,
1095         2602,
1096         (char)-8,
1097         0,
1098         64,
1099         64,
1100         -1,
1101     },
1102     {
1103         0,
1104         2594,
1105         (char)-8,
1106         0,
1107         64,
1108         64,
1109         -1,
1110     },
1111     {
1112         0,
1113         753,
1114         (char)-8,
1115         0,
1116         64,
1117         64,
1118         -1,
1119     },
1120     {
1121         0,
1122         753,
1123         (char)-8,
1124         7,
1125         64,
1126         64,
1127         -1,
1128     },
1129     {
1130         0,
1131         3558,
1132         (char)-128,
1133         0,
1134         64,
1135         64,
1136         -1,
1137     },
1138     {
1139         0,
1140         3558,
1141         (char)-128,
1142         7,
1143         64,
1144         64,
1145         -1,
1146     }
1147 };
1148 
1149 AMMOITEMDATA gAmmoItemData[] = {
1150     {
1151         0,
1152         618,
1153         (char)-8,
1154         0,
1155         40,
1156         40,
1157         480,
1158         6,
1159         7
1160     },
1161     {
1162         0,
1163         589,
1164         (char)-8,
1165         0,
1166         48,
1167         48,
1168         1,
1169         5,
1170         6
1171     },
1172     {
1173         0,
1174         589,
1175         (char)-8,
1176         0,
1177         48,
1178         48,
1179         1,
1180         5,
1181         6
1182     },
1183     {
1184         0,
1185         809,
1186         (char)-8,
1187         0,
1188         48,
1189         48,
1190         5,
1191         5,
1192         6
1193     },
1194     {
1195         0,
1196         811,
1197         (char)-8,
1198         0,
1199         48,
1200         48,
1201         1,
1202         10,
1203         11
1204     },
1205     {
1206         0,
1207         810,
1208         (char)-8,
1209         0,
1210         48,
1211         48,
1212         1,
1213         11,
1214         12
1215     },
1216     {
1217         0,
1218         820,
1219         (char)-8,
1220         0,
1221         24,
1222         24,
1223         10,
1224         8,
1225         0
1226     },
1227     {
1228         0,
1229         619,
1230         (char)-8,
1231         0,
1232         48,
1233         48,
1234         4,
1235         2,
1236         0
1237     },
1238     {
1239         0,
1240         812,
1241         (char)-8,
1242         0,
1243         48,
1244         48,
1245         15,
1246         2,
1247         0
1248     },
1249     {
1250         0,
1251         813,
1252         (char)-8,
1253         0,
1254         48,
1255         48,
1256         15,
1257         3,
1258         0
1259     },
1260     {
1261         0,
1262         525,
1263         (char)-8,
1264         0,
1265         48,
1266         48,
1267         100,
1268         9,
1269         10
1270     },
1271     {
1272         0,
1273         814,
1274         (char)-8,
1275         0,
1276         48,
1277         48,
1278         15,
1279         255,
1280         0
1281     },
1282     {
1283         0,
1284         817,
1285         (char)-8,
1286         0,
1287         48,
1288         48,
1289         100,
1290         3,
1291         0
1292     },
1293     {
1294         0,
1295         548,
1296         (char)-8,
1297         0,
1298         24,
1299         24,
1300         32,
1301         7,
1302         0
1303     },
1304     {
1305         0,
1306         0,
1307         (char)-8,
1308         0,
1309         48,
1310         48,
1311         6,
1312         255,
1313         0
1314     },
1315     {
1316         0,
1317         0,
1318         (char)-8,
1319         0,
1320         48,
1321         48,
1322         6,
1323         255,
1324         0
1325     },
1326     {
1327         0,
1328         816,
1329         (char)-8,
1330         0,
1331         48,
1332         48,
1333         8,
1334         1,
1335         0
1336     },
1337     {
1338         0,
1339         818,
1340         (char)-8,
1341         0,
1342         48,
1343         48,
1344         8,
1345         255,
1346         0
1347     },
1348     {
1349         0,
1350         819,
1351         (char)-8,
1352         0,
1353         48,
1354         48,
1355         8,
1356         255,
1357         0
1358     },
1359     {
1360         0,
1361         801,
1362         (char)-8,
1363         0,
1364         48,
1365         48,
1366         6,
1367         4,
1368         0
1369     },
1370     {
1371         0,
1372         0,
1373         0,
1374         0,
1375         0,
1376         0,
1377         0,
1378         0,
1379         0
1380     },
1381 };
1382 
1383 WEAPONITEMDATA gWeaponItemData[] = {
1384     {
1385         0,
1386         -1,
1387         (char)0,
1388         0,
1389         0,
1390         0,
1391         0,
1392         -1,
1393         0
1394     },
1395     {
1396         0,
1397         559,
1398         (char)-8,
1399         0,
1400         48,
1401         48,
1402         3,
1403         2,
1404         8
1405     },
1406     {
1407         0,
1408         558,
1409         (char)-8,
1410         0,
1411         48,
1412         48,
1413         4,
1414         3,
1415         50
1416     },
1417     {
1418         0,
1419         524,
1420         (char)-8,
1421         0,
1422         48,
1423         48,
1424         2,
1425         1,
1426         9
1427     },
1428     {
1429         0,
1430         525,
1431         (char)-8,
1432         0,
1433         48,
1434         48,
1435         10,
1436         9,
1437         100
1438     },
1439     {
1440         0,
1441         539,
1442         (char)-8,
1443         0,
1444         48,
1445         48,
1446         8,
1447         7,
1448         64
1449     },
1450     {
1451         0,
1452         526,
1453         (char)-8,
1454         0,
1455         48,
1456         48,
1457         5,
1458         4,
1459         6
1460     },
1461     {
1462         0,
1463         -1,
1464         (char)0,
1465         0,
1466         0,
1467         0,
1468         1,
1469         -1,
1470         0
1471     },
1472     {
1473         0,
1474         618,
1475         (char)-8,
1476         0,
1477         48,
1478         48,
1479         7,
1480         6,
1481         480
1482     },
1483     {
1484         0,
1485         589,
1486         (char)-8,
1487         0,
1488         48,
1489         48,
1490         6,
1491         5,
1492         1
1493     },
1494     {
1495         0,
1496         800,
1497         (char)-8,
1498         0,
1499         48,
1500         48,
1501         9,
1502         8,
1503         35
1504     }
1505 };
1506 
1507 MissileType missileInfo[] = {
1508     // Cleaver
1509     {
1510         2138,
1511         978670,
1512         512,
1513         40,
1514         40,
1515         (char)-16,
1516         16,
1517     },
1518     // Regular flare
1519     {
1520         2424,
1521         3145728,
1522         0,
1523         32,
1524         32,
1525         (char)-128,
1526         32,
1527     },
1528     // Tesla alt
1529     {
1530         3056,
1531         2796202,
1532         0,
1533         32,
1534         32,
1535         (char)-128,
1536         32,
1537     },
1538     // Flare alt
1539     {
1540         2424,
1541         2446677,
1542         0,
1543         32,
1544         32,
1545         (char)-128,
1546         4,
1547     },
1548     // Spray flame
1549     {
1550         0,
1551         1118481,
1552         0,
1553         24,
1554         24,
1555         (char)-128,
1556         16,
1557     },
1558     // Fireball
1559     {
1560         0,
1561         1118481,
1562         0,
1563         32,
1564         32,
1565         (char)-128,
1566         32,
1567     },
1568     // Tesla regular
1569     {
1570         2130,
1571         2796202,
1572         0,
1573         32,
1574         32,
1575         (char)-128,
1576         16,
1577     },
1578     // EctoSkull
1579     {
1580         870,
1581         699050,
1582         0,
1583         32,
1584         32,
1585         (char)-24,
1586         32,
1587     },
1588     // Hellhound flame
1589     {
1590         0,
1591         1118481,
1592         0,
1593         24,
1594         24,
1595         (char)-128,
1596         16,
1597     },
1598     // Puke
1599     {
1600         0,
1601         838860,
1602         0,
1603         16,
1604         16,
1605         (char)-16,
1606         16,
1607     },
1608     // Reserved
1609     {
1610         0,
1611         838860,
1612         0,
1613         8,
1614         8,
1615         (char)0,
1616         16,
1617     },
1618     // Stone gargoyle projectile
1619     {
1620         3056,
1621         2097152,
1622         0,
1623         32,
1624         32,
1625         (char)-128,
1626         16,
1627     },
1628     // Napalm launcher
1629     {
1630         0,
1631         2446677,
1632         0,
1633         30,
1634         30,
1635         (char)-128,
1636         24,
1637     },
1638     // Cerberus fireball
1639     {
1640         0,
1641         2446677,
1642         0,
1643         30,
1644         30,
1645         (char)-128,
1646         24,
1647     },
1648     // Tchernobog fireball
1649     {
1650         0,
1651         1398101,
1652         0,
1653         24,
1654         24,
1655         (char)-128,
1656         16,
1657     },
1658     // Regular life leech
1659     {
1660         2446,
1661         2796202,
1662         0,
1663         32,
1664         32,
1665         (char)-128,
1666         16,
1667     },
1668     // Dropped life leech (enough ammo)
1669     {
1670         3056,
1671         2446677,
1672         0,
1673         16,
1674         16,
1675         (char)-128,
1676         16,
1677     },
1678     // Dropped life leech (no ammo)
1679     {
1680         3056,
1681         1747626,
1682         0,
1683         32,
1684         32,
1685         (char)-128,
1686         16,
1687     }
1688 };
1689 
1690 THINGINFO thingInfo[] = {
1691     //TNT Barrel
1692     {
1693         25,
1694         250,
1695         32,
1696         11,
1697         4096,
1698         80,
1699         384,
1700         907,
1701         (char)0,
1702         0,
1703         0,
1704         0,
1705         256, 256, 128, 64, 0, 0, 128,
1706     },
1707 
1708     // Armed Proxy Dynamite
1709     {
1710         5,
1711         5,
1712         16,
1713         3,
1714         24576,
1715         1600,
1716         256,
1717         3444,
1718         (char)-16,
1719         0,
1720         32,
1721         32,
1722         256, 256, 256, 64, 0, 0, 512,
1723     },
1724     // Armed Remote Dynamite
1725     {
1726         5,
1727         5,
1728         16,
1729         3,
1730         24576,
1731         1600,
1732         256,
1733         3457,
1734         (char)-16,
1735         0,
1736         32,
1737         32,
1738         256, 256, 256, 64, 0, 0, 512,
1739     },
1740     // Vase1
1741     {
1742         1,
1743         20,
1744         32,
1745         3,
1746         32768,
1747         80,
1748         0,
1749         739,
1750         (char)0,
1751         0,
1752         0,
1753         0,
1754         256, 0, 256, 128, 0, 0, 0,
1755     },
1756     // Vase2
1757     {
1758         1,
1759         150,
1760         32,
1761         3,
1762         32768,
1763         80,
1764         0,
1765         642,
1766         (char)0,
1767         0,
1768         0,
1769         0,
1770         256, 256, 256, 128, 0, 0, 0,
1771     },
1772     // Crate face
1773     {
1774         10,
1775         0,
1776         0,
1777         0,
1778         0,
1779         0,
1780         0,
1781         462,
1782         (char)0,
1783         0,
1784         0,
1785         0,
1786         0, 0, 0, 256, 0, 0, 0,
1787     },
1788     // Glass window
1789     {
1790         1,
1791         0,
1792         0,
1793         0,
1794         0,
1795         0,
1796         0,
1797         266,
1798         (char)0,
1799         0,
1800         0,
1801         0,
1802         256, 0, 256, 256, 0, 0, 0,
1803     },
1804     // Flourescent Light
1805     {
1806         1,
1807         0,
1808         0,
1809         0,
1810         0,
1811         0,
1812         0,
1813         796,
1814         (char)0,
1815         0,
1816         0,
1817         0,
1818         256, 0, 256, 256, 0, 0, 512,
1819     },
1820     // Wall Crack
1821     {
1822         50,
1823         0,
1824         0,
1825         0,
1826         0,
1827         0,
1828         0,
1829         1127,
1830         (char)0,
1831         0,
1832         0,
1833         0,
1834         0, 0, 0, 256, 0, 0, 0,
1835     },
1836     // Wood Beam
1837     {
1838         8,
1839         0,
1840         0,
1841         0,
1842         0,
1843         0,
1844         0,
1845         1142,
1846         (char)0,
1847         0,
1848         0,
1849         0,
1850         256, 0, 256, 128, 0, 0, 0,
1851     },
1852     // Spider's Web
1853     {
1854         4,
1855         0,
1856         0,
1857         0,
1858         0,
1859         0,
1860         0,
1861         1069,
1862         (char)0,
1863         0,
1864         0,
1865         0,
1866         256, 256, 64, 256, 0, 0, 128,
1867     },
1868     // Metal Grate
1869     {
1870         40,
1871         0,
1872         0,
1873         0,
1874         0,
1875         0,
1876         0,
1877         483,
1878         (char)0,
1879         0,
1880         0,
1881         0,
1882         64, 0, 128, 256, 0, 0, 0,
1883     },
1884     // Flammable Tree
1885     {
1886         1,
1887         0,
1888         0,
1889         0,
1890         0,
1891         0,
1892         0,
1893         -1,
1894         (char)0,
1895         0,
1896         0,
1897         0,
1898         0, 256, 0, 256, 0, 0, 128,
1899     },
1900     // MachineGun Trap
1901     {
1902         1000,
1903         0,
1904         0,
1905         8,
1906         0,
1907         0,
1908         0,
1909         -1,
1910         (char)0,
1911         0,
1912         0,
1913         0,
1914         0, 0, 128, 256, 0, 0, 512,
1915     },
1916     // Falling Rock
1917     {
1918         0,
1919         15,
1920         8,
1921         3,
1922         32768,
1923         0,
1924         0,
1925         -1,
1926         (char)0,
1927         0,
1928         0,
1929         0,
1930         0, 0, 0, 0, 0, 0, 0,
1931     },
1932     // Kickable Pail
1933     {
1934         0,
1935         8,
1936         48,
1937         3,
1938         49152,
1939         0,
1940         0,
1941         -1,
1942         (char)0,
1943         0,
1944         0,
1945         0,
1946         0, 0, 0, 0, 0, 0, 0,
1947     },
1948     // Gib Object
1949     {
1950         10,
1951         2,
1952         0,
1953         0,
1954         32768,
1955         0,
1956         0,
1957         -1,
1958         (char)0,
1959         0,
1960         0,
1961         0,
1962         256, 0, 256, 256, 0, 0, 128,
1963     },
1964     // Explode Object
1965     {
1966         20,
1967         2,
1968         0,
1969         0,
1970         32768,
1971         0,
1972         0,
1973         -1,
1974         (char)0,
1975         0,
1976         0,
1977         0,
1978         0, 0, 0, 256, 0, 0, 128,
1979     },
1980     // Armed stick Of TNT
1981     {
1982         5,
1983         14,
1984         16,
1985         3,
1986         24576,
1987         1600,
1988         256,
1989         3422,
1990         (char)-32,
1991         0,
1992         32,
1993         32,
1994         64, 256, 128, 64, 0, 0, 256,
1995     },
1996     // Armed bundle Of TNT
1997     {
1998         5,
1999         14,
2000         16,
2001         3,
2002         24576,
2003         1600,
2004         256,
2005         3433,
2006         (char)-32,
2007         0,
2008         32,
2009         32,
2010         64, 256, 128, 64, 0, 0, 256,
2011     },
2012     // Armed aerosol
2013     {
2014         5,
2015         14,
2016         16,
2017         3,
2018         32768,
2019         1600,
2020         256,
2021         3467,
2022         (char)-128,
2023         0,
2024         32,
2025         32,
2026         64, 256, 128, 64, 0, 0, 256,
2027     },
2028     // Bone (Flesh Garg.)
2029     {
2030         5,
2031         6,
2032         16,
2033         3,
2034         32768,
2035         1600,
2036         256,
2037         1462,
2038         (char)0,
2039         0,
2040         32,
2041         32,
2042         0, 0, 0, 0, 0, 0, 0,
2043     },
2044     // Some alpha stuff
2045     {
2046         8,
2047         3,
2048         16,
2049         11,
2050         32768,
2051         1600,
2052         256,
2053         -1,
2054         (char)0,
2055         0,
2056         0,
2057         0,
2058         256, 0, 256, 256, 0, 0, 0,
2059     },
2060     // WaterDrip
2061     {
2062         0,
2063         1,
2064         1,
2065         2,
2066         0,
2067         0,
2068         0,
2069         1147,
2070         (char)0,
2071         10,
2072         0,
2073         0,
2074         0, 0, 0, 0, 0, 0, 0,
2075     },
2076     // BloodDrip
2077     {
2078         0,
2079         1,
2080         1,
2081         2,
2082         0,
2083         0,
2084         0,
2085         1160,
2086         (char)0,
2087         2,
2088         0,
2089         0,
2090         0, 0, 0, 0, 0, 0, 0,
2091     },
2092     // Blood chucks1
2093     {
2094         15,
2095         4,
2096         4,
2097         3,
2098         24576,
2099         0,
2100         257,
2101         -1,
2102         (char)0,
2103         0,
2104         0,
2105         0,
2106         128, 64, 256, 256, 0, 0, 256,
2107     },
2108     // Blood chucks2
2109     {
2110         30,
2111         30,
2112         8,
2113         3,
2114         8192,
2115         0,
2116         257,
2117         -1,
2118         (char)0,
2119         0,
2120         0,
2121         0,
2122         128, 64, 256, 256, 0, 0, 64,
2123     },
2124     // Axe Zombie Head
2125     {
2126         60,
2127         5,
2128         32,
2129         3,
2130         40960,
2131         1280,
2132         257,
2133         3405,
2134         (char)0,
2135         0,
2136         40,
2137         40,
2138         128, 64, 256, 256, 0, 0, 64,
2139     },
2140     // Napalm's Alt Fire explosion
2141     {
2142         80,
2143         30,
2144         32,
2145         3,
2146         57344,
2147         1600,
2148         256,
2149         3281,
2150         (char)-128,
2151         0,
2152         32,
2153         32,
2154         0, 0, 0, 0, 0, 0, 0,
2155     },
2156     // Fire Pod Explosion
2157     {
2158         80,
2159         30,
2160         32,
2161         3,
2162         57344,
2163         1600,
2164         256,
2165         2020,
2166         (char)-128,
2167         0,
2168         32,
2169         32,
2170         256, 0, 256, 256, 0, 0, 0,
2171     },
2172     // Green Pod Explosion
2173     {
2174         80,
2175         30,
2176         32,
2177         3,
2178         57344,
2179         1600,
2180         256,
2181         1860,
2182         (char)-128,
2183         0,
2184         32,
2185         32,
2186         256, 0, 256, 256, 0, 0, 0,
2187     },
2188     // Life Leech
2189     {
2190         150,
2191         30,
2192         48,
2193         3,
2194         32768,
2195         1600,
2196         257,
2197         800,
2198         (char)-128,
2199         0,
2200         48,
2201         48,
2202         64, 64, 112, 64, 0, 96, 96,
2203     },
2204     // Voodoo Head
2205     {
2206         1,
2207         30,
2208         48,
2209         3,
2210         32768,
2211         1600,
2212         0,
2213         2443,
2214         (char)-128,
2215         0,
2216         16,
2217         16,
2218         0, 0, 0, 0, 0, 0, 0,
2219     },
2220     // 433 - kModernThingTNTProx
2221     {
2222         5,
2223         5,
2224         16,
2225         3,
2226         24576,
2227         1600,
2228         256,
2229         3444,
2230         (char)-16,
2231         7,
2232         32,
2233         32,
2234         256, 256, 256, 64, 0, 0, 512,
2235     },
2236     // 434 - kModernThingThrowableRock
2237     {
2238         5,
2239         6,
2240         16,
2241         3,
2242         32768,
2243         1600,
2244         256,
2245         1462,
2246         (char)0,
2247         0,
2248         32,
2249         32,
2250         0, 0, 0, 0, 0, 0, 0,
2251     },
2252     // 435 - kModernThingEnemyLifeLeech
2253     {
2254         150,
2255         30,
2256         48,
2257         3,
2258         32768,
2259         1600,
2260         257,
2261         800,
2262         (char)-128,
2263         0,
2264         44,
2265         44,
2266         0, 1024, 512, 1024, 0, 64, 512,
2267     },
2268 };
2269 
2270 EXPLOSION explodeInfo[] = {
2271     {
2272         40,
2273         10,
2274         10,
2275         75,
2276         450,
2277         0,
2278         60,
2279         80,
2280         40
2281     },
2282     {
2283         80,
2284         20,
2285         10,
2286         150,
2287         900,
2288         0,
2289         60,
2290         160,
2291         60
2292     },
2293     {
2294         120,
2295         40,
2296         15,
2297         225,
2298         1350,
2299         0,
2300         60,
2301         240,
2302         80
2303     },
2304     {
2305         80,
2306         5,
2307         10,
2308         120,
2309         20,
2310         10,
2311         60,
2312         0,
2313         40
2314     },
2315     {
2316         120,
2317         10,
2318         10,
2319         180,
2320         40,
2321         10,
2322         60,
2323         0,
2324         80
2325     },
2326     {
2327         160,
2328         15,
2329         10,
2330         240,
2331         60,
2332         10,
2333         60,
2334         0,
2335         120
2336     },
2337     {
2338         40,
2339         20,
2340         10,
2341         120,
2342         0,
2343         10,
2344         30,
2345         60,
2346         40
2347     },
2348     {
2349         80,
2350         20,
2351         10,
2352         150,
2353         800,
2354         5,
2355         60,
2356         160,
2357         60
2358     },
2359 };
2360 
2361 int gDudeDrag = 0x2a00;
2362 
2363 short gAffectedSectors[kMaxSectors];
2364 short gAffectedXWalls[kMaxXWalls];
2365 short gPlayerGibThingComments[] = {
2366     734, 735, 736, 737, 738, 739, 740, 741, 3038, 3049
2367 };
2368 
2369 void FireballSeqCallback(int, int);
2370 void sub_38938(int, int);
2371 void NapalmSeqCallback(int, int);
2372 void sub_3888C(int, int);
2373 void TreeToGibCallback(int, int);
2374 void DudeToGibCallback1(int, int);
2375 void DudeToGibCallback2(int, int);
2376 
2377 int nFireballClient = seqRegisterClient(FireballSeqCallback);
2378 int dword_2192D8 = seqRegisterClient(sub_38938); // fireball smoke
2379 int nNapalmClient = seqRegisterClient(NapalmSeqCallback);
2380 int dword_2192E0 = seqRegisterClient(sub_3888C); // flame lick
2381 int nTreeToGibClient = seqRegisterClient(TreeToGibCallback);
2382 int nDudeToGibClient1 = seqRegisterClient(DudeToGibCallback1);
2383 int nDudeToGibClient2 = seqRegisterClient(DudeToGibCallback2);
2384 
2385 int gPostCount = 0;
2386 
2387 struct POSTPONE {
2388     short at0;
2389     short at2;
2390 };
2391 
2392 POSTPONE gPost[kMaxSprites];
2393 
IsUnderwaterSector(int nSector)2394 bool IsUnderwaterSector(int nSector)
2395 {
2396     int nXSector = sector[nSector].extra;
2397     if (nXSector > 0 && xsector[nXSector].Underwater)
2398         return 1;
2399     return 0;
2400 }
2401 
actSpriteOwnerToSpriteId(spritetype * pSprite)2402 int actSpriteOwnerToSpriteId(spritetype *pSprite)
2403 {
2404     dassert(pSprite != NULL);
2405     if (pSprite->owner == -1)
2406         return -1;
2407     int nSprite = pSprite->owner & (kMaxSprites-1);
2408     if (pSprite->owner & kMaxSprites)
2409         nSprite = gPlayer[nSprite].pSprite->index;
2410     return nSprite;
2411 }
2412 
actPropagateSpriteOwner(spritetype * pTarget,spritetype * pSource)2413 void actPropagateSpriteOwner(spritetype *pTarget, spritetype *pSource)
2414 {
2415     dassert(pTarget != NULL && pSource != NULL);
2416     if (IsPlayerSprite(pSource))
2417         pTarget->owner = (pSource->type - kDudePlayer1) | kMaxSprites;
2418     else
2419         pTarget->owner = pSource->index;
2420 }
2421 
actSpriteIdToOwnerId(int nSprite)2422 int actSpriteIdToOwnerId(int nSprite)
2423 {
2424     if (nSprite == -1)
2425         return -1;
2426     dassert(nSprite >= 0 && nSprite < kMaxSprites);
2427     spritetype *pSprite = &sprite[nSprite];
2428     if (IsPlayerSprite(pSprite))
2429         nSprite = (pSprite->type - kDudePlayer1) | kMaxSprites;
2430     return nSprite;
2431 }
2432 
actOwnerIdToSpriteId(int nSprite)2433 int actOwnerIdToSpriteId(int nSprite)
2434 {
2435     if (nSprite == -1)
2436         return -1;
2437     if (nSprite & kMaxSprites)
2438         nSprite = gPlayer[nSprite&(kMaxSprites-1)].pSprite->index;
2439     return nSprite;
2440 }
2441 
actTypeInSector(int nSector,int nType)2442 bool actTypeInSector(int nSector, int nType)
2443 {
2444     for (int nSprite = headspritesect[nSector]; nSprite >= 0; nSprite = nextspritestat[nSprite])
2445     {
2446         if (sprite[nSprite].index == nType)
2447             return 1;
2448     }
2449     return 0;
2450 }
2451 
actAllocateSpares(void)2452 void actAllocateSpares(void)
2453 {
2454 }
2455 
2456 int DudeDifficulty[5] = {
2457     512, 384, 256, 208, 160
2458 };
2459 
actInit(bool bSaveLoad)2460 void actInit(bool bSaveLoad) {
2461 
2462     #ifdef NOONE_EXTENSIONS
2463     if (!gModernMap) {
2464         initprintf("> This map *does not* provide modern features.\n");
2465         nnExtResetGlobals();
2466     } else {
2467         initprintf("> This map provides modern features.\n");
2468         nnExtInitModernStuff(bSaveLoad);
2469     }
2470     #endif
2471 
2472     for (int nSprite = headspritestat[kStatItem]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
2473         switch (sprite[nSprite].type) {
2474             case kItemWeaponVoodooDoll:
2475                 sprite[nSprite].type = kAmmoItemVoodooDoll;
2476                 break;
2477         }
2478     }
2479 
2480     for (int nSprite = headspritestat[kStatTraps]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
2481         spritetype *pSprite = &sprite[nSprite];
2482         switch (pSprite->type) {
2483             case kTrapExploder:
2484                 pSprite->cstat &= ~1; pSprite->cstat |= CSTAT_SPRITE_INVISIBLE;
2485                 if (pSprite->extra <= 0 || pSprite->extra >= kMaxXSprites) continue;
2486                 xsprite[pSprite->extra].waitTime = ClipLow(xsprite[pSprite->extra].waitTime, 1);
2487                 xsprite[pSprite->extra].state = 0;
2488                 break;
2489         }
2490     }
2491 
2492     for (int nSprite = headspritestat[kStatThing]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
2493         if (sprite[nSprite].extra <= 0 || sprite[nSprite].extra >= kMaxXSprites) continue;
2494         spritetype* pSprite = &sprite[nSprite]; XSPRITE *pXSprite = &xsprite[pSprite->extra];
2495 
2496         int nType = pSprite->type - kThingBase;
2497         pXSprite->health = thingInfo[nType].startHealth << 4;
2498         #ifdef NOONE_EXTENSIONS
2499             // allow level designer to set custom clipdist.
2500             // this is especially useful for various Gib and Explode objects which have clipdist 1 for some reason predefined,
2501             // but what if it have voxel model...?
2502             if (!gModernMap)
2503         #endif
2504             pSprite->clipdist = thingInfo[nType].clipdist;
2505 
2506         pSprite->flags = thingInfo[nType].flags;
2507         if (pSprite->flags & kPhysGravity) pSprite->flags |= kPhysFalling;
2508         xvel[nSprite] = yvel[nSprite] = zvel[nSprite] = 0;
2509 
2510         switch (pSprite->type) {
2511             case kThingArmedProxBomb:
2512             case kTrapMachinegun:
2513             #ifdef NOONE_EXTENSIONS
2514             case kModernThingTNTProx:
2515             #endif
2516                 pXSprite->state = 0;
2517                 break;
2518             case kThingBloodChunks: {
2519                 SEQINST *pInst = GetInstance(3, pSprite->extra);
2520                 if (pInst && pInst->isPlaying) {
2521                     DICTNODE *hSeq = gSysRes.Lookup(pInst->nSeq, "SEQ");
2522                     if (!hSeq) break;
2523                     seqSpawn(pInst->nSeq, 3, pSprite->extra);
2524                 }
2525                 break;
2526             }
2527             default:
2528                 pXSprite->state = 1;
2529                 break;
2530         }
2531     }
2532 
2533     if (gGameOptions.nMonsterSettings == 0) {
2534         gKillMgr.SetCount(0);
2535         while (headspritestat[kStatDude] >= 0) {
2536             spritetype *pSprite = &sprite[headspritestat[kStatDude]];
2537             if (pSprite->extra > 0 && pSprite->extra < kMaxXSprites && xsprite[pSprite->extra].key > 0) // Drop Key
2538                 actDropObject(pSprite, kItemKeyBase + (xsprite[pSprite->extra].key - 1));
2539             DeleteSprite(headspritestat[kStatDude]);
2540         }
2541     } else {
2542         // by NoOne: WTF is this?
2543         ///////////////
2544         char unk[kDudeMax-kDudeBase];
2545         memset(unk, 0, sizeof(unk));
2546         for (int nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
2547             spritetype *pSprite = &sprite[nSprite];
2548             if (pSprite->type < kDudeBase || pSprite->type >= kDudeMax)
2549                 ThrowError("Non-enemy sprite (%d) in the enemy sprite list.\n", nSprite);
2550             unk[pSprite->type - kDudeBase] = 1;
2551         }
2552 
2553         gKillMgr.sub_2641C();
2554         ///////////////
2555 
2556         for (int i = 0; i < kDudeMax - kDudeBase; i++)
2557             for (int j = 0; j < 7; j++)
2558                 dudeInfo[i].at70[j] = mulscale8(DudeDifficulty[gGameOptions.nDifficulty], dudeInfo[i].startDamage[j]);
2559 
2560         for (int nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
2561             if (sprite[nSprite].extra <= 0 || sprite[nSprite].extra >= kMaxXSprites) continue;
2562             spritetype *pSprite = &sprite[nSprite]; XSPRITE *pXSprite = &xsprite[pSprite->extra];
2563 
2564             int nType = pSprite->type - kDudeBase; int seqStartId = dudeInfo[nType].seqStartID;
2565             if (!IsPlayerSprite(pSprite)) {
2566                 #ifdef NOONE_EXTENSIONS
2567                     switch (pSprite->type) {
2568                         case kDudeModernCustom:
2569                         case kDudeModernCustomBurning:
2570                             pSprite->cstat |= 4096 + CSTAT_SPRITE_BLOCK_HITSCAN + CSTAT_SPRITE_BLOCK;
2571                             seqStartId = genDudeSeqStartId(pXSprite); //  Custom Dude stores it's SEQ in data2
2572                             pXSprite->sysData1 = pXSprite->data3; // move sndStartId to sysData1, because data3 used by the game;
2573                             pXSprite->data3 = 0;
2574                             break;
2575                         case kDudePodMother:  // FakeDude type (no seq, custom flags, clipdist and cstat)
2576                             if (gModernMap) break;
2577                             fallthrough__;
2578                         default:
2579                             pSprite->clipdist = dudeInfo[nType].clipdist;
2580                             pSprite->cstat |= 4096 + CSTAT_SPRITE_BLOCK_HITSCAN + CSTAT_SPRITE_BLOCK;
2581                             break;
2582                     }
2583                 #else
2584                     pSprite->clipdist = dudeInfo[nType].clipdist;
2585                     pSprite->cstat |= 4096 + CSTAT_SPRITE_BLOCK_HITSCAN + CSTAT_SPRITE_BLOCK;
2586                 #endif
2587 
2588                 xvel[nSprite] = yvel[nSprite] = zvel[nSprite] = 0;
2589 
2590                 #ifdef NOONE_EXTENSIONS
2591                     // add a way to set custom hp for every enemy - should work only if map just started and not loaded.
2592                     if (!gModernMap || pXSprite->sysData2 <= 0) pXSprite->health = dudeInfo[nType].startHealth << 4;
2593                     else pXSprite->health = ClipRange(pXSprite->sysData2 << 4, 1, 65535);
2594                 #else
2595                     pXSprite->health = dudeInfo[nType].startHealth << 4;
2596                 #endif
2597 
2598             }
2599 
2600             if (gSysRes.Lookup(seqStartId, "SEQ")) seqSpawn(seqStartId, 3, pSprite->extra);
2601         }
2602         aiInit();
2603     }
2604 }
2605 
ConcussSprite(int a1,spritetype * pSprite,int x,int y,int z,int a6)2606 void ConcussSprite(int a1, spritetype *pSprite, int x, int y, int z, int a6)
2607 {
2608     dassert(pSprite != NULL);
2609     int dx = pSprite->x-x;
2610     int dy = pSprite->y-y;
2611     int dz = (pSprite->z-z)>>4;
2612     int dist2 = 0x40000+dx*dx+dy*dy+dz*dz;
2613     dassert(dist2 > 0);
2614     a6 = scale(0x40000, a6, dist2);
2615 
2616     if (pSprite->flags & kPhysMove) {
2617         int mass = 0;
2618         if (IsDudeSprite(pSprite)) {
2619 
2620             mass = getDudeInfo(pSprite->type)->mass;
2621             #ifdef NOONE_EXTENSIONS
2622                 switch (pSprite->type) {
2623                 case kDudeModernCustom:
2624                 case kDudeModernCustomBurning:
2625                     mass = getSpriteMassBySize(pSprite);
2626                     break;
2627                 }
2628             #endif
2629 
2630         } else if (pSprite->type >= kThingBase && pSprite->type < kThingMax) {
2631             mass = thingInfo[pSprite->type - kThingBase].mass;
2632         } else {
2633             consoleSysMsg("Unexpected type in ConcussSprite(): Sprite: %d  Type: %d  Stat: %d", (int)pSprite->index, (int)pSprite->type, (int)pSprite->statnum);
2634             return;
2635         }
2636 
2637         int size = (tilesiz[pSprite->picnum].x*pSprite->xrepeat*tilesiz[pSprite->picnum].y*pSprite->yrepeat)>>1;
2638         dassert(mass > 0);
2639 
2640         int t = scale(a6, size, mass);
2641         dx = mulscale16(t, dx);
2642         dy = mulscale16(t, dy);
2643         dz = mulscale16(t, dz);
2644         int nSprite = pSprite->index;
2645         dassert(nSprite >= 0 && nSprite < kMaxSprites);
2646         xvel[nSprite] += dx;
2647         yvel[nSprite] += dy;
2648         zvel[nSprite] += dz;
2649     }
2650 
2651     actDamageSprite(a1, pSprite, kDamageExplode, a6);
2652 }
2653 
actWallBounceVector(int * x,int * y,int nWall,int a4)2654 int actWallBounceVector(int *x, int *y, int nWall, int a4)
2655 {
2656     int wx, wy;
2657     GetWallNormal(nWall, &wx, &wy);
2658     int t = dmulscale16(*x, wx, *y, wy);
2659     int t2 = mulscale16r(t, a4+0x10000);
2660     *x -= mulscale16(wx, t2);
2661     *y -= mulscale16(wy, t2);
2662     return mulscale16r(t, 0x10000-a4);
2663 }
2664 
actFloorBounceVector(int * x,int * y,int * z,int nSector,int a5)2665 int actFloorBounceVector(int *x, int *y, int *z, int nSector, int a5)
2666 {
2667     int t = 0x10000-a5;
2668     if (sector[nSector].floorheinum == 0)
2669     {
2670         int t2 = mulscale16(*z, t);
2671         *z = -(*z-t2);
2672         return t2;
2673     }
2674     walltype *pWall = &wall[sector[nSector].wallptr];
2675     walltype *pWall2 = &wall[pWall->point2];
2676     int angle = getangle(pWall2->x-pWall->x, pWall2->y-pWall->y)+512;
2677     int t2 = sector[nSector].floorheinum<<4;
2678     int t3 = approxDist(-0x10000, t2);
2679     int t4 = divscale16(-0x10000, t3);
2680     int t5 = divscale16(t2, t3);
2681     int t6 = mulscale30(t5, Cos(angle));
2682     int t7 = mulscale30(t5, Sin(angle));
2683     int t8 = tmulscale16(*x, t6, *y, t7, *z, t4);
2684     int t9 = mulscale16(t8, 0x10000+a5);
2685     *x -= mulscale16(t6, t9);
2686     *y -= mulscale16(t7, t9);
2687     *z -= mulscale16(t4, t9);
2688     return mulscale16r(t8, t);
2689 }
2690 
sub_2A620(int nSprite,int x,int y,int z,int nSector,int nDist,int a7,int a8,DAMAGE_TYPE a9,int a10,int a11,int a12,int a13)2691 void sub_2A620(int nSprite, int x, int y, int z, int nSector, int nDist, int a7, int a8, DAMAGE_TYPE a9, int a10, int a11, int a12, int a13)
2692 {
2693     UNREFERENCED_PARAMETER(a12);
2694     UNREFERENCED_PARAMETER(a13);
2695     char va0[(kMaxSectors+7)>>3];
2696     int nOwner = actSpriteIdToOwnerId(nSprite);
2697     gAffectedSectors[0] = 0;
2698     gAffectedXWalls[0] = 0;
2699     GetClosestSpriteSectors(nSector, x, y, nDist, gAffectedSectors, va0, gAffectedXWalls);
2700     nDist <<= 4;
2701     if (a10 & 2)
2702     {
2703         for (int i = headspritestat[kStatDude]; i >= 0; i = nextspritestat[i])
2704         {
2705             if (i != nSprite || (a10 & 1))
2706             {
2707                 spritetype *pSprite2 = &sprite[i];
2708                 if (pSprite2->extra > 0 && pSprite2->extra < kMaxXSprites)
2709                 {
2710 
2711                     if (pSprite2->flags & 0x20)
2712                         continue;
2713                     if (!TestBitString(va0, pSprite2->sectnum))
2714                         continue;
2715                     if (!CheckProximity(pSprite2, x, y, z, nSector, nDist))
2716                         continue;
2717                     int dx = klabs(x-pSprite2->x);
2718                     int dy = klabs(y-pSprite2->y);
2719                     int dz = klabs(z-pSprite2->z)>>4;
2720                     int dist = ksqrt(dx*dx+dy*dy+dz*dz);
2721                     if (dist > nDist)
2722                         continue;
2723                     int vcx;
2724                     if (dist != 0)
2725                         vcx = a7+((nDist-dist)*a8)/nDist;
2726                     else
2727                         vcx = a7+a8;
2728                     actDamageSprite(nSprite, pSprite2, a9, vcx<<4);
2729                     if (a11)
2730                         actBurnSprite(nOwner, &xsprite[pSprite2->extra], a11);
2731                 }
2732             }
2733         }
2734     }
2735     if (a10 & 4)
2736     {
2737         for (int i = headspritestat[kStatThing]; i >= 0; i = nextspritestat[i])
2738         {
2739             spritetype *pSprite2 = &sprite[i];
2740 
2741             if (pSprite2->flags&0x20)
2742                 continue;
2743             if (!TestBitString(va0, pSprite2->sectnum))
2744                 continue;
2745             if (!CheckProximity(pSprite2, x, y, z, nSector, nDist))
2746                 continue;
2747             XSPRITE *pXSprite2 = &xsprite[pSprite2->extra];
2748             if (pXSprite2->locked)
2749                 continue;
2750             int dx = klabs(x-pSprite2->x);
2751             int dy = klabs(y-pSprite2->y);
2752             int dist = ksqrt(dx*dx+dy*dy);
2753             if (dist > nDist)
2754                 continue;
2755             int vcx;
2756             if (dist != 0)
2757                 vcx = a7+((nDist-dist)*a8)/nDist;
2758             else
2759                 vcx = a7+a8;
2760             actDamageSprite(nSprite, pSprite2, a9, vcx<<4);
2761             if (a11)
2762                 actBurnSprite(nOwner, pXSprite2, a11);
2763         }
2764     }
2765 }
2766 
sub_2AA94(spritetype * pSprite,XSPRITE * pXSprite)2767 void sub_2AA94(spritetype *pSprite, XSPRITE *pXSprite)
2768 {
2769     int nSprite = actOwnerIdToSpriteId(pSprite->owner);
2770     actPostSprite(pSprite->index, kStatDecoration);
2771     seqSpawn(9, 3, pSprite->extra);
2772     if (Chance(0x8000))
2773         pSprite->cstat |= 4;
2774 
2775     sfxPlay3DSound(pSprite, 303, 24+(pSprite->flags&3), 1);
2776     sub_2A620(nSprite, pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum, 128, 0, 60, kDamageExplode, 15, 120, 0, 0);
2777     if (pXSprite->data4 > 1)
2778     {
2779         GibSprite(pSprite, GIBTYPE_5, NULL, NULL);
2780         int v14[2];
2781         v14[0] = pXSprite->data4>>1;
2782         v14[1] = pXSprite->data4-v14[0];
2783         int v4 = pSprite->ang;
2784         xvel[pSprite->index] = 0;
2785         yvel[pSprite->index] = 0;
2786         zvel[pSprite->index] = 0;
2787         for (int i = 0; i < 2; i++)
2788         {
2789             int t1 = Random(0x33333)+0x33333;
2790             int t2 = Random2(0x71);
2791             pSprite->ang = (t2+v4+2048)&2047;
2792             spritetype *pSprite2 = actFireThing(pSprite, 0, 0, -0x93d0, kThingNapalmBall, t1);
2793             XSPRITE *pXSprite2 = &xsprite[pSprite2->extra];
2794             pSprite2->owner = pSprite->owner;
2795             seqSpawn(61, 3, pSprite2->extra, nNapalmClient);
2796             pXSprite2->data4 = v14[i];
2797         }
2798     }
2799 }
2800 
actSpawnFloor(spritetype * pSprite)2801 spritetype *actSpawnFloor(spritetype *pSprite)
2802 {
2803     short nSector = pSprite->sectnum;
2804     int x = pSprite->x;
2805     int y = pSprite->y;
2806     updatesector(x, y, &nSector);
2807     int zFloor = getflorzofslope(nSector, x, y);
2808     spritetype *pSprite2 = actSpawnSprite(nSector, x, y, zFloor, 3, 0);
2809     if (pSprite2)
2810         pSprite2->cstat &= ~257;
2811     return pSprite2;
2812 }
2813 
actDropAmmo(spritetype * pSprite,int nType)2814 spritetype *actDropAmmo(spritetype *pSprite, int nType)
2815 {
2816     spritetype *pSprite2 = NULL;
2817     if (pSprite && pSprite->statnum < kMaxStatus && nType >= kItemAmmoBase && nType < kItemAmmoMax)
2818     {
2819         pSprite2 = actSpawnFloor(pSprite);
2820         AMMOITEMDATA *pAmmo = &gAmmoItemData[nType - kItemAmmoBase];
2821         pSprite2->type = nType;
2822         pSprite2->picnum = pAmmo->picnum;
2823         pSprite2->shade = pAmmo->shade;
2824         pSprite2->xrepeat = pAmmo->xrepeat;
2825         pSprite2->yrepeat = pAmmo->yrepeat;
2826     }
2827     return pSprite2;
2828 }
2829 
actDropWeapon(spritetype * pSprite,int nType)2830 spritetype *actDropWeapon(spritetype *pSprite, int nType)
2831 {
2832     spritetype *pSprite2 = NULL;
2833     if (pSprite && pSprite->statnum < kMaxStatus && nType >= kItemWeaponBase && nType < kItemWeaponMax)
2834     {
2835         pSprite2 = actSpawnFloor(pSprite);
2836         WEAPONITEMDATA *pWeapon = &gWeaponItemData[nType - kItemWeaponBase];
2837         pSprite2->type = nType;
2838         pSprite2->picnum = pWeapon->picnum;
2839         pSprite2->shade = pWeapon->shade;
2840         pSprite2->xrepeat = pWeapon->xrepeat;
2841         pSprite2->yrepeat = pWeapon->yrepeat;
2842     }
2843     return pSprite2;
2844 }
2845 
actDropItem(spritetype * pSprite,int nType)2846 spritetype *actDropItem(spritetype *pSprite, int nType)
2847 {
2848     spritetype *pSprite2 = NULL;
2849     if (pSprite && pSprite->statnum < kMaxStatus && nType >= kItemBase && nType < kItemMax)
2850     {
2851         pSprite2 = actSpawnFloor(pSprite);
2852         ITEMDATA *pItem = &gItemData[nType - kItemBase];
2853         pSprite2->type = nType;
2854         pSprite2->picnum = pItem->picnum;
2855         pSprite2->shade = pItem->shade;
2856         pSprite2->xrepeat = pItem->xrepeat;
2857         pSprite2->yrepeat = pItem->yrepeat;
2858     }
2859     return pSprite2;
2860 }
2861 
actDropKey(spritetype * pSprite,int nType)2862 spritetype *actDropKey(spritetype *pSprite, int nType)
2863 {
2864     spritetype *pSprite2 = NULL;
2865     if (pSprite && pSprite->statnum < kMaxStatus && nType >= kItemKeyBase && nType < kItemKeyMax)
2866     {
2867         pSprite2 = actDropItem(pSprite, nType);
2868         if (pSprite2 && gGameOptions.nGameType == 1)
2869         {
2870             if (pSprite2->extra == -1)
2871                 dbInsertXSprite(pSprite2->index);
2872             xsprite[pSprite2->extra].respawn = 3;
2873             gSpriteHit[pSprite2->extra].florhit = 0;
2874             gSpriteHit[pSprite2->extra].ceilhit = 0;
2875         }
2876     }
2877     return pSprite2;
2878 }
2879 
actDropFlag(spritetype * pSprite,int nType)2880 spritetype *actDropFlag(spritetype *pSprite, int nType)
2881 {
2882     spritetype *pSprite2 = NULL;
2883     if (pSprite && pSprite->statnum < kMaxStatus && (nType == 147 || nType == 148))
2884     {
2885         pSprite2 = actDropItem(pSprite, nType);
2886         if (pSprite2 && gGameOptions.nGameType == 3)
2887         {
2888             evPost(pSprite2->index, 3, 1800, kCallbackReturnFlag);
2889         }
2890     }
2891     return pSprite2;
2892 }
2893 
actDropObject(spritetype * pSprite,int nType)2894 spritetype *actDropObject(spritetype *pSprite, int nType) {
2895     spritetype *pSprite2 = NULL;
2896 
2897     if (nType >= kItemKeyBase && nType < kItemKeyMax) pSprite2 = actDropKey(pSprite, nType);
2898     else if (nType == kItemFlagA || nType == kItemFlagB) pSprite2 = actDropFlag(pSprite, nType);
2899     else if (nType >= kItemBase && nType < kItemMax) pSprite2 = actDropItem(pSprite, nType);
2900     else if (nType >= kItemAmmoBase && nType < kItemAmmoMax) pSprite2 = actDropAmmo(pSprite, nType);
2901     else if (nType >= kItemWeaponBase && nType < kItemWeaponMax) pSprite2 = actDropWeapon(pSprite, nType);
2902 
2903     if (pSprite2) {
2904         int top, bottom;
2905         GetSpriteExtents(pSprite2, &top, &bottom);
2906         if (bottom >= pSprite2->z)
2907             pSprite2->z -= bottom - pSprite2->z;
2908     }
2909 
2910     return pSprite2;
2911 }
2912 
actHealDude(XSPRITE * pXDude,int a2,int a3)2913 bool actHealDude(XSPRITE *pXDude, int a2, int a3)
2914 {
2915     dassert(pXDude != NULL);
2916     a2 <<= 4;
2917     a3 <<= 4;
2918     if (pXDude->health < a3)
2919     {
2920         spritetype *pSprite = &sprite[pXDude->reference];
2921         if (IsPlayerSprite(pSprite))
2922             sfxPlay3DSound(pSprite->x, pSprite->y, pSprite->z, 780, pSprite->sectnum);
2923         pXDude->health = ClipHigh(pXDude->health+a2, a3);
2924         return 1;
2925     }
2926     return 0;
2927 }
2928 
actKillDude(int nKillerSprite,spritetype * pSprite,DAMAGE_TYPE damageType,int damage)2929 void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType, int damage)
2930 {
2931     spritetype *pKillerSprite = &sprite[nKillerSprite];
2932     dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
2933     int nType = pSprite->type-kDudeBase;
2934     int nXSprite = pSprite->extra;
2935     dassert(nXSprite > 0);
2936     XSPRITE *pXSprite = &xsprite[pSprite->extra];
2937 
2938     switch (pSprite->type) {
2939     #ifdef NOONE_EXTENSIONS
2940     case kDudeModernCustom: {
2941 
2942         GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
2943         removeDudeStuff(pSprite);
2944         if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == NULL) {
2945 
2946             if (pExtra->weaponType == kGenDudeWeaponKamikaze && Chance(0x4000) && damageType != 5 && damageType != 4) {
2947                 doExplosion(pSprite, pXSprite->data1 - kTrapExploder);
2948                 if (Chance(0x9000)) damageType = (DAMAGE_TYPE) 3;
2949             }
2950 
2951             if (damageType == kDamageBurn) {
2952                 if (pExtra->availDeaths[kDamageBurn] && !spriteIsUnderwater(pSprite)) {
2953                     if (pExtra->canBurn) {
2954                         pSprite->type = kDudeModernCustomBurning;
2955                         if (pXSprite->data2 == kGenDudeDefaultSeq) // don't inherit palette for burning if using default animation
2956                             pSprite->pal = 0;
2957 
2958                         aiGenDudeNewState(pSprite, &genDudeBurnGoto);
2959                         actHealDude(pXSprite, dudeInfo[55].startHealth, dudeInfo[55].startHealth);
2960                         if (pXSprite->burnTime <= 0) pXSprite->burnTime = 1200;
2961                         gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360;
2962                         return;
2963                     }
2964 
2965                 } else {
2966                     pXSprite->burnTime = 0;
2967                     pXSprite->burnSource = -1;
2968                     damageType = kDamageFall;
2969                 }
2970             }
2971 
2972         } else {
2973 
2974             pXSprite->locked = 1; // lock while transforming
2975 
2976             aiSetGenIdleState(pSprite, pXSprite); // set idle state
2977 
2978             if (pXSprite->key > 0) // drop keys
2979                 actDropObject(pSprite, kItemKeyBase + pXSprite->key - 1);
2980 
2981             if (pXSprite->dropMsg > 0) // drop items
2982                 actDropObject(pSprite, pXSprite->dropMsg);
2983 
2984 
2985             pSprite->flags &= ~kPhysMove; xvel[pSprite->index] = yvel[pSprite->index] = 0;
2986 
2987             playGenDudeSound(pSprite, kGenDudeSndTransforming);
2988             int seqId = pXSprite->data2 + kGenDudeSeqTransform;
2989             if (gSysRes.Lookup(seqId, "SEQ")) seqSpawn(seqId, 3, nXSprite, -1);
2990             else {
2991                 seqKill(3, nXSprite);
2992                 spritetype* pEffect = gFX.fxSpawn((FX_ID)52, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, pSprite->ang);
2993                 if (pEffect != NULL) {
2994                     pEffect->cstat = CSTAT_SPRITE_ALIGNMENT_FACING;
2995                     pEffect->pal = 6;
2996                     pEffect->xrepeat = pSprite->xrepeat;
2997                     pEffect->yrepeat = pSprite->yrepeat;
2998                 }
2999 
3000                 GIBTYPE nGibType;
3001                 for (int i = 0; i < 3; i++) {
3002                     if (Chance(0x3000)) nGibType = GIBTYPE_6;
3003                     else if (Chance(0x2000)) nGibType = GIBTYPE_5;
3004                     else nGibType = GIBTYPE_17;
3005 
3006                     int top, bottom;
3007                     GetSpriteExtents(pSprite, &top, &bottom);
3008                     CGibPosition gibPos(pSprite->x, pSprite->y, top);
3009                     CGibVelocity gibVel(xvel[pSprite->index] >> 1, yvel[pSprite->index] >> 1, -0xccccc);
3010                     GibSprite(pSprite, nGibType, &gibPos, &gibVel);
3011                 }
3012             }
3013 
3014             pXSprite->sysData1 = kGenDudeTransformStatus; // in transform
3015             return;
3016         }
3017         break;
3018     }
3019     #endif
3020     case kDudeCerberusTwoHead: // Cerberus
3021         seqSpawn(dudeInfo[nType].seqStartID+1, 3, nXSprite, -1);
3022         return;
3023     case kDudeCultistTommy:
3024     case kDudeCultistShotgun:
3025     case kDudeCultistTesla:
3026     case kDudeCultistTNT:
3027         if (damageType == kDamageBurn && pXSprite->medium == kMediumNormal)
3028         {
3029             pSprite->type = kDudeBurningCultist;
3030             aiNewState(pSprite, pXSprite, &cultistBurnGoto);
3031             actHealDude(pXSprite, dudeInfo[40].startHealth, dudeInfo[40].startHealth);
3032             return;
3033         }
3034         // no break
3035         fallthrough__;
3036     case kDudeBeast:
3037         if (damageType == kDamageBurn && pXSprite->medium == kMediumNormal)
3038         {
3039             pSprite->type = kDudeBurningBeast;
3040             aiNewState(pSprite, pXSprite, &beastBurnGoto);
3041             actHealDude(pXSprite, dudeInfo[53].startHealth, dudeInfo[53].startHealth);
3042             return;
3043         }
3044         // no break
3045         fallthrough__;
3046     case kDudeInnocent:
3047         if (damageType == kDamageBurn && pXSprite->medium == kMediumNormal)
3048         {
3049             pSprite->type = kDudeBurningInnocent;
3050             aiNewState(pSprite, pXSprite, &innocentBurnGoto);
3051             actHealDude(pXSprite, dudeInfo[39].startHealth, dudeInfo[39].startHealth);
3052             return;
3053         }
3054         break;
3055     }
3056     for (int p = connecthead; p >= 0; p = connectpoint2[p])
3057     {
3058         if (gPlayer[p].fraggerId == pSprite->index && gPlayer[p].deathTime > 0)
3059             gPlayer[p].fraggerId = -1;
3060     }
3061     if (pSprite->type != kDudeCultistBeast)
3062         trTriggerSprite(pSprite->index, pXSprite, kCmdOff);
3063 
3064     pSprite->flags |= 7;
3065     if (VanillaMode()) {
3066         if (IsPlayerSprite(pKillerSprite)) {
3067             PLAYER *pPlayer = &gPlayer[pKillerSprite->type - kDudePlayer1];
3068             if (gGameOptions.nGameType == 1)
3069                 pPlayer->fragCount++;
3070         }
3071     } else if (gGameOptions.nGameType == 1 && IsPlayerSprite(pKillerSprite) && pSprite->statnum == kStatDude) {
3072             switch (pSprite->type) {
3073                 case kDudeBat:
3074                 case kDudeRat:
3075                 case kDudeInnocent:
3076                 case kDudeBurningInnocent:
3077                     break;
3078                 default:
3079                     PLAYER* pKillerPlayer = &gPlayer[pKillerSprite->type - kDudePlayer1];
3080                     pKillerPlayer->fragCount++;
3081                     break;
3082             }
3083 
3084      }
3085 
3086     if (pXSprite->key > 0)
3087         actDropObject(pSprite, kItemKeyBase + pXSprite->key - 1);
3088 
3089     if (pXSprite->dropMsg > 0)
3090         actDropObject(pSprite, pXSprite->dropMsg);
3091 
3092     switch (pSprite->type) {
3093         case kDudeCultistTommy: {
3094             int nRand = Random(100);
3095             if (nRand < 10) actDropObject(pSprite, kItemWeaponTommygun);
3096             else if (nRand < 50) actDropObject(pSprite, kItemAmmoTommygunFew);
3097         }
3098         break;
3099         case kDudeCultistShotgun: {
3100             int nRand = Random(100);
3101             if (nRand <= 10) actDropObject(pSprite, kItemWeaponSawedoff);
3102             else if (nRand <= 50) actDropObject(pSprite, kItemAmmoSawedoffFew);
3103         }
3104         break;
3105     }
3106 
3107     int nSeq;
3108     switch (damageType)
3109     {
3110     case kDamageExplode:
3111         nSeq = 2;
3112         switch (pSprite->type) {
3113             #ifdef NOONE_EXTENSIONS
3114             case kDudeModernCustom:
3115             case kDudeModernCustomBurning: {
3116                 playGenDudeSound(pSprite, kGenDudeSndDeathExplode);
3117                 GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
3118                 if (!pExtra->availDeaths[damageType]) {
3119                     nSeq = 1; damageType = kDamageFall;
3120                 }
3121                 break;
3122             }
3123             #endif
3124             case kDudeCultistTommy:
3125             case kDudeCultistShotgun:
3126             case kDudeCultistTommyProne:
3127             case kDudeBurningInnocent:
3128             case kDudeBurningCultist:
3129             case kDudeInnocent:
3130             case kDudeCultistShotgunProne:
3131             case kDudeCultistTesla:
3132             case kDudeCultistTNT:
3133             case kDudeCultistBeast:
3134             case kDudeTinyCaleb:
3135             case kDudeBurningTinyCaleb:
3136                 sfxPlay3DSound(pSprite, 717,-1,0);
3137                 break;
3138         }
3139         break;
3140     case kDamageBurn:
3141         nSeq = 3;
3142         sfxPlay3DSound(pSprite, 351, -1, 0);
3143         break;
3144     case kDamageSpirit:
3145         switch (pSprite->type) {
3146             case kDudeZombieAxeNormal:
3147             case kDudeZombieAxeBuried:
3148                 nSeq = 14;
3149                 break;
3150             case kDudeZombieButcher:
3151                 nSeq = 11;
3152                 break;
3153             default:
3154                 nSeq = 1;
3155                 break;
3156         }
3157         break;
3158     case kDamageFall:
3159         switch (pSprite->type)
3160         {
3161         case kDudeCultistTommy:
3162         case kDudeCultistShotgun:
3163             nSeq = 1;
3164             break;
3165         default:
3166             nSeq = 1;
3167             break;
3168         }
3169         break;
3170     default:
3171         nSeq = 1;
3172         break;
3173     }
3174 
3175     if (!gSysRes.Lookup(getDudeInfo(nType+kDudeBase)->seqStartID + nSeq, "SEQ"))
3176     {
3177         seqKill(3, nXSprite);
3178         gKillMgr.AddKill(pSprite);
3179         actPostSprite(pSprite->index, kStatFree);
3180         return;
3181     }
3182 
3183     switch (pSprite->type) {
3184     case kDudeZombieAxeNormal:
3185         sfxPlay3DSound(pSprite, 1107+Random(2), -1, 0);
3186         if (nSeq == 2) {
3187 
3188             seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, nDudeToGibClient1);
3189             int top, bottom;
3190             GetSpriteExtents(pSprite, &top, &bottom);
3191             CGibPosition gibPos(pSprite->x, pSprite->y, top);
3192             CGibVelocity gibVel(xvel[pSprite->index]>>1, yvel[pSprite->index]>>1, -0xccccc);
3193             GibSprite(pSprite, GIBTYPE_27, &gibPos, &gibVel);
3194 
3195         } else if (nSeq == 1 && Chance(0x4000)) {
3196 
3197             seqSpawn(dudeInfo[nType].seqStartID+7, 3, nXSprite, nDudeToGibClient1);
3198             evPost(pSprite->index, 3, 0, kCallbackFXZombieSpurt);
3199             sfxPlay3DSound(pSprite, 362, -1, 0);
3200             pXSprite->data1 = 35;
3201             pXSprite->data2 = 5;
3202             int top, bottom;
3203             GetSpriteExtents(pSprite, &top, &bottom);
3204             CGibPosition gibPos(pSprite->x, pSprite->y, top);
3205             CGibVelocity gibVel(xvel[pSprite->index] >> 1, yvel[pSprite->index] >> 1, -0x111111);
3206             GibSprite(pSprite, GIBTYPE_27, &gibPos, &gibVel);
3207 
3208         } else if (nSeq == 14)
3209             seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3210         else if (nSeq == 3)
3211             seqSpawn(dudeInfo[nType].seqStartID+13, 3, nXSprite, nDudeToGibClient2);
3212         else
3213             seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, nDudeToGibClient1);
3214         break;
3215     case kDudeCultistTommy:
3216     case kDudeCultistShotgun:
3217     case kDudeCultistTesla:
3218     case kDudeCultistTNT:
3219         sfxPlay3DSound(pSprite, 1018+Random(2), -1, 0);
3220         if (nSeq == 3)
3221             seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, nDudeToGibClient2);
3222         else
3223             seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, nDudeToGibClient1);
3224         break;
3225     case kDudeBurningCultist:
3226         if (Chance(0x4000) && nSeq == 3)
3227             sfxPlay3DSound(pSprite, 718, -1, 0);
3228         else
3229             sfxPlay3DSound(pSprite, 1018+Random(2), -1, 0);
3230         damageType = kDamageExplode;
3231         if (Chance(0x8000))
3232         {
3233             for (int i = 0; i < 3; i++)
3234                 GibSprite(pSprite, GIBTYPE_7, NULL, NULL);
3235             seqSpawn(dudeInfo[nType].seqStartID+16-Random(1), 3, nXSprite, nDudeToGibClient1);
3236         }
3237         else
3238             seqSpawn(dudeInfo[nType].seqStartID+15, 3, nXSprite, nDudeToGibClient2);
3239         break;
3240 #ifdef NOONE_EXTENSIONS
3241     case kDudeModernCustom: {
3242         playGenDudeSound(pSprite, kGenDudeSndDeathNormal);
3243         int dudeToGib = (actCheckRespawn(pSprite)) ? -1 : ((nSeq == 3) ? nDudeToGibClient2 : nDudeToGibClient1);
3244         if (nSeq == 3) {
3245 
3246             GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
3247             if (pExtra->availDeaths[kDmgBurn] == 3) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, dudeToGib);
3248             else if (pExtra->availDeaths[kDmgBurn] == 2) seqSpawn(16 + pXSprite->data2, 3, nXSprite, dudeToGib);
3249             else if (pExtra->availDeaths[kDmgBurn] == 1) seqSpawn(15 + pXSprite->data2, 3, nXSprite, dudeToGib);
3250             else if (gSysRes.Lookup(pXSprite->data2 + nSeq, "SEQ"))seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, dudeToGib);
3251             else seqSpawn(1 + pXSprite->data2, 3, nXSprite, dudeToGib);
3252 
3253         } else {
3254             seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, dudeToGib);
3255         }
3256         genDudePostDeath(pSprite, damageType, damage);
3257         return;
3258 
3259     }
3260     case kDudeModernCustomBurning: {
3261         playGenDudeSound(pSprite, kGenDudeSndDeathExplode);
3262         int dudeToGib = (actCheckRespawn(pSprite)) ? -1 : nDudeToGibClient1;
3263         damageType = kDamageExplode;
3264 
3265         if (Chance(0x4000)) {
3266             int top, bottom;
3267             GetSpriteExtents(pSprite, &top, &bottom);
3268             CGibPosition gibPos(pSprite->x, pSprite->y, top);
3269             CGibVelocity gibVel(xvel[pSprite->index] >> 1, yvel[pSprite->index] >> 1, -0xccccc);
3270             GibSprite(pSprite, GIBTYPE_7, &gibPos, &gibVel);
3271         }
3272 
3273         GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
3274         if (pExtra->availDeaths[kDmgBurn] == 3) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, dudeToGib);
3275         else if (pExtra->availDeaths[kDmgBurn] == 2) seqSpawn(16 + pXSprite->data2, 3, nXSprite, dudeToGib);
3276         else if (pExtra->availDeaths[kDmgBurn] == 1) seqSpawn(15 + pXSprite->data2, 3, nXSprite, dudeToGib);
3277         else seqSpawn(1 + pXSprite->data2, 3, nXSprite, dudeToGib);
3278         genDudePostDeath(pSprite, damageType, damage);
3279         return;
3280     }
3281 #endif
3282     case kDudeBurningZombieAxe:
3283         if (Chance(0x8000) && nSeq == 3)
3284             sfxPlay3DSound(pSprite, 1109, -1, 0);
3285         else
3286             sfxPlay3DSound(pSprite, 1107+Random(2), -1, 0);
3287         damageType = kDamageExplode;
3288         if (Chance(0x8000))
3289         {
3290             seqSpawn(dudeInfo[nType].seqStartID+13, 3, nXSprite, nDudeToGibClient1);
3291             int top, bottom;
3292             GetSpriteExtents(pSprite, &top, &bottom);
3293             CGibPosition gibPos(pSprite->x, pSprite->y, top);
3294             CGibVelocity gibVel(xvel[pSprite->index]>>1, yvel[pSprite->index]>>1, -0xccccc);
3295             GibSprite(pSprite, GIBTYPE_27, &gibPos, &gibVel);
3296         }
3297         else
3298             seqSpawn(dudeInfo[nType].seqStartID+13, 3, nXSprite, nDudeToGibClient2);
3299         break;
3300     case kDudeBurningZombieButcher:
3301         if (Chance(0x4000) && nSeq == 3)
3302             sfxPlay3DSound(pSprite, 1206, -1, 0);
3303         else
3304             sfxPlay3DSound(pSprite, 1204+Random(2), -1, 0);
3305         seqSpawn(dudeInfo[4].seqStartID+10, 3, nXSprite, -1);
3306         break;
3307     case kDudeBurningInnocent:
3308         damageType = kDamageExplode;
3309         seqSpawn(dudeInfo[nType].seqStartID+7, 3, nXSprite, nDudeToGibClient1);
3310         break;
3311     case kDudeZombieButcher:
3312         if (nSeq == 14) {
3313             sfxPlay3DSound(pSprite, 1206, -1, 0);
3314             seqSpawn(dudeInfo[nType].seqStartID+11, 3, nXSprite, -1);
3315             break;
3316         }
3317         sfxPlay3DSound(pSprite, 1204+Random(2), -1, 0);
3318         if (nSeq == 3)
3319             seqSpawn(dudeInfo[nType].seqStartID+10, 3, nXSprite, -1);
3320         else
3321             seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3322         break;
3323     case kDudeGargoyleFlesh:
3324         if (Chance(0x4000) && nSeq == 3) sfxPlay3DSound(pSprite, 1405, -1, 0);
3325         else sfxPlay3DSound(pSprite, 1403+Random(2), -1, 0);
3326         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3327         break;
3328     case kDudeGargoyleStone:
3329         if (Chance(0x4000) && nSeq == 3) sfxPlay3DSound(pSprite, 1455, -1, 0);
3330         else sfxPlay3DSound(pSprite, 1453+Random(2), -1, 0);
3331         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3332         break;
3333     case kDudePhantasm:
3334         if (Chance(0x4000) && nSeq == 3) sfxPlay3DSound(pSprite, 1605, -1, 0);
3335         else sfxPlay3DSound(pSprite, 1603+Random(2), -1, 0);
3336         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3337         break;
3338     case kDudeHellHound:
3339         if (Chance(0x4000) && nSeq == 3) sfxPlay3DSound(pSprite, 1305, -1, 0);
3340         else sfxPlay3DSound(pSprite, 1303+Random(2), -1, 0);
3341         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3342         break;
3343     case kDudeHand:
3344         if (Chance(0x4000) && nSeq == 3) sfxPlay3DSound(pSprite, 1905, -1, 0);
3345         else sfxPlay3DSound(pSprite, 1903+Random(2), -1, 0);
3346         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3347         break;
3348     case kDudeSpiderBrown:
3349         if (pSprite->owner != -1) {
3350             spritetype *pOwner = &sprite[actSpriteOwnerToSpriteId(pSprite)];
3351             gDudeExtra[pOwner->extra].at6.u1.at4--;
3352         }
3353 
3354         if (Chance(0x4000) && nSeq == 3) sfxPlay3DSound(pSprite, 1805, -1, 0);
3355         else sfxPlay3DSound(pSprite, 1803+Random(2), -1, 0);
3356         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3357         break;
3358     case kDudeSpiderRed:
3359         if (pSprite->owner != -1) {
3360             spritetype *pOwner = &sprite[actSpriteOwnerToSpriteId(pSprite)];
3361             gDudeExtra[pOwner->extra].at6.u1.at4--;
3362         }
3363 
3364         if (Chance(0x4000) && nSeq == 3) sfxPlay3DSound(pSprite, 1805, -1, 0);
3365         else sfxPlay3DSound(pSprite, 1803+Random(2), -1, 0);
3366         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3367         break;
3368     case kDudeSpiderBlack:
3369         if (pSprite->owner != -1) {
3370             spritetype *pOwner = &sprite[actSpriteOwnerToSpriteId(pSprite)];
3371             gDudeExtra[pOwner->extra].at6.u1.at4--;
3372         }
3373 
3374         if (Chance(0x4000) && nSeq == 3) sfxPlay3DSound(pSprite, 1805, -1, 0);
3375         else sfxPlay3DSound(pSprite, 1803+Random(2), -1, 0);
3376         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3377         break;
3378     case kDudeSpiderMother:
3379         sfxPlay3DSound(pSprite, 1850, -1, 0);
3380         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3381         break;
3382     case kDudeGillBeast:
3383         if (Chance(0x4000) && nSeq == 3) sfxPlay3DSound(pSprite, 1705, -1, 0);
3384         else sfxPlay3DSound(pSprite, 1703+Random(2), -1, 0);
3385         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3386         break;
3387     case kDudeBoneEel:
3388         if (Chance(0x4000) && nSeq == 3) sfxPlay3DSound(pSprite, 1505, -1, 0);
3389         else sfxPlay3DSound(pSprite, 1503+Random(2), -1, 0);
3390         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3391         break;
3392     case kDudeBat:
3393         if (Chance(0x4000) && nSeq == 3)
3394             sfxPlay3DSound(pSprite, 2005, -1, 0);
3395         else
3396             sfxPlay3DSound(pSprite, 2003+Random(2), -1, 0);
3397         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3398         break;
3399     case kDudeRat:
3400         if (Chance(0x4000) && nSeq == 3)
3401             sfxPlay3DSound(pSprite, 2105, -1, 0);
3402         else
3403             sfxPlay3DSound(pSprite, 2103+Random(2), -1, 0);
3404         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3405         break;
3406     case kDudePodGreen:
3407     case kDudeTentacleGreen:
3408     case kDudePodFire:
3409     case kDudeTentacleFire:
3410         if ((pSprite->cstat & CSTAT_SPRITE_YFLIP)) pSprite->cstat &= ~CSTAT_SPRITE_YFLIP;
3411         switch (pSprite->type) {
3412             case kDudePodGreen:
3413                 if (Chance(0x4000) && nSeq == 3)
3414                     sfxPlay3DSound(pSprite, 2205, -1, 0);
3415                 else
3416                     sfxPlay3DSound(pSprite, 2203 + Random(2), -1, 0);
3417                 seqSpawn(dudeInfo[nType].seqStartID + nSeq, 3, nXSprite, -1);
3418                 break;
3419             case kDudeTentacleGreen:
3420                 if (damage == 5)
3421                     sfxPlay3DSound(pSprite, 2471, -1, 0);
3422                 else
3423                     sfxPlay3DSound(pSprite, 2472, -1, 0);
3424                 seqSpawn(dudeInfo[nType].seqStartID + nSeq, 3, nXSprite, -1);
3425                 break;
3426             case kDudePodFire:
3427                 if (damage == 5)
3428                     sfxPlay3DSound(pSprite, 2451, -1, 0);
3429                 else
3430                     sfxPlay3DSound(pSprite, 2452, -1, 0);
3431                 seqSpawn(dudeInfo[nType].seqStartID + nSeq, 3, nXSprite, -1);
3432                 break;
3433             case kDudeTentacleFire:
3434                 sfxPlay3DSound(pSprite, 2501, -1, 0);
3435                 seqSpawn(dudeInfo[nType].seqStartID + nSeq, 3, nXSprite, -1);
3436                 break;
3437         }
3438         break;
3439     case kDudePodMother:
3440         if (Chance(0x4000) && nSeq == 3)
3441             sfxPlay3DSound(pSprite, 2205, -1, 0);
3442         else
3443             sfxPlay3DSound(pSprite, 2203+Random(2), -1, 0);
3444         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3445         break;
3446     case kDudeTentacleMother:
3447         if (Chance(0x4000) && nSeq == 3)
3448             sfxPlay3DSound(pSprite, 2205, -1, 0);
3449         else
3450             sfxPlay3DSound(pSprite, 2203+Random(2), -1, 0);
3451         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3452         break;
3453     case kDudeCerberusTwoHead:
3454         if (Chance(0x4000) && nSeq == 3)
3455             sfxPlay3DSound(pSprite, 2305, -1, 0);
3456         else
3457             sfxPlay3DSound(pSprite, 2305+Random(2), -1, 0);
3458         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3459         break;
3460     case kDudeCerberusOneHead:
3461         if (Chance(0x4000) && nSeq == 3)
3462             sfxPlay3DSound(pSprite, 2305, -1, 0);
3463         else
3464             sfxPlay3DSound(pSprite, 2305+Random(2), -1, 0);
3465         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3466         break;
3467     case kDudeTchernobog:
3468         sfxPlay3DSound(pSprite, 2380, -1, 0);
3469         seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
3470         break;
3471     case kDudeBurningTinyCaleb:
3472         damageType = kDamageExplode;
3473         seqSpawn(dudeInfo[nType].seqStartID+11, 3, nXSprite, nDudeToGibClient1);
3474         break;
3475     case kDudeBeast:
3476         sfxPlay3DSound(pSprite, 9000+Random(2), -1, 0);
3477         if (nSeq == 3)
3478             seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, nDudeToGibClient2);
3479         else
3480             seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, nDudeToGibClient1);
3481         break;
3482     case kDudeBurningBeast:
3483         damageType = kDamageExplode;
3484         seqSpawn(dudeInfo[nType].seqStartID+12, 3, nXSprite, nDudeToGibClient1);
3485         break;
3486     default:
3487         seqSpawn(getDudeInfo(nType+kDudeBase)->seqStartID+nSeq, 3, nXSprite, -1);
3488         break;
3489     }
3490 
3491     if (damageType == kDamageExplode)
3492     {
3493         DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
3494         for (int i = 0; i < 3; i++)
3495             if (pDudeInfo->nGibType[i] > -1)
3496                 GibSprite(pSprite, (GIBTYPE)pDudeInfo->nGibType[i], NULL, NULL);
3497         for (int i = 0; i < 4; i++)
3498             fxSpawnBlood(pSprite, damage);
3499     }
3500     gKillMgr.AddKill(pSprite);
3501     actCheckRespawn(pSprite);
3502     pSprite->type = kThingBloodChunks;
3503     actPostSprite(pSprite->index, kStatThing);
3504 }
3505 
actDamageSprite(int nSource,spritetype * pSprite,DAMAGE_TYPE damageType,int damage)3506 int actDamageSprite(int nSource, spritetype *pSprite, DAMAGE_TYPE damageType, int damage) {
3507     dassert(nSource < kMaxSprites);
3508 
3509     if (pSprite->flags&32 || pSprite->extra <= 0 || pSprite->extra >= kMaxXSprites || xsprite[pSprite->extra].reference != pSprite->index)
3510         return 0;
3511 
3512     XSPRITE *pXSprite = &xsprite[pSprite->extra];
3513     if ((pXSprite->health == 0 && pSprite->statnum != kStatDude) || pXSprite->locked)
3514         return 0;
3515 
3516     if (nSource == -1)
3517         nSource = pSprite->index;
3518 
3519     PLAYER *pSourcePlayer = NULL;
3520     if (IsPlayerSprite(&sprite[nSource])) pSourcePlayer = &gPlayer[sprite[nSource].type - kDudePlayer1];
3521     if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pSourcePlayer, pSprite)) return 0;
3522 
3523     switch (pSprite->statnum) {
3524         case kStatDude: {
3525             if (!IsDudeSprite(pSprite)) {
3526                 consoleSysMsg("Bad Dude Failed: initial=%d type=%d %s\n", (int)pSprite->inittype, (int)pSprite->type, (int)(pSprite->flags & 16) ? "RESPAWN" : "NORMAL");
3527                 return damage >> 4;
3528                 //ThrowError("Bad Dude Failed: initial=%d type=%d %s\n", (int)pSprite->inittype, (int)pSprite->type, (int)(pSprite->flags & 16) ? "RESPAWN" : "NORMAL");
3529             }
3530 
3531             int nType = pSprite->type - kDudeBase; int nDamageFactor = getDudeInfo(nType+kDudeBase)->at70[damageType];
3532             #ifdef NOONE_EXTENSIONS
3533             if (pSprite->type == kDudeModernCustom)
3534                 nDamageFactor = gGenDudeExtra[pSprite->index].dmgControl[damageType];
3535             #endif
3536 
3537             if (!nDamageFactor) return 0;
3538             else if (nDamageFactor != 256)
3539                 damage = mulscale8(damage, nDamageFactor);
3540 
3541             if (!IsPlayerSprite(pSprite)) {
3542 
3543                 if (pXSprite->health <= 0) return 0;
3544                 damage = aiDamageSprite(pSprite, pXSprite, nSource, damageType, damage);
3545                 if (pXSprite->health <= 0)
3546                     actKillDude(nSource, pSprite, ((damageType == kDamageExplode && damage < 160) ? kDamageFall : damageType), damage);
3547 
3548             } else {
3549 
3550                 PLAYER *pPlayer = &gPlayer[pSprite->type - kDudePlayer1];
3551                 if (pXSprite->health > 0 || playerSeqPlaying(pPlayer, 16))
3552                     damage = playerDamageSprite(nSource, pPlayer, damageType, damage);
3553 
3554             }
3555         }
3556         break;
3557     case kStatThing:
3558         dassert(pSprite->type >= kThingBase && pSprite->type < kThingMax);
3559         int nType = pSprite->type - kThingBase; int nDamageFactor = thingInfo[nType].dmgControl[damageType];
3560 
3561         if (!nDamageFactor) return 0;
3562         else if (nDamageFactor != 256)
3563             damage = mulscale8(damage, nDamageFactor);
3564 
3565         pXSprite->health = ClipLow(pXSprite->health - damage, 0);
3566         if (pXSprite->health <= 0) {
3567             switch (pSprite->type) {
3568                 case kThingDroppedLifeLeech:
3569                 #ifdef NOONE_EXTENSIONS
3570                 case kModernThingEnemyLifeLeech:
3571                 #endif
3572                     GibSprite(pSprite, GIBTYPE_14, NULL, NULL);
3573                     pXSprite->data1 = pXSprite->data2 =  pXSprite->data3 = pXSprite->DudeLockout = 0;
3574                     pXSprite->stateTimer =  pXSprite->data4 = pXSprite->isTriggered = 0;
3575 
3576                     #ifdef NOONE_EXTENSIONS
3577                     if (pSprite->owner >= 0 && sprite[pSprite->owner].type == kDudeModernCustom)
3578                         sprite[pSprite->owner].owner = kMaxSprites - 1; // indicates if custom dude had life leech.
3579                     #endif
3580                     break;
3581 
3582                 default:
3583                     if (!(pSprite->flags & kHitagRespawn))
3584                         actPropagateSpriteOwner(pSprite, &sprite[nSource]);
3585                     break;
3586             }
3587 
3588             trTriggerSprite(pSprite->index, pXSprite, kCmdOff);
3589 
3590             switch (pSprite->type) {
3591                 case kThingObjectGib:
3592                 case kThingObjectExplode:
3593                 case kThingBloodBits:
3594                 case kThingBloodChunks:
3595                 case kThingZombieHead:
3596                     if (damageType == 3 && pSourcePlayer && gFrameClock > pSourcePlayer->laughCount && Chance(0x4000)) {
3597                         sfxPlay3DSound(pSourcePlayer->pSprite, gPlayerGibThingComments[Random(10)], 0, 2);
3598                         pSourcePlayer->laughCount = (int)gFrameClock+3600;
3599                     }
3600                     break;
3601                 case kTrapMachinegun:
3602                     seqSpawn(28, 3, pSprite->extra, -1);
3603                     break;
3604                 case kThingFluorescent:
3605                     seqSpawn(12, 3, pSprite->extra, -1);
3606                     GibSprite(pSprite, GIBTYPE_6, NULL, NULL);
3607                     break;
3608                 case kThingSpiderWeb:
3609                     seqSpawn(15, 3, pSprite->extra, -1);
3610                     break;
3611                 case kThingMetalGrate:
3612                     seqSpawn(21, 3, pSprite->extra, -1);
3613                     GibSprite(pSprite, GIBTYPE_4, NULL, NULL);
3614                     break;
3615                 case kThingFlammableTree:
3616                     switch (pXSprite->data1) {
3617                         case -1:
3618                             GibSprite(pSprite, GIBTYPE_14, NULL, NULL);
3619                             sfxPlay3DSound(pSprite->x, pSprite->y, pSprite->z, 312, pSprite->sectnum);
3620                             actPostSprite(pSprite->index, kStatFree);
3621                             break;
3622                         case 0:
3623                             seqSpawn(25, 3, pSprite->extra, nTreeToGibClient);
3624                             sfxPlay3DSound(pSprite, 351, -1, 0);
3625                             break;
3626                         case 1:
3627                             seqSpawn(26, 3, pSprite->extra, nTreeToGibClient);
3628                             sfxPlay3DSound(pSprite, 351, -1, 0);
3629                             break;
3630                     }
3631                     break;
3632             }
3633         }
3634         break;
3635     }
3636 
3637     return damage >> 4;
3638 }
3639 
actHitcodeToData(int a1,HITINFO * pHitInfo,int * a3,spritetype ** a4,XSPRITE ** a5,int * a6,walltype ** a7,XWALL ** a8,int * a9,sectortype ** a10,XSECTOR ** a11)3640 void actHitcodeToData(int a1, HITINFO *pHitInfo, int *a3, spritetype **a4, XSPRITE **a5, int *a6, walltype **a7, XWALL **a8, int *a9, sectortype **a10, XSECTOR **a11)
3641 {
3642     dassert(pHitInfo != NULL);
3643     int nSprite = -1;
3644     spritetype *pSprite = NULL;
3645     XSPRITE *pXSprite = NULL;
3646     int nWall = -1;
3647     walltype *pWall = NULL;
3648     XWALL *pXWall = NULL;
3649     int nSector = -1;
3650     sectortype *pSector = NULL;
3651     XSECTOR *pXSector = NULL;
3652     switch (a1)
3653     {
3654     case 3:
3655     case 5:
3656         nSprite = pHitInfo->hitsprite;
3657         dassert(nSprite >= 0 && nSprite < kMaxSprites);
3658         pSprite = &sprite[nSprite];
3659         if (pSprite->extra > 0)
3660             pXSprite = &xsprite[pSprite->extra];
3661         break;
3662     case 0:
3663     case 4:
3664         nWall = pHitInfo->hitwall;
3665         dassert(nWall >= 0 && nWall < kMaxWalls);
3666         pWall = &wall[nWall];
3667         if (pWall->extra > 0)
3668             pXWall = &xwall[pWall->extra];
3669         break;
3670     case 1:
3671     case 2:
3672     case 6:
3673         nSector = pHitInfo->hitsect;
3674         dassert(nSector >= 0 && nSector < kMaxSectors);
3675         pSector = &sector[nSector];
3676         if (pSector->extra > 0)
3677             pXSector = &xsector[pSector->extra];
3678         break;
3679     }
3680     if (a3)
3681         *a3 = nSprite;
3682     if (a4)
3683         *a4 = pSprite;
3684     if (a5)
3685         *a5 = pXSprite;
3686     if (a6)
3687         *a6 = nWall;
3688     if (a7)
3689         *a7 = pWall;
3690     if (a8)
3691         *a8 = pXWall;
3692     if (a9)
3693         *a9 = nSector;
3694     if (a10)
3695         *a10 = pSector;
3696     if (a11)
3697         *a11 = pXSector;
3698 }
3699 
actImpactMissile(spritetype * pMissile,int hitCode)3700 void actImpactMissile(spritetype *pMissile, int hitCode)
3701 {
3702     int nXMissile = pMissile->extra;
3703     dassert(nXMissile > 0 && nXMissile < kMaxXSprites);
3704     XSPRITE *pXMissile = &xsprite[pMissile->extra];
3705 
3706     int nSpriteHit = -1; int nWallHit = -1; int nSectorHit = -1;
3707     spritetype *pSpriteHit = NULL; XSPRITE *pXSpriteHit = NULL;
3708     walltype *pWallHit = NULL; XWALL *pXWallHit = NULL;
3709     sectortype *pSectorHit = NULL; XSECTOR *pXSectorHit = NULL;
3710 
3711     actHitcodeToData(hitCode, &gHitInfo, &nSpriteHit, &pSpriteHit, &pXSpriteHit, &nWallHit, &pWallHit, &pXWallHit, &nSectorHit, &pSectorHit, &pXSectorHit);
3712     THINGINFO *pThingInfo = NULL; DUDEINFO *pDudeInfo = NULL;
3713 
3714     if (hitCode == 3 && pSpriteHit) {
3715         switch (pSpriteHit->statnum) {
3716             case kStatThing:
3717                 pThingInfo = &thingInfo[pSpriteHit->type - kThingBase];
3718                 break;
3719             case kStatDude:
3720                 pDudeInfo = getDudeInfo(pSpriteHit->type);
3721                 break;
3722         }
3723     }
3724     switch (pMissile->type) {
3725         case kMissileLifeLeechRegular:
3726             if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo)) {
3727                 int nOwner = actSpriteOwnerToSpriteId(pMissile);
3728                 DAMAGE_TYPE rand1 = (DAMAGE_TYPE)Random(7);
3729                 int rand2 = (7 + Random(7)) << 4;
3730                 int nDamage = actDamageSprite(nOwner, pSpriteHit, rand1, rand2);
3731                 if ((pThingInfo && pThingInfo->dmgControl[kDamageBurn] != 0) || (pDudeInfo && pDudeInfo->at70[kDamageBurn] != 0))
3732                     actBurnSprite(pMissile->owner, pXSpriteHit, 360);
3733 
3734                 // by NoOne: make Life Leech heal user, just like it was in 1.0x versions
3735                 if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus() && pDudeInfo != NULL) {
3736                     spritetype* pSource = &sprite[nOwner];
3737                     XSPRITE* pXSource = (pSource->extra >= 0) ? &xsprite[pSource->extra] : NULL;
3738 
3739                     if (IsDudeSprite(pSource) && pXSource != NULL && pXSource->health != 0)
3740 
3741                         actHealDude(pXSource, nDamage >> 2, getDudeInfo(pSource->type)->startHealth);
3742                 }
3743             }
3744 
3745             if (pMissile->extra > 0) {
3746                 actPostSprite(pMissile->index, kStatDecoration);
3747                 if (pMissile->ang == 1024) sfxPlay3DSound(pMissile, 307, -1, 0);
3748                 pMissile->type = kSpriteDecoration;
3749                 seqSpawn(9, 3, pMissile->extra, -1);
3750             } else {
3751                 actPostSprite(pMissile->index, kStatFree);
3752             }
3753 
3754             break;
3755         case kMissileTeslaAlt:
3756             sub_51340(pMissile, hitCode);
3757             switch (hitCode) {
3758                 case 0:
3759                 case 4:
3760                     if (pWallHit) {
3761                         spritetype* pFX = gFX.fxSpawn(FX_52, pMissile->sectnum, pMissile->x, pMissile->y, pMissile->z, 0);
3762                         if (pFX) pFX->ang = (GetWallAngle(nWallHit) + 512) & 2047;
3763                     }
3764                     break;
3765             }
3766             GibSprite(pMissile, GIBTYPE_24, NULL, NULL);
3767             actPostSprite(pMissile->index, kStatFree);
3768             break;
3769         case kMissilePukeGreen:
3770             seqKill(3, nXMissile);
3771             if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo))
3772             {
3773                 int nOwner = actSpriteOwnerToSpriteId(pMissile);
3774                 int nDamage = (15+Random(7))<<4;
3775                 actDamageSprite(nOwner, pSpriteHit, kDamageBullet, nDamage);
3776             }
3777             actPostSprite(pMissile->index, kStatFree);
3778             break;
3779         case kMissileArcGargoyle:
3780             sfxKill3DSound(pMissile, -1, -1);
3781             sfxPlay3DSound(pMissile->x, pMissile->y, pMissile->z, 306, pMissile->sectnum);
3782             GibSprite(pMissile, GIBTYPE_6, NULL, NULL);
3783             if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo))
3784             {
3785                 int nOwner = actSpriteOwnerToSpriteId(pMissile);
3786                 int nDamage = (25+Random(20))<<4;
3787                 actDamageSprite(nOwner, pSpriteHit, kDamageSpirit, nDamage);
3788             }
3789             actPostSprite(pMissile->index, kStatFree);
3790             break;
3791         case kMissileLifeLeechAltNormal:
3792         case kMissileLifeLeechAltSmall:
3793             sfxKill3DSound(pMissile, -1, -1);
3794             sfxPlay3DSound(pMissile->x, pMissile->y, pMissile->z, 306, pMissile->sectnum);
3795             if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo)) {
3796                 int nOwner = actSpriteOwnerToSpriteId(pMissile);
3797                 int nDmgMul = (pMissile->type == kMissileLifeLeechAltSmall) ? 6 : 3;
3798                 int nDamage = (nDmgMul+Random(nDmgMul))<<4;
3799                 actDamageSprite(nOwner, pSpriteHit, kDamageSpirit, nDamage);
3800             }
3801             actPostSprite(pMissile->index, kStatFree);
3802             break;
3803         case kMissileFireball:
3804         case kMissileFireballNapam:
3805             if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo))
3806             {
3807                 if (pThingInfo && pSpriteHit->type == kThingTNTBarrel && pXSpriteHit->burnTime == 0)
3808                     evPost(nSpriteHit, 3, 0, kCallbackFXFlameLick);
3809                 int nOwner = actSpriteOwnerToSpriteId(pMissile);
3810                 int nDamage = (50+Random(50))<<4;
3811                 actDamageSprite(nOwner, pSpriteHit, kDamageBullet, nDamage);
3812             }
3813             actExplodeSprite(pMissile);
3814             break;
3815         case kMissileFlareAlt:
3816             sfxKill3DSound(pMissile, -1, -1);
3817             actExplodeSprite(pMissile);
3818             break;
3819         case kMissileFlareRegular:
3820             sfxKill3DSound(pMissile, -1, -1);
3821             if ((hitCode == 3 && pSpriteHit) && (pThingInfo || pDudeInfo)) {
3822                 int nOwner = actSpriteOwnerToSpriteId(pMissile);
3823                 if ((pThingInfo && pThingInfo->dmgControl[kDamageBurn] != 0) || (pDudeInfo && pDudeInfo->at70[kDamageBurn] != 0)) {
3824                     if (pThingInfo && pSpriteHit->type == kThingTNTBarrel && pXSpriteHit->burnTime == 0)
3825                         evPost(nSpriteHit, 3, 0, kCallbackFXFlameLick);
3826 
3827                     actBurnSprite(pMissile->owner, pXSpriteHit, 480);
3828                     sub_2A620(nOwner, pMissile->x, pMissile->y, pMissile->z, pMissile->sectnum, 16, 20, 10, kDamageBullet, 6, 480, 0, 0);
3829 
3830                     // by NoOne: allow additional bullet damage for Flare Gun
3831                     if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus()) {
3832                         int nDamage = (20 + Random(10)) << 4;
3833                         actDamageSprite(nOwner, pSpriteHit, kDamageBullet, nDamage);
3834                     }
3835                 } else  {
3836                     int nDamage = (20+Random(10))<<4;
3837                     actDamageSprite(nOwner, pSpriteHit, kDamageBullet, nDamage);
3838                 }
3839 
3840                 if (surfType[pSpriteHit->picnum] == kSurfFlesh) {
3841                     pMissile->picnum = 2123;
3842                     pXMissile->target = nSpriteHit;
3843                     pXMissile->targetZ = pMissile->z-pSpriteHit->z;
3844                     pXMissile->goalAng = getangle(pMissile->x-pSpriteHit->x, pMissile->y-pSpriteHit->y)-pSpriteHit->ang;
3845                     pXMissile->state = 1;
3846                     actPostSprite(pMissile->index, kStatFlare);
3847                     pMissile->cstat &= ~257;
3848                     break;
3849                 }
3850             }
3851             GibSprite(pMissile, GIBTYPE_17, NULL, NULL);
3852             actPostSprite(pMissile->index, kStatFree);
3853             break;
3854         case kMissileFlameSpray:
3855         case kMissileFlameHound:
3856             if (hitCode == 3)
3857             {
3858                 int nObject = gHitInfo.hitsprite;
3859                 dassert(nObject >= 0 && nObject < kMaxSprites);
3860                 spritetype *pObject = &sprite[nObject];
3861                 if (pObject->extra > 0)
3862                 {
3863                     XSPRITE *pXObject = &xsprite[pObject->extra];
3864                     if ((pObject->statnum == kStatThing || pObject->statnum == kStatDude) && pXObject->burnTime == 0)
3865                         evPost(nObject, 3, 0, kCallbackFXFlameLick);
3866                     int nOwner = actSpriteOwnerToSpriteId(pMissile);
3867                     actBurnSprite(pMissile->owner, pXObject, (4+gGameOptions.nDifficulty)<<2);
3868                     actDamageSprite(nOwner, pObject, kDamageBurn, 8);
3869                 }
3870             }
3871             break;
3872         case kMissileFireballCerberus:
3873             actExplodeSprite(pMissile);
3874             if (hitCode == 3)
3875             {
3876                 int nObject = gHitInfo.hitsprite;
3877                 dassert(nObject >= 0 && nObject < kMaxSprites);
3878                 spritetype *pObject = &sprite[nObject];
3879                 if (pObject->extra > 0)
3880                 {
3881                     XSPRITE *pXObject = &xsprite[pObject->extra];
3882                     if ((pObject->statnum == kStatThing || pObject->statnum == kStatDude) && pXObject->burnTime == 0)
3883                         evPost(nObject, 3, 0, kCallbackFXFlameLick);
3884                     int nOwner = actSpriteOwnerToSpriteId(pMissile);
3885                     actBurnSprite(pMissile->owner, pXObject, (4+gGameOptions.nDifficulty)<<2);
3886                     actDamageSprite(nOwner, pObject, kDamageBurn, 8);
3887                     int nDamage = (25+Random(10))<<4;
3888                     actDamageSprite(nOwner, pObject, kDamageBullet, nDamage);
3889                 }
3890             }
3891             actExplodeSprite(pMissile);
3892             break;
3893         case kMissileFireballTchernobog:
3894             actExplodeSprite(pMissile);
3895             if (hitCode == 3)
3896             {
3897                 int nObject = gHitInfo.hitsprite;
3898                 dassert(nObject >= 0 && nObject < kMaxSprites);
3899                 spritetype *pObject = &sprite[nObject];
3900                 if (pObject->extra > 0)
3901                 {
3902                     XSPRITE *pXObject = &xsprite[pObject->extra];
3903                     if ((pObject->statnum == kStatThing || pObject->statnum == kStatDude) && pXObject->burnTime == 0)
3904                         evPost(nObject, 3, 0, kCallbackFXFlameLick);
3905                     int nOwner = actSpriteOwnerToSpriteId(pMissile);
3906                     actBurnSprite(pMissile->owner, pXObject, 32);
3907                     actDamageSprite(nOwner, pObject, kDamageSpirit, 12);
3908                     int nDamage = (25+Random(10))<<4;
3909                     actDamageSprite(nOwner, pObject, kDamageBullet, nDamage);
3910                 }
3911             }
3912             actExplodeSprite(pMissile);
3913             break;
3914         case kMissileEctoSkull:
3915             sfxKill3DSound(pMissile, -1, -1);
3916             sfxPlay3DSound(pMissile->x, pMissile->y, pMissile->z, 522, pMissile->sectnum);
3917             actPostSprite(pMissile->index, kStatDebris);
3918             seqSpawn(20, 3, pMissile->extra, -1);
3919             if (hitCode == 3)
3920             {
3921                 int nObject = gHitInfo.hitsprite;
3922                 dassert(nObject >= 0 && nObject < kMaxSprites);
3923                 spritetype *pObject = &sprite[nObject];
3924                 if (pObject->statnum == kStatDude)
3925                 {
3926                     int nOwner = actSpriteOwnerToSpriteId(pMissile);
3927                     int nDamage = (25+Random(10))<<4;
3928                     actDamageSprite(nOwner, pObject, kDamageSpirit, nDamage);
3929                 }
3930             }
3931             break;
3932         case kMissileButcherKnife:
3933             actPostSprite(pMissile->index, kStatDebris);
3934             pMissile->cstat &= ~16;
3935             pMissile->type = kSpriteDecoration;
3936             seqSpawn(20, 3, pMissile->extra, -1);
3937             if (hitCode == 3)
3938             {
3939                 int nObject = gHitInfo.hitsprite;
3940                 dassert(nObject >= 0 && nObject < kMaxSprites);
3941                 spritetype *pObject = &sprite[nObject];
3942                 if (pObject->statnum == kStatDude)
3943                 {
3944                     int nOwner = actSpriteOwnerToSpriteId(pMissile);
3945                     int nDamage = (10+Random(10))<<4;
3946                     actDamageSprite(nOwner, pObject, kDamageSpirit, nDamage);
3947                     spritetype *pOwner = &sprite[nOwner];
3948                     XSPRITE *pXOwner = &xsprite[pOwner->extra];
3949                     int nType = pOwner->type-kDudeBase;
3950                     if (pXOwner->health > 0)
3951                         actHealDude(pXOwner, 10, getDudeInfo(nType+kDudeBase)->startHealth);
3952                 }
3953             }
3954             break;
3955         case kMissileTeslaRegular:
3956             sfxKill3DSound(pMissile, -1, -1);
3957             sfxPlay3DSound(pMissile->x, pMissile->y, pMissile->z, 518, pMissile->sectnum);
3958             GibSprite(pMissile, (hitCode == 2) ? GIBTYPE_23 : GIBTYPE_22, NULL, NULL);
3959             evKill(pMissile->index, 3);
3960             seqKill(3, nXMissile);
3961             actPostSprite(pMissile->index, kStatFree);
3962             if (hitCode == 3)
3963             {
3964                 int nObject = gHitInfo.hitsprite;
3965                 dassert(nObject >= 0 && nObject < kMaxSprites);
3966                 spritetype *pObject = &sprite[nObject];
3967                 int nOwner = actSpriteOwnerToSpriteId(pMissile);
3968                 int nDamage = (15+Random(10))<<4;
3969                 actDamageSprite(nOwner, pObject, kDamageTesla, nDamage);
3970             }
3971             break;
3972         default:
3973             seqKill(3, nXMissile);
3974             actPostSprite(pMissile->index, kStatFree);
3975             if (hitCode == 3)
3976             {
3977                 int nObject = gHitInfo.hitsprite;
3978                 dassert(nObject >= 0 && nObject < kMaxSprites);
3979                 spritetype *pObject = &sprite[nObject];
3980                 int nOwner = actSpriteOwnerToSpriteId(pMissile);
3981                 int nDamage = (10+Random(10))<<4;
3982                 actDamageSprite(nOwner, pObject, kDamageFall, nDamage);
3983             }
3984             break;
3985     }
3986 
3987     #ifdef NOONE_EXTENSIONS
3988     if (gModernMap && pXSpriteHit && pXSpriteHit->state != pXSpriteHit->restState && pXSpriteHit->Impact)
3989         trTriggerSprite(nSpriteHit, pXSpriteHit, kCmdSpriteImpact);
3990     #endif
3991     pMissile->cstat &= ~257;
3992 }
3993 
actKickObject(spritetype * pSprite1,spritetype * pSprite2)3994 void actKickObject(spritetype *pSprite1, spritetype *pSprite2)
3995 {
3996     int nSprite1 = pSprite1->index;
3997     int nSprite2 = pSprite2->index;
3998     int nSpeed = ClipLow(approxDist(xvel[nSprite1], yvel[nSprite1])*2, 0xaaaaa);
3999     xvel[nSprite2] = mulscale30(nSpeed, Cos(pSprite1->ang+Random2(85)));
4000     yvel[nSprite2] = mulscale30(nSpeed, Sin(pSprite1->ang+Random2(85)));
4001     zvel[nSprite2] = mulscale(nSpeed, -0x2000, 14);
4002     pSprite2->flags = 7;
4003 }
4004 
actTouchFloor(spritetype * pSprite,int nSector)4005 void actTouchFloor(spritetype *pSprite, int nSector)
4006 {
4007     dassert(pSprite != NULL);
4008     dassert(nSector >= 0 && nSector < kMaxSectors);
4009     sectortype * pSector = &sector[nSector];
4010     XSECTOR * pXSector = NULL;
4011     if (pSector->extra > 0)
4012         pXSector = &xsector[pSector->extra];
4013 
4014     bool doDamage = (pXSector && (pSector->type == kSectorDamage || pXSector->damageType > 0));
4015     // don't allow damage for damage sectors if they are not enabled
4016     #ifdef NOONE_EXTENSIONS
4017     if (gModernMap && doDamage && pSector->type == kSectorDamage && !pXSector->state)
4018         doDamage = false;
4019     #endif
4020 
4021     if (doDamage) {
4022         DAMAGE_TYPE nDamageType;
4023 
4024         if (pSector->type == kSectorDamage)
4025             nDamageType = (DAMAGE_TYPE)ClipRange(pXSector->damageType, kDamageFall, kDamageTesla);
4026         else
4027             nDamageType = (DAMAGE_TYPE)ClipRange(pXSector->damageType - 1, kDamageFall, kDamageTesla);
4028         int nDamage;
4029         if (pXSector->data)
4030             nDamage = ClipRange(pXSector->data, 0, 1000);
4031         else
4032             nDamage = 1000;
4033         actDamageSprite(pSprite->index, pSprite, nDamageType, scale(4, nDamage, 120) << 4);
4034     }
4035     if (tileGetSurfType(nSector + 0x4000) == kSurfLava)
4036     {
4037         actDamageSprite(pSprite->index, pSprite, kDamageBurn, 16);
4038         sfxPlay3DSound(pSprite, 352, 5, 2);
4039     }
4040 }
4041 
ProcessTouchObjects(spritetype * pSprite,int nXSprite)4042 void ProcessTouchObjects(spritetype *pSprite, int nXSprite)
4043 {
4044     int nSprite = pSprite->index;
4045     XSPRITE *pXSprite = &xsprite[nXSprite];
4046     SPRITEHIT *pSpriteHit = &gSpriteHit[nXSprite];
4047     PLAYER *pPlayer = NULL;
4048     if (IsPlayerSprite(pSprite))
4049         pPlayer = &gPlayer[pSprite->type-kDudePlayer1];
4050     int nHitSprite = pSpriteHit->ceilhit & 0x3fff;
4051     switch (pSpriteHit->ceilhit&0xc000)
4052     {
4053     case 0x8000:
4054         break;
4055     case 0xc000:
4056         if (sprite[nHitSprite].extra > 0)
4057         {
4058             spritetype *pSprite2 = &sprite[nHitSprite];
4059             XSPRITE *pXSprite2 = &xsprite[pSprite2->extra];
4060             if ((pSprite2->statnum == kStatThing || pSprite2->statnum == kStatDude) && (xvel[nSprite] != 0 || yvel[nSprite] != 0 || zvel[nSprite] != 0))
4061             {
4062                 if (pSprite2->statnum == kStatThing)
4063                 {
4064                     int nType = pSprite2->type-kThingBase;
4065                     THINGINFO *pThingInfo = &thingInfo[nType];
4066                     if (pThingInfo->flags&1)
4067 
4068                         pSprite2->flags |= 1;
4069                     if (pThingInfo->flags&2)
4070 
4071                         pSprite2->flags |= 4;
4072                     // Inlined ?
4073                     xvel[pSprite2->index] += mulscale(4, pSprite2->x-sprite[nSprite].x, 2);
4074                     yvel[pSprite2->index] += mulscale(4, pSprite2->y-sprite[nSprite].y, 2);
4075                 }
4076                 else
4077                 {
4078 
4079                     pSprite2->flags |= 5;
4080                     xvel[pSprite2->index] += mulscale(4, pSprite2->x-sprite[nSprite].x, 2);
4081                     yvel[pSprite2->index] += mulscale(4, pSprite2->y-sprite[nSprite].y, 2);
4082 
4083                     #ifdef NOONE_EXTENSIONS
4084                     // add size shroom abilities
4085                     if ((IsPlayerSprite(pSprite) && isShrinked(pSprite)) || (IsPlayerSprite(pSprite2) && isGrown(pSprite2))) {
4086 
4087                         int mass1 = getDudeInfo(pSprite2->type)->mass;
4088                         int mass2 = getDudeInfo(pSprite->type)->mass;
4089                         switch (pSprite->type) {
4090                             case kDudeModernCustom:
4091                             case kDudeModernCustomBurning:
4092                                 mass2 = getSpriteMassBySize(pSprite);
4093                                 break;
4094                         }
4095                         if (mass1 > mass2) {
4096                             int dmg = abs((mass1 - mass2) * (pSprite2->clipdist - pSprite->clipdist));
4097                             if (IsDudeSprite(pSprite2)) {
4098                                 if (dmg > 0)
4099                                     actDamageSprite(pSprite2->index, pSprite, (Chance(0x2000)) ? kDamageFall : (Chance(0x4000)) ? kDamageExplode : kDamageBullet, dmg);
4100 
4101                                 if (Chance(0x0200))
4102                                     actKickObject(pSprite2, pSprite);
4103                             }
4104                         }
4105                     }
4106                     #endif
4107                     if (!IsPlayerSprite(pSprite) || gPlayer[pSprite->type - kDudePlayer1].godMode == 0) {
4108                         switch (pSprite2->type) {
4109                             case kDudeTchernobog:
4110                                 actDamageSprite(pSprite2->index, pSprite, kDamageExplode, pXSprite->health << 2);
4111                                 break;
4112                             #ifdef NOONE_EXTENSIONS
4113                             case kDudeModernCustom:
4114                             case kDudeModernCustomBurning:
4115                                 int dmg = 0;
4116                                 if (!IsDudeSprite(pSprite) || (dmg = ClipLow((getSpriteMassBySize(pSprite2) - getSpriteMassBySize(pSprite)) >> 1, 0)) == 0)
4117                                     break;
4118 
4119                                 if (!IsPlayerSprite(pSprite)) {
4120                                     actDamageSprite(pSprite2->index, pSprite, kDamageFall, dmg);
4121                                     if (xspriRangeIsFine(pSprite->extra) && !isActive(pSprite->index))
4122                                         aiActivateDude(pSprite, &xsprite[pSprite->extra]);
4123                                 }
4124                                 else if (powerupCheck(&gPlayer[pSprite->type - kDudePlayer1], kPwUpJumpBoots) > 0) actDamageSprite(pSprite2->index, pSprite, kDamageExplode, dmg);
4125                                 else actDamageSprite(pSprite2->index, pSprite, kDamageFall, dmg);
4126                                 break;
4127                             #endif
4128 
4129                         }
4130 
4131                     }
4132                 }
4133             }
4134 
4135             if (pSprite2->type == kTrapSawCircular) {
4136                 if (!pXSprite2->state) actDamageSprite(nSprite, pSprite, kDamageBullet, 1);
4137                 else {
4138                     pXSprite2->data1 = 1;
4139                     pXSprite2->data2 = ClipHigh(pXSprite2->data2+8, 600);
4140                     actDamageSprite(nSprite, pSprite, kDamageBullet, 16);
4141                 }
4142             }
4143 
4144         }
4145         break;
4146     }
4147     nHitSprite = pSpriteHit->hit & 0x3fff;
4148     switch (pSpriteHit->hit&0xc000)
4149     {
4150     case 0x8000:
4151         break;
4152     case 0xc000:
4153         if (sprite[nHitSprite].extra > 0)
4154         {
4155             spritetype *pSprite2 = &sprite[nHitSprite];
4156             //XSPRITE *pXSprite2 = &Xsprite[pSprite2->extra];
4157 
4158             #ifdef NOONE_EXTENSIONS
4159             // add size shroom abilities
4160             if ((IsPlayerSprite(pSprite2) && isShrinked(pSprite2)) || (IsPlayerSprite(pSprite) && isGrown(pSprite))) {
4161                 if (xvel[pSprite->xvel] != 0 && IsDudeSprite(pSprite2)) {
4162                     int mass1 = getDudeInfo(pSprite->type)->mass;
4163                     int mass2 = getDudeInfo(pSprite2->type)->mass;
4164                     switch (pSprite2->type) {
4165                         case kDudeModernCustom:
4166                         case kDudeModernCustomBurning:
4167                             mass2 = getSpriteMassBySize(pSprite2);
4168                             break;
4169                     }
4170                     if (mass1 > mass2) {
4171                         actKickObject(pSprite, pSprite2);
4172                         sfxPlay3DSound(pSprite, 357, -1, 1);
4173                         int dmg = (mass1 - mass2) + abs(xvel[pSprite->index] >> 16);
4174                         if (dmg > 0)
4175                             actDamageSprite(nSprite, pSprite2, (Chance(0x2000)) ? kDamageFall : kDamageBullet, dmg);
4176                     }
4177                 }
4178             }
4179             #endif
4180 
4181             switch (pSprite2->type) {
4182                 case kThingKickablePail:
4183                     actKickObject(pSprite, pSprite2);
4184                     break;
4185                 case kThingZombieHead:
4186                     sfxPlay3DSound(pSprite->x, pSprite->y, pSprite->z, 357, pSprite->sectnum);
4187                     actKickObject(pSprite, pSprite2);
4188                     actDamageSprite(-1, pSprite2, kDamageFall, 80);
4189                     break;
4190                 case kDudeBurningInnocent:
4191                 case kDudeBurningCultist:
4192                 case kDudeBurningZombieAxe:
4193                 case kDudeBurningZombieButcher:
4194                     // This does not make sense
4195                     pXSprite->burnTime = ClipLow(pXSprite->burnTime-4, 0);
4196                     actDamageSprite(actOwnerIdToSpriteId(pXSprite->burnSource), pSprite, kDamageBurn, 8);
4197                     break;
4198             }
4199         }
4200         break;
4201     }
4202     nHitSprite = pSpriteHit->florhit & 0x3fff;
4203     switch (pSpriteHit->florhit & 0xc000) {
4204     case 0x8000:
4205         break;
4206     case 0x4000:
4207         actTouchFloor(pSprite, nHitSprite);
4208         break;
4209     case 0xc000:
4210         if (sprite[nHitSprite].extra > 0)
4211         {
4212             spritetype *pSprite2 = &sprite[nHitSprite];
4213             XSPRITE *pXSprite2 = &xsprite[pSprite2->extra];
4214 
4215             #ifdef NOONE_EXTENSIONS
4216             // add size shroom abilities
4217             if ((IsPlayerSprite(pSprite2) && isShrinked(pSprite2)) || (IsPlayerSprite(pSprite) && isGrown(pSprite))) {
4218 
4219                 int mass1 = getDudeInfo(pSprite->type)->mass;
4220                 int mass2 = getDudeInfo(pSprite2->type)->mass;
4221                 switch (pSprite2->type) {
4222                     case kDudeModernCustom:
4223                     case kDudeModernCustomBurning:
4224                         mass2 = getSpriteMassBySize(pSprite2);
4225                         break;
4226                 }
4227                 if (mass1 > mass2 && IsDudeSprite(pSprite2)) {
4228                     if ((IsPlayerSprite(pSprite2) && Chance(0x500)) || !IsPlayerSprite(pSprite2))
4229                         actKickObject(pSprite, pSprite2);
4230 
4231                     int dmg = (mass1 - mass2) + pSprite->clipdist;
4232                     if (dmg > 0)
4233                         actDamageSprite(nSprite, pSprite2, (Chance(0x2000)) ? kDamageFall : kDamageBullet, dmg);
4234                 }
4235             }
4236             #endif
4237 
4238             switch (pSprite2->type) {
4239             case kThingKickablePail:
4240                 if (pPlayer) {
4241                     if (pPlayer->kickPower > gFrameClock) return;
4242                     pPlayer->kickPower = (int)gFrameClock+60;
4243                 }
4244                 actKickObject(pSprite, pSprite2);
4245                 sfxPlay3DSound(pSprite->x, pSprite->y, pSprite->z, 357, pSprite->sectnum);
4246                 sfxPlay3DSound(pSprite, 374, 0, 0);
4247                 break;
4248             case kThingZombieHead:
4249                 if (pPlayer) {
4250                     if (pPlayer->kickPower > gFrameClock) return;
4251                     pPlayer->kickPower = (int)gFrameClock+60;
4252                 }
4253                 actKickObject(pSprite, pSprite2);
4254                 sfxPlay3DSound(pSprite->x, pSprite->y, pSprite->z, 357, pSprite->sectnum);
4255                 actDamageSprite(-1, pSprite2, kDamageFall, 80);
4256                 break;
4257             case kTrapSawCircular:
4258                 if (!pXSprite2->state) actDamageSprite(nSprite, pSprite, kDamageBullet, 1);
4259                 else {
4260                     pXSprite2->data1 = 1;
4261                     pXSprite2->data2 = ClipHigh(pXSprite2->data2+8, 600);
4262                     actDamageSprite(nSprite, pSprite, kDamageBullet, 16);
4263                 }
4264                 break;
4265             case kDudeCultistTommy:
4266             case kDudeCultistShotgun:
4267             case kDudeZombieAxeNormal:
4268             case kDudeZombieButcher:
4269             case kDudeZombieAxeBuried:
4270             case kDudeGargoyleFlesh:
4271             case kDudeGargoyleStone:
4272             case kDudePhantasm:
4273             case kDudeHellHound:
4274             case kDudeHand:
4275             case kDudeSpiderBrown:
4276             case kDudeSpiderRed:
4277             case kDudeSpiderBlack:
4278             case kDudeGillBeast:
4279             case kDudeBat:
4280             case kDudeRat:
4281             case kDudePodGreen:
4282             case kDudeTentacleGreen:
4283             case kDudePodFire:
4284             case kDudeTentacleFire:
4285             case kDudePodMother:
4286             case kDudeTentacleMother:
4287             case kDudeCerberusTwoHead:
4288             case kDudeCerberusOneHead:
4289             case kDudeTchernobog:
4290             case kDudePlayer1:
4291             case kDudePlayer2:
4292             case kDudePlayer3:
4293             case kDudePlayer4:
4294             case kDudePlayer5:
4295             case kDudePlayer6:
4296             case kDudePlayer7:
4297             case kDudePlayer8:
4298             #ifdef NOONE_EXTENSIONS
4299                 if (pPlayer && !isShrinked(pSprite))
4300             #else
4301                 if (pPlayer)
4302             #endif
4303                 actDamageSprite(nSprite, pSprite2,kDamageBullet, 8);
4304                 break;
4305             }
4306         }
4307         break;
4308     }
4309 
4310     #ifdef NOONE_EXTENSIONS
4311     // add more trigger statements for Touch flag
4312     if (gModernMap && IsDudeSprite(pSprite)) {
4313 
4314         // Touch sprites
4315         int nHSprite = -1;
4316         if ((gSpriteHit[nXSprite].hit & 0xc000) == 0xc000)
4317             nHSprite = gSpriteHit[nXSprite].hit & 0x3fff;
4318         else if ((gSpriteHit[nXSprite].florhit & 0xc000) == 0xc000)
4319             nHSprite = gSpriteHit[nXSprite].florhit & 0x3fff;
4320         else if ((gSpriteHit[nXSprite].ceilhit & 0xc000) == 0xc000)
4321             nHSprite = gSpriteHit[nXSprite].ceilhit & 0x3fff;
4322 
4323         if (spriRangeIsFine(nHSprite) && xspriRangeIsFine(sprite[nHSprite].extra)) {
4324             XSPRITE* pXHSprite = &xsprite[sprite[nHSprite].extra];
4325             if (pXHSprite->Touch && !pXHSprite->isTriggered && (!pXHSprite->DudeLockout || IsPlayerSprite(pSprite)))
4326                 trTriggerSprite(nHSprite, pXHSprite, kCmdSpriteTouch);
4327         }
4328 
4329         // Touch walls
4330         int nHWall = -1;
4331         if ((gSpriteHit[nXSprite].hit & 0xc000) == 0x8000) {
4332             nHWall = gSpriteHit[nXSprite].hit & 0x3fff;
4333             if (wallRangeIsFine(nHWall) && xwallRangeIsFine(wall[nHWall].extra)) {
4334                 XWALL* pXHWall = &xwall[wall[nHWall].extra];
4335                 if (pXHWall->triggerTouch && !pXHWall->isTriggered && (!pXHWall->dudeLockout || IsPlayerSprite(pSprite)))
4336                     trTriggerWall(nHWall, pXHWall, kCmdWallTouch);
4337             }
4338         }
4339 
4340         // enough to reset gSpriteHit values
4341         if (nHWall != -1 || nHSprite != -1) xvel[nSprite] += 5;
4342 
4343     }
4344     #endif
4345 }
4346 
actAirDrag(spritetype * pSprite,int a2)4347 void actAirDrag(spritetype *pSprite, int a2)
4348 {
4349     int vbp = 0;
4350     int v4 = 0;
4351     int nSector = pSprite->sectnum;
4352     dassert(nSector >= 0 && nSector < kMaxSectors);
4353     sectortype *pSector = &sector[nSector];
4354     int nXSector = pSector->extra;
4355     if (nXSector > 0)
4356     {
4357         dassert(nXSector < kMaxXSectors);
4358         XSECTOR *pXSector = &xsector[nXSector];
4359         if (pXSector->windVel && (pXSector->windAlways || pXSector->busy))
4360         {
4361             int vcx = pXSector->windVel<<12;
4362             if (!pXSector->windAlways && pXSector->busy)
4363                 vcx = mulscale16(vcx, pXSector->busy);
4364             vbp = mulscale30(vcx, Cos(pXSector->windAng));
4365             v4 = mulscale30(vcx, Sin(pXSector->windAng));
4366         }
4367     }
4368     xvel[pSprite->index] += mulscale16(vbp-xvel[pSprite->index], a2);
4369     yvel[pSprite->index] += mulscale16(v4-yvel[pSprite->index], a2);
4370     zvel[pSprite->index] -= mulscale16(zvel[pSprite->index], a2);
4371 }
4372 
MoveThing(spritetype * pSprite)4373 int MoveThing(spritetype *pSprite)
4374 {
4375     int nXSprite = pSprite->extra;
4376     dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
4377     XSPRITE *pXSprite = &xsprite[nXSprite];
4378     int nSprite = pSprite->index;
4379     int v8 = 0;
4380     dassert(pSprite->type >= kThingBase && pSprite->type < kThingMax);
4381     THINGINFO *pThingInfo = &thingInfo[pSprite->type-kThingBase];
4382     int nSector = pSprite->sectnum;
4383     dassert(nSector >= 0 && nSector < kMaxSectors);
4384     int top, bottom;
4385     GetSpriteExtents(pSprite, &top, &bottom);
4386     if (xvel[nSprite] || yvel[nSprite])
4387     {
4388         short bakCstat = pSprite->cstat;
4389         pSprite->cstat &= ~257;
4390         v8 = gSpriteHit[nXSprite].hit = ClipMove((int*)&pSprite->x, (int*)&pSprite->y, (int*)&pSprite->z, &nSector, xvel[nSprite]>>12, yvel[nSprite]>>12, pSprite->clipdist<<2, (pSprite->z-top)/4, (bottom-pSprite->z)/4, CLIPMASK0);
4391         pSprite->cstat = bakCstat;
4392         dassert(nSector >= 0);
4393         if (pSprite->sectnum != nSector)
4394         {
4395             dassert(nSector >= 0 && nSector < kMaxSectors);
4396             ChangeSpriteSect(nSprite, nSector);
4397         }
4398         if ((gSpriteHit[nXSprite].hit&0xc000) == 0x8000) {
4399             int nHitWall = gSpriteHit[nXSprite].hit&0x3fff;
4400             actWallBounceVector((int*)&xvel[nSprite], (int*)&yvel[nSprite], nHitWall, pThingInfo->elastic);
4401             switch (pSprite->type) {
4402                 case kThingZombieHead:
4403                     sfxPlay3DSound(pSprite, 607, 0, 0);
4404                     actDamageSprite(-1, pSprite, kDamageFall, 80);
4405                     break;
4406                 case kThingKickablePail:
4407                     sfxPlay3DSound(pSprite, 374, 0, 0);
4408                     break;
4409             }
4410         }
4411     }
4412     else
4413     {
4414         dassert(nSector >= 0 && nSector < kMaxSectors);
4415         FindSector(pSprite->x, pSprite->y, pSprite->z, &nSector);
4416     }
4417     if (zvel[nSprite])
4418         pSprite->z += zvel[nSprite]>>8;
4419     int ceilZ, ceilHit, floorZ, floorHit;
4420     GetZRange(pSprite, &ceilZ, &ceilHit, &floorZ, &floorHit, pSprite->clipdist<<2, CLIPMASK0);
4421     GetSpriteExtents(pSprite, &top, &bottom);
4422     if ((pSprite->flags & 2) && bottom < floorZ)
4423     {
4424         pSprite->z += 455;
4425         zvel[nSprite] += 58254;
4426         if (pSprite->type == kThingZombieHead)
4427         {
4428             spritetype *pFX = gFX.fxSpawn(FX_27, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
4429             if (pFX)
4430             {
4431                 int v34 = ((int)gFrameClock*3)&2047;
4432                 int v30 = ((int)gFrameClock*5)&2047;
4433                 int vbx = ((int)gFrameClock*11)&2047;
4434                 int v2c = 0x44444;
4435                 int v28 = 0;
4436                 int v24 = 0;
4437                 RotateVector(&v2c,&v28,vbx);
4438                 RotateVector(&v2c,&v24,v30);
4439                 RotateVector(&v28,&v24,v34);
4440                 xvel[pFX->index] = xvel[pSprite->index]+v2c;
4441                 yvel[pFX->index] = yvel[pSprite->index]+v28;
4442                 zvel[pFX->index] = zvel[pSprite->index]+v24;
4443             }
4444         }
4445     }
4446     if (CheckLink(pSprite))
4447         GetZRange(pSprite, &ceilZ, &ceilHit, &floorZ, &floorHit, pSprite->clipdist<<2, CLIPMASK0);
4448     GetSpriteExtents(pSprite, &top, &bottom);
4449     if (bottom >= floorZ)
4450     {
4451         actTouchFloor(pSprite, pSprite->sectnum);
4452         gSpriteHit[nXSprite].florhit = floorHit;
4453         pSprite->z += floorZ-bottom;
4454         int v20 = zvel[nSprite]-velFloor[pSprite->sectnum];
4455         if (v20 > 0)
4456         {
4457 
4458             pSprite->flags |= 4;
4459             int vax = actFloorBounceVector((int*)&xvel[nSprite], (int*)&yvel[nSprite], (int*)&v20, pSprite->sectnum, pThingInfo->elastic);
4460             int nDamage = mulscale(vax, vax, 30)-pThingInfo->dmgResist;
4461             if (nDamage > 0)
4462                 actDamageSprite(nSprite, pSprite, kDamageFall, nDamage);
4463             zvel[nSprite] = v20;
4464             if (velFloor[pSprite->sectnum] == 0 && klabs(zvel[nSprite]) < 0x10000)
4465             {
4466                 zvel[nSprite] = 0;
4467 
4468                 pSprite->flags &= ~4;
4469             }
4470 
4471             switch (pSprite->type) {
4472                 case kThingNapalmBall:
4473                     if (zvel[nSprite] == 0 || Chance(0xA000)) sub_2AA94(pSprite, pXSprite);
4474                     break;
4475                 case kThingZombieHead:
4476                     if (klabs(zvel[nSprite]) > 0x80000) {
4477                         sfxPlay3DSound(pSprite, 607, 0, 0);
4478                         actDamageSprite(-1, pSprite, kDamageFall, 80);
4479                     }
4480                     break;
4481                 case kThingKickablePail:
4482                     if (klabs(zvel[nSprite]) > 0x80000)
4483                         sfxPlay3DSound(pSprite, 374, 0, 0);
4484                     break;
4485             }
4486 
4487             v8 = 0x4000|nSector;
4488         }
4489         else if (zvel[nSprite] == 0)
4490 
4491             pSprite->flags &= ~4;
4492     }
4493     else
4494     {
4495         gSpriteHit[nXSprite].florhit = 0;
4496 
4497         if (pSprite->flags&2)
4498             pSprite->flags |= 4;
4499     }
4500     if (top <= ceilZ)
4501     {
4502         gSpriteHit[nXSprite].ceilhit = ceilHit;
4503         pSprite->z += ClipLow(ceilZ-top, 0);
4504         if (zvel[nSprite] < 0)
4505         {
4506             xvel[nSprite] = mulscale16(xvel[nSprite], 0xc000);
4507             yvel[nSprite] = mulscale16(yvel[nSprite], 0xc000);
4508             zvel[nSprite] = mulscale16(-zvel[nSprite], 0x4000);
4509             switch (pSprite->type) {
4510                 case kThingZombieHead:
4511                     if (klabs(zvel[nSprite]) > 0x80000) {
4512                         sfxPlay3DSound(pSprite, 607, 0, 0);
4513                         actDamageSprite(-1, pSprite, kDamageFall, 80);
4514                     }
4515                     break;
4516                 case kThingKickablePail:
4517                     if (klabs(zvel[nSprite]) > 0x80000)
4518                         sfxPlay3DSound(pSprite, 374, 0, 0);
4519                     break;
4520             }
4521         }
4522     }
4523     else
4524         gSpriteHit[nXSprite].ceilhit = 0;
4525     if (bottom >= floorZ)
4526     {
4527         int nVel = approxDist(xvel[nSprite], yvel[nSprite]);
4528         int nVelClipped = ClipHigh(nVel, 0x11111);
4529         if ((floorHit & 0xc000) == 0xc000)
4530         {
4531             int nHitSprite = floorHit & 0x3fff;
4532             if ((sprite[nHitSprite].cstat & 0x30) == 0)
4533             {
4534                 xvel[nSprite] += mulscale(4, pSprite->x - sprite[nHitSprite].x, 2);
4535                 yvel[nSprite] += mulscale(4, pSprite->y - sprite[nHitSprite].y, 2);
4536                 v8 = gSpriteHit[nXSprite].hit;
4537             }
4538         }
4539         if (nVel > 0)
4540         {
4541             int t = divscale16(nVelClipped, nVel);
4542             xvel[nSprite] -= mulscale16(t, xvel[nSprite]);
4543             yvel[nSprite] -= mulscale16(t, yvel[nSprite]);
4544         }
4545     }
4546     if (xvel[nSprite] || yvel[nSprite])
4547         pSprite->ang = getangle(xvel[nSprite], yvel[nSprite]);
4548     return v8;
4549 }
4550 
MoveDude(spritetype * pSprite)4551 void MoveDude(spritetype *pSprite)
4552 {
4553     int nXSprite = pSprite->extra;
4554     XSPRITE *pXSprite = &xsprite[nXSprite];
4555     int nSprite = pSprite->index;
4556     PLAYER *pPlayer = NULL;
4557     if (IsPlayerSprite(pSprite))
4558         pPlayer = &gPlayer[pSprite->type-kDudePlayer1];
4559     if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax)) {
4560         consoleSysMsg("pSprite->type >= kDudeBase && pSprite->type < kDudeMax");
4561         return;
4562     }
4563     DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
4564     int top, bottom;
4565     GetSpriteExtents(pSprite, &top, &bottom);
4566     int bz = (bottom-pSprite->z)/4;
4567     int tz = (pSprite->z-top)/4;
4568     int wd = pSprite->clipdist<<2;
4569     int nSector = pSprite->sectnum;
4570     dassert(nSector >= 0 && nSector < kMaxSectors);
4571     if (xvel[nSprite] || yvel[nSprite])
4572     {
4573         if (pPlayer && gNoClip)
4574         {
4575             pSprite->x += xvel[nSprite]>>12;
4576             pSprite->y += yvel[nSprite]>>12;
4577             if (!FindSector(pSprite->x, pSprite->y, &nSector))
4578                 nSector = pSprite->sectnum;
4579         }
4580         else
4581         {
4582             short bakCstat = pSprite->cstat;
4583             pSprite->cstat &= ~257;
4584             gSpriteHit[nXSprite].hit = ClipMove((int*)&pSprite->x, (int*)&pSprite->y, (int*)&pSprite->z, &nSector, xvel[nSprite]>>12, yvel[nSprite]>>12, wd, tz, bz, CLIPMASK0);
4585             if (nSector == -1)
4586             {
4587                 nSector = pSprite->sectnum;
4588                 if (pSprite->statnum == kStatDude || pSprite->statnum == kStatThing)
4589                     actDamageSprite(pSprite->index, pSprite, kDamageFall, 1000<<4);
4590             }
4591 
4592             if (sector[nSector].type >= kSectorPath && sector[nSector].type <= kSectorRotate)
4593             {
4594                 short nSector2 = nSector;
4595                 if (pushmove_old(&pSprite->x, &pSprite->y, &pSprite->z, &nSector2, wd, tz, bz, CLIPMASK0) == -1)
4596                     actDamageSprite(nSprite, pSprite, kDamageFall, 1000 << 4);
4597                 if (nSector2 != -1)
4598                     nSector = nSector2;
4599             }
4600             dassert(nSector >= 0);
4601             pSprite->cstat = bakCstat;
4602         }
4603         switch (gSpriteHit[nXSprite].hit&0xc000)
4604         {
4605         case 0xc000:
4606         {
4607             int nHitSprite = gSpriteHit[nXSprite].hit&0x3fff;
4608             spritetype *pHitSprite = &sprite[nHitSprite];
4609             XSPRITE *pHitXSprite = NULL;
4610             // Should be pHitSprite here
4611             if (pSprite->extra > 0)
4612                 pHitXSprite = &xsprite[pHitSprite->extra];
4613             int nOwner = actSpriteOwnerToSpriteId(pHitSprite);
4614 
4615             if (pHitSprite->statnum == kStatProjectile && !(pHitSprite->flags&32) && pSprite->index != nOwner)
4616             {
4617                 HITINFO hitInfo = gHitInfo;
4618                 gHitInfo.hitsprite = nSprite;
4619                 actImpactMissile(pHitSprite, 3);
4620                 gHitInfo = hitInfo;
4621             }
4622             #ifdef NOONE_EXTENSIONS
4623             if (!gModernMap && pHitXSprite && pHitXSprite->Touch && !pHitXSprite->state && !pHitXSprite->isTriggered)
4624                 trTriggerSprite(nHitSprite, pHitXSprite, kCmdSpriteTouch);
4625             #else
4626                 if (pHitXSprite && pHitXSprite->Touch && !pHitXSprite->state && !pHitXSprite->isTriggered)
4627                     trTriggerSprite(nHitSprite, pHitXSprite, kCmdSpriteTouch);
4628             #endif
4629 
4630             if (pDudeInfo->lockOut && pHitXSprite && pHitXSprite->Push && !pHitXSprite->key && !pHitXSprite->DudeLockout && !pHitXSprite->state && !pHitXSprite->busy && !pPlayer)
4631                 trTriggerSprite(nHitSprite, pHitXSprite, kCmdSpritePush);
4632 
4633             break;
4634         }
4635         case 0x8000:
4636         {
4637             int nHitWall = gSpriteHit[nXSprite].hit&0x3fff;
4638             walltype *pHitWall = &wall[nHitWall];
4639             XWALL *pHitXWall = NULL;
4640             if (pHitWall->extra > 0)
4641                 pHitXWall = &xwall[pHitWall->extra];
4642             if (pDudeInfo->lockOut && pHitXWall && pHitXWall->triggerPush && !pHitXWall->key && !pHitXWall->dudeLockout && !pHitXWall->state && !pHitXWall->busy && !pPlayer)
4643                 trTriggerWall(nHitWall, pHitXWall, kCmdWallPush);
4644             if (pHitWall->nextsector != -1)
4645             {
4646                 sectortype *pHitSector = &sector[pHitWall->nextsector];
4647                 XSECTOR *pHitXSector = NULL;
4648                 if (pHitSector->extra > 0)
4649                     pHitXSector = &xsector[pHitSector->extra];
4650                 if (pDudeInfo->lockOut && pHitXSector && pHitXSector->Wallpush && !pHitXSector->Key && !pHitXSector->dudeLockout && !pHitXSector->state && !pHitXSector->busy && !pPlayer)
4651                     trTriggerSector(pHitWall->nextsector, pHitXSector, kCmdSectorPush);
4652                 if (top < pHitSector->ceilingz || bottom > pHitSector->floorz)
4653                 {
4654                     // ???
4655                 }
4656             }
4657             actWallBounceVector((int*)&xvel[nSprite], (int*)&yvel[nSprite], nHitWall, 0);
4658             break;
4659         }
4660         }
4661     }
4662     else
4663     {
4664         dassert(nSector >= 0 && nSector < kMaxSectors);
4665         FindSector(pSprite->x, pSprite->y, pSprite->z, &nSector);
4666     }
4667     if (pSprite->sectnum != nSector)
4668     {
4669         dassert(nSector >= 0 && nSector < kMaxSectors);
4670         XSECTOR *pXSector;
4671         int nXSector = sector[pSprite->sectnum].extra;
4672         if (nXSector > 0)
4673             pXSector = &xsector[nXSector];
4674         else
4675             pXSector = NULL;
4676         if (pXSector && pXSector->Exit && (pPlayer || !pXSector->dudeLockout))
4677             trTriggerSector(pSprite->sectnum, pXSector, kCmdSectorExit);
4678         ChangeSpriteSect(nSprite, nSector);
4679 
4680         nXSector = sector[nSector].extra;
4681         pXSector = (nXSector > 0) ? &xsector[nXSector] : NULL;
4682         if (pXSector && pXSector->Enter && (pPlayer || !pXSector->dudeLockout)) {
4683 
4684             if (sector[nSector].type == kSectorTeleport)
4685                 pXSector->data = pPlayer ? nSprite : -1;
4686             trTriggerSector(nSector, pXSector, kCmdSectorEnter);
4687         }
4688 
4689         nSector = pSprite->sectnum;
4690     }
4691     char bUnderwater = 0;
4692     char bDepth = 0;
4693     if (sector[nSector].extra > 0)
4694     {
4695         XSECTOR *pXSector = &xsector[sector[nSector].extra];
4696         if (pXSector->Underwater)
4697             bUnderwater = 1;
4698         if (pXSector->Depth)
4699             bDepth = 1;
4700     }
4701     int nUpperLink = gUpperLink[nSector];
4702     int nLowerLink = gLowerLink[nSector];
4703     if (nUpperLink >= 0 && (sprite[nUpperLink].type == kMarkerUpWater || sprite[nUpperLink].type == kMarkerUpGoo))
4704         bDepth = 1;
4705     if (nLowerLink >= 0 && (sprite[nLowerLink].type == kMarkerLowWater || sprite[nLowerLink].type == kMarkerLowGoo))
4706         bDepth = 1;
4707     if (pPlayer)
4708         wd += 16;
4709     if (zvel[nSprite])
4710         pSprite->z += zvel[nSprite]>>8;
4711     int ceilZ, ceilHit, floorZ, floorHit;
4712     GetZRange(pSprite, &ceilZ, &ceilHit, &floorZ, &floorHit, wd, CLIPMASK0, PARALLAXCLIP_CEILING|PARALLAXCLIP_FLOOR);
4713     GetSpriteExtents(pSprite, &top, &bottom);
4714 
4715     if (pSprite->flags & 2)
4716     {
4717         int vc = 58254;
4718         if (bDepth)
4719         {
4720             if (bUnderwater)
4721             {
4722                 int cz = getceilzofslope(nSector, pSprite->x, pSprite->y);
4723                 if (cz > top)
4724                     vc += ((bottom-cz)*-80099) / (bottom-top);
4725                 else
4726                     vc = 0;
4727             }
4728             else
4729             {
4730                 int fz = getflorzofslope(nSector, pSprite->x, pSprite->y);
4731                 if (fz < bottom)
4732                     vc += ((bottom-fz)*-80099) / (bottom-top);
4733             }
4734         }
4735         else
4736         {
4737             if (bUnderwater)
4738                 vc = 0;
4739             else if (bottom >= floorZ)
4740                 vc =  0;
4741         }
4742         if (vc)
4743         {
4744             pSprite->z += ((vc*4)/2)>>8;
4745             zvel[nSprite] += vc;
4746         }
4747     }
4748     if (pPlayer && zvel[nSprite] > 0x155555 && !pPlayer->fallScream && pXSprite->height > 0)
4749     {
4750         pPlayer->fallScream = 1;
4751         sfxPlay3DSound(pSprite, 719, 0, 0);
4752     }
4753     vec3_t const oldpos = pSprite->pos;
4754     int nLink = CheckLink(pSprite);
4755     if (nLink)
4756     {
4757         GetZRange(pSprite, &ceilZ, &ceilHit, &floorZ, &floorHit, wd, CLIPMASK0, PARALLAXCLIP_CEILING|PARALLAXCLIP_FLOOR);
4758         if (pPlayer)
4759         {
4760             if (bVanilla)
4761                 playerResetInertia(pPlayer);
4762             else
4763                 playerCorrectInertia(pPlayer, &oldpos);
4764         }
4765         switch (nLink) {
4766         case kMarkerLowStack:
4767             if (pPlayer == gView)
4768                 SetBitString(gotpic, sector[pSprite->sectnum].floorpicnum);
4769             break;
4770         case kMarkerUpStack:
4771             if (pPlayer == gView)
4772                 SetBitString(gotpic, sector[pSprite->sectnum].ceilingpicnum);
4773             break;
4774         case kMarkerLowWater:
4775         case kMarkerLowGoo:
4776             pXSprite->medium = kMediumNormal;
4777             if (pPlayer) {
4778                 pPlayer->posture = 0;
4779                 pPlayer->bubbleTime = 0;
4780                 if (!pPlayer->cantJump && pPlayer->input.buttonFlags.jump) {
4781                     zvel[nSprite] = -0x6aaaa;
4782                     pPlayer->cantJump = 1;
4783                 }
4784                 sfxPlay3DSound(pSprite, 721, -1, 0);
4785             } else {
4786                 switch (pSprite->type) {
4787                     case kDudeCultistTommy:
4788                     case kDudeCultistShotgun:
4789                         aiNewState(pSprite, pXSprite, &cultistGoto);
4790                         break;
4791                     case kDudeGillBeast:
4792                         aiNewState(pSprite, pXSprite, &gillBeastGoto);
4793                         pSprite->flags |= 6;
4794                         break;
4795                     case kDudeBoneEel:
4796                         actKillDude(pSprite->index, pSprite, kDamageFall, 1000<<4);
4797                         break;
4798                 }
4799             }
4800             break;
4801         case kMarkerUpWater:
4802         case kMarkerUpGoo:
4803         {
4804             int chance = 0xa00; int medium = kMediumWater;
4805             if (nLink == kMarkerUpGoo){
4806                 medium = kMediumGoo;
4807                 chance = 0x400;
4808             }
4809 
4810             pXSprite->medium = medium;
4811 
4812             if (pPlayer)
4813             {
4814                 #ifdef NOONE_EXTENSIONS
4815                 // look for palette in data2 of marker. If value <= 0, use default ones.
4816                 pPlayer->nWaterPal = 0;
4817                 int nXUpper = sprite[gUpperLink[nSector]].extra;
4818                 if (nXUpper >= 0)
4819                     pPlayer->nWaterPal = xsprite[nXUpper].data2;
4820                 #endif
4821 
4822                 pPlayer->posture = 1;
4823                 pXSprite->burnTime = 0;
4824                 pPlayer->bubbleTime = klabs(zvel[nSprite]) >> 12;
4825                 evPost(nSprite, 3, 0, kCallbackPlayerBubble);
4826                 sfxPlay3DSound(pSprite, 720, -1, 0);
4827             }
4828             else
4829             {
4830                 switch (pSprite->type) {
4831                 case kDudeCultistTommy:
4832                 case kDudeCultistShotgun:
4833                     pXSprite->burnTime = 0;
4834                     evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4835                     sfxPlay3DSound(pSprite, 720, -1, 0);
4836                     aiNewState(pSprite, pXSprite, &cultistSwimGoto);
4837                     break;
4838                 case kDudeBurningCultist:
4839                 {
4840                     if (Chance(chance))
4841                     {
4842                         pSprite->type = kDudeCultistTommy;
4843                         pXSprite->burnTime = 0;
4844                         evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4845                         sfxPlay3DSound(pSprite, 720, -1, 0);
4846                         aiNewState(pSprite, pXSprite, &cultistSwimGoto);
4847                     }
4848                     else
4849                     {
4850                         pSprite->type = kDudeCultistShotgun;
4851                         pXSprite->burnTime = 0;
4852                         evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4853                         sfxPlay3DSound(pSprite, 720, -1, 0);
4854                         aiNewState(pSprite, pXSprite, &cultistSwimGoto);
4855                     }
4856                     break;
4857                 }
4858                 case kDudeZombieAxeNormal:
4859                     pXSprite->burnTime = 0;
4860                     evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4861                     sfxPlay3DSound(pSprite, 720, -1, 0);
4862                     aiNewState(pSprite, pXSprite, &zombieAGoto);
4863                     break;
4864                 case kDudeZombieButcher:
4865                     pXSprite->burnTime = 0;
4866                     evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4867                     sfxPlay3DSound(pSprite, 720, -1, 0);
4868                     aiNewState(pSprite, pXSprite, &zombieFGoto);
4869                     break;
4870                 case kDudeGillBeast:
4871                     pXSprite->burnTime = 0;
4872                     evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4873                     sfxPlay3DSound(pSprite, 720, -1, 0);
4874                     aiNewState(pSprite, pXSprite, &gillBeastSwimGoto);
4875 
4876                     pSprite->flags &= ~6;
4877                     break;
4878                 case kDudeGargoyleFlesh:
4879                 case kDudeHellHound:
4880                 case kDudeSpiderBrown:
4881                 case kDudeSpiderRed:
4882                 case kDudeSpiderBlack:
4883                 case kDudeBat:
4884                 case kDudeRat:
4885                 case kDudeBurningInnocent:
4886                     actKillDude(pSprite->index, pSprite, kDamageFall, 1000 << 4);
4887                     break;
4888                 #ifdef NOONE_EXTENSIONS
4889                 case kDudeModernCustom:
4890                     evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4891                     if (!canSwim(pSprite)) actKillDude(pSprite->index, pSprite, kDamageFall, 1000 << 4);
4892                     break;
4893                 #endif
4894                 }
4895 
4896             }
4897             break;
4898         }
4899         /*case 13:
4900             pXSprite->medium = kMediumGoo;
4901             if (pPlayer)
4902             {
4903                 pPlayer->changeTargetKin = 1;
4904                 pXSprite->burnTime = 0;
4905                 pPlayer->bubbleTime = klabs(zvel[nSprite])>>12;
4906                 evPost(nSprite, 3, 0, kCallbackPlayerBubble);
4907                 sfxPlay3DSound(pSprite, 720, -1, 0);
4908             }
4909             else
4910             {
4911                 switch (pSprite->type)
4912                 {
4913                 case kDudeCultistTommy:
4914                 case kDudeCultistShotgun:
4915                     pXSprite->burnTime = 0;
4916                     evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4917                     sfxPlay3DSound(pSprite, 720, -1, 0);
4918                     aiNewState(pSprite, pXSprite, &cultistSwimGoto);
4919                     break;
4920                 case kDudeBurningCultist:
4921                     if (Chance(0x400))
4922                     {
4923                         pSprite->type = kDudeCultistTommy;
4924                         pXSprite->burnTime = 0;
4925                         evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4926                         sfxPlay3DSound(pSprite, 720, -1, 0);
4927                         aiNewState(pSprite, pXSprite, &cultistSwimGoto);
4928                     }
4929                     else
4930                     {
4931                         pSprite->type = kDudeCultistShotgun;
4932                         pXSprite->burnTime = 0;
4933                         evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4934                         sfxPlay3DSound(pSprite, 720, -1, 0);
4935                         aiNewState(pSprite, pXSprite, &cultistSwimGoto);
4936                     }
4937                     break;
4938                 case kDudeZombieAxeNormal:
4939                     pXSprite->burnTime = 0;
4940                     evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4941                     sfxPlay3DSound(pSprite, 720, -1, 0);
4942                     aiNewState(pSprite, pXSprite, &zombieAGoto);
4943                     break;
4944                 case kDudeZombieButcher:
4945                     pXSprite->burnTime = 0;
4946                     evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4947                     sfxPlay3DSound(pSprite, 720, -1, 0);
4948                     aiNewState(pSprite, pXSprite, &zombieFGoto);
4949                     break;
4950                 case kDudeGillBeast:
4951                     pXSprite->burnTime = 0;
4952                     evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
4953                     sfxPlay3DSound(pSprite, 720, -1, 0);
4954                     aiNewState(pSprite, pXSprite, &gillBeastSwimGoto);
4955                     pSprite->flags &= ~6;
4956                     break;
4957                 case kDudeGargoyleFlesh:
4958                 case kDudeHellHound:
4959                 case kDudeSpiderBrown:
4960                 case kDudeSpiderRed:
4961                 case kDudeSpiderBlack:
4962                 case kDudeBat:
4963                 case kDudeRat:
4964                 case kDudeBurningInnocent:
4965                     actKillDude(pSprite->index, pSprite, kDamageFall, 1000<<4);
4966                     break;
4967                 }
4968             }
4969             break;*/
4970         }
4971     }
4972     GetSpriteExtents(pSprite, &top, &bottom);
4973     if (pPlayer && bottom >= floorZ)
4974     {
4975         int floorZ2 = floorZ;
4976         int floorHit2 = floorHit;
4977         GetZRange(pSprite, &ceilZ, &ceilHit, &floorZ, &floorHit, pSprite->clipdist<<2, CLIPMASK0, PARALLAXCLIP_CEILING|PARALLAXCLIP_FLOOR);
4978         if (bottom <= floorZ && pSprite->z - floorZ2 < bz)
4979         {
4980             floorZ = floorZ2;
4981             floorHit = floorHit2;
4982         }
4983     }
4984     if (floorZ <= bottom)
4985     {
4986         gSpriteHit[nXSprite].florhit = floorHit;
4987         pSprite->z += floorZ-bottom;
4988         int v30 = zvel[nSprite]-velFloor[pSprite->sectnum];
4989         if (v30 > 0)
4990         {
4991             int vax = actFloorBounceVector((int*)&xvel[nSprite], (int*)&yvel[nSprite], (int*)&v30, pSprite->sectnum, 0);
4992             int nDamage = mulscale(vax, vax, 30);
4993             if (pPlayer)
4994             {
4995                 pPlayer->fallScream = 0;
4996 
4997                 if (nDamage > (15<<4) && (pSprite->flags&4))
4998                     playerLandingSound(pPlayer);
4999                 if (nDamage > (30<<4))
5000                     sfxPlay3DSound(pSprite, 701, 0, 0);
5001             }
5002             nDamage -= 100<<4;
5003             if (nDamage > 0)
5004                 actDamageSprite(nSprite, pSprite, kDamageFall, nDamage);
5005             zvel[nSprite] = v30;
5006             if (klabs(zvel[nSprite]) < 0x10000)
5007             {
5008                 zvel[nSprite] = velFloor[pSprite->sectnum];
5009 
5010                 pSprite->flags &= ~4;
5011             }
5012             else
5013 
5014                 pSprite->flags |= 4;
5015             switch (tileGetSurfType(floorHit))
5016             {
5017             case kSurfWater:
5018                 gFX.fxSpawn(FX_9, pSprite->sectnum, pSprite->x, pSprite->y, floorZ, 0);
5019                 break;
5020             case kSurfLava:
5021             {
5022                 spritetype *pFX = gFX.fxSpawn(FX_10, pSprite->sectnum, pSprite->x, pSprite->y, floorZ, 0);
5023                 if (pFX)
5024                 {
5025                     for (int i = 0; i < 7; i++)
5026                     {
5027                         spritetype *pFX2 = gFX.fxSpawn(FX_14, pFX->sectnum, pFX->x, pFX->y, pFX->z, 0);
5028                         if (pFX2)
5029                         {
5030                             xvel[pFX2->index] = Random2(0x6aaaa);
5031                             yvel[pFX2->index] = Random2(0x6aaaa);
5032                             zvel[pFX2->index] = -Random(0xd5555);
5033                         }
5034                     }
5035                 }
5036                 break;
5037             }
5038             }
5039         }
5040         else if (zvel[nSprite] == 0)
5041 
5042             pSprite->flags &= ~4;
5043     }
5044     else
5045     {
5046         gSpriteHit[nXSprite].florhit = 0;
5047 
5048         if (pSprite->flags&2)
5049             pSprite->flags |= 4;
5050     }
5051     if (top <= ceilZ)
5052     {
5053         gSpriteHit[nXSprite].ceilhit = ceilHit;
5054         pSprite->z += ClipLow(ceilZ-top, 0);
5055 
5056         if (zvel[nSprite] <= 0 && (pSprite->flags&4))
5057             zvel[nSprite] = mulscale16(-zvel[nSprite], 0x2000);
5058     }
5059     else
5060         gSpriteHit[nXSprite].ceilhit = 0;
5061     GetSpriteExtents(pSprite,&top,&bottom);
5062 
5063     pXSprite->height = ClipLow(floorZ-bottom, 0)>>8;
5064     if (xvel[nSprite] || yvel[nSprite])
5065     {
5066         if ((floorHit & 0xc000) == 0xc000)
5067         {
5068             int nHitSprite = floorHit & 0x3fff;
5069             if ((sprite[nHitSprite].cstat & 0x30) == 0)
5070             {
5071                 xvel[nSprite] += mulscale(4, pSprite->x - sprite[nHitSprite].x, 2);
5072                 yvel[nSprite] += mulscale(4, pSprite->y - sprite[nHitSprite].y, 2);
5073                 return;
5074             }
5075         }
5076         int nXSector = sector[pSprite->sectnum].extra;
5077         if (nXSector > 0 && xsector[nXSector].Underwater)
5078             return;
5079         if (pXSprite->height >= 0x100)
5080             return;
5081         int nDrag = gDudeDrag;
5082         if (pXSprite->height > 0)
5083             nDrag -= scale(gDudeDrag, pXSprite->height, 0x100);
5084         xvel[nSprite] -= mulscale16r(xvel[nSprite], nDrag);
5085         yvel[nSprite] -= mulscale16r(yvel[nSprite], nDrag);
5086 
5087         if (approxDist(xvel[nSprite], yvel[nSprite]) < 0x1000)
5088             xvel[nSprite] = yvel[nSprite] = 0;
5089     }
5090 }
5091 
MoveMissile(spritetype * pSprite)5092 int MoveMissile(spritetype *pSprite)
5093 {
5094     int nXSprite = pSprite->extra;
5095     XSPRITE *pXSprite = &xsprite[nXSprite];
5096     int vdi = -1;
5097     spritetype *pOwner = NULL;
5098     int bakCstat = 0;
5099     if (pSprite->owner >= 0)
5100     {
5101         int nOwner = actSpriteOwnerToSpriteId(pSprite);
5102         pOwner = &sprite[nOwner];
5103         if (IsDudeSprite(pOwner))
5104         {
5105             bakCstat = pOwner->cstat;
5106             pOwner->cstat &= ~257;
5107         }
5108         else
5109             pOwner = NULL;
5110     }
5111     gHitInfo.hitsect = -1;
5112     gHitInfo.hitwall = -1;
5113     gHitInfo.hitsprite = -1;
5114     if (pSprite->type == kMissileFlameSpray)
5115         actAirDrag(pSprite, 0x1000);
5116     int nSprite = pSprite->index;
5117     if (pXSprite->target != -1 && (xvel[nSprite] || yvel[nSprite] || zvel[nSprite]))
5118     {
5119         spritetype *pTarget = &sprite[pXSprite->target];
5120         XSPRITE *pXTarget;
5121         if (pTarget->extra > 0)
5122             pXTarget = &xsprite[pTarget->extra];
5123         else
5124             pXTarget = NULL;
5125         if (pTarget->statnum == kStatDude && pXTarget && pXTarget->health > 0)
5126         {
5127             int nTargetAngle = getangle(-(pTarget->y-pSprite->y), pTarget->x-pSprite->x);
5128             int UNUSED(nAngle) = getangle(xvel[nSprite]>>12,yvel[nSprite]>>12);
5129             int vx = missileInfo[pSprite->type - kMissileBase].velocity;
5130             int vy = 0;
5131             RotatePoint(&vx, &vy, (nTargetAngle+1536)&2047, 0, 0);
5132             xvel[nSprite] = vx;
5133             yvel[nSprite] = vy;
5134             int dx = pTarget->x-pSprite->x;
5135             int dy = pTarget->y-pSprite->y;
5136             int dz = pTarget->z-pSprite->z;
5137             // Inlined
5138             int vax = dz/10;
5139             if (pTarget->z < pSprite->z)
5140                 vax = -vax;
5141             zvel[nSprite] += vax;
5142             ksqrt(dx*dx+dy*dy+dz*dz);
5143         }
5144     }
5145     int vx = xvel[nSprite]>>12;
5146     int vy = yvel[nSprite]>>12;
5147     int vz = zvel[nSprite]>>8;
5148     int top, bottom;
5149     GetSpriteExtents(pSprite, &top, &bottom);
5150     int i = 1;
5151     while (1)
5152     {
5153         int x = pSprite->x;
5154         int y = pSprite->y;
5155         int z = pSprite->z;
5156         int nSector2 = pSprite->sectnum;
5157         clipmoveboxtracenum = 1;
5158         int vdx = ClipMove(&x, &y, &z, &nSector2, vx, vy, pSprite->clipdist<<2, (z-top)/4, (bottom-z)/4, CLIPMASK0);
5159         clipmoveboxtracenum = 3;
5160         short nSector = nSector2;
5161         if (nSector2 < 0)
5162         {
5163             vdi = -1;
5164             break;
5165         }
5166         if (vdx)
5167         {
5168             int nHitSprite = vdx & 0x3fff;
5169             if ((vdx&0xc000) == 0xc000)
5170             {
5171                 gHitInfo.hitsprite = nHitSprite;
5172                 vdi = 3;
5173             }
5174             else if ((vdx & 0xc000) == 0x8000)
5175             {
5176                 gHitInfo.hitwall = nHitSprite;
5177                 if (wall[nHitSprite].nextsector == -1)
5178                     vdi = 0;
5179                 else
5180                 {
5181                     int32_t fz, cz;
5182                     getzsofslope(wall[nHitSprite].nextsector, x, y, &cz, &fz);
5183                     if (z <= cz || z >= fz)
5184                         vdi = 0;
5185                     else
5186                         vdi = 4;
5187                 }
5188             }
5189         }
5190         if (vdi == 4)
5191         {
5192             walltype *pWall = &wall[gHitInfo.hitwall];
5193             if (pWall->extra > 0)
5194             {
5195                 XWALL *pXWall = &xwall[pWall->extra];
5196                 if (pXWall->triggerVector)
5197                 {
5198                     trTriggerWall(gHitInfo.hitwall, pXWall, kCmdWallImpact);
5199                     if (!(pWall->cstat&64))
5200                     {
5201                         vdi = -1;
5202                         if (i-- > 0)
5203                             continue;
5204                         vdi = 0;
5205                         break;
5206                     }
5207                 }
5208             }
5209         }
5210         if (vdi >= 0 && vdi != 3)
5211         {
5212             int nAngle = getangle(xvel[nSprite], yvel[nSprite]);
5213             x -= mulscale30(Cos(nAngle), 16);
5214             y -= mulscale30(Sin(nAngle), 16);
5215             int nVel = approxDist(xvel[nSprite], yvel[nSprite]);
5216             vz -= scale(0x100, zvel[nSprite], nVel);
5217             updatesector(x, y, &nSector);
5218             nSector2 = nSector;
5219         }
5220         int ceilZ, ceilHit, floorZ, floorHit;
5221         GetZRangeAtXYZ(x, y, z, nSector2, &ceilZ, &ceilHit, &floorZ, &floorHit, pSprite->clipdist<<2, CLIPMASK0);
5222         GetSpriteExtents(pSprite, &top, &bottom);
5223         top += vz;
5224         bottom += vz;
5225         if (bottom >= floorZ)
5226         {
5227             gSpriteHit[nXSprite].florhit = floorHit;
5228             vz += floorZ-bottom;
5229             vdi = 2;
5230         }
5231         if (top <= ceilZ)
5232         {
5233             gSpriteHit[nXSprite].ceilhit = ceilHit;
5234             vz += ClipLow(ceilZ-top, 0);
5235             vdi = 1;
5236         }
5237         pSprite->x = x;
5238         pSprite->y = y;
5239         pSprite->z = z+vz;
5240         updatesector(x, y, &nSector);
5241         if (nSector >= 0 && nSector != pSprite->sectnum)
5242         {
5243             dassert(nSector >= 0 && nSector < kMaxSectors);
5244             ChangeSpriteSect(nSprite, nSector);
5245         }
5246         CheckLink(pSprite);
5247         gHitInfo.hitsect = pSprite->sectnum;
5248         gHitInfo.hitx = pSprite->x;
5249         gHitInfo.hity = pSprite->y;
5250         gHitInfo.hitz = pSprite->z;
5251         break;
5252     }
5253     if (pOwner)
5254         pOwner->cstat = bakCstat;
5255     return vdi;
5256 }
5257 
actExplodeSprite(spritetype * pSprite)5258 void actExplodeSprite(spritetype *pSprite)
5259 {
5260     int nXSprite = pSprite->extra;
5261     if (nXSprite <= 0 || nXSprite >= kMaxXSprites)
5262         return;
5263     if (pSprite->statnum == kStatExplosion)
5264         return;
5265     sfxKill3DSound(pSprite, -1, -1);
5266     evKill(pSprite->index, 3);
5267     int nType = kExplosionStandard;
5268 
5269     switch (pSprite->type)
5270     {
5271     case kMissileFireballNapam:
5272         nType = kExplosionNapalm;
5273         seqSpawn(4, 3, nXSprite, -1);
5274         if (Chance(0x8000))
5275             pSprite->cstat |= 4;
5276         sfxPlay3DSound(pSprite, 303, -1, 0);
5277         GibSprite(pSprite, GIBTYPE_5, NULL, NULL);
5278         break;
5279     case kMissileFlareAlt:
5280         nType = kExplosionFireball;
5281         seqSpawn(9, 3, nXSprite, -1);
5282         if (Chance(0x8000))
5283             pSprite->cstat |= 4;
5284         sfxPlay3DSound(pSprite, 306, 24+(pSprite->index&3), 1);
5285         GibSprite(pSprite, GIBTYPE_5, NULL, NULL);
5286         break;
5287     case kMissileFireballCerberus:
5288     case kMissileFireballTchernobog:
5289         nType = kExplosionFireball;
5290         seqSpawn(5, 3, nXSprite, -1);
5291         sfxPlay3DSound(pSprite, 304, -1, 0);
5292         GibSprite(pSprite, GIBTYPE_5, NULL, NULL);
5293         break;
5294     case kThingArmedTNTStick:
5295         nType = kExplosionSmall;
5296         if (gSpriteHit[nXSprite].florhit == 0) seqSpawn(4,3,nXSprite,-1);
5297         else seqSpawn(3,3,nXSprite,-1);
5298         sfxPlay3DSound(pSprite, 303, -1, 0);
5299         GibSprite(pSprite, GIBTYPE_5, NULL, NULL);
5300         break;
5301     case kThingArmedProxBomb:
5302     case kThingArmedRemoteBomb:
5303     case kThingArmedTNTBundle:
5304     #ifdef NOONE_EXTENSIONS
5305     case kModernThingTNTProx:
5306     #endif
5307         nType = kExplosionStandard;
5308         if (gSpriteHit[nXSprite].florhit == 0)
5309             seqSpawn(4,3,nXSprite,-1);
5310         else
5311             seqSpawn(3,3,nXSprite,-1);
5312         sfxPlay3DSound(pSprite, 304, -1, 0);
5313         GibSprite(pSprite, GIBTYPE_5, NULL, NULL);
5314         break;
5315     case kThingArmedSpray:
5316         nType = kExplosionSpray;
5317         seqSpawn(5, 3, nXSprite, -1);
5318         sfxPlay3DSound(pSprite, 307, -1, 0);
5319         GibSprite(pSprite, GIBTYPE_5, NULL, NULL);
5320         break;
5321     case kThingTNTBarrel:
5322     {
5323         spritetype *pSprite2 = actSpawnSprite(pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0, 1);
5324         pSprite2->owner = pSprite->owner;
5325         if (actCheckRespawn(pSprite))
5326         {
5327             XSPRITE *pXSprite = &xsprite[nXSprite];
5328             pXSprite->state = 1;
5329             pXSprite->health = thingInfo[0].startHealth<<4;
5330         }
5331         else
5332             actPostSprite(pSprite->index, kStatFree);
5333         nType = kExplosionLarge;
5334         nXSprite = pSprite2->extra;
5335         seqSpawn(4, 3, nXSprite, -1);
5336         sfxPlay3DSound(pSprite2, 305, -1, 0);
5337         GibSprite(pSprite2, GIBTYPE_14, NULL, NULL);
5338         pSprite = pSprite2;
5339         break;
5340     }
5341     case kTrapExploder:
5342 	{
5343 		// Defaults for exploder
5344 		nType = 1; int nSnd = 304; int nSeq = 4;
5345 
5346         #ifdef NOONE_EXTENSIONS
5347         // allow to customize hidden exploder trap
5348         if (gModernMap) {
5349             // Temp variables for override via data fields
5350             int tSnd = 0; int tSeq = 0;
5351 
5352 
5353             XSPRITE* pXSPrite = &xsprite[nXSprite];
5354             nType = pXSPrite->data1;  // Explosion type
5355             tSeq = pXSPrite->data2; // SEQ id
5356             tSnd = pXSPrite->data3; // Sound Id
5357 
5358             if (nType <= 1 || nType > kExplodeMax) { nType = 1; nSeq = 4; nSnd = 304; }
5359             else if (nType == 2) { nSeq = 4; nSnd = 305; }
5360             else if (nType == 3) { nSeq = 9; nSnd = 307; }
5361             else if (nType == 4) { nSeq = 5; nSnd = 307; }
5362             else if (nType <= 6) { nSeq = 4; nSnd = 303; }
5363             else if (nType == 7) { nSeq = 4; nSnd = 303; }
5364             else if (nType == 8) { nType = 0; nSeq = 3; nSnd = 303; }
5365 
5366             // Override previous sound and seq assigns
5367             if (tSeq > 0) nSeq = tSeq;
5368             if (tSnd > 0) nSnd = tSnd;
5369         }
5370         #endif
5371 
5372         if (gSysRes.Lookup(nSeq, "SEQ"))
5373 		    seqSpawn(nSeq, 3, nXSprite, -1);
5374 
5375 		sfxPlay3DSound(pSprite, nSnd, -1, 0);
5376 	}
5377         break;
5378     case kThingPodFireBall:
5379         nType = kExplosionFireball;
5380         seqSpawn(9, 3, nXSprite, -1);
5381         sfxPlay3DSound(pSprite, 307, -1, 0);
5382         GibSprite(pSprite, GIBTYPE_5, NULL, NULL);
5383         sub_746D4(pSprite, 240);
5384         break;
5385     default:
5386         nType = kExplosionStandard;
5387         seqSpawn(4, 3, nXSprite, -1);
5388         if (Chance(0x8000))
5389             pSprite->cstat |= 4;
5390         sfxPlay3DSound(pSprite, 303, -1, 0);
5391         GibSprite(pSprite, GIBTYPE_5, NULL, NULL);
5392         break;
5393     }
5394     int nSprite = pSprite->index;
5395     xvel[nSprite] = yvel[nSprite] = zvel[nSprite] = 0;
5396     actPostSprite(nSprite, kStatExplosion);
5397     pSprite->xrepeat = pSprite->yrepeat = explodeInfo[nType].repeat;
5398 
5399     pSprite->flags &= ~3;
5400     pSprite->type = nType;
5401     EXPLOSION *pExplodeInfo = &explodeInfo[nType];
5402     xsprite[nXSprite].target = 0;
5403     xsprite[nXSprite].data1 = pExplodeInfo->ticks;
5404     xsprite[nXSprite].data2 = pExplodeInfo->quakeEffect;
5405     xsprite[nXSprite].data3 = pExplodeInfo->flashEffect;
5406 }
5407 
actActivateGibObject(spritetype * pSprite,XSPRITE * pXSprite)5408 void actActivateGibObject(spritetype *pSprite, XSPRITE *pXSprite)
5409 {
5410     int vdx = ClipRange(pXSprite->data1, 0, 31);
5411     int vc = ClipRange(pXSprite->data2, 0, 31);
5412     int v4 = ClipRange(pXSprite->data3, 0, 31);
5413     int vbp = pXSprite->data4;
5414     int v8 = pXSprite->dropMsg;
5415     if (vdx > 0)
5416         GibSprite(pSprite, (GIBTYPE)(vdx-1), NULL, NULL);
5417     if (vc > 0)
5418         GibSprite(pSprite, (GIBTYPE)(vc-1), NULL, NULL);
5419     if (v4 > 0 && pXSprite->burnTime > 0)
5420         GibSprite(pSprite, (GIBTYPE)(v4-1), NULL, NULL);
5421     if (vbp > 0)
5422         sfxPlay3DSound(pSprite->x, pSprite->y, pSprite->z, vbp, pSprite->sectnum);
5423     if (v8 > 0)
5424         actDropObject(pSprite, v8);
5425 
5426     if (!(pSprite->cstat&32768) && !(pSprite->flags&kHitagRespawn))
5427         actPostSprite(pSprite->index, kStatFree);
5428 }
5429 
IsUnderWater(spritetype * pSprite)5430 bool IsUnderWater(spritetype *pSprite)
5431 {
5432     int nSector = pSprite->sectnum;
5433     int nXSector = sector[nSector].extra;
5434     if (nXSector > 0 && nXSector < kMaxXSectors)
5435         if (xsector[nXSector].Underwater)
5436             return 1;
5437     return 0;
5438 }
5439 
5440 void MakeSplash(spritetype *pSprite, XSPRITE *pXSprite);
5441 
actProcessSprites(void)5442 void actProcessSprites(void)
5443 {
5444     int nSprite;
5445     int nNextSprite;
5446 
5447     #ifdef NOONE_EXTENSIONS
5448     if (gModernMap) nnExtProcessSuperSprites();
5449     #endif
5450 
5451     for (nSprite = headspritestat[kStatThing]; nSprite >= 0; nSprite = nextspritestat[nSprite])
5452     {
5453         spritetype *pSprite = &sprite[nSprite];
5454 
5455         if (pSprite->flags&32)
5456             continue;
5457         int nXSprite = pSprite->extra;
5458         if (nXSprite > 0) {
5459             XSPRITE *pXSprite = &xsprite[nXSprite];
5460             switch (pSprite->type) {
5461                 case kThingBloodBits:
5462                 case kThingBloodChunks:
5463                 case kThingZombieHead:
5464                     if (pXSprite->locked && gFrameClock >= pXSprite->targetX) pXSprite->locked = 0;
5465                     break;
5466             }
5467 
5468             if (pXSprite->burnTime > 0)
5469             {
5470                 pXSprite->burnTime = ClipLow(pXSprite->burnTime-4,0);
5471                 actDamageSprite(actOwnerIdToSpriteId(pXSprite->burnSource), pSprite, kDamageBurn, 8);
5472             }
5473 
5474             if (pXSprite->Proximity) {
5475                 #ifdef NOONE_EXTENSIONS
5476                 // don't process locked or 1-shot things for proximity
5477                 if (gModernMap && (pXSprite->locked || pXSprite->isTriggered))
5478                     continue;
5479                 #endif
5480 
5481                 if (pSprite->type == kThingDroppedLifeLeech) pXSprite->target = -1;
5482                 for (int nSprite2 = headspritestat[kStatDude]; nSprite2 >= 0; nSprite2 = nNextSprite)
5483                 {
5484 
5485                     nNextSprite = nextspritestat[nSprite2];
5486                     spritetype *pSprite2 = &sprite[nSprite2];
5487 
5488                     if (pSprite2->flags&32) continue;
5489                     XSPRITE *pXSprite2 = &xsprite[pSprite2->extra];
5490                     if ((unsigned int)pXSprite2->health > 0) {
5491 
5492                         #ifdef NOONE_EXTENSIONS
5493                         // allow dudeLockout for proximity flag
5494                         if (gModernMap && pSprite->type != kThingDroppedLifeLeech && pXSprite->DudeLockout && !IsPlayerSprite(pSprite2))
5495                             continue;
5496                         #endif
5497 
5498                         int proxyDist = 96;
5499                         #ifdef NOONE_EXTENSIONS
5500                         if (pSprite->type == kModernThingEnemyLifeLeech) proxyDist = 512;
5501                         #endif
5502                         if (pSprite->type == kThingDroppedLifeLeech && pXSprite->target == -1)  {
5503                             int nOwner = actOwnerIdToSpriteId(pSprite->owner);
5504                             spritetype *pOwner = &sprite[nOwner];
5505                             if (!IsPlayerSprite(pOwner))
5506                                 continue;
5507                             PLAYER *pPlayer = &gPlayer[pOwner->type - kDudePlayer1];
5508                             PLAYER *pPlayer2 = NULL;
5509                             if (IsPlayerSprite(pSprite2))
5510                                 pPlayer2 = &gPlayer[pSprite2->type - kDudePlayer1];
5511                             if (nSprite2 == nOwner || pSprite2->type == kDudeZombieAxeBuried || pSprite2->type == kDudeRat || pSprite2->type == kDudeBat)
5512                                 continue;
5513                             if (gGameOptions.nGameType == 3 && pPlayer2 && pPlayer->teamId == pPlayer2->teamId)
5514                                 continue;
5515                             if (gGameOptions.nGameType == 1 && pPlayer2)
5516                                 continue;
5517                             proxyDist = 512;
5518                         }
5519 
5520                         if (CheckProximity(pSprite2, pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum, proxyDist)) {
5521 
5522                             switch (pSprite->type) {
5523                                 case kThingDroppedLifeLeech:
5524                                     if (!Chance(0x4000) && nNextSprite >= 0) continue;
5525                                     if (pSprite2->cstat & CLIPMASK0) pXSprite->target = pSprite2->index;
5526                                     else continue;
5527                                     break;
5528                                 #ifdef NOONE_EXTENSIONS
5529                                 case kModernThingTNTProx:
5530                                     if (!IsPlayerSprite(pSprite2)) continue;
5531                                     pSprite->pal = 0;
5532                                     break;
5533                                 case kModernThingEnemyLifeLeech:
5534                                     if (pXSprite->target != pSprite2->index) continue;
5535                                     break;
5536                                 #endif
5537                             }
5538                             if (pSprite->owner == -1) actPropagateSpriteOwner(pSprite, pSprite2);
5539                             trTriggerSprite(nSprite, pXSprite, kCmdSpriteProximity);
5540                         }
5541                     }
5542                 }
5543             }
5544         }
5545     }
5546     for (nSprite = headspritestat[kStatThing]; nSprite >= 0; nSprite = nextspritestat[nSprite])
5547     {
5548         spritetype *pSprite = &sprite[nSprite];
5549 
5550         if (pSprite->flags & 32)
5551             continue;
5552         int nSector = pSprite->sectnum;
5553         int nXSprite = pSprite->extra;
5554         dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
5555         int nXSector = sector[nSector].extra;
5556         XSECTOR *pXSector = NULL;
5557         if (nXSector > 0)
5558         {
5559             dassert(nXSector > 0 && nXSector < kMaxXSectors);
5560             dassert(xsector[nXSector].reference == nSector);
5561             pXSector = &xsector[nXSector];
5562         }
5563         if (pXSector && pXSector->panVel && (pXSector->panAlways || pXSector->state || pXSector->busy))
5564         {
5565             int nType = pSprite->type - kThingBase;
5566             THINGINFO *pThingInfo = &thingInfo[nType];
5567             if (pThingInfo->flags & 1)
5568 
5569                 pSprite->flags |= 1;
5570             if (pThingInfo->flags & 2)
5571 
5572                 pSprite->flags |= 4;
5573         }
5574 
5575         if (pSprite->flags&3)
5576         {
5577             viewBackupSpriteLoc(nSprite, pSprite);
5578             if (pXSector && pXSector->panVel)
5579             {
5580                 int top, bottom;
5581                 GetSpriteExtents(pSprite, &top, &bottom);
5582                 if (getflorzofslope(nSector, pSprite->x, pSprite->y) <= bottom)
5583                 {
5584                     int angle = pXSector->panAngle;
5585                     int speed = 0;
5586                     if (pXSector->panAlways || pXSector->state || pXSector->busy)
5587                     {
5588                         speed = pXSector->panVel << 9;
5589                         if (!pXSector->panAlways && pXSector->busy)
5590                             speed = mulscale16(speed, pXSector->busy);
5591                     }
5592                     if (sector[nSector].floorstat&64)
5593                         angle = (angle+GetWallAngle(sector[nSector].wallptr)+512)&2047;
5594                     int dx = mulscale30(speed, Cos(angle));
5595                     int dy = mulscale30(speed, Sin(angle));
5596                     xvel[nSprite] += dx;
5597                     yvel[nSprite] += dy;
5598                 }
5599             }
5600             actAirDrag(pSprite, 128);
5601 
5602             if (((pSprite->index>>8)&15) == (gFrame&15) && (pSprite->flags&2))
5603                 pSprite->flags |= 4;
5604             if ((pSprite->flags&4) || xvel[nSprite] || yvel[nSprite] || zvel[nSprite] ||
5605                 velFloor[pSprite->sectnum] || velCeil[pSprite->sectnum])
5606             {
5607                 int hit = MoveThing(pSprite);
5608                 if (hit)
5609                 {
5610                     int nXSprite = pSprite->extra;
5611                     if (nXSprite)
5612                     {
5613                         XSPRITE *pXSprite = &xsprite[nXSprite];
5614                         if (pXSprite->Impact)
5615                             trTriggerSprite(nSprite, pXSprite, kCmdOff);
5616                         switch (pSprite->type) {
5617                         case kThingDripWater:
5618                         case kThingDripBlood:
5619                             MakeSplash(pSprite, pXSprite);
5620                             break;
5621                         #ifdef NOONE_EXTENSIONS
5622                         case kModernThingThrowableRock:
5623                             seqSpawn(24, 3, nXSprite, -1);
5624                             if ((hit & 0xc000) == 0xc000)
5625                             {
5626                                 pSprite->xrepeat = 32;
5627                                 pSprite->yrepeat = 32;
5628                                 int nObject = hit & 0x3fff;
5629                                 dassert(nObject >= 0 && nObject < kMaxSprites);
5630                                 spritetype * pObject = &sprite[nObject];
5631                                 actDamageSprite(actSpriteOwnerToSpriteId(pSprite), pObject, kDamageFall, pXSprite->data1);
5632                             }
5633                             break;
5634                         #endif
5635                         case kThingBone:
5636                             seqSpawn(24, 3, nXSprite, -1);
5637                             if ((hit&0xc000) == 0xc000)
5638                             {
5639                                 int nObject = hit & 0x3fff;
5640                                 dassert(nObject >= 0 && nObject < kMaxSprites);
5641                                 spritetype *pObject = &sprite[nObject];
5642                                 actDamageSprite(actSpriteOwnerToSpriteId(pSprite), pObject, kDamageFall, 12);
5643                             }
5644                             break;
5645                         case kThingPodGreenBall:
5646                             if ((hit&0xc000) == 0x4000)
5647                             {
5648                                 sub_2A620(actSpriteOwnerToSpriteId(pSprite), pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum, 200, 1, 20, kDamageExplode, 6, 0, 0, 0);
5649                                 evPost(pSprite->index, 3, 0, kCallbackFXPodBloodSplat);
5650                             }
5651                             else
5652                             {
5653                                 int nObject = hit & 0x3fff;
5654                                 if ((hit&0xc000) != 0xc000 && (nObject < 0 || nObject >= 4096))
5655                                     break;
5656                                 dassert(nObject >= 0 && nObject < kMaxSprites);
5657                                 spritetype *pObject = &sprite[nObject];
5658                                 actDamageSprite(actSpriteOwnerToSpriteId(pSprite), pObject, kDamageFall, 12);
5659                                 evPost(pSprite->index, 3, 0, kCallbackFXPodBloodSplat);
5660                             }
5661                             break;
5662                         case kThingPodFireBall:
5663                         {
5664                             int nObject = hit & 0x3fff;
5665                             if ((hit&0xc000) != 0xc000 && (nObject < 0 || nObject >= 4096))
5666                                 break;
5667                             dassert(nObject >= 0 && nObject < kMaxSprites);
5668                             int UNUSED(nOwner) = actSpriteOwnerToSpriteId(pSprite);
5669                             actExplodeSprite(pSprite);
5670                             break;
5671                         }
5672                         }
5673                     }
5674                 }
5675             }
5676         }
5677     }
5678     for (nSprite = headspritestat[kStatProjectile]; nSprite >= 0; nSprite = nextspritestat[nSprite])
5679     {
5680         spritetype *pSprite = &sprite[nSprite];
5681 
5682         if (pSprite->flags & 32)
5683             continue;
5684         viewBackupSpriteLoc(nSprite, pSprite);
5685         int hit = MoveMissile(pSprite);
5686         if (hit >= 0)
5687             actImpactMissile(pSprite, hit);
5688     }
5689     for (nSprite = headspritestat[kStatExplosion]; nSprite >= 0; nSprite = nextspritestat[nSprite])
5690     {
5691         char v24c[(kMaxSectors+7)>>3];
5692         spritetype *pSprite = &sprite[nSprite];
5693 
5694         if (pSprite->flags & 32)
5695             continue;
5696         int nOwner = actSpriteOwnerToSpriteId(pSprite);
5697         int nType = pSprite->type;
5698         dassert(nType >= 0 && nType < kExplodeMax);
5699         EXPLOSION *pExplodeInfo = &explodeInfo[nType];
5700         int nXSprite = pSprite->extra;
5701         dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
5702         XSPRITE *pXSprite = &xsprite[nXSprite];
5703         int x = pSprite->x;
5704         int y = pSprite->y;
5705         int z = pSprite->z;
5706         int nSector = pSprite->sectnum;
5707         gAffectedSectors[0] = -1;
5708         gAffectedXWalls[0] = -1;
5709         int radius = pExplodeInfo->radius;
5710 
5711         #ifdef NOONE_EXTENSIONS
5712         // Allow to override explosion radius by data4 field of any sprite which have statnum 2 set in editor
5713         // or of Hidden Exploder.
5714         if (gModernMap && pXSprite->data4 > 0)
5715             radius = pXSprite->data4;
5716         #endif
5717 
5718         GetClosestSpriteSectors(nSector, x, y, radius, gAffectedSectors, v24c, gAffectedXWalls);
5719 
5720         for (int i = 0; i < kMaxXWalls; i++)
5721         {
5722             int nWall = gAffectedXWalls[i];
5723             if (nWall == -1)
5724                 break;
5725             XWALL *pXWall = &xwall[wall[nWall].extra];
5726             trTriggerWall(nWall, pXWall, kCmdWallImpact);
5727         }
5728 
5729         for (int nSprite2 = headspritestat[kStatDude]; nSprite2 >= 0; nSprite2 = nextspritestat[nSprite2])
5730         {
5731             spritetype *pDude = &sprite[nSprite2];
5732 
5733             if (pDude->flags & 32)
5734                 continue;
5735             if (TestBitString(v24c, pDude->sectnum))
5736             {
5737                 if (pXSprite->data1 && CheckProximity(pDude, x, y, z, nSector, radius))
5738                 {
5739                     if (pExplodeInfo->dmg && pXSprite->target == 0)
5740                     {
5741                         pXSprite->target = 1;
5742                         actDamageSprite(nOwner, pDude, kDamageFall, (pExplodeInfo->dmg+Random(pExplodeInfo->dmgRng))<<4);
5743                     }
5744                     if (pExplodeInfo->dmgType)
5745                         ConcussSprite(nOwner, pDude, x, y, z, pExplodeInfo->dmgType);
5746                     if (pExplodeInfo->burnTime)
5747                     {
5748                         dassert(pDude->extra > 0 && pDude->extra < kMaxXSprites);
5749                         XSPRITE *pXDude = &xsprite[pDude->extra];
5750                         if (!pXDude->burnTime)
5751                             evPost(nSprite2, 3, 0, kCallbackFXFlameLick);
5752                         actBurnSprite(pSprite->owner, pXDude, pExplodeInfo->burnTime<<2);
5753                     }
5754                 }
5755             }
5756         }
5757 
5758         for (int nSprite2 = headspritestat[kStatThing]; nSprite2 >= 0; nSprite2 = nextspritestat[nSprite2])
5759         {
5760             spritetype *pThing = &sprite[nSprite2];
5761 
5762             if (pThing->flags & 32)
5763                 continue;
5764             if (TestBitString(v24c, pThing->sectnum))
5765             {
5766                 if (pXSprite->data1 && CheckProximity(pThing, x, y, z, nSector, radius))
5767                 {
5768                     XSPRITE *pXSprite2 = &xsprite[pThing->extra];
5769                     if (!pXSprite2->locked)
5770                     {
5771                         if (pExplodeInfo->dmgType)
5772                             ConcussSprite(nOwner, pThing, x, y, z, pExplodeInfo->dmgType);
5773                         if (pExplodeInfo->burnTime)
5774                         {
5775                             dassert(pThing->extra > 0 && pThing->extra < kMaxXSprites);
5776                             XSPRITE *pXThing = &xsprite[pThing->extra];
5777                             if (pThing->type == kThingTNTBarrel && !pXThing->burnTime)
5778                                 evPost(nSprite2, 3, 0, kCallbackFXFlameLick);
5779                             actBurnSprite(pSprite->owner, pXThing, pExplodeInfo->burnTime<<2);
5780                         }
5781                     }
5782                 }
5783             }
5784         }
5785 
5786         for (int p = connecthead; p >= 0; p = connectpoint2[p])
5787         {
5788             spritetype *pSprite2 = gPlayer[p].pSprite;
5789             int dx = (x - pSprite2->x)>>4;
5790             int dy = (y - pSprite2->y)>>4;
5791             int dz = (z - pSprite2->z)>>8;
5792             int nDist = dx*dx+dy*dy+dz*dz+0x40000;
5793             int t = divscale16(pXSprite->data2, nDist);
5794             gPlayer[p].flickerEffect += t;
5795         }
5796 
5797         #ifdef NOONE_EXTENSIONS
5798         if (pXSprite->data1 != 0) {
5799 
5800             // add impulse for sprites from physics list
5801             if (gPhysSpritesCount > 0 && pExplodeInfo->dmgType != 0) {
5802                 for (int i = 0; i < gPhysSpritesCount; i++) {
5803                     if (gPhysSpritesList[i] == -1) continue;
5804                     else if (sprite[gPhysSpritesList[i]].sectnum < 0 || (sprite[gPhysSpritesList[i]].flags & kHitagFree) != 0)
5805                         continue;
5806 
5807                     spritetype* pDebris = &sprite[gPhysSpritesList[i]];
5808                     if (!TestBitString(v24c, pDebris->sectnum) || !CheckProximity(pDebris, x, y, z, nSector, radius)) continue;
5809                     else debrisConcuss(nOwner, i, x, y, z, pExplodeInfo->dmgType);
5810                 }
5811             }
5812 
5813             // trigger sprites from impact list
5814             if (gImpactSpritesCount > 0) {
5815                 for (int i = 0; i < gImpactSpritesCount; i++) {
5816                     if (gImpactSpritesList[i] == -1) continue;
5817                     else if (sprite[gImpactSpritesList[i]].sectnum < 0 || (sprite[gImpactSpritesList[i]].flags & kHitagFree) != 0)
5818                         continue;
5819 
5820                     spritetype* pImpact = &sprite[gImpactSpritesList[i]]; XSPRITE* pXImpact = &xsprite[pImpact->extra];
5821                     if (/*pXImpact->state == pXImpact->restState ||*/ !TestBitString(v24c, pImpact->sectnum) || !CheckProximity(pImpact, x, y, z, nSector, radius))
5822                         continue;
5823 
5824                     trTriggerSprite(pImpact->index, pXImpact, kCmdSpriteImpact);
5825                 }
5826             }
5827 
5828         }
5829 
5830         if (!gModernMap || !(pSprite->flags & kModernTypeFlag1)) {
5831             // if data4 > 0, do not remove explosion. This can be useful when designer wants put explosion generator in map manually
5832             // via sprite statnum 2.
5833             pXSprite->data1 = ClipLow(pXSprite->data1 - 4, 0);
5834             pXSprite->data2 = ClipLow(pXSprite->data2 - 4, 0);
5835             pXSprite->data3 = ClipLow(pXSprite->data3 - 4, 0);
5836         }
5837         #else
5838         pXSprite->data1 = ClipLow(pXSprite->data1 - 4, 0);
5839         pXSprite->data2 = ClipLow(pXSprite->data2 - 4, 0);
5840         pXSprite->data3 = ClipLow(pXSprite->data3 - 4, 0);
5841         #endif
5842 
5843         if (pXSprite->data1 == 0 && pXSprite->data2 == 0 && pXSprite->data3 == 0 && seqGetStatus(3, nXSprite) < 0)
5844             actPostSprite(nSprite, kStatFree);
5845     }
5846 
5847     for (nSprite = headspritestat[kStatTraps]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
5848         spritetype *pSprite = &sprite[nSprite];
5849 
5850         if (pSprite->flags & 32)
5851             continue;
5852         int nXSprite = pSprite->extra;
5853         //dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
5854         if (nXSprite <= 0 || nXSprite >= kMaxXSprites)
5855             continue;
5856         XSPRITE *pXSprite = &xsprite[nXSprite];
5857         switch (pSprite->type) {
5858         case kTrapSawCircular:
5859             pXSprite->data2 = ClipLow(pXSprite->data2-4, 0);
5860             break;
5861         case kTrapFlame:
5862             if (pXSprite->state && seqGetStatus(3, nXSprite) < 0) {
5863                 int x = pSprite->x;
5864                 int y = pSprite->y;
5865                 int z = pSprite->z;
5866                 int t = (pXSprite->data1<<23)/120;
5867                 int dx = mulscale30(t, Cos(pSprite->ang));
5868                 int dy = mulscale30(t, Sin(pSprite->ang));
5869                 for (int i = 0; i < 2; i++)
5870                 {
5871                     spritetype *pFX = gFX.fxSpawn(FX_32, pSprite->sectnum, x, y, z, 0);
5872                     if (pFX)
5873                     {
5874                         xvel[pFX->index] = dx + Random2(0x8888);
5875                         yvel[pFX->index] = dy + Random2(0x8888);
5876                         zvel[pFX->index] = Random2(0x8888);
5877                     }
5878                     x += (dx/2)>>12;
5879                     y += (dy/2)>>12;
5880                 }
5881                 dy = Sin(pSprite->ang)>>16;
5882                 dx = Cos(pSprite->ang)>>16;
5883                 gVectorData[kVectorTchernobogBurn].maxDist = pXSprite->data1<<9;
5884                 actFireVector(pSprite, 0, 0, dx, dy, Random2(0x8888), kVectorTchernobogBurn);
5885             }
5886             break;
5887         }
5888     }
5889     for (nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite])
5890     {
5891         spritetype *pSprite = &sprite[nSprite];
5892 
5893         if (pSprite->flags & 32)
5894             continue;
5895         int nXSprite = pSprite->extra;
5896         if (nXSprite > 0)
5897         {
5898             XSPRITE *pXSprite = &xsprite[nXSprite];
5899             if (pXSprite->burnTime > 0)
5900             {
5901                 switch (pSprite->type)
5902                 {
5903                 case kDudeBurningInnocent:
5904                 case kDudeBurningCultist:
5905                 case kDudeBurningZombieAxe:
5906                 case kDudeBurningZombieButcher:
5907                     actDamageSprite(actOwnerIdToSpriteId(pXSprite->burnSource), pSprite, kDamageBurn, 8);
5908                     break;
5909                 default:
5910                     pXSprite->burnTime = ClipLow(pXSprite->burnTime-4, 0);
5911                     actDamageSprite(actOwnerIdToSpriteId(pXSprite->burnSource), pSprite, kDamageBurn, 8);
5912                     break;
5913                 }
5914             }
5915 
5916             #ifdef NOONE_EXTENSIONS
5917             // handle incarnations of custom dude
5918             if (pSprite->type == kDudeModernCustom && pXSprite->txID > 0 && pXSprite->sysData1 == kGenDudeTransformStatus) {
5919                 xvel[pSprite->index] = yvel[pSprite->index] =  0;
5920                 if (seqGetStatus(3, nXSprite) < 0)
5921                     genDudeTransform(pSprite);
5922             }
5923             #endif
5924             if (pSprite->type == kDudeCerberusTwoHead)
5925             {
5926                 if (pXSprite->health <= 0 && seqGetStatus(3, nXSprite) < 0)
5927                 {
5928                     pXSprite->health = dudeInfo[28].startHealth<<4;
5929                     pSprite->type = kDudeCerberusOneHead;
5930                     if (pXSprite->target != -1)
5931                         aiSetTarget(pXSprite, pXSprite->target);
5932                     aiActivateDude(pSprite, pXSprite);
5933                 }
5934             }
5935             if (pXSprite->Proximity && !pXSprite->isTriggered)
5936             {
5937                 for (int nSprite2 = headspritestat[kStatDude]; nSprite2 >= 0; nSprite2 = nNextSprite)
5938                 {
5939                     nNextSprite = nextspritestat[nSprite2];
5940                     spritetype *pSprite2 = &sprite[nSprite2];
5941 
5942                     if (pSprite2->flags&32)
5943                         continue;
5944                     XSPRITE *pXSprite2 = &xsprite[pSprite2->extra];
5945                     if ((unsigned int)pXSprite2->health > 0 && IsPlayerSprite(pSprite2)) {
5946                         if (CheckProximity(pSprite2, pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum, 128))
5947                             trTriggerSprite(nSprite, pXSprite, kCmdSpriteProximity);
5948                     }
5949                 }
5950             }
5951             if (IsPlayerSprite(pSprite))
5952             {
5953                 PLAYER *pPlayer = &gPlayer[pSprite->type-kDudePlayer1];
5954                 if (pPlayer->voodooTargets)
5955                     sub_41250(pPlayer);
5956                 if (pPlayer->hand && Chance(0x8000))
5957                     actDamageSprite(nSprite, pSprite, kDamageDrown, 12);
5958                 if (pPlayer->isUnderwater)
5959                 {
5960                     char bActive = packItemActive(pPlayer, 1);
5961                     if (bActive || pPlayer->godMode)
5962                         pPlayer->underwaterTime = 1200;
5963                     else
5964                         pPlayer->underwaterTime = ClipLow(pPlayer->underwaterTime-4, 0);
5965                     if (pPlayer->underwaterTime < 1080 && packCheckItem(pPlayer, 1) && !bActive)
5966                         packUseItem(pPlayer, 1);
5967                     if (!pPlayer->underwaterTime)
5968                     {
5969                         pPlayer->chokeEffect += 4;
5970                         if (Chance(pPlayer->chokeEffect))
5971                             actDamageSprite(nSprite, pSprite, kDamageDrown, 3<<4);
5972                     }
5973                     else
5974                         pPlayer->chokeEffect = 0;
5975                     if (xvel[nSprite] || yvel[nSprite])
5976                         sfxPlay3DSound(pSprite, 709, 100, 2);
5977                     pPlayer->bubbleTime = ClipLow(pPlayer->bubbleTime-4, 0);
5978                 }
5979                 else if (gGameOptions.nGameType == 0)
5980                 {
5981                     if (pPlayer->pXSprite->health > 0 && pPlayer->restTime >= 1200 && Chance(0x200))
5982                     {
5983                         pPlayer->restTime = -1;
5984                         sfxPlay3DSound(pSprite, 3100+Random(11), 0, 2);
5985                     }
5986                 }
5987             }
5988             ProcessTouchObjects(pSprite, nXSprite);
5989         }
5990     }
5991     for (nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite])
5992     {
5993         spritetype *pSprite = &sprite[nSprite];
5994 
5995         if (pSprite->flags & 32)
5996             continue;
5997         int nXSprite = pSprite->extra;
5998         dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
5999         int nSector = pSprite->sectnum;
6000         viewBackupSpriteLoc(nSprite, pSprite);
6001         int nXSector = sector[nSector].extra;
6002         XSECTOR *pXSector = NULL;
6003         if (nXSector > 0)
6004         {
6005             dassert(nXSector > 0 && nXSector < kMaxXSectors);
6006             dassert(xsector[nXSector].reference == nSector);
6007             pXSector = &xsector[nXSector];
6008         }
6009         if (pXSector)
6010         {
6011             int top, bottom;
6012             GetSpriteExtents(pSprite, &top, &bottom);
6013             if (getflorzofslope(nSector, pSprite->x, pSprite->y) <= bottom)
6014             {
6015                 int angle = pXSector->panAngle;
6016                 int speed = 0;
6017                 if (pXSector->panAlways || pXSector->state || pXSector->busy)
6018                 {
6019                     speed = pXSector->panVel << 9;
6020                     if (!pXSector->panAlways && pXSector->busy)
6021                         speed = mulscale16(speed, pXSector->busy);
6022                 }
6023                 if (sector[nSector].floorstat&64)
6024                     angle = (angle+GetWallAngle(sector[nSector].wallptr)+512)&2047;
6025                 int dx = mulscale30(speed, Cos(angle));
6026                 int dy = mulscale30(speed, Sin(angle));
6027                 xvel[nSprite] += dx;
6028                 yvel[nSprite] += dy;
6029             }
6030         }
6031         if (pXSector && pXSector->Underwater)
6032             actAirDrag(pSprite, 5376);
6033         else
6034             actAirDrag(pSprite, 128);
6035 
6036         if ((pSprite->flags&4) || xvel[nSprite] || yvel[nSprite] || zvel[nSprite] ||
6037             velFloor[pSprite->sectnum] || velCeil[pSprite->sectnum])
6038             MoveDude(pSprite);
6039     }
6040     for (nSprite = headspritestat[kStatFlare]; nSprite >= 0; nSprite = nextspritestat[nSprite])
6041     {
6042         spritetype *pSprite = &sprite[nSprite];
6043 
6044         if (pSprite->flags & 32)
6045             continue;
6046         int nXSprite = pSprite->extra;
6047         dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
6048         XSPRITE *pXSprite = &xsprite[nXSprite];
6049         int nTarget = pXSprite->target;
6050         dassert(nTarget >= 0);
6051         viewBackupSpriteLoc(nSprite, pSprite);
6052         dassert(nTarget < kMaxSprites);
6053         spritetype *pTarget = &sprite[nTarget];
6054         if (pTarget->statnum == kMaxStatus)
6055         {
6056             GibSprite(pSprite, GIBTYPE_17, NULL, NULL);
6057             actPostSprite(pSprite->index, kStatFree);
6058         }
6059         if (pTarget->extra > 0 && xsprite[pTarget->extra].health > 0)
6060         {
6061             int x = pTarget->x+mulscale30r(Cos(pXSprite->goalAng+pTarget->ang), pTarget->clipdist*2);
6062             int y = pTarget->y+mulscale30r(Sin(pXSprite->goalAng+pTarget->ang), pTarget->clipdist*2);
6063             int z = pTarget->z+pXSprite->targetZ;
6064             vec3_t pos = { x, y, z };
6065             setsprite(nSprite,&pos);
6066             xvel[nSprite] = xvel[nTarget];
6067             yvel[nSprite] = yvel[nTarget];
6068             zvel[nSprite] = zvel[nTarget];
6069         }
6070         else
6071         {
6072             GibSprite(pSprite, GIBTYPE_17, NULL, NULL);
6073             actPostSprite(pSprite->index, kStatFree);
6074         }
6075     }
6076     aiProcessDudes();
6077     gFX.fxProcess();
6078 }
6079 
actSpawnSprite(int nSector,int x,int y,int z,int nStat,char a6)6080 spritetype * actSpawnSprite(int nSector, int x, int y, int z, int nStat, char a6)
6081 {
6082     int nSprite = InsertSprite(nSector, nStat);
6083     if (nSprite >= 0)
6084         sprite[nSprite].extra = -1;
6085     else
6086     {
6087         nSprite = headspritestat[kStatPurge];
6088         dassert(nSprite >= 0);
6089         dassert(nSector >= 0 && nSector < kMaxSectors);
6090         ChangeSpriteSect(nSprite, nSector);
6091         actPostSprite(nSprite, nStat);
6092     }
6093     vec3_t pos = { x, y, z };
6094     setsprite(nSprite, &pos);
6095     spritetype *pSprite = &sprite[nSprite];
6096     pSprite->type = kSpriteDecoration;
6097     if (a6 && pSprite->extra == -1)
6098     {
6099         int nXSprite = dbInsertXSprite(nSprite);
6100         gSpriteHit[nXSprite].florhit = 0;
6101         gSpriteHit[nXSprite].ceilhit = 0;
6102         if (!VanillaMode())
6103             xsprite[nXSprite].target = -1;
6104     }
6105     return pSprite;
6106 }
6107 
6108 spritetype * actSpawnSprite(spritetype *pSource, int nStat);
6109 
actSpawnDude(spritetype * pSource,short nType,int a3,int a4)6110 spritetype *actSpawnDude(spritetype *pSource, short nType, int a3, int a4)
6111 {
6112     XSPRITE* pXSource = &xsprite[pSource->extra];
6113     spritetype *pSprite2 = actSpawnSprite(pSource, kStatDude);
6114     if (!pSprite2) return NULL;
6115     XSPRITE *pXSprite2 = &xsprite[pSprite2->extra];
6116     int angle = pSource->ang;
6117     int nDude = nType-kDudeBase;
6118     int x, y, z;
6119     z = a4 + pSource->z;
6120     if (a3 < 0)
6121     {
6122         x = pSource->x;
6123         y = pSource->y;
6124     }
6125     else
6126     {
6127         x = pSource->x+mulscale30r(Cos(angle), a3);
6128         y = pSource->y+mulscale30r(Sin(angle), a3);
6129     }
6130     pSprite2->type = nType;
6131     pSprite2->ang = angle;
6132     vec3_t pos = { x, y, z };
6133     setsprite(pSprite2->index, &pos);
6134     pSprite2->cstat |= 0x1101;
6135     pSprite2->clipdist = getDudeInfo(nDude+kDudeBase)->clipdist;
6136     pXSprite2->health = getDudeInfo(nDude+kDudeBase)->startHealth<<4;
6137     pXSprite2->respawn = 1;
6138     if (gSysRes.Lookup(getDudeInfo(nDude+kDudeBase)->seqStartID, "SEQ"))
6139         seqSpawn(getDudeInfo(nDude+kDudeBase)->seqStartID, 3, pSprite2->extra, -1);
6140 
6141     #ifdef NOONE_EXTENSIONS
6142     // add a way to inherit some values of spawner type 18 by dude.
6143     // This way designer can count enemies via switches and do many other interesting things.
6144     if (gModernMap && pSource->flags & kModernTypeFlag1) {
6145         switch (pSource->type) { // allow inheriting only for selected source types
6146             case kMarkerDudeSpawn:
6147                 //inherit pal?
6148                 if (pSprite2->pal <= 0) pSprite2->pal = pSource->pal;
6149 
6150                 // inherit spawn sprite trigger settings, so designer can count monsters.
6151                 pXSprite2->txID = pXSource->txID;
6152                 pXSprite2->command = pXSource->command;
6153                 pXSprite2->triggerOn = pXSource->triggerOn;
6154                 pXSprite2->triggerOff = pXSource->triggerOff;
6155 
6156                 // inherit drop items
6157                 pXSprite2->dropMsg = pXSource->dropMsg;
6158 
6159                 // inherit dude flags
6160                 pXSprite2->dudeDeaf = pXSource->dudeDeaf;
6161                 pXSprite2->dudeGuard = pXSource->dudeGuard;
6162                 pXSprite2->dudeAmbush = pXSource->dudeAmbush;
6163                 pXSprite2->dudeFlag4 = pXSource->dudeFlag4;
6164                 pXSprite2->unused1 = pXSource->unused1;
6165                 break;
6166         }
6167     }
6168     #endif
6169 
6170     aiInitSprite(pSprite2);
6171     return pSprite2;
6172 }
6173 
actSpawnSprite(spritetype * pSource,int nStat)6174 spritetype * actSpawnSprite(spritetype *pSource, int nStat)
6175 {
6176     int nSprite = InsertSprite(pSource->sectnum, nStat);
6177     if (nSprite < 0)
6178     {
6179         nSprite = headspritestat[kStatPurge];
6180         dassert(nSprite >= 0);
6181         dassert(pSource->sectnum >= 0 && pSource->sectnum < kMaxSectors);
6182         ChangeSpriteSect(nSprite, pSource->sectnum);
6183         actPostSprite(nSprite, nStat);
6184     }
6185     spritetype *pSprite = &sprite[nSprite];
6186     pSprite->x = pSource->x;
6187     pSprite->y = pSource->y;
6188     pSprite->z = pSource->z;
6189     xvel[nSprite] = xvel[pSource->index];
6190     yvel[nSprite] = yvel[pSource->index];
6191     zvel[nSprite] = zvel[pSource->index];
6192     pSprite->flags = 0;
6193     int nXSprite = dbInsertXSprite(nSprite);
6194     gSpriteHit[nXSprite].florhit = 0;
6195     gSpriteHit[nXSprite].ceilhit = 0;
6196     if (!VanillaMode())
6197         xsprite[nXSprite].target = -1;
6198     return pSprite;
6199 }
6200 
actSpawnThing(int nSector,int x,int y,int z,int nThingType)6201 spritetype * actSpawnThing(int nSector, int x, int y, int z, int nThingType)
6202 {
6203     dassert(nThingType >= kThingBase && nThingType < kThingMax);
6204     spritetype *pSprite = actSpawnSprite(nSector, x, y, z, 4, 1);
6205     int nType = nThingType-kThingBase;
6206     int nThing = pSprite->index;
6207     int nXThing = pSprite->extra;
6208     pSprite->type = nThingType;
6209     dassert(nXThing > 0 && nXThing < kMaxXSprites);
6210     XSPRITE *pXThing = &xsprite[nXThing];
6211     THINGINFO *pThingInfo = &thingInfo[nType];
6212     pXThing->health = pThingInfo->startHealth<<4;
6213     pSprite->clipdist = pThingInfo->clipdist;
6214     pSprite->flags = pThingInfo->flags;
6215     if (pSprite->flags & 2)
6216         pSprite->flags |= 4;
6217     pSprite->cstat |= pThingInfo->cstat;
6218     pSprite->picnum = pThingInfo->picnum;
6219     pSprite->shade = pThingInfo->shade;
6220     pSprite->pal = pThingInfo->pal;
6221     if (pThingInfo->xrepeat)
6222         pSprite->xrepeat = pThingInfo->xrepeat;
6223     if (pThingInfo->yrepeat)
6224         pSprite->yrepeat = pThingInfo->yrepeat;
6225     SetBitString(show2dsprite, pSprite->index);
6226     switch (nThingType) {
6227     case kThingVoodooHead:
6228         pXThing->data1 = 0;
6229         pXThing->data2 = 0;
6230         pXThing->data3 = 0;
6231         pXThing->data4 = 0;
6232         pXThing->state = 1;
6233         pXThing->triggerOnce = 1;
6234         pXThing->isTriggered = 0;
6235         break;
6236     case kThingDroppedLifeLeech:
6237     #ifdef NOONE_EXTENSIONS
6238     case kModernThingEnemyLifeLeech:
6239     #endif
6240         pXThing->data1 = 0;
6241         pXThing->data2 = 0;
6242         pXThing->data3 = 0;
6243         pXThing->data4 = 0;
6244         pXThing->state = 1;
6245         pXThing->triggerOnce = 0;
6246         pXThing->isTriggered = 0;
6247         break;
6248     case kThingZombieHead:
6249         pXThing->data1 = 8;
6250         pXThing->data2 = 0;
6251         pXThing->data3 = 0;
6252         pXThing->data4 = 318;
6253         pXThing->targetX = (int)gFrameClock+180.0;
6254         pXThing->locked = 1;
6255         pXThing->state = 1;
6256         pXThing->triggerOnce = 0;
6257         pXThing->isTriggered = 0;
6258         break;
6259     case kThingBloodBits:
6260     case kThingBloodChunks:
6261         pXThing->data1 = (nThingType == kThingBloodBits) ? 19 : 8;
6262         pXThing->data2 = 0;
6263         pXThing->data3 = 0;
6264         pXThing->data4 = 318;
6265         pXThing->targetX = (int)gFrameClock+180.0;
6266         pXThing->locked = 1;
6267         pXThing->state = 1;
6268         pXThing->triggerOnce = 0;
6269         pXThing->isTriggered = 0;
6270         break;
6271     case kThingArmedTNTStick:
6272         evPost(nThing, 3, 0, kCallbackFXDynPuff);
6273         sfxPlay3DSound(pSprite, 450, 0, 0);
6274         break;
6275     case kThingArmedTNTBundle:
6276         sfxPlay3DSound(pSprite, 450, 0, 0);
6277         evPost(nThing, 3, 0, kCallbackFXDynPuff);
6278         break;
6279     case kThingArmedSpray:
6280         evPost(nThing, 3, 0, kCallbackFXDynPuff);
6281         break;
6282     }
6283     return pSprite;
6284 }
6285 
actFireThing(spritetype * pSprite,int a2,int a3,int a4,int thingType,int a6)6286 spritetype * actFireThing(spritetype *pSprite, int a2, int a3, int a4, int thingType, int a6)
6287 {
6288     dassert(thingType >= kThingBase && thingType < kThingMax);
6289     int x = pSprite->x+mulscale30(a2, Cos(pSprite->ang+512));
6290     int y = pSprite->y+mulscale30(a2, Sin(pSprite->ang+512));
6291     int z = pSprite->z+a3;
6292     x += mulscale28(pSprite->clipdist, Cos(pSprite->ang));
6293     y += mulscale28(pSprite->clipdist, Sin(pSprite->ang));
6294     if (HitScan(pSprite, z, x-pSprite->x, y-pSprite->y, 0, CLIPMASK0, pSprite->clipdist) != -1)
6295     {
6296         x = gHitInfo.hitx-mulscale28(pSprite->clipdist<<1, Cos(pSprite->ang));
6297         y = gHitInfo.hity-mulscale28(pSprite->clipdist<<1, Sin(pSprite->ang));
6298     }
6299     spritetype *pThing = actSpawnThing(pSprite->sectnum, x, y, z, thingType);
6300     actPropagateSpriteOwner(pThing, pSprite);
6301     pThing->ang = pSprite->ang;
6302     xvel[pThing->index] = mulscale30(a6, Cos(pThing->ang));
6303     yvel[pThing->index] = mulscale30(a6, Sin(pThing->ang));
6304     zvel[pThing->index] = mulscale(a6, a4, 14);
6305     xvel[pThing->index] += xvel[pSprite->index]/2;
6306     yvel[pThing->index] += yvel[pSprite->index]/2;
6307     zvel[pThing->index] += zvel[pSprite->index]/2;
6308     return pThing;
6309 }
6310 
actFireMissile(spritetype * pSprite,int a2,int a3,int a4,int a5,int a6,int nType)6311 spritetype* actFireMissile(spritetype *pSprite, int a2, int a3, int a4, int a5, int a6, int nType)
6312 {
6313 
6314     dassert(nType >= kMissileBase && nType < kMissileMax);
6315     char v4 = 0;
6316     int nSprite = pSprite->index;
6317     MissileType *pMissileInfo = &missileInfo[nType-kMissileBase];
6318     int x = pSprite->x+mulscale30(a2, Cos(pSprite->ang+512));
6319     int y = pSprite->y+mulscale30(a2, Sin(pSprite->ang+512));
6320     int z = pSprite->z+a3;
6321     int clipdist = pMissileInfo->clipDist+pSprite->clipdist;
6322     x += mulscale28(clipdist, Cos(pSprite->ang));
6323     y += mulscale28(clipdist, Sin(pSprite->ang));
6324     int hit = HitScan(pSprite, z, x-pSprite->x, y-pSprite->y, 0, CLIPMASK0, clipdist);
6325     if (hit != -1)
6326     {
6327         if (hit == 3 || hit == 0)
6328         {
6329             v4 = 1;
6330             x = gHitInfo.hitx-mulscale30(Cos(pSprite->ang), 16);
6331             y = gHitInfo.hity-mulscale30(Sin(pSprite->ang), 16);
6332         }
6333         else
6334         {
6335             x = gHitInfo.hitx-mulscale28(pMissileInfo->clipDist<<1, Cos(pSprite->ang));
6336             y = gHitInfo.hity-mulscale28(pMissileInfo->clipDist<<1, Sin(pSprite->ang));
6337         }
6338     }
6339     spritetype *pMissile = actSpawnSprite(pSprite->sectnum, x, y, z, 5, 1);
6340     int nMissile = pMissile->index;
6341     SetBitString(show2dsprite, nMissile);
6342     pMissile->type = nType;
6343     pMissile->shade = pMissileInfo->shade;
6344     pMissile->pal = 0;
6345     pMissile->clipdist = pMissileInfo->clipDist;
6346     pMissile->flags = 1;
6347     pMissile->xrepeat = pMissileInfo->xrepeat;
6348     pMissile->yrepeat = pMissileInfo->yrepeat;
6349     pMissile->picnum = pMissileInfo->picnum;
6350     pMissile->ang = (pSprite->ang+pMissileInfo->angleOfs)&2047;
6351     xvel[nMissile] = mulscale(pMissileInfo->velocity, a4, 14);
6352     yvel[nMissile] = mulscale(pMissileInfo->velocity, a5, 14);
6353     zvel[nMissile] = mulscale(pMissileInfo->velocity, a6, 14);
6354     actPropagateSpriteOwner(pMissile, pSprite);
6355     pMissile->cstat |= 1;
6356     int nXSprite = pMissile->extra;
6357     dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
6358     xsprite[nXSprite].target = -1;
6359     evPost(nMissile, 3, 600, kCallbackRemove);
6360 
6361     actBuildMissile(pMissile, nXSprite, nSprite);
6362 
6363     if (v4)
6364     {
6365         actImpactMissile(pMissile, hit);
6366         pMissile = NULL;
6367     }
6368     return pMissile;
6369 }
6370 
actBuildMissile(spritetype * pMissile,int nXSprite,int nSprite)6371 void actBuildMissile(spritetype* pMissile, int nXSprite, int nSprite) {
6372     int nMissile = pMissile->index;
6373     switch (pMissile->type) {
6374         case kMissileLifeLeechRegular:
6375             evPost(nMissile, 3, 0, kCallbackFXFlameLick);
6376             break;
6377         case kMissileTeslaAlt:
6378             evPost(nMissile, 3, 0, kCallbackFXTeslaAlt);
6379             break;
6380         case kMissilePukeGreen:
6381             seqSpawn(29, 3, nXSprite, -1);
6382             break;
6383         case kMissileButcherKnife:
6384             pMissile->cstat |= 16;
6385             break;
6386         case kMissileTeslaRegular:
6387             sfxPlay3DSound(pMissile, 251, 0, 0);
6388             break;
6389         case kMissileEctoSkull:
6390             seqSpawn(2, 3, nXSprite, -1);
6391             sfxPlay3DSound(pMissile, 493, 0, 0);
6392             break;
6393         case kMissileFireballNapam:
6394             seqSpawn(61, 3, nXSprite, nNapalmClient);
6395             sfxPlay3DSound(pMissile, 441, 0, 0);
6396             break;
6397         case kMissileFireball:
6398             seqSpawn(22, 3, nXSprite, nFireballClient);
6399             sfxPlay3DSound(pMissile, 441, 0, 0);
6400             break;
6401         case kMissileFlameHound:
6402             seqSpawn(27, 3, nXSprite, -1);
6403             xvel[nMissile] += xvel[nSprite] / 2 + Random2(0x11111);
6404             yvel[nMissile] += yvel[nSprite] / 2 + Random2(0x11111);
6405             zvel[nMissile] += zvel[nSprite] / 2 + Random2(0x11111);
6406             break;
6407         case kMissileFireballCerberus:
6408             seqSpawn(61, 3, nXSprite, dword_2192E0);
6409             sfxPlay3DSound(pMissile, 441, 0, 0);
6410             break;
6411         case kMissileFireballTchernobog:
6412             seqSpawn(23, 3, nXSprite, dword_2192D8);
6413             xvel[nMissile] += xvel[nSprite] / 2 + Random2(0x11111);
6414             yvel[nMissile] += yvel[nSprite] / 2 + Random2(0x11111);
6415             zvel[nMissile] += zvel[nSprite] / 2 + Random2(0x11111);
6416             break;
6417         case kMissileFlameSpray:
6418             if (Chance(0x8000))
6419                 seqSpawn(0, 3, nXSprite, -1);
6420             else
6421                 seqSpawn(1, 3, nXSprite, -1);
6422             xvel[nMissile] += xvel[nSprite] + Random2(0x11111);
6423             yvel[nMissile] += yvel[nSprite] + Random2(0x11111);
6424             zvel[nMissile] += zvel[nSprite] + Random2(0x11111);
6425             break;
6426         case kMissileFlareAlt:
6427             evPost(nMissile, 3, 30, kCallbackFXFlareBurst);
6428             evPost(nMissile, 3, 0, kCallbackFXFlareSpark);
6429             sfxPlay3DSound(pMissile, 422, 0, 0);
6430             break;
6431         case kMissileFlareRegular:
6432             evPost(nMissile, 3, 0, kCallbackFXFlareSpark);
6433             sfxPlay3DSound(pMissile, 422, 0, 0);
6434             break;
6435         case kMissileLifeLeechAltSmall:
6436             evPost(nMissile, 3, 0, kCallbackFXArcSpark);
6437             break;
6438         case kMissileArcGargoyle:
6439             sfxPlay3DSound(pMissile, 252, 0, 0);
6440             break;
6441     }
6442 }
6443 
actGetRespawnTime(spritetype * pSprite)6444 int actGetRespawnTime(spritetype *pSprite) {
6445     if (pSprite->extra <= 0) return -1;
6446     XSPRITE *pXSprite = &xsprite[pSprite->extra];
6447     if (IsDudeSprite(pSprite) && !IsPlayerSprite(pSprite)) {
6448         if (pXSprite->respawn == 2 || (pXSprite->respawn != 1 && gGameOptions.nMonsterSettings == 2))
6449             return gGameOptions.nMonsterRespawnTime;
6450         return -1;
6451     }
6452 
6453     if (IsWeaponSprite(pSprite)) {
6454         if (pXSprite->respawn == 3 || gGameOptions.nWeaponSettings == 1) return 0;
6455         else if (pXSprite->respawn != 1 && gGameOptions.nWeaponSettings != 0)
6456             return gGameOptions.nWeaponRespawnTime;
6457         return -1;
6458     }
6459 
6460     if (IsAmmoSprite(pSprite)) {
6461         if (pXSprite->respawn == 2 || (pXSprite->respawn != 1 && gGameOptions.nWeaponSettings != 0))
6462             return gGameOptions.nWeaponRespawnTime;
6463         return -1;
6464     }
6465 
6466     if (IsItemSprite(pSprite)) {
6467         if (pXSprite->respawn == 3 && gGameOptions.nGameType == 1) return 0;
6468         else if (pXSprite->respawn == 2 || (pXSprite->respawn != 1 && gGameOptions.nItemSettings != 0)) {
6469             switch (pSprite->type) {
6470                 case kItemShadowCloak:
6471                 case kItemTwoGuns:
6472                 case kItemReflectShots:
6473                     return gGameOptions.nSpecialRespawnTime;
6474                 case kItemDeathMask:
6475                     return gGameOptions.nSpecialRespawnTime<<1;
6476                 default:
6477                     return gGameOptions.nItemRespawnTime;
6478             }
6479         }
6480         return -1;
6481     }
6482     return -1;
6483 }
6484 
actCheckRespawn(spritetype * pSprite)6485 bool actCheckRespawn(spritetype *pSprite)
6486 {
6487     int nSprite = pSprite->index;
6488     int nXSprite = pSprite->extra;
6489     if (nXSprite > 0)
6490     {
6491         XSPRITE *pXSprite = &xsprite[nXSprite];
6492         int nRespawnTime = actGetRespawnTime(pSprite);
6493         if (nRespawnTime < 0)
6494             return 0;
6495         pXSprite->respawnPending = 1;
6496         if (pSprite->type >= kThingBase && pSprite->type < kThingMax)
6497         {
6498             pXSprite->respawnPending = 3;
6499             if (pSprite->type == kThingTNTBarrel)
6500                 pSprite->cstat |= 32768;
6501         }
6502         if (nRespawnTime > 0)
6503         {
6504             if (pXSprite->respawnPending == 1)
6505                 nRespawnTime = mulscale16(nRespawnTime, 0xa000);
6506             pSprite->owner = pSprite->statnum;
6507             actPostSprite(pSprite->index, kStatRespawn);
6508             pSprite->flags |= kHitagRespawn;
6509             if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
6510             {
6511                 pSprite->cstat &= ~257;
6512                 pSprite->x = baseSprite[nSprite].x;
6513                 pSprite->y = baseSprite[nSprite].y;
6514                 pSprite->z = baseSprite[nSprite].z;
6515             }
6516             evPost(nSprite, 3, nRespawnTime, kCallbackRespawn);
6517         }
6518         return 1;
6519     }
6520     return  0;
6521 }
6522 
actCanSplatWall(int nWall)6523 bool actCanSplatWall(int nWall)
6524 {
6525     dassert(nWall >= 0 && nWall < kMaxWalls);
6526     walltype *pWall = &wall[nWall];
6527     if (pWall->cstat & 16384)
6528         return 0;
6529     if (pWall->cstat & 32768)
6530         return 0;
6531     int nType = GetWallType(nWall);
6532     if (nType >= kWallBase && nType < kWallMax)
6533         return 0;
6534     if (pWall->nextsector != -1)
6535     {
6536         sectortype *pSector = &sector[pWall->nextsector];
6537         if (pSector->type >= kSectorBase && pSector->type < kSectorMax)
6538             return 0;
6539     }
6540     return 1;
6541 }
6542 
actFireVector(spritetype * pShooter,int a2,int a3,int a4,int a5,int a6,VECTOR_TYPE vectorType)6543 void actFireVector(spritetype *pShooter, int a2, int a3, int a4, int a5, int a6, VECTOR_TYPE vectorType)
6544 {
6545     int nShooter = pShooter->index;
6546     dassert(vectorType >= 0 && vectorType < kVectorMax);
6547     VECTORDATA *pVectorData = &gVectorData[vectorType];
6548     int nRange = pVectorData->maxDist;
6549     int hit = VectorScan(pShooter, a2, a3, a4, a5, a6, nRange, 1);
6550     if (hit == 3)
6551     {
6552         int nSprite = gHitInfo.hitsprite;
6553         dassert(nSprite >= 0 && nSprite < kMaxSprites);
6554         spritetype *pSprite = &sprite[nSprite];
6555         if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pShooter, pSprite)) return;
6556         if (IsPlayerSprite(pSprite)) {
6557             PLAYER *pPlayer = &gPlayer[pSprite->type-kDudePlayer1];
6558             if (powerupCheck(pPlayer, kPwUpReflectShots))
6559             {
6560                 gHitInfo.hitsprite = nShooter;
6561                 gHitInfo.hitx = pShooter->x;
6562                 gHitInfo.hity = pShooter->y;
6563                 gHitInfo.hitz = pShooter->z;
6564             }
6565         }
6566     }
6567     int x = gHitInfo.hitx-mulscale(a4, 16, 14);
6568     int y = gHitInfo.hity-mulscale(a5, 16, 14);
6569     int z = gHitInfo.hitz-mulscale(a6, 256, 14);
6570     short nSector = gHitInfo.hitsect;
6571     char nSurf = kSurfNone;
6572     if (nRange == 0 || approxDist(gHitInfo.hitx-pShooter->x, gHitInfo.hity-pShooter->y) < nRange)
6573     {
6574         switch (hit)
6575         {
6576         case 1:
6577         {
6578             int nSector = gHitInfo.hitsect;
6579             if (sector[nSector].ceilingstat&1)
6580                 nSurf = kSurfNone;
6581             else
6582                 nSurf = surfType[sector[nSector].ceilingpicnum];
6583             break;
6584         }
6585         case 2:
6586         {
6587             int nSector = gHitInfo.hitsect;
6588             if (sector[nSector].floorstat&1)
6589                 nSurf = kSurfNone;
6590             else
6591                 nSurf = surfType[sector[nSector].floorpicnum];
6592             break;
6593         }
6594         case 0:
6595         {
6596             int nWall = gHitInfo.hitwall;
6597             dassert(nWall >= 0 && nWall < kMaxWalls);
6598             nSurf = surfType[wall[nWall].picnum];
6599             if (actCanSplatWall(nWall))
6600             {
6601                 int x = gHitInfo.hitx-mulscale(a4, 16, 14);
6602                 int y = gHitInfo.hity-mulscale(a5, 16, 14);
6603                 int z = gHitInfo.hitz-mulscale(a6, 256, 14);
6604                 int nSurf = surfType[wall[nWall].picnum];
6605                 dassert(nSurf < kSurfMax);
6606                 if (pVectorData->surfHit[nSurf].fx1 >= 0)
6607                 {
6608                     spritetype *pFX = gFX.fxSpawn(pVectorData->surfHit[nSurf].fx1, nSector, x, y, z, 0);
6609                     if (pFX)
6610                     {
6611                         pFX->ang = (GetWallAngle(nWall)+512)&2047;
6612                         pFX->cstat |= 16;
6613                     }
6614                 }
6615             }
6616             break;
6617         }
6618         case 4:
6619         {
6620             int nWall = gHitInfo.hitwall;
6621             dassert(nWall >= 0 && nWall < kMaxWalls);
6622             nSurf = surfType[wall[nWall].overpicnum];
6623             int nXWall = wall[nWall].extra;
6624             if (nXWall > 0)
6625             {
6626                 XWALL *pXWall = &xwall[nXWall];
6627                 if (pXWall->triggerVector)
6628                     trTriggerWall(nWall, pXWall, kCmdWallImpact);
6629             }
6630             break;
6631         }
6632         case 3:
6633         {
6634             int nSprite = gHitInfo.hitsprite;
6635             nSurf = surfType[sprite[nSprite].picnum];
6636             dassert(nSprite >= 0 && nSprite < kMaxSprites);
6637             spritetype *pSprite = &sprite[nSprite];
6638             x -= mulscale(a4, 112, 14);
6639             y -= mulscale(a5, 112, 14);
6640             z -= mulscale(a6, 112<<4, 14);
6641             int shift = 4;
6642             if (vectorType == kVectorTine && !IsPlayerSprite(pSprite))
6643                 shift = 3;
6644             actDamageSprite(nShooter, pSprite, pVectorData->dmgType, pVectorData->dmg<<shift);
6645             int nXSprite = pSprite->extra;
6646             if (nXSprite > 0)
6647             {
6648                 XSPRITE *pXSprite = &xsprite[nXSprite];
6649                 if (pXSprite->Vector)
6650                     trTriggerSprite(nSprite, pXSprite, kCmdSpriteImpact);
6651             }
6652             if (pSprite->statnum == kStatThing)
6653             {
6654                 int t = thingInfo[pSprite->type-kThingBase].mass;
6655                 if (t > 0 && pVectorData->impulse)
6656                 {
6657                     int t2 = divscale(pVectorData->impulse, t, 8);
6658                     xvel[nSprite] += mulscale16(a4, t2);
6659                     yvel[nSprite] += mulscale16(a5, t2);
6660                     zvel[nSprite] += mulscale16(a6, t2);
6661                 }
6662                 if (pVectorData->burnTime)
6663                 {
6664                     XSPRITE *pXSprite = &xsprite[nXSprite];
6665                     if (!pXSprite->burnTime)
6666                         evPost(nSprite, 3, 0, kCallbackFXFlameLick);
6667                     actBurnSprite(actSpriteIdToOwnerId(nShooter), pXSprite, pVectorData->burnTime);
6668                 }
6669             }
6670             if (pSprite->statnum == kStatDude)
6671             {
6672                 int t = getDudeInfo(pSprite->type)->mass;
6673 
6674                 #ifdef NOONE_EXTENSIONS
6675                 if (IsDudeSprite(pSprite)) {
6676                     switch (pSprite->type) {
6677                         case kDudeModernCustom:
6678                         case kDudeModernCustomBurning:
6679                             t = getSpriteMassBySize(pSprite);
6680                             break;
6681                     }
6682                 }
6683                 #endif
6684 
6685                 if (t > 0 && pVectorData->impulse)
6686                 {
6687                     int t2 = divscale(pVectorData->impulse, t, 8);
6688                     xvel[nSprite] += mulscale16(a4, t2);
6689                     yvel[nSprite] += mulscale16(a5, t2);
6690                     zvel[nSprite] += mulscale16(a6, t2);
6691                 }
6692                 if (pVectorData->burnTime)
6693                 {
6694                     XSPRITE *pXSprite = &xsprite[nXSprite];
6695                     if (!pXSprite->burnTime)
6696                         evPost(nSprite, 3, 0, kCallbackFXFlameLick);
6697                     actBurnSprite(actSpriteIdToOwnerId(nShooter), pXSprite, pVectorData->burnTime);
6698                 }
6699                 if (Chance(pVectorData->fxChance))
6700                 {
6701                     int t = gVectorData[19].maxDist;
6702                     a4 += Random3(4000);
6703                     a5 += Random3(4000);
6704                     a6 += Random3(4000);
6705                     if (HitScan(pSprite, gHitInfo.hitz, a4, a5, a6, CLIPMASK1, t) == 0)
6706                     {
6707                         if (approxDist(gHitInfo.hitx-pSprite->x, gHitInfo.hity-pSprite->y) <= t)
6708                         {
6709                             int nWall = gHitInfo.hitwall;
6710                             int nSector = gHitInfo.hitsect;
6711                             if (actCanSplatWall(nWall))
6712                             {
6713                                 int x = gHitInfo.hitx - mulscale(a4, 16, 14);
6714                                 int y = gHitInfo.hity - mulscale(a5, 16, 14);
6715                                 int z = gHitInfo.hitz - mulscale(a6, 16<<4, 14);
6716                                 int nSurf = surfType[wall[nWall].picnum];
6717                                 VECTORDATA *pVectorData = &gVectorData[19];
6718                                 FX_ID t2 = pVectorData->surfHit[nSurf].fx2;
6719                                 FX_ID t3 = pVectorData->surfHit[nSurf].fx3;
6720                                 spritetype *pFX = NULL;
6721                                 if (t2 > FX_NONE && (t3 == FX_NONE || Chance(0x4000)))
6722                                     pFX = gFX.fxSpawn(t2, nSector, x, y, z, 0);
6723                                 else if(t3 > FX_NONE)
6724                                     pFX = gFX.fxSpawn(t3, nSector, x, y, z, 0);
6725                                 if (pFX)
6726                                 {
6727                                     zvel[pFX->index] = 0x2222;
6728                                     pFX->ang = (GetWallAngle(nWall)+512)&2047;
6729                                     pFX->cstat |= 16;
6730                                 }
6731                             }
6732                         }
6733                     }
6734                 }
6735                 for (int i = 0; i < pVectorData->bloodSplats; i++)
6736                     if (Chance(pVectorData->splatChance))
6737                         fxSpawnBlood(pSprite, pVectorData->dmg<<4);
6738             }
6739             #ifdef NOONE_EXTENSIONS
6740             // add impulse for sprites from physics list
6741             if (gPhysSpritesCount > 0 && pVectorData->impulse) {
6742                 int nIndex = debrisGetIndex(pSprite->index);
6743                 if (nIndex != -1 && (xsprite[pSprite->extra].physAttr & kPhysDebrisVector)) {
6744                     int impulse = divscale(pVectorData->impulse, ClipLow(gSpriteMass[pSprite->extra].mass, 10), 6);
6745                     xvel[nSprite] += mulscale16(a4, impulse);
6746                     yvel[nSprite] += mulscale16(a5, impulse);
6747                     zvel[nSprite] += mulscale16(a6, impulse);
6748 
6749                     if (pVectorData->burnTime != 0) {
6750                         if (!xsprite[nXSprite].burnTime) evPost(nSprite, 3, 0, kCallbackFXFlameLick);
6751                         actBurnSprite(actSpriteIdToOwnerId(nShooter), &xsprite[nXSprite], pVectorData->burnTime);
6752                     }
6753 
6754                     //if (pSprite->type >= kThingBase && pSprite->type < kThingMax)
6755                         //changespritestat(pSprite->index, kStatThing);
6756                         //actPostSprite(pSprite->index, kStatThing); // if it was a thing, return it's statnum back
6757                 }
6758             }
6759             #endif
6760             break;
6761         }
6762         }
6763     }
6764     dassert(nSurf < kSurfMax);
6765     if (pVectorData->surfHit[nSurf].fx2 >= 0)
6766         gFX.fxSpawn(pVectorData->surfHit[nSurf].fx2, nSector, x, y, z, 0);
6767     if (pVectorData->surfHit[nSurf].fx3 >= 0)
6768         gFX.fxSpawn(pVectorData->surfHit[nSurf].fx3, nSector, x, y, z, 0);
6769     if (pVectorData->surfHit[nSurf].fxSnd >= 0)
6770         sfxPlay3DSound(x, y, z, pVectorData->surfHit[nSurf].fxSnd, nSector);
6771 }
6772 
FireballSeqCallback(int,int nXSprite)6773 void FireballSeqCallback(int, int nXSprite)
6774 {
6775     XSPRITE *pXSprite = &xsprite[nXSprite];
6776     int nSprite = pXSprite->reference;
6777     spritetype *pSprite = &sprite[nSprite];
6778     spritetype *pFX = gFX.fxSpawn(FX_11, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
6779     if (pFX)
6780     {
6781         int nFX = pFX->index;
6782         xvel[nFX] = xvel[nSprite];
6783         yvel[nFX] = yvel[nSprite];
6784         zvel[nFX] = zvel[nSprite];
6785     }
6786 }
6787 
NapalmSeqCallback(int,int nXSprite)6788 void NapalmSeqCallback(int, int nXSprite)
6789 {
6790     XSPRITE *pXSprite = &xsprite[nXSprite];
6791     int nSprite = pXSprite->reference;
6792     spritetype *pSprite = &sprite[nSprite];
6793     spritetype *pFX = gFX.fxSpawn(FX_12, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
6794     if (pFX)
6795     {
6796         int nFX = pFX->index;
6797         xvel[nFX] = xvel[nSprite];
6798         yvel[nFX] = yvel[nSprite];
6799         zvel[nFX] = zvel[nSprite];
6800     }
6801 }
6802 
sub_3888C(int,int nXSprite)6803 void sub_3888C(int, int nXSprite)
6804 {
6805     XSPRITE *pXSprite = &xsprite[nXSprite];
6806     int nSprite = pXSprite->reference;
6807     spritetype *pSprite = &sprite[nSprite];
6808     spritetype *pFX = gFX.fxSpawn(FX_32, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
6809     if (pFX)
6810     {
6811         int nFX = pFX->index;
6812         xvel[nFX] = xvel[nSprite];
6813         yvel[nFX] = yvel[nSprite];
6814         zvel[nFX] = zvel[nSprite];
6815     }
6816 }
6817 
sub_38938(int,int nXSprite)6818 void sub_38938(int, int nXSprite)
6819 {
6820     XSPRITE *pXSprite = &xsprite[nXSprite];
6821     int nSprite = pXSprite->reference;
6822     spritetype *pSprite = &sprite[nSprite];
6823     spritetype *pFX = gFX.fxSpawn(FX_33, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
6824     if (pFX)
6825     {
6826         int nFX = pFX->index;
6827         xvel[nFX] = xvel[nSprite];
6828         yvel[nFX] = yvel[nSprite];
6829         zvel[nFX] = zvel[nSprite];
6830     }
6831 }
6832 
TreeToGibCallback(int,int nXSprite)6833 void TreeToGibCallback(int, int nXSprite)
6834 {
6835     XSPRITE *pXSprite = &xsprite[nXSprite];
6836     int nSprite = pXSprite->reference;
6837     spritetype *pSprite = &sprite[nSprite];
6838     pSprite->type = kThingObjectExplode;
6839     pXSprite->state = 1;
6840     pXSprite->data1 = 15;
6841     pXSprite->data2 = 0;
6842     pXSprite->data3 = 0;
6843     pXSprite->health = thingInfo[17].startHealth;
6844     pXSprite->data4 = 312;
6845     pSprite->cstat |= 257;
6846 }
6847 
DudeToGibCallback1(int,int nXSprite)6848 void DudeToGibCallback1(int, int nXSprite)
6849 {
6850     XSPRITE *pXSprite = &xsprite[nXSprite];
6851     int nSprite = pXSprite->reference;
6852     spritetype *pSprite = &sprite[nSprite];
6853     pSprite->type = kThingBloodChunks;
6854     pXSprite->data1 = 8;
6855     pXSprite->data2 = 0;
6856     pXSprite->data3 = 0;
6857     pXSprite->health = thingInfo[26].startHealth;
6858     pXSprite->data4 = 319;
6859     pXSprite->triggerOnce = 0;
6860     pXSprite->isTriggered = 0;
6861     pXSprite->locked = 0;
6862     pXSprite->targetX = (int)gFrameClock;
6863     pXSprite->state = 1;
6864 }
6865 
DudeToGibCallback2(int,int nXSprite)6866 void DudeToGibCallback2(int, int nXSprite)
6867 {
6868     XSPRITE *pXSprite = &xsprite[nXSprite];
6869     int nSprite = pXSprite->reference;
6870     spritetype *pSprite = &sprite[nSprite];
6871     pSprite->type = kThingBloodChunks;
6872     pXSprite->data1 = 3;
6873     pXSprite->data2 = 0;
6874     pXSprite->data3 = 0;
6875     pXSprite->health = thingInfo[26].startHealth;
6876     pXSprite->data4 = 319;
6877     pXSprite->triggerOnce = 0;
6878     pXSprite->isTriggered = 0;
6879     pXSprite->locked = 0;
6880     pXSprite->targetX = (int)gFrameClock;
6881     pXSprite->state = 1;
6882 }
6883 
actPostSprite(int nSprite,int nStatus)6884 void actPostSprite(int nSprite, int nStatus)
6885 {
6886     int n;
6887     dassert(gPostCount < kMaxSprites);
6888     dassert(nSprite < kMaxSprites && sprite[nSprite].statnum < kMaxStatus);
6889     dassert(nStatus >= 0 && nStatus <= kStatFree);
6890     if (sprite[nSprite].flags&32)
6891     {
6892         for (n = 0; n < gPostCount; n++)
6893             if (gPost[n].at0 == nSprite)
6894                 break;
6895         dassert(n < gPostCount);
6896     }
6897     else
6898     {
6899         n = gPostCount;
6900         sprite[nSprite].flags |= 32;
6901         gPostCount++;
6902     }
6903     gPost[n].at0 = nSprite;
6904     gPost[n].at2 = nStatus;
6905 }
6906 
actPostProcess(void)6907 void actPostProcess(void)
6908 {
6909     for (int i = 0; i < gPostCount; i++)
6910     {
6911         POSTPONE *pPost = &gPost[i];
6912         int nSprite = pPost->at0;
6913         spritetype *pSprite = &sprite[nSprite];
6914         pSprite->flags &= ~32;
6915         int nStatus = pPost->at2;
6916         if (nStatus == kStatFree)
6917         {
6918             evKill(nSprite, 3);
6919             if (sprite[nSprite].extra > 0)
6920                 seqKill(3, sprite[nSprite].extra);
6921             DeleteSprite(nSprite);
6922         }
6923         else
6924             ChangeSpriteStat(nSprite, nStatus);
6925     }
6926     gPostCount = 0;
6927 }
6928 
MakeSplash(spritetype * pSprite,XSPRITE * pXSprite)6929 void MakeSplash(spritetype *pSprite, XSPRITE *pXSprite)
6930 {
6931     UNREFERENCED_PARAMETER(pXSprite);
6932     pSprite->flags &= ~2;
6933     int nXSprite = pSprite->extra;
6934     pSprite->z -= 4 << 8;
6935     int nSurface = tileGetSurfType(gSpriteHit[nXSprite].florhit);
6936     switch (pSprite->type) {
6937         case kThingDripWater:
6938             switch (nSurface) {
6939                 case kSurfWater:
6940                     seqSpawn(6, 3, nXSprite, -1);
6941                     sfxPlay3DSound(pSprite, 356, -1, 0);
6942                     break;
6943                 default:
6944                     seqSpawn(7, 3, nXSprite, -1);
6945                     sfxPlay3DSound(pSprite, 354, -1, 0);
6946                     break;
6947             }
6948             break;
6949         case kThingDripBlood:
6950             seqSpawn(8, 3, nXSprite, -1);
6951             sfxPlay3DSound(pSprite, 354, -1, 0);
6952             break;
6953     }
6954 }
6955 
6956 class ActorLoadSave : public LoadSave
6957 {
6958     virtual void Load(void);
6959     virtual void Save(void);
6960 };
6961 
Load(void)6962 void ActorLoadSave::Load(void)
6963 {
6964     Read(gSpriteHit, sizeof(gSpriteHit));
6965     Read(gAffectedSectors, sizeof(gAffectedSectors));
6966     Read(gAffectedXWalls, sizeof(gAffectedXWalls));
6967     Read(&gPostCount, sizeof(gPostCount));
6968     Read(gPost, sizeof(gPost));
6969     actInit(true);
6970 }
6971 
Save(void)6972 void ActorLoadSave::Save(void)
6973 {
6974     Write(gSpriteHit, sizeof(gSpriteHit));
6975     Write(gAffectedSectors, sizeof(gAffectedSectors));
6976     Write(gAffectedXWalls, sizeof(gAffectedXWalls));
6977     Write(&gPostCount, sizeof(gPostCount));
6978     Write(gPost, sizeof(gPost));
6979 }
6980 
6981 static ActorLoadSave *myLoadSave;
6982 
ActorLoadSaveConstruct(void)6983 void ActorLoadSaveConstruct(void)
6984 {
6985     myLoadSave = new ActorLoadSave();
6986 }
6987 
6988 #ifdef POLYMER
6989 
6990 // this is the same crap as in game.c's tspr manipulation.  puke.
6991 // XXX: may access tilesizy out-of-bounds by bad user code.
6992 #define LIGHTRAD(spriteNum, s) (s->yrepeat * tilesiz[s->picnum].y)
6993 #define LIGHTRAD2(spriteNum, s) ((s->yrepeat + ((rand() % s->yrepeat)>>2)) * tilesiz[s->picnum].y)
6994 
G_AddGameLight(int lightRadius,int spriteNum,int zOffset,int lightRange,int lightColor,int lightPrio)6995 void G_AddGameLight(int lightRadius, int spriteNum, int zOffset, int lightRange, int lightColor, int lightPrio)
6996 {
6997     auto const s = &sprite[spriteNum];
6998 
6999     if (videoGetRenderMode() != REND_POLYMER || pr_lighting != 1)
7000         return;
7001 
7002     if (gPolymerLight[spriteNum].lightptr == NULL)
7003     {
7004 #pragma pack(push, 1)
7005         _prlight mylight;
7006 #pragma pack(pop)
7007         Bmemset(&mylight, 0, sizeof(mylight));
7008 
7009         mylight.sector = s->sectnum;
7010         mylight.x = s->x;
7011         mylight.y = s->y;
7012         mylight.z = s->z - zOffset;
7013         mylight.color[0] = lightColor & 255;
7014         mylight.color[1] = (lightColor >> 8) & 255;
7015         mylight.color[2] = (lightColor >> 16) & 255;
7016         mylight.radius = lightRadius;
7017         gPolymerLight[spriteNum].lightmaxrange = mylight.range = lightRange;
7018 
7019         mylight.priority = lightPrio;
7020         mylight.tilenum = 0;
7021 
7022         mylight.publicflags.emitshadow = 1;
7023         mylight.publicflags.negative = 0;
7024 
7025         gPolymerLight[spriteNum].lightId = polymer_addlight(&mylight);
7026         if (gPolymerLight[spriteNum].lightId >= 0)
7027             gPolymerLight[spriteNum].lightptr = &prlights[gPolymerLight[spriteNum].lightId];
7028         return;
7029     }
7030 
7031     s->z -= zOffset;
7032 
7033     if (lightRange<gPolymerLight[spriteNum].lightmaxrange>> 1)
7034         gPolymerLight[spriteNum].lightmaxrange = 0;
7035 
7036     if (lightRange > gPolymerLight[spriteNum].lightmaxrange || lightPrio != gPolymerLight[spriteNum].lightptr->priority ||
7037         Bmemcmp(&sprite[spriteNum], gPolymerLight[spriteNum].lightptr, sizeof(int32_t) * 3))
7038     {
7039         if (lightRange > gPolymerLight[spriteNum].lightmaxrange)
7040             gPolymerLight[spriteNum].lightmaxrange = lightRange;
7041 
7042         Bmemcpy(gPolymerLight[spriteNum].lightptr, &sprite[spriteNum], sizeof(int32_t) * 3);
7043         gPolymerLight[spriteNum].lightptr->sector = s->sectnum;
7044         gPolymerLight[spriteNum].lightptr->flags.invalidate = 1;
7045     }
7046 
7047     gPolymerLight[spriteNum].lightptr->priority = lightPrio;
7048     gPolymerLight[spriteNum].lightptr->range = lightRange;
7049     gPolymerLight[spriteNum].lightptr->color[0] = lightColor & 255;
7050     gPolymerLight[spriteNum].lightptr->color[1] = (lightColor >> 8) & 255;
7051     gPolymerLight[spriteNum].lightptr->color[2] = (lightColor >> 16) & 255;
7052 
7053     s->z += zOffset;
7054 }
7055 
actDoLight(int nSprite)7056 void actDoLight(int nSprite)
7057 {
7058     auto const pSprite = &sprite[nSprite];
7059     int savedFires = 0;
7060     if (((sector[pSprite->sectnum].floorz - sector[pSprite->sectnum].ceilingz) < 16) || pSprite->z > sector[pSprite->sectnum].floorz)
7061     {
7062         if (gPolymerLight[nSprite].lightptr != NULL)
7063             DeleteLight(nSprite);
7064     }
7065     else
7066     {
7067         if (gPolymerLight[nSprite].lightptr != NULL && gPolymerLight[nSprite].lightcount)
7068         {
7069             if (!(--gPolymerLight[nSprite].lightcount))
7070                 DeleteLight(nSprite);
7071         }
7072 
7073         if (pr_lighting != 1)
7074             return;
7075 
7076         switch (pSprite->statnum)
7077         {
7078         case kStatProjectile:
7079             switch (pSprite->type)
7080             {
7081             case kMissileTeslaRegular:
7082                 {
7083                     int32_t x = ((sintable[(pSprite->ang+512)&2047])>>6);
7084                     int32_t y = ((sintable[(pSprite->ang)&2047])>>6);
7085 
7086                     pSprite->x -= x;
7087                     pSprite->y -= y;
7088 
7089                     G_AddGameLight(0, nSprite, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 2048, 80+(252<<8)+(120<<16),PR_LIGHT_PRIO_HIGH_GAME);
7090 
7091                     pSprite->x += x;
7092                     pSprite->y += y;
7093                 }
7094                 break;
7095             }
7096             break;
7097         case kStatExplosion:
7098             switch (pSprite->type)
7099             {
7100             default:
7101                 if (!gPolymerLight[nSprite].lightcount)
7102                 {
7103                     // XXX: This block gets CODEDUP'd too much.
7104                     int32_t x = ((sintable[(pSprite->ang+512)&2047])>>6);
7105                     int32_t y = ((sintable[(pSprite->ang)&2047])>>6);
7106 
7107                     pSprite->x -= x;
7108                     pSprite->y -= y;
7109 
7110                     G_AddGameLight(0, nSprite, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite), 240+(160<<8)+(80<<16),
7111                         pSprite->yrepeat > 32 ? PR_LIGHT_PRIO_HIGH_GAME : PR_LIGHT_PRIO_LOW_GAME);
7112 
7113                     pSprite->x += x;
7114                     pSprite->y += y;
7115                 }
7116                 break;
7117             }
7118             break;
7119         }
7120     }
7121 #if 0
7122     if (((sector[pSprite->sectnum].floorz - sector[pSprite->sectnum].ceilingz) < 16) || pSprite->z > sector[pSprite->sectnum].floorz || pSprite->z > actor[spriteNum].floorz ||
7123         (pSprite->picnum != SECTOREFFECTOR && ((pSprite->cstat & 32768) || pSprite->yrepeat < 4)) ||
7124         A_CheckSpriteFlags(spriteNum, SFLAG_NOLIGHT) || (A_CheckSpriteFlags(spriteNum, SFLAG_USEACTIVATOR) && sector[pSprite->sectnum].lotag & 16384))
7125     {
7126         if (actor[spriteNum].lightptr != NULL)
7127             A_DeleteLight(spriteNum);
7128     }
7129     else
7130     {
7131         if (actor[spriteNum].lightptr != NULL && actor[spriteNum].lightcount)
7132         {
7133             if (!(--actor[spriteNum].lightcount))
7134                 A_DeleteLight(spriteNum);
7135         }
7136 
7137         if (pr_lighting != 1)
7138             return;
7139 
7140 #ifndef EDUKE32_STANDALONE
7141         for (int ii=0; ii<2; ii++)
7142         {
7143             if (pSprite->picnum <= 0)  // oob safety
7144                 break;
7145 
7146             switch (DYNAMICTILEMAP(pSprite->picnum-1+ii))
7147             {
7148             case DIPSWITCH__STATIC:
7149             case DIPSWITCH2__STATIC:
7150             case DIPSWITCH3__STATIC:
7151             case PULLSWITCH__STATIC:
7152             case SLOTDOOR__STATIC:
7153             case LIGHTSWITCH__STATIC:
7154             case SPACELIGHTSWITCH__STATIC:
7155             case SPACEDOORSWITCH__STATIC:
7156             case FRANKENSTINESWITCH__STATIC:
7157             case POWERSWITCH1__STATIC:
7158             case LOCKSWITCH1__STATIC:
7159             case POWERSWITCH2__STATIC:
7160             case TECHSWITCH__STATIC:
7161             case ACCESSSWITCH__STATIC:
7162             case ACCESSSWITCH2__STATIC:
7163                 {
7164                     if ((pSprite->cstat & 32768) || A_CheckSpriteFlags(spriteNum, SFLAG_NOLIGHT))
7165                     {
7166                         if (actor[spriteNum].lightptr != NULL)
7167                             A_DeleteLight(spriteNum);
7168                         break;
7169                     }
7170 
7171                     vec2_t const d = { sintable[(pSprite->ang+512)&2047]>>7, sintable[(pSprite->ang)&2047]>>7 };
7172 
7173                     pSprite->x += d.x;
7174                     pSprite->y += d.y;
7175 
7176                     int16_t sectnum = pSprite->sectnum;
7177                     updatesector(pSprite->x, pSprite->y, &sectnum);
7178 
7179                     if ((unsigned) sectnum >= MAXSECTORS || pSprite->z > sector[sectnum].floorz || pSprite->z < sector[sectnum].ceilingz)
7180                         goto POOP;
7181 
7182                     G_AddGameLight(0, spriteNum, (pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1, 512-ii*128,
7183                         ii==0 ? (172+(200<<8)+(104<<16)) : 216+(52<<8)+(20<<16), PR_LIGHT_PRIO_LOW);
7184 
7185                 POOP:
7186                     pSprite->x -= d.x;
7187                     pSprite->y -= d.y;
7188                 }
7189                 break;
7190             }
7191         }
7192 
7193         switch (DYNAMICTILEMAP(pSprite->picnum))
7194         {
7195         case ATOMICHEALTH__STATIC:
7196             G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD2(spriteNum, pSprite), 128+(128<<8)+(255<<16),PR_LIGHT_PRIO_HIGH_GAME);
7197             break;
7198 
7199         case FIRE__STATIC:
7200         case FIRE2__STATIC:
7201         case BURNING__STATIC:
7202         case BURNING2__STATIC:
7203             {
7204                 uint32_t color;
7205                 int32_t jj;
7206 
7207                 static int32_t savedfires[32][4];  // sectnum x y z
7208 
7209                 /*
7210                 if (Actor[i].floorz - Actor[i].ceilingz < 128) break;
7211                 if (s->z > Actor[i].floorz+2048) break;
7212                 */
7213 
7214                 switch (pSprite->pal)
7215                 {
7216                 case 1: color = 128+(128<<8)+(255<<16); break;
7217                 case 2: color = 255+(48<<8)+(48<<16); break;
7218                 case 8: color = 48+(255<<8)+(48<<16); break;
7219                 default: color = 240+(160<<8)+(80<<16); break;
7220                 }
7221 
7222                 for (jj=savedFires-1; jj>=0; jj--)
7223                     if (savedfires[jj][0]==pSprite->sectnum && savedfires[jj][1]==(pSprite->x>>3) &&
7224                         savedfires[jj][2]==(pSprite->y>>3) && savedfires[jj][3]==(pSprite->z>>7))
7225                         break;
7226 
7227                 if (jj==-1 && savedFires<32)
7228                 {
7229                     jj = savedFires;
7230                     G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD2(spriteNum, pSprite), color, PR_LIGHT_PRIO_HIGH_GAME);
7231                     savedfires[jj][0] = pSprite->sectnum;
7232                     savedfires[jj][1] = pSprite->x>>3;
7233                     savedfires[jj][2] = pSprite->y>>3;
7234                     savedfires[jj][3] = pSprite->z>>7;
7235                     savedFires++;
7236                 }
7237             }
7238             break;
7239 
7240         case OOZFILTER__STATIC:
7241             if (pSprite->xrepeat > 4)
7242                 G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 4096, 176+(252<<8)+(120<<16),PR_LIGHT_PRIO_HIGH_GAME);
7243             break;
7244         case FLOORFLAME__STATIC:
7245         case FIREBARREL__STATIC:
7246         case FIREVASE__STATIC:
7247             G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<2), LIGHTRAD2(spriteNum, pSprite)>>1, 255+(95<<8),PR_LIGHT_PRIO_HIGH_GAME);
7248             break;
7249 
7250         case EXPLOSION2__STATIC:
7251             if (!actor[spriteNum].lightcount)
7252             {
7253                 // XXX: This block gets CODEDUP'd too much.
7254                 int32_t x = ((sintable[(pSprite->ang+512)&2047])>>6);
7255                 int32_t y = ((sintable[(pSprite->ang)&2047])>>6);
7256 
7257                 pSprite->x -= x;
7258                 pSprite->y -= y;
7259 
7260                 G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite), 240+(160<<8)+(80<<16),
7261                     pSprite->yrepeat > 32 ? PR_LIGHT_PRIO_HIGH_GAME : PR_LIGHT_PRIO_LOW_GAME);
7262 
7263                 pSprite->x += x;
7264                 pSprite->y += y;
7265             }
7266             break;
7267         case FORCERIPPLE__STATIC:
7268         case TRANSPORTERBEAM__STATIC:
7269             G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite), 80+(80<<8)+(255<<16),PR_LIGHT_PRIO_LOW_GAME);
7270             break;
7271         case GROWSPARK__STATIC:
7272             {
7273                 int32_t x = ((sintable[(pSprite->ang+512)&2047])>>6);
7274                 int32_t y = ((sintable[(pSprite->ang)&2047])>>6);
7275 
7276                 pSprite->x -= x;
7277                 pSprite->y -= y;
7278 
7279                 G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 1024, 216+(52<<8)+(20<<16),PR_LIGHT_PRIO_HIGH_GAME);
7280 
7281                 pSprite->x += x;
7282                 pSprite->y += y;
7283             }
7284             break;
7285         case SHRINKEREXPLOSION__STATIC:
7286             {
7287                 int32_t x = ((sintable[(pSprite->ang+512)&2047])>>6);
7288                 int32_t y = ((sintable[(pSprite->ang)&2047])>>6);
7289 
7290                 pSprite->x -= x;
7291                 pSprite->y -= y;
7292 
7293                 G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 2048, 176+(252<<8)+(120<<16),PR_LIGHT_PRIO_HIGH_GAME);
7294 
7295                 pSprite->x += x;
7296                 pSprite->y += y;
7297             }
7298             break;
7299         case FREEZEBLAST__STATIC:
7300             G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite)<<2, 72+(88<<8)+(140<<16),PR_LIGHT_PRIO_HIGH_GAME);
7301             break;
7302         case COOLEXPLOSION1__STATIC:
7303             G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite)<<2, 128+(0<<8)+(255<<16),PR_LIGHT_PRIO_HIGH_GAME);
7304             break;
7305         case SHRINKSPARK__STATIC:
7306             G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite), 176+(252<<8)+(120<<16),PR_LIGHT_PRIO_HIGH_GAME);
7307             break;
7308         case FIRELASER__STATIC:
7309             if (pSprite->statnum == STAT_PROJECTILE)
7310                 G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 64 * pSprite->yrepeat, 255+(95<<8),PR_LIGHT_PRIO_LOW_GAME);
7311             break;
7312         case RPG__STATIC:
7313             G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 128 * pSprite->yrepeat, 255+(95<<8),PR_LIGHT_PRIO_LOW_GAME);
7314             break;
7315         case SHOTSPARK1__STATIC:
7316             if (actor[spriteNum].t_data[2] == 0) // check for first frame of action
7317             {
7318                 int32_t x = ((sintable[(pSprite->ang+512)&2047])>>7);
7319                 int32_t y = ((sintable[(pSprite->ang)&2047])>>7);
7320 
7321                 pSprite->x -= x;
7322                 pSprite->y -= y;
7323 
7324                 G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 8 * pSprite->yrepeat, 240+(160<<8)+(80<<16),PR_LIGHT_PRIO_LOW_GAME);
7325                 actor[spriteNum].lightcount = 1;
7326 
7327                 pSprite->x += x;
7328                 pSprite->y += y;
7329             }
7330             break;
7331         }
7332 #endif
7333     }
7334 #endif
7335 }
7336 #endif // POLYMER
7337