A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 * 02111-1307, USA.
26 *
27 * DESCRIPTION:
28 * Ceiling aninmation (lowering, crushing, raising)
29 *
30 *-----------------------------------------------------------------------------*/
31
32#include "doomstat.h"
33#include "r_main.h"
34#include "p_spec.h"
35#include "p_tick.h"
36#include "s_sound.h"
37#include "sounds.h"
38#include "z_zone.h"
39#include "doomdef.h"
40#define PU_LEVSPEC 51 // a special thinker in a level
41#include "rockmacros.h"
42
43// the list of ceilings moving currently, including crushers
44ceilinglist_t *activeceilings;
45
46/////////////////////////////////////////////////////////////////
47//
48// Ceiling action routine and linedef type handler
49//
50/////////////////////////////////////////////////////////////////
51
52//
53// T_MoveCeiling
54//
55// Action routine that moves ceilings. Called once per tick.
56//
57// Passed a ceiling_t structure that contains all the info about the move.
58// see P_SPEC.H for fields. No return.
59//
60// jff 02/08/98 all cases with labels beginning with gen added to support
61// generalized line type behaviors.
62//
63void T_MoveCeiling (ceiling_t* ceiling)
64{
65 result_e res;
66
67 switch(ceiling->direction)
68 {
69 case 0:
70 // If ceiling in stasis, do nothing
71 break;
72
73 case 1:
74 // Ceiling is moving up
75 res = T_MovePlane
76 (
77 ceiling->sector,
78 ceiling->speed,
79 ceiling->topheight,
80 false,
81 1,
82 ceiling->direction
83 );
84
85 // if not a silent crusher, make moving sound
86 if (!(leveltime&7))
87 {
88 switch(ceiling->type)
89 {
90 case silentCrushAndRaise:
91 case genSilentCrusher:
92 break;
93 default:
94 S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_stnmov);
95 break;
96 }
97 }
98
99 // handle reaching destination height
100 if (res == pastdest)
101 {
102 switch(ceiling->type)
103 {
104 // plain movers are just removed
105 case raiseToHighest:
106 case genCeiling:
107 P_RemoveActiveCeiling(ceiling);
108 break;
109
110 // movers with texture change, change the texture then get removed
111 case genCeilingChgT:
112 case genCeilingChg0:
113 ceiling->sector->special = ceiling->newspecial;
114 //jff 3/14/98 transfer old special field as well
115 ceiling->sector->oldspecial = ceiling->oldspecial;
116 case genCeilingChg:
117 ceiling->sector->ceilingpic = ceiling->texture;
118 P_RemoveActiveCeiling(ceiling);
119 break;
120
121 // crushers reverse direction at the top
122 case silentCrushAndRaise:
123 S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop);
124 /* fallthrough */
125 case genSilentCrusher:
126 case genCrusher:
127 case fastCrushAndRaise:
128 case crushAndRaise:
129 ceiling->direction = -1;
130 break;
131
132 default:
133 break;
134 }
135 }
136 break;
137
138 case -1:
139 // Ceiling moving down
140 res = T_MovePlane
141 (
142 ceiling->sector,
143 ceiling->speed,
144 ceiling->bottomheight,
145 ceiling->crush,
146 1,
147 ceiling->direction
148 );
149
150 // if not silent crusher type make moving sound
151 if (!(leveltime&7))
152 {
153 switch(ceiling->type)
154 {
155 case silentCrushAndRaise:
156 case genSilentCrusher:
157 break;
158 default:
159 S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_stnmov);
160 }
161 }
162
163 // handle reaching destination height
164 if (res == pastdest)
165 {
166 switch(ceiling->type)
167 {
168 // 02/09/98 jff change slow crushers' speed back to normal
169 // start back up
170 case genSilentCrusher:
171 case genCrusher:
172 if (ceiling->oldspeed<CEILSPEED*3)
173 ceiling->speed = ceiling->oldspeed;
174 ceiling->direction = 1; //jff 2/22/98 make it go back up!
175 break;
176
177 // make platform stop at bottom of all crusher strokes
178 // except generalized ones, reset speed, start back up
179 case silentCrushAndRaise:
180 S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop);
181 /* fallthrough */
182 case crushAndRaise:
183 ceiling->speed = CEILSPEED;
184 /* fallthrough */
185 case fastCrushAndRaise:
186 ceiling->direction = 1;
187 break;
188
189 // in the case of ceiling mover/changer, change the texture
190 // then remove the active ceiling
191 case genCeilingChgT:
192 case genCeilingChg0:
193 ceiling->sector->special = ceiling->newspecial;
194 //jff add to fix bug in special transfers from changes
195 ceiling->sector->oldspecial = ceiling->oldspecial;
196 case genCeilingChg:
197 ceiling->sector->ceilingpic = ceiling->texture;
198 P_RemoveActiveCeiling(ceiling);
199 break;
200
201 // all other case, just remove the active ceiling
202 case lowerAndCrush:
203 case lowerToFloor:
204 case lowerToLowest:
205 case lowerToMaxFloor:
206 case genCeiling:
207 P_RemoveActiveCeiling(ceiling);
208 break;
209
210 default:
211 break;
212 }
213 }
214 else // ( res != pastdest )
215 {
216 // handle the crusher encountering an obstacle
217 if (res == crushed)
218 {
219 switch(ceiling->type)
220 {
221 //jff 02/08/98 slow down slow crushers on obstacle
222 case genCrusher:
223 case genSilentCrusher:
224 if (ceiling->oldspeed < CEILSPEED*3)
225 ceiling->speed = CEILSPEED / 8;
226 break;
227 case silentCrushAndRaise:
228 case crushAndRaise:
229 case lowerAndCrush:
230 ceiling->speed = CEILSPEED / 8;
231 break;
232
233 default:
234 break;
235 }
236 }
237 }
238 break;
239 }
240}
241
242
243//
244// EV_DoCeiling
245//
246// Move a ceiling up/down or start a crusher
247//
248// Passed the linedef activating the function and the type of function desired
249// returns true if a thinker started
250//
251int EV_DoCeiling
252( line_t* line,
253 ceiling_e type )
254{
255 int secnum;
256 int rtn;
257 sector_t* sec;
258 ceiling_t* ceiling;
259
260 secnum = -1;
261 rtn = 0;
262
263 // Reactivate in-stasis ceilings...for certain types.
264 // This restarts a crusher after it has been stopped
265 switch(type)
266 {
267 case fastCrushAndRaise:
268 case silentCrushAndRaise:
269 case crushAndRaise:
270 //jff 4/5/98 return if activated
271 rtn = P_ActivateInStasisCeiling(line);
272 default:
273 break;
274 }
275
276 // affects all sectors with the same tag as the linedef
277 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
278 {
279 sec = §ors[secnum];
280
281 // if ceiling already moving, don't start a second function on it
282 if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98
283 continue;
284
285 // create a new ceiling thinker
286 rtn = 1;
287 ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0);
288 P_AddThinker (&ceiling->thinker);
289 sec->ceilingdata = ceiling; //jff 2/22/98
290 ceiling->thinker.function = T_MoveCeiling;
291 ceiling->sector = sec;
292 ceiling->crush = false;
293
294 // setup ceiling structure according to type of function
295 switch(type)
296 {
297 case fastCrushAndRaise:
298 ceiling->crush = true;
299 ceiling->topheight = sec->ceilingheight;
300 ceiling->bottomheight = sec->floorheight + (8*FRACUNIT);
301 ceiling->direction = -1;
302 ceiling->speed = CEILSPEED * 2;
303 break;
304
305 case silentCrushAndRaise:
306 case crushAndRaise:
307 ceiling->crush = true;
308 ceiling->topheight = sec->ceilingheight;
309 case lowerAndCrush:
310 case lowerToFloor:
311 ceiling->bottomheight = sec->floorheight;
312 if (type != lowerToFloor)
313 ceiling->bottomheight += 8*FRACUNIT;
314 ceiling->direction = -1;
315 ceiling->speed = CEILSPEED;
316 break;
317
318 case raiseToHighest:
319 ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
320 ceiling->direction = 1;
321 ceiling->speed = CEILSPEED;
322 break;
323
324 case lowerToLowest:
325 ceiling->bottomheight = P_FindLowestCeilingSurrounding(sec);
326 ceiling->direction = -1;
327 ceiling->speed = CEILSPEED;
328 break;
329
330 case lowerToMaxFloor:
331 ceiling->bottomheight = P_FindHighestFloorSurrounding(sec);
332 ceiling->direction = -1;
333 ceiling->speed = CEILSPEED;
334 break;
335
336 default:
337 break;
338 }
339
340 // add the ceiling to the active list
341 ceiling->tag = sec->tag;
342 ceiling->type = type;
343 P_AddActiveCeiling(ceiling);
344 }
345 return rtn;
346}
347
348//////////////////////////////////////////////////////////////////////
349//
350// Active ceiling list primitives
351//
352/////////////////////////////////////////////////////////////////////
353
354// jff 2/22/98 - modified Lee's plat code to work for ceilings
355//
356// The following were all rewritten by Lee Killough
357// to use the new structure which places no limits
358// on active ceilings. It also avoids spending as much
359// time searching for active ceilings. Previously a
360// fixed-size array was used, with NULL indicating
361// empty entries, while now a doubly-linked list
362// is used.
363
364//
365// P_ActivateInStasisCeiling()
366//
367// Reactivates all stopped crushers with the right tag
368//
369// Passed the line reactivating the crusher
370// Returns true if a ceiling reactivated
371//
372//jff 4/5/98 return if activated
373int P_ActivateInStasisCeiling(line_t *line)
374{
375 ceilinglist_t *cl;
376 int rtn=0;
377
378 for (cl=activeceilings; cl; cl=cl->next)
379 {
380 ceiling_t *ceiling = cl->ceiling;
381 if (ceiling->tag == line->tag && ceiling->direction == 0)
382 {
383 ceiling->direction = ceiling->olddirection;
384 ceiling->thinker.function = T_MoveCeiling;
385 //jff 4/5/98 return if activated
386 rtn=1;
387 }
388 }
389 return rtn;
390}
391
392//
393// EV_CeilingCrushStop()
394//
395// Stops all active ceilings with the right tag
396//
397// Passed the linedef stopping the ceilings
398// Returns true if a ceiling put in stasis
399//
400int EV_CeilingCrushStop(line_t* line)
401{
402 int rtn=0;
403
404 ceilinglist_t *cl;
405 for (cl=activeceilings; cl; cl=cl->next)
406 {
407 ceiling_t *ceiling = cl->ceiling;
408 if (ceiling->direction != 0 && ceiling->tag == line->tag)
409 {
410 ceiling->olddirection = ceiling->direction;
411 ceiling->direction = 0;
412 ceiling->thinker.function = NULL;
413 rtn=1;
414 }
415 }
416 return rtn;
417}
418
419//
420// P_AddActiveCeiling()
421//
422// Adds a ceiling to the head of the list of active ceilings
423//
424// Passed the ceiling motion structure
425// Returns nothing
426//
427void P_AddActiveCeiling(ceiling_t* ceiling)
428{
429 ceilinglist_t *list = malloc(sizeof *list);
430 list->ceiling = ceiling;
431 ceiling->list = list;
432 if ((list->next = activeceilings))
433 list->next->prev = &list->next;
434 list->prev = &activeceilings;
435 activeceilings = list;
436}
437
438//
439// P_RemoveActiveCeiling()
440//
441// Removes a ceiling from the list of active ceilings
442//
443// Passed the ceiling motion structure
444// Returns nothing
445//
446void P_RemoveActiveCeiling(ceiling_t* ceiling)
447{
448 ceilinglist_t *list = ceiling->list;
449 ceiling->sector->ceilingdata = NULL; //jff 2/22/98
450 P_RemoveThinker(&ceiling->thinker);
451 if ((*list->prev = list->next))
452 list->next->prev = list->prev;
453 free(list);
454}
455
456//
457// P_RemoveAllActiveCeilings()
458//
459// Removes all ceilings from the active ceiling list
460//
461// Passed nothing, returns nothing
462//
463void P_RemoveAllActiveCeilings(void)
464{
465 while (activeceilings)
466 {
467 ceilinglist_t *next = activeceilings->next;
468 free(activeceilings);
469 activeceilings = next;
470 }
471}