Subversion Repositories Kolibri OS

Rev

Rev 8557 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8557 maxcodehac 1
// WL_PLAY.C
2
 
3
#include "wl_def.h"
4
#pragma hdrstop
5
 
6
#include "wl_cloudsky.h"
7
#include "wl_shade.h"
8
 
9
/*
10
=============================================================================
11
 
12
                                                 LOCAL CONSTANTS
13
 
14
=============================================================================
15
*/
16
 
17
#define sc_Question     0x35
18
 
19
/*
20
=============================================================================
21
 
22
                                                 GLOBAL VARIABLES
23
 
24
=============================================================================
25
*/
26
 
27
boolean madenoise;              // true when shooting or screaming
28
 
29
exit_t playstate;
30
 
31
static musicnames lastmusicchunk = (musicnames) 0;
32
 
33
static int DebugOk;
34
 
35
objtype objlist[MAXACTORS];
36
objtype *newobj, *obj, *player, *lastobj, *objfreelist, *killerobj;
37
 
38
boolean noclip, ammocheat;
39
int godmode, singlestep, extravbls = 0;
40
 
41
byte tilemap[MAPSIZE][MAPSIZE]; // wall values only
42
byte spotvis[MAPSIZE][MAPSIZE];
43
objtype *actorat[MAPSIZE][MAPSIZE];
44
 
45
//
46
// replacing refresh manager
47
//
48
unsigned tics;
49
 
50
//
51
// control info
52
//
53
boolean mouseenabled, joystickenabled;
54
int dirscan[4] = { sc_UpArrow, sc_RightArrow, sc_DownArrow, sc_LeftArrow };
55
int buttonscan[NUMBUTTONS] = { sc_Control, sc_Alt, sc_LShift, sc_Space, sc_1, sc_2, sc_3, sc_4 };
56
int buttonmouse[4] = { bt_attack, bt_strafe, bt_use, bt_nobutton };
57
int buttonjoy[32] = {
58
#ifdef _arch_dreamcast
59
    bt_attack, bt_strafe, bt_use, bt_run, bt_esc, bt_prevweapon, bt_nobutton, bt_nextweapon,
60
    bt_pause, bt_strafeleft, bt_straferight, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton,
61
#else
62
    bt_attack, bt_strafe, bt_use, bt_run, bt_strafeleft, bt_straferight, bt_esc, bt_pause,
63
    bt_prevweapon, bt_nextweapon, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton,
64
#endif
65
    bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton,
66
    bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton
67
};
68
 
69
int viewsize;
70
 
71
boolean buttonheld[NUMBUTTONS];
72
 
73
boolean demorecord, demoplayback;
74
int8_t *demoptr, *lastdemoptr;
75
memptr demobuffer;
76
 
77
//
78
// current user input
79
//
80
int controlx, controly;         // range from -100 to 100 per tic
81
boolean buttonstate[NUMBUTTONS];
82
 
83
int lastgamemusicoffset = 0;
84
 
85
 
86
//===========================================================================
87
 
88
 
89
void CenterWindow (word w, word h);
90
void InitObjList (void);
91
void RemoveObj (objtype * gone);
92
void PollControls (void);
93
int StopMusic (void);
94
void StartMusic (void);
95
void ContinueMusic (int offs);
96
void PlayLoop (void);
97
 
98
/*
99
=============================================================================
100
 
101
                                                 LOCAL VARIABLES
102
 
103
=============================================================================
104
*/
105
 
106
 
107
objtype dummyobj;
108
 
