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 * Plats (i.e. elevator platforms) code, raising/lowering.
30 *-----------------------------------------------------------------------------*/
39 #include "rockmacros.h"
40 platlist_t
*activeplats
; // killough 2/14/98: made global again
45 // Action routine to move a plat up and down
47 // Passed a plat structure containing all pertinent information about the move
50 // jff 02/08/98 all cases with labels beginning with gen added to support
51 // generalized line type behaviors.
53 void T_PlatRaise(plat_t
* plat
)
57 // handle plat moving, up, down, waiting, or in stasis,
60 case up
: // plat moving up
61 res
= T_MovePlane(plat
->sector
,plat
->speed
,plat
->high
,plat
->crush
,0,1);
63 // if a pure raise type, make the plat moving sound
64 if (plat
->type
== raiseAndChange
65 || plat
->type
== raiseToNearestAndChange
)
68 S_StartSound((mobj_t
*)&plat
->sector
->soundorg
, sfx_stnmov
);
71 // if encountered an obstacle, and not a crush type, reverse direction
72 if (res
== crushed
&& (!plat
->crush
))
74 plat
->count
= plat
->wait
;
76 S_StartSound((mobj_t
*)&plat
->sector
->soundorg
, sfx_pstart
);
78 else // else handle reaching end of up stroke
80 if (res
== pastdest
) // end of stroke
82 // if not an instant toggle type, wait, make plat stop sound
83 if (plat
->type
!=toggleUpDn
)
85 plat
->count
= plat
->wait
;
86 plat
->status
= waiting
;
87 S_StartSound((mobj_t
*)&plat
->sector
->soundorg
, sfx_pstop
);
89 else // else go into stasis awaiting next toggle activation
91 plat
->oldstatus
= plat
->status
;//jff 3/14/98 after action wait
92 plat
->status
= in_stasis
; //for reactivation of toggle
95 // lift types and pure raise types are done at end of up stroke
96 // only the perpetual type waits then goes back up
102 case raiseToNearestAndChange
:
104 P_RemoveActivePlat(plat
); // killough
112 case down
: // plat moving down
113 res
= T_MovePlane(plat
->sector
,plat
->speed
,plat
->low
,false,0,-1);
115 // handle reaching end of down stroke
118 // if not an instant toggle, start waiting, make plat stop sound
119 if (plat
->type
!=toggleUpDn
) //jff 3/14/98 toggle up down
120 { // is silent, instant, no waiting
121 plat
->count
= plat
->wait
;
122 plat
->status
= waiting
;
123 S_StartSound((mobj_t
*)&plat
->sector
->soundorg
,sfx_pstop
);
125 else // instant toggles go into stasis awaiting next activation
127 plat
->oldstatus
= plat
->status
;//jff 3/14/98 after action wait
128 plat
->status
= in_stasis
; //for reactivation of toggle
131 //jff 1/26/98 remove the plat if it bounced so it can be tried again
132 //only affects plats that raise and bounce
133 //killough 1/31/98: relax compatibility to demo_compatibility
135 // remove the plat if its a pure raise type
136 if (!comp
[comp_floors
])
141 case raiseToNearestAndChange
:
142 P_RemoveActivePlat(plat
);
150 case waiting
: // plat is waiting
151 if (!--plat
->count
) // downcount and check for delay elapsed
153 if (plat
->sector
->floorheight
== plat
->low
)
154 plat
->status
= up
; // if at bottom, start up
156 plat
->status
= down
; // if at top, start down
158 // make plat start sound
159 S_StartSound((mobj_t
*)&plat
->sector
->soundorg
,sfx_pstart
);
161 break; //jff 1/27/98 don't pickup code added later to in_stasis
163 case in_stasis
: // do nothing if in stasis
172 // Handle Plat linedef types
174 // Passed the linedef that activated the plat, the type of plat action,
175 // and for some plat types, an amount to raise
176 // Returns true if a thinker is started, or restarted from stasis
192 // Activate all <type> plats that are in_stasis
196 P_ActivateInStasis(line
->tag
);
200 P_ActivateInStasis(line
->tag
);
208 // act on all sectors tagged the same as the activating linedef
209 while ((secnum
= P_FindSectorFromLineTag(line
,secnum
)) >= 0)
211 sec
= §ors
[secnum
];
213 // don't start a second floor function if already moving
214 if (P_SectorActive(floor_special
,sec
)) //jff 2/23/98 multiple thinkers
219 plat
= Z_Malloc( sizeof(*plat
), PU_LEVSPEC
, 0);
220 P_AddThinker(&plat
->thinker
);
224 plat
->sector
->floordata
= plat
; //jff 2/23/98 multiple thinkers
225 plat
->thinker
.function
= T_PlatRaise
;
227 plat
->tag
= line
->tag
;
229 //jff 1/26/98 Avoid raise plat bouncing a head off a ceiling and then
230 //going down forever -- default low to plat height when triggered
231 plat
->low
= sec
->floorheight
;
233 // set up plat according to type
236 case raiseToNearestAndChange
:
237 plat
->speed
= PLATSPEED
/2;
238 sec
->floorpic
= sides
[line
->sidenum
[0]].sector
->floorpic
;
239 plat
->high
= P_FindNextHighestFloor(sec
,sec
->floorheight
);
243 //jff 3/14/98 clear old field as well
246 S_StartSound((mobj_t
*)&sec
->soundorg
,sfx_stnmov
);
250 plat
->speed
= PLATSPEED
/2;
251 sec
->floorpic
= sides
[line
->sidenum
[0]].sector
->floorpic
;
252 plat
->high
= sec
->floorheight
+ amount
*FRACUNIT
;
256 S_StartSound((mobj_t
*)&sec
->soundorg
,sfx_stnmov
);
260 plat
->speed
= PLATSPEED
* 4;
261 plat
->low
= P_FindLowestFloorSurrounding(sec
);
263 if (plat
->low
> sec
->floorheight
)
264 plat
->low
= sec
->floorheight
;
266 plat
->high
= sec
->floorheight
;
267 plat
->wait
= 35*PLATWAIT
;
269 S_StartSound((mobj_t
*)&sec
->soundorg
,sfx_pstart
);
273 plat
->speed
= PLATSPEED
* 8;
274 plat
->low
= P_FindLowestFloorSurrounding(sec
);
276 if (plat
->low
> sec
->floorheight
)
277 plat
->low
= sec
->floorheight
;
279 plat
->high
= sec
->floorheight
;
280 plat
->wait
= 35*PLATWAIT
;
282 S_StartSound((mobj_t
*)&sec
->soundorg
,sfx_pstart
);
286 plat
->speed
= PLATSPEED
;
287 plat
->low
= P_FindLowestFloorSurrounding(sec
);
289 if (plat
->low
> sec
->floorheight
)
290 plat
->low
= sec
->floorheight
;
292 plat
->high
= P_FindHighestFloorSurrounding(sec
);
294 if (plat
->high
< sec
->floorheight
)
295 plat
->high
= sec
->floorheight
;
297 plat
->wait
= 35*PLATWAIT
;
298 plat
->status
= P_Random(pr_plats
)&1;
300 S_StartSound((mobj_t
*)&sec
->soundorg
,sfx_pstart
);
303 case toggleUpDn
: //jff 3/14/98 add new type to support instant toggle
304 plat
->speed
= PLATSPEED
; //not used
305 plat
->wait
= 35*PLATWAIT
; //not used
306 plat
->crush
= true; //jff 3/14/98 crush anything in the way
308 // set up toggling between ceiling, floor inclusive
309 plat
->low
= sec
->ceilingheight
;
310 plat
->high
= sec
->floorheight
;
317 P_AddActivePlat(plat
); // add plat to list of active plats
322 // The following were all rewritten by Lee Killough
323 // to use the new structure which places no limits
324 // on active plats. It also avoids spending as much
325 // time searching for active plats. Previously a
326 // fixed-size array was used, with NULL indicating
327 // empty entries, while now a doubly-linked list
331 // P_ActivateInStasis()
333 // Activate a plat that has been put in stasis
334 // (stopped perpetual floor, instant floor/ceil toggle)
336 // Passed the tag of the plat that should be reactivated
339 void P_ActivateInStasis(int tag
)
342 for (pl
=activeplats
; pl
; pl
=pl
->next
) // search the active plats
344 plat_t
*plat
= pl
->plat
; // for one in stasis with right tag
345 if (plat
->tag
== tag
&& plat
->status
== in_stasis
)
347 if (plat
->type
==toggleUpDn
) //jff 3/14/98 reactivate toggle type
348 plat
->status
= plat
->oldstatus
==up
? down
: up
;
350 plat
->status
= plat
->oldstatus
;
351 plat
->thinker
.function
= T_PlatRaise
;
359 // Handler for "stop perpetual floor" linedef type
361 // Passed the linedef that stopped the plat
362 // Returns true if a plat was put in stasis
364 // jff 2/12/98 added int return value, fixed return
366 int EV_StopPlat(line_t
* line
)
369 for (pl
=activeplats
; pl
; pl
=pl
->next
) // search the active plats
371 plat_t
*plat
= pl
->plat
; // for one with the tag not in stasis
372 if (plat
->status
!= in_stasis
&& plat
->tag
== line
->tag
)
374 plat
->oldstatus
= plat
->status
; // put it in stasis
375 plat
->status
= in_stasis
;
376 plat
->thinker
.function
= NULL
;
385 // Add a plat to the head of the active plat list
387 // Passed a pointer to the plat to add
390 void P_AddActivePlat(plat_t
* plat
)
392 platlist_t
*list
= malloc(sizeof *list
);
395 if ((list
->next
= activeplats
))
396 list
->next
->prev
= &list
->next
;
397 list
->prev
= &activeplats
;
402 // P_RemoveActivePlat()
404 // Remove a plat from the active plat list
406 // Passed a pointer to the plat to remove
409 void P_RemoveActivePlat(plat_t
* plat
)
411 platlist_t
*list
= plat
->list
;
412 plat
->sector
->floordata
= NULL
; //jff 2/23/98 multiple thinkers
413 P_RemoveThinker(&plat
->thinker
);
414 if ((*list
->prev
= list
->next
))
415 list
->next
->prev
= list
->prev
;
420 // P_RemoveAllActivePlats()
422 // Remove all plats from the active plat list
424 // Passed nothing, returns nothing
426 void P_RemoveAllActivePlats(void)
430 platlist_t
*next
= activeplats
->next
;