OSDN Git Service

going on vacation >.<
[proj16/16.git] / src / lib / hb / play / c3_play.c
1 /* Catacomb 3-D Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 // C3_PLAY.C\r
20 \r
21 #include "C3_DEF.H"\r
22 #pragma hdrstop\r
23 \r
24 /*\r
25 =============================================================================\r
26 \r
27                                                  LOCAL CONSTANTS\r
28 \r
29 =============================================================================\r
30 */\r
31 \r
32 #define POINTTICS       6\r
33 \r
34 \r
35 /*\r
36 =============================================================================\r
37 \r
38                                                  GLOBAL VARIABLES\r
39 \r
40 =============================================================================\r
41 */\r
42 \r
43 ControlInfo     c;\r
44 boolean         running,slowturn;\r
45 \r
46 int                     bordertime;\r
47 objtype objlist[MAXACTORS],*new,*obj,*player,*lastobj,*objfreelist;\r
48 \r
49 unsigned        farmapylookup[MAPSIZE];\r
50 byte            *nearmapylookup[MAPSIZE];\r
51 \r
52 boolean         singlestep,godmode;\r
53 int                     extravbls;\r
54 \r
55 //\r
56 // replacing refresh manager\r
57 //\r
58 unsigned        mapwidth,mapheight,tics;\r
59 boolean         compatability;\r
60 byte            *updateptr;\r
61 unsigned        mapwidthtable[64];\r
62 unsigned        uwidthtable[UPDATEHIGH];\r
63 unsigned        blockstarts[UPDATEWIDE*UPDATEHIGH];\r
64 #define UPDATESCREENSIZE        (UPDATEWIDE*PORTTILESHIGH+2)\r
65 #define UPDATESPARESIZE         (UPDATEWIDE*2+4)\r
66 #define UPDATESIZE                      (UPDATESCREENSIZE+2*UPDATESPARESIZE)\r
67 byte            update[UPDATESIZE];\r
68 \r
69 int             mousexmove,mouseymove;\r
70 int             pointcount,pointsleft;\r
71 \r
72 /*\r
73 =============================================================================\r
74 \r
75                                                  LOCAL VARIABLES\r
76 \r
77 =============================================================================\r
78 */\r
79 \r
80 void CalcBounds (objtype *ob);\r
81 void DrawPlayScreen (void);\r
82 \r
83 \r
84 //\r
85 // near data map array (wall values only, get text number from far data)\r
86 //\r
87 byte            tilemap[MAPSIZE][MAPSIZE];\r
88 byte            spotvis[MAPSIZE][MAPSIZE];\r
89 objtype         *actorat[MAPSIZE][MAPSIZE];\r
90 \r
91 objtype dummyobj;\r
92 \r
93 int bordertime;\r
94 int     objectcount;\r
95 \r
96 void StopMusic(void);\r
97 void StartMusic(void);\r
98 \r
99 \r
100 //==========================================================================\r
101 \r
102 ///////////////////////////////////////////////////////////////////////////\r
103 //\r
104 //      CenterWindow() - Generates a window of a given width & height in the\r
105 //              middle of the screen\r
106 //\r
107 ///////////////////////////////////////////////////////////////////////////\r
108 \r
109 #define MAXX    264\r
110 #define MAXY    146\r
111 \r
112 void    CenterWindow(word w,word h)\r
113 {\r
114         US_DrawWindow(((MAXX / 8) - w) / 2,((MAXY / 8) - h) / 2,w,h);\r
115 }\r
116 \r
117 //===========================================================================\r
118 \r
119 \r
120 /*\r
121 =====================\r
122 =\r
123 = CheckKeys\r
124 =\r
125 =====================\r
126 */\r
127 \r
128 void CheckKeys (void)\r
129 {\r
130         if (screenfaded)                        // don't do anything with a faded screen\r
131                 return;\r
132 \r
133 //\r
134 // pause key wierdness can't be checked as a scan code\r
135 //\r
136         if (Paused)\r
137         {\r
138                 CenterWindow (8,3);\r
139                 US_PrintCentered ("PAUSED");\r
140                 VW_UpdateScreen ();\r
141                 SD_MusicOff();\r
142                 IN_Ack();\r
143                 SD_MusicOn();\r
144                 Paused = false;\r
145                 if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
146         }\r
147 \r
148 //\r
149 // F1-F7/ESC to enter control panel\r
150 //\r
151         if ( (LastScan >= sc_F1 && LastScan <= sc_F7) || LastScan == sc_Escape)\r
152         {\r
153                 StopMusic ();\r
154                 NormalScreen ();\r
155                 FreeUpMemory ();\r
156                 US_CenterWindow (20,8);\r
157                 US_CPrint ("Loading");\r
158                 VW_UpdateScreen ();\r
159                 US_ControlPanel();\r
160                 if (abortgame)\r
161                 {\r
162                         playstate = ex_abort;\r
163                         return;\r
164                 }\r
165                 StartMusic ();\r
166                 IN_ClearKeysDown();\r
167                 if (restartgame)\r
168                         playstate = ex_resetgame;\r
169                 if (loadedgame)\r
170                         playstate = ex_loadedgame;\r
171                 DrawPlayScreen ();\r
172                 CacheScaleds ();\r
173                 lasttimecount = TimeCount;\r
174                 if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
175         }\r
176 \r
177 //\r
178 // F10-? debug keys\r
179 //\r
180         if (Keyboard[sc_F10])\r
181         {\r
182                 DebugKeys();\r
183                 if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
184                 lasttimecount = TimeCount;\r
185         }\r
186 \r
187 }\r
188 \r
189 \r
190 //===========================================================================\r
191 \r
192 /*\r
193 #############################################################################\r
194 \r
195                                   The objlist data structure\r
196 \r
197 #############################################################################\r
198 \r
199 objlist containt structures for every actor currently playing.  The structure\r
200 is accessed as a linked list starting at *player, ending when ob->next ==\r
201 NULL.  GetNewObj inserts a new object at the end of the list, meaning that\r
202 if an actor spawn another actor, the new one WILL get to think and react the\r
203 same frame.  RemoveObj unlinks the given object and returns it to the free\r
204 list, but does not damage the objects ->next pointer, so if the current object\r
205 removes itself, a linked list following loop can still safely get to the\r
206 next element.\r
207 \r
208 <backwardly linked free list>\r
209 \r
210 #############################################################################\r
211 */\r
212 \r
213 \r
214 /*\r
215 =========================\r
216 =\r
217 = InitObjList\r
218 =\r
219 = Call to clear out the entire object list, returning them all to the free\r
220 = list.  Allocates a special spot for the player.\r
221 =\r
222 =========================\r
223 */\r
224 \r
225 void InitObjList (void)\r
226 {\r
227         int     i;\r
228 \r
229         for (i=0;i<MAXACTORS;i++)\r
230         {\r
231                 objlist[i].prev = &objlist[i+1];\r
232                 objlist[i].next = NULL;\r
233         }\r
234 \r
235         objlist[MAXACTORS-1].prev = NULL;\r
236 \r
237         objfreelist = &objlist[0];\r
238         lastobj = NULL;\r
239 \r
240         objectcount = 0;\r
241 \r
242 //\r
243 // give the player and score the first free spots\r
244 //\r
245         GetNewObj (false);\r
246         player = new;\r
247 }\r
248 \r
249 //===========================================================================\r
250 \r
251 /*\r
252 =========================\r
253 =\r
254 = GetNewObj\r
255 =\r
256 = Sets the global variable new to point to a free spot in objlist.\r
257 = The free spot is inserted at the end of the liked list\r
258 =\r
259 = When the object list is full, the caller can either have it bomb out ot\r
260 = return a dummy object pointer that will never get used\r
261 =\r
262 =========================\r
263 */\r
264 \r
265 void GetNewObj (boolean usedummy)\r
266 {\r
267         if (!objfreelist)\r
268         {\r
269                 if (usedummy)\r
270                 {\r
271                         new = &dummyobj;\r
272                         return;\r
273                 }\r
274                 Quit ("GetNewObj: No free spots in objlist!");\r
275         }\r
276 \r
277         new = objfreelist;\r
278         objfreelist = new->prev;\r
279         memset (new,0,sizeof(*new));\r
280 \r
281         if (lastobj)\r
282                 lastobj->next = new;\r
283         new->prev = lastobj;    // new->next is allready NULL from memset\r
284 \r
285         new->active = false;\r
286         lastobj = new;\r
287 \r
288         objectcount++;\r
289 }\r
290 \r
291 //===========================================================================\r
292 \r
293 /*\r
294 =========================\r
295 =\r
296 = RemoveObj\r
297 =\r
298 = Add the given object back into the free list, and unlink it from it's\r
299 = neighbors\r
300 =\r
301 =========================\r
302 */\r
303 \r
304 void RemoveObj (objtype *gone)\r
305 {\r
306         objtype **spotat;\r
307 \r
308         if (gone == player)\r
309                 Quit ("RemoveObj: Tried to remove the player!");\r
310 \r
311 //\r
312 // fix the next object's back link\r
313 //\r
314         if (gone == lastobj)\r
315                 lastobj = (objtype *)gone->prev;\r
316         else\r
317                 gone->next->prev = gone->prev;\r
318 \r
319 //\r
320 // fix the previous object's forward link\r
321 //\r
322         gone->prev->next = gone->next;\r
323 \r
324 //\r
325 // add it back in to the free list\r
326 //\r
327         gone->prev = objfreelist;\r
328         objfreelist = gone;\r
329 }\r
330 \r
331 //==========================================================================\r
332 \r
333 /*\r
334 ===================\r
335 =\r
336 = PollControls\r
337 =\r
338 ===================\r
339 */\r
340 \r
341 void PollControls (void)\r
342 {\r
343         unsigned buttons;\r
344 \r
345         IN_ReadControl(0,&c);\r
346 \r
347         if (MousePresent)\r
348         {\r
349                 Mouse(MButtons);\r
350                 buttons = _BX;\r
351                 Mouse(MDelta);\r
352                 mousexmove = _CX;\r
353                 mouseymove = _DX;\r
354 \r
355                 if (buttons&1)\r
356                         c.button0 = 1;\r
357                 if (buttons&2)\r
358                         c.button1 = 1;\r
359 \r
360         }\r
361 \r
362         if (Controls[0]==ctrl_Joystick)\r
363         {\r
364                 if (c.x>120 || c.x <-120 || c.y>120 || c.y<-120)\r
365                         running = true;\r
366                 else\r
367                         running = false;\r
368                 if (c.x>-48 && c.x<48)\r
369                         slowturn = true;\r
370                 else\r
371                         slowturn = false;\r
372         }\r
373         else\r
374         {\r
375                 if (Keyboard[sc_RShift])\r
376                         running = true;\r
377                 else\r
378                         running = false;\r
379                 if (c.button0)\r
380                         slowturn = true;\r
381                 else\r
382                         slowturn = false;\r
383         }\r
384 }\r
385 \r
386 //==========================================================================\r
387 \r
388 /*\r
389 =================\r
390 =\r
391 = StopMusic\r
392 =\r
393 =================\r
394 */\r
395 \r
396 void StopMusic(void)\r
397 {\r
398         int     i;\r
399 \r
400         SD_MusicOff();\r
401         for (i = 0;i < LASTMUSIC;i++)\r
402                 if (audiosegs[STARTMUSIC + i])\r
403                 {\r
404                         MM_SetPurge(&((memptr)audiosegs[STARTMUSIC + i]),3);\r
405                         MM_SetLock(&((memptr)audiosegs[STARTMUSIC + i]),false);\r
406                 }\r
407 }\r
408 \r
409 //==========================================================================\r
410 \r
411 \r
412 /*\r
413 =================\r
414 =\r
415 = StartMusic\r
416 =\r
417 =================\r
418 */\r
419 \r
420 // JAB - Cache & start the appropriate music for this level\r
421 void StartMusic(void)\r
422 {\r
423         musicnames      chunk;\r
424 \r
425         SD_MusicOff();\r
426         chunk = TOOHOT_MUS;\r
427 //      if ((chunk == -1) || (MusicMode != smm_AdLib))\r
428 //DEBUG control panel           return;\r
429 \r
430         MM_BombOnError (false);\r
431         CA_CacheAudioChunk(STARTMUSIC + chunk);\r
432         MM_BombOnError (true);\r
433         if (mmerror)\r
434                 mmerror = false;\r
435         else\r
436         {\r
437                 MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true);\r
438                 SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]);\r
439         }\r
440 }\r
441 \r
442 //==========================================================================\r
443 \r
444 \r
445 /*\r
446 ===================\r
447 =\r
448 = PlayLoop\r
449 =\r
450 ===================\r
451 */\r
452 \r
453 void PlayLoop (void)\r
454 {\r
455         int             give;\r
456 \r
457         void (*think)();\r
458 \r
459         ingame = true;\r
460         playstate = TimeCount = 0;\r
461         gamestate.shotpower = handheight = 0;\r
462         pointcount = pointsleft = 0;\r
463 \r
464         DrawLevelNumber (gamestate.mapon);\r
465         DrawBars ();\r
466 \r
467 #ifndef PROFILE\r
468         fizzlein = true;                                // fizzle fade in the first refresh\r
469 #endif\r
470         TimeCount = lasttimecount = lastnuke = 0;\r
471 \r
472         PollControls ();                                // center mouse\r
473         StartMusic ();\r
474         do\r
475         {\r
476 #ifndef PROFILE\r
477                 PollControls();\r
478 #else\r
479                 c.xaxis = 1;\r
480                 if (++TimeCount == 300)\r
481                         return;\r
482 #endif\r
483 \r
484                 for (obj = player;obj;obj = obj->next)\r
485                         if (obj->active)\r
486                         {\r
487                                 if (obj->ticcount)\r
488                                 {\r
489                                         obj->ticcount-=tics;\r
490                                         while ( obj->ticcount <= 0)\r
491                                         {\r
492                                                 think = obj->state->think;\r
493                                                 if (think)\r
494                                                 {\r
495                                                         think (obj);\r
496                                                         if (!obj->state)\r
497                                                         {\r
498                                                                 RemoveObj (obj);\r
499                                                                 goto nextactor;\r
500                                                         }\r
501                                                 }\r
502 \r
503                                                 obj->state = obj->state->next;\r
504                                                 if (!obj->state)\r
505                                                 {\r
506                                                         RemoveObj (obj);\r
507                                                         goto nextactor;\r
508                                                 }\r
509                                                 if (!obj->state->tictime)\r
510                                                 {\r
511                                                         obj->ticcount = 0;\r
512                                                         goto nextactor;\r
513                                                 }\r
514                                                 if (obj->state->tictime>0)\r
515                                                         obj->ticcount += obj->state->tictime;\r
516                                         }\r
517                                 }\r
518                                 think = obj->state->think;\r
519                                 if (think)\r
520                                 {\r
521                                         think (obj);\r
522                                         if (!obj->state)\r
523                                                 RemoveObj (obj);\r
524                                 }\r
525 nextactor:;\r
526                         }\r
527 \r
528 \r
529                 if (bordertime)\r
530                 {\r
531                         bordertime -= tics;\r
532                         if (bordertime<=0)\r
533                         {\r
534                                 bordertime = 0;\r
535                                 VW_ColorBorder (3);\r
536                         }\r
537                 }\r
538 \r
539                 if (pointcount)\r
540                 {\r
541                         pointcount -= tics;\r
542                         if (pointcount <= 0)\r
543                         {\r
544                                 pointcount += POINTTICS;\r
545                                 give = (pointsleft > 1000)? 1000 :\r
546                                                 (\r
547                                                         (pointsleft > 100)? 100 :\r
548                                                                 ((pointsleft < 20)? pointsleft : 20)\r
549                                                 );\r
550                                 SD_PlaySound (GETPOINTSSND);\r
551                                 AddPoints (give);\r
552                                 pointsleft -= give;\r
553                                 if (!pointsleft)\r
554                                         pointcount = 0;\r
555                         }\r
556                 }\r
557 \r
558                 ThreeDRefresh ();\r
559 \r
560                 CheckKeys();\r
561                 if (singlestep)\r
562                 {\r
563                         VW_WaitVBL(14);\r
564                         lasttimecount = TimeCount;\r
565                 }\r
566                 if (extravbls)\r
567                         VW_WaitVBL(extravbls);\r
568 \r
569         }while (!playstate);\r
570         StopMusic ();\r
571 \r
572         ingame = false;\r
573         if (bordertime)\r
574         {\r
575                 bordertime = 0;\r
576                 VW_ColorBorder (3);\r
577         }\r
578 \r
579         if (!abortgame)\r
580                 AddPoints (pointsleft);\r
581         else\r
582                 abortgame = false;\r
583 }\r
584 \r