Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
8557 maxcodehac 1
// WL_AGENT.C
2
 
3
#include "wl_def.h"
4
#pragma hdrstop
5
 
6
/*
7
=============================================================================
8
 
9
                                LOCAL CONSTANTS
10
 
11
=============================================================================
12
*/
13
 
14
#define MAXMOUSETURN    10
15
 
16
 
17
#define MOVESCALE       150l
18
#define BACKMOVESCALE   100l
19
#define ANGLESCALE      20
20
 
21
/*
22
=============================================================================
23
 
24
                                GLOBAL VARIABLES
25
 
26
=============================================================================
27
*/
28
 
29
 
30
 
31
//
32
// player state info
33
//
34
int32_t         thrustspeed;
35
 
36
word            plux,pluy;          // player coordinates scaled to unsigned
37
 
38
short           anglefrac;
39
 
40
objtype        *LastAttacker;
41
 
42
/*
43
=============================================================================
44
 
45
                                                 LOCAL VARIABLES
46
 
47
=============================================================================
48
*/
49
 
50
 
51
void    T_Player (objtype *ob);
52
void    T_Attack (objtype *ob);
53
 
54
statetype   s_player = {false,0,0,(statefunc) T_Player,NULL,NULL};
55
statetype   s_attack = {false,0,0,(statefunc) T_Attack,NULL,NULL};
56
 
57
struct atkinf
58
{
59
    int8_t    tics,attack,frame;              // attack is 1 for gun, 2 for knife
60
} attackinfo[4][14] =
61
{
62
    { {6,0,1},{6,2,2},{6,0,3},{6,-1,4} },
63
    { {6,0,1},{6,1,2},{6,0,3},{6,-1,4} },
64
    { {6,0,1},{6,1,2},{6,3,3},{6,-1,4} },
65
    { {6,0,1},{6,1,2},{6,4,3},{6,-1,4} },
66
};
67
 
68
//===========================================================================
69
 
70
//----------
71
 
72
void Attack (void);
73
void Use (void);
74
void Search (objtype *ob);
75
void SelectWeapon (void);
76
void SelectItem (void);
77
 
78
//----------
79
 
80
boolean TryMove (objtype *ob);
81
void T_Player (objtype *ob);
82
 
83
void ClipMove (objtype *ob, int32_t xmove, int32_t ymove);
84
 
85
/*
86
=============================================================================
87
 
88
                                CONTROL STUFF
89
 
90
=============================================================================
91
*/
92
 
93
/*
94
======================
95
=
96
= CheckWeaponChange
97
=
98
= Keys 1-4 change weapons
99
=
100
======================
101
*/
102
 
103
void CheckWeaponChange (void)
104
{
105
    int newWeapon = -1;
106
 
107
    if (!gamestate.ammo)            // must use knife with no ammo
108
        return;
109
 
110
#ifdef _arch_dreamcast
111
    int joyx, joyy;
112
    IN_GetJoyFineDelta (&joyx, &joyy);
113
    if(joyx < -64)
114
        buttonstate[bt_prevweapon] = true;
115
    else if(joyx > 64)
116
        buttonstate[bt_nextweapon] = true;
117
#endif
118
 
119
    if(buttonstate[bt_nextweapon] && !buttonheld[bt_nextweapon])
120
    {
121
        newWeapon = gamestate.weapon + 1;
122
        if(newWeapon > gamestate.bestweapon) newWeapon = 0;
123
    }
124
    else if(buttonstate[bt_prevweapon] && !buttonheld[bt_prevweapon])
125
    {
126
        newWeapon = gamestate.weapon - 1;
127
        if(newWeapon < 0) newWeapon = gamestate.bestweapon;
128
    }
129
    else
130
    {
131
        for(int i = wp_knife; i <= gamestate.bestweapon; i++)
132
        {
133
            if (buttonstate[bt_readyknife + i - wp_knife])
134
            {
135
                newWeapon = i;
136
                break;
137
            }
138
        }
139
    }
140
 
141
    if(newWeapon != -1)
142
    {
143
        gamestate.weapon = gamestate.chosenweapon = (weapontype) newWeapon;
144
        DrawWeapon();
145
    }
146
}
147
 
148
 
149
/*
150
=======================
151
=
152
= ControlMovement
153
=
154
= Takes controlx,controly, and buttonstate[bt_strafe]
155
=
156
= Changes the player's angle and position
157
=
158
= There is an angle hack because when going 70 fps, the roundoff becomes
159
= significant
160
=
161
=======================
162
*/
163
 
