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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 "panel.h"
31 #include "game.h"
32 #include "tags.h"
33 #include "weapon.h"
34 #include "sprite.h"
35 #include "actor.h"
36 
37 extern int jump_grav;
38 
39 extern STATE s_DebrisNinja[];
40 extern STATE s_DebrisRat[];
41 extern STATE s_DebrisCrab[];
42 extern STATE s_DebrisStarFish[];
43 extern STATE s_NinjaDieSliced[];
44 
45 extern STATEp sg_NinjaGrabThroat[];
46 
47 int DoActorStopFall(short SpriteNum);
48 
49 
50 int
DoScaleSprite(short SpriteNum)51 DoScaleSprite(short SpriteNum)
52     {
53     SPRITEp sp = &sprite[SpriteNum];
54     USERp u = User[SpriteNum];
55     int scale_value;
56 
57     if (u->scale_speed)
58         {
59         u->scale_value += u->scale_speed * ACTORMOVETICS;
60 
61         scale_value = u->scale_value >> 8;
62 
63         if (u->scale_speed > 0)
64             {
65             if (scale_value > u->scale_tgt)
66                 u->scale_speed = 0;
67             else
68                 sp->xrepeat = sp->yrepeat = scale_value;
69             }
70         else
71             {
72             if (scale_value < u->scale_tgt)
73                 u->scale_speed = 0;
74             else
75                 sp->xrepeat = sp->yrepeat = scale_value;
76             }
77 
78         }
79 
80     return(0);
81     }
82 
83 int
DoActorDie(short SpriteNum,short weapon)84 DoActorDie(short SpriteNum, short weapon)
85     {
86     USERp u = User[SpriteNum];
87     SPRITEp sp = &sprite[SpriteNum];
88 
89 
90     change_sprite_stat(SpriteNum, STAT_DEAD_ACTOR);
91     SET(u->Flags, SPR_DEAD);
92     RESET(u->Flags, SPR_FALLING | SPR_JUMPING);
93     u->floor_dist = Z(40);
94 
95     // test for gibable dead bodies
96     SET(sp->extra, SPRX_BREAKABLE);
97     SET(sp->cstat, CSTAT_SPRITE_BREAKABLE);
98 
99     if (weapon < 0)
100         {
101         // killed by one of these non-sprites
102         switch (weapon)
103             {
104         case WPN_NM_LAVA:
105             ChangeState(SpriteNum, u->StateEnd);
106             u->RotNum = 0;
107             break;
108 
109         case WPN_NM_SECTOR_SQUISH:
110             ChangeState(SpriteNum, u->StateEnd);
111             u->RotNum = 0;
112             break;
113             }
114 
115         return(0);
116         }
117 
118 
119     // killed by one of these sprites
120     switch (User[weapon]->ID)
121         {
122         // Coolie actually explodes himself
123         // he is the Sprite AND Weapon
124         case COOLIE_RUN_R0:
125             ChangeState(SpriteNum, u->StateEnd);
126             u->RotNum = 0;
127             sp->xvel <<= 1;
128             u->ActorActionFunc = NULL;
129             sprite[SpriteNum].ang = NORM_ANGLE(sprite[SpriteNum].ang + 1024);
130             break;
131 
132         case NINJA_RUN_R0:
133             if(u->ID == NINJA_RUN_R0)  // Cut in half!
134             {
135                 SPRITEp wp = &sprite[weapon];
136 
137                 if(User[weapon]->WeaponNum != WPN_FIST)
138                     {
139                     //SpawnBlood(SpriteNum, SpriteNum, -1, -1, -1, -1);
140                     InitPlasmaFountain(wp, sp);
141                     InitPlasmaFountain(wp, sp);
142                     PlaySound(DIGI_NINJAINHALF,&sp->x,&sp->y,&sp->z,v3df_none);
143                     ChangeState(SpriteNum, &s_NinjaDieSliced[0]);
144                     } else
145                     {
146                     if(RANDOM_RANGE(1000) > 500)
147                         {
148                         SPRITEp wp = &sprite[weapon];
149                         InitPlasmaFountain(wp, sp);
150                         }
151 
152                     ChangeState(SpriteNum, u->StateEnd);
153                     u->RotNum = 0;
154                     u->ActorActionFunc = NULL;
155                     sp->xvel = 200 + RANDOM_RANGE(200);
156                     u->jump_speed = -200 - RANDOM_RANGE(250);
157                     DoActorBeginJump(SpriteNum);
158                     sprite[SpriteNum].ang = sprite[weapon].ang;
159                     }
160             }
161             else
162             {
163                 // test for gibable dead bodies
164                 if (RANDOM_RANGE(1000) > 500)
165                     SET(sp->cstat, CSTAT_SPRITE_YFLIP);
166                 ChangeState(SpriteNum, u->StateEnd);
167 	            sp->xvel = 0;
168    		        u->jump_speed = 0;
169     	        DoActorBeginJump(SpriteNum);
170             }
171 
172             u->RotNum = 0;
173 
174             u->ActorActionFunc = NULL;
175             //u->ActorActionFunc = NullAnimator;
176             sprite[SpriteNum].ang = sprite[weapon].ang;
177             break;
178 
179         case COOLG_RUN_R0:
180         case SKEL_RUN_R0:
181         case RIPPER_RUN_R0:
182         case RIPPER2_RUN_R0:
183         case EEL_RUN_R0:
184         case STAR1:
185         case SUMO_RUN_R0:
186             ChangeState(SpriteNum, u->StateEnd);
187             u->RotNum = 0;
188             break;
189 
190         case UZI_SMOKE:
191                 if (RANDOM_RANGE(1000) > 500)
192                     SET(sp->cstat, CSTAT_SPRITE_YFLIP);
193                 ChangeState(SpriteNum, u->StateEnd);
194                 u->RotNum = 0;
195                 // Rippers still gotta jump or they fall off walls weird
196                 if(u->ID == RIPPER_RUN_R0 || u->ID == RIPPER2_RUN_R0)
197                     {
198                     sp->xvel <<= 1;
199                     u->jump_speed = -100 - RANDOM_RANGE(250);
200                     DoActorBeginJump(SpriteNum);
201                     } else
202                     {
203                     sp->xvel = 0;
204                     u->jump_speed = -10 - RANDOM_RANGE(25);
205                     DoActorBeginJump(SpriteNum);
206                     }
207                 u->ActorActionFunc = NULL;
208                 // Get angle to player
209                 sp->ang = NORM_ANGLE(getangle(u->tgt_sp->x - sp->x, u->tgt_sp->y - sp->y) + 1024);
210             break;
211 
212         case UZI_SMOKE+1: // Shotgun
213                 if (RANDOM_RANGE(1000) > 500)
214                     SET(sp->cstat, CSTAT_SPRITE_YFLIP);
215                 ChangeState(SpriteNum, u->StateEnd);
216                 u->RotNum = 0;
217 
218                 // Rippers still gotta jump or they fall off walls weird
219                 if(u->ID == RIPPER_RUN_R0 || u->ID == RIPPER2_RUN_R0)
220                     {
221                     sp->xvel = 75 + RANDOM_RANGE(100);
222                     u->jump_speed = -100 - RANDOM_RANGE(150);
223                     } else
224                     {
225                     sp->xvel = 100 + RANDOM_RANGE(200);
226                     u->jump_speed = -100 - RANDOM_RANGE(250);
227                     }
228                 DoActorBeginJump(SpriteNum);
229                 u->ActorActionFunc = NULL;
230                 // Get angle to player
231                 sp->ang = NORM_ANGLE(getangle(u->tgt_sp->x - sp->x, u->tgt_sp->y - sp->y) + 1024);
232             break;
233 
234         default:
235             ASSERT(weapon >= 0);
236             switch (u->ID)
237                 {
238                 case SKULL_R0:
239                 case BETTY_R0:
240                     ChangeState(SpriteNum, u->StateEnd);
241                     break;
242 
243                 default:
244                     if(RANDOM_RANGE(1000) > 700)
245                         {
246                         SPRITEp wp = &sprite[weapon];
247                         InitPlasmaFountain(wp, sp);
248                         }
249 
250                     if (RANDOM_RANGE(1000) > 500)
251                         SET(sp->cstat, CSTAT_SPRITE_YFLIP);
252                     ChangeState(SpriteNum, u->StateEnd);
253                     u->RotNum = 0;
254                     u->ActorActionFunc = NULL;
255                     sp->xvel = 300 + RANDOM_RANGE(400);
256                     u->jump_speed = -300 - RANDOM_RANGE(350);
257                     DoActorBeginJump(SpriteNum);
258                     sprite[SpriteNum].ang = sprite[weapon].ang;
259                     break;
260                 }
261             break;
262         }
263 
264     // These are too big to flip upside down
265     switch (u->ID)
266         {
267         case RIPPER2_RUN_R0:
268         case COOLIE_RUN_R0:
269         case SUMO_RUN_R0:
270         case ZILLA_RUN_R0:
271             RESET(sp->cstat, CSTAT_SPRITE_YFLIP);
272             break;
273         }
274 
275     u->ID = 0;
276 
277     return (0);
278     }
279 
280 VOID
DoDebrisCurrent(SPRITEp sp)281 DoDebrisCurrent(SPRITEp sp)
282     {
283     int xvect, yvect;
284     int nx, ny;
285     int ret=0;
286     USERp u = User[sp - sprite];
287     SECT_USERp sectu = SectUser[sp->sectnum];
288 
289     //sp->clipdist = (256+128)>>2;
290 
291     nx = DIV4(sectu->speed) * (int) sintable[NORM_ANGLE(sectu->ang + 512)] >> 14;
292     ny = DIV4(sectu->speed) * (int) sintable[sectu->ang] >> 14;
293 
294     // faster than move_sprite
295     //move_missile(sp-sprite, nx, ny, 0, Z(2), Z(0), 0, ACTORMOVETICS);
296     ret = move_sprite(sp-sprite, nx, ny, 0, u->ceiling_dist, u->floor_dist, 0, ACTORMOVETICS);
297 
298     // attempt to move away from wall
299     if (ret)
300         {
301         short rang = RANDOM_P2(2048);
302 
303         nx = DIV4(sectu->speed) * (int) sintable[NORM_ANGLE(sectu->ang + rang + 512)] >> 14;
304         ny = DIV4(sectu->speed) * (int) sintable[NORM_ANGLE(sectu->ang + rang)] >> 14;
305 
306         move_sprite(sp-sprite, nx, ny, 0, u->ceiling_dist, u->floor_dist, 0, ACTORMOVETICS);
307         }
308 
309     sp->z = u->loz;
310     }
311 
312 int
DoActorSectorDamage(short SpriteNum)313 DoActorSectorDamage(short SpriteNum)
314     {
315     SPRITEp sp = &sprite[SpriteNum];
316     USERp u = User[SpriteNum];
317     SECT_USERp sectu = SectUser[sp->sectnum];
318     SECTORp sectp = &sector[sp->sectnum];
319 
320     if (u->Health <= 0)
321         return(FALSE);
322 
323     if (sectu && sectu->damage)
324         {
325         if (TEST(sectu->flags, SECTFU_DAMAGE_ABOVE_SECTOR))
326             {
327             if ((u->DamageTics -= synctics) < 0)
328                 {
329                 u->DamageTics = 60;
330                 u->Health -= sectu->damage;
331 
332                 if (u->Health <= 0)
333                     {
334                     UpdateSinglePlayKills(SpriteNum);
335                     DoActorDie(SpriteNum, WPN_NM_LAVA);
336                     return(TRUE);
337                     }
338                 }
339             }
340         else
341         if (SPRITEp_BOS(sp) >= sectp->floorz)
342             {
343             if ((u->DamageTics -= synctics) < 0)
344                 {
345                 u->DamageTics = 60;
346                 u->Health -= sectu->damage;
347 
348                 if (u->Health <= 0)
349                     {
350                     UpdateSinglePlayKills(SpriteNum);
351                     DoActorDie(SpriteNum, WPN_NM_LAVA);
352                     return(TRUE);
353                     }
354                 }
355             }
356         }
357 
358     // note that most squishing is done in vator.c
359     if (u->lo_sectp && u->hi_sectp && labs(u->loz - u->hiz) < DIV2(SPRITEp_SIZE_Z(sp)))
360     //if (u->lo_sectp && u->hi_sectp && labs(u->loz - u->hiz) < SPRITEp_SIZE_Z(sp))
361         {
362         u->Health = 0;
363         if (SpawnShrap(SpriteNum, WPN_NM_SECTOR_SQUISH))
364             {
365             UpdateSinglePlayKills(SpriteNum);
366             SetSuicide(SpriteNum);
367             }
368         else
369             {
370             ASSERT(TRUE == FALSE);
371             //DoActorDie(SpriteNum, WPN_NM_SECTOR_SQUISH);
372             }
373 
374         return(TRUE);
375         }
376 
377     return(FALSE);
378     }
379 
380 
381 int
move_debris(short SpriteNum,int xchange,int ychange,int zchange)382 move_debris(short SpriteNum, int xchange, int ychange, int zchange)
383     {
384     SPRITEp sp = &sprite[SpriteNum];
385     USERp u = User[SpriteNum];
386     int nx, ny;
387 
388     u->ret = move_sprite(SpriteNum, xchange, ychange, zchange,
389         u->ceiling_dist, u->floor_dist, 0, ACTORMOVETICS);
390 
391     return (!u->ret);
392     }
393 
394 // !AIC - Supposed to allow floating of DEBRIS (dead bodies, flotsam, jetsam).  Or if water has
395 // current move with the current.
396 
397 int
DoActorDebris(short SpriteNum)398 DoActorDebris(short SpriteNum)
399     {
400     SPRITEp sp = &sprite[SpriteNum];
401     USERp u = User[SpriteNum];
402     SECTORp sectp = &sector[sp->sectnum];
403     int nx, ny;
404 
405     // This was move from DoActorDie so actor's can't be walked through until they are on the floor
406     RESET(sp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
407 
408     // Don't let some actors float
409     switch(u->ID)
410         {
411         case HORNET_RUN_R0:
412         case BUNNY_RUN_R0:
413             KillSprite(SpriteNum);
414             return(0);
415         case ZILLA_RUN_R0:
416             getzsofslope(sp->sectnum, sp->x, sp->y, &u->hiz, &u->loz);
417             u->lo_sectp = &sector[sp->sectnum];
418             u->hi_sectp = &sector[sp->sectnum];
419             u->lo_sp = NULL;
420             u->hi_sp = NULL;
421             break;
422         }
423 
424     if (TEST(sectp->extra, SECTFX_SINK))
425         {
426         if (TEST(sectp->extra, SECTFX_CURRENT))
427             {
428             DoDebrisCurrent(sp);
429             }
430         else
431             {
432             //nx = sp->xvel * ACTORMOVETICS * (int) sintable[NORM_ANGLE(sp->ang + 512)] >> 14;
433             //ny = sp->xvel * ACTORMOVETICS * (int) sintable[sp->ang] >> 14;
434             nx = ACTORMOVETICS * (int) sintable[NORM_ANGLE(sp->ang + 512)] >> 14;
435             ny = ACTORMOVETICS * (int) sintable[sp->ang] >> 14;
436 
437             //sp->clipdist = (256+128)>>2;
438 
439             if (!move_debris(SpriteNum, nx, ny, 0L))
440                 {
441                 sp->ang = RANDOM_P2(2048);
442                 }
443             }
444 
445         if (SectUser[sp->sectnum] && SectUser[sp->sectnum]->depth > 10)	// JBF: added null check
446             {
447             u->WaitTics = (u->WaitTics + (ACTORMOVETICS << 3)) & 1023;
448             //sp->z = Z(2) + u->loz + ((Z(4) * (int) sintable[u->WaitTics]) >> 14);
449             sp->z = u->loz - ((Z(2) * (int) sintable[u->WaitTics]) >> 14);
450             }
451         }
452     else
453         {
454         sp->z = u->loz;
455         }
456 
457     return(0);
458     }
459 
460 
461 int
DoFireFly(short SpriteNum)462 DoFireFly(short SpriteNum)
463     {
464     SPRITEp sp = &sprite[SpriteNum];
465     USERp u = User[SpriteNum];
466     int nx, ny;
467 
468     nx = 4 * ACTORMOVETICS * (int) sintable[NORM_ANGLE(sp->ang + 512)] >> 14;
469     ny = 4 * ACTORMOVETICS * (int) sintable[sp->ang] >> 14;
470 
471     sp->clipdist = 256>>2;
472     if (!move_actor(SpriteNum, nx, ny, 0L))
473         {
474         sp->ang = NORM_ANGLE(sp->ang + 1024);
475         }
476 
477     u->WaitTics = (u->WaitTics + (ACTORMOVETICS << 1)) & 2047;
478 
479     sp->z = u->sz + ((Z(32) * (int) sintable[u->WaitTics]) >> 14);
480     return(0);
481     }
482 
483 int
DoGenerateSewerDebris(short SpriteNum)484 DoGenerateSewerDebris(short SpriteNum)
485     {
486     SPRITEp sp = &sprite[SpriteNum], np;
487     USERp u = User[SpriteNum], nu;
488     short n;
489 
490     static STATEp Debris[] =
491         {
492         s_DebrisNinja,
493         s_DebrisRat,
494         s_DebrisCrab,
495         s_DebrisStarFish
496         };
497 
498     u->Tics -= ACTORMOVETICS;
499 
500     if (u->Tics <= 0)
501         {
502         u->Tics = u->WaitTics;
503 
504         n = SpawnSprite(STAT_DEAD_ACTOR, 0, Debris[RANDOM_P2(4<<8)>>8], sp->sectnum, sp->x, sp->y, sp->z, sp->ang, 200);
505         np = &sprite[n];
506         nu = User[n];
507 
508         SetOwner(SpriteNum, n);
509         }
510 
511     return(0);
512     }
513 
514 // !AIC - Tries to keep actors correctly on the floor.  More that a bit messy.
515 
516 VOID
KeepActorOnFloor(short SpriteNum)517 KeepActorOnFloor(short SpriteNum)
518     {
519     USERp u = User[SpriteNum];
520     SPRITEp sp = User[SpriteNum]->SpriteP;
521     SECTORp sectp;
522     int depth;
523 
524     sectp = &sector[sp->sectnum];
525 
526     RESET(sp->cstat, CSTAT_SPRITE_YFLIP); // If upside down, reset it
527 
528     if (TEST(u->Flags, SPR_JUMPING | SPR_FALLING))
529         return;
530 
531     if (u->lo_sectp && SectUser[u->lo_sectp - sector])
532         depth = SectUser[u->lo_sectp - sector]->depth;
533     else
534         depth = 0;
535 
536     if (TEST(sectp->extra, SECTFX_SINK) &&
537         depth > 35 &&
538         u->ActorActionSet && u->ActorActionSet->Swim)
539         {
540         if (TEST(u->Flags, SPR_SWIMMING))
541             {
542             if (u->Rot != u->ActorActionSet->Run && u->Rot != u->ActorActionSet->Swim && u->Rot != u->ActorActionSet->Stand)
543                 {
544                 // was swimming but have now stopped
545                 RESET(u->Flags, SPR_SWIMMING);
546                 RESET(sp->cstat, CSTAT_SPRITE_YCENTER);
547                 u->oz = sp->z = u->loz;
548                 return;
549                 }
550 
551             if (u->Rot == u->ActorActionSet->Run)
552                 {
553                 NewStateGroup(SpriteNum, u->ActorActionSet->Swim);
554                 }
555 
556             // are swimming
557             u->oz = sp->z = u->loz - Z(depth);
558             }
559         else
560             {
561             // only start swimming if you are running
562             if (u->Rot == u->ActorActionSet->Run || u->Rot == u->ActorActionSet->Swim)
563                 {
564                 NewStateGroup(SpriteNum, u->ActorActionSet->Swim);
565                 u->oz = sp->z = u->loz - Z(depth);
566                 SET(u->Flags, SPR_SWIMMING);
567                 SET(sp->cstat, CSTAT_SPRITE_YCENTER);
568                 }
569             else
570                 {
571                 RESET(u->Flags, SPR_SWIMMING);
572                 RESET(sp->cstat, CSTAT_SPRITE_YCENTER);
573                 u->oz = sp->z = u->loz;
574                 }
575             }
576 
577         return;
578         }
579 
580     // NOT in a swimming situation
581     RESET(u->Flags, SPR_SWIMMING);
582     RESET(sp->cstat, CSTAT_SPRITE_YCENTER);
583 
584     #if 1
585     if (TEST(u->Flags, SPR_MOVED))
586         {
587         u->oz = sp->z = u->loz;
588         }
589     else
590         {
591         int ceilz,ceilhit,florz,florhit;
592         FAFgetzrangepoint(sp->x, sp->y, sp->z, sp->sectnum,
593             &ceilz, &ceilhit, &florz, &florhit);
594 
595         u->oz = sp->z = florz;
596         }
597     #endif
598 
599 
600     }
601 
602 int
DoActorBeginSlide(short SpriteNum,short ang,short vel,short dec)603 DoActorBeginSlide(short SpriteNum, short ang, short vel, short dec)
604     {
605     USERp u = User[SpriteNum];
606     SPRITEp sp = User[SpriteNum]->SpriteP;
607 
608     SET(u->Flags, SPR_SLIDING);
609 
610     u->slide_ang = ang;
611     u->slide_vel = vel;
612     u->slide_dec = dec;
613 
614     //DoActorSlide(SpriteNum);
615 
616     return (0);
617     }
618 
619 // !AIC - Sliding can occur in different directions from movement of the actor.
620 // Has its own set of variables
621 
622 int
DoActorSlide(short SpriteNum)623 DoActorSlide(short SpriteNum)
624     {
625     USERp u = User[SpriteNum];
626     SPRITEp sp = User[SpriteNum]->SpriteP;
627     int nx, ny;
628 
629     nx = u->slide_vel * (int) sintable[NORM_ANGLE(u->slide_ang + 512)] >> 14;
630     ny = u->slide_vel * (int) sintable[u->slide_ang] >> 14;
631 
632     if (!move_actor(SpriteNum, nx, ny, 0L))
633         {
634         RESET(u->Flags, SPR_SLIDING);
635         return (FALSE);
636         }
637 
638     u->slide_vel -= u->slide_dec * ACTORMOVETICS;
639 
640     if (u->slide_vel < 20)
641         {
642         RESET(u->Flags, SPR_SLIDING);
643         }
644 
645     return (TRUE);
646     }
647 
648 // !AIC - Actor jumping and falling
649 
650 int
DoActorBeginJump(short SpriteNum)651 DoActorBeginJump(short SpriteNum)
652     {
653     USERp u = User[SpriteNum];
654     SPRITEp sp = User[SpriteNum]->SpriteP;
655 
656     SET(u->Flags, SPR_JUMPING);
657     RESET(u->Flags, SPR_FALLING);
658 
659     // u->jump_speed = should be set before calling
660 
661     // set up individual actor jump gravity
662     u->jump_grav = ACTOR_GRAVITY;
663 
664     // Change sprites state to jumping
665     if(u->ActorActionSet)
666         {
667         if (TEST(u->Flags, SPR_DEAD))
668             NewStateGroup(SpriteNum, u->ActorActionSet->DeathJump);
669         else
670             NewStateGroup(SpriteNum, u->ActorActionSet->Jump);
671         }
672     u->StateFallOverride = NULL;
673 
674     //DO NOT CALL DoActorJump! DoActorStopFall can cause an infinite loop and
675     //stack overflow if it is called.
676     //DoActorJump(SpriteNum);
677 
678     return (0);
679     }
680 
681 int
DoActorJump(short SpriteNum)682 DoActorJump(short SpriteNum)
683     {
684     USERp u = User[SpriteNum];
685     SPRITEp sp = User[SpriteNum]->SpriteP;
686 
687     int jump_adj;
688 
689     // precalculate jump value to adjust jump speed by
690     jump_adj = u->jump_grav * ACTORMOVETICS;
691 
692     // adjust jump speed by gravity - if jump speed greater than 0 player
693     // have started falling
694     if ((u->jump_speed += jump_adj) > 0)
695         {
696         //DSPRINTF(ds,"Actor Jump Height %d", labs(sp->z - sector[sp->sectnum].floorz)>>8 );
697         MONO_PRINT(ds);
698 
699         // Start falling
700         DoActorBeginFall(SpriteNum);
701         return (0);
702         }
703 
704     // adjust height by jump speed
705     sp->z += u->jump_speed * ACTORMOVETICS;
706 
707     // if player gets to close the ceiling while jumping
708     if (sp->z < u->hiz + Z(PIC_SIZY(SpriteNum)))
709         {
710         // put player at the ceiling
711         sp->z = u->hiz + Z(PIC_SIZY(SpriteNum));
712 
713         // reverse your speed to falling
714         u->jump_speed = -u->jump_speed;
715 
716         //DSPRINTF(ds,"Jump: sp_num %d, hi_num %d, hi_sect %d",SpriteNum, u->hi_sp - sprite, u->hi_sectp - sector);
717         MONO_PRINT(ds);
718 
719         // Change sprites state to falling
720         DoActorBeginFall(SpriteNum);
721         }
722 
723     return (0);
724     }
725 
726 
727 int
DoActorBeginFall(short SpriteNum)728 DoActorBeginFall(short SpriteNum)
729     {
730     USERp u = User[SpriteNum];
731 
732     SET(u->Flags, SPR_FALLING);
733     RESET(u->Flags, SPR_JUMPING);
734 
735     u->jump_grav = ACTOR_GRAVITY;
736 
737     // Change sprites state to falling
738     if(u->ActorActionSet)
739         {
740         if (TEST(u->Flags, SPR_DEAD))
741             {
742             NewStateGroup(SpriteNum, u->ActorActionSet->DeathFall);
743             } else
744             NewStateGroup(SpriteNum, u->ActorActionSet->Fall);
745 
746         if (u->StateFallOverride)
747             {
748             NewStateGroup(SpriteNum, u->StateFallOverride);
749             }
750         }
751 
752     DoActorFall(SpriteNum);
753 
754     return (0);
755     }
756 
757 
758 int
DoActorFall(short SpriteNum)759 DoActorFall(short SpriteNum)
760     {
761     USERp u = User[SpriteNum];
762     SPRITEp sp = User[SpriteNum]->SpriteP;
763 
764     // adjust jump speed by gravity
765     u->jump_speed += u->jump_grav * ACTORMOVETICS;
766 
767     // adjust player height by jump speed
768     sp->z += u->jump_speed * ACTORMOVETICS;
769 
770     // Stick like glue when you hit the ground
771     if (sp->z > u->loz)
772         {
773         DoActorStopFall(SpriteNum);
774         }
775 
776     return (0);
777     }
778 
779 int
DoActorStopFall(short SpriteNum)780 DoActorStopFall(short SpriteNum)
781     {
782     USERp u = User[SpriteNum];
783     SPRITEp sp = User[SpriteNum]->SpriteP;
784 
785     sp->z = u->loz;
786 
787     RESET(u->Flags, SPR_FALLING | SPR_JUMPING);
788     RESET(sp->cstat, CSTAT_SPRITE_YFLIP);
789 
790 
791     // don't stand on face or wall sprites - jump again
792     if (u->lo_sp && !TEST(u->lo_sp->cstat, CSTAT_SPRITE_FLOOR))
793         {
794         USERp tu = User[u->lo_sp - sprite];
795 
796         //sp->ang = NORM_ANGLE(sp->ang + (RANDOM_P2(64<<8)>>8) - 32);
797         sp->ang = NORM_ANGLE(sp->ang + 1024 + (RANDOM_P2(512<<8)>>8));
798         u->jump_speed = -350;
799 
800         //DSPRINTF(ds,"StopFall: sp_num %d, sp->picnum %d, lo_num %d, lo_sp->picnum %d",SpriteNum, sp->picnum, u->lo_sp - sprite, u->lo_sp->picnum);
801         MONO_PRINT(ds);
802 
803         DoActorBeginJump(SpriteNum);
804         return(0);
805         }
806 
807     // Change sprites state to running
808     if(u->ActorActionSet)
809         {
810         if (TEST(u->Flags, SPR_DEAD))
811             {
812             NewStateGroup(SpriteNum, u->ActorActionSet->Dead);
813             PlaySound(DIGI_ACTORBODYFALL1,&sp->x,&sp->y,&sp->z,v3df_none);
814             }
815         else
816             {
817             PlaySound(DIGI_ACTORHITGROUND,&sp->x,&sp->y,&sp->z,v3df_none);
818 
819             NewStateGroup(SpriteNum, u->ActorActionSet->Run);
820 
821             if ((u->track >= 0) && (u->jump_speed) > 800 && (u->ActorActionSet->Sit))
822                 {
823                 u->WaitTics = 80;
824                 NewStateGroup(SpriteNum, u->ActorActionSet->Sit);
825                 }
826             }
827         }
828 
829     return (0);
830     }
831 
832 int
DoActorDeathMove(short SpriteNum)833 DoActorDeathMove(short SpriteNum)
834     {
835     ANIMATOR DoFindGround;
836 
837     USERp u = User[SpriteNum];
838     SPRITEp sp = User[SpriteNum]->SpriteP;
839     int nx, ny;
840 
841     if (TEST(u->Flags, SPR_JUMPING | SPR_FALLING))
842         {
843         if (TEST(u->Flags, SPR_JUMPING))
844             DoActorJump(SpriteNum);
845         else
846             DoActorFall(SpriteNum);
847         }
848 
849     nx = sp->xvel * (int) sintable[NORM_ANGLE(sp->ang + 512)] >> 14;
850     ny = sp->xvel * (int) sintable[sp->ang] >> 14;
851 
852     sp->clipdist = (128+64)>>2;
853     move_actor(SpriteNum, nx, ny, 0);
854 
855     // only fall on top of floor sprite or sector
856     DoFindGroundPoint(SpriteNum);
857 
858     return (0);
859     }
860 
861 // !AIC - Jumping a falling for shrapnel and other stuff, not actors.
862 
863 int
DoBeginJump(short SpriteNum)864 DoBeginJump(short SpriteNum)
865     {
866     USERp u = User[SpriteNum];
867     SPRITEp sp = User[SpriteNum]->SpriteP;
868 
869     SET(u->Flags, SPR_JUMPING);
870     RESET(u->Flags, SPR_FALLING);
871 
872     // set up individual actor jump gravity
873     u->jump_grav = ACTOR_GRAVITY;
874 
875     DoJump(SpriteNum);
876 
877     return (0);
878     }
879 
880 int
DoJump(short SpriteNum)881 DoJump(short SpriteNum)
882     {
883     USERp u = User[SpriteNum];
884     SPRITEp sp = User[SpriteNum]->SpriteP;
885 
886     int jump_adj;
887 
888     // precalculate jump value to adjust jump speed by
889     jump_adj = u->jump_grav * ACTORMOVETICS;
890 
891     // adjust jump speed by gravity - if jump speed greater than 0 player
892     // have started falling
893     if ((u->jump_speed += jump_adj) > 0)
894         {
895         // Start falling
896         DoBeginFall(SpriteNum);
897         return (0);
898         }
899 
900     // adjust height by jump speed
901     sp->z += u->jump_speed * ACTORMOVETICS;
902 
903     // if player gets to close the ceiling while jumping
904     if (sp->z < u->hiz + Z(PIC_SIZY(SpriteNum)))
905         {
906         // put player at the ceiling
907         sp->z = u->hiz + Z(PIC_SIZY(SpriteNum));
908 
909         // reverse your speed to falling
910         u->jump_speed = -u->jump_speed;
911 
912         // Change sprites state to falling
913         DoBeginFall(SpriteNum);
914         }
915 
916     return (0);
917     }
918 
919 
920 int
DoBeginFall(short SpriteNum)921 DoBeginFall(short SpriteNum)
922     {
923     USERp u = User[SpriteNum];
924 
925     SET(u->Flags, SPR_FALLING);
926     RESET(u->Flags, SPR_JUMPING);
927 
928     u->jump_grav = ACTOR_GRAVITY;
929 
930     DoFall(SpriteNum);
931 
932     return (0);
933     }
934 
935 #if 0
936 int
937 DoFall(short SpriteNum)
938     {
939     USERp u = User[SpriteNum];
940     SPRITEp sp = User[SpriteNum]->SpriteP;
941 
942     // adjust jump speed by gravity
943     u->jump_speed += u->jump_grav * ACTORMOVETICS;
944 
945     // adjust player height by jump speed
946     sp->z += u->jump_speed * ACTORMOVETICS;
947 
948     // Stick like glue when you hit the ground
949     if (sp->z > u->loz)
950         {
951         sp->z = u->loz;
952         RESET(u->Flags, SPR_FALLING);
953         }
954 
955     return (0);
956     }
957 #else
958 int
DoFall(short SpriteNum)959 DoFall(short SpriteNum)
960     {
961     USERp u = User[SpriteNum];
962     SPRITEp sp = User[SpriteNum]->SpriteP;
963 
964     // adjust jump speed by gravity
965     u->jump_speed += u->jump_grav * ACTORMOVETICS;
966 
967     // adjust player height by jump speed
968     sp->z += u->jump_speed * ACTORMOVETICS;
969 
970     // Stick like glue when you hit the ground
971     if (sp->z > u->loz - u->floor_dist)
972         {
973         sp->z = u->loz - u->floor_dist;
974         RESET(u->Flags, SPR_FALLING);
975         }
976 
977     return (0);
978     }
979 #endif
980 
981 
982 #include "saveable.h"
983 
984 static saveable_code saveable_actor_code[] = {
985 	SAVE_CODE(DoScaleSprite),
986 	SAVE_CODE(DoActorDie),
987 	SAVE_CODE(DoDebrisCurrent),
988 	SAVE_CODE(DoActorSectorDamage),
989 	SAVE_CODE(DoActorDebris),
990 	SAVE_CODE(DoFireFly),
991 	SAVE_CODE(DoGenerateSewerDebris),
992 	SAVE_CODE(KeepActorOnFloor),
993 	SAVE_CODE(DoActorBeginSlide),
994 	SAVE_CODE(DoActorSlide),
995 	SAVE_CODE(DoActorBeginJump),
996 	SAVE_CODE(DoActorJump),
997 	SAVE_CODE(DoActorBeginFall),
998 	SAVE_CODE(DoActorFall),
999 	SAVE_CODE(DoActorStopFall),
1000 	SAVE_CODE(DoActorDeathMove),
1001 	SAVE_CODE(DoBeginJump),
1002 	SAVE_CODE(DoJump),
1003 	SAVE_CODE(DoBeginFall),
1004 	SAVE_CODE(DoFall)
1005 };
1006 
1007 saveable_module saveable_actor = {
1008 	// code
1009 	saveable_actor_code,
1010 	SIZ(saveable_actor_code),
1011 
1012 	// data
1013 	NULL,0
1014 };
1015