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 = §ors[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