109
//
110
// LIST OF SONGS FOR EACH VERSION
111
//
112
int songs[] = {
113
#ifndef SPEAR
114
    //
115
    // Episode One
116
    //
117
    GETTHEM_MUS,
118
    SEARCHN_MUS,
119
    POW_MUS,
120
    SUSPENSE_MUS,
121
    GETTHEM_MUS,
122
    SEARCHN_MUS,
123
    POW_MUS,
124
    SUSPENSE_MUS,
125
 
126
    WARMARCH_MUS,               // Boss level
127
    CORNER_MUS,                 // Secret level
128
 
129
    //
130
    // Episode Two
131
    //
132
    NAZI_OMI_MUS,
133
    PREGNANT_MUS,
134
    GOINGAFT_MUS,
135
    HEADACHE_MUS,
136
    NAZI_OMI_MUS,
137
    PREGNANT_MUS,
138
    HEADACHE_MUS,
139
    GOINGAFT_MUS,
140
 
141
    WARMARCH_MUS,               // Boss level
142
    DUNGEON_MUS,                // Secret level
143
 
144
    //
145
    // Episode Three
146
    //
147
    INTROCW3_MUS,
148
    NAZI_RAP_MUS,
149
    TWELFTH_MUS,
150
    ZEROHOUR_MUS,
151
    INTROCW3_MUS,
152
    NAZI_RAP_MUS,
153
    TWELFTH_MUS,
154
    ZEROHOUR_MUS,
155
 
156
    ULTIMATE_MUS,               // Boss level
157
    PACMAN_MUS,                 // Secret level
158
 
159
    //
160
    // Episode Four
161
    //
162
    GETTHEM_MUS,
163
    SEARCHN_MUS,
164
    POW_MUS,
165
    SUSPENSE_MUS,
166
    GETTHEM_MUS,
167
    SEARCHN_MUS,
168
    POW_MUS,
169
    SUSPENSE_MUS,
170
 
171
    WARMARCH_MUS,               // Boss level
172
    CORNER_MUS,                 // Secret level
173
 
174
    //
175
    // Episode Five
176
    //
177
    NAZI_OMI_MUS,
178
    PREGNANT_MUS,
179
    GOINGAFT_MUS,
180
    HEADACHE_MUS,
181
    NAZI_OMI_MUS,
182
    PREGNANT_MUS,
183
    HEADACHE_MUS,
184
    GOINGAFT_MUS,
185
 
186
    WARMARCH_MUS,               // Boss level
187
    DUNGEON_MUS,                // Secret level
188
 
189
    //
190
    // Episode Six
191
    //
192
    INTROCW3_MUS,
193
    NAZI_RAP_MUS,
194
    TWELFTH_MUS,
195
    ZEROHOUR_MUS,
196
    INTROCW3_MUS,
197
    NAZI_RAP_MUS,
198
    TWELFTH_MUS,
199
    ZEROHOUR_MUS,
200
 
201
    ULTIMATE_MUS,               // Boss level
202
    FUNKYOU_MUS                 // Secret level
203
#else
204
 
205
    //////////////////////////////////////////////////////////////
206
    //
207
    // SPEAR OF DESTINY TRACKS
208
    //
209
    //////////////////////////////////////////////////////////////
210
    XTIPTOE_MUS,
211
    XFUNKIE_MUS,
212
    XDEATH_MUS,
213
    XGETYOU_MUS,                // DON'T KNOW
9097 turbocat 214
    ULTIMATE_MUS,               // Trans Gr�sse
8557 maxcodehac 215
 
216
    DUNGEON_MUS,
217
    GOINGAFT_MUS,
218
    POW_MUS,
219
    TWELFTH_MUS,
220
    ULTIMATE_MUS,               // Barnacle Wilhelm BOSS
221
 
222
    NAZI_OMI_MUS,
223
    GETTHEM_MUS,
224
    SUSPENSE_MUS,
225
    SEARCHN_MUS,
226
    ZEROHOUR_MUS,
227
    ULTIMATE_MUS,               // Super Mutant BOSS
228
 
229
    XPUTIT_MUS,
230
    ULTIMATE_MUS,               // Death Knight BOSS
231
 
232
    XJAZNAZI_MUS,               // Secret level
233
    XFUNKIE_MUS,                // Secret level (DON'T KNOW)
234
 
235
    XEVIL_MUS                   // Angel of Death BOSS
236
#endif
237
};
238
 
239
 
240
/*
241
=============================================================================
242
 
243
                               USER CONTROL
244
 
245
=============================================================================
246
*/
247
 
248
/*
249
===================
250
=
251
= PollKeyboardButtons
252
=
253
===================
254
*/
255
 
256
void PollKeyboardButtons (void)
257
{
258
    int i;
259
 
260
    for (i = 0; i < NUMBUTTONS; i++)
261
        if (Keyboard[buttonscan[i]])
262
            buttonstate[i] = true;
263
}
264
 
265
 
266
/*
267
===================
268
=
269
= PollMouseButtons
270
=
271
===================
272
*/
273
 
274
void PollMouseButtons (void)
275
{
276
    int buttons = IN_MouseButtons ();
277
 
278
    if (buttons & 1)
279
        buttonstate[buttonmouse[0]] = true;
280
    if (buttons & 2)
281
        buttonstate[buttonmouse[1]] = true;
282
    if (buttons & 4)
283
        buttonstate[buttonmouse[2]] = true;
284
}
285
 
286
 
287
 
288
/*
289
===================
290
=
291
= PollJoystickButtons
292
=
293
===================
294
*/
295
 
296
void PollJoystickButtons (void)
297
{
298
    int buttons = IN_JoyButtons();
299
 
300
    for(int i = 0, val = 1; i < JoyNumButtons; i++, val <<= 1)
301
    {
302
        if(buttons & val)
303
            buttonstate[buttonjoy[i]] = true;
304
    }
305
}
306
 
307
 
308
/*
309
===================
310
=
311
= PollKeyboardMove
312
=
313
===================
314
*/
315
 
