OSDN Git Service

going on vacation >.<
[proj16/16.git] / src / lib / hb / c6_state.c
1 /* Catacomb Apocalypse 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 aquamanobj:\r
155                         points = 7;\r
156                 break;\r
157 \r
158                 case wizardobj:\r
159                         points = 7;\r
160                 break;\r
161 \r
162                 case trollobj:\r
163                         points = 10;\r
164                 break;\r
165 \r
166                 case invisdudeobj:\r
167                         points = 10;\r
168                 break;\r
169 \r
170                 case demonobj:\r
171                 case cyborgdemonobj:\r
172                         points = 15;\r
173                 break;\r
174 \r
175                 }\r
176                 points = EasyDoDamage(points);\r
177                 TakeDamage (points);\r
178                 ob->flags |= of_damagedone;\r
179         }\r
180 }\r
181 \r
182 \r
183 //==========================================================================\r
184 \r
185 /*\r
186 ==================================\r
187 =\r
188 = Walk\r
189 =\r
190 ==================================\r
191 */\r
192 \r
193 boolean Walk (objtype *ob)\r
194 {\r
195         switch (ob->dir)\r
196         {\r
197         case north:\r
198                 if (actorat[ob->tilex][ob->tiley-1])\r
199                         return false;\r
200                 ob->tiley--;\r
201                 ob->distance = TILEGLOBAL;\r
202                 return true;\r
203 \r
204         case northeast:\r
205                 if (actorat[ob->tilex+1][ob->tiley-1])\r
206                         return false;\r
207                 ob->tilex++;\r
208                 ob->tiley--;\r
209                 ob->distance = TILEGLOBAL;\r
210                 return true;\r
211 \r
212         case east:\r
213                 if (actorat[ob->tilex+1][ob->tiley])\r
214                         return false;\r
215                 ob->tilex++;\r
216                 ob->distance = TILEGLOBAL;\r
217                 return true;\r
218 \r
219         case southeast:\r
220                 if (actorat[ob->tilex+1][ob->tiley+1])\r
221                         return false;\r
222                 ob->tilex++;\r
223                 ob->tiley++;\r
224                 ob->distance = TILEGLOBAL;\r
225                 return true;\r
226 \r
227         case south:\r
228                 if (actorat[ob->tilex][ob->tiley+1])\r
229                         return false;\r
230                 ob->tiley++;\r
231                 ob->distance = TILEGLOBAL;\r
232                 return true;\r
233 \r
234         case southwest:\r
235                 if (actorat[ob->tilex-1][ob->tiley+1])\r
236                         return false;\r
237                 ob->tilex--;\r
238                 ob->tiley++;\r
239                 ob->distance = TILEGLOBAL;\r
240                 return true;\r
241 \r
242         case west:\r
243                 if (actorat[ob->tilex-1][ob->tiley])\r
244                         return false;\r
245                 ob->tilex--;\r
246                 ob->distance = TILEGLOBAL;\r
247                 return true;\r
248 \r
249         case northwest:\r
250                 if (actorat[ob->tilex-1][ob->tiley-1])\r
251                         return false;\r
252                 ob->tilex--;\r
253                 ob->tiley--;\r
254                 ob->distance = TILEGLOBAL;\r
255                 return true;\r
256 \r
257         case nodir:\r
258                 return false;\r
259         }\r
260 \r
261         Quit ("Walk: Bad dir");\r
262         return false;\r
263 }\r
264 \r
265 \r
266 \r
267 /*\r
268 ==================================\r
269 =\r
270 = ChaseThink\r
271 = have the current monster go after the player,\r
272 = either diagonally or straight on\r
273 =\r
274 ==================================\r
275 */\r
276 \r
277 void ChaseThink (objtype *obj, boolean diagonal)\r
278 {\r
279         int deltax,deltay,i;\r
280         dirtype d[3];\r
281         dirtype tdir, olddir, turnaround;\r
282 \r
283 \r
284         olddir=obj->dir;\r
285         turnaround=opposite[olddir];\r
286 \r
287         deltax=player->tilex - obj->tilex;\r
288         deltay=player->tiley - obj->tiley;\r
289 \r
290         d[1]=nodir;\r
291         d[2]=nodir;\r
292 \r
293         if (deltax>0)\r
294                 d[1]= east;\r
295         if (deltax<0)\r
296                 d[1]= west;\r
297         if (deltay>0)\r
298                 d[2]=south;\r
299         if (deltay<0)\r
300                 d[2]=north;\r
301 \r
302         if (abs(deltay)>abs(deltax))\r
303         {\r
304                 tdir=d[1];\r
305                 d[1]=d[2];\r
306                 d[2]=tdir;\r
307         }\r
308 \r
309         if (d[1]==turnaround)\r
310                 d[1]=nodir;\r
311         if (d[2]==turnaround)\r
312                 d[2]=nodir;\r
313 \r
314 \r
315         if (diagonal)\r
316         {                           /*ramdiagonals try the best dir first*/\r
317                 if (d[1]!=nodir)\r
318                 {\r
319                         obj->dir=d[1];\r
320                         if (Walk(obj))\r
321                                 return;     /*either moved forward or attacked*/\r
322                 }\r
323 \r
324                 if (d[2]!=nodir)\r
325                 {\r
326                         obj->dir=d[2];\r
327                         if (Walk(obj))\r
328                                 return;\r
329                 }\r
330         }\r
331         else\r
332         {                  /*ramstraights try the second best dir first*/\r
333 \r
334                 if (d[2]!=nodir)\r
335                 {\r
336                         obj->dir=d[2];\r
337                         if (Walk(obj))\r
338                                 return;\r
339                 }\r
340 \r
341                 if (d[1]!=nodir)\r
342                 {\r
343                         obj->dir=d[1];\r
344                         if (Walk(obj))\r
345                                 return;\r
346                 }\r
347         }\r
348 \r
349         // Kluge to make the running eye stay in place if blocked, ie, not divert\r
350         // from path\r
351         if (obj->obclass == reyeobj)\r
352                 return;\r
353 \r
354 \r
355 /* there is no direct path to the player, so pick another direction */\r
356 \r
357         obj->dir=olddir;\r
358         if (Walk(obj))\r
359                 return;\r
360 \r
361         if (US_RndT()>128)      /*randomly determine direction of search*/\r
362         {\r
363                 for (tdir=north;tdir<=west;tdir++)\r
364                 {\r
365                         if (tdir!=turnaround)\r
366                         {\r
367                                 obj->dir=tdir;\r
368                                 if (Walk(obj))\r
369                                         return;\r
370                         }\r
371                 }\r
372         }\r
373         else\r
374         {\r
375                 for (tdir=west;tdir>=north;tdir--)\r
376                 {\r
377                         if (tdir!=turnaround)\r
378                         {\r
379                           obj->dir=tdir;\r
380                           if (Walk(obj))\r
381                                 return;\r
382                         }\r
383                 }\r
384         }\r
385 \r
386         obj->dir=turnaround;\r
387         Walk(obj);              /*last chance, don't worry about returned value*/\r
388 }\r
389 \r
390 \r
391 /*\r
392 =================\r
393 =\r
394 = MoveObj\r
395 =\r
396 =================\r
397 */\r
398 \r
399 void MoveObj (objtype *ob, long move)\r
400 {\r
401         ob->distance -=move;\r
402 \r
403         switch (ob->dir)\r
404         {\r
405         case north:\r
406                 ob->y -= move;\r
407                 return;\r
408         case northeast:\r
409                 ob->x += move;\r
410                 ob->y -= move;\r
411                 return;\r
412         case east:\r
413                 ob->x += move;\r
414                 return;\r
415         case southeast:\r
416                 ob->x += move;\r
417                 ob->y += move;\r
418                 return;\r
419         case south:\r
420                 ob->y += move;\r
421                 return;\r
422         case southwest:\r
423                 ob->x -= move;\r
424                 ob->y += move;\r
425                 return;\r
426         case west:\r
427                 ob->x -= move;\r
428                 return;\r
429         case northwest:\r
430                 ob->x -= move;\r
431                 ob->y -= move;\r
432                 return;\r
433 \r
434         case nodir:\r
435                 return;\r
436         }\r
437 }\r
438 \r
439 \r
440 /*\r
441 =================\r
442 =\r
443 = Chase\r
444 =\r
445 = returns true if hand attack range\r
446 =\r
447 =================\r
448 */\r
449 \r
450 boolean Chase (objtype *ob, boolean diagonal)\r
451 {\r
452         long move;\r
453         long deltax,deltay,size;\r
454 \r
455         ob->flags &= ~of_damagedone;\r
456 \r
457         move = ob->speed*tics;\r
458         size = (long)ob->size + player->size + move + SIZE_TEST;\r
459 \r
460         while (move)\r
461         {\r
462                 deltax = ob->x - player->x;\r
463                 deltay = ob->y - player->y;\r
464 \r
465                 if (deltax <= size && deltax >= -size\r
466                 && deltay <= size && deltay >= -size)\r
467                 {\r
468                         CalcBounds (ob);\r
469                         return true;\r
470                 }\r
471 \r
472                 if (move < ob->distance)                //ob->distance - distance before you move\r
473                 {                             //               over into next tile\r
474                         MoveObj (ob,move);\r
475                         break;\r
476                 }\r
477                 else\r
478                         if (ob->obclass == reyeobj)     // Kludge for the "running eye"\r
479                         {\r
480                                 if (ob->temp1 < 2)\r
481                                 {\r
482                                         MoveObj(ob, ob->distance/2);\r
483                                         ob->temp1 = 0;\r
484                                 }\r
485                         }\r
486 \r
487                 actorat[ob->tilex][ob->tiley] = 0;      // pick up marker from goal\r
488                 if (ob->dir == nodir)\r
489                         ob->dir = north;\r
490 \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
494 \r
495                 ChaseThink (ob, diagonal);\r
496                 if (!ob->distance)\r
497                         break;                  // no possible move\r
498                 actorat[ob->tilex][ob->tiley] = ob;     // set down a new goal marker\r
499         }\r
500         CalcBounds (ob);\r
501         return false;\r
502 }\r
503 \r
504 //===========================================================================\r
505 \r
506 \r
507 /*\r
508 ===================\r
509 =\r
510 = ShootActor\r
511 =\r
512 ===================\r
513 */\r
514 \r
515 void ShootActor (objtype *ob, unsigned damage)\r
516 {\r
517 \r
518         ob->hitpoints -= damage;\r
519 \r
520         if (ob->hitpoints<=0)\r
521         {\r
522                 switch (ob->obclass)\r
523                 {\r
524 \r
525                 case headobj:\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
530                 break;\r
531 \r
532                 case aquamanobj:\r
533                         ob->state = &s_aqua_die1;\r
534                         ob->temp1 = 10;\r
535                 break;\r
536 \r
537                 case wizardobj:\r
538                         ob->state = &s_wizard_die1;\r
539                 break;\r
540 \r
541                 case trollobj:\r
542                         ob->state = &s_trolldie1;\r
543                 break;\r
544 \r
545                 case blobobj:\r
546                         ob->state = &s_blob_die1;\r
547                 break;\r
548 \r
549                 case rayobj:\r
550                         ob->state = &s_ray_die1;\r
551                 break;\r
552 \r
553                 case ramboneobj:\r
554                         ob->state = &s_skel_die1;\r
555                 break;\r
556 \r
557                 case fmageobj:\r
558                         ob->state = &s_fmagedie1;\r
559                 break;\r
560 \r
561                 case robotankobj:\r
562                         ob->state = &s_robotank_death1;\r
563                         ob->temp1 = 10;\r
564                 break;\r
565 \r
566                 case stompyobj:\r
567                         ob->state = &s_stompy_death1;\r
568                 break;\r
569 \r
570                 case bugobj:\r
571                         ob->state = &s_bug_death1;\r
572                 break;\r
573 \r
574                 case demonobj:\r
575                         ob->state = &s_demondie1;\r
576                 break;\r
577 \r
578                 case cyborgdemonobj:\r
579                         ob->state = &s_cyborg_demondie1;\r
580                 break;\r
581 \r
582                 case invisdudeobj:\r
583                         ob->state = &s_invis_death1;\r
584                 break;\r
585 \r
586                 case grelmobj:\r
587                         ob->state = &s_greldie1;\r
588                 break;\r
589 \r
590                 case eyeobj:\r
591                         ob->state = &s_eye_die1;\r
592                 break;\r
593 \r
594                 case reyeobj:\r
595                         ob->state = &s_reye_die1;\r
596                 break;\r
597 \r
598                 case bounceobj:\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
603                 break;\r
604 \r
605                 case rshotobj:\r
606                 case eshotobj:\r
607                 case wshotobj:\r
608                 case hshotobj:\r
609                 case bshotobj:\r
610                 case rbshotobj:\r
611                 case fmshotobj:\r
612                 case rtshotobj:\r
613                 case syshotobj:\r
614                 case bgshotobj:\r
615                         ob->state = &s_bonus_die;\r
616 #if USE_INERT_LIST\r
617                         ob->obclass = solidobj;         // don't add these objs to inert list\r
618 #endif\r
619                 break;\r
620 \r
621                 case bonusobj:\r
622                 case freezeobj:\r
623                         switch (ob->temp1)\r
624                         {\r
625                                 case B_POTION:\r
626                                 case B_OLDCHEST:\r
627                                 case B_CHEST:\r
628                                 case B_NUKE:\r
629                                 case B_BOLT:\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
635                                         bcolor = 14;\r
636                                         VW_ColorBorder(14 | 56);\r
637                                         DisplaySMsg("Item destroyed", NULL);\r
638                                         status_flag  = S_NONE;\r
639                                         status_delay = 80;\r
640                                 break;\r
641                         }\r
642 #if USE_INERT_LIST\r
643                         ob->obclass = solidobj;         // don't add this obj to inert list\r
644 #endif\r
645                 break;\r
646                 }\r
647 \r
648                 if (ob->obclass != solidobj && ob->obclass != realsolidobj)\r
649                 {\r
650                         ob->obclass = inertobj;\r
651                         ob->flags &= ~of_shootable;\r
652                         actorat[ob->tilex][ob->tiley] = NULL;\r
653 #if USE_INERT_LIST\r
654                         MoveObjToInert(ob);\r
655 #endif\r
656                 }\r
657                 else\r
658                 {\r
659                         if (ob->flags & of_forcefield)\r
660                         {\r
661                                 ob->state = &s_force_field_die;\r
662                                 ob->flags &= ~of_shootable;\r
663                         }\r
664                 }\r
665         }\r
666         else\r
667         {\r
668                 switch (ob->obclass)\r
669                 {\r
670                 case wizardobj:\r
671                         ob->state = &s_wizard_ouch;\r
672                 break;\r
673 \r
674                 case trollobj:\r
675                         if (!random(5))\r
676                                 ob->state = &s_trollouch;\r
677                         else\r
678                                 return;\r
679                 break;\r
680 \r
681                 case blobobj:\r
682                         ob->state = &s_blob_ouch;\r
683                 break;\r
684 \r
685                 case ramboneobj:\r
686                         ob->state = &s_skel_ouch;\r
687                 break;\r
688 \r
689                 case fmageobj:\r
690                         ob->state = &s_fmageouch;\r
691                 break;\r
692 \r
693                 case stompyobj:\r
694                         ob->state = &s_stompy_ouch;\r
695                 break;\r
696 \r
697                 case bugobj:\r
698                         ob->state = &s_bug_ouch;\r
699                 break;\r
700 \r
701                 case cyborgdemonobj:\r
702                         if (!(random(8)))\r
703                                 ob->state = &s_cyborg_demonouch;\r
704                         else\r
705                                 return;\r
706                 break;\r
707 \r
708                 case demonobj:\r
709                         if (!(random(8)))\r
710                                 ob->state = &s_demonouch;\r
711                         else\r
712                                 return;\r
713                 break;\r
714 \r
715                 case invisdudeobj:\r
716                         ob->state = &s_invis_fizz1;\r
717                 break;\r
718 \r
719                 case grelmobj:\r
720                         ob->state = &s_grelouch;\r
721                 break;\r
722 \r
723                 case eyeobj:\r
724                         ob->state = &s_eye_ouch;\r
725                 break;\r
726 \r
727                 case reyeobj:\r
728                         ob->state = &s_reye_ouch;\r
729                 break;\r
730                 }\r
731         }\r
732 \r
733         ob->ticcount = ob->state->tictime;\r
734 }\r
735 \r
736 \r