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
34 =============================================================================
\r
38 =============================================================================
\r
44 =============================================================================
\r
48 =============================================================================
\r
52 dirtype opposite[9] =
\r
53 {south,west,north,east,southwest,northwest,northeast,southeast,nodir};
\r
57 //===========================================================================
\r
63 = Internal_SpawnNewObj
\r
67 void Internal_SpawnNewObj (unsigned x, unsigned y, statetype *state, unsigned size, boolean UseDummy, boolean PutInActorat)
\r
69 extern objtype dummyobj;
\r
71 GetNewObj(UseDummy);
\r
74 new->ticcount = random (state->tictime)+1;
\r
78 new->x = ((long)x<<TILESHIFT)+TILEGLOBAL/2;
\r
79 new->y = ((long)y<<TILESHIFT)+TILEGLOBAL/2;
\r
82 new->active = noalways;
\r
84 if (new != &dummyobj && PutInActorat)
\r
85 actorat[new->tilex][new->tiley] = new;
\r
88 void Internal_SpawnNewObjFrac (long x, long y, statetype *state, unsigned size,boolean UseDummy)
\r
90 GetNewObj(UseDummy);
\r
93 new->ticcount = random (state->tictime)+1;
\r
94 new->active = noalways;
\r
98 new->tilex = x>>TILESHIFT;
\r
99 new->tiley = y>>TILESHIFT;
\r
101 new->distance = 100;
\r
109 ===================
\r
113 = If the object can move next to the player, it will return true
\r
115 ===================
\r
118 boolean CheckHandAttack (objtype *ob)
\r
120 long deltax,deltay,size;
\r
122 size = (long)ob->size + player->size + ob->speed*tics + SIZE_TEST;
\r
123 deltax = ob->x - player->x;
\r
124 deltay = ob->y - player->y;
\r
126 if (deltax > size || deltax < -size || deltay > size || deltay < -size)
\r
134 ===================
\r
138 = Attacks the player if still nearby, then immediately changes to next state
\r
140 ===================
\r
143 void T_DoDamage (objtype *ob)
\r
148 if (CheckHandAttack(ob) && (!(ob->flags & of_damagedone)))
\r
152 switch (ob->obclass)
\r
171 case cyborgdemonobj:
\r
176 points = EasyDoDamage(points);
\r
177 TakeDamage (points);
\r
178 ob->flags |= of_damagedone;
\r
183 //==========================================================================
\r
186 ==================================
\r
190 ==================================
\r
193 boolean Walk (objtype *ob)
\r
198 if (actorat[ob->tilex][ob->tiley-1])
\r
201 ob->distance = TILEGLOBAL;
\r
205 if (actorat[ob->tilex+1][ob->tiley-1])
\r
209 ob->distance = TILEGLOBAL;
\r
213 if (actorat[ob->tilex+1][ob->tiley])
\r
216 ob->distance = TILEGLOBAL;
\r
220 if (actorat[ob->tilex+1][ob->tiley+1])
\r
224 ob->distance = TILEGLOBAL;
\r
228 if (actorat[ob->tilex][ob->tiley+1])
\r
231 ob->distance = TILEGLOBAL;
\r
235 if (actorat[ob->tilex-1][ob->tiley+1])
\r
239 ob->distance = TILEGLOBAL;
\r
243 if (actorat[ob->tilex-1][ob->tiley])
\r
246 ob->distance = TILEGLOBAL;
\r
250 if (actorat[ob->tilex-1][ob->tiley-1])
\r
254 ob->distance = TILEGLOBAL;
\r
261 Quit ("Walk: Bad dir");
\r
268 ==================================
\r
271 = have the current monster go after the player,
\r
272 = either diagonally or straight on
\r
274 ==================================
\r
277 void ChaseThink (objtype *obj, boolean diagonal)
\r
279 int deltax,deltay,i;
\r
281 dirtype tdir, olddir, turnaround;
\r
285 turnaround=opposite[olddir];
\r
287 deltax=player->tilex - obj->tilex;
\r
288 deltay=player->tiley - obj->tiley;
\r
302 if (abs(deltay)>abs(deltax))
\r
309 if (d[1]==turnaround)
\r
311 if (d[2]==turnaround)
\r
316 { /*ramdiagonals try the best dir first*/
\r
321 return; /*either moved forward or attacked*/
\r
332 { /*ramstraights try the second best dir first*/
\r
349 // Kluge to make the running eye stay in place if blocked, ie, not divert
\r
351 if (obj->obclass == reyeobj)
\r
355 /* there is no direct path to the player, so pick another direction */
\r
361 if (US_RndT()>128) /*randomly determine direction of search*/
\r
363 for (tdir=north;tdir<=west;tdir++)
\r
365 if (tdir!=turnaround)
\r
375 for (tdir=west;tdir>=north;tdir--)
\r
377 if (tdir!=turnaround)
\r
386 obj->dir=turnaround;
\r
387 Walk(obj); /*last chance, don't worry about returned value*/
\r
399 void MoveObj (objtype *ob, long move)
\r
401 ob->distance -=move;
\r
445 = returns true if hand attack range
\r
450 boolean Chase (objtype *ob, boolean diagonal)
\r
453 long deltax,deltay,size;
\r
455 ob->flags &= ~of_damagedone;
\r
457 move = ob->speed*tics;
\r
458 size = (long)ob->size + player->size + move + SIZE_TEST;
\r
462 deltax = ob->x - player->x;
\r
463 deltay = ob->y - player->y;
\r
465 if (deltax <= size && deltax >= -size
\r
466 && deltay <= size && deltay >= -size)
\r
472 if (move < ob->distance) //ob->distance - distance before you move
\r
473 { // over into next tile
\r
478 if (ob->obclass == reyeobj) // Kludge for the "running eye"
\r
482 MoveObj(ob, ob->distance/2);
\r
487 actorat[ob->tilex][ob->tiley] = 0; // pick up marker from goal
\r
488 if (ob->dir == nodir)
\r
491 ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
\r
492 ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
\r
493 move -= ob->distance;
\r
495 ChaseThink (ob, diagonal);
\r
497 break; // no possible move
\r
498 actorat[ob->tilex][ob->tiley] = ob; // set down a new goal marker
\r
504 //===========================================================================
\r
508 ===================
\r
512 ===================
\r
515 void ShootActor (objtype *ob, unsigned damage)
\r
518 ob->hitpoints -= damage;
\r
520 if (ob->hitpoints<=0)
\r
522 switch (ob->obclass)
\r
526 ob->state = &s_pshot_exp1;
\r
527 ob->obclass = expobj;
\r
528 ob->ticcount = ob->state->tictime;
\r
529 SpawnBigExplosion(ob->x,ob->y,12,(16l<<16L));
\r
533 ob->state = &s_aqua_die1;
\r
538 ob->state = &s_wizard_die1;
\r
542 ob->state = &s_trolldie1;
\r
546 ob->state = &s_blob_die1;
\r
550 ob->state = &s_ray_die1;
\r
554 ob->state = &s_skel_die1;
\r
558 ob->state = &s_fmagedie1;
\r
562 ob->state = &s_robotank_death1;
\r
567 ob->state = &s_stompy_death1;
\r
571 ob->state = &s_bug_death1;
\r
575 ob->state = &s_demondie1;
\r
578 case cyborgdemonobj:
\r
579 ob->state = &s_cyborg_demondie1;
\r
583 ob->state = &s_invis_death1;
\r
587 ob->state = &s_greldie1;
\r
591 ob->state = &s_eye_die1;
\r
595 ob->state = &s_reye_die1;
\r
599 ob->state = &s_pshot_exp1;
\r
600 ob->obclass = expobj;
\r
601 ob->ticcount = ob->state->tictime;
\r
602 SpawnBigExplosion(ob->x,ob->y,12,(16l<<16L));
\r
615 ob->state = &s_bonus_die;
\r
617 ob->obclass = solidobj; // don't add these objs to inert list
\r
630 ob->state = &s_pshot_exp1;
\r
631 ob->obclass = expobj;
\r
632 ob->ticcount = ob->state->tictime;
\r
633 SpawnBigExplosion(ob->x,ob->y,12,(16l<<16L));
\r
634 bordertime = FLASHTICS<<2;
\r
636 VW_ColorBorder(14 | 56);
\r
637 DisplaySMsg("Item destroyed", NULL);
\r
638 status_flag = S_NONE;
\r
643 ob->obclass = solidobj; // don't add this obj to inert list
\r
648 if (ob->obclass != solidobj && ob->obclass != realsolidobj)
\r
650 ob->obclass = inertobj;
\r
651 ob->flags &= ~of_shootable;
\r
652 actorat[ob->tilex][ob->tiley] = NULL;
\r
654 MoveObjToInert(ob);
\r
659 if (ob->flags & of_forcefield)
\r
661 ob->state = &s_force_field_die;
\r
662 ob->flags &= ~of_shootable;
\r
668 switch (ob->obclass)
\r
671 ob->state = &s_wizard_ouch;
\r
676 ob->state = &s_trollouch;
\r
682 ob->state = &s_blob_ouch;
\r
686 ob->state = &s_skel_ouch;
\r
690 ob->state = &s_fmageouch;
\r
694 ob->state = &s_stompy_ouch;
\r
698 ob->state = &s_bug_ouch;
\r
701 case cyborgdemonobj:
\r
703 ob->state = &s_cyborg_demonouch;
\r
710 ob->state = &s_demonouch;
\r
716 ob->state = &s_invis_fizz1;
\r
720 ob->state = &s_grelouch;
\r
724 ob->state = &s_eye_ouch;
\r
728 ob->state = &s_reye_ouch;
\r
733 ob->ticcount = ob->state->tictime;
\r