]> 4ch.mooo.com Git - 16.git/blob - 16/cawat/C5_STATE.C
wwww added catacombs source~
[16.git] / 16 / cawat / C5_STATE.C
1 /* Catacomb Armageddon Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\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
8  *\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
13  *\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
17  */\r
18 \r
19 // C3_STATE.C\r
20 \r
21 #include "DEF.H"\r
22 #pragma hdrstop\r
23 \r
24 /*\r
25 =============================================================================\r
26 \r
27                                                  LOCAL CONSTANTS\r
28 \r
29 =============================================================================\r
30 */\r
31 \r
32 \r
33 /*\r
34 =============================================================================\r
35 \r
36                                                  GLOBAL VARIABLES\r
37 \r
38 =============================================================================\r
39 */\r
40 \r
41 \r
42 \r
43 /*\r
44 =============================================================================\r
45 \r
46                                                  LOCAL VARIABLES\r
47 \r
48 =============================================================================\r
49 */\r
50 \r
51 \r
52 dirtype opposite[9] =\r
53         {south,west,north,east,southwest,northwest,northeast,southeast,nodir};\r
54 \r
55 \r
56 \r
57 //===========================================================================\r
58 \r
59 \r
60 /*\r
61 ===================\r
62 =\r
63 = Internal_SpawnNewObj\r
64 =\r
65 ===================\r
66 */\r
67 void Internal_SpawnNewObj (unsigned x, unsigned y, statetype *state, unsigned size, boolean UseDummy, boolean PutInActorat)\r
68 {\r
69         extern objtype dummyobj;\r
70 \r
71         GetNewObj(UseDummy);\r
72         new->size = size;\r
73         new->state = state;\r
74         new->ticcount = random (state->tictime)+1;\r
75 \r
76         new->tilex = x;\r
77         new->tiley = y;\r
78         new->x = ((long)x<<TILESHIFT)+TILEGLOBAL/2;\r
79         new->y = ((long)y<<TILESHIFT)+TILEGLOBAL/2;\r
80         CalcBounds(new);\r
81         new->dir = nodir;\r
82         new->active = noalways;\r
83 \r
84         if (new != &dummyobj && PutInActorat)\r
85                 actorat[new->tilex][new->tiley] = new;\r
86 }\r
87 \r
88 void Internal_SpawnNewObjFrac (long x, long y, statetype *state, unsigned size,boolean UseDummy)\r
89 {\r
90         GetNewObj(UseDummy);\r
91         new->size = size;\r
92         new->state = state;\r
93         new->ticcount = random (state->tictime)+1;\r
94         new->active = noalways;\r
95 \r
96         new->x = x;\r
97         new->y = y;\r
98         new->tilex = x>>TILESHIFT;\r
99         new->tiley = y>>TILESHIFT;\r
100         CalcBounds(new);\r
101         new->distance = 100;\r
102         new->dir = nodir;\r
103 }\r
104 \r
105 \r
106 \r
107 \r
108 /*\r
109 ===================\r
110 =\r
111 = CheckHandAttack\r
112 =\r
113 = If the object can move next to the player, it will return true\r
114 =\r
115 ===================\r
116 */\r
117 \r
118 boolean CheckHandAttack (objtype *ob)\r
119 {\r
120         long deltax,deltay,size;\r
121 \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
125 \r
126         if (deltax > size || deltax < -size || deltay > size || deltay < -size)\r
127                 return false;\r
128 \r
129         return true;\r
130 }\r
131 \r
132 \r
133 /*\r
134 ===================\r
135 =\r
136 = T_DoDamage\r
137 =\r
138 = Attacks the player if still nearby, then immediately changes to next state\r
139 =\r
140 ===================\r
141 */\r
142 \r
143 void T_DoDamage (objtype *ob)\r
144 {\r
145         int     points;\r
146 \r
147 \r
148         if (CheckHandAttack(ob) && (!(ob->flags & of_damagedone)))\r
149         {\r
150                 points = 0;\r
151 \r
152                 switch (ob->obclass)\r
153                 {\r
154                 case zombieobj:\r
155                 case fatdemonobj:\r
156                         points = 8;\r
157                         break;\r
158                 case reddemonobj:\r
159                 case godessobj:\r
160                         points = 15;\r
161                         break;\r
162                 case antobj:\r
163                         points = 2;\r
164                         break;\r
165                 case skeletonobj:\r
166                         points = 6;\r
167                         break;\r
168 \r
169                 case wetobj:\r
170                         points = 7;\r
171                         break;\r
172                 case treeobj:\r
173                         points = 7;\r
174                         break;\r
175                 case bunnyobj:\r
176                         points = 4;\r
177                         break;\r
178                 }\r
179                 TakeDamage (points);\r
180                 ob->flags |= of_damagedone;\r
181         }\r
182 }\r
183 \r
184 \r
185 //==========================================================================\r
186 \r
187 /*\r
188 ==================================\r
189 =\r
190 = Walk\r
191 =\r
192 ==================================\r
193 */\r
194 \r
195 boolean Walk (objtype *ob)\r
196 {\r
197         switch (ob->dir)\r
198         {\r
199         case north:\r
200                 if (actorat[ob->tilex][ob->tiley-1])\r
201                         return false;\r
202                 ob->tiley--;\r
203                 ob->distance = TILEGLOBAL;\r
204                 return true;\r
205 \r
206         case northeast:\r
207                 if (actorat[ob->tilex+1][ob->tiley-1])\r
208                         return false;\r
209                 ob->tilex++;\r
210                 ob->tiley--;\r
211                 ob->distance = TILEGLOBAL;\r
212                 return true;\r
213 \r
214         case east:\r
215                 if (actorat[ob->tilex+1][ob->tiley])\r
216                         return false;\r
217                 ob->tilex++;\r
218                 ob->distance = TILEGLOBAL;\r
219                 return true;\r
220 \r
221         case southeast:\r
222                 if (actorat[ob->tilex+1][ob->tiley+1])\r
223                         return false;\r
224                 ob->tilex++;\r
225                 ob->tiley++;\r
226                 ob->distance = TILEGLOBAL;\r
227                 return true;\r
228 \r
229         case south:\r
230                 if (actorat[ob->tilex][ob->tiley+1])\r
231                         return false;\r
232                 ob->tiley++;\r
233                 ob->distance = TILEGLOBAL;\r
234                 return true;\r
235 \r
236         case southwest:\r
237                 if (actorat[ob->tilex-1][ob->tiley+1])\r
238                         return false;\r
239                 ob->tilex--;\r
240                 ob->tiley++;\r
241                 ob->distance = TILEGLOBAL;\r
242                 return true;\r
243 \r
244         case west:\r
245                 if (actorat[ob->tilex-1][ob->tiley])\r
246                         return false;\r
247                 ob->tilex--;\r
248                 ob->distance = TILEGLOBAL;\r
249                 return true;\r
250 \r
251         case northwest:\r
252                 if (actorat[ob->tilex-1][ob->tiley-1])\r
253                         return false;\r
254                 ob->tilex--;\r
255                 ob->tiley--;\r
256                 ob->distance = TILEGLOBAL;\r
257                 return true;\r
258 \r
259         case nodir:\r
260                 return false;\r
261         }\r
262 \r
263         Quit ("Walk: Bad dir");\r
264         return false;\r
265 }\r
266 \r
267 \r
268 \r
269 /*\r
270 ==================================\r
271 =\r
272 = ChaseThink\r
273 = have the current monster go after the player,\r
274 = either diagonally or straight on\r
275 =\r
276 ==================================\r
277 */\r
278 \r
279 void ChaseThink (objtype *obj, boolean diagonal)\r
280 {\r
281         int deltax,deltay,i;\r
282         dirtype d[3];\r
283         dirtype tdir, olddir, turnaround;\r
284 \r
285 \r
286         olddir=obj->dir;\r
287         turnaround=opposite[olddir];\r
288 \r
289         deltax=player->tilex - obj->tilex;\r
290         deltay=player->tiley - obj->tiley;\r
291 \r
292         d[1]=nodir;\r
293         d[2]=nodir;\r
294 \r
295         if (deltax>0)\r
296                 d[1]= east;\r
297         if (deltax<0)\r
298                 d[1]= west;\r
299         if (deltay>0)\r
300                 d[2]=south;\r
301         if (deltay<0)\r
302                 d[2]=north;\r
303 \r
304         if (abs(deltay)>abs(deltax))\r
305         {\r
306                 tdir=d[1];\r
307                 d[1]=d[2];\r
308                 d[2]=tdir;\r
309         }\r
310 \r
311         if (d[1]==turnaround)\r
312                 d[1]=nodir;\r
313         if (d[2]==turnaround)\r
314                 d[2]=nodir;\r
315 \r
316 \r
317         if (diagonal)\r
318         {                           /*ramdiagonals try the best dir first*/\r
319                 if (d[1]!=nodir)\r
320                 {\r
321                         obj->dir=d[1];\r
322                         if (Walk(obj))\r
323                                 return;     /*either moved forward or attacked*/\r
324                 }\r
325 \r
326                 if (d[2]!=nodir)\r
327                 {\r
328                         obj->dir=d[2];\r
329                         if (Walk(obj))\r
330                                 return;\r
331                 }\r
332         }\r
333         else\r
334         {                  /*ramstraights try the second best dir first*/\r
335 \r
336                 if (d[2]!=nodir)\r
337                 {\r
338                         obj->dir=d[2];\r
339                         if (Walk(obj))\r
340                                 return;\r
341                 }\r
342 \r
343                 if (d[1]!=nodir)\r
344                 {\r
345                         obj->dir=d[1];\r
346                         if (Walk(obj))\r
347                                 return;\r
348                 }\r
349         }\r
350 \r
351 /* there is no direct path to the player, so pick another direction */\r
352 \r
353         obj->dir=olddir;\r
354         if (Walk(obj))\r
355                 return;\r
356 \r
357         if (US_RndT()>128)      /*randomly determine direction of search*/\r
358         {\r
359                 for (tdir=north;tdir<=west;tdir++)\r
360                 {\r
361                         if (tdir!=turnaround)\r
362                         {\r
363                                 obj->dir=tdir;\r
364                                 if (Walk(obj))\r
365                                         return;\r
366                         }\r
367                 }\r
368         }\r
369         else\r
370         {\r
371                 for (tdir=west;tdir>=north;tdir--)\r
372                 {\r
373                         if (tdir!=turnaround)\r
374                         {\r
375                           obj->dir=tdir;\r
376                           if (Walk(obj))\r
377                                 return;\r
378                         }\r
379                 }\r
380         }\r
381 \r
382         obj->dir=turnaround;\r
383         Walk(obj);              /*last chance, don't worry about returned value*/\r
384 }\r
385 \r
386 \r
387 /*\r
388 =================\r
389 =\r
390 = MoveObj\r
391 =\r
392 =================\r
393 */\r
394 \r
395 void MoveObj (objtype *ob, long move)\r
396 {\r
397         ob->distance -=move;\r
398 \r
399         switch (ob->dir)\r
400         {\r
401         case north:\r
402                 ob->y -= move;\r
403                 return;\r
404         case northeast:\r
405                 ob->x += move;\r
406                 ob->y -= move;\r
407                 return;\r
408         case east:\r
409                 ob->x += move;\r
410                 return;\r
411         case southeast:\r
412                 ob->x += move;\r
413                 ob->y += move;\r
414                 return;\r
415         case south:\r
416                 ob->y += move;\r
417                 return;\r
418         case southwest:\r
419                 ob->x -= move;\r
420                 ob->y += move;\r
421                 return;\r
422         case west:\r
423                 ob->x -= move;\r
424                 return;\r
425         case northwest:\r
426                 ob->x -= move;\r
427                 ob->y -= move;\r
428                 return;\r
429 \r
430         case nodir:\r
431                 return;\r
432         }\r
433 }\r
434 \r
435 \r
436 /*\r
437 =================\r
438 =\r
439 = Chase\r
440 =\r
441 = returns true if hand attack range\r
442 =\r
443 =================\r
444 */\r
445 \r
446 boolean Chase (objtype *ob, boolean diagonal)\r
447 {\r
448         long move;\r
449         long deltax,deltay,size;\r
450 \r
451         ob->flags &= ~of_damagedone;\r
452 \r
453         move = ob->speed*tics;\r
454         size = (long)ob->size + player->size + move + SIZE_TEST;\r
455 \r
456         while (move)\r
457         {\r
458                 deltax = ob->x - player->x;\r
459                 deltay = ob->y - player->y;\r
460 \r
461                 if (deltax <= size && deltax >= -size\r
462                 && deltay <= size && deltay >= -size)\r
463                 {\r
464                         CalcBounds (ob);\r
465                         return true;\r
466                 }\r
467 \r
468                 if (move < ob->distance)\r
469                 {\r
470                         MoveObj (ob,move);\r
471                         break;\r
472                 }\r
473                 actorat[ob->tilex][ob->tiley] = 0;      // pick up marker from goal\r
474                 if (ob->dir == nodir)\r
475                         ob->dir = north;\r
476 \r
477                 ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
478                 ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
479                 move -= ob->distance;\r
480 \r
481                 ChaseThink (ob,diagonal);\r
482                 if (!ob->distance)\r
483                         break;                  // no possible move\r
484                 actorat[ob->tilex][ob->tiley] = ob;     // set down a new goal marker\r
485         }\r
486         CalcBounds (ob);\r
487         return false;\r
488 }\r
489 \r
490 //===========================================================================\r
491 \r
492 \r
493 /*\r
494 ===================\r
495 =\r
496 = ShootActor\r
497 =\r
498 ===================\r
499 */\r
500 \r
501 void ShootActor (objtype *ob, unsigned damage)\r
502 {\r
503         ob->hitpoints -= damage;\r
504 \r
505         if (ob->hitpoints<=0)\r
506         {\r
507                 switch (ob->obclass)\r
508                 {\r
509                 case reddemonobj:\r
510                         ob->state = &s_red_demondie1;\r
511                         break;\r
512                 case succubusobj:\r
513                         ob->state = &s_succubus_death1;\r
514                         break;\r
515                 case fatdemonobj:\r
516                         ob->state = &s_fatdemon_blowup1;\r
517                         break;\r
518                 case godessobj:\r
519                         ob->state = &s_godessdie1;\r
520                         break;\r
521                 case mageobj:\r
522                         ob->state = &s_magedie1;\r
523                         break;\r
524                 case batobj:\r
525                         ob->state = &s_batdie1;\r
526 #if USE_INERT_LIST\r
527                         ob->obclass = solidobj;         // don't add this obj to inert list\r
528 #endif\r
529                         break;\r
530                 case grelmobj:\r
531                         ob->state = &s_greldie1;\r
532                         break;\r
533 \r
534                 case zombieobj:\r
535                         ob->state = &s_zombie_death1;\r
536                 break;\r
537 \r
538                 case skeletonobj:\r
539                         ob->state = &s_skel_die1;\r
540                 break;\r
541 \r
542                 case antobj:\r
543                         ob->state = &s_ant_die1;\r
544                 break;\r
545 \r
546                 case wetobj:\r
547                         ob->state = &s_wet_die1;\r
548 #if USE_INERT_LIST\r
549                         ob->obclass = solidobj;         // don't add this obj to inert list\r
550 #endif\r
551                 break;\r
552 \r
553                 case eyeobj:\r
554                         ob->state = &s_eye_die1;\r
555                 break;\r
556 \r
557                 case sshotobj:\r
558                 case eshotobj:\r
559                 case mshotobj:\r
560                         ob->state = &s_bonus_die;\r
561 #if USE_INERT_LIST\r
562                         ob->obclass = solidobj;         // don't add these objs to inert list\r
563 #endif\r
564                 break;\r
565 \r
566                 case treeobj:\r
567                         ob->state = &s_tree_death1;\r
568                         ob->obclass = solidobj;\r
569                         ob->temp1 = 3;\r
570                         ob->flags &= ~of_damagedone;\r
571                         CalcBounds(ob);\r
572                 break;\r
573 \r
574                 case bunnyobj:\r
575                         ob->state = &s_bunny_death1;\r
576                 break;\r
577 \r
578                 case bonusobj:\r
579                 case freezeobj:\r
580                         switch (ob->temp1)\r
581                         {\r
582                                 case B_POTION:\r
583                                 case B_CHEST:\r
584                                 case B_NUKE:\r
585                                 case B_BOLT:\r
586                                         ob->state = &s_pshot_exp1;\r
587                                         ob->obclass = expobj;\r
588                                         ob->ticcount = ob->state->tictime;\r
589                                         SpawnBigExplosion(ob->x,ob->y,12,(16l<<16L));\r
590                                         bordertime = FLASHTICS<<2;\r
591                                         bcolor = 14;\r
592                                         VW_ColorBorder(14 | 56);\r
593                                         DisplaySMsg("Item destroyed", NULL);\r
594                                         status_flag  = S_NONE;\r
595                                         status_delay = 80;\r
596                                 break;\r
597                         }\r
598 #if USE_INERT_LIST\r
599                         ob->obclass = solidobj;         // don't add this obj to inert list\r
600 #endif\r
601                 break;\r
602 \r
603                 }\r
604 \r
605                 if (ob->obclass != solidobj && ob->obclass != realsolidobj)\r
606                 {\r
607                         ob->obclass = inertobj;\r
608                         ob->flags &= ~of_shootable;\r
609                         actorat[ob->tilex][ob->tiley] = NULL;\r
610 #if USE_INERT_LIST\r
611                         MoveObjToInert(ob);\r
612 #endif\r
613                 }\r
614                 else\r
615                 {\r
616                         if (ob->flags & of_forcefield)\r
617                         {\r
618                                 ob->state = &s_force_field_die;\r
619                                 ob->flags &= ~of_shootable;\r
620                         }\r
621                 }\r
622         }\r
623         else\r
624         {\r
625                 switch (ob->obclass)\r
626                 {\r
627                 case reddemonobj:\r
628                         if (!(random(8)))\r
629                                 ob->state = &s_red_demonouch;\r
630                         else\r
631                                 return;\r
632                         break;\r
633                 case succubusobj:\r
634                         ob->state = &s_succubus_ouch;\r
635                         break;\r
636                 case fatdemonobj:\r
637                         ob->state = &s_fatdemon_ouch;\r
638                         break;\r
639                 case godessobj:\r
640                         ob->state = &s_godessouch;\r
641                         break;\r
642                 case mageobj:\r
643                         ob->state = &s_mageouch;\r
644                         break;\r
645 \r
646                 case grelmobj:\r
647                         ob->state = &s_grelouch;\r
648                         break;\r
649 \r
650                 case zombieobj:\r
651                         ob->state = &s_zombie_ouch;\r
652                 break;\r
653 \r
654                 case antobj:\r
655                         ob->state = &s_ant_ouch;\r
656                         break;\r
657 \r
658                 case skeletonobj:\r
659                         ob->state = &s_skel_ouch;\r
660                         break;\r
661 \r
662                 case wetobj:\r
663                         ob->state = &s_wet_ouch;\r
664                         break;\r
665 \r
666                 case eyeobj:\r
667                         ob->state = &s_eye_ouch;\r
668                 break;\r
669 \r
670                 case treeobj:\r
671                         ob->state = &s_tree_ouch;\r
672                 break;\r
673 \r
674                 case bunnyobj:\r
675                         ob->state = &s_bunny_ouch;\r
676                 break;\r
677                 }\r
678         }\r
679         ob->ticcount = ob->state->tictime;\r
680 }\r
681 \r
682 \r