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