1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2000 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:
30  *  Action routines for lighting thinkers
31  *  Spawn sector based lighting effects.
32  *  Handle lighting linedef types
33  *
34  *-----------------------------------------------------------------------------*/
35 
36 #include "doomstat.h" //jff 5/18/98
37 #include "doomdef.h"
38 #include "m_random.h"
39 #include "r_main.h"
40 #include "p_spec.h"
41 #include "p_tick.h"
42 
43 //////////////////////////////////////////////////////////
44 //
45 // Lighting action routines, called once per tick
46 //
47 //////////////////////////////////////////////////////////
48 
49 //
50 // T_FireFlicker()
51 //
52 // Firelight flicker action routine, called once per tick
53 //
54 // Passed a fireflicker_t structure containing light levels and timing
55 // Returns nothing
56 //
T_FireFlicker(fireflicker_t * flick)57 void T_FireFlicker (fireflicker_t* flick)
58 {
59   int amount;
60 
61   if (--flick->count)
62     return;
63 
64   amount = (P_Random(pr_lights)&3)*16;
65 
66   if (flick->sector->lightlevel - amount < flick->minlight)
67     flick->sector->lightlevel = flick->minlight;
68   else
69     flick->sector->lightlevel = flick->maxlight - amount;
70 
71   flick->count = 4;
72 }
73 
74 //
75 // T_LightFlash()
76 //
77 // Broken light flashing action routine, called once per tick
78 //
79 // Passed a lightflash_t structure containing light levels and timing
80 // Returns nothing
81 //
T_LightFlash(lightflash_t * flash)82 void T_LightFlash (lightflash_t* flash)
83 {
84   if (--flash->count)
85     return;
86 
87   if (flash->sector->lightlevel == flash->maxlight)
88   {
89     flash-> sector->lightlevel = flash->minlight;
90     flash->count = (P_Random(pr_lights)&flash->mintime)+1;
91   }
92   else
93   {
94     flash-> sector->lightlevel = flash->maxlight;
95     flash->count = (P_Random(pr_lights)&flash->maxtime)+1;
96   }
97 
98 }
99 
100 //
101 // T_StrobeFlash()
102 //
103 // Strobe light flashing action routine, called once per tick
104 //
105 // Passed a strobe_t structure containing light levels and timing
106 // Returns nothing
107 //
T_StrobeFlash(strobe_t * flash)108 void T_StrobeFlash (strobe_t*   flash)
109 {
110   if (--flash->count)
111     return;
112 
113   if (flash->sector->lightlevel == flash->minlight)
114   {
115     flash-> sector->lightlevel = flash->maxlight;
116     flash->count = flash->brighttime;
117   }
118   else
119   {
120     flash-> sector->lightlevel = flash->minlight;
121     flash->count =flash->darktime;
122   }
123 }
124 
125 //
126 // T_Glow()
127 //
128 // Glowing light action routine, called once per tick
129 //
130 // Passed a glow_t structure containing light levels and timing
131 // Returns nothing
132 //
133 
T_Glow(glow_t * g)134 void T_Glow(glow_t* g)
135 {
136   switch(g->direction)
137   {
138     case -1:
139       // light dims
140       g->sector->lightlevel -= GLOWSPEED;
141       if (g->sector->lightlevel <= g->minlight)
142       {
143         g->sector->lightlevel += GLOWSPEED;
144         g->direction = 1;
145       }
146       break;
147 
148     case 1:
149       // light brightens
150       g->sector->lightlevel += GLOWSPEED;
151       if (g->sector->lightlevel >= g->maxlight)
152       {
153         g->sector->lightlevel -= GLOWSPEED;
154         g->direction = -1;
155       }
156       break;
157   }
158 }
159 
160 //////////////////////////////////////////////////////////
161 //
162 // Sector lighting type spawners
163 //
164 // After the map has been loaded, each sector is scanned
165 // for specials that spawn thinkers
166 //
167 //////////////////////////////////////////////////////////
168 
169 //
170 // P_SpawnFireFlicker()
171 //
172 // Spawns a fire flicker lighting thinker
173 //
174 // Passed the sector that spawned the thinker
175 // Returns nothing
176 //
P_SpawnFireFlicker(sector_t * sector)177 void P_SpawnFireFlicker (sector_t*  sector)
178 {
179   fireflicker_t*  flick;
180 
181   // Note that we are resetting sector attributes.
182   // Nothing special about it during gameplay.
183   sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type
184 
185   flick = Z_Malloc ( sizeof(*flick), PU_LEVSPEC, 0);
186 
187   memset(flick, 0, sizeof(*flick));
188   P_AddThinker (&flick->thinker);
189 
190   flick->thinker.function = T_FireFlicker;
191   flick->sector = sector;
192   flick->maxlight = sector->lightlevel;
193   flick->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel)+16;
194   flick->count = 4;
195 }
196 
197 //
198 // P_SpawnLightFlash()
199 //
200 // Spawns a broken light flash lighting thinker
201 //
202 // Passed the sector that spawned the thinker
203 // Returns nothing
204 //
P_SpawnLightFlash(sector_t * sector)205 void P_SpawnLightFlash (sector_t* sector)
206 {
207   lightflash_t* flash;
208 
209   // nothing special about it during gameplay
210   sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type
211 
212   flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0);
213 
214   memset(flash, 0, sizeof(*flash));
215   P_AddThinker (&flash->thinker);
216 
217   flash->thinker.function = T_LightFlash;
218   flash->sector           = sector;
219   flash->maxlight         = sector->lightlevel;
220 
221   flash->minlight         = P_FindMinSurroundingLight(sector,sector->lightlevel);
222   flash->maxtime          = 64;
223   flash->mintime          = 7;
224   flash->count            = (P_Random(pr_lights)&flash->maxtime)+1;
225 }
226 
227 //
228 // P_SpawnStrobeFlash
229 //
230 // Spawns a blinking light thinker
231 //
232 // Passed the sector that spawned the thinker, speed of blinking
233 // and whether blinking is to by syncrhonous with other sectors
234 //
235 // Returns nothing
236 //
P_SpawnStrobeFlash(sector_t * sector,int fastOrSlow,int inSync)237 void P_SpawnStrobeFlash
238 ( sector_t* sector,
239   int   fastOrSlow,
240   int   inSync )
241 {
242   strobe_t* flash;
243 
244   flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0);
245 
246   memset(flash, 0, sizeof(*flash));
247   P_AddThinker (&flash->thinker);
248 
249   flash->sector = sector;
250   flash->darktime = fastOrSlow;
251   flash->brighttime = STROBEBRIGHT;
252   flash->thinker.function = T_StrobeFlash;
253   flash->maxlight = sector->lightlevel;
254   flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel);
255 
256   if (flash->minlight == flash->maxlight)
257     flash->minlight = 0;
258 
259   // nothing special about it during gameplay
260   sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type
261 
262   if (!inSync)
263     flash->count = (P_Random(pr_lights)&7)+1;
264   else
265     flash->count = 1;
266 }
267 
268 //
269 // P_SpawnGlowingLight()
270 //
271 // Spawns a glowing light (smooth oscillation from min to max) thinker
272 //
273 // Passed the sector that spawned the thinker
274 // Returns nothing
275 //
P_SpawnGlowingLight(sector_t * sector)276 void P_SpawnGlowingLight(sector_t*  sector)
277 {
278   glow_t* g;
279 
280   g = Z_Malloc( sizeof(*g), PU_LEVSPEC, 0);
281 
282   memset(g, 0, sizeof(*g));
283   P_AddThinker(&g->thinker);
284 
285   g->sector = sector;
286   g->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel);
287   g->maxlight = sector->lightlevel;
288   g->thinker.function = T_Glow;
289   g->direction = -1;
290 
291   sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type
292 }
293 
294 //////////////////////////////////////////////////////////
295 //
296 // Linedef lighting function handlers
297 //
298 //////////////////////////////////////////////////////////
299 
300 //
301 // EV_StartLightStrobing()
302 //
303 // Start strobing lights (usually from a trigger)
304 //
305 // Passed the line that activated the strobing
306 // Returns TRUE
307 //
308 // jff 2/12/98 added int return value, fixed return
309 //
EV_StartLightStrobing(line_t * line)310 int EV_StartLightStrobing(line_t* line)
311 {
312   sector_t* sec;
313   int   secnum = -1;
314 
315   // start lights strobing in all sectors tagged same as line
316   while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
317   {
318     sec = &sectors[secnum];
319     // if already doing a lighting function, don't start a second
320     if (P_SectorActive(lighting_special,sec)) //jff 2/22/98
321       continue;
322 
323     P_SpawnStrobeFlash (sec,SLOWDARK, 0);
324   }
325   return 1;
326 }
327 
328 //
329 // EV_TurnTagLightsOff()
330 //
331 // Turn line's tagged sector's lights to min adjacent neighbor level
332 //
333 // Passed the line that activated the lights being turned off
334 // Returns TRUE
335 //
336 // jff 2/12/98 added int return value, fixed return
337 //
EV_TurnTagLightsOff(line_t * line)338 int EV_TurnTagLightsOff(line_t* line)
339 {
340   int j;
341 
342   // search sectors for those with same tag as activating line
343 
344   // killough 10/98: replaced inefficient search with fast search
345   for (j = -1; (j = P_FindSectorFromLineTag(line,j)) >= 0;)
346     {
347       sector_t *sector = sectors + j, *tsec;
348       int i, min = sector->lightlevel;
349       // find min neighbor light level
350       for (i = 0;i < sector->linecount; i++)
351   if ((tsec = getNextSector(sector->lines[i], sector)) &&
352       tsec->lightlevel < min)
353     min = tsec->lightlevel;
354       sector->lightlevel = min;
355     }
356   return 1;
357 }
358 
359 //
360 // EV_LightTurnOn()
361 //
362 // Turn sectors tagged to line lights on to specified or max neighbor level
363 //
364 // Passed the activating line, and a level to set the light to
365 // If level passed is 0, the maximum neighbor lighting is used
366 // Returns TRUE
367 //
368 // jff 2/12/98 added int return value, fixed return
369 //
EV_LightTurnOn(line_t * line,int bright)370 int EV_LightTurnOn(line_t *line, int bright)
371 {
372    int i;
373 
374    // search all sectors for ones with same tag as activating line
375 
376    // killough 10/98: replace inefficient search with fast search
377    for (i = -1; (i = P_FindSectorFromLineTag(line,i)) >= 0;)
378    {
379       sector_t *temp, *sector = sectors+i;
380       int j, tbright = bright; //jff 5/17/98 search for maximum PER sector
381 
382       // bright = 0 means to search for highest light level surrounding sector
383 
384       if (!bright)
385       {
386          for (j = 0;j < sector->linecount; j++)
387             if ((temp = getNextSector(sector->lines[j],sector)) &&
388                   temp->lightlevel > tbright)
389                tbright = temp->lightlevel;
390       }
391 
392       sector->lightlevel = tbright;
393 
394       //jff 5/17/98 unless compatibility optioned
395       //then maximum near ANY tagged sector
396       if (comp[comp_model])
397          bright = tbright;
398    }
399    return 1;
400 }
401 
402 /* killough 10/98:
403  *
404  * EV_LightTurnOnPartway()
405  *
406  * Turn sectors tagged to line lights on to specified or max neighbor level
407  *
408  * Passed the activating line, and a light level fraction between 0 and 1.
409  * Sets the light to min on 0, max on 1, and interpolates in-between.
410  * Used for doors with gradual lighting effects.
411  *
412  * Returns TRUE
413  */
414 
EV_LightTurnOnPartway(line_t * line,fixed_t level)415 int EV_LightTurnOnPartway(line_t *line, fixed_t level)
416 {
417   int i;
418 
419   if (level < 0)          // clip at extremes
420     level = 0;
421   if (level > FRACUNIT)
422     level = FRACUNIT;
423 
424   // search all sectors for ones with same tag as activating line
425   for (i = -1; (i = P_FindSectorFromLineTag(line,i)) >= 0;)
426     {
427       sector_t *temp, *sector = sectors+i;
428       int j, bright = 0, min = sector->lightlevel;
429 
430       for (j = 0; j < sector->linecount; j++)
431   if ((temp = getNextSector(sector->lines[j],sector)))
432     {
433       if (temp->lightlevel > bright)
434         bright = temp->lightlevel;
435       if (temp->lightlevel < min)
436         min = temp->lightlevel;
437     }
438 
439       sector->lightlevel =   // Set level in-between extremes
440   (level * bright + (FRACUNIT-level) * min) >> FRACBITS;
441     }
442   return 1;
443 }
444 
445