164
void ControlMovement (objtype *ob)
165
{
166
    int32_t oldx,oldy;
167
    int     angle;
168
    int     angleunits;
169
 
170
    thrustspeed = 0;
171
 
172
    oldx = player->x;
173
    oldy = player->y;
174
 
175
    if(buttonstate[bt_strafeleft])
176
    {
177
        angle = ob->angle + ANGLES/4;
178
        if(angle >= ANGLES)
179
            angle -= ANGLES;
180
        if(buttonstate[bt_run])
181
            Thrust(angle, RUNMOVE * MOVESCALE * tics);
182
        else
183
            Thrust(angle, BASEMOVE * MOVESCALE * tics);
184
    }
185
 
186
    if(buttonstate[bt_straferight])
187
    {
188
        angle = ob->angle - ANGLES/4;
189
        if(angle < 0)
190
            angle += ANGLES;
191
        if(buttonstate[bt_run])
192
            Thrust(angle, RUNMOVE * MOVESCALE * tics );
193
        else
194
            Thrust(angle, BASEMOVE * MOVESCALE * tics);
195
    }
196
 
197
    //
198
    // side to side move
199
    //
200
    if (buttonstate[bt_strafe])
201
    {
202
        //
203
        // strafing
204
        //
205
        //
206
        if (controlx > 0)
207
        {
208
            angle = ob->angle - ANGLES/4;
209
            if (angle < 0)
210
                angle += ANGLES;
211
            Thrust (angle,controlx*MOVESCALE);      // move to left
212
        }
213
        else if (controlx < 0)
214
        {
215
            angle = ob->angle + ANGLES/4;
216
            if (angle >= ANGLES)
217
                angle -= ANGLES;
218
            Thrust (angle,-controlx*MOVESCALE);     // move to right
219
        }
220
    }
221
    else
222
    {
223
        //
224
        // not strafing
225
        //
226
        anglefrac += controlx;
227
        angleunits = anglefrac/ANGLESCALE;
228
        anglefrac -= angleunits*ANGLESCALE;
229
        ob->angle -= angleunits;
230
 
231
        if (ob->angle >= ANGLES)
232
            ob->angle -= ANGLES;
233
        if (ob->angle < 0)
234
            ob->angle += ANGLES;
235
 
236
    }
237
 
238
    //
239
    // forward/backwards move
240
    //
241
    if (controly < 0)
242
    {
243
        Thrust (ob->angle,-controly*MOVESCALE); // move forwards
244
    }
245
    else if (controly > 0)
246
    {
247
        angle = ob->angle + ANGLES/2;
248
        if (angle >= ANGLES)
249
            angle -= ANGLES;
250
        Thrust (angle,controly*BACKMOVESCALE);          // move backwards
251
    }
252
 
253
    if (gamestate.victoryflag)              // watching the BJ actor
254
        return;
255
}
256
 
257
/*
258
=============================================================================
259
 
260
                            STATUS WINDOW STUFF
261
 
262
=============================================================================
263
*/
264
 
265
 
266
/*
267
==================
268
=
269
= StatusDrawPic
270
=
271
==================
272
*/
273
 
274
void StatusDrawPic (unsigned x, unsigned y, unsigned picnum)
275
{
276
    LatchDrawPicScaledCoord ((screenWidth-scaleFactor*320)/16 + scaleFactor*x,
277
        screenHeight-scaleFactor*(STATUSLINES-y),picnum);
278
}
279
 
280
void StatusDrawFace(unsigned picnum)
281
{
282
    StatusDrawPic(17, 4, picnum);
283
 
284
#ifdef _arch_dreamcast
285
    DC_StatusDrawLCD(picnum);
286
#endif
287
}
288
 
289
 
290
/*
291
==================
292
=
293
= DrawFace
294
=
295
==================
296
*/
297
 
298
void DrawFace (void)
299
{
300
    if(viewsize == 21 && ingame) return;
301
    if (SD_SoundPlaying() == GETGATLINGSND)
302
        StatusDrawFace(GOTGATLINGPIC);
303
    else if (gamestate.health)
304
    {
305
#ifdef SPEAR
306
        if (godmode)
307
            StatusDrawFace(GODMODEFACE1PIC+gamestate.faceframe);
308
        else
309
#endif
310
            StatusDrawFace(FACE1APIC+3*((100-gamestate.health)/16)+gamestate.faceframe);
311
    }
312
    else
313
    {
314
#ifndef SPEAR
315
        if (LastAttacker && LastAttacker->obclass == needleobj)
316
            StatusDrawFace(MUTANTBJPIC);
317
        else
318
#endif
319
            StatusDrawFace(FACE8APIC);
320
    }
321
}
322
 
323
/*
324
===============
325
=
326
= UpdateFace
327
=
328
= Calls draw face if time to change
329
=
330
===============
331
*/
332
 
333
int facecount = 0;
334
int facetimes = 0;
335
 
336
void UpdateFace (void)
337
{
338
    // don't make demo depend on sound playback
339
    if(demoplayback || demorecord)
340
    {
341
        if(facetimes > 0)
342
        {
343
            facetimes--;
344
            return;
345
        }
346
    }
347
    else if(SD_SoundPlaying() == GETGATLINGSND)
348
        return;
349
 
350
    facecount += tics;
351
    if (facecount > US_RndT())
352
    {
353
        gamestate.faceframe = (US_RndT()>>6);
354
        if (gamestate.faceframe==3)
355
            gamestate.faceframe = 1;
356
 
357
        facecount = 0;
358
        DrawFace ();
359
    }
360
}
361
 
362
 
363
 
364
/*
365
===============
366
=
367
= LatchNumber
368
=
369
= right justifies and pads with blanks
370
=
371
===============
372
*/
373
 
