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 = §or[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 = §or[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 = §or[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 = §or[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 = §or[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, §num);
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