316
void PollKeyboardMove (void)
317
{
318
    int delta = buttonstate[bt_run] ? RUNMOVE * tics : BASEMOVE * tics;
319
 
320
    if (Keyboard[dirscan[di_north]])
321
        controly -= delta;
322
    if (Keyboard[dirscan[di_south]])
323
        controly += delta;
324
    if (Keyboard[dirscan[di_west]])
325
        controlx -= delta;
326
    if (Keyboard[dirscan[di_east]])
327
        controlx += delta;
328
}
329
 
330
 
331
/*
332
===================
333
=
334
= PollMouseMove
335
=
336
===================
337
*/
338
 
339
void PollMouseMove (void)
340
{
341
    int mousexmove, mouseymove;
342
 
343
    SDL_GetMouseState(&mousexmove, &mouseymove);
344
    if(IN_IsInputGrabbed())
345
        IN_CenterMouse();
346
 
347
    mousexmove -= screenWidth / 2;
348
    mouseymove -= screenHeight / 2;
349
 
350
    controlx += mousexmove * 10 / (13 - mouseadjustment);
351
    controly += mouseymove * 20 / (13 - mouseadjustment);
352
}
353
 
354
 
355
/*
356
===================
357
=
358
= PollJoystickMove
359
=
360
===================
361
*/
362
 
363
void PollJoystickMove (void)
364
{
365
    int joyx, joyy;
366
 
367
    IN_GetJoyDelta (&joyx, &joyy);
368
 
369
    int delta = buttonstate[bt_run] ? RUNMOVE * tics : BASEMOVE * tics;
370
 
371
    if (joyx > 64 || buttonstate[bt_turnright])
372
        controlx += delta;
373
    else if (joyx < -64  || buttonstate[bt_turnleft])
374
        controlx -= delta;
375
    if (joyy > 64 || buttonstate[bt_movebackward])
376
        controly += delta;
377
    else if (joyy < -64 || buttonstate[bt_moveforward])
378
        controly -= delta;
379
}
380
 
381
/*
382
===================
383
=
384
= PollControls
385
=
386
= Gets user or demo input, call once each frame
387
=
388
= controlx              set between -100 and 100 per tic
389
= controly
390
= buttonheld[]  the state of the buttons LAST frame
391
= buttonstate[] the state of the buttons THIS frame
392
=
393
===================
394
*/
395
 
396
void PollControls (void)
397
{
398
    int max, min, i;
399
    byte buttonbits;
400
 
401
    IN_ProcessEvents();
402
 
403
//
404
// get timing info for last frame
405
//
406
    if (demoplayback || demorecord)   // demo recording and playback needs to be constant
407
    {
408
        // wait up to DEMOTICS Wolf tics
9097 turbocat 409
        uint32_t curtime =  uSDL_GetTicks();
8557 maxcodehac 410
        lasttimecount += DEMOTICS;
411
        int32_t timediff = (lasttimecount * 100) / 7 - curtime;
412
        if(timediff > 0)
9097 turbocat 413
            uSDL_Delay(timediff);
8557 maxcodehac 414
 
415
        if(timediff < -2 * DEMOTICS)       // more than 2-times DEMOTICS behind?
416
            lasttimecount = (curtime * 7) / 100;    // yes, set to current timecount
417
 
418
        tics = DEMOTICS;
419
    }
420
    else
421
        CalcTics ();
422
 
423
    controlx = 0;
424
    controly = 0;
425
    memcpy (buttonheld, buttonstate, sizeof (buttonstate));
426
    memset (buttonstate, 0, sizeof (buttonstate));
427
 
428
    if (demoplayback)
429
    {
430
        //
431
        // read commands from demo buffer
432
        //
433
        buttonbits = *demoptr++;
434
        for (i = 0; i < NUMBUTTONS; i++)
435
        {
436
            buttonstate[i] = buttonbits & 1;
437
            buttonbits >>= 1;
438
        }
439
 
440
        controlx = *demoptr++;
441
        controly = *demoptr++;
442
 
443
        if (demoptr == lastdemoptr)
444
            playstate = ex_completed;   // demo is done
445
 
446
        controlx *= (int) tics;
447
        controly *= (int) tics;
448
 
449
        return;
450
    }
451
 
452
 
453
//
454
// get button states
455
//
456
    PollKeyboardButtons ();
457
 
458
    if (mouseenabled && IN_IsInputGrabbed())
459
        PollMouseButtons ();
460
 
461
    if (joystickenabled)
462
        PollJoystickButtons ();
463
 
464
//
465
// get movements
466
//
467
    PollKeyboardMove ();
468
 
469
    if (mouseenabled && IN_IsInputGrabbed())
470
        PollMouseMove ();
471
 
472
    if (joystickenabled)
473
        PollJoystickMove ();
474
 
475
//
476
// bound movement to a maximum
477
//
478
    max = 100 * tics;
479
    min = -max;
480
    if (controlx > max)
481
        controlx = max;
482
    else if (controlx < min)
483
        controlx = min;
484
 
485
    if (controly > max)
486
        controly = max;
487
    else if (controly < min)
488
        controly = min;
489
 
490
    if (demorecord)
491
    {
492
        //
493
        // save info out to demo buffer
494
        //
495
        controlx /= (int) tics;
496
        controly /= (int) tics;
497
 
498
        buttonbits = 0;
499
 
500
        // TODO: Support 32-bit buttonbits
501
        for (i = NUMBUTTONS - 1; i >= 0; i--)
502
        {
503
            buttonbits <<= 1;
504
            if (buttonstate[i])
505
                buttonbits |= 1;
506
        }
507
 
508
        *demoptr++ = buttonbits;
509
        *demoptr++ = controlx;
510
        *demoptr++ = controly;
511
 
512
        if (demoptr >= lastdemoptr - 8)
513
            playstate = ex_completed;
514
        else
515
        {
516
            controlx *= (int) tics;
517
            controly *= (int) tics;
518
        }
519
    }
520
}
521
 
