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