Prepare new maemo release
[maemo-rb.git] / apps / plugins / doom / p_plats.c
blob4a5c28bb883df376255e92555c9eaf3cb4b11170
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
25 * 02111-1307, USA.
27 * DESCRIPTION:
28 * Plats (i.e. elevator platforms) code, raising/lowering.
30 *-----------------------------------------------------------------------------*/
32 #include "doomstat.h"
33 #include "m_random.h"
34 #include "r_main.h"
35 #include "p_spec.h"
36 #include "p_tick.h"
37 #include "s_sound.h"
38 #include "sounds.h"
39 #include "rockmacros.h"
40 platlist_t *activeplats; // killough 2/14/98: made global again
43 // T_PlatRaise()
45 // Action routine to move a plat up and down
47 // Passed a plat structure containing all pertinent information about the move
48 // No return
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)
55 result_e res;
57 // handle plat moving, up, down, waiting, or in stasis,
58 switch(plat->status)
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)
67 if (!(leveltime&7))
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;
75 plat->status = down;
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
97 switch(plat->type)
99 case blazeDWUS:
100 case downWaitUpStay:
101 case raiseAndChange:
102 case raiseToNearestAndChange:
103 case genLift:
104 P_RemoveActivePlat(plat); // killough
105 default:
106 break;
110 break;
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
116 if (res == pastdest)
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])
138 switch(plat->type)
140 case raiseAndChange:
141 case raiseToNearestAndChange:
142 P_RemoveActivePlat(plat);
143 default:
144 break;
148 break;
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
155 else
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
164 break;
170 // EV_DoPlat
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
178 int EV_DoPlat
179 ( line_t* line,
180 plattype_e type,
181 int amount )
183 plat_t* plat;
184 int secnum;
185 int rtn;
186 sector_t* sec;
188 secnum = -1;
189 rtn = 0;
192 // Activate all <type> plats that are in_stasis
193 switch(type)
195 case perpetualRaise:
196 P_ActivateInStasis(line->tag);
197 break;
199 case toggleUpDn:
200 P_ActivateInStasis(line->tag);
201 rtn=1;
202 break;
204 default:
205 break;
208 // act on all sectors tagged the same as the activating linedef
209 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
211 sec = &sectors[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
215 continue;
217 // Create a thinker
218 rtn = 1;
219 plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0);
220 P_AddThinker(&plat->thinker);
222 plat->type = type;
223 plat->sector = sec;
224 plat->sector->floordata = plat; //jff 2/23/98 multiple thinkers
225 plat->thinker.function = T_PlatRaise;
226 plat->crush = false;
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
234 switch(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);
240 plat->wait = 0;
241 plat->status = up;
242 sec->special = 0;
243 //jff 3/14/98 clear old field as well
244 sec->oldspecial = 0;
246 S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov);
247 break;
249 case raiseAndChange:
250 plat->speed = PLATSPEED/2;
251 sec->floorpic = sides[line->sidenum[0]].sector->floorpic;
252 plat->high = sec->floorheight + amount*FRACUNIT;
253 plat->wait = 0;
254 plat->status = up;
256 S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov);
257 break;
259 case downWaitUpStay:
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;
268 plat->status = down;
269 S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart);
270 break;
272 case blazeDWUS:
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;
281 plat->status = down;
282 S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart);
283 break;
285 case perpetualRaise:
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);
301 break;
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;
311 plat->status = down;
312 break;
314 default:
315 break;
317 P_AddActivePlat(plat); // add plat to list of active plats
319 return rtn;
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
328 // is used.
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
337 // Returns nothing
339 void P_ActivateInStasis(int tag)
341 platlist_t *pl;
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;
349 else
350 plat->status = plat->oldstatus;
351 plat->thinker.function = T_PlatRaise;
357 // EV_StopPlat()
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)
368 platlist_t *pl;
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;
379 return 1;
383 // P_AddActivePlat()
385 // Add a plat to the head of the active plat list
387 // Passed a pointer to the plat to add
388 // Returns nothing
390 void P_AddActivePlat(plat_t* plat)
392 platlist_t *list = malloc(sizeof *list);
393 list->plat = plat;
394 plat->list = list;
395 if ((list->next = activeplats))
396 list->next->prev = &list->next;
397 list->prev = &activeplats;
398 activeplats = list;
402 // P_RemoveActivePlat()
404 // Remove a plat from the active plat list
406 // Passed a pointer to the plat to remove
407 // Returns nothing
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;
416 free(list);
420 // P_RemoveAllActivePlats()
422 // Remove all plats from the active plat list
424 // Passed nothing, returns nothing
426 void P_RemoveAllActivePlats(void)
428 while (activeplats)
430 platlist_t *next = activeplats->next;
431 free(activeplats);
432 activeplats = next;