522
 
523
 
524
//==========================================================================
525
 
526
 
527
 
528
///////////////////////////////////////////////////////////////////////////
529
//
530
//      CenterWindow() - Generates a window of a given width & height in the
531
//              middle of the screen
532
//
533
///////////////////////////////////////////////////////////////////////////
534
#define MAXX    320
535
#define MAXY    160
536
 
537
void CenterWindow (word w, word h)
538
{
539
    US_DrawWindow (((MAXX / 8) - w) / 2, ((MAXY / 8) - h) / 2, w, h);
540
}
541
 
542
//===========================================================================
543
 
544
 
545
/*
546
=====================
547
=
548
= CheckKeys
549
=
550
=====================
551
*/
552
 
553
void CheckKeys (void)
554
{
555
    ScanCode scan;
556
 
557
 
558
    if (screenfaded || demoplayback)    // don't do anything with a faded screen
559
        return;
560
 
561
    scan = LastScan;
562
 
563
 
564
#ifdef SPEAR
565
    //
566
    // SECRET CHEAT CODE: TAB-G-F10
567
    //
568
    if (Keyboard[sc_Tab] && Keyboard[sc_G] && Keyboard[sc_F10])
569
    {
570
        WindowH = 160;
571
        if (godmode)
572
        {
573
            Message ("God mode OFF");
574
            SD_PlaySound (NOBONUSSND);
575
        }
576
        else
577
        {
578
            Message ("God mode ON");
579
            SD_PlaySound (ENDBONUS2SND);
580
        }
581
 
582
        IN_Ack ();
583
        godmode ^= 1;
584
        DrawPlayBorderSides ();
585
        IN_ClearKeysDown ();
586
        return;
587
    }
588
#endif
589
 
590
 
591
    //
592
    // SECRET CHEAT CODE: 'MLI'
593
    //
594
    if (Keyboard[sc_M] && Keyboard[sc_L] && Keyboard[sc_I])
595
    {
596
        gamestate.health = 100;
597
        gamestate.ammo = 99;
598
        gamestate.keys = 3;
599
        gamestate.score = 0;
600
        gamestate.TimeCount += 42000L;
601
        GiveWeapon (wp_chaingun);
602
        DrawWeapon ();
603
        DrawHealth ();
604
        DrawKeys ();
605
        DrawAmmo ();
606
        DrawScore ();
607
 
608
        ClearMemory ();
609
        CA_CacheGrChunk (STARTFONT + 1);
610
        ClearSplitVWB ();
611
 
612
        Message (STR_CHEATER1 "\n"
613
                 STR_CHEATER2 "\n\n" STR_CHEATER3 "\n" STR_CHEATER4 "\n" STR_CHEATER5);
614
 
615
        UNCACHEGRCHUNK (STARTFONT + 1);
616
        IN_ClearKeysDown ();
617
        IN_Ack ();
618
 
619
        if (viewsize < 17)
620
            DrawPlayBorder ();
621
    }
622
 
623
    //
624
    // OPEN UP DEBUG KEYS
625
    //
626
#ifdef DEBUGKEYS
627
    if (Keyboard[sc_BackSpace] && Keyboard[sc_LShift] && Keyboard[sc_Alt] && param_debugmode)
628
    {
629
        ClearMemory ();
630
        CA_CacheGrChunk (STARTFONT + 1);
631
        ClearSplitVWB ();
632
 
633
        Message ("Debugging keys are\nnow available!");
634
        UNCACHEGRCHUNK (STARTFONT + 1);
635
        IN_ClearKeysDown ();
636
        IN_Ack ();
637
 
638
        DrawPlayBorderSides ();
639
        DebugOk = 1;
640
    }
641
#endif
642
 
643
    //
644
    // TRYING THE KEEN CHEAT CODE!
645
    //
646
    if (Keyboard[sc_B] && Keyboard[sc_A] && Keyboard[sc_T])
647
    {
648
        ClearMemory ();
649
        CA_CacheGrChunk (STARTFONT + 1);
650
        ClearSplitVWB ();
651
 
652
        Message ("Commander Keen is also\n"
653
                 "available from Apogee, but\n"
654
                 "then, you already know\n" "that - right, Cheatmeister?!");
655
 
656
        UNCACHEGRCHUNK (STARTFONT + 1);
657
        IN_ClearKeysDown ();
658
        IN_Ack ();
659
 
660
        if (viewsize < 18)
661
            DrawPlayBorder ();
662
    }
663
 
664
//
665
// pause key weirdness can't be checked as a scan code
666
//
667
    if(buttonstate[bt_pause]) Paused = true;
668
    if(Paused)
669
    {
670
        int lastoffs = StopMusic();
671
        LatchDrawPic (20 - 4, 80 - 2 * 8, PAUSEDPIC);
672
        VH_UpdateScreen();
673
        IN_Ack ();
674
        Paused = false;
675
        ContinueMusic(lastoffs);
676
        if (MousePresent && IN_IsInputGrabbed())
677
            IN_CenterMouse();     // Clear accumulated mouse movement
678
        lasttimecount = GetTimeCount();
679
        return;
680
    }
681
 
682
//
683
// F1-F7/ESC to enter control panel
684
//
685
    if (
686
#ifndef DEBCHECK
687
           scan == sc_F10 ||
688
#endif
689
           scan == sc_F9 || scan == sc_F7 || scan == sc_F8)     // pop up quit dialog
690
    {
691
        short oldmapon = gamestate.mapon;
692
        short oldepisode = gamestate.episode;
693
        ClearMemory ();
694
        ClearSplitVWB ();
695
        US_ControlPanel (scan);
696
 
697
        DrawPlayBorderSides ();
698
 
699
        SETFONTCOLOR (0, 15);
700
        IN_ClearKeysDown ();
701
        return;
702
    }
703
 
704
    if ((scan >= sc_F1 && scan <= sc_F9) || scan == sc_Escape || buttonstate[bt_esc])
705
    {
706
        int lastoffs = StopMusic ();
707
        ClearMemory ();
708
        VW_FadeOut ();
709
 
710
        US_ControlPanel (buttonstate[bt_esc] ? sc_Escape : scan);
711
 
712
        SETFONTCOLOR (0, 15);
713
        IN_ClearKeysDown ();
714
        VW_FadeOut();
715
        if(viewsize != 21)
716
            DrawPlayScreen ();
717
        if (!startgame && !loadedgame)
718
            ContinueMusic (lastoffs);
719
        if (loadedgame)
720
            playstate = ex_abort;
721
        lasttimecount = GetTimeCount();
722
        if (MousePresent && IN_IsInputGrabbed())
723
            IN_CenterMouse();     // Clear accumulated mouse movement
724
        return;
725
    }
726
 
727
//
728
// TAB-? debug keys
729
//
730
#ifdef DEBUGKEYS
731
    if (Keyboard[sc_Tab] && DebugOk)
732
    {
733
        CA_CacheGrChunk (STARTFONT);
734
        fontnumber = 0;
735
        SETFONTCOLOR (0, 15);
736
        if (DebugKeys () && viewsize < 20)
737
            DrawPlayBorder ();       // dont let the blue borders flash
738
 
739
        if (MousePresent && IN_IsInputGrabbed())
740
            IN_CenterMouse();     // Clear accumulated mouse movement
741
 
742
        lasttimecount = GetTimeCount();
743
        return;
744
    }
745
#endif
746
}
747
 
