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