1 /* Catacomb Apocalypse Source Code
\r
2 * Copyright (C) 1993-2014 Flat Rock Software
\r
4 * This program is free software; you can redistribute it and/or modify
\r
5 * it under the terms of the GNU General Public License as published by
\r
6 * the Free Software Foundation; either version 2 of the License, or
\r
7 * (at your option) any later version.
\r
9 * This program is distributed in the hope that it will be useful,
\r
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
12 * GNU General Public License for more details.
\r
14 * You should have received a copy of the GNU General Public License along
\r
15 * with this program; if not, write to the Free Software Foundation, Inc.,
\r
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
25 =============================================================================
\r
29 =============================================================================
\r
33 =============================================================================
\r
37 =============================================================================
\r
40 boolean ShootPlayer (objtype *ob, short obclass, short speed, statetype *state);
\r
41 void T_ShootPlayer(objtype *ob);
\r
44 =============================================================================
\r
48 =============================================================================
\r
56 =============================================================================
\r
60 =============================================================================
\r
63 void T_TrollDemon (objtype *ob);
\r
65 statetype s_demonpause = {DEMON1PIC,40,NULL,&s_demon2};
\r
67 statetype s_demon1 = {DEMON1PIC,20,&T_TrollDemon,&s_demon2};
\r
68 statetype s_demon2 = {DEMON2PIC,20,&T_TrollDemon,&s_demon3};
\r
69 statetype s_demon3 = {DEMON3PIC,20,&T_TrollDemon,&s_demon4};
\r
70 statetype s_demon4 = {DEMON4PIC,20,&T_TrollDemon,&s_demon1};
\r
72 statetype s_demonattack1 = {DEMONATTACK1PIC,20,NULL,&s_demonattack2};
\r
73 statetype s_demonattack2 = {DEMONATTACK2PIC,20,NULL,&s_demonattack3};
\r
74 statetype s_demonattack3 = {DEMONATTACK3PIC,30,&T_DoDamage,&s_demonpause};
\r
76 statetype s_demonouch = {DEMONOUCHPIC,15,&T_TrollDemon,&s_demon1};
\r
78 statetype s_demondie1 = {DEMONDIE1PIC,40,NULL,&s_demondie2};
\r
79 statetype s_demondie2 = {DEMONDIE2PIC,30,&LargeSound,&s_demondie3};
\r
80 statetype s_demondie3 = {DEMONDIE3PIC,0,NULL,&s_demondie3};
\r
92 void SpawnDemon (int tilex, int tiley)
\r
94 SpawnNewObj(tilex,tiley,&s_demon1,PIXRADIUS*35);
\r
95 new->obclass = demonobj;
\r
97 new->flags |= of_shootable;
\r
98 new->hitpoints = EasyHitPoints(30);
\r
103 =============================================================================
\r
107 =============================================================================
\r
110 statetype s_trollpause = {TROLL1PIC, 30, &T_DoDamage, &s_troll2};
\r
112 statetype s_troll1 = {TROLL1PIC, 13, &T_TrollDemon, &s_troll2};
\r
113 statetype s_troll2 = {TROLL2PIC, 13, &T_TrollDemon, &s_troll3};
\r
114 statetype s_troll3 = {TROLL3PIC, 13, &T_TrollDemon, &s_troll4};
\r
115 statetype s_troll4 = {TROLL4PIC, 13, &T_TrollDemon, &s_troll1};
\r
117 statetype s_trollattack1 = {TROLLATTACK1PIC, 15, NULL, &s_trollattack2};
\r
118 statetype s_trollattack2 = {TROLLATTACK2PIC, 20, NULL, &s_trollpause};
\r
120 statetype s_trollouch = {TROLLOUCHPIC, 14, &T_TrollDemon, &s_troll1};
\r
122 statetype s_trolldie1 = {TROLLDIE1PIC, 18, NULL, &s_trolldie2};
\r
123 statetype s_trolldie2 = {TROLLDIE2PIC, 15, &LargeSound, &s_trolldie3};
\r
124 statetype s_trolldie3 = {TROLLDIE3PIC, 0, NULL, &s_trolldie3};
\r
135 void SpawnTroll (int tilex, int tiley)
\r
137 SpawnNewObj(tilex,tiley,&s_troll1,35*PIXRADIUS);
\r
139 new->obclass = trollobj;
\r
140 new->flags |= of_shootable;
\r
141 new->hitpoints = EasyHitPoints(15);
\r
146 =============================================================================
\r
150 =============================================================================
\r
153 void T_Demon (objtype *ob);
\r
155 statetype s_cyborg_demon1 = {CYBORG1PIC, 20, T_TrollDemon, &s_cyborg_demon2};
\r
156 statetype s_cyborg_demon2 = {CYBORG2PIC, 20, T_TrollDemon, &s_cyborg_demon3};
\r
157 statetype s_cyborg_demon3 = {CYBORG3PIC, 20, T_TrollDemon, &s_cyborg_demon4};
\r
158 statetype s_cyborg_demon4 = {CYBORG4PIC, 20, T_TrollDemon, &s_cyborg_demon1};
\r
160 statetype s_cyborg_demonattack1 = {CYBORGATTACK1PIC, 20, NULL, &s_cyborg_demonattack2};
\r
161 statetype s_cyborg_demonattack2 = {CYBORGATTACK2PIC, 20, NULL, &s_cyborg_demonattack3};
\r
162 statetype s_cyborg_demonattack3 = {CYBORGATTACK3PIC, 30, T_DoDamage, &s_cyborg_demon2};
\r
164 statetype s_cyborg_demonouch = {CYBORGOUCHPIC, 30, NULL, &s_cyborg_demon1};
\r
166 statetype s_cyborg_demondie1 = {CYBORGOUCHPIC, 40, NULL, &s_cyborg_demondie2};
\r
167 statetype s_cyborg_demondie2 = {CYBORGDIE1PIC, 30, &LargeSound, &s_cyborg_demondie3};
\r
168 statetype s_cyborg_demondie3 = {CYBORGDIE2PIC, 20, NULL, &s_cyborg_demondie3};
\r
178 void SpawnCyborgDemon (int tilex, int tiley)
\r
180 SpawnNewObj(tilex, tiley, &s_cyborg_demon1, PIXRADIUS*35);
\r
181 new->obclass = cyborgdemonobj;
\r
183 new->flags |= of_shootable;
\r
184 new->hitpoints = EasyHitPoints(30);
\r
196 void T_TrollDemon (objtype *ob)
\r
198 if (Chase (ob,true) || (random(1000)<RANDOM_ATTACK))
\r
200 if (ob->obclass == cyborgdemonobj)
\r
201 ob->state = &s_cyborg_demonattack1;
\r
203 if (ob->obclass == trollobj)
\r
204 ob->state = &s_trollattack1;
\r
206 ob->state = &s_demonattack1;
\r
207 ob->ticcount = ob->state->tictime;
\r
216 =============================================================================
\r
220 =============================================================================
\r
223 void T_InvisibleDude (objtype *ob);
\r
225 statetype s_invis_fizz1 = {INVIS_FIZZ1PIC, 8, &T_InvisibleDude, &s_invis_fizz2};
\r
226 statetype s_invis_fizz2 = {INVIS_FIZZ2PIC, 8, &T_InvisibleDude, &s_invis_fizz3};
\r
227 statetype s_invis_fizz3 = {INVIS_FIZZ3PIC, 8, &T_InvisibleDude, &s_invis_walk};
\r
229 statetype s_invis_walk = {0, 25, &T_InvisibleDude, &s_invis_walk};
\r
230 statetype s_invis_attack = {0, -1, &T_DoDamage, &s_invis_pause};
\r
231 statetype s_invis_pause = {0, 40, NULL, &s_invis_walk};
\r
233 statetype s_invis_flash1 = {INVIS_FIZZ1PIC, 8, &T_InvisibleDude, &s_invis_walk};
\r
234 statetype s_invis_flash2 = {INVIS_FIZZ2PIC, 8, &T_InvisibleDude, &s_invis_walk};
\r
235 statetype s_invis_flash3 = {INVIS_FIZZ3PIC, 8, &T_InvisibleDude, &s_invis_walk};
\r
237 statetype s_invis_death1 = {INVIS_DEATH1PIC, 40, NULL, &s_invis_death2};
\r
238 statetype s_invis_death2 = {INVIS_DEATH2PIC, 30, &LargeSound, &s_invis_death3};
\r
239 statetype s_invis_death3 = {INVIS_DEATH3PIC, 20, NULL, &s_invis_death3};
\r
248 void SpawnInvisDude(int tilex, int tiley)
\r
250 SpawnNewObj(tilex, tiley, &s_invis_walk, PIXRADIUS*20);
\r
251 new->obclass = invisdudeobj;
\r
253 new->flags |= of_shootable;
\r
254 new->hitpoints = EasyHitPoints(20);
\r
255 new->temp1 = 0; // for random flashing of pictures
\r
266 void T_InvisibleDude (objtype *ob)
\r
270 switch (ob->temp1++)
\r
273 ob->state = &s_invis_flash1;
\r
277 ob->state = &s_invis_flash2;
\r
281 ob->state = &s_invis_flash3;
\r
285 ob->ticcount = ob->state->tictime;
\r
289 if (Chase (ob,true))
\r
291 ob->state = &s_invis_attack;
\r
292 ob->ticcount = ob->state->tictime;
\r
300 =============================================================================
\r
304 temp2 = set when hit player, reset when hit wall
\r
306 =============================================================================
\r
309 #define SPDBOUNCE 4096
\r
310 #define DMGBOUNCE 10
\r
312 void T_Bounce (objtype *ob);
\r
313 void T_Bounce_Death (objtype *ob);
\r
315 statetype s_bounce1 = {PSHOT1PIC, 8, &T_Bounce, &s_bounce2};
\r
316 statetype s_bounce2 = {PSHOT2PIC, 8, &T_Bounce, &s_bounce1};
\r
326 void SpawnBounce (int tilex, int tiley, boolean towest)
\r
328 SpawnNewObj(tilex, tiley, &s_bounce1, 24*PIXRADIUS);
\r
329 new->obclass = bounceobj;
\r
330 new->hitpoints = EasyHitPoints(10);
\r
331 new->flags |= of_shootable;
\r
347 void T_Bounce (objtype *ob)
\r
350 long deltax,deltay,size;
\r
352 move = SPDBOUNCE*tics;
\r
353 size = (long)ob->size + player->size + move;
\r
357 deltax = ob->x - player->x;
\r
358 deltay = ob->y - player->y;
\r
360 if (deltax <= size && deltax >= -size
\r
361 && deltay <= size && deltay >= -size && !ob->temp2)
\r
364 TakeDamage (DMGBOUNCE);
\r
367 if (move < ob->distance)
\r
372 actorat[ob->tilex][ob->tiley] = 0; // pick up marker from goal
\r
374 ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
\r
375 ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
\r
376 move -= ob->distance;
\r
379 // bounce if hit wall
\r
384 if (tilemap[ob->tilex][--ob->tiley])
\r
392 if (tilemap[++ob->tilex][ob->tiley])
\r
400 if (tilemap[ob->tilex][++ob->tiley])
\r
408 if (tilemap[--ob->tilex][ob->tiley])
\r
417 ob->distance = TILEGLOBAL;
\r
419 actorat[ob->tilex][ob->tiley] = ob; // set down a new goal marker
\r
426 =============================================================================
\r
430 =============================================================================
\r
434 void T_Grelminar (objtype *ob);
\r
435 void T_GrelminarShoot (objtype *ob);
\r
436 void T_Grelm_DropKey(objtype *ob);
\r
438 statetype s_grelpause = {GREL1PIC,50,NULL,&s_grel2};
\r
440 statetype s_grel1 = {GREL1PIC,20,T_Grelminar,&s_grel2};
\r
441 statetype s_grel2 = {GREL2PIC,20,T_Grelminar,&s_grel1};
\r
443 statetype s_grelattack3 = {GRELATTACKPIC,30,NULL,&s_grelpause};
\r
445 statetype s_grelouch = {GRELHITPIC,6,NULL,&s_grel1};
\r
447 statetype s_greldie1 = {GRELDIE1PIC,22,NULL,&s_greldie2};
\r
448 statetype s_greldie2 = {GRELDIE2PIC,22,NULL,&s_greldie3};
\r
449 statetype s_greldie3 = {GRELDIE3PIC,22,NULL,&s_greldie4};
\r
450 statetype s_greldie4 = {GRELDIE4PIC,22,NULL,&s_greldie5};
\r
451 statetype s_greldie5 = {GRELDIE5PIC,22,NULL,&s_greldie5a};
\r
452 statetype s_greldie5a = {GRELDIE5PIC,-1,T_Grelm_DropKey,&s_greldie6};
\r
453 statetype s_greldie6 = {GRELDIE6PIC,0,NULL,&s_greldie6};
\r
455 statetype s_gshot1 = {SKULL_SHOTPIC,8,T_ShootPlayer,&s_gshot1};
\r
465 void SpawnGrelminar (int tilex, int tiley)
\r
467 unsigned Grel_Hard;
\r
470 SpawnNewObj(tilex,tiley,&s_grel1,PIXRADIUS*25);
\r
471 new->obclass = grelmobj;
\r
473 new->flags |= of_shootable;
\r
476 // if Grelminar is to drop a key the info-plane byte to the right
\r
477 // should have a 1 in the highbyte, else he will not drop the key.
\r
479 DropKey = *(mapsegs[2]+farmapylookup[tiley]+tilex+1);
\r
481 new->temp1 = DropKey>>8;
\r
486 // The info-plane byte below Grelminar will determine how powerful
\r
487 // Grelminar is. If nothing is there, he is the most powerful.
\r
488 // -- affected are the hit points and the shot damage.
\r
489 // The hit points are controlled here, the shot damage is controlled
\r
490 // within the spawning of the shot. See ShootPlayer for more info.
\r
492 Grel_Hard = *(mapsegs[2]+farmapylookup[tiley+1]+tilex);
\r
495 new->temp2 = Grel_Hard>>8;
\r
496 new->hitpoints = EasyHitPoints((new->temp2 * 10));
\r
500 new->hitpoints = EasyHitPoints(100);
\r
514 void T_Grelminar (objtype *ob)
\r
519 if (ShootPlayer(ob,gshotobj,ob->temp2,&s_gshot1))
\r
521 ob->state = &s_grelattack3;
\r
522 ob->ticcount = ob->state->tictime;
\r
524 if (CheckHandAttack(ob))
\r
525 TakeDamage (ob->temp2*3);
\r
530 //=================================
\r
534 //=================================
\r
535 void T_Grelm_DropKey(objtype *ob)
\r
543 SpawnBonus(ob->tilex,ob->tiley,B_RKEY);
\r
544 SD_PlaySound(GRELM_DEADSND);
\r
550 //--------------------------------------------------------------------------
\r
552 //--------------------------------------------------------------------------
\r
553 boolean ShootPlayer(objtype *ob, short obclass, short speed, statetype *state)
\r
555 int angle = AngleNearPlayer(ob);
\r
560 DSpawnNewObjFrac (ob->x,ob->y,state,PIXRADIUS*14);
\r
561 new->obclass = obclass;
\r
562 new->active = always;
\r
563 new->angle = angle;
\r
566 // If the shot is Grelminar's, then determine the power of the shot.
\r
567 // The shot speed is hard-wired as 10000. But the shot power is
\r
568 // determined by speed. Speed now contains "Grelminar's level of
\r
569 // hardness" and this is multiplied by 3 to get the shot power.
\r
571 if (obclass == gshotobj)
\r
573 new->speed = 10000;
\r
574 new->temp1 = speed*3;
\r
577 new->speed = speed;
\r
583 //--------------------------------------------------------------------------
\r
585 //--------------------------------------------------------------------------
\r
586 void T_ShootPlayer(objtype *ob)
\r
589 long xmove,ymove,speed;
\r
591 speed = ob->speed*tics;
\r
593 xmove = FixedByFrac(speed,costable[ob->angle]);
\r
594 ymove = -FixedByFrac(speed,sintable[ob->angle]);
\r
596 if (ShotClipMove(ob,xmove,ymove))
\r
598 ob->state = &s_pshot_exp1;
\r
599 ob->ticcount = ob->state->tictime;
\r
603 ob->tilex = ob->x >> TILESHIFT;
\r
604 ob->tiley = ob->y >> TILESHIFT;
\r
607 // check for collision with wall
\r
609 if (tilemap[ob->tilex][ob->tiley])
\r
611 // SD_PlaySound (SHOOTWALLSND);
\r
612 ob->state = &s_pshot_exp1;
\r
613 ob->ticcount = s_pshot_exp1.tictime;
\r
619 // check for collision with player
\r
621 if ( ob->xl <= player->xh
\r
622 && ob->xh >= player->xl
\r
623 && ob->yl <= player->yh
\r
624 && ob->yh >= player->yl)
\r
626 switch (ob->obclass)
\r
628 case wshotobj: // Wizard's shot
\r
632 case hshotobj: // Egyptian Head's shot
\r
636 case bshotobj: // Blob's shot
\r
640 case rshotobj: // Ray's shot
\r
644 case rbshotobj: // RamBone's shot
\r
648 case fmshotobj: // Future Mage's shot
\r
652 case rtshotobj: // RoboTank's shot
\r
656 case syshotobj: // Stompy's shot
\r
660 case bgshotobj: // Bug's shot
\r
664 case eshotobj: // Eye's shot
\r
669 TakeDamage (ob->temp1); // the damage of Grelminar's shot -
\r
670 break; // see Grelminar's spawning
\r
677 // check for collision with other solid and realsolid objects.
\r
678 // Great terminology!! -- solid objects really aren't solid
\r
679 // -- realsolid objects ARE solid
\r
680 // if ((actorat[ob->tilex][ob->tiley]) && (actorat[ob->tilex][ob->tiley]->obclass != ob->obclass))
\r
681 if (((actorat[ob->tilex][ob->tiley]->obclass == realsolidobj) ||
\r
682 (actorat[ob->tilex][ob->tiley]->obclass == solidobj)) &&
\r
683 (actorat[ob->tilex][ob->tiley]->flags & of_shootable))
\r
685 ob->state = &s_pshot_exp1;
\r
686 ob->ticcount = s_pshot_exp1.tictime;
\r
691 // check for collision with player
\r
693 for (check = player->next; check; check=check->next)
\r
694 if ((ob->flags & of_shootable)
\r
695 && ob->xl <= check->xh
\r
696 && ob->xh >= check->xl
\r
697 && ob->yl <= check->yh
\r
698 && ob->yh >= check->yl)
\r
700 switch (ob->obclass)
\r
703 case wshotobj: // Wizard's shot
\r
704 ShootActor (check, 3);
\r
707 case hshotobj: // Egyptian Head's shot
\r
708 ShootActor (check, 5);
\r
711 case bshotobj: // Blob's shot
\r
712 ShootActor (check, 2);
\r
715 case rshotobj: // Ray's shot
\r
716 ShootActor (check, 5);
\r
719 case rbshotobj: // RamBone's shot
\r
720 ShootActor (check, 5);
\r
723 case fmshotobj: // Future Mage's shot
\r
724 ShootActor (check, 5);
\r
727 case rtshotobj: // RoboTank's shot
\r
728 ShootActor (check, 15);
\r
731 case syshotobj: // Stompy's shot
\r
732 ShootActor (check, 5);
\r
735 case bgshotobj: // Bug's shot
\r
736 ShootActor (check, 3);
\r
739 case eshotobj: // Eye's shot
\r
740 ShootActor (check, 2);
\r
744 ShootActor (check,25); //NOLAN--check on me!!!!!!!
\r
748 ShootActor (check,25);
\r
752 ob->state = &s_pshot_exp1;
\r
753 ob->ticcount = s_pshot_exp1.tictime;
\r
758 //-------------------------------------------------------------------------
\r
759 // AngleNearPlayer()
\r
760 //-------------------------------------------------------------------------
\r
761 int AngleNearPlayer(objtype *ob)
\r
764 int xdiff = ob->tilex-player->tilex;
\r
765 int ydiff = ob->tiley-player->tiley;
\r
767 if (ob->tiley == player->tiley)
\r
769 if (ob->tilex < player->tilex)
\r
775 if (ob->tilex == player->tilex)
\r
777 if (ob->tiley < player->tiley)
\r
783 if (xdiff == ydiff)
\r
784 if (ob->tilex < player->tilex)
\r
786 if (ob->tiley < player->tiley)
\r
793 if (ob->tiley < player->tiley)
\r