748
 
749
//===========================================================================
750
 
751
/*
752
#############################################################################
753
 
754
                                  The objlist data structure
755
 
756
#############################################################################
757
 
758
objlist containt structures for every actor currently playing.  The structure
759
is accessed as a linked list starting at *player, ending when ob->next ==
760
NULL.  GetNewObj inserts a new object at the end of the list, meaning that
761
if an actor spawn another actor, the new one WILL get to think and react the
762
same frame.  RemoveObj unlinks the given object and returns it to the free
763
list, but does not damage the objects ->next pointer, so if the current object
764
removes itself, a linked list following loop can still safely get to the
765
next element.
766
 
767
768
 
769
#############################################################################
770
*/
771
 
772
 
773
/*
774
=========================
775
=
776
= InitActorList
777
=
778
= Call to clear out the actor object lists returning them all to the free
779
= list.  Allocates a special spot for the player.
780
=
781
=========================
782
*/
783
 
784
int objcount;
785
 
786
void InitActorList (void)
787
{
788
    int i;
789
 
790
//
791
// init the actor lists
792
//
793
    for (i = 0; i < MAXACTORS; i++)
794
    {
795
        objlist[i].prev = &objlist[i + 1];
796
        objlist[i].next = NULL;
797
    }
798
 
799
    objlist[MAXACTORS - 1].prev = NULL;
800
 
801
    objfreelist = &objlist[0];
802
    lastobj = NULL;
803
 
804
    objcount = 0;
805
 
806
//
807
// give the player the first free spots
808
//
809
    GetNewActor ();
810
    player = newobj;
811
 
812
}
813
 
