summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/progs/wolf3d/wl_game.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/progs/wolf3d/wl_game.c')
-rw-r--r--apps/plugins/sdl/progs/wolf3d/wl_game.c1601
1 files changed, 1601 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/wolf3d/wl_game.c b/apps/plugins/sdl/progs/wolf3d/wl_game.c
new file mode 100644
index 0000000000..445cf00153
--- /dev/null
+++ b/apps/plugins/sdl/progs/wolf3d/wl_game.c
@@ -0,0 +1,1601 @@
1// WL_GAME.C
2
3#include "wl_def.h"
4#pragma hdrstop
5
6
7/*
8=============================================================================
9
10 LOCAL CONSTANTS
11
12=============================================================================
13*/
14
15
16/*
17=============================================================================
18
19 GLOBAL VARIABLES
20
21=============================================================================
22*/
23
24boolean ingame,fizzlein;
25gametype gamestate;
26byte bordercol=VIEWCOLOR; // color of the Change View/Ingame border
27
28#ifdef SPEAR
29int32_t spearx,speary;
30unsigned spearangle;
31boolean spearflag;
32#endif
33
34#ifdef USE_FEATUREFLAGS
35int ffDataTopLeft, ffDataTopRight, ffDataBottomLeft, ffDataBottomRight;
36#endif
37
38//
39// ELEVATOR BACK MAPS - REMEMBER (-1)!!
40//
41int ElevatorBackTo[]={1,1,7,3,5,3};
42
43void SetupGameLevel (void);
44void DrawPlayScreen (void);
45void LoadLatchMem (void);
46void GameLoop (void);
47
48/*
49=============================================================================
50
51 LOCAL VARIABLES
52
53=============================================================================
54*/
55
56
57
58//===========================================================================
59//===========================================================================
60
61
62/*
63==========================
64=
65= SetSoundLoc - Given the location of an object (in terms of global
66= coordinates, held in globalsoundx and globalsoundy), munges the values
67= for an approximate distance from the left and right ear, and puts
68= those values into leftchannel and rightchannel.
69=
70= JAB
71=
72==========================
73*/
74
75int leftchannel, rightchannel;
76#define ATABLEMAX 15
77byte righttable[ATABLEMAX][ATABLEMAX * 2] = {
78{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 0, 0, 0, 0, 0, 1, 3, 5, 8, 8, 8, 8, 8, 8, 8, 8},
79{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 6, 4, 0, 0, 0, 0, 0, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8},
80{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 4, 1, 0, 0, 0, 1, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8},
81{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 5, 4, 2, 1, 0, 1, 2, 3, 5, 7, 8, 8, 8, 8, 8, 8, 8, 8},
82{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 5, 4, 3, 2, 2, 3, 3, 5, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8},
83{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 4, 4, 4, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8},
84{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
85{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
86{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
87{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
88{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
89{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
90{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
91{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
92{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
93};
94byte lefttable[ATABLEMAX][ATABLEMAX * 2] = {
95{ 8, 8, 8, 8, 8, 8, 8, 8, 5, 3, 1, 0, 0, 0, 0, 0, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
96{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 0, 0, 0, 0, 0, 4, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
97{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 1, 0, 0, 0, 1, 4, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
98{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 3, 2, 1, 0, 1, 2, 4, 5, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
99{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 5, 3, 3, 2, 2, 3, 4, 5, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8},
100{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 5, 4, 4, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8},
101{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 6, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8},
102{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
103{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
104{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
105{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
106{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
107{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
108{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
109{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
110};
111
112void
113SetSoundLoc(fixed gx,fixed gy)
114{
115 fixed xt,yt;
116 int x,y;
117
118//
119// translate point to view centered coordinates
120//
121 gx -= viewx;
122 gy -= viewy;
123
124//
125// calculate newx
126//
127 xt = FixedMul(gx,viewcos);
128 yt = FixedMul(gy,viewsin);
129 x = (xt - yt) >> TILESHIFT;
130
131//
132// calculate newy
133//
134 xt = FixedMul(gx,viewsin);
135 yt = FixedMul(gy,viewcos);
136 y = (yt + xt) >> TILESHIFT;
137
138 if (y >= ATABLEMAX)
139 y = ATABLEMAX - 1;
140 else if (y <= -ATABLEMAX)
141 y = -ATABLEMAX;
142 if (x < 0)
143 x = -x;
144 if (x >= ATABLEMAX)
145 x = ATABLEMAX - 1;
146 leftchannel = lefttable[x][y + ATABLEMAX];
147 rightchannel = righttable[x][y + ATABLEMAX];
148
149#if 0
150 CenterWindow(8,1);
151 US_PrintSigned(leftchannel);
152 US_Print(",");
153 US_PrintSigned(rightchannel);
154 VW_UpdateScreen();
155#endif
156}
157
158/*
159==========================
160=
161= SetSoundLocGlobal - Sets up globalsoundx & globalsoundy and then calls
162= UpdateSoundLoc() to transform that into relative channel volumes. Those
163= values are then passed to the Sound Manager so that they'll be used for
164= the next sound played (if possible).
165=
166= JAB
167=
168==========================
169*/
170void PlaySoundLocGlobal(word s,fixed gx,fixed gy)
171{
172 SetSoundLoc(gx, gy);
173 SD_PositionSound(leftchannel, rightchannel);
174
175 int channel = SD_PlaySound((soundnames) s);
176 if(channel)
177 {
178 channelSoundPos[channel - 1].globalsoundx = gx;
179 channelSoundPos[channel - 1].globalsoundy = gy;
180 channelSoundPos[channel - 1].valid = 1;
181 }
182}
183
184void UpdateSoundLoc(void)
185{
186/* if (SoundPositioned)
187 {
188 SetSoundLoc(globalsoundx,globalsoundy);
189 SD_SetPosition(leftchannel,rightchannel);
190 }*/
191
192 for(int i = 0; i < MIX_CHANNELS; i++)
193 {
194 if(channelSoundPos[i].valid)
195 {
196 SetSoundLoc(channelSoundPos[i].globalsoundx,
197 channelSoundPos[i].globalsoundy);
198 SD_SetPosition(i, leftchannel, rightchannel);
199 }
200 }
201}
202
203/*
204** JAB End
205*/
206
207/*
208==========================
209=
210= ScanInfoPlane
211=
212= Spawn all actors and mark down special places
213=
214==========================
215*/
216
217static void ScanInfoPlane(void)
218{
219 unsigned x,y;
220 int tile;
221 word *start;
222
223 start = mapsegs[1];
224 for (y=0;y<mapheight;y++)
225 {
226 for (x=0;x<mapwidth;x++)
227 {
228 tile = *start++;
229 if (!tile)
230 continue;
231
232 switch (tile)
233 {
234 case 19:
235 case 20:
236 case 21:
237 case 22:
238 SpawnPlayer(x,y,NORTH+tile-19);
239 break;
240
241 case 23:
242 case 24:
243 case 25:
244 case 26:
245 case 27:
246 case 28:
247 case 29:
248 case 30:
249
250 case 31:
251 case 32:
252 case 33:
253 case 34:
254 case 35:
255 case 36:
256 case 37:
257 case 38:
258
259 case 39:
260 case 40:
261 case 41:
262 case 42:
263 case 43:
264 case 44:
265 case 45:
266 case 46:
267
268 case 47:
269 case 48:
270 case 49:
271 case 50:
272 case 51:
273 case 52:
274 case 53:
275 case 54:
276
277 case 55:
278 case 56:
279 case 57:
280 case 58:
281 case 59:
282 case 60:
283 case 61:
284 case 62:
285
286 case 63:
287 case 64:
288 case 65:
289 case 66:
290 case 67:
291 case 68:
292 case 69:
293 case 70:
294 case 71:
295 case 72:
296#ifdef SPEAR
297 case 73: // TRUCK AND SPEAR!
298 case 74:
299#elif defined(USE_DIR3DSPR) // just for the example
300 case 73:
301#endif
302 SpawnStatic(x,y,tile-23);
303 break;
304
305//
306// P wall
307//
308 case 98:
309 if (!loadedgame)
310 gamestate.secrettotal++;
311 break;
312
313//
314// guard
315//
316 case 180:
317 case 181:
318 case 182:
319 case 183:
320 if (gamestate.difficulty<gd_hard)
321 break;
322 tile -= 36;
323 case 144:
324 case 145:
325 case 146:
326 case 147:
327 if (gamestate.difficulty<gd_medium)
328 break;
329 tile -= 36;
330 case 108:
331 case 109:
332 case 110:
333 case 111:
334 SpawnStand(en_guard,x,y,tile-108);
335 break;
336
337
338 case 184:
339 case 185:
340 case 186:
341 case 187:
342 if (gamestate.difficulty<gd_hard)
343 break;
344 tile -= 36;
345 case 148:
346 case 149:
347 case 150:
348 case 151:
349 if (gamestate.difficulty<gd_medium)
350 break;
351 tile -= 36;
352 case 112:
353 case 113:
354 case 114:
355 case 115:
356 SpawnPatrol(en_guard,x,y,tile-112);
357 break;
358
359 case 124:
360 SpawnDeadGuard (x,y);
361 break;
362//
363// officer
364//
365 case 188:
366 case 189:
367 case 190:
368 case 191:
369 if (gamestate.difficulty<gd_hard)
370 break;
371 tile -= 36;
372 case 152:
373 case 153:
374 case 154:
375 case 155:
376 if (gamestate.difficulty<gd_medium)
377 break;
378 tile -= 36;
379 case 116:
380 case 117:
381 case 118:
382 case 119:
383 SpawnStand(en_officer,x,y,tile-116);
384 break;
385
386
387 case 192:
388 case 193:
389 case 194:
390 case 195:
391 if (gamestate.difficulty<gd_hard)
392 break;
393 tile -= 36;
394 case 156:
395 case 157:
396 case 158:
397 case 159:
398 if (gamestate.difficulty<gd_medium)
399 break;
400 tile -= 36;
401 case 120:
402 case 121:
403 case 122:
404 case 123:
405 SpawnPatrol(en_officer,x,y,tile-120);
406 break;
407
408
409//
410// ss
411//
412 case 198:
413 case 199:
414 case 200:
415 case 201:
416 if (gamestate.difficulty<gd_hard)
417 break;
418 tile -= 36;
419 case 162:
420 case 163:
421 case 164:
422 case 165:
423 if (gamestate.difficulty<gd_medium)
424 break;
425 tile -= 36;
426 case 126:
427 case 127:
428 case 128:
429 case 129:
430 SpawnStand(en_ss,x,y,tile-126);
431 break;
432
433
434 case 202:
435 case 203:
436 case 204:
437 case 205:
438 if (gamestate.difficulty<gd_hard)
439 break;
440 tile -= 36;
441 case 166:
442 case 167:
443 case 168:
444 case 169:
445 if (gamestate.difficulty<gd_medium)
446 break;
447 tile -= 36;
448 case 130:
449 case 131:
450 case 132:
451 case 133:
452 SpawnPatrol(en_ss,x,y,tile-130);
453 break;
454
455//
456// dogs
457//
458 case 206:
459 case 207:
460 case 208:
461 case 209:
462 if (gamestate.difficulty<gd_hard)
463 break;
464 tile -= 36;
465 case 170:
466 case 171:
467 case 172:
468 case 173:
469 if (gamestate.difficulty<gd_medium)
470 break;
471 tile -= 36;
472 case 134:
473 case 135:
474 case 136:
475 case 137:
476 SpawnStand(en_dog,x,y,tile-134);
477 break;
478
479
480 case 210:
481 case 211:
482 case 212:
483 case 213:
484 if (gamestate.difficulty<gd_hard)
485 break;
486 tile -= 36;
487 case 174:
488 case 175:
489 case 176:
490 case 177:
491 if (gamestate.difficulty<gd_medium)
492 break;
493 tile -= 36;
494 case 138:
495 case 139:
496 case 140:
497 case 141:
498 SpawnPatrol(en_dog,x,y,tile-138);
499 break;
500
501//
502// boss
503//
504#ifndef SPEAR
505 case 214:
506 SpawnBoss (x,y);
507 break;
508 case 197:
509 SpawnGretel (x,y);
510 break;
511 case 215:
512 SpawnGift (x,y);
513 break;
514 case 179:
515 SpawnFat (x,y);
516 break;
517 case 196:
518 SpawnSchabbs (x,y);
519 break;
520 case 160:
521 SpawnFakeHitler (x,y);
522 break;
523 case 178:
524 SpawnHitler (x,y);
525 break;
526#else
527 case 106:
528 SpawnSpectre (x,y);
529 break;
530 case 107:
531 SpawnAngel (x,y);
532 break;
533 case 125:
534 SpawnTrans (x,y);
535 break;
536 case 142:
537 SpawnUber (x,y);
538 break;
539 case 143:
540 SpawnWill (x,y);
541 break;
542 case 161:
543 SpawnDeath (x,y);
544 break;
545
546#endif
547
548//
549// mutants
550//
551 case 252:
552 case 253:
553 case 254:
554 case 255:
555 if (gamestate.difficulty<gd_hard)
556 break;
557 tile -= 18;
558 case 234:
559 case 235:
560 case 236:
561 case 237:
562 if (gamestate.difficulty<gd_medium)
563 break;
564 tile -= 18;
565 case 216:
566 case 217:
567 case 218:
568 case 219:
569 SpawnStand(en_mutant,x,y,tile-216);
570 break;
571
572 case 256:
573 case 257:
574 case 258:
575 case 259:
576 if (gamestate.difficulty<gd_hard)
577 break;
578 tile -= 18;
579 case 238:
580 case 239:
581 case 240:
582 case 241:
583 if (gamestate.difficulty<gd_medium)
584 break;
585 tile -= 18;
586 case 220:
587 case 221:
588 case 222:
589 case 223:
590 SpawnPatrol(en_mutant,x,y,tile-220);
591 break;
592
593//
594// ghosts
595//
596#ifndef SPEAR
597 case 224:
598 SpawnGhosts (en_blinky,x,y);
599 break;
600 case 225:
601 SpawnGhosts (en_clyde,x,y);
602 break;
603 case 226:
604 SpawnGhosts (en_pinky,x,y);
605 break;
606 case 227:
607 SpawnGhosts (en_inky,x,y);
608 break;
609#endif
610 }
611 }
612 }
613}
614
615//==========================================================================
616
617/*
618==================
619=
620= SetupGameLevel
621=
622==================
623*/
624
625void SetupGameLevel (void)
626{
627 int x,y;
628 word *map;
629 word tile;
630
631
632 if (!loadedgame)
633 {
634 gamestate.TimeCount
635 = gamestate.secrettotal
636 = gamestate.killtotal
637 = gamestate.treasuretotal
638 = gamestate.secretcount
639 = gamestate.killcount
640 = gamestate.treasurecount
641 = pwallstate = pwallpos = facetimes = 0;
642 LastAttacker = NULL;
643 killerobj = NULL;
644 }
645
646 if (demoplayback || demorecord)
647 US_InitRndT (false);
648 else
649 US_InitRndT (true);
650
651//
652// load the level
653//
654 CA_CacheMap (gamestate.mapon+10*gamestate.episode);
655 mapon-=gamestate.episode*10;
656
657#ifdef USE_FEATUREFLAGS
658 // Temporary definition to make things clearer
659 #define MXX MAPSIZE - 1
660
661 // Read feature flags data from map corners and overwrite corners with adjacent tiles
662 ffDataTopLeft = MAPSPOT(0, 0, 0); MAPSPOT(0, 0, 0) = MAPSPOT(1, 0, 0);
663 ffDataTopRight = MAPSPOT(MXX, 0, 0); MAPSPOT(MXX, 0, 0) = MAPSPOT(MXX, 1, 0);
664 ffDataBottomRight = MAPSPOT(MXX, MXX, 0); MAPSPOT(MXX, MXX, 0) = MAPSPOT(MXX - 1, MXX, 0);
665 ffDataBottomLeft = MAPSPOT(0, MXX, 0); MAPSPOT(0, MXX, 0) = MAPSPOT(0, MXX - 1, 0);
666
667 #undef MXX
668#endif
669
670//
671// copy the wall data to a data segment array
672//
673 memset (tilemap,0,sizeof(tilemap));
674 memset (actorat,0,sizeof(actorat));
675 map = mapsegs[0];
676 for (y=0;y<mapheight;y++)
677 {
678 for (x=0;x<mapwidth;x++)
679 {
680 tile = *map++;
681 if (tile<AREATILE)
682 {
683 // solid wall
684 tilemap[x][y] = (byte) tile;
685 actorat[x][y] = (objtype *)(uintptr_t) tile;
686 }
687 else
688 {
689 // area floor
690 tilemap[x][y] = 0;
691 actorat[x][y] = 0;
692 }
693 }
694 }
695
696//
697// spawn doors
698//
699 InitActorList (); // start spawning things with a clean slate
700 InitDoorList ();
701 InitStaticList ();
702
703 map = mapsegs[0];
704 for (y=0;y<mapheight;y++)
705 {
706 for (x=0;x<mapwidth;x++)
707 {
708 tile = *map++;
709 if (tile >= 90 && tile <= 101)
710 {
711 // door
712 switch (tile)
713 {
714 case 90:
715 case 92:
716 case 94:
717 case 96:
718 case 98:
719 case 100:
720 SpawnDoor (x,y,1,(tile-90)/2);
721 break;
722 case 91:
723 case 93:
724 case 95:
725 case 97:
726 case 99:
727 case 101:
728 SpawnDoor (x,y,0,(tile-91)/2);
729 break;
730 }
731 }
732 }
733 }
734
735//
736// spawn actors
737//
738 ScanInfoPlane ();
739
740
741//
742// take out the ambush markers
743//
744 map = mapsegs[0];
745 for (y=0;y<mapheight;y++)
746 {
747 for (x=0;x<mapwidth;x++)
748 {
749 tile = *map++;
750 if (tile == AMBUSHTILE)
751 {
752 tilemap[x][y] = 0;
753 if ( (unsigned)(uintptr_t)actorat[x][y] == AMBUSHTILE)
754 actorat[x][y] = NULL;
755
756 if (*map >= AREATILE)
757 tile = *map;
758 if (*(map-1-mapwidth) >= AREATILE)
759 tile = *(map-1-mapwidth);
760 if (*(map-1+mapwidth) >= AREATILE)
761 tile = *(map-1+mapwidth);
762 if ( *(map-2) >= AREATILE)
763 tile = *(map-2);
764
765 *(map-1) = tile;
766 }
767 }
768 }
769
770
771//
772// have the caching manager load and purge stuff to make sure all marks
773// are in memory
774//
775 CA_LoadAllSounds ();
776}
777
778
779//==========================================================================
780
781
782/*
783===================
784=
785= DrawPlayBorderSides
786=
787= To fix window overwrites
788=
789===================
790*/
791void DrawPlayBorderSides(void)
792{
793 if(viewsize == 21) return;
794
795 const int sw = screenWidth;
796 const int sh = screenHeight;
797 const int vw = viewwidth;
798 const int vh = viewheight;
799 const int px = scaleFactor; // size of one "pixel"
800
801 const int h = sh - px * STATUSLINES;
802 const int xl = sw / 2 - vw / 2;
803 const int yl = (h - vh) / 2;
804
805 if(xl != 0)
806 {
807 VWB_BarScaledCoord(0, 0, xl - px, h, bordercol); // left side
808 VWB_BarScaledCoord(xl + vw + px, 0, xl - px * 2, h, bordercol); // right side
809 }
810
811 if(yl != 0)
812 {
813 VWB_BarScaledCoord(0, 0, sw, yl - px, bordercol); // upper side
814 VWB_BarScaledCoord(0, yl + vh + px, sw, yl - px, bordercol); // lower side
815 }
816
817 if(xl != 0)
818 {
819 // Paint game view border lines
820 VWB_BarScaledCoord(xl - px, yl - px, vw + px, px, 0); // upper border
821 VWB_BarScaledCoord(xl, yl + vh, vw + px, px, bordercol - 2); // lower border
822 VWB_BarScaledCoord(xl - px, yl - px, px, vh + px, 0); // left border
823 VWB_BarScaledCoord(xl + vw, yl - px, px, vh + px * 2, bordercol - 2); // right border
824 VWB_BarScaledCoord(xl - px, yl + vh, px, px, bordercol - 3); // lower left highlight
825 }
826 else
827 {
828 // Just paint a lower border line
829 VWB_BarScaledCoord(0, yl+vh, vw, px, bordercol-2); // lower border
830 }
831}
832
833
834/*
835===================
836=
837= DrawStatusBorder
838=
839===================
840*/
841
842void DrawStatusBorder (byte color)
843{
844 int statusborderw = (screenWidth-scaleFactor*320)/2;
845
846 VWB_BarScaledCoord (0,0,screenWidth,screenHeight-scaleFactor*(STATUSLINES-3),color);
847 VWB_BarScaledCoord (0,screenHeight-scaleFactor*(STATUSLINES-3),
848 statusborderw+scaleFactor*8,scaleFactor*(STATUSLINES-4),color);
849 VWB_BarScaledCoord (0,screenHeight-scaleFactor*2,screenWidth,scaleFactor*2,color);
850 VWB_BarScaledCoord (screenWidth-statusborderw-scaleFactor*8, screenHeight-scaleFactor*(STATUSLINES-3),
851 statusborderw+scaleFactor*8,scaleFactor*(STATUSLINES-4),color);
852
853 VWB_BarScaledCoord (statusborderw+scaleFactor*9, screenHeight-scaleFactor*3,
854 scaleFactor*97, scaleFactor*1, color-1);
855 VWB_BarScaledCoord (statusborderw+scaleFactor*106, screenHeight-scaleFactor*3,
856 scaleFactor*161, scaleFactor*1, color-2);
857 VWB_BarScaledCoord (statusborderw+scaleFactor*267, screenHeight-scaleFactor*3,
858 scaleFactor*44, scaleFactor*1, color-3);
859 VWB_BarScaledCoord (screenWidth-statusborderw-scaleFactor*9, screenHeight-scaleFactor*(STATUSLINES-4),
860 scaleFactor*1, scaleFactor*20, color-2);
861 VWB_BarScaledCoord (screenWidth-statusborderw-scaleFactor*9, screenHeight-scaleFactor*(STATUSLINES/2-4),
862 scaleFactor*1, scaleFactor*14, color-3);
863}
864
865
866/*
867===================
868=
869= DrawPlayBorder
870=
871===================
872*/
873
874void DrawPlayBorder (void)
875{
876 const int px = scaleFactor; // size of one "pixel"
877
878 if (bordercol != VIEWCOLOR)
879 DrawStatusBorder(bordercol);
880 else
881 {
882 const int statusborderw = (screenWidth-px*320)/2;
883 VWB_BarScaledCoord (0, screenHeight-px*STATUSLINES,
884 statusborderw+px*8, px*STATUSLINES, bordercol);
885 VWB_BarScaledCoord (screenWidth-statusborderw-px*8, screenHeight-px*STATUSLINES,
886 statusborderw+px*8, px*STATUSLINES, bordercol);
887 }
888
889 if((unsigned) viewheight == screenHeight) return;
890
891 VWB_BarScaledCoord (0,0,screenWidth,screenHeight-px*STATUSLINES,bordercol);
892
893 const int xl = screenWidth/2-viewwidth/2;
894 const int yl = (screenHeight-px*STATUSLINES-viewheight)/2;
895 VWB_BarScaledCoord (xl,yl,viewwidth,viewheight,0);
896
897 if(xl != 0)
898 {
899 // Paint game view border lines
900 VWB_BarScaledCoord(xl-px, yl-px, viewwidth+px, px, 0); // upper border
901 VWB_BarScaledCoord(xl, yl+viewheight, viewwidth+px, px, bordercol-2); // lower border
902 VWB_BarScaledCoord(xl-px, yl-px, px, viewheight+px, 0); // left border
903 VWB_BarScaledCoord(xl+viewwidth, yl-px, px, viewheight+2*px, bordercol-2); // right border
904 VWB_BarScaledCoord(xl-px, yl+viewheight, px, px, bordercol-3); // lower left highlight
905 }
906 else
907 {
908 // Just paint a lower border line
909 VWB_BarScaledCoord(0, yl+viewheight, viewwidth, px, bordercol-2); // lower border
910 }
911}
912
913
914/*
915===================
916=
917= DrawPlayScreen
918=
919===================
920*/
921
922void DrawPlayScreen (void)
923{
924 VWB_DrawPicScaledCoord ((screenWidth-scaleFactor*320)/2,screenHeight-scaleFactor*STATUSLINES,STATUSBARPIC);
925 DrawPlayBorder ();
926
927 DrawFace ();
928 DrawHealth ();
929 DrawLives ();
930 DrawLevel ();
931 DrawAmmo ();
932 DrawKeys ();
933 DrawWeapon ();
934 DrawScore ();
935}
936
937// Uses LatchDrawPic instead of StatusDrawPic
938void LatchNumberHERE (int x, int y, unsigned width, int32_t number)
939{
940 unsigned length,c;
941 char str[20];
942
943 ltoa (number,str,10);
944
945 length = (unsigned) strlen (str);
946
947 while (length<width)
948 {
949 LatchDrawPic (x,y,N_BLANKPIC);
950 x++;
951 width--;
952 }
953
954 c = length <= width ? 0 : length-width;
955
956 while (c<length)
957 {
958 LatchDrawPic (x,y,str[c]-'0'+ N_0PIC);
959 x++;
960 c++;
961 }
962}
963
964void ShowActStatus()
965{
966 // Draw status bar without borders
967 byte *source = grsegs[STATUSBARPIC];
968 int picnum = STATUSBARPIC - STARTPICS;
969 int width = pictable[picnum].width;
970 int height = pictable[picnum].height;
971 int destx = (screenWidth-scaleFactor*320)/2 + 9 * scaleFactor;
972 int desty = screenHeight - (height - 4) * scaleFactor;
973 VL_MemToScreenScaledCoord_ex(source, width, height, 9, 4, destx, desty, width - 18, height - 7);
974
975 ingame = false;
976 DrawFace ();
977 DrawHealth ();
978 DrawLives ();
979 DrawLevel ();
980 DrawAmmo ();
981 DrawKeys ();
982 DrawWeapon ();
983 DrawScore ();
984 ingame = true;
985}
986
987
988//==========================================================================
989
990/*
991==================
992=
993= StartDemoRecord
994=
995==================
996*/
997
998char demoname[13] = "DEMO?.";
999
1000#ifndef REMDEBUG
1001#define MAXDEMOSIZE 8192
1002
1003void StartDemoRecord (int levelnumber)
1004{
1005 demobuffer=malloc(MAXDEMOSIZE);
1006 CHECKMALLOCRESULT(demobuffer);
1007 demoptr = (int8_t *) demobuffer;
1008 lastdemoptr = demoptr+MAXDEMOSIZE;
1009
1010 *demoptr = levelnumber;
1011 demoptr += 4; // leave space for length
1012 demorecord = true;
1013}
1014
1015
1016/*
1017==================
1018=
1019= FinishDemoRecord
1020=
1021==================
1022*/
1023
1024void FinishDemoRecord (void)
1025{
1026 int32_t length,level;
1027
1028 demorecord = false;
1029
1030 length = (int32_t) (demoptr - (int8_t *)demobuffer);
1031
1032 demoptr = ((int8_t *)demobuffer)+1;
1033 demoptr[0] = (int8_t) length;
1034 demoptr[1] = (int8_t) (length >> 8);
1035 demoptr[2] = 0;
1036
1037 VW_FadeIn();
1038 CenterWindow(24,3);
1039 PrintY+=6;
1040 fontnumber=0;
1041 SETFONTCOLOR(0,15);
1042 US_Print(" Demo number (0-9): ");
1043 VW_UpdateScreen();
1044
1045 if (US_LineInput (px,py,str,NULL,true,1,0))
1046 {
1047 level = atoi (str);
1048 if (level>=0 && level<=9)
1049 {
1050 demoname[4] = (char)('0'+level);
1051 CA_WriteFile (demoname,demobuffer,length);
1052 }
1053 }
1054
1055 free(demobuffer);
1056}
1057
1058//==========================================================================
1059
1060/*
1061==================
1062=
1063= RecordDemo
1064=
1065= Fades the screen out, then starts a demo. Exits with the screen faded
1066=
1067==================
1068*/
1069
1070void RecordDemo (void)
1071{
1072 int level,esc,maps;
1073
1074 CenterWindow(26,3);
1075 PrintY+=6;
1076 CA_CacheGrChunk(STARTFONT);
1077 fontnumber=0;
1078 SETFONTCOLOR(0,15);
1079#ifndef SPEAR
1080#ifdef UPLOAD
1081 US_Print(" Demo which level(1-10): "); maps = 10;
1082#else
1083 US_Print(" Demo which level(1-60): "); maps = 60;
1084#endif
1085#else
1086 US_Print(" Demo which level(1-21): "); maps = 21;
1087#endif
1088 VW_UpdateScreen();
1089 VW_FadeIn ();
1090 esc = !US_LineInput (px,py,str,NULL,true,2,0);
1091 if (esc)
1092 return;
1093
1094 level = atoi (str);
1095 level--;
1096
1097 if (level >= maps || level < 0)
1098 return;
1099
1100 VW_FadeOut ();
1101
1102#ifndef SPEAR
1103 NewGame (gd_hard,level/10);
1104 gamestate.mapon = level%10;
1105#else
1106 NewGame (gd_hard,0);
1107 gamestate.mapon = level;
1108#endif
1109
1110 StartDemoRecord (level);
1111
1112 DrawPlayScreen ();
1113 VW_FadeIn ();
1114
1115 startgame = false;
1116 demorecord = true;
1117
1118 SetupGameLevel ();
1119 StartMusic ();
1120
1121 if(usedoublebuffering) VH_UpdateScreen();
1122 fizzlein = true;
1123
1124 PlayLoop ();
1125
1126 demoplayback = false;
1127
1128 StopMusic ();
1129 VW_FadeOut ();
1130 ClearMemory ();
1131
1132 FinishDemoRecord ();
1133}
1134#else
1135void FinishDemoRecord (void) {return;}
1136void RecordDemo (void) {return;}
1137#endif
1138
1139
1140
1141//==========================================================================
1142
1143/*
1144==================
1145=
1146= PlayDemo
1147=
1148= Fades the screen out, then starts a demo. Exits with the screen unfaded
1149=
1150==================
1151*/
1152
1153void PlayDemo (int demonumber)
1154{
1155 int length;
1156#ifdef DEMOSEXTERN
1157// debug: load chunk
1158#ifndef SPEARDEMO
1159 int dems[4]={T_DEMO0,T_DEMO1,T_DEMO2,T_DEMO3};
1160#else
1161 int dems[1]={T_DEMO0};
1162#endif
1163
1164 CA_CacheGrChunk(dems[demonumber]);
1165 demoptr = (int8_t *) grsegs[dems[demonumber]];
1166#else
1167 demoname[4] = '0'+demonumber;
1168 CA_LoadFile (demoname,&demobuffer);
1169 demoptr = (int8_t *)demobuffer;
1170#endif
1171
1172 NewGame (1,0);
1173 gamestate.mapon = *demoptr++;
1174 LOGF("%d", gamestate.mapon);
1175 gamestate.difficulty = gd_hard;
1176 /* FIXME POSSIBLE BUG */
1177 length = READWORD((uint8_t **)&demoptr);
1178 LOGF("%d", length);
1179 // TODO: Seems like the original demo format supports 16 MB demos
1180 // But T_DEM00 and T_DEM01 of Wolf have a 0xd8 as third length size...
1181 demoptr++;
1182 lastdemoptr = demoptr-4+length;
1183
1184 VW_FadeOut ();
1185
1186 SETFONTCOLOR(0,15);
1187 DrawPlayScreen ();
1188
1189 startgame = false;
1190 demoplayback = true;
1191
1192 SetupGameLevel ();
1193 StartMusic ();
1194
1195 PlayLoop ();
1196
1197#ifdef DEMOSEXTERN
1198 UNCACHEGRCHUNK(dems[demonumber]);
1199#else
1200 MM_FreePtr (&demobuffer);
1201#endif
1202
1203 demoplayback = false;
1204
1205 StopMusic ();
1206 ClearMemory ();
1207}
1208
1209//==========================================================================
1210
1211/*
1212==================
1213=
1214= Died
1215=
1216==================
1217*/
1218
1219#define DEATHROTATE 2
1220
1221void Died (void)
1222{
1223 float fangle;
1224 int32_t dx,dy;
1225 int iangle,curangle,clockwise,counter,change;
1226
1227 if (screenfaded)
1228 {
1229 ThreeDRefresh ();
1230 VW_FadeIn ();
1231 }
1232
1233 gamestate.weapon = (weapontype) -1; // take away weapon
1234 SD_PlaySound (PLAYERDEATHSND);
1235
1236 //
1237 // swing around to face attacker
1238 //
1239 if(killerobj)
1240 {
1241 dx = killerobj->x - player->x;
1242 dy = player->y - killerobj->y;
1243
1244 fangle = (float) atan2((float) dy, (float) dx); // returns -pi to pi
1245 if (fangle<0)
1246 fangle = (float) (M_PI*2+fangle);
1247
1248 iangle = (int) (fangle/(M_PI*2)*ANGLES);
1249 }
1250 else
1251 {
1252 iangle = player->angle + ANGLES / 2;
1253 if(iangle >= ANGLES) iangle -= ANGLES;
1254 }
1255
1256 if (player->angle > iangle)
1257 {
1258 counter = player->angle - iangle;
1259 clockwise = ANGLES-player->angle + iangle;
1260 }
1261 else
1262 {
1263 clockwise = iangle - player->angle;
1264 counter = player->angle + ANGLES-iangle;
1265 }
1266
1267 curangle = player->angle;
1268
1269 if (clockwise<counter)
1270 {
1271 //
1272 // rotate clockwise
1273 //
1274 if (curangle>iangle)
1275 curangle -= ANGLES;
1276 do
1277 {
1278 change = tics*DEATHROTATE;
1279 if (curangle + change > iangle)
1280 change = iangle-curangle;
1281
1282 curangle += change;
1283 player->angle += change;
1284 if (player->angle >= ANGLES)
1285 player->angle -= ANGLES;
1286
1287 ThreeDRefresh ();
1288 CalcTics ();
1289 } while (curangle != iangle);
1290 }
1291 else
1292 {
1293 //
1294 // rotate counterclockwise
1295 //
1296 if (curangle<iangle)
1297 curangle += ANGLES;
1298 do
1299 {
1300 change = -(int)tics*DEATHROTATE;
1301 if (curangle + change < iangle)
1302 change = iangle-curangle;
1303
1304 curangle += change;
1305 player->angle += change;
1306 if (player->angle < 0)
1307 player->angle += ANGLES;
1308
1309 ThreeDRefresh ();
1310 CalcTics ();
1311 } while (curangle != iangle);
1312 }
1313
1314 //
1315 // fade to red
1316 //
1317 FinishPaletteShifts ();
1318
1319 if(usedoublebuffering) VH_UpdateScreen();
1320
1321 VL_BarScaledCoord (viewscreenx,viewscreeny,viewwidth,viewheight,4);
1322
1323 IN_ClearKeysDown ();
1324
1325 FizzleFade(screenBuffer,viewscreenx,viewscreeny,viewwidth,viewheight,70,false);
1326
1327 IN_UserInput(100);
1328 SD_WaitSoundDone ();
1329 ClearMemory();
1330
1331 gamestate.lives--;
1332
1333 if (gamestate.lives > -1)
1334 {
1335 gamestate.health = 100;
1336 gamestate.weapon = gamestate.bestweapon
1337 = gamestate.chosenweapon = wp_pistol;
1338 gamestate.ammo = STARTAMMO;
1339 gamestate.keys = 0;
1340 pwallstate = pwallpos = 0;
1341 gamestate.attackframe = gamestate.attackcount =
1342 gamestate.weaponframe = 0;
1343
1344 if(viewsize != 21)
1345 {
1346 DrawKeys ();
1347 DrawWeapon ();
1348 DrawAmmo ();
1349 DrawHealth ();
1350 DrawFace ();
1351 DrawLives ();
1352 }
1353 }
1354}
1355
1356//==========================================================================
1357
1358/*
1359===================
1360=
1361= GameLoop
1362=
1363===================
1364*/
1365
1366void GameLoop (void)
1367{
1368 boolean died;
1369#ifdef MYPROFILE
1370 clock_t start,end;
1371#endif
1372
1373restartgame:
1374 ClearMemory ();
1375 SETFONTCOLOR(0,15);
1376 VW_FadeOut();
1377 DrawPlayScreen ();
1378 died = false;
1379 do
1380 {
1381 if (!loadedgame)
1382 gamestate.score = gamestate.oldscore;
1383 if(!died || viewsize != 21) DrawScore();
1384
1385 startgame = false;
1386 if (!loadedgame)
1387 SetupGameLevel ();
1388
1389#ifdef SPEAR
1390 if (gamestate.mapon == 20) // give them the key allways
1391 {
1392 gamestate.keys |= 1;
1393 DrawKeys ();
1394 }
1395#endif
1396
1397 ingame = true;
1398 if(loadedgame)
1399 {
1400 ContinueMusic(lastgamemusicoffset);
1401 loadedgame = false;
1402 }
1403 else StartMusic ();
1404
1405 if (!died)
1406 PreloadGraphics (); // TODO: Let this do something useful!
1407 else
1408 {
1409 died = false;
1410 fizzlein = true;
1411 }
1412
1413 DrawLevel ();
1414
1415#ifdef SPEAR
1416startplayloop:
1417#endif
1418 PlayLoop ();
1419
1420#ifdef SPEAR
1421 if (spearflag)
1422 {
1423 SD_StopSound();
1424 SD_PlaySound(GETSPEARSND);
1425 if (DigiMode != sds_Off)
1426 {
1427 Delay(150);
1428 }
1429 else
1430 SD_WaitSoundDone();
1431
1432 ClearMemory ();
1433 gamestate.oldscore = gamestate.score;
1434 gamestate.mapon = 20;
1435 SetupGameLevel ();
1436 StartMusic ();
1437 player->x = spearx;
1438 player->y = speary;
1439 player->angle = (short)spearangle;
1440 spearflag = false;
1441 Thrust (0,0);
1442 goto startplayloop;
1443 }
1444#endif
1445
1446 StopMusic ();
1447 ingame = false;
1448
1449 if (demorecord && playstate != ex_warped)
1450 FinishDemoRecord ();
1451
1452 if (startgame || loadedgame)
1453 goto restartgame;
1454
1455 switch (playstate)
1456 {
1457 case ex_completed:
1458 case ex_secretlevel:
1459 if(viewsize == 21) DrawPlayScreen();
1460 gamestate.keys = 0;
1461 DrawKeys ();
1462 VW_FadeOut ();
1463
1464 ClearMemory ();
1465
1466 LevelCompleted (); // do the intermission
1467 if(viewsize == 21) DrawPlayScreen();
1468
1469#ifdef SPEARDEMO
1470 if (gamestate.mapon == 1)
1471 {
1472 died = true; // don't "get psyched!"
1473
1474 VW_FadeOut ();
1475
1476 ClearMemory ();
1477
1478 CheckHighScore (gamestate.score,gamestate.mapon+1);
1479#ifndef JAPAN
1480 strcpy(MainMenu[viewscores].string,STR_VS);
1481#endif
1482 MainMenu[viewscores].routine = CP_ViewScores;
1483 return;
1484 }
1485#endif
1486
1487#ifdef JAPDEMO
1488 if (gamestate.mapon == 3)
1489 {
1490 died = true; // don't "get psyched!"
1491
1492 VW_FadeOut ();
1493
1494 ClearMemory ();
1495
1496 CheckHighScore (gamestate.score,gamestate.mapon+1);
1497#ifndef JAPAN
1498 strcpy(MainMenu[viewscores].string,STR_VS);
1499#endif
1500 MainMenu[viewscores].routine = CP_ViewScores;
1501 return;
1502 }
1503#endif
1504
1505 gamestate.oldscore = gamestate.score;
1506
1507#ifndef SPEAR
1508 //
1509 // COMING BACK FROM SECRET LEVEL
1510 //
1511 if (gamestate.mapon == 9)
1512 gamestate.mapon = ElevatorBackTo[gamestate.episode]; // back from secret
1513 else
1514 //
1515 // GOING TO SECRET LEVEL
1516 //
1517 if (playstate == ex_secretlevel)
1518 gamestate.mapon = 9;
1519#else
1520
1521#define FROMSECRET1 3
1522#define FROMSECRET2 11
1523
1524 //
1525 // GOING TO SECRET LEVEL
1526 //
1527 if (playstate == ex_secretlevel)
1528 switch(gamestate.mapon)
1529 {
1530 case FROMSECRET1: gamestate.mapon = 18; break;
1531 case FROMSECRET2: gamestate.mapon = 19; break;
1532 }
1533 else
1534 //
1535 // COMING BACK FROM SECRET LEVEL
1536 //
1537 if (gamestate.mapon == 18 || gamestate.mapon == 19)
1538 switch(gamestate.mapon)
1539 {
1540 case 18: gamestate.mapon = FROMSECRET1+1; break;
1541 case 19: gamestate.mapon = FROMSECRET2+1; break;
1542 }
1543#endif
1544 else
1545 //
1546 // GOING TO NEXT LEVEL
1547 //
1548 gamestate.mapon++;
1549 break;
1550
1551 case ex_died:
1552 Died ();
1553 died = true; // don't "get psyched!"
1554
1555 if (gamestate.lives > -1)
1556 break; // more lives left
1557
1558 VW_FadeOut ();
1559 if(screenHeight % 200 != 0)
1560 VL_ClearScreen(0);
1561
1562#ifdef _arch_dreamcast
1563 DC_StatusClearLCD();
1564#endif
1565
1566 ClearMemory ();
1567
1568 CheckHighScore (gamestate.score,gamestate.mapon+1);
1569#ifndef JAPAN
1570 strcpy(MainMenu[viewscores].string,STR_VS);
1571#endif
1572 MainMenu[viewscores].routine = CP_ViewScores;
1573 return;
1574
1575 case ex_victorious:
1576 if(viewsize == 21) DrawPlayScreen();
1577#ifndef SPEAR
1578 VW_FadeOut ();
1579#else
1580 VL_FadeOut (0,255,0,17,17,300);
1581#endif
1582 ClearMemory ();
1583
1584 Victory ();
1585
1586 ClearMemory ();
1587
1588 CheckHighScore (gamestate.score,gamestate.mapon+1);
1589#ifndef JAPAN
1590 strcpy(MainMenu[viewscores].string,STR_VS);
1591#endif
1592 MainMenu[viewscores].routine = CP_ViewScores;
1593 return;
1594
1595 default:
1596 if(viewsize == 21) DrawPlayScreen();
1597 ClearMemory ();
1598 break;
1599 }
1600 } while (1);
1601}