OSDN Git Service

going on vacation >.<
[proj16/16.git] / src / lib / hb / wl_state.c
1 // WL_STATE.C\r
2 \r
3 #include "WL_DEF.H"\r
4 #pragma hdrstop\r
5 \r
6 /*\r
7 =============================================================================\r
8 \r
9                                                  LOCAL CONSTANTS\r
10 \r
11 =============================================================================\r
12 */\r
13 \r
14 \r
15 /*\r
16 =============================================================================\r
17 \r
18                                                  GLOBAL VARIABLES\r
19 \r
20 =============================================================================\r
21 */\r
22 \r
23 \r
24 dirtype opposite[9] =\r
25         {west,southwest,south,southeast,east,northeast,north,northwest,nodir};\r
26 \r
27 dirtype diagonal[9][9] =\r
28 {\r
29 /* east */      {nodir,nodir,northeast,nodir,nodir,nodir,southeast,nodir,nodir},\r
30                         {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},\r
31 /* north */ {northeast,nodir,nodir,nodir,northwest,nodir,nodir,nodir,nodir},\r
32                         {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},\r
33 /* west */  {nodir,nodir,northwest,nodir,nodir,nodir,southwest,nodir,nodir},\r
34                         {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},\r
35 /* south */ {southeast,nodir,nodir,nodir,southwest,nodir,nodir,nodir,nodir},\r
36                         {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},\r
37                         {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}\r
38 };\r
39 \r
40 \r
41 \r
42 void    SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state);\r
43 void    NewState (objtype *ob, statetype *state);\r
44 \r
45 boolean TryWalk (objtype *ob);\r
46 void    MoveObj (objtype *ob, long move);\r
47 \r
48 void    KillActor (objtype *ob);\r
49 void    DamageActor (objtype *ob, unsigned damage);\r
50 \r
51 boolean CheckLine (objtype *ob);\r
52 void FirstSighting (objtype *ob);\r
53 boolean CheckSight (objtype *ob);\r
54 \r
55 /*\r
56 =============================================================================\r
57 \r
58                                                  LOCAL VARIABLES\r
59 \r
60 =============================================================================\r
61 */\r
62 \r
63 \r
64 \r
65 //===========================================================================\r
66 \r
67 \r
68 /*\r
69 ===================\r
70 =\r
71 = SpawnNewObj\r
72 =\r
73 = Spaws a new actor at the given TILE coordinates, with the given state, and\r
74 = the given size in GLOBAL units.\r
75 =\r
76 = new                   = a pointer to an initialized new actor\r
77 =\r
78 ===================\r
79 */\r
80 \r
81 void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state)\r
82 {\r
83         GetNewActor ();\r
84         new->state = state;\r
85         if (state->tictime)\r
86                 new->ticcount = US_RndT () % state->tictime;\r
87         else\r
88                 new->ticcount = 0;\r
89 \r
90         new->tilex = tilex;\r
91         new->tiley = tiley;\r
92         new->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;\r
93         new->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;\r
94         new->dir = nodir;\r
95 \r
96         actorat[tilex][tiley] = new;\r
97         new->areanumber =\r
98                 *(mapsegs[0] + farmapylookup[new->tiley]+new->tilex) - AREATILE;\r
99 }\r
100 \r
101 \r
102 \r
103 /*\r
104 ===================\r
105 =\r
106 = NewState\r
107 =\r
108 = Changes ob to a new state, setting ticcount to the max for that state\r
109 =\r
110 ===================\r
111 */\r
112 \r
113 void NewState (objtype *ob, statetype *state)\r
114 {\r
115         ob->state = state;\r
116         ob->ticcount = state->tictime;\r
117 }\r
118 \r
119 \r
120 \r
121 /*\r
122 =============================================================================\r
123 \r
124                                 ENEMY TILE WORLD MOVEMENT CODE\r
125 \r
126 =============================================================================\r
127 */\r
128 \r
129 \r
130 /*\r
131 ==================================\r
132 =\r
133 = TryWalk\r
134 =\r
135 = Attempts to move ob in its current (ob->dir) direction.\r
136 =\r
137 = If blocked by either a wall or an actor returns FALSE\r
138 =\r
139 = If move is either clear or blocked only by a door, returns TRUE and sets\r
140 =\r
141 = ob->tilex                     = new destination\r
142 = ob->tiley\r
143 = ob->areanumber    = the floor tile number (0-(NUMAREAS-1)) of destination\r
144 = ob->distance          = TILEGLOBAl, or -doornumber if a door is blocking the way\r
145 =\r
146 = If a door is in the way, an OpenDoor call is made to start it opening.\r
147 = The actor code should wait until\r
148 =       doorobjlist[-ob->distance].action = dr_open, meaning the door has been\r
149 =       fully opened\r
150 =\r
151 ==================================\r
152 */\r
153 \r
154 #define CHECKDIAG(x,y)                                                          \\r
155 {                                                   \\r
156         temp=(unsigned)actorat[x][y];                   \\r
157         if (temp)                                       \\r
158         {                                               \\r
159                 if (temp<256)                               \\r
160                         return false;                           \\r
161                 if (((objtype *)temp)->flags&FL_SHOOTABLE)  \\r
162                         return false;                           \\r
163         }                                               \\r
164 }\r
165 \r
166 #define CHECKSIDE(x,y)                                                          \\r
167 {                                                   \\r
168         temp=(unsigned)actorat[x][y];                   \\r
169         if (temp)                                       \\r
170         {                                               \\r
171                 if (temp<128)                               \\r
172                         return false;                           \\r
173                 if (temp<256)                               \\r
174                         doornum = temp&63;                      \\r
175                 else if (((objtype *)temp)->flags&FL_SHOOTABLE)\\r
176                         return false;                           \\r
177         }                                               \\r
178 }\r
179 \r
180 \r
181 boolean TryWalk (objtype *ob)\r
182 {\r
183         int                     doornum;\r
184         unsigned        temp;\r
185 \r
186         doornum = -1;\r
187 \r
188         if (ob->obclass == inertobj)\r
189         {\r
190                 switch (ob->dir)\r
191                 {\r
192                 case north:\r
193                         ob->tiley--;\r
194                         break;\r
195 \r
196                 case northeast:\r
197                         ob->tilex++;\r
198                         ob->tiley--;\r
199                         break;\r
200 \r
201                 case east:\r
202                         ob->tilex++;\r
203                         break;\r
204 \r
205                 case southeast:\r
206                         ob->tilex++;\r
207                         ob->tiley++;\r
208                         break;\r
209 \r
210                 case south:\r
211                         ob->tiley++;\r
212                         break;\r
213 \r
214                 case southwest:\r
215                         ob->tilex--;\r
216                         ob->tiley++;\r
217                         break;\r
218 \r
219                 case west:\r
220                         ob->tilex--;\r
221                         break;\r
222 \r
223                 case northwest:\r
224                         ob->tilex--;\r
225                         ob->tiley--;\r
226                         break;\r
227                 }\r
228         }\r
229         else\r
230                 switch (ob->dir)\r
231                 {\r
232                 case north:\r
233                         if (ob->obclass == dogobj || ob->obclass == fakeobj)\r
234                         {\r
235                                 CHECKDIAG(ob->tilex,ob->tiley-1);\r
236                         }\r
237                         else\r
238                         {\r
239                                 CHECKSIDE(ob->tilex,ob->tiley-1);\r
240                         }\r
241                         ob->tiley--;\r
242                         break;\r
243 \r
244                 case northeast:\r
245                         CHECKDIAG(ob->tilex+1,ob->tiley-1);\r
246                         CHECKDIAG(ob->tilex+1,ob->tiley);\r
247                         CHECKDIAG(ob->tilex,ob->tiley-1);\r
248                         ob->tilex++;\r
249                         ob->tiley--;\r
250                         break;\r
251 \r
252                 case east:\r
253                         if (ob->obclass == dogobj || ob->obclass == fakeobj)\r
254                         {\r
255                                 CHECKDIAG(ob->tilex+1,ob->tiley);\r
256                         }\r
257                         else\r
258                         {\r
259                                 CHECKSIDE(ob->tilex+1,ob->tiley);\r
260                         }\r
261                         ob->tilex++;\r
262                         break;\r
263 \r
264                 case southeast:\r
265                         CHECKDIAG(ob->tilex+1,ob->tiley+1);\r
266                         CHECKDIAG(ob->tilex+1,ob->tiley);\r
267                         CHECKDIAG(ob->tilex,ob->tiley+1);\r
268                         ob->tilex++;\r
269                         ob->tiley++;\r
270                         break;\r
271 \r
272                 case south:\r
273                         if (ob->obclass == dogobj || ob->obclass == fakeobj)\r
274                         {\r
275                                 CHECKDIAG(ob->tilex,ob->tiley+1);\r
276                         }\r
277                         else\r
278                         {\r
279                                 CHECKSIDE(ob->tilex,ob->tiley+1);\r
280                         }\r
281                         ob->tiley++;\r
282                         break;\r
283 \r
284                 case southwest:\r
285                         CHECKDIAG(ob->tilex-1,ob->tiley+1);\r
286                         CHECKDIAG(ob->tilex-1,ob->tiley);\r
287                         CHECKDIAG(ob->tilex,ob->tiley+1);\r
288                         ob->tilex--;\r
289                         ob->tiley++;\r
290                         break;\r
291 \r
292                 case west:\r
293                         if (ob->obclass == dogobj || ob->obclass == fakeobj)\r
294                         {\r
295                                 CHECKDIAG(ob->tilex-1,ob->tiley);\r
296                         }\r
297                         else\r
298                         {\r
299                                 CHECKSIDE(ob->tilex-1,ob->tiley);\r
300                         }\r
301                         ob->tilex--;\r
302                         break;\r
303 \r
304                 case northwest:\r
305                         CHECKDIAG(ob->tilex-1,ob->tiley-1);\r
306                         CHECKDIAG(ob->tilex-1,ob->tiley);\r
307                         CHECKDIAG(ob->tilex,ob->tiley-1);\r
308                         ob->tilex--;\r
309                         ob->tiley--;\r
310                         break;\r
311 \r
312                 case nodir:\r
313                         return false;\r
314 \r
315                 default:\r
316                         Quit ("Walk: Bad dir");\r
317                 }\r
318 \r
319         if (doornum != -1)\r
320         {\r
321                 OpenDoor (doornum);\r
322                 ob->distance = -doornum-1;\r
323                 return true;\r
324         }\r
325 \r
326 \r
327         ob->areanumber =\r
328                 *(mapsegs[0] + farmapylookup[ob->tiley]+ob->tilex) - AREATILE;\r
329 \r
330         ob->distance = TILEGLOBAL;\r
331         return true;\r
332 }\r
333 \r
334 \r
335 \r
336 /*\r
337 ==================================\r
338 =\r
339 = SelectDodgeDir\r
340 =\r
341 = Attempts to choose and initiate a movement for ob that sends it towards\r
342 = the player while dodging\r
343 =\r
344 = If there is no possible move (ob is totally surrounded)\r
345 =\r
346 = ob->dir                       =       nodir\r
347 =\r
348 = Otherwise\r
349 =\r
350 = ob->dir                       = new direction to follow\r
351 = ob->distance          = TILEGLOBAL or -doornumber\r
352 = ob->tilex                     = new destination\r
353 = ob->tiley\r
354 = ob->areanumber    = the floor tile number (0-(NUMAREAS-1)) of destination\r
355 =\r
356 ==================================\r
357 */\r
358 \r
359 void SelectDodgeDir (objtype *ob)\r
360 {\r
361         int             deltax,deltay,i;\r
362         unsigned        absdx,absdy;\r
363         dirtype         dirtry[5];\r
364         dirtype         turnaround,tdir;\r
365 \r
366         if (ob->flags & FL_FIRSTATTACK)\r
367         {\r
368         //\r
369         // turning around is only ok the very first time after noticing the\r
370         // player\r
371         //\r
372                 turnaround = nodir;\r
373                 ob->flags &= ~FL_FIRSTATTACK;\r
374         }\r
375         else\r
376                 turnaround=opposite[ob->dir];\r
377 \r
378         deltax = player->tilex - ob->tilex;\r
379         deltay = player->tiley - ob->tiley;\r
380 \r
381 //\r
382 // arange 5 direction choices in order of preference\r
383 // the four cardinal directions plus the diagonal straight towards\r
384 // the player\r
385 //\r
386 \r
387         if (deltax>0)\r
388         {\r
389                 dirtry[1]= east;\r
390                 dirtry[3]= west;\r
391         }\r
392         else\r
393         {\r
394                 dirtry[1]= west;\r
395                 dirtry[3]= east;\r
396         }\r
397 \r
398         if (deltay>0)\r
399         {\r
400                 dirtry[2]= south;\r
401                 dirtry[4]= north;\r
402         }\r
403         else\r
404         {\r
405                 dirtry[2]= north;\r
406                 dirtry[4]= south;\r
407         }\r
408 \r
409 //\r
410 // randomize a bit for dodging\r
411 //\r
412         absdx = abs(deltax);\r
413         absdy = abs(deltay);\r
414 \r
415         if (absdx > absdy)\r
416         {\r
417                 tdir = dirtry[1];\r
418                 dirtry[1] = dirtry[2];\r
419                 dirtry[2] = tdir;\r
420                 tdir = dirtry[3];\r
421                 dirtry[3] = dirtry[4];\r
422                 dirtry[4] = tdir;\r
423         }\r
424 \r
425         if (US_RndT() < 128)\r
426         {\r
427                 tdir = dirtry[1];\r
428                 dirtry[1] = dirtry[2];\r
429                 dirtry[2] = tdir;\r
430                 tdir = dirtry[3];\r
431                 dirtry[3] = dirtry[4];\r
432                 dirtry[4] = tdir;\r
433         }\r
434 \r
435         dirtry[0] = diagonal [ dirtry[1] ] [ dirtry[2] ];\r
436 \r
437 //\r
438 // try the directions util one works\r
439 //\r
440         for (i=0;i<5;i++)\r
441         {\r
442                 if ( dirtry[i] == nodir || dirtry[i] == turnaround)\r
443                         continue;\r
444 \r
445                 ob->dir = dirtry[i];\r
446                 if (TryWalk(ob))\r
447                         return;\r
448         }\r
449 \r
450 //\r
451 // turn around only as a last resort\r
452 //\r
453         if (turnaround != nodir)\r
454         {\r
455                 ob->dir = turnaround;\r
456 \r
457                 if (TryWalk(ob))\r
458                         return;\r
459         }\r
460 \r
461         ob->dir = nodir;\r
462 }\r
463 \r
464 \r
465 /*\r
466 ============================\r
467 =\r
468 = SelectChaseDir\r
469 =\r
470 = As SelectDodgeDir, but doesn't try to dodge\r
471 =\r
472 ============================\r
473 */\r
474 \r
475 void SelectChaseDir (objtype *ob)\r
476 {\r
477         int deltax,deltay,i;\r
478         dirtype d[3];\r
479         dirtype tdir, olddir, turnaround;\r
480 \r
481 \r
482         olddir=ob->dir;\r
483         turnaround=opposite[olddir];\r
484 \r
485         deltax=player->tilex - ob->tilex;\r
486         deltay=player->tiley - ob->tiley;\r
487 \r
488         d[1]=nodir;\r
489         d[2]=nodir;\r
490 \r
491         if (deltax>0)\r
492                 d[1]= east;\r
493         else if (deltax<0)\r
494                 d[1]= west;\r
495         if (deltay>0)\r
496                 d[2]=south;\r
497         else if (deltay<0)\r
498                 d[2]=north;\r
499 \r
500         if (abs(deltay)>abs(deltax))\r
501         {\r
502                 tdir=d[1];\r
503                 d[1]=d[2];\r
504                 d[2]=tdir;\r
505         }\r
506 \r
507         if (d[1]==turnaround)\r
508                 d[1]=nodir;\r
509         if (d[2]==turnaround)\r
510                 d[2]=nodir;\r
511 \r
512 \r
513         if (d[1]!=nodir)\r
514         {\r
515                 ob->dir=d[1];\r
516                 if (TryWalk(ob))\r
517                         return;     /*either moved forward or attacked*/\r
518         }\r
519 \r
520         if (d[2]!=nodir)\r
521         {\r
522                 ob->dir=d[2];\r
523                 if (TryWalk(ob))\r
524                         return;\r
525         }\r
526 \r
527 /* there is no direct path to the player, so pick another direction */\r
528 \r
529         if (olddir!=nodir)\r
530         {\r
531                 ob->dir=olddir;\r
532                 if (TryWalk(ob))\r
533                         return;\r
534         }\r
535 \r
536         if (US_RndT()>128)      /*randomly determine direction of search*/\r
537         {\r
538                 for (tdir=north;tdir<=west;tdir++)\r
539                 {\r
540                         if (tdir!=turnaround)\r
541                         {\r
542                                 ob->dir=tdir;\r
543                                 if ( TryWalk(ob) )\r
544                                         return;\r
545                         }\r
546                 }\r
547         }\r
548         else\r
549         {\r
550                 for (tdir=west;tdir>=north;tdir--)\r
551                 {\r
552                         if (tdir!=turnaround)\r
553                         {\r
554                           ob->dir=tdir;\r
555                           if ( TryWalk(ob) )\r
556                                 return;\r
557                         }\r
558                 }\r
559         }\r
560 \r
561         if (turnaround !=  nodir)\r
562         {\r
563                 ob->dir=turnaround;\r
564                 if (ob->dir != nodir)\r
565                 {\r
566                         if ( TryWalk(ob) )\r
567                                 return;\r
568                 }\r
569         }\r
570 \r
571         ob->dir = nodir;                // can't move\r
572 }\r
573 \r
574 \r
575 /*\r
576 ============================\r
577 =\r
578 = SelectRunDir\r
579 =\r
580 = Run Away from player\r
581 =\r
582 ============================\r
583 */\r
584 \r
585 void SelectRunDir (objtype *ob)\r
586 {\r
587         int deltax,deltay,i;\r
588         dirtype d[3];\r
589         dirtype tdir, olddir, turnaround;\r
590 \r
591 \r
592         deltax=player->tilex - ob->tilex;\r
593         deltay=player->tiley - ob->tiley;\r
594 \r
595         if (deltax<0)\r
596                 d[1]= east;\r
597         else\r
598                 d[1]= west;\r
599         if (deltay<0)\r
600                 d[2]=south;\r
601         else\r
602                 d[2]=north;\r
603 \r
604         if (abs(deltay)>abs(deltax))\r
605         {\r
606                 tdir=d[1];\r
607                 d[1]=d[2];\r
608                 d[2]=tdir;\r
609         }\r
610 \r
611         ob->dir=d[1];\r
612         if (TryWalk(ob))\r
613                 return;     /*either moved forward or attacked*/\r
614 \r
615         ob->dir=d[2];\r
616         if (TryWalk(ob))\r
617                 return;\r
618 \r
619 /* there is no direct path to the player, so pick another direction */\r
620 \r
621         if (US_RndT()>128)      /*randomly determine direction of search*/\r
622         {\r
623                 for (tdir=north;tdir<=west;tdir++)\r
624                 {\r
625                         ob->dir=tdir;\r
626                         if ( TryWalk(ob) )\r
627                                 return;\r
628                 }\r
629         }\r
630         else\r
631         {\r
632                 for (tdir=west;tdir>=north;tdir--)\r
633                 {\r
634                         ob->dir=tdir;\r
635                         if ( TryWalk(ob) )\r
636                           return;\r
637                 }\r
638         }\r
639 \r
640         ob->dir = nodir;                // can't move\r
641 }\r
642 \r
643 \r
644 /*\r
645 =================\r
646 =\r
647 = MoveObj\r
648 =\r
649 = Moves ob be move global units in ob->dir direction\r
650 = Actors are not allowed to move inside the player\r
651 = Does NOT check to see if the move is tile map valid\r
652 =\r
653 = ob->x                 = adjusted for new position\r
654 = ob->y\r
655 =\r
656 =================\r
657 */\r
658 \r
659 void MoveObj (objtype *ob, long move)\r
660 {\r
661         long    deltax,deltay;\r
662 \r
663         switch (ob->dir)\r
664         {\r
665         case north:\r
666                 ob->y -= move;\r
667                 break;\r
668         case northeast:\r
669                 ob->x += move;\r
670                 ob->y -= move;\r
671                 break;\r
672         case east:\r
673                 ob->x += move;\r
674                 break;\r
675         case southeast:\r
676                 ob->x += move;\r
677                 ob->y += move;\r
678                 break;\r
679         case south:\r
680                 ob->y += move;\r
681                 break;\r
682         case southwest:\r
683                 ob->x -= move;\r
684                 ob->y += move;\r
685                 break;\r
686         case west:\r
687                 ob->x -= move;\r
688                 break;\r
689         case northwest:\r
690                 ob->x -= move;\r
691                 ob->y -= move;\r
692                 break;\r
693 \r
694         case nodir:\r
695                 return;\r
696 \r
697         default:\r
698                 Quit ("MoveObj: bad dir!");\r
699         }\r
700 \r
701 //\r
702 // check to make sure it's not on top of player\r
703 //\r
704         if (areabyplayer[ob->areanumber])\r
705         {\r
706                 deltax = ob->x - player->x;\r
707                 if (deltax < -MINACTORDIST || deltax > MINACTORDIST)\r
708                         goto moveok;\r
709                 deltay = ob->y - player->y;\r
710                 if (deltay < -MINACTORDIST || deltay > MINACTORDIST)\r
711                         goto moveok;\r
712 \r
713                 if (ob->obclass == ghostobj || ob->obclass == spectreobj)\r
714                         TakeDamage (tics*2,ob);\r
715 \r
716         //\r
717         // back up\r
718         //\r
719                 switch (ob->dir)\r
720                 {\r
721                 case north:\r
722                         ob->y += move;\r
723                         break;\r
724                 case northeast:\r
725                         ob->x -= move;\r
726                         ob->y += move;\r
727                         break;\r
728                 case east:\r
729                         ob->x -= move;\r
730                         break;\r
731                 case southeast:\r
732                         ob->x -= move;\r
733                         ob->y -= move;\r
734                         break;\r
735                 case south:\r
736                         ob->y -= move;\r
737                         break;\r
738                 case southwest:\r
739                         ob->x += move;\r
740                         ob->y -= move;\r
741                         break;\r
742                 case west:\r
743                         ob->x += move;\r
744                         break;\r
745                 case northwest:\r
746                         ob->x += move;\r
747                         ob->y += move;\r
748                         break;\r
749 \r
750                 case nodir:\r
751                         return;\r
752                 }\r
753                 return;\r
754         }\r
755 moveok:\r
756         ob->distance -=move;\r
757 }\r
758 \r
759 /*\r
760 =============================================================================\r
761 \r
762                                                         STUFF\r
763 \r
764 =============================================================================\r
765 */\r
766 \r
767 /*\r
768 ===============\r
769 =\r
770 = DropItem\r
771 =\r
772 = Tries to drop a bonus item somewhere in the tiles surrounding the\r
773 = given tilex/tiley\r
774 =\r
775 ===============\r
776 */\r
777 \r
778 void DropItem (stat_t itemtype, int tilex, int tiley)\r
779 {\r
780         int     x,y,xl,xh,yl,yh;\r
781 \r
782 //\r
783 // find a free spot to put it in\r
784 //\r
785         if (!actorat[tilex][tiley])\r
786         {\r
787                 PlaceItemType (itemtype, tilex,tiley);\r
788                 return;\r
789         }\r
790 \r
791         xl = tilex-1;\r
792         xh = tilex+1;\r
793         yl = tiley-1;\r
794         yh = tiley+1;\r
795 \r
796         for (x=xl ; x<= xh ; x++)\r
797                 for (y=yl ; y<= yh ; y++)\r
798                         if (!actorat[x][y])\r
799                         {\r
800                                 PlaceItemType (itemtype, x,y);\r
801                                 return;\r
802                         }\r
803 }\r
804 \r
805 \r
806 \r
807 /*\r
808 ===============\r
809 =\r
810 = KillActor\r
811 =\r
812 ===============\r
813 */\r
814 \r
815 void KillActor (objtype *ob)\r
816 {\r
817         int     tilex,tiley;\r
818 \r
819         tilex = ob->tilex = ob->x >> TILESHIFT;         // drop item on center\r
820         tiley = ob->tiley = ob->y >> TILESHIFT;\r
821 \r
822         switch (ob->obclass)\r
823         {\r
824         case guardobj:\r
825                 GivePoints (100);\r
826                 NewState (ob,&s_grddie1);\r
827                 PlaceItemType (bo_clip2,tilex,tiley);\r
828                 break;\r
829 \r
830         case officerobj:\r
831                 GivePoints (400);\r
832                 NewState (ob,&s_ofcdie1);\r
833                 PlaceItemType (bo_clip2,tilex,tiley);\r
834                 break;\r
835 \r
836         case mutantobj:\r
837                 GivePoints (700);\r
838                 NewState (ob,&s_mutdie1);\r
839                 PlaceItemType (bo_clip2,tilex,tiley);\r
840                 break;\r
841 \r
842         case ssobj:\r
843                 GivePoints (500);\r
844                 NewState (ob,&s_ssdie1);\r
845                 if (gamestate.bestweapon < wp_machinegun)\r
846                         PlaceItemType (bo_machinegun,tilex,tiley);\r
847                 else\r
848                         PlaceItemType (bo_clip2,tilex,tiley);\r
849                 break;\r
850 \r
851         case dogobj:\r
852                 GivePoints (200);\r
853                 NewState (ob,&s_dogdie1);\r
854                 break;\r
855 \r
856 #ifndef SPEAR\r
857         case bossobj:\r
858                 GivePoints (5000);\r
859                 NewState (ob,&s_bossdie1);\r
860                 PlaceItemType (bo_key1,tilex,tiley);\r
861                 break;\r
862 \r
863         case gretelobj:\r
864                 GivePoints (5000);\r
865                 NewState (ob,&s_greteldie1);\r
866                 PlaceItemType (bo_key1,tilex,tiley);\r
867                 break;\r
868 \r
869         case giftobj:\r
870                 GivePoints (5000);\r
871                 gamestate.killx = player->x;\r
872                 gamestate.killy = player->y;\r
873                 NewState (ob,&s_giftdie1);\r
874                 break;\r
875 \r
876         case fatobj:\r
877                 GivePoints (5000);\r
878                 gamestate.killx = player->x;\r
879                 gamestate.killy = player->y;\r
880                 NewState (ob,&s_fatdie1);\r
881                 break;\r
882 \r
883         case schabbobj:\r
884                 GivePoints (5000);\r
885                 gamestate.killx = player->x;\r
886                 gamestate.killy = player->y;\r
887                 NewState (ob,&s_schabbdie1);\r
888                 A_DeathScream(ob);\r
889                 break;\r
890         case fakeobj:\r
891                 GivePoints (2000);\r
892                 NewState (ob,&s_fakedie1);\r
893                 break;\r
894 \r
895         case mechahitlerobj:\r
896                 GivePoints (5000);\r
897                 NewState (ob,&s_mechadie1);\r
898                 break;\r
899         case realhitlerobj:\r
900                 GivePoints (5000);\r
901                 gamestate.killx = player->x;\r
902                 gamestate.killy = player->y;\r
903                 NewState (ob,&s_hitlerdie1);\r
904                 A_DeathScream(ob);\r
905                 break;\r
906 #else\r
907         case spectreobj:\r
908                 GivePoints (200);\r
909                 NewState (ob,&s_spectredie1);\r
910                 break;\r
911 \r
912         case angelobj:\r
913                 GivePoints (5000);\r
914                 NewState (ob,&s_angeldie1);\r
915                 break;\r
916 \r
917         case transobj:\r
918                 GivePoints (5000);\r
919                 NewState (ob,&s_transdie0);\r
920                 PlaceItemType (bo_key1,tilex,tiley);\r
921                 break;\r
922 \r
923         case uberobj:\r
924                 GivePoints (5000);\r
925                 NewState (ob,&s_uberdie0);\r
926                 PlaceItemType (bo_key1,tilex,tiley);\r
927                 break;\r
928 \r
929         case willobj:\r
930                 GivePoints (5000);\r
931                 NewState (ob,&s_willdie1);\r
932                 PlaceItemType (bo_key1,tilex,tiley);\r
933                 break;\r
934 \r
935         case deathobj:\r
936                 GivePoints (5000);\r
937                 NewState (ob,&s_deathdie1);\r
938                 PlaceItemType (bo_key1,tilex,tiley);\r
939                 break;\r
940 #endif\r
941         }\r
942 \r
943         gamestate.killcount++;\r
944         ob->flags &= ~FL_SHOOTABLE;\r
945         actorat[ob->tilex][ob->tiley] = NULL;\r
946         ob->flags |= FL_NONMARK;\r
947 }\r
948 \r
949 \r
950 \r
951 /*\r
952 ===================\r
953 =\r
954 = DamageActor\r
955 =\r
956 = Called when the player succesfully hits an enemy.\r
957 =\r
958 = Does damage points to enemy ob, either putting it into a stun frame or\r
959 = killing it.\r
960 =\r
961 ===================\r
962 */\r
963 \r
964 void DamageActor (objtype *ob, unsigned damage)\r
965 {\r
966         madenoise = true;\r
967 \r
968 //\r
969 // do double damage if shooting a non attack mode actor\r
970 //\r
971         if ( !(ob->flags & FL_ATTACKMODE) )\r
972                 damage <<= 1;\r
973 \r
974         ob->hitpoints -= damage;\r
975 \r
976         if (ob->hitpoints<=0)\r
977                 KillActor (ob);\r
978         else\r
979         {\r
980                 if (! (ob->flags & FL_ATTACKMODE) )\r
981                         FirstSighting (ob);             // put into combat mode\r
982 \r
983                 switch (ob->obclass)            // dogs only have one hit point\r
984                 {\r
985                 case guardobj:\r
986                         if (ob->hitpoints&1)\r
987                                 NewState (ob,&s_grdpain);\r
988                         else\r
989                                 NewState (ob,&s_grdpain1);\r
990                         break;\r
991 \r
992                 case officerobj:\r
993                         if (ob->hitpoints&1)\r
994                                 NewState (ob,&s_ofcpain);\r
995                         else\r
996                                 NewState (ob,&s_ofcpain1);\r
997                         break;\r
998 \r
999                 case mutantobj:\r
1000                         if (ob->hitpoints&1)\r
1001                                 NewState (ob,&s_mutpain);\r
1002                         else\r
1003                                 NewState (ob,&s_mutpain1);\r
1004                         break;\r
1005 \r
1006                 case ssobj:\r
1007                         if (ob->hitpoints&1)\r
1008                                 NewState (ob,&s_sspain);\r
1009                         else\r
1010                                 NewState (ob,&s_sspain1);\r
1011 \r
1012                         break;\r
1013 \r
1014                 }\r
1015         }\r
1016 }\r
1017 \r
1018 /*\r
1019 =============================================================================\r
1020 \r
1021                                                         CHECKSIGHT\r
1022 \r
1023 =============================================================================\r
1024 */\r
1025 \r
1026 \r
1027 /*\r
1028 =====================\r
1029 =\r
1030 = CheckLine\r
1031 =\r
1032 = Returns true if a straight line between the player and ob is unobstructed\r
1033 =\r
1034 =====================\r
1035 */\r
1036 \r
1037 boolean CheckLine (objtype *ob)\r
1038 {\r
1039         int     x1,y1,xt1,yt1,x2,y2,xt2,yt2;\r
1040         int     x,y;\r
1041         int     xdist,ydist,xstep,ystep;\r
1042         int     temp;\r
1043         int     partial,delta;\r
1044         long    ltemp;\r
1045         int     xfrac,yfrac,deltafrac;\r
1046         unsigned        value,intercept;\r
1047 \r
1048         x1 = ob->x >> UNSIGNEDSHIFT;            // 1/256 tile precision\r
1049         y1 = ob->y >> UNSIGNEDSHIFT;\r
1050         xt1 = x1 >> 8;\r
1051         yt1 = y1 >> 8;\r
1052 \r
1053         x2 = plux;\r
1054         y2 = pluy;\r
1055         xt2 = player->tilex;\r
1056         yt2 = player->tiley;\r
1057 \r
1058 \r
1059         xdist = abs(xt2-xt1);\r
1060 \r
1061         if (xdist > 0)\r
1062         {\r
1063                 if (xt2 > xt1)\r
1064                 {\r
1065                         partial = 256-(x1&0xff);\r
1066                         xstep = 1;\r
1067                 }\r
1068                 else\r
1069                 {\r
1070                         partial = x1&0xff;\r
1071                         xstep = -1;\r
1072                 }\r
1073 \r
1074                 deltafrac = abs(x2-x1);\r
1075                 delta = y2-y1;\r
1076                 ltemp = ((long)delta<<8)/deltafrac;\r
1077                 if (ltemp > 0x7fffl)\r
1078                         ystep = 0x7fff;\r
1079                 else if (ltemp < -0x7fffl)\r
1080                         ystep = -0x7fff;\r
1081                 else\r
1082                         ystep = ltemp;\r
1083                 yfrac = y1 + (((long)ystep*partial) >>8);\r
1084 \r
1085                 x = xt1+xstep;\r
1086                 xt2 += xstep;\r
1087                 do\r
1088                 {\r
1089                         y = yfrac>>8;\r
1090                         yfrac += ystep;\r
1091 \r
1092                         value = (unsigned)tilemap[x][y];\r
1093                         x += xstep;\r
1094 \r
1095                         if (!value)\r
1096                                 continue;\r
1097 \r
1098                         if (value<128 || value>256)\r
1099                                 return false;\r
1100 \r
1101                         //\r
1102                         // see if the door is open enough\r
1103                         //\r
1104                         value &= ~0x80;\r
1105                         intercept = yfrac-ystep/2;\r
1106 \r
1107                         if (intercept>doorposition[value])\r
1108                                 return false;\r
1109 \r
1110                 } while (x != xt2);\r
1111         }\r
1112 \r
1113         ydist = abs(yt2-yt1);\r
1114 \r
1115         if (ydist > 0)\r
1116         {\r
1117                 if (yt2 > yt1)\r
1118                 {\r
1119                         partial = 256-(y1&0xff);\r
1120                         ystep = 1;\r
1121                 }\r
1122                 else\r
1123                 {\r
1124                         partial = y1&0xff;\r
1125                         ystep = -1;\r
1126                 }\r
1127 \r
1128                 deltafrac = abs(y2-y1);\r
1129                 delta = x2-x1;\r
1130                 ltemp = ((long)delta<<8)/deltafrac;\r
1131                 if (ltemp > 0x7fffl)\r
1132                         xstep = 0x7fff;\r
1133                 else if (ltemp < -0x7fffl)\r
1134                         xstep = -0x7fff;\r
1135                 else\r
1136                         xstep = ltemp;\r
1137                 xfrac = x1 + (((long)xstep*partial) >>8);\r
1138 \r
1139                 y = yt1 + ystep;\r
1140                 yt2 += ystep;\r
1141                 do\r
1142                 {\r
1143                         x = xfrac>>8;\r
1144                         xfrac += xstep;\r
1145 \r
1146                         value = (unsigned)tilemap[x][y];\r
1147                         y += ystep;\r
1148 \r
1149                         if (!value)\r
1150                                 continue;\r
1151 \r
1152                         if (value<128 || value>256)\r
1153                                 return false;\r
1154 \r
1155                         //\r
1156                         // see if the door is open enough\r
1157                         //\r
1158                         value &= ~0x80;\r
1159                         intercept = xfrac-xstep/2;\r
1160 \r
1161                         if (intercept>doorposition[value])\r
1162                                 return false;\r
1163                 } while (y != yt2);\r
1164         }\r
1165 \r
1166         return true;\r
1167 }\r
1168 \r
1169 \r
1170 \r
1171 /*\r
1172 ================\r
1173 =\r
1174 = CheckSight\r
1175 =\r
1176 = Checks a straight line between player and current object\r
1177 =\r
1178 = If the sight is ok, check alertness and angle to see if they notice\r
1179 =\r
1180 = returns true if the player has been spoted\r
1181 =\r
1182 ================\r
1183 */\r
1184 \r
1185 #define MINSIGHT        0x18000l\r
1186 \r
1187 boolean CheckSight (objtype *ob)\r
1188 {\r
1189         long            deltax,deltay;\r
1190 \r
1191 //\r
1192 // don't bother tracing a line if the area isn't connected to the player's\r
1193 //\r
1194         if (!areabyplayer[ob->areanumber])\r
1195                 return false;\r
1196 \r
1197 //\r
1198 // if the player is real close, sight is automatic\r
1199 //\r
1200         deltax = player->x - ob->x;\r
1201         deltay = player->y - ob->y;\r
1202 \r
1203         if (deltax > -MINSIGHT && deltax < MINSIGHT\r
1204         && deltay > -MINSIGHT && deltay < MINSIGHT)\r
1205                 return true;\r
1206 \r
1207 //\r
1208 // see if they are looking in the right direction\r
1209 //\r
1210         switch (ob->dir)\r
1211         {\r
1212         case north:\r
1213                 if (deltay > 0)\r
1214                         return false;\r
1215                 break;\r
1216 \r
1217         case east:\r
1218                 if (deltax < 0)\r
1219                         return false;\r
1220                 break;\r
1221 \r
1222         case south:\r
1223                 if (deltay < 0)\r
1224                         return false;\r
1225                 break;\r
1226 \r
1227         case west:\r
1228                 if (deltax > 0)\r
1229                         return false;\r
1230                 break;\r
1231         }\r
1232 \r
1233 //\r
1234 // trace a line to check for blocking tiles (corners)\r
1235 //\r
1236         return CheckLine (ob);\r
1237 \r
1238 }\r
1239 \r
1240 \r
1241 \r
1242 /*\r
1243 ===============\r
1244 =\r
1245 = FirstSighting\r
1246 =\r
1247 = Puts an actor into attack mode and possibly reverses the direction\r
1248 = if the player is behind it\r
1249 =\r
1250 ===============\r
1251 */\r
1252 \r
1253 void FirstSighting (objtype *ob)\r
1254 {\r
1255 //\r
1256 // react to the player\r
1257 //\r
1258         switch (ob->obclass)\r
1259         {\r
1260         case guardobj:\r
1261                 PlaySoundLocActor(HALTSND,ob);\r
1262                 NewState (ob,&s_grdchase1);\r
1263                 ob->speed *= 3;                 // go faster when chasing player\r
1264                 break;\r
1265 \r
1266         case officerobj:\r
1267                 PlaySoundLocActor(SPIONSND,ob);\r
1268                 NewState (ob,&s_ofcchase1);\r
1269                 ob->speed *= 5;                 // go faster when chasing player\r
1270                 break;\r
1271 \r
1272         case mutantobj:\r
1273                 NewState (ob,&s_mutchase1);\r
1274                 ob->speed *= 3;                 // go faster when chasing player\r
1275                 break;\r
1276 \r
1277         case ssobj:\r
1278                 PlaySoundLocActor(SCHUTZADSND,ob);\r
1279                 NewState (ob,&s_sschase1);\r
1280                 ob->speed *= 4;                 // go faster when chasing player\r
1281                 break;\r
1282 \r
1283         case dogobj:\r
1284                 PlaySoundLocActor(DOGBARKSND,ob);\r
1285                 NewState (ob,&s_dogchase1);\r
1286                 ob->speed *= 2;                 // go faster when chasing player\r
1287                 break;\r
1288 \r
1289 #ifndef SPEAR\r
1290         case bossobj:\r
1291                 SD_PlaySound(GUTENTAGSND);\r
1292                 NewState (ob,&s_bosschase1);\r
1293                 ob->speed = SPDPATROL*3;        // go faster when chasing player\r
1294                 break;\r
1295 \r
1296         case gretelobj:\r
1297                 SD_PlaySound(KEINSND);\r
1298                 NewState (ob,&s_gretelchase1);\r
1299                 ob->speed *= 3;                 // go faster when chasing player\r
1300                 break;\r
1301 \r
1302         case giftobj:\r
1303                 SD_PlaySound(EINESND);\r
1304                 NewState (ob,&s_giftchase1);\r
1305                 ob->speed *= 3;                 // go faster when chasing player\r
1306                 break;\r
1307 \r
1308         case fatobj:\r
1309                 SD_PlaySound(ERLAUBENSND);\r
1310                 NewState (ob,&s_fatchase1);\r
1311                 ob->speed *= 3;                 // go faster when chasing player\r
1312                 break;\r
1313 \r
1314         case schabbobj:\r
1315                 SD_PlaySound(SCHABBSHASND);\r
1316                 NewState (ob,&s_schabbchase1);\r
1317                 ob->speed *= 3;                 // go faster when chasing player\r
1318                 break;\r
1319 \r
1320         case fakeobj:\r
1321                 SD_PlaySound(TOT_HUNDSND);\r
1322                 NewState (ob,&s_fakechase1);\r
1323                 ob->speed *= 3;                 // go faster when chasing player\r
1324                 break;\r
1325 \r
1326         case mechahitlerobj:\r
1327                 SD_PlaySound(DIESND);\r
1328                 NewState (ob,&s_mechachase1);\r
1329                 ob->speed *= 3;                 // go faster when chasing player\r
1330                 break;\r
1331 \r
1332         case realhitlerobj:\r
1333                 SD_PlaySound(DIESND);\r
1334                 NewState (ob,&s_hitlerchase1);\r
1335                 ob->speed *= 5;                 // go faster when chasing player\r
1336                 break;\r
1337 \r
1338         case ghostobj:\r
1339                 NewState (ob,&s_blinkychase1);\r
1340                 ob->speed *= 2;                 // go faster when chasing player\r
1341                 break;\r
1342 #else\r
1343 \r
1344         case spectreobj:\r
1345                 SD_PlaySound(GHOSTSIGHTSND);\r
1346                 NewState (ob,&s_spectrechase1);\r
1347                 ob->speed = 800;                        // go faster when chasing player\r
1348                 break;\r
1349 \r
1350         case angelobj:\r
1351                 SD_PlaySound(ANGELSIGHTSND);\r
1352                 NewState (ob,&s_angelchase1);\r
1353                 ob->speed = 1536;                       // go faster when chasing player\r
1354                 break;\r
1355 \r
1356         case transobj:\r
1357                 SD_PlaySound(TRANSSIGHTSND);\r
1358                 NewState (ob,&s_transchase1);\r
1359                 ob->speed = 1536;                       // go faster when chasing player\r
1360                 break;\r
1361 \r
1362         case uberobj:\r
1363                 NewState (ob,&s_uberchase1);\r
1364                 ob->speed = 3000;                       // go faster when chasing player\r
1365                 break;\r
1366 \r
1367         case willobj:\r
1368                 SD_PlaySound(WILHELMSIGHTSND);\r
1369                 NewState (ob,&s_willchase1);\r
1370                 ob->speed = 2048;                       // go faster when chasing player\r
1371                 break;\r
1372 \r
1373         case deathobj:\r
1374                 SD_PlaySound(KNIGHTSIGHTSND);\r
1375                 NewState (ob,&s_deathchase1);\r
1376                 ob->speed = 2048;                       // go faster when chasing player\r
1377                 break;\r
1378 \r
1379 #endif\r
1380         }\r
1381 \r
1382         if (ob->distance < 0)\r
1383                 ob->distance = 0;       // ignore the door opening command\r
1384 \r
1385         ob->flags |= FL_ATTACKMODE|FL_FIRSTATTACK;\r
1386 }\r
1387 \r
1388 \r
1389 \r
1390 /*\r
1391 ===============\r
1392 =\r
1393 = SightPlayer\r
1394 =\r
1395 = Called by actors that ARE NOT chasing the player.  If the player\r
1396 = is detected (by sight, noise, or proximity), the actor is put into\r
1397 = it's combat frame and true is returned.\r
1398 =\r
1399 = Incorporates a random reaction delay\r
1400 =\r
1401 ===============\r
1402 */\r
1403 \r
1404 boolean SightPlayer (objtype *ob)\r
1405 {\r
1406         if (ob->flags & FL_ATTACKMODE)\r
1407                 Quit ("An actor in ATTACKMODE called SightPlayer!");\r
1408 \r
1409         if (ob->temp2)\r
1410         {\r
1411         //\r
1412         // count down reaction time\r
1413         //\r
1414                 ob->temp2 -= tics;\r
1415                 if (ob->temp2 > 0)\r
1416                         return false;\r
1417                 ob->temp2 = 0;                                  // time to react\r
1418         }\r
1419         else\r
1420         {\r
1421                 if (!areabyplayer[ob->areanumber])\r
1422                         return false;\r
1423 \r
1424                 if (ob->flags & FL_AMBUSH)\r
1425                 {\r
1426                         if (!CheckSight (ob))\r
1427                                 return false;\r
1428                         ob->flags &= ~FL_AMBUSH;\r
1429                 }\r
1430                 else\r
1431                 {\r
1432                         if (!madenoise && !CheckSight (ob))\r
1433                                 return false;\r
1434                 }\r
1435 \r
1436 \r
1437                 switch (ob->obclass)\r
1438                 {\r
1439                 case guardobj:\r
1440                         ob->temp2 = 1+US_RndT()/4;\r
1441                         break;\r
1442                 case officerobj:\r
1443                         ob->temp2 = 2;\r
1444                         break;\r
1445                 case mutantobj:\r
1446                         ob->temp2 = 1+US_RndT()/6;\r
1447                         break;\r
1448                 case ssobj:\r
1449                         ob->temp2 = 1+US_RndT()/6;\r
1450                         break;\r
1451                 case dogobj:\r
1452                         ob->temp2 = 1+US_RndT()/8;\r
1453                         break;\r
1454 \r
1455                 case bossobj:\r
1456                 case schabbobj:\r
1457                 case fakeobj:\r
1458                 case mechahitlerobj:\r
1459                 case realhitlerobj:\r
1460                 case gretelobj:\r
1461                 case giftobj:\r
1462                 case fatobj:\r
1463                 case spectreobj:\r
1464                 case angelobj:\r
1465                 case transobj:\r
1466                 case uberobj:\r
1467                 case willobj:\r
1468                 case deathobj:\r
1469                         ob->temp2 = 1;\r
1470                         break;\r
1471                 }\r
1472                 return false;\r
1473         }\r
1474 \r
1475         FirstSighting (ob);\r
1476 \r
1477         return true;\r
1478 }\r
1479 \r
1480 \r