Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
8557 maxcodehac 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
 
24
static const dirtype opposite[9] =
25
    {west,southwest,south,southeast,east,northeast,north,northwest,nodir};
26
 
27
static 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
 
42
void    SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state);
43
void    NewState (objtype *ob, statetype *state);
44
 
45
boolean TryWalk (objtype *ob);
46
void    MoveObj (objtype *ob, int32_t move);
47
 
48
void    KillActor (objtype *ob);
49
void    DamageActor (objtype *ob, unsigned damage);
50
 
51
boolean CheckLine (objtype *ob);
52
void    FirstSighting (objtype *ob);
53
boolean 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
 
81
void 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<
95
    newobj->y = ((int32_t)tiley<
96
    newobj->dir = nodir;
97
 
98
    actorat[tilex][tiley] = newobj;
99
    newobj->areanumber =
100
        *(mapsegs[0] + (newobj->tiley<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
 
115
void 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
 
204
boolean 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<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
 
386
void 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
 
502
void 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
 
612
void 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
 
686
void 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
    }
785
moveok:
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
 
808
void 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
 
849
void 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
 
1000
void 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
 
1072
boolean 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
 
1219
boolean 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
 
1305
void 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
 
1456
boolean 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
}