374
static void LatchNumber (int x, int y, unsigned width, int32_t number)
375
{
376
    unsigned length,c;
377
    char    str[20];
378
 
379
    ltoa (number,str,10);
380
 
381
    length = (unsigned) strlen (str);
382
 
383
    while (length
384
    {
385
        StatusDrawPic (x,y,N_BLANKPIC);
386
        x++;
387
        width--;
388
    }
389
 
390
    c = length <= width ? 0 : length-width;
391
 
392
    while (c
393
    {
394
        StatusDrawPic (x,y,str[c]-'0'+ N_0PIC);
395
        x++;
396
        c++;
397
    }
398
}
399
 
400
 
401
/*
402
===============
403
=
404
= DrawHealth
405
=
406
===============
407
*/
408
 
409
void DrawHealth (void)
410
{
411
    if(viewsize == 21 && ingame) return;
412
    LatchNumber (21,16,3,gamestate.health);
413
}
414
 
415
 
416
/*
417
===============
418
=
419
= TakeDamage
420
=
421
===============
422
*/
423
 
424
void TakeDamage (int points,objtype *attacker)
425
{
426
    LastAttacker = attacker;
427
 
428
    if (gamestate.victoryflag)
429
        return;
430
    if (gamestate.difficulty==gd_baby)
431
        points>>=2;
432
 
433
    if (!godmode)
434
        gamestate.health -= points;
435
 
436
    if (gamestate.health<=0)
437
    {
438
        gamestate.health = 0;
439
        playstate = ex_died;
440
        killerobj = attacker;
441
    }
442
 
443
    if (godmode != 2)
444
        StartDamageFlash (points);
445
 
446
    DrawHealth ();
447
    DrawFace ();
448
 
449
    //
450
    // MAKE BJ'S EYES BUG IF MAJOR DAMAGE!
451
    //
452
#ifdef SPEAR
453
    if (points > 30 && gamestate.health!=0 && !godmode && viewsize != 21)
454
    {
455
        StatusDrawFace(BJOUCHPIC);
456
        facecount = 0;
457
    }
458
#endif
459
}
460
 
461
/*
462
===============
463
=
464
= HealSelf
465
=
466
===============
467
*/
468
 
469
void HealSelf (int points)
470
{
471
    gamestate.health += points;
472
    if (gamestate.health>100)
473
        gamestate.health = 100;
474
 
475
    DrawHealth ();
476
    DrawFace ();
477
}
478
 
479
 
480
//===========================================================================
481
 
482
 
483
/*
484
===============
485
=
486
= DrawLevel
487
=
488
===============
489
*/
490
 
491
void DrawLevel (void)
492
{
493
    if(viewsize == 21 && ingame) return;
494
#ifdef SPEAR
495
    if (gamestate.mapon == 20)
496
        LatchNumber (2,16,2,18);
497
    else
498
#endif
499
        LatchNumber (2,16,2,gamestate.mapon+1);
500
}
501
 
502
//===========================================================================
503
 
504
 
505
/*
506
===============
507
=
508
= DrawLives
509
=
510
===============
511
*/
512
 
513
void DrawLives (void)
514
{
515
    if(viewsize == 21 && ingame) return;
516
    LatchNumber (14,16,1,gamestate.lives);
517
}
518
 
519
 
520
/*
521
===============
522
=
523
= GiveExtraMan
524
=
525
===============
526
*/
527
 
528
void GiveExtraMan (void)
529
{
530
    if (gamestate.lives<9)
531
        gamestate.lives++;
532
    DrawLives ();
533
    SD_PlaySound (BONUS1UPSND);
534
}
535
 
536
//===========================================================================
537
 
538
/*
539
===============
540
=
541
= DrawScore
542
=
543
===============
544
*/
545
 
546
void DrawScore (void)
547
{
548
    if(viewsize == 21 && ingame) return;
549
    LatchNumber (6,16,6,gamestate.score);
550
}
551
 
552
/*
553
===============
554
=
555
= GivePoints
556
=
557
===============
558
*/
559
 
560
void GivePoints (int32_t points)
561
{
562
    gamestate.score += points;
563
    while (gamestate.score >= gamestate.nextextra)
564
    {
565
        gamestate.nextextra += EXTRAPOINTS;
566
        GiveExtraMan ();
567
    }
568
    DrawScore ();
569
}
570
 
571
//===========================================================================
572
 
573
/*
574
==================
575
=
576
= DrawWeapon
577
=
578
==================
579
*/
580
 
581
void DrawWeapon (void)
582
{
583
    if(viewsize == 21 && ingame) return;
584
    StatusDrawPic (32,8,KNIFEPIC+gamestate.weapon);
585
}
586
 
587
 
588
/*
589
==================
590
=
591
= DrawKeys
592
=
593
==================
594
*/
595
 
596
void DrawKeys (void)
597
{
598
    if(viewsize == 21 && ingame) return;
599
    if (gamestate.keys & 1)
600
        StatusDrawPic (30,4,GOLDKEYPIC);
601
    else
602
        StatusDrawPic (30,4,NOKEYPIC);
603
 
604
    if (gamestate.keys & 2)
605
        StatusDrawPic (30,20,SILVERKEYPIC);
606
    else
607
        StatusDrawPic (30,20,NOKEYPIC);
608
}
609
 
610
/*
611
==================
612
=
613
= GiveWeapon
614
=
615
==================
616
*/
617
 
618
void GiveWeapon (int weapon)
619
{
620
    GiveAmmo (6);
621
 
622
    if (gamestate.bestweapon
623
        gamestate.bestweapon = gamestate.weapon
624
        = gamestate.chosenweapon = (weapontype) weapon;
625
 
626
    DrawWeapon ();
627
}
628
 
629
//===========================================================================
630
 
631
/*
632
===============
633
=
634
= DrawAmmo
635
=
636
===============
637
*/
638
 
639
void DrawAmmo (void)
640
{
641
    if(viewsize == 21 && ingame) return;
642
    LatchNumber (27,16,2,gamestate.ammo);
643
}
644
 
645
/*
646
===============
647
=
648
= GiveAmmo
649
=
650
===============
651
*/
652
 
653
void GiveAmmo (int ammo)
654
{
655
    if (!gamestate.ammo)                            // knife was out
656
    {
657
        if (!gamestate.attackframe)
658
        {
659
            gamestate.weapon = gamestate.chosenweapon;
660
            DrawWeapon ();
661
        }
662
    }
663
    gamestate.ammo += ammo;
664
    if (gamestate.ammo > 99)
665
        gamestate.ammo = 99;
666
    DrawAmmo ();
667
}
668
 
669
//===========================================================================
670
 
671
/*
672
==================
673
=
674
= GiveKey
675
=
676
==================
677
*/
678
 
679
void GiveKey (int key)
680
{
681
    gamestate.keys |= (1<
682
    DrawKeys ();
683
}
684
 
685
 
686
 
687
/*
688
=============================================================================
689
 
690
                                MOVEMENT
691
 
692
=============================================================================
693
*/
694
 
695
 
696
/*
697
===================
698
=
699
= GetBonus
700
=
701
===================
702
*/
703
void GetBonus (statobj_t *check)
704
{
705
    switch (check->itemnumber)
706
    {
707
        case    bo_firstaid:
708
            if (gamestate.health == 100)
709
                return;
710
 
711
            SD_PlaySound (HEALTH2SND);
712
            HealSelf (25);
713
            break;
714
 
715
        case    bo_key1:
716
        case    bo_key2:
717
        case    bo_key3:
718
        case    bo_key4:
719
            GiveKey (check->itemnumber - bo_key1);
720
            SD_PlaySound (GETKEYSND);
721
            break;
722
 
723
        case    bo_cross:
724
            SD_PlaySound (BONUS1SND);
725
            GivePoints (100);
726
            gamestate.treasurecount++;
727
            break;
728
        case    bo_chalice:
729
            SD_PlaySound (BONUS2SND);
730
            GivePoints (500);
731
            gamestate.treasurecount++;
732
            break;
733
        case    bo_bible:
734
            SD_PlaySound (BONUS3SND);
735
            GivePoints (1000);
736
            gamestate.treasurecount++;
737
            break;
738
        case    bo_crown:
739
            SD_PlaySound (BONUS4SND);
740
            GivePoints (5000);
741
            gamestate.treasurecount++;
742
            break;
743
 
744
        case    bo_clip:
745
            if (gamestate.ammo == 99)
746
                return;
747
 
748
            SD_PlaySound (GETAMMOSND);
749
            GiveAmmo (8);
750
            break;
751
        case    bo_clip2:
752
            if (gamestate.ammo == 99)
753
                return;
754
 
755
            SD_PlaySound (GETAMMOSND);
756
            GiveAmmo (4);
757
            break;
758
 
759
#ifdef SPEAR
760
        case    bo_25clip:
761
            if (gamestate.ammo == 99)
762
                return;
763
 
764
            SD_PlaySound (GETAMMOBOXSND);
765
            GiveAmmo (25);
766
            break;
767
#endif
768
 
769
        case    bo_machinegun:
770
            SD_PlaySound (GETMACHINESND);
771
            GiveWeapon (wp_machinegun);
772
            break;
773
        case    bo_chaingun:
774
            SD_PlaySound (GETGATLINGSND);
775
            facetimes = 38;
776
            GiveWeapon (wp_chaingun);
777
 
778
            if(viewsize != 21)
779
                StatusDrawFace (GOTGATLINGPIC);
780
            facecount = 0;
781
            break;
782
 
783
        case    bo_fullheal:
784
            SD_PlaySound (BONUS1UPSND);
785
            HealSelf (99);
786
            GiveAmmo (25);
787
            GiveExtraMan ();
788
            gamestate.treasurecount++;
789
            break;
790
 
791
        case    bo_food:
792
            if (gamestate.health == 100)
793
                return;
794
 
795
            SD_PlaySound (HEALTH1SND);
796
            HealSelf (10);
797
            break;
798
 
799
        case    bo_alpo:
800
            if (gamestate.health == 100)
801
                return;
802
 
803
            SD_PlaySound (HEALTH1SND);
804
            HealSelf (4);
805
            break;
806
 
807
        case    bo_gibs:
808
            if (gamestate.health >10)
809
                return;
810
 
811
            SD_PlaySound (SLURPIESND);
812
            HealSelf (1);
813
            break;
814
 
815
#ifdef SPEAR
816
        case    bo_spear:
817
            spearflag = true;
818
            spearx = player->x;
819
            speary = player->y;
820
            spearangle = player->angle;
821
            playstate = ex_completed;
822
#endif
823
    }
824
 
825
    StartBonusFlash ();
826
    check->shapenum = -1;                   // remove from list
827
}
828
 
829
/*
830
===================
831
=
832
= TryMove
833
=
834
= returns true if move ok
835
= debug: use pointers to optimize
836
===================
837
*/
838
 
839
boolean TryMove (objtype *ob)
840
{
841
    int         xl,yl,xh,yh,x,y;
842
    objtype    *check;
843
    int32_t     deltax,deltay;
844
 
845
    xl = (ob->x-PLAYERSIZE) >>TILESHIFT;
846
    yl = (ob->y-PLAYERSIZE) >>TILESHIFT;
847
 
848
    xh = (ob->x+PLAYERSIZE) >>TILESHIFT;
849
    yh = (ob->y+PLAYERSIZE) >>TILESHIFT;
850
 
851
#define PUSHWALLMINDIST PLAYERSIZE
852
 
853
    //
854
    // check for solid walls
855
    //
856
    for (y=yl;y<=yh;y++)
857
    {
858
        for (x=xl;x<=xh;x++)
859
        {
860
            check = actorat[x][y];
861
            if (check && !ISPOINTER(check))
862
            {
863
                if(tilemap[x][y]==64 && x==pwallx && y==pwally)   // back of moving pushwall?
864
                {
865
                    switch(pwalldir)
866
                    {
867
                        case di_north:
868
                            if(ob->y-PUSHWALLMINDIST<=(pwally<
869
                                return false;
870
                            break;
871
                        case di_west:
872
                            if(ob->x-PUSHWALLMINDIST<=(pwallx<
873
                                return false;
874
                            break;
875
                        case di_east:
876
                            if(ob->x+PUSHWALLMINDIST>=(pwallx<
877
                                return false;
878
                            break;
879
                        case di_south:
880
                            if(ob->y+PUSHWALLMINDIST>=(pwally<
881
                                return false;
882
                            break;
883
                    }
884
                }
885
                else return false;
886
            }
887
        }
888
    }
889
 
890
    //
891
    // check for actors
892
    //
893
    if (yl>0)
894
        yl--;
895
    if (yh
896
        yh++;
897
    if (xl>0)
898
        xl--;
899
    if (xh
900
        xh++;
901
 
902
    for (y=yl;y<=yh;y++)
903
    {
904
        for (x=xl;x<=xh;x++)
905
        {
906
            check = actorat[x][y];
907
            if (ISPOINTER(check) && check != player && (check->flags & FL_SHOOTABLE) )
908
            {
909
                deltax = ob->x - check->x;
910
                if (deltax < -MINACTORDIST || deltax > MINACTORDIST)
911
                    continue;
912
                deltay = ob->y - check->y;
913
                if (deltay < -MINACTORDIST || deltay > MINACTORDIST)
914
                    continue;
915
 
916
                return false;
917
            }
918
        }
919
    }
920
 
921
    return true;
922
}
923
 
924
 
925
/*
926
===================
927
=
928
= ClipMove
929
=
930
===================
931
*/
932
 
933
void ClipMove (objtype *ob, int32_t xmove, int32_t ymove)
934
{
935
    int32_t    basex,basey;
936
 
937
    basex = ob->x;
938
    basey = ob->y;
939
 
940
    ob->x = basex+xmove;
941
    ob->y = basey+ymove;
942
    if (TryMove (ob))
943
        return;
944
 
945
#ifndef REMDEBUG
946
    if (noclip && ob->x > 2*TILEGLOBAL && ob->y > 2*TILEGLOBAL
947
        && ob->x < (((int32_t)(mapwidth-1))<
948
        && ob->y < (((int32_t)(mapheight-1))<
949
        return;         // walk through walls
950
#endif
951
 
952
    if (!SD_SoundPlaying())
953
        SD_PlaySound (HITWALLSND);
954
 
955
    ob->x = basex+xmove;
956
    ob->y = basey;
957
    if (TryMove (ob))
958
        return;
959
 
960
    ob->x = basex;
961
    ob->y = basey+ymove;
962
    if (TryMove (ob))
963
        return;
964
 
965
    ob->x = basex;
966
    ob->y = basey;
967
}
968
 
969
//==========================================================================
970
 
971
/*
972
===================
973
=
974
= VictoryTile
975
=
976
===================
977
*/
978
 
979
void VictoryTile (void)
980
{
981
#ifndef SPEAR
982
    SpawnBJVictory ();
983
#endif
984
 
985
    gamestate.victoryflag = true;
986
}
987
 
988
/*
989
===================
990
=
991
= Thrust
992
=
993
===================
994
*/
995
 
996
// For player movement in demos exactly as in the original Wolf3D v1.4 source code
997
static fixed FixedByFracOrig(fixed a, fixed b)
998
{
999
    int sign = 0;
1000
    if(b == 65536) b = 65535;
1001
    else if(b == -65536) b = 65535, sign = 1;
1002
    else if(b < 0) b = (-b), sign = 1;
1003
 
1004
    if(a < 0)
1005
    {
1006
        a = -a;
1007
        sign = !sign;
1008
    }
1009
    fixed res = (fixed)(((int64_t) a * b) >> 16);
1010
    if(sign)
1011
        res = -res;
1012
    return res;
1013
}
1014
 
1015
void Thrust (int angle, int32_t speed)
1016
{
1017
    int32_t xmove,ymove;
1018
    unsigned offset;
1019
 
1020
 
1021
    //
1022
    // ZERO FUNNY COUNTER IF MOVED!
1023
    //
1024
#ifdef SPEAR
1025
    if (speed)
1026
        funnyticount = 0;
1027
#endif
1028
 
1029
    thrustspeed += speed;
1030
    //
1031
    // moving bounds speed
1032
    //
1033
    if (speed >= MINDIST*2)
1034
        speed = MINDIST*2-1;
1035
 
1036
    xmove = DEMOCHOOSE_ORIG_SDL(
1037
                FixedByFracOrig(speed, costable[angle]),
1038
                FixedMul(speed,costable[angle]));
1039
    ymove = DEMOCHOOSE_ORIG_SDL(
1040
                -FixedByFracOrig(speed, sintable[angle]),
1041
                -FixedMul(speed,sintable[angle]));
1042
 
1043
    ClipMove(player,xmove,ymove);
1044
 
1045
    player->tilex = (short)(player->x >> TILESHIFT);                // scale to tile values
1046
    player->tiley = (short)(player->y >> TILESHIFT);
1047
 
1048
    offset = (player->tiley<tilex;
1049
    player->areanumber = *(mapsegs[0] + offset) -AREATILE;
1050
 
1051
    if (*(mapsegs[1] + offset) == EXITTILE)
1052
        VictoryTile ();
1053
}
1054
 
1055
 
1056
/*
1057
=============================================================================
1058
 
1059
                                ACTIONS
1060
 
1061
=============================================================================
1062
*/
1063
 
1064
 
1065
/*
1066
===============
1067
=
1068
= Cmd_Fire
1069
=
1070
===============
1071
*/
1072
 
1073
void Cmd_Fire (void)
1074
{
1075
    buttonheld[bt_attack] = true;
1076
 
1077
    gamestate.weaponframe = 0;
1078
 
1079
    player->state = &s_attack;
1080
 
1081
    gamestate.attackframe = 0;
1082
    gamestate.attackcount =
1083
        attackinfo[gamestate.weapon][gamestate.attackframe].tics;
1084
    gamestate.weaponframe =
1085
        attackinfo[gamestate.weapon][gamestate.attackframe].frame;
1086
}
1087
 
1088
//===========================================================================
1089
 
1090
/*
1091
===============
1092
=
1093
= Cmd_Use
1094
=
1095
===============
1096
*/
1097
 
1098
void Cmd_Use (void)
1099
{
1100
    int     checkx,checky,doornum,dir;
1101
    boolean elevatorok;
1102
 
1103
    //
1104
    // find which cardinal direction the player is facing
1105
    //
1106
    if (player->angle < ANGLES/8 || player->angle > 7*ANGLES/8)
1107
    {
1108
        checkx = player->tilex + 1;
1109
        checky = player->tiley;
1110
        dir = di_east;
1111
        elevatorok = true;
1112
    }
1113
    else if (player->angle < 3*ANGLES/8)
1114
    {
1115
        checkx = player->tilex;
1116
        checky = player->tiley-1;
1117
        dir = di_north;
1118
        elevatorok = false;
1119
    }
1120
    else if (player->angle < 5*ANGLES/8)
1121
    {
1122
        checkx = player->tilex - 1;
1123
        checky = player->tiley;
1124
        dir = di_west;
1125
        elevatorok = true;
1126
    }
1127
    else
1128
    {
1129
        checkx = player->tilex;
1130
        checky = player->tiley + 1;
1131
        dir = di_south;
1132
        elevatorok = false;
1133
    }
1134
 
1135
    doornum = tilemap[checkx][checky];
1136
    if (*(mapsegs[1]+(checky<
1137
    {
1138
        //
1139
        // pushable wall
1140
        //
1141
 
1142
        PushWall (checkx,checky,dir);
1143
        return;
1144
    }
1145
    if (!buttonheld[bt_use] && doornum == ELEVATORTILE && elevatorok)
1146
    {
1147
        //
1148
        // use elevator
1149
        //
1150
        buttonheld[bt_use] = true;
1151
 
1152
        tilemap[checkx][checky]++;              // flip switch
1153
        if (*(mapsegs[0]+(player->tiley<tilex) == ALTELEVATORTILE)
1154
            playstate = ex_secretlevel;
1155
        else
1156
            playstate = ex_completed;
1157
        SD_PlaySound (LEVELDONESND);
1158
        SD_WaitSoundDone();
1159
    }
1160
    else if (!buttonheld[bt_use] && doornum & 0x80)
1161
    {
1162
        buttonheld[bt_use] = true;
1163
        OperateDoor (doornum & ~0x80);
1164
    }
1165
    else
1166
        SD_PlaySound (DONOTHINGSND);
1167
}
1168
 
1169
/*
1170
=============================================================================
1171
 
1172
                                PLAYER CONTROL
1173
 
1174
=============================================================================
1175
*/
1176
 
1177
 
1178
 
1179
/*
1180
===============
1181
=
1182
= SpawnPlayer
1183
=
1184
===============
1185
*/
1186
 
1187
void SpawnPlayer (int tilex, int tiley, int dir)
1188
{
1189
    player->obclass = playerobj;
1190
    player->active = ac_yes;
1191
    player->tilex = tilex;
1192
    player->tiley = tiley;
1193
    player->areanumber = (byte) *(mapsegs[0]+(player->tiley<tilex);
1194
    player->x = ((int32_t)tilex<
1195
    player->y = ((int32_t)tiley<
1196
    player->state = &s_player;
1197
    player->angle = (1-dir)*90;
1198
    if (player->angle<0)
1199
        player->angle += ANGLES;
1200
    player->flags = FL_NEVERMARK;
1201
    Thrust (0,0);                           // set some variables
1202
 
1203
    InitAreas ();
1204
}
1205
 
1206
 
1207
//===========================================================================
1208
 
1209
/*
1210
===============
1211
=
1212
= T_KnifeAttack
1213
=
1214
= Update player hands, and try to do damage when the proper frame is reached
1215
=
1216
===============
1217
*/
1218
 
1219
void    KnifeAttack (objtype *ob)
1220
{
1221
    objtype *check,*closest;
1222
    int32_t  dist;
1223
 
1224
    SD_PlaySound (ATKKNIFESND);
1225
    // actually fire
1226
    dist = 0x7fffffff;
1227
    closest = NULL;
1228
    for (check=ob->next; check; check=check->next)
1229
    {
1230
        if ( (check->flags & FL_SHOOTABLE) && (check->flags & FL_VISABLE)
1231
            && abs(check->viewx-centerx) < shootdelta)
1232
        {
1233
            if (check->transx < dist)
1234
            {
1235
                dist = check->transx;
1236
                closest = check;
1237
            }
1238
        }
1239
    }
1240
 
1241
    if (!closest || dist > 0x18000l)
1242
    {
1243
        // missed
1244
        return;
1245
    }
1246
 
1247
    // hit something
1248
    DamageActor (closest,US_RndT() >> 4);
1249
}
1250
 
1251
 
1252
 
1253
void    GunAttack (objtype *ob)
1254
{
1255
    objtype *check,*closest,*oldclosest;
1256
    int      damage;
1257
    int      dx,dy,dist;
1258
    int32_t  viewdist;
1259
 
1260
    switch (gamestate.weapon)
1261
    {
1262
        case wp_pistol:
1263
            SD_PlaySound (ATKPISTOLSND);
1264
            break;
1265
        case wp_machinegun:
1266
            SD_PlaySound (ATKMACHINEGUNSND);
1267
            break;
1268
        case wp_chaingun:
1269
            SD_PlaySound (ATKGATLINGSND);
1270
            break;
1271
    }
1272
 
1273
    madenoise = true;
1274
 
1275
    //
1276
    // find potential targets
1277
    //
1278
    viewdist = 0x7fffffffl;
1279
    closest = NULL;
1280
 
1281
    while (1)
1282
    {
1283
        oldclosest = closest;
1284
 
1285
        for (check=ob->next ; check ; check=check->next)
1286
        {
1287
            if ((check->flags & FL_SHOOTABLE) && (check->flags & FL_VISABLE)
1288
                && abs(check->viewx-centerx) < shootdelta)
1289
            {
1290
                if (check->transx < viewdist)
1291
                {
1292
                    viewdist = check->transx;
1293
                    closest = check;
1294
                }
1295
            }
1296
        }
1297
 
1298
        if (closest == oldclosest)
1299
            return;                                         // no more targets, all missed
1300
 
1301
        //
1302
        // trace a line from player to enemey
1303
        //
1304
        if (CheckLine(closest))
1305
            break;
1306
    }
1307
 
1308
    //
1309
    // hit something
1310
    //
1311
    dx = ABS(closest->tilex - player->tilex);
1312
    dy = ABS(closest->tiley - player->tiley);
1313
    dist = dx>dy ? dx:dy;
1314
    if (dist<2)
1315
        damage = US_RndT() / 4;
1316
    else if (dist<4)
1317
        damage = US_RndT() / 6;
1318
    else
1319
    {
1320
        if ( (US_RndT() / 12) < dist)           // missed
1321
            return;
1322
        damage = US_RndT() / 6;
1323
    }
1324
    DamageActor (closest,damage);
1325
}
1326
 
1327
//===========================================================================
1328
 
1329
/*
1330
===============
1331
=
1332
= VictorySpin
1333
=
1334
===============
1335
*/
1336
 
1337
void VictorySpin (void)
1338
{
1339
    int32_t    desty;
1340
 
1341
    if (player->angle > 270)
1342
    {
1343
        player->angle -= (short)(tics * 3);
1344
        if (player->angle < 270)
1345
            player->angle = 270;
1346
    }
1347
    else if (player->angle < 270)
1348
    {
1349
        player->angle += (short)(tics * 3);
1350
        if (player->angle > 270)
1351
            player->angle = 270;
1352
    }
1353
 
1354
    desty = (((int32_t)player->tiley-5)<
1355
 
1356
    if (player->y > desty)
1357
    {
1358
        player->y -= tics*4096;
1359
        if (player->y < desty)
1360
            player->y = desty;
1361
    }
1362
}
1363
 
1364
 
1365
//===========================================================================
1366
 
1367
/*
1368
===============
1369
=
1370
= T_Attack
1371
=
1372
===============
1373
*/
1374
 
1375
void    T_Attack (objtype *ob)
1376
{
1377
    struct  atkinf  *cur;
1378
 
1379
    UpdateFace ();
1380
 
1381
    if (gamestate.victoryflag)              // watching the BJ actor
1382
    {
1383
        VictorySpin ();
1384
        return;
1385
    }
1386
 
1387
    if ( buttonstate[bt_use] && !buttonheld[bt_use] )
1388
        buttonstate[bt_use] = false;
1389
 
1390
    if ( buttonstate[bt_attack] && !buttonheld[bt_attack])
1391
        buttonstate[bt_attack] = false;
1392
 
1393
    ControlMovement (ob);
1394
    if (gamestate.victoryflag)              // watching the BJ actor
1395
        return;
1396
 
1397
    plux = (word) (player->x >> UNSIGNEDSHIFT);                     // scale to fit in unsigned
1398
    pluy = (word) (player->y >> UNSIGNEDSHIFT);
1399
    player->tilex = (short)(player->x >> TILESHIFT);                // scale to tile values
1400
    player->tiley = (short)(player->y >> TILESHIFT);
1401
 
1402
    //
1403
    // change frame and fire
1404
    //
1405
    gamestate.attackcount -= (short) tics;
1406
    while (gamestate.attackcount <= 0)
1407
    {
1408
        cur = &attackinfo[gamestate.weapon][gamestate.attackframe];
1409
        switch (cur->attack)
1410
        {
1411
            case -1:
1412
                ob->state = &s_player;
1413
                if (!gamestate.ammo)
1414
                {
1415
                    gamestate.weapon = wp_knife;
1416
                    DrawWeapon ();
1417
                }
1418
                else
1419
                {
1420
                    if (gamestate.weapon != gamestate.chosenweapon)
1421
                    {
1422
                        gamestate.weapon = gamestate.chosenweapon;
1423
                        DrawWeapon ();
1424
                    }
1425
                }
1426
                gamestate.attackframe = gamestate.weaponframe = 0;
1427
                return;
1428
 
1429
            case 4:
1430
                if (!gamestate.ammo)
1431
                    break;
1432
                if (buttonstate[bt_attack])
1433
                    gamestate.attackframe -= 2;
1434
            case 1:
1435
                if (!gamestate.ammo)
1436
                {       // can only happen with chain gun
1437
                    gamestate.attackframe++;
1438
                    break;
1439
                }
1440
                GunAttack (ob);
1441
                if (!ammocheat)
1442
                    gamestate.ammo--;
1443
                DrawAmmo ();
1444
                break;
1445
 
1446
            case 2:
1447
                KnifeAttack (ob);
1448
                break;
1449
 
1450
            case 3:
1451
                if (gamestate.ammo && buttonstate[bt_attack])
1452
                    gamestate.attackframe -= 2;
1453
                break;
1454
        }
1455
 
1456
        gamestate.attackcount += cur->tics;
1457
        gamestate.attackframe++;
1458
        gamestate.weaponframe =
1459
            attackinfo[gamestate.weapon][gamestate.attackframe].frame;
1460
    }
1461
}
1462
 
1463
 
1464
 
1465
//===========================================================================
1466
 
1467
/*
1468
===============
1469
=
1470
= T_Player
1471
=
1472
===============
1473
*/
1474
 
1475
void    T_Player (objtype *ob)
1476
{
1477
    if (gamestate.victoryflag)              // watching the BJ actor
1478
    {
1479
        VictorySpin ();
1480
        return;
1481
    }
1482
 
1483
    UpdateFace ();
1484
    CheckWeaponChange ();
1485
 
1486
    if ( buttonstate[bt_use] )
1487
        Cmd_Use ();
1488
 
1489
    if ( buttonstate[bt_attack] && !buttonheld[bt_attack])
1490
        Cmd_Fire ();
1491
 
1492
    ControlMovement (ob);
1493
    if (gamestate.victoryflag)              // watching the BJ actor
1494
        return;
1495
 
1496
    plux = (word) (player->x >> UNSIGNEDSHIFT);                     // scale to fit in unsigned
1497
    pluy = (word) (player->y >> UNSIGNEDSHIFT);
1498
    player->tilex = (short)(player->x >> TILESHIFT);                // scale to tile values
1499
    player->tiley = (short)(player->y >> TILESHIFT);
1500
}