1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
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
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.
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.
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
28 * Ceiling aninmation (lowering, crushing, raising)
30 *-----------------------------------------------------------------------------*/
40 #define PU_LEVSPEC 51 // a special thinker in a level
41 #include "rockmacros.h"
43 // the list of ceilings moving currently, including crushers
44 ceilinglist_t
*activeceilings
;
46 /////////////////////////////////////////////////////////////////
48 // Ceiling action routine and linedef type handler
50 /////////////////////////////////////////////////////////////////
55 // Action routine that moves ceilings. Called once per tick.
57 // Passed a ceiling_t structure that contains all the info about the move.
58 // see P_SPEC.H for fields. No return.
60 // jff 02/08/98 all cases with labels beginning with gen added to support
61 // generalized line type behaviors.
63 void T_MoveCeiling (ceiling_t
* ceiling
)
67 switch(ceiling
->direction
)
70 // If ceiling in stasis, do nothing
74 // Ceiling is moving up
85 // if not a silent crusher, make moving sound
90 case silentCrushAndRaise
:
91 case genSilentCrusher
:
94 S_StartSound((mobj_t
*)&ceiling
->sector
->soundorg
,sfx_stnmov
);
99 // handle reaching destination height
102 switch(ceiling
->type
)
104 // plain movers are just removed
107 P_RemoveActiveCeiling(ceiling
);
110 // movers with texture change, change the texture then get removed
113 ceiling
->sector
->special
= ceiling
->newspecial
;
114 //jff 3/14/98 transfer old special field as well
115 ceiling
->sector
->oldspecial
= ceiling
->oldspecial
;
117 ceiling
->sector
->ceilingpic
= ceiling
->texture
;
118 P_RemoveActiveCeiling(ceiling
);
121 // crushers reverse direction at the top
122 case silentCrushAndRaise
:
123 S_StartSound((mobj_t
*)&ceiling
->sector
->soundorg
,sfx_pstop
);
124 case genSilentCrusher
:
126 case fastCrushAndRaise
:
128 ceiling
->direction
= -1;
138 // Ceiling moving down
143 ceiling
->bottomheight
,
149 // if not silent crusher type make moving sound
152 switch(ceiling
->type
)
154 case silentCrushAndRaise
:
155 case genSilentCrusher
:
158 S_StartSound((mobj_t
*)&ceiling
->sector
->soundorg
,sfx_stnmov
);
162 // handle reaching destination height
165 switch(ceiling
->type
)
167 // 02/09/98 jff change slow crushers' speed back to normal
169 case genSilentCrusher
:
171 if (ceiling
->oldspeed
<CEILSPEED
*3)
172 ceiling
->speed
= ceiling
->oldspeed
;
173 ceiling
->direction
= 1; //jff 2/22/98 make it go back up!
176 // make platform stop at bottom of all crusher strokes
177 // except generalized ones, reset speed, start back up
178 case silentCrushAndRaise
:
179 S_StartSound((mobj_t
*)&ceiling
->sector
->soundorg
,sfx_pstop
);
181 ceiling
->speed
= CEILSPEED
;
182 case fastCrushAndRaise
:
183 ceiling
->direction
= 1;
186 // in the case of ceiling mover/changer, change the texture
187 // then remove the active ceiling
190 ceiling
->sector
->special
= ceiling
->newspecial
;
191 //jff add to fix bug in special transfers from changes
192 ceiling
->sector
->oldspecial
= ceiling
->oldspecial
;
194 ceiling
->sector
->ceilingpic
= ceiling
->texture
;
195 P_RemoveActiveCeiling(ceiling
);
198 // all other case, just remove the active ceiling
202 case lowerToMaxFloor
:
204 P_RemoveActiveCeiling(ceiling
);
211 else // ( res != pastdest )
213 // handle the crusher encountering an obstacle
216 switch(ceiling
->type
)
218 //jff 02/08/98 slow down slow crushers on obstacle
220 case genSilentCrusher
:
221 if (ceiling
->oldspeed
< CEILSPEED
*3)
222 ceiling
->speed
= CEILSPEED
/ 8;
224 case silentCrushAndRaise
:
227 ceiling
->speed
= CEILSPEED
/ 8;
243 // Move a ceiling up/down or start a crusher
245 // Passed the linedef activating the function and the type of function desired
246 // returns true if a thinker started
260 // Reactivate in-stasis ceilings...for certain types.
261 // This restarts a crusher after it has been stopped
264 case fastCrushAndRaise
:
265 case silentCrushAndRaise
:
267 //jff 4/5/98 return if activated
268 rtn
= P_ActivateInStasisCeiling(line
);
273 // affects all sectors with the same tag as the linedef
274 while ((secnum
= P_FindSectorFromLineTag(line
,secnum
)) >= 0)
276 sec
= §ors
[secnum
];
278 // if ceiling already moving, don't start a second function on it
279 if (P_SectorActive(ceiling_special
,sec
)) //jff 2/22/98
282 // create a new ceiling thinker
284 ceiling
= Z_Malloc (sizeof(*ceiling
), PU_LEVSPEC
, 0);
285 P_AddThinker (&ceiling
->thinker
);
286 sec
->ceilingdata
= ceiling
; //jff 2/22/98
287 ceiling
->thinker
.function
= T_MoveCeiling
;
288 ceiling
->sector
= sec
;
289 ceiling
->crush
= false;
291 // setup ceiling structure according to type of function
294 case fastCrushAndRaise
:
295 ceiling
->crush
= true;
296 ceiling
->topheight
= sec
->ceilingheight
;
297 ceiling
->bottomheight
= sec
->floorheight
+ (8*FRACUNIT
);
298 ceiling
->direction
= -1;
299 ceiling
->speed
= CEILSPEED
* 2;
302 case silentCrushAndRaise
:
304 ceiling
->crush
= true;
305 ceiling
->topheight
= sec
->ceilingheight
;
308 ceiling
->bottomheight
= sec
->floorheight
;
309 if (type
!= lowerToFloor
)
310 ceiling
->bottomheight
+= 8*FRACUNIT
;
311 ceiling
->direction
= -1;
312 ceiling
->speed
= CEILSPEED
;
316 ceiling
->topheight
= P_FindHighestCeilingSurrounding(sec
);
317 ceiling
->direction
= 1;
318 ceiling
->speed
= CEILSPEED
;
322 ceiling
->bottomheight
= P_FindLowestCeilingSurrounding(sec
);
323 ceiling
->direction
= -1;
324 ceiling
->speed
= CEILSPEED
;
327 case lowerToMaxFloor
:
328 ceiling
->bottomheight
= P_FindHighestFloorSurrounding(sec
);
329 ceiling
->direction
= -1;
330 ceiling
->speed
= CEILSPEED
;
337 // add the ceiling to the active list
338 ceiling
->tag
= sec
->tag
;
339 ceiling
->type
= type
;
340 P_AddActiveCeiling(ceiling
);
345 //////////////////////////////////////////////////////////////////////
347 // Active ceiling list primitives
349 /////////////////////////////////////////////////////////////////////
351 // jff 2/22/98 - modified Lee's plat code to work for ceilings
353 // The following were all rewritten by Lee Killough
354 // to use the new structure which places no limits
355 // on active ceilings. It also avoids spending as much
356 // time searching for active ceilings. Previously a
357 // fixed-size array was used, with NULL indicating
358 // empty entries, while now a doubly-linked list
362 // P_ActivateInStasisCeiling()
364 // Reactivates all stopped crushers with the right tag
366 // Passed the line reactivating the crusher
367 // Returns true if a ceiling reactivated
369 //jff 4/5/98 return if activated
370 int P_ActivateInStasisCeiling(line_t
*line
)
375 for (cl
=activeceilings
; cl
; cl
=cl
->next
)
377 ceiling_t
*ceiling
= cl
->ceiling
;
378 if (ceiling
->tag
== line
->tag
&& ceiling
->direction
== 0)
380 ceiling
->direction
= ceiling
->olddirection
;
381 ceiling
->thinker
.function
= T_MoveCeiling
;
382 //jff 4/5/98 return if activated
390 // EV_CeilingCrushStop()
392 // Stops all active ceilings with the right tag
394 // Passed the linedef stopping the ceilings
395 // Returns true if a ceiling put in stasis
397 int EV_CeilingCrushStop(line_t
* line
)
402 for (cl
=activeceilings
; cl
; cl
=cl
->next
)
404 ceiling_t
*ceiling
= cl
->ceiling
;
405 if (ceiling
->direction
!= 0 && ceiling
->tag
== line
->tag
)
407 ceiling
->olddirection
= ceiling
->direction
;
408 ceiling
->direction
= 0;
409 ceiling
->thinker
.function
= NULL
;
417 // P_AddActiveCeiling()
419 // Adds a ceiling to the head of the list of active ceilings
421 // Passed the ceiling motion structure
424 void P_AddActiveCeiling(ceiling_t
* ceiling
)
426 ceilinglist_t
*list
= malloc(sizeof *list
);
427 list
->ceiling
= ceiling
;
428 ceiling
->list
= list
;
429 if ((list
->next
= activeceilings
))
430 list
->next
->prev
= &list
->next
;
431 list
->prev
= &activeceilings
;
432 activeceilings
= list
;
436 // P_RemoveActiveCeiling()
438 // Removes a ceiling from the list of active ceilings
440 // Passed the ceiling motion structure
443 void P_RemoveActiveCeiling(ceiling_t
* ceiling
)
445 ceilinglist_t
*list
= ceiling
->list
;
446 ceiling
->sector
->ceilingdata
= NULL
; //jff 2/22/98
447 P_RemoveThinker(&ceiling
->thinker
);
448 if ((*list
->prev
= list
->next
))
449 list
->next
->prev
= list
->prev
;
454 // P_RemoveAllActiveCeilings()
456 // Removes all ceilings from the active ceiling list
458 // Passed nothing, returns nothing
460 void P_RemoveAllActiveCeilings(void)
462 while (activeceilings
)
464 ceilinglist_t
*next
= activeceilings
->next
;
465 free(activeceilings
);
466 activeceilings
= next
;