1 /* Catacomb 3-D Source Code
\r
2 * Copyright (C) 1993-2014 Flat Rock Software
\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
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
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
25 =============================================================================
\r
29 =============================================================================
\r
36 =============================================================================
\r
40 =============================================================================
\r
44 boolean running,slowturn;
\r
47 objtype objlist[MAXACTORS],*new,*obj,*player,*lastobj,*objfreelist;
\r
49 unsigned farmapylookup[MAPSIZE];
\r
50 byte *nearmapylookup[MAPSIZE];
\r
52 boolean singlestep,godmode;
\r
56 // replacing refresh manager
\r
58 unsigned mapwidth,mapheight,tics;
\r
59 boolean compatability;
\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
69 int mousexmove,mouseymove;
\r
70 int pointcount,pointsleft;
\r
73 =============================================================================
\r
77 =============================================================================
\r
80 void CalcBounds (objtype *ob);
\r
81 void DrawPlayScreen (void);
\r
85 // near data map array (wall values only, get text number from far data)
\r
87 byte tilemap[MAPSIZE][MAPSIZE];
\r
88 byte spotvis[MAPSIZE][MAPSIZE];
\r
89 objtype *actorat[MAPSIZE][MAPSIZE];
\r
96 void StopMusic(void);
\r
97 void StartMusic(void);
\r
100 //==========================================================================
\r
102 ///////////////////////////////////////////////////////////////////////////
\r
104 // CenterWindow() - Generates a window of a given width & height in the
\r
105 // middle of the screen
\r
107 ///////////////////////////////////////////////////////////////////////////
\r
112 void CenterWindow(word w,word h)
\r
114 US_DrawWindow(((MAXX / 8) - w) / 2,((MAXY / 8) - h) / 2,w,h);
\r
117 //===========================================================================
\r
121 =====================
\r
125 =====================
\r
128 void CheckKeys (void)
\r
130 if (screenfaded) // don't do anything with a faded screen
\r
134 // pause key wierdness can't be checked as a scan code
\r
138 CenterWindow (8,3);
\r
139 US_PrintCentered ("PAUSED");
\r
140 VW_UpdateScreen ();
\r
145 if (MousePresent) Mouse(MDelta); // Clear accumulated mouse movement
\r
149 // F1-F7/ESC to enter control panel
\r
151 if ( (LastScan >= sc_F1 && LastScan <= sc_F7) || LastScan == sc_Escape)
\r
156 US_CenterWindow (20,8);
\r
157 US_CPrint ("Loading");
\r
158 VW_UpdateScreen ();
\r
162 playstate = ex_abort;
\r
166 IN_ClearKeysDown();
\r
168 playstate = ex_resetgame;
\r
170 playstate = ex_loadedgame;
\r
173 lasttimecount = TimeCount;
\r
174 if (MousePresent) Mouse(MDelta); // Clear accumulated mouse movement
\r
178 // F10-? debug keys
\r
180 if (Keyboard[sc_F10])
\r
183 if (MousePresent) Mouse(MDelta); // Clear accumulated mouse movement
\r
184 lasttimecount = TimeCount;
\r
190 //===========================================================================
\r
193 #############################################################################
\r
195 The objlist data structure
\r
197 #############################################################################
\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
208 <backwardly linked free list>
\r
210 #############################################################################
\r
215 =========================
\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
222 =========================
\r
225 void InitObjList (void)
\r
229 for (i=0;i<MAXACTORS;i++)
\r
231 objlist[i].prev = &objlist[i+1];
\r
232 objlist[i].next = NULL;
\r
235 objlist[MAXACTORS-1].prev = NULL;
\r
237 objfreelist = &objlist[0];
\r
243 // give the player and score the first free spots
\r
249 //===========================================================================
\r
252 =========================
\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
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
262 =========================
\r
265 void GetNewObj (boolean usedummy)
\r
274 Quit ("GetNewObj: No free spots in objlist!");
\r
278 objfreelist = new->prev;
\r
279 memset (new,0,sizeof(*new));
\r
282 lastobj->next = new;
\r
283 new->prev = lastobj; // new->next is allready NULL from memset
\r
285 new->active = false;
\r
291 //===========================================================================
\r
294 =========================
\r
298 = Add the given object back into the free list, and unlink it from it's
\r
301 =========================
\r
304 void RemoveObj (objtype *gone)
\r
308 if (gone == player)
\r
309 Quit ("RemoveObj: Tried to remove the player!");
\r
312 // fix the next object's back link
\r
314 if (gone == lastobj)
\r
315 lastobj = (objtype *)gone->prev;
\r
317 gone->next->prev = gone->prev;
\r
320 // fix the previous object's forward link
\r
322 gone->prev->next = gone->next;
\r
325 // add it back in to the free list
\r
327 gone->prev = objfreelist;
\r
328 objfreelist = gone;
\r
331 //==========================================================================
\r
334 ===================
\r
338 ===================
\r
341 void PollControls (void)
\r
345 IN_ReadControl(0,&c);
\r
362 if (Controls[0]==ctrl_Joystick)
\r
364 if (c.x>120 || c.x <-120 || c.y>120 || c.y<-120)
\r
368 if (c.x>-48 && c.x<48)
\r
375 if (Keyboard[sc_RShift])
\r
386 //==========================================================================
\r
396 void StopMusic(void)
\r
401 for (i = 0;i < LASTMUSIC;i++)
\r
402 if (audiosegs[STARTMUSIC + i])
\r
404 MM_SetPurge(&((memptr)audiosegs[STARTMUSIC + i]),3);
\r
405 MM_SetLock(&((memptr)audiosegs[STARTMUSIC + i]),false);
\r
409 //==========================================================================
\r
420 // JAB - Cache & start the appropriate music for this level
\r
421 void StartMusic(void)
\r
426 chunk = TOOHOT_MUS;
\r
427 // if ((chunk == -1) || (MusicMode != smm_AdLib))
\r
428 //DEBUG control panel return;
\r
430 MM_BombOnError (false);
\r
431 CA_CacheAudioChunk(STARTMUSIC + chunk);
\r
432 MM_BombOnError (true);
\r
437 MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true);
\r
438 SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]);
\r
442 //==========================================================================
\r
446 ===================
\r
450 ===================
\r
453 void PlayLoop (void)
\r
460 playstate = TimeCount = 0;
\r
461 gamestate.shotpower = handheight = 0;
\r
462 pointcount = pointsleft = 0;
\r
464 DrawLevelNumber (gamestate.mapon);
\r
468 fizzlein = true; // fizzle fade in the first refresh
\r
470 TimeCount = lasttimecount = lastnuke = 0;
\r
472 PollControls (); // center mouse
\r
480 if (++TimeCount == 300)
\r
484 for (obj = player;obj;obj = obj->next)
\r
489 obj->ticcount-=tics;
\r
490 while ( obj->ticcount <= 0)
\r
492 think = obj->state->think;
\r
503 obj->state = obj->state->next;
\r
509 if (!obj->state->tictime)
\r
514 if (obj->state->tictime>0)
\r
515 obj->ticcount += obj->state->tictime;
\r
518 think = obj->state->think;
\r
531 bordertime -= tics;
\r
535 VW_ColorBorder (3);
\r
541 pointcount -= tics;
\r
542 if (pointcount <= 0)
\r
544 pointcount += POINTTICS;
\r
545 give = (pointsleft > 1000)? 1000 :
\r
547 (pointsleft > 100)? 100 :
\r
548 ((pointsleft < 20)? pointsleft : 20)
\r
550 SD_PlaySound (GETPOINTSSND);
\r
552 pointsleft -= give;
\r
564 lasttimecount = TimeCount;
\r
567 VW_WaitVBL(extravbls);
\r
569 }while (!playstate);
\r
576 VW_ColorBorder (3);
\r
580 AddPoints (pointsleft);
\r