814
//===========================================================================
815
 
816
/*
817
=========================
818
=
819
= GetNewActor
820
=
821
= Sets the global variable new to point to a free spot in objlist.
822
= The free spot is inserted at the end of the liked list
823
=
824
= When the object list is full, the caller can either have it bomb out ot
825
= return a dummy object pointer that will never get used
826
=
827
=========================
828
*/
829
 
830
void GetNewActor (void)
831
{
832
    if (!objfreelist)
833
        Quit ("GetNewActor: No free spots in objlist!");
834
 
835
    newobj = objfreelist;
836
    objfreelist = newobj->prev;
837
    memset (newobj, 0, sizeof (*newobj));
838
 
839
    if (lastobj)
840
        lastobj->next = newobj;
841
    newobj->prev = lastobj;     // new->next is allready NULL from memset
842
 
843
    newobj->active = ac_no;
844
    lastobj = newobj;
845
 
846
    objcount++;
847
}
848
 
849
//===========================================================================
850
 
851
/*
852
=========================
853
=
854
= RemoveObj
855
=
856
= Add the given object back into the free list, and unlink it from it's
857
= neighbors
858
=
859
=========================
860
*/
861
 
862
void RemoveObj (objtype * gone)
863
{
864
    if (gone == player)
865
        Quit ("RemoveObj: Tried to remove the player!");
866
 
867
    gone->state = NULL;
868
 
869
//
870
// fix the next object's back link
871
//
872
    if (gone == lastobj)
873
        lastobj = (objtype *) gone->prev;
874
    else
875
        gone->next->prev = gone->prev;
876
 
877
//
878
// fix the previous object's forward link
879
//
880
    gone->prev->next = gone->next;
881
 
882
//
883
// add it back in to the free list
884
//
885
    gone->prev = objfreelist;
886
    objfreelist = gone;
887
 
888
    objcount--;
889
}
890
 
891
/*
892
=============================================================================
893
 
894
                                                MUSIC STUFF
895
 
896
=============================================================================
897
*/
898
 
899
 
900
/*
901
=================
902
=
903
= StopMusic
904
=
905
=================
906
*/
907
int StopMusic (void)
908
{
909
    int lastoffs = SD_MusicOff ();
910
 
911
    UNCACHEAUDIOCHUNK (STARTMUSIC + lastmusicchunk);
912
 
913
    return lastoffs;
914
}
915
 
916
//==========================================================================
917
 
918
 
919
/*
920
=================
921
=
922
= StartMusic
923
=
924
=================
925
*/
926
 
927
void StartMusic ()
928
{
929
    SD_MusicOff ();
930
    lastmusicchunk = (musicnames) songs[gamestate.mapon + gamestate.episode * 10];
931
    SD_StartMusic(STARTMUSIC + lastmusicchunk);
932
}
933
 
934
void ContinueMusic (int offs)
935
{
936
    SD_MusicOff ();
937
    lastmusicchunk = (musicnames) songs[gamestate.mapon + gamestate.episode * 10];
938
    SD_ContinueMusic(STARTMUSIC + lastmusicchunk, offs);
939
}
940
 
941
/*
942
=============================================================================
943
 
944
                                        PALETTE SHIFTING STUFF
945
 
946
=============================================================================
947
*/
948
 
949
#define NUMREDSHIFTS    6
950
#define REDSTEPS        8
951
 
952
#define NUMWHITESHIFTS  3
953
#define WHITESTEPS      20
954
#define WHITETICS       6
955
 
956
 
957
SDL_Color redshifts[NUMREDSHIFTS][256];
958
SDL_Color whiteshifts[NUMWHITESHIFTS][256];
959
 
960
int damagecount, bonuscount;
961
boolean palshifted;
962
 
963
/*
964
=====================
965
=
966
= InitRedShifts
967
=
968
=====================
969
*/
970
 
