1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 1997, 2005 - 3D Realms Entertainment
4
5 This file is part of Shadow Warrior version 1.2
6
7 Shadow Warrior is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
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 Original Source: 1997 - Frank Maddin and Jim Norwood
23 Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
24 */
25 //-------------------------------------------------------------------------
26 #include "build.h"
27
28 #include "keys.h"
29 #include "names2.h"
30 #include "game.h"
31 #include "tags.h"
32 #include "ai.h"
33 #include "weapon.h"
34 #include "actor.h"
35
36 int InitSpriteGrenade(short SpriteNum);
37 int InitSpriteChemBomb(short SpriteNum);
38 int InitFlashBomb(short SpriteNum);
39 int InitCaltrops(short SpriteNum);
40 int InitPhosphorus(int16_t SpriteNum);
41
42 //////////////////////
43 //
44 // SKULL Wait
45 //
46 //////////////////////
47
48
49 extern DAMAGE_DATA DamageData[];
50 ANIMATOR DoSkullMove,NullAnimator,DoActorDebris;
51
52 #define SKULL_RATE 10
53 ANIMATOR DoSkullWait;
54
55 STATE s_SkullWait[5][1] =
56 {
57 {
58 {SKULL_R0 + 0, SKULL_RATE, DoSkullWait, &s_SkullWait[0][0]},
59 },
60 {
61 {SKULL_R1 + 0, SKULL_RATE, DoSkullWait, &s_SkullWait[1][0]},
62 },
63 {
64 {SKULL_R2 + 0, SKULL_RATE, DoSkullWait, &s_SkullWait[2][0]},
65 },
66 {
67 {SKULL_R3 + 0, SKULL_RATE, DoSkullWait, &s_SkullWait[3][0]},
68 },
69 {
70 {SKULL_R4 + 0, SKULL_RATE, DoSkullWait, &s_SkullWait[4][0]},
71 }
72 };
73
74
75 STATEp sg_SkullWait[] =
76 {
77 &s_SkullWait[0][0],
78 &s_SkullWait[1][0],
79 &s_SkullWait[2][0],
80 &s_SkullWait[3][0],
81 &s_SkullWait[4][0]
82 };
83
84 ATTRIBUTE SkullAttrib =
85 {
86 {60, 80, 100, 130}, // Speeds
87 {3, 0, -2, -3}, // Tic Adjusts
88 3, // MaxWeapons;
89 {
90 DIGI_AHAMBIENT, 0, 0, 0, DIGI_AHSCREAM,
91 DIGI_AHEXPLODE,0,0,0,0
92 }
93 };
94
95 //////////////////////
96 //
97 // SKULL for Serp God
98 //
99 //////////////////////
100
101 ANIMATOR DoSerpRing;
102
103 STATE s_SkullRing[5][1] =
104 {
105 {
106 {SKULL_R0 + 0, SKULL_RATE, DoSerpRing, &s_SkullRing[0][0]},
107 },
108 {
109 {SKULL_R1 + 0, SKULL_RATE, DoSerpRing, &s_SkullRing[1][0]},
110 },
111 {
112 {SKULL_R2 + 0, SKULL_RATE, DoSerpRing, &s_SkullRing[2][0]},
113 },
114 {
115 {SKULL_R3 + 0, SKULL_RATE, DoSerpRing, &s_SkullRing[3][0]},
116 },
117 {
118 {SKULL_R4 + 0, SKULL_RATE, DoSerpRing, &s_SkullRing[4][0]},
119 }
120 };
121
122
123 STATEp sg_SkullRing[] =
124 {
125 &s_SkullRing[0][0],
126 &s_SkullRing[1][0],
127 &s_SkullRing[2][0],
128 &s_SkullRing[3][0],
129 &s_SkullRing[4][0]
130 };
131
132
133
134 //////////////////////
135 //
136 // SKULL Jump
137 //
138 //////////////////////
139
140 ANIMATOR DoSkullJump;
141
142 STATE s_SkullJump[5][1] =
143 {
144 {
145 {SKULL_R0 + 0, SKULL_RATE, DoSkullJump, &s_SkullJump[0][0]},
146 },
147 {
148 {SKULL_R1 + 0, SKULL_RATE, DoSkullJump, &s_SkullJump[1][0]},
149 },
150 {
151 {SKULL_R2 + 0, SKULL_RATE, DoSkullJump, &s_SkullJump[2][0]},
152 },
153 {
154 {SKULL_R3 + 0, SKULL_RATE, DoSkullJump, &s_SkullJump[3][0]},
155 },
156 {
157 {SKULL_R4 + 0, SKULL_RATE, DoSkullJump, &s_SkullJump[4][0]},
158 }
159 };
160
161
162 STATEp sg_SkullJump[] =
163 {
164 &s_SkullJump[0][0],
165 &s_SkullJump[1][0],
166 &s_SkullJump[2][0],
167 &s_SkullJump[3][0],
168 &s_SkullJump[4][0]
169 };
170
171
172 //////////////////////
173 //
174 // SKULL Explode
175 //
176 //////////////////////
177
178 #define SKULL_EXPLODE_RATE 11
179 ANIMATOR DoSuicide;
180 ANIMATOR DoDamageTest;
181 ANIMATOR DoSkullSpawnShrap;
182
183 STATE s_SkullExplode[] =
184 {
185 {SKULL_EXPLODE + 0, 1, NullAnimator, &s_SkullExplode[1]},
186 {SKULL_EXPLODE + 0, SF_QUICK_CALL, DoDamageTest, &s_SkullExplode[2]},
187 {SKULL_EXPLODE + 0, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[3]},
188 {SKULL_EXPLODE + 1, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[4]},
189 {SKULL_EXPLODE + 2, SF_QUICK_CALL, DoSkullSpawnShrap, &s_SkullExplode[5]},
190 {SKULL_EXPLODE + 2, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[6]},
191 {SKULL_EXPLODE + 3, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[7]},
192 {SKULL_EXPLODE + 4, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[8]},
193 {SKULL_EXPLODE + 5, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[9]},
194 {SKULL_EXPLODE + 6, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[10]},
195 {SKULL_EXPLODE + 7, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[11]},
196 {SKULL_EXPLODE + 8, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[12]},
197 {SKULL_EXPLODE + 9, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[13]},
198 {SKULL_EXPLODE +10, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[14]},
199 {SKULL_EXPLODE +11, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[15]},
200 {SKULL_EXPLODE +12, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[16]},
201 {SKULL_EXPLODE +13, SKULL_EXPLODE_RATE, NullAnimator, &s_SkullExplode[17]},
202 {SKULL_EXPLODE +13, SKULL_EXPLODE_RATE, DoSuicide, &s_SkullExplode[17]}
203 };
204
205 STATEp sg_SkullExplode[] =
206 {
207 s_SkullExplode,
208 };
209
210
211 int
SetupSkull(short SpriteNum)212 SetupSkull(short SpriteNum)
213 {
214 SPRITEp sp = &sprite[SpriteNum];
215 USERp u;
216 ANIMATOR DoActorDecide;
217
218 if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
219 {
220 u = User[SpriteNum];
221 ASSERT(u);
222 }
223 else
224 {
225 User[SpriteNum] = u = SpawnUser(SpriteNum,SKULL_R0,s_SkullWait[0]);
226 u->Health = HEALTH_SKULL;
227 }
228
229 ChangeState(SpriteNum, s_SkullWait[0]);
230 u->Attrib = &SkullAttrib;
231 DoActorSetSpeed(SpriteNum, NORM_SPEED);
232 u->StateEnd = s_SkullExplode;
233 u->Rot = sg_SkullWait;
234
235 u->ID = SKULL_R0;
236
237 EnemyDefaults(SpriteNum, NULL, NULL);
238 sp->clipdist = (128+64) >> 2;
239 SET(u->Flags, SPR_XFLIP_TOGGLE);
240 SET(sp->cstat, CSTAT_SPRITE_YCENTER);
241
242 u->Radius = 400;
243
244 if (SPRITEp_BOS(sp) > u->loz - Z(16))
245 {
246 sp->z = u->loz + Z(SPRITEp_YOFF(sp));
247
248 u->loz = sp->z;
249 // leave 8 pixels above the ground
250 sp->z += SPRITEp_SIZE_TOS(sp) - Z(3);;
251 }
252 else
253 {
254 u->Counter = RANDOM_P2(2048);
255 u->sz = sp->z;
256 }
257
258
259 return 0;
260 }
261
262 int
DoSkullMove(int16_t SpriteNum)263 DoSkullMove(int16_t SpriteNum)
264 {
265 SPRITEp sp = &sprite[SpriteNum];
266 USERp u = User[SpriteNum];
267 int32_t dax, day, daz;
268
269 dax = MOVEx(sp->xvel, sp->ang);
270 day = MOVEy(sp->xvel, sp->ang);
271 daz = sp->zvel;
272
273 u->ret = move_missile(SpriteNum, dax, day, daz, Z(16), Z(16), CLIPMASK_MISSILE, ACTORMOVETICS);
274
275 DoFindGroundPoint(SpriteNum);
276 return 0;
277 }
278
279 int
DoSkullBeginDeath(int16_t SpriteNum)280 DoSkullBeginDeath(int16_t SpriteNum)
281 {
282 SPRITEp sp = &sprite[SpriteNum];
283 USERp u = User[SpriteNum];
284 int16_t i,num_ord=0;
285 //extern short *DamageRadiusSkull;
286
287 // Decrease for Serp God
288 if (sp->owner >= 0)
289 User[sp->owner]->Counter--;
290
291 // starts the explosion that does the actual damage
292
293 switch (sp->hitag)
294 {
295 case 1:
296 if (sp->lotag) num_ord = sp->lotag;
297 else
298 num_ord = 2;
299 if (num_ord > 3) num_ord = 3;
300 for (i=0; i<num_ord; i++)
301 {
302 sp->ang = NORM_ANGLE(sp->ang+(i*1024));
303 InitSpriteChemBomb(SpriteNum);
304 }
305 break;
306
307 case 2:
308 if (sp->lotag) num_ord = sp->lotag;
309 else
310 num_ord = 5;
311 if (num_ord > 10) num_ord = 10;
312 for (i=0; i<num_ord; i++)
313 {
314 sp->ang = NORM_ANGLE(RANDOM_RANGE(2048));
315 InitCaltrops(SpriteNum);
316 }
317 break;
318
319 case 3:
320 UpdateSinglePlayKills(SpriteNum);
321 InitFlashBomb(SpriteNum);
322 break;
323
324 case 4:
325 if (sp->lotag) num_ord = sp->lotag;
326 else
327 num_ord = 5;
328 if (num_ord > 10) num_ord = 10;
329 for (i=0; i<num_ord; i++)
330 {
331 sp->ang = NORM_ANGLE(sp->ang+(i*(2048/num_ord)));
332 InitSpriteGrenade(SpriteNum);
333 }
334 break;
335 default:
336 SpawnMineExp(SpriteNum);
337 for (i=0; i<3; i++)
338 {
339 sp->ang = NORM_ANGLE(RANDOM_RANGE(2048));
340 InitPhosphorus(SpriteNum);
341 }
342 break;
343 }
344
345 RESET(sp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
346 u->RotNum = 0;
347 u->Tics = 0;
348 // ChangeState(SpriteNum, u->StateEnd);
349 //u->State = u->StateStart = u->StateEnd;
350 //u->State = u->StateEnd;
351 u->ID = SKULL_R0;
352 u->Radius = DamageData[DMG_SKULL_EXP].radius; //*DamageRadiusSkull;
353 u->OverlapZ = Z(64);
354 change_sprite_stat(SpriteNum, STAT_DEAD_ACTOR);
355 sp->shade = -40;
356
357 SpawnLittleExp(SpriteNum);
358 SetSuicide(SpriteNum);
359
360 //u->spal = sp->pal = PALETTE_RED_LIGHTING;
361
362
363 return 0;
364 }
365
366
DoSkullJump(short SpriteNum)367 int DoSkullJump(short SpriteNum)
368 {
369 SPRITEp sp = &sprite[SpriteNum];
370 USERp u = User[SpriteNum];
371
372
373 if (sp->xvel)
374 DoSkullMove(SpriteNum);
375 else
376 sp->ang = NORM_ANGLE(sp->ang + (64 * ACTORMOVETICS));
377
378 if (TEST(u->Flags,SPR_JUMPING))
379 {
380 DoJump(SpriteNum);
381 }
382 else if (TEST(u->Flags,SPR_FALLING))
383 {
384 DoFall(SpriteNum);
385
386 // jump/fall type
387 if (sp->xvel)
388 {
389 SWBOOL SpriteOverlapZ(int16_t, int16_t, int);
390
391 int dist,a,b,c;
392
393 DISTANCE(sp->x, sp->y, u->tgt_sp->x, u->tgt_sp->y, dist, a, b, c);
394
395 if (dist < 1000 &&
396 SpriteOverlapZ(SpriteNum, u->tgt_sp - sprite, Z(32)))
397 {
398 UpdateSinglePlayKills(SpriteNum);
399 DoSkullBeginDeath(SpriteNum);
400 return 0;
401 }
402
403 if ((sp->z > u->loz - Z(36)))
404 {
405 sp->z = u->loz - Z(36);
406 UpdateSinglePlayKills(SpriteNum);
407 DoSkullBeginDeath(SpriteNum);
408 return 0;
409 }
410 }
411 // non jumping type
412 else
413 {
414 if (u->jump_speed > 200)
415 {
416 UpdateSinglePlayKills(SpriteNum);
417 DoSkullBeginDeath(SpriteNum);
418 }
419 }
420
421 }
422 else
423 {
424 UpdateSinglePlayKills(SpriteNum);
425 DoSkullBeginDeath(SpriteNum);
426 }
427
428 return 0;
429 }
430
DoSkullBob(short SpriteNum)431 int DoSkullBob(short SpriteNum)
432 {
433 SPRITEp sp = &sprite[SpriteNum];
434 USERp u = User[SpriteNum];
435
436 // actor does a sine wave about u->sz - this is the z mid point
437 #define SKULL_BOB_AMT (Z(16))
438
439 u->Counter = (u->Counter + (ACTORMOVETICS << 3) + (ACTORMOVETICS << 1)) & 2047;
440 sp->z = u->sz + ((SKULL_BOB_AMT * (int)sintable[u->Counter]) >> 14) +
441 ((DIV2(SKULL_BOB_AMT) * (int)sintable[u->Counter]) >> 14);
442
443 return 0;
444 }
445
DoSkullSpawnShrap(short SpriteNum)446 int DoSkullSpawnShrap(short SpriteNum)
447 {
448 int SpawnShrap(short, short);
449
450 SpawnShrap(SpriteNum, -1);
451
452 //PlaySpriteSound(SpriteNum,attr_extra1,v3df_none);
453 return 0;
454 }
455
DoSkullWait(short SpriteNum)456 int DoSkullWait(short SpriteNum)
457 {
458 SPRITEp sp = &sprite[SpriteNum];
459 USERp u = User[SpriteNum];
460 int a,b,c,dist;
461
462 DISTANCE(sp->x, sp->y, u->tgt_sp->x, u->tgt_sp->y, dist, a, b, c);
463
464 DoActorPickClosePlayer(SpriteNum);
465
466 //if (dist < u->active_range)
467 // return(0);
468
469 if ((u->WaitTics -= ACTORMOVETICS) <= 0)
470 {
471 PlaySound(DIGI_AHSCREAM,&sp->x,&sp->y,&sp->z,v3df_none);
472 u->WaitTics = SEC(3) + RANDOM_RANGE(360);
473 }
474
475 // below the floor type
476 if (sp->z > u->loz)
477 {
478 // look for closest player every once in a while
479 if (dist < 3500)
480 {
481 sp->xvel = 0;
482 u->jump_speed = -600;
483 NewStateGroup(SpriteNum, sg_SkullJump);
484 DoBeginJump(SpriteNum);
485 }
486 }
487 else
488 // above the floor type
489 {
490 sp->ang = NORM_ANGLE(sp->ang + (48 * ACTORMOVETICS));
491
492 DoSkullBob(SpriteNum);
493
494 if (dist < 8000)
495 {
496 sp->ang = getangle(u->tgt_sp->x - sp->x, u->tgt_sp->y - sp->y);
497 sp->xvel = 128 + (RANDOM_P2(256<<8)>>8);
498 u->jump_speed = -700;
499 NewStateGroup(SpriteNum, sg_SkullJump);
500 DoBeginJump(SpriteNum);
501 }
502 }
503
504 return 0;
505 }
506
507 //////////////////////////////////////////////////////////////////////////////////////////////
508
509 //////////////////////
510 //
511 // BETTY Wait
512 //
513 //////////////////////
514
515
516 ANIMATOR DoBettyMove,NullAnimator,DoActorDebris;
517
518 #define BETTY_RATE 10
519 ANIMATOR DoBettyWait;
520
521 STATE s_BettyWait[5][3] =
522 {
523 {
524 {BETTY_R0 + 0, BETTY_RATE, DoBettyWait, &s_BettyWait[0][1]},
525 {BETTY_R0 + 1, BETTY_RATE, DoBettyWait, &s_BettyWait[0][2]},
526 {BETTY_R0 + 2, BETTY_RATE, DoBettyWait, &s_BettyWait[0][0]},
527 },
528 {
529 {BETTY_R1 + 0, BETTY_RATE, DoBettyWait, &s_BettyWait[1][1]},
530 {BETTY_R1 + 1, BETTY_RATE, DoBettyWait, &s_BettyWait[1][2]},
531 {BETTY_R1 + 2, BETTY_RATE, DoBettyWait, &s_BettyWait[1][0]},
532 },
533 {
534 {BETTY_R2 + 0, BETTY_RATE, DoBettyWait, &s_BettyWait[2][1]},
535 {BETTY_R2 + 1, BETTY_RATE, DoBettyWait, &s_BettyWait[2][2]},
536 {BETTY_R2 + 2, BETTY_RATE, DoBettyWait, &s_BettyWait[2][0]},
537 },
538 {
539 {BETTY_R3 + 0, BETTY_RATE, DoBettyWait, &s_BettyWait[3][1]},
540 {BETTY_R3 + 1, BETTY_RATE, DoBettyWait, &s_BettyWait[3][2]},
541 {BETTY_R3 + 2, BETTY_RATE, DoBettyWait, &s_BettyWait[3][0]},
542 },
543 {
544 {BETTY_R4 + 0, BETTY_RATE, DoBettyWait, &s_BettyWait[4][1]},
545 {BETTY_R4 + 1, BETTY_RATE, DoBettyWait, &s_BettyWait[4][2]},
546 {BETTY_R4 + 2, BETTY_RATE, DoBettyWait, &s_BettyWait[4][0]},
547 }
548 };
549
550
551 STATEp sg_BettyWait[] =
552 {
553 &s_BettyWait[0][0],
554 &s_BettyWait[1][0],
555 &s_BettyWait[2][0],
556 &s_BettyWait[3][0],
557 &s_BettyWait[4][0]
558 };
559
560 ATTRIBUTE BettyAttrib =
561 {
562 {60, 80, 100, 130}, // Speeds
563 {3, 0, -2, -3}, // Tic Adjusts
564 3, // MaxWeapons;
565 {0, 0, 0, 0, 0, 0,0,0,0,0}
566 };
567
568 //////////////////////
569 //
570 // BETTY Jump
571 //
572 //////////////////////
573
574 ANIMATOR DoBettyJump;
575
576 STATE s_BettyJump[5][1] =
577 {
578 {
579 {BETTY_R0 + 0, BETTY_RATE, DoBettyJump, &s_BettyJump[0][0]},
580 },
581 {
582 {BETTY_R1 + 0, BETTY_RATE, DoBettyJump, &s_BettyJump[1][0]},
583 },
584 {
585 {BETTY_R2 + 0, BETTY_RATE, DoBettyJump, &s_BettyJump[2][0]},
586 },
587 {
588 {BETTY_R3 + 0, BETTY_RATE, DoBettyJump, &s_BettyJump[3][0]},
589 },
590 {
591 {BETTY_R4 + 0, BETTY_RATE, DoBettyJump, &s_BettyJump[4][0]},
592 }
593 };
594
595
596 STATEp sg_BettyJump[] =
597 {
598 &s_BettyJump[0][0],
599 &s_BettyJump[1][0],
600 &s_BettyJump[2][0],
601 &s_BettyJump[3][0],
602 &s_BettyJump[4][0]
603 };
604
605
606 //////////////////////
607 //
608 // BETTY Explode
609 //
610 //////////////////////
611
612 #define BETTY_EXPLODE_RATE 11
613 #define BETTY_EXPLODE BETTY_R0
614 ANIMATOR DoSuicide;
615 ANIMATOR DoDamageTest;
616 ANIMATOR DoBettySpawnShrap;
617
618 STATE s_BettyExplode[] =
619 {
620 {BETTY_EXPLODE + 0, SF_QUICK_CALL, DoDamageTest, &s_BettyExplode[1]},
621 {BETTY_EXPLODE + 0, BETTY_EXPLODE_RATE, DoSuicide, &s_BettyExplode[0]}
622 };
623
624 STATEp sg_BettyExplode[] =
625 {
626 s_BettyExplode,
627 };
628
629
630 int
SetupBetty(short SpriteNum)631 SetupBetty(short SpriteNum)
632 {
633 SPRITEp sp = &sprite[SpriteNum];
634 USERp u;
635 ANIMATOR DoActorDecide;
636
637 if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
638 {
639 u = User[SpriteNum];
640 ASSERT(u);
641 }
642 else
643 {
644 User[SpriteNum] = u = SpawnUser(SpriteNum,BETTY_R0,s_BettyWait[0]);
645 u->Health = HEALTH_SKULL;
646 }
647
648 ChangeState(SpriteNum, s_BettyWait[0]);
649 u->Attrib = &BettyAttrib;
650 DoActorSetSpeed(SpriteNum, NORM_SPEED);
651 u->StateEnd = s_BettyExplode;
652 u->Rot = sg_BettyWait;
653
654 u->ID = BETTY_R0;
655
656 EnemyDefaults(SpriteNum, NULL, NULL);
657 sp->clipdist = (128+64) >> 2;
658 SET(u->Flags, SPR_XFLIP_TOGGLE);
659 SET(sp->cstat, CSTAT_SPRITE_YCENTER);
660
661 u->Radius = 400;
662
663 if (SPRITEp_BOS(sp) > u->loz - Z(16))
664 {
665 sp->z = u->loz + Z(SPRITEp_YOFF(sp));
666
667 u->loz = sp->z;
668 // leave 8 pixels above the ground
669 sp->z += SPRITEp_SIZE_TOS(sp) - Z(3);;
670 }
671 else
672 {
673 u->Counter = RANDOM_P2(2048);
674 u->sz = sp->z;
675 }
676
677
678 return 0;
679 }
680
681 int
DoBettyMove(int16_t SpriteNum)682 DoBettyMove(int16_t SpriteNum)
683 {
684 SPRITEp sp = &sprite[SpriteNum];
685 USERp u = User[SpriteNum];
686 int32_t dax, day, daz;
687
688 dax = MOVEx(sp->xvel, sp->ang);
689 day = MOVEy(sp->xvel, sp->ang);
690 daz = sp->zvel;
691
692 u->ret = move_missile(SpriteNum, dax, day, daz, Z(16), Z(16), CLIPMASK_MISSILE, ACTORMOVETICS);
693
694 DoFindGroundPoint(SpriteNum);
695 return 0;
696 }
697
698 int
DoBettyBeginDeath(int16_t SpriteNum)699 DoBettyBeginDeath(int16_t SpriteNum)
700 {
701 SPRITEp sp = &sprite[SpriteNum];
702 USERp u = User[SpriteNum];
703 int16_t i,num_ord=0;
704 //extern short *DamageRadiusBetty;
705
706 // starts the explosion that does the actual damage
707
708 switch (sp->hitag)
709 {
710 case 1:
711 if (sp->lotag) num_ord = sp->lotag;
712 else
713 num_ord = 2;
714 if (num_ord > 3) num_ord = 3;
715 for (i=0; i<num_ord; i++)
716 {
717 sp->ang = NORM_ANGLE(sp->ang+(i*1024));
718 InitSpriteChemBomb(SpriteNum);
719 }
720 break;
721
722 case 2:
723 if (sp->lotag) num_ord = sp->lotag;
724 else
725 num_ord = 5;
726 if (num_ord > 10) num_ord = 10;
727 for (i=0; i<num_ord; i++)
728 {
729 sp->ang = NORM_ANGLE(RANDOM_RANGE(2048));
730 InitCaltrops(SpriteNum);
731 }
732 break;
733
734 case 3:
735 InitFlashBomb(SpriteNum);
736 break;
737
738 case 4:
739 if (sp->lotag) num_ord = sp->lotag;
740 else
741 num_ord = 5;
742 if (num_ord > 10) num_ord = 10;
743 for (i=0; i<num_ord; i++)
744 {
745 sp->ang = NORM_ANGLE(sp->ang + (i*(2048/num_ord)));
746 InitSpriteGrenade(SpriteNum);
747 }
748 break;
749 default:
750 for (i=0; i<5; i++)
751 {
752 sp->ang = NORM_ANGLE(RANDOM_RANGE(2048));
753 InitPhosphorus(SpriteNum);
754 SpawnMineExp(SpriteNum);
755 }
756 break;
757 }
758
759 RESET(sp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
760 u->RotNum = 0;
761 u->Tics = 0;
762 // ChangeState(SpriteNum, u->StateEnd);
763 //u->State = u->StateStart = u->StateEnd;
764 //u->State = u->StateEnd;
765 u->ID = BETTY_R0;
766 u->Radius = DamageData[DMG_SKULL_EXP].radius; //*DamageRadiusBetty;
767 u->OverlapZ = Z(64);
768 change_sprite_stat(SpriteNum, STAT_DEAD_ACTOR);
769 sp->shade = -40;
770
771 SpawnLittleExp(SpriteNum);
772 SetSuicide(SpriteNum);
773
774 //u->spal = sp->pal = PALETTE_RED_LIGHTING;
775
776
777 return 0;
778 }
779
780
DoBettyJump(short SpriteNum)781 int DoBettyJump(short SpriteNum)
782 {
783 SPRITEp sp = &sprite[SpriteNum];
784 USERp u = User[SpriteNum];
785
786
787 if (sp->xvel)
788 DoBettyMove(SpriteNum);
789 else
790 sp->ang = NORM_ANGLE(sp->ang + (64 * ACTORMOVETICS));
791
792 if (TEST(u->Flags,SPR_JUMPING))
793 {
794 DoJump(SpriteNum);
795 }
796 else if (TEST(u->Flags,SPR_FALLING))
797 {
798 DoFall(SpriteNum);
799
800 // jump/fall type
801 if (sp->xvel)
802 {
803 SWBOOL SpriteOverlapZ(int16_t, int16_t, int);
804
805 int dist,a,b,c;
806
807 DISTANCE(sp->x, sp->y, u->tgt_sp->x, u->tgt_sp->y, dist, a, b, c);
808
809 if (dist < 1000 &&
810 SpriteOverlapZ(SpriteNum, u->tgt_sp - sprite, Z(32)))
811 {
812 UpdateSinglePlayKills(SpriteNum);
813 DoBettyBeginDeath(SpriteNum);
814 return 0;
815 }
816
817 if ((sp->z > u->loz - Z(36)))
818 {
819 sp->z = u->loz - Z(36);
820 UpdateSinglePlayKills(SpriteNum);
821 DoBettyBeginDeath(SpriteNum);
822 return 0;
823 }
824 }
825 // non jumping type
826 else
827 {
828 if (u->jump_speed > 200)
829 {
830 UpdateSinglePlayKills(SpriteNum);
831 DoBettyBeginDeath(SpriteNum);
832 }
833 }
834
835 }
836 else
837 {
838 UpdateSinglePlayKills(SpriteNum);
839 DoBettyBeginDeath(SpriteNum);
840 }
841 return 0;
842 }
843
DoBettyBob(short SpriteNum)844 int DoBettyBob(short SpriteNum)
845 {
846 SPRITEp sp = &sprite[SpriteNum];
847 USERp u = User[SpriteNum];
848
849 // actor does a sine wave about u->sz - this is the z mid point
850 #define BETTY_BOB_AMT (Z(16))
851
852 u->Counter = (u->Counter + (ACTORMOVETICS << 3) + (ACTORMOVETICS << 1)) & 2047;
853 sp->z = u->sz + ((BETTY_BOB_AMT * (int)sintable[u->Counter]) >> 14) +
854 ((DIV2(BETTY_BOB_AMT) * (int)sintable[u->Counter]) >> 14);
855
856 return 0;
857 }
858
DoBettySpawnShrap(short SpriteNum)859 int DoBettySpawnShrap(short SpriteNum)
860 {
861 int SpawnShrap(short, short);
862 SpawnShrap(SpriteNum, -1);
863 //PlaySpriteSound(SpriteNum,attr_extra1,v3df_none);
864 return 0;
865 }
866
DoBettyWait(short SpriteNum)867 int DoBettyWait(short SpriteNum)
868 {
869 SPRITEp sp = &sprite[SpriteNum];
870 USERp u = User[SpriteNum];
871 int a,b,c,dist;
872
873 DISTANCE(sp->x, sp->y, u->tgt_sp->x, u->tgt_sp->y, dist, a, b, c);
874
875 DoActorPickClosePlayer(SpriteNum);
876
877 //if (dist < u->active_range)
878 // return(0);
879
880 if ((u->WaitTics -= ACTORMOVETICS) <= 0)
881 {
882 PlaySound(DIGI_MINEBEEP,&sp->x,&sp->y,&sp->z,v3df_none);
883 u->WaitTics = SEC(3);
884 }
885
886 // below the floor type
887 if (sp->z > u->loz)
888 {
889 // look for closest player every once in a while
890 if (dist < 3500)
891 {
892 sp->xvel = 0;
893 u->jump_speed = -600;
894 NewStateGroup(SpriteNum, sg_BettyJump);
895 DoBeginJump(SpriteNum);
896 }
897 }
898 else
899 // above the floor type
900 {
901 sp->ang = NORM_ANGLE(sp->ang + (48 * ACTORMOVETICS));
902
903 DoBettyBob(SpriteNum);
904
905 if (dist < 8000)
906 {
907 sp->ang = getangle(u->tgt_sp->x - sp->x, u->tgt_sp->y - sp->y);
908 sp->xvel = 128 + (RANDOM_P2(256<<8)>>8);
909 u->jump_speed = -700;
910 NewStateGroup(SpriteNum, sg_BettyJump);
911 DoBeginJump(SpriteNum);
912 }
913 }
914
915 return 0;
916 }
917
918
919 #include "saveable.h"
920
921 static saveable_code saveable_skull_code[] =
922 {
923 SAVE_CODE(SetupSkull),
924 SAVE_CODE(DoSkullMove),
925 SAVE_CODE(DoSkullBeginDeath),
926 SAVE_CODE(DoSkullJump),
927 SAVE_CODE(DoSkullBob),
928 SAVE_CODE(DoSkullSpawnShrap),
929 SAVE_CODE(DoSkullWait),
930
931 SAVE_CODE(SetupBetty),
932 SAVE_CODE(DoBettyMove),
933 SAVE_CODE(DoBettyBeginDeath),
934 SAVE_CODE(DoBettyJump),
935 SAVE_CODE(DoBettyBob),
936 SAVE_CODE(DoBettySpawnShrap),
937 SAVE_CODE(DoBettyWait),
938 };
939
940 static saveable_data saveable_skull_data[] =
941 {
942 SAVE_DATA(s_SkullWait),
943 SAVE_DATA(sg_SkullWait),
944
945 SAVE_DATA(SkullAttrib),
946
947 SAVE_DATA(s_SkullRing),
948 SAVE_DATA(sg_SkullRing),
949 SAVE_DATA(s_SkullJump),
950 SAVE_DATA(sg_SkullJump),
951 SAVE_DATA(s_SkullExplode),
952 SAVE_DATA(sg_SkullExplode),
953 SAVE_DATA(s_BettyWait),
954 SAVE_DATA(sg_BettyWait),
955
956 SAVE_DATA(BettyAttrib),
957
958 SAVE_DATA(s_BettyJump),
959 SAVE_DATA(sg_BettyJump),
960 SAVE_DATA(s_BettyExplode),
961 SAVE_DATA(sg_BettyExplode),
962 };
963
964 saveable_module saveable_skull =
965 {
966 // code
967 saveable_skull_code,
968 SIZ(saveable_skull_code),
969
970 // data
971 saveable_skull_data,
972 SIZ(saveable_skull_data)
973 };
974