971
void InitRedShifts (void)
972
{
973
    SDL_Color *workptr, *baseptr;
974
    int i, j, delta;
975
 
976
 
977
//
978
// fade through intermediate frames
979
//
980
    for (i = 1; i <= NUMREDSHIFTS; i++)
981
    {
982
        workptr = redshifts[i - 1];
983
        baseptr = gamepal;
984
 
985
        for (j = 0; j <= 255; j++)
986
        {
987
            delta = 256 - baseptr->r;
988
            workptr->r = baseptr->r + delta * i / REDSTEPS;
989
            delta = -baseptr->g;
990
            workptr->g = baseptr->g + delta * i / REDSTEPS;
991
            delta = -baseptr->b;
992
            workptr->b = baseptr->b + delta * i / REDSTEPS;
993
            baseptr++;
994
            workptr++;
995
        }
996
    }
997
 
998
    for (i = 1; i <= NUMWHITESHIFTS; i++)
999
    {
1000
        workptr = whiteshifts[i - 1];
1001
        baseptr = gamepal;
1002
 
1003
        for (j = 0; j <= 255; j++)
1004
        {
1005
            delta = 256 - baseptr->r;
1006
            workptr->r = baseptr->r + delta * i / WHITESTEPS;
1007
            delta = 248 - baseptr->g;
1008
            workptr->g = baseptr->g + delta * i / WHITESTEPS;
1009
            delta = 0-baseptr->b;
1010
            workptr->b = baseptr->b + delta * i / WHITESTEPS;
1011
            baseptr++;
1012
            workptr++;
1013
        }
1014
    }
1015
}
1016
 
1017
 
1018
/*
1019
=====================
1020
=
1021
= ClearPaletteShifts
1022
=
1023
=====================
1024
*/
1025
 
1026
void ClearPaletteShifts (void)
1027
{
1028
    bonuscount = damagecount = 0;
1029
    palshifted = false;
1030
}
1031
 
1032
 
1033
/*
1034
=====================
1035
=
1036
= StartBonusFlash
1037
=
1038
=====================
1039
*/
1040
 
1041
void StartBonusFlash (void)
1042
{
1043
    bonuscount = NUMWHITESHIFTS * WHITETICS;    // white shift palette
1044
}
1045
 
1046
 
1047
/*
1048
=====================
1049
=
1050
= StartDamageFlash
1051
=
1052
=====================
1053
*/
1054
 
1055
void StartDamageFlash (int damage)
1056
{
1057
    damagecount += damage;
1058
}
1059
 
1060
 
1061
/*
1062
=====================
1063
=
1064
= UpdatePaletteShifts
1065
=
1066
=====================
1067
*/
1068
 
1069
void UpdatePaletteShifts (void)
1070
{
1071
    int red, white;
1072
 
1073
    if (bonuscount)
1074
    {
1075
        white = bonuscount / WHITETICS + 1;
1076
        if (white > NUMWHITESHIFTS)
1077
            white = NUMWHITESHIFTS;
1078
        bonuscount -= tics;
1079
        if (bonuscount < 0)
1080
            bonuscount = 0;
1081
    }
1082
    else
1083
        white = 0;
1084
 
1085
 
1086
    if (damagecount)
1087
    {
1088
        red = damagecount / 10 + 1;
1089
        if (red > NUMREDSHIFTS)
1090
            red = NUMREDSHIFTS;
1091
 
1092
        damagecount -= tics;
1093
        if (damagecount < 0)
1094
            damagecount = 0;
1095
    }
1096
    else
1097
        red = 0;
1098
 
1099
    if (red)
1100
    {
1101
        VL_SetPalette (redshifts[red - 1], false);
1102
        palshifted = true;
1103
    }
1104
    else if (white)
1105
    {
1106
        VL_SetPalette (whiteshifts[white - 1], false);
1107
        palshifted = true;
1108
    }
1109
    else if (palshifted)
1110
    {
1111
        VL_SetPalette (gamepal, false);        // back to normal
1112
        palshifted = false;
1113
    }
1114
}
1115
 
1116
 
1117
/*
1118
=====================
1119
=
1120
= FinishPaletteShifts
1121
=
1122
= Resets palette to normal if needed
1123
=
1124
=====================
1125
*/
1126
 
1127
void FinishPaletteShifts (void)
1128
{
1129
    if (palshifted)
1130
    {
1131
        palshifted = 0;
1132
        VL_SetPalette (gamepal, true);
1133
    }
1134
}
1135
 
1136
 
1137
/*
1138
=============================================================================
1139
 
1140
                                                CORE PLAYLOOP
1141
 
1142
=============================================================================
1143
*/
1144
 
1145
 
1146
/*
1147
=====================
1148
=
1149
= DoActor
1150
=
1151
=====================
1152
*/
1153
 
1154
void DoActor (objtype * ob)
1155
{
1156
    void (*think) (objtype *);
1157
 
1158
    if (!ob->active && !areabyplayer[ob->areanumber])
1159
        return;
1160
 
1161
    if (!(ob->flags & (FL_NONMARK | FL_NEVERMARK)))
1162
        actorat[ob->tilex][ob->tiley] = NULL;
1163
 
1164
//
1165
// non transitional object
1166
//
1167
 
1168
    if (!ob->ticcount)
1169
    {
1170
        think = (void (*)(objtype *)) ob->state->think;
1171
        if (think)
1172
        {
1173
            think (ob);
1174
            if (!ob->state)
1175
            {
1176
                RemoveObj (ob);
1177
                return;
1178
            }
1179
        }
1180
 
1181
        if (ob->flags & FL_NEVERMARK)
1182
            return;
1183
 
1184
        if ((ob->flags & FL_NONMARK) && actorat[ob->tilex][ob->tiley])
1185
            return;
1186
 
1187
        actorat[ob->tilex][ob->tiley] = ob;
1188
        return;
1189
    }
1190
 
1191
//
1192
// transitional object
1193
//
1194
    ob->ticcount -= (short) tics;
1195
    while (ob->ticcount <= 0)
1196
    {
1197
        think = (void (*)(objtype *)) ob->state->action;        // end of state action
1198
        if (think)
1199
        {
1200
            think (ob);
1201
            if (!ob->state)
1202
            {
1203
                RemoveObj (ob);
1204
                return;
1205
            }
1206
        }
1207
 
1208
        ob->state = ob->state->next;
1209
 
1210
        if (!ob->state)
1211
        {
1212
            RemoveObj (ob);
1213
            return;
1214
        }
1215
 
1216
        if (!ob->state->tictime)
1217
        {
1218
            ob->ticcount = 0;
1219
            goto think;
1220
        }
1221
 
1222
        ob->ticcount += ob->state->tictime;
1223
    }
1224
 
1225
think:
1226
    //
1227
    // think
1228
    //
1229
    think = (void (*)(objtype *)) ob->state->think;
1230
    if (think)
1231
    {
1232
        think (ob);
1233
        if (!ob->state)
1234
        {
1235
            RemoveObj (ob);
1236
            return;
1237
        }
1238
    }
1239
 
1240
    if (ob->flags & FL_NEVERMARK)
1241
        return;
1242
 
1243
    if ((ob->flags & FL_NONMARK) && actorat[ob->tilex][ob->tiley])
1244
        return;
1245
 
1246
    actorat[ob->tilex][ob->tiley] = ob;
1247
}
1248
 
1249
//==========================================================================
1250
 
1251
 
1252
/*
1253
===================
1254
=
1255
= PlayLoop
1256
=
1257
===================
1258
*/
1259
int32_t funnyticount;
1260
 
1261
 
1262
void PlayLoop (void)
1263
{
1264
#if defined(USE_FEATUREFLAGS) && defined(USE_CLOUDSKY)
1265
    if(GetFeatureFlags() & FF_CLOUDSKY)
1266
        InitSky();
1267
#endif
1268
 
1269
#ifdef USE_SHADING
1270
    InitLevelShadeTable();
1271
#endif
1272
 
1273
    playstate = ex_stillplaying;
1274
    lasttimecount = GetTimeCount();
1275
    frameon = 0;
1276
    anglefrac = 0;
1277
    facecount = 0;
1278
    funnyticount = 0;
1279
    memset (buttonstate, 0, sizeof (buttonstate));
1280
    ClearPaletteShifts ();
1281
 
1282
    if (MousePresent && IN_IsInputGrabbed())
1283
        IN_CenterMouse();         // Clear accumulated mouse movement
1284
 
1285
    if (demoplayback)
1286
        IN_StartAck ();
1287
 
1288
    do
1289
    {
1290
        PollControls ();
1291
 
1292
//
1293
// actor thinking
1294
//
1295
        madenoise = false;
1296
 
1297
        MoveDoors ();
1298
        MovePWalls ();
1299
 
1300
        for (obj = player; obj; obj = obj->next)
1301
            DoActor (obj);
1302
 
1303
        UpdatePaletteShifts ();
1304
 
1305
        ThreeDRefresh ();
1306
 
1307
        //
1308
        // MAKE FUNNY FACE IF BJ DOESN'T MOVE FOR AWHILE
1309
        //
1310
#ifdef SPEAR
1311
        funnyticount += tics;
1312
        if (funnyticount > 30l * 70)
1313
        {
1314
            funnyticount = 0;
1315
            if(viewsize != 21)
1316
                StatusDrawFace(BJWAITING1PIC + (US_RndT () & 1));
1317
            facecount = 0;
1318
        }
1319
#endif
1320
 
1321
        gamestate.TimeCount += tics;
1322
 
1323
        UpdateSoundLoc ();      // JAB
1324
        if (screenfaded)
1325
            VW_FadeIn ();
1326
 
1327
        CheckKeys ();
1328
 
1329
//
1330
// debug aids
1331
//
1332
        if (singlestep)
1333
        {
1334
            VW_WaitVBL (singlestep);
1335
            lasttimecount = GetTimeCount();
1336
        }
1337
        if (extravbls)
1338
            VW_WaitVBL (extravbls);
1339
 
1340
        if (demoplayback)
1341
        {
1342
            if (IN_CheckAck ())
1343
            {
1344
                IN_ClearKeysDown ();
1345
                playstate = ex_abort;
1346
            }
1347
        }
1348
    }
1349
    while (!playstate && !startgame);
1350
 
1351
    if (playstate != ex_died)
1352
        FinishPaletteShifts ();
1353
}