diff options
Diffstat (limited to 'src/p_floor.c')
-rw-r--r-- | src/p_floor.c | 1042 |
1 files changed, 1042 insertions, 0 deletions
diff --git a/src/p_floor.c b/src/p_floor.c new file mode 100644 index 0000000..ba55fdf --- /dev/null +++ b/src/p_floor.c | |||
@@ -0,0 +1,1042 @@ | |||
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 | * General plane mover and floor mover action routines | ||
31 | * Floor motion, pure changer types, raising stairs. donuts, elevators | ||
32 | * | ||
33 | *-----------------------------------------------------------------------------*/ | ||
34 | |||
35 | #include "doomstat.h" | ||
36 | #include "r_main.h" | ||
37 | #include "p_map.h" | ||
38 | #include "p_spec.h" | ||
39 | #include "p_tick.h" | ||
40 | #include "s_sound.h" | ||
41 | #include "sounds.h" | ||
42 | |||
43 | /////////////////////////////////////////////////////////////////////// | ||
44 | // | ||
45 | // Plane (floor or ceiling), Floor motion and Elevator action routines | ||
46 | // | ||
47 | /////////////////////////////////////////////////////////////////////// | ||
48 | |||
49 | // | ||
50 | // T_MovePlane() | ||
51 | // | ||
52 | // Move a plane (floor or ceiling) and check for crushing. Called | ||
53 | // every tick by all actions that move floors or ceilings. | ||
54 | // | ||
55 | // Passed the sector to move a plane in, the speed to move it at, | ||
56 | // the dest height it is to achieve, whether it crushes obstacles, | ||
57 | // whether it moves a floor or ceiling, and the direction up or down | ||
58 | // to move. | ||
59 | // | ||
60 | // Returns a result_e: | ||
61 | // ok - plane moved normally, has not achieved destination yet | ||
62 | // pastdest - plane moved normally and is now at destination height | ||
63 | // crushed - plane encountered an obstacle, is holding until removed | ||
64 | // | ||
65 | result_e T_MovePlane | ||
66 | ( sector_t* sector, | ||
67 | fixed_t speed, | ||
68 | fixed_t dest, | ||
69 | boolean crush, | ||
70 | int floorOrCeiling, | ||
71 | int direction ) | ||
72 | { | ||
73 | boolean flag; | ||
74 | fixed_t lastpos; | ||
75 | fixed_t destheight; //jff 02/04/98 used to keep floors/ceilings | ||
76 | // from moving thru each other | ||
77 | |||
78 | switch(floorOrCeiling) | ||
79 | { | ||
80 | case 0: | ||
81 | // Moving a floor | ||
82 | switch(direction) | ||
83 | { | ||
84 | case -1: | ||
85 | // Moving a floor down | ||
86 | if (sector->floorheight - speed < dest) | ||
87 | { | ||
88 | lastpos = sector->floorheight; | ||
89 | sector->floorheight = dest; | ||
90 | flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
91 | if (flag == true) | ||
92 | { | ||
93 | sector->floorheight =lastpos; | ||
94 | P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
95 | } | ||
96 | return pastdest; | ||
97 | } | ||
98 | else | ||
99 | { | ||
100 | lastpos = sector->floorheight; | ||
101 | sector->floorheight -= speed; | ||
102 | flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
103 | /* cph - make more compatible with original Doom, by | ||
104 | * reintroducing this code. This means floors can't lower | ||
105 | * if objects are stuck in the ceiling */ | ||
106 | if ((flag == true) && comp[comp_floors]) { | ||
107 | sector->floorheight = lastpos; | ||
108 | P_ChangeSector(sector,crush); | ||
109 | return crushed; | ||
110 | } | ||
111 | } | ||
112 | break; | ||
113 | |||
114 | case 1: | ||
115 | // Moving a floor up | ||
116 | // jff 02/04/98 keep floor from moving thru ceilings | ||
117 | // jff 2/22/98 weaken check to demo_compatibility | ||
118 | destheight = (comp[comp_floors] || dest<sector->ceilingheight)? | ||
119 | dest : sector->ceilingheight; | ||
120 | if (sector->floorheight + speed > destheight) | ||
121 | { | ||
122 | lastpos = sector->floorheight; | ||
123 | sector->floorheight = destheight; | ||
124 | flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
125 | if (flag == true) | ||
126 | { | ||
127 | sector->floorheight = lastpos; | ||
128 | P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
129 | } | ||
130 | return pastdest; | ||
131 | } | ||
132 | else | ||
133 | { | ||
134 | // crushing is possible | ||
135 | lastpos = sector->floorheight; | ||
136 | sector->floorheight += speed; | ||
137 | flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
138 | if (flag == true) | ||
139 | { | ||
140 | /* jff 1/25/98 fix floor crusher */ | ||
141 | if (comp[comp_floors]) { | ||
142 | if (crush == true) | ||
143 | return crushed; | ||
144 | } | ||
145 | sector->floorheight = lastpos; | ||
146 | P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
147 | return crushed; | ||
148 | } | ||
149 | } | ||
150 | break; | ||
151 | } | ||
152 | break; | ||
153 | |||
154 | case 1: | ||
155 | // moving a ceiling | ||
156 | switch(direction) | ||
157 | { | ||
158 | case -1: | ||
159 | // moving a ceiling down | ||
160 | // jff 02/04/98 keep ceiling from moving thru floors | ||
161 | // jff 2/22/98 weaken check to demo_compatibility | ||
162 | destheight = (comp[comp_floors] || dest>sector->floorheight)? | ||
163 | dest : sector->floorheight; | ||
164 | if (sector->ceilingheight - speed < destheight) | ||
165 | { | ||
166 | lastpos = sector->ceilingheight; | ||
167 | sector->ceilingheight = destheight; | ||
168 | flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
169 | |||
170 | if (flag == true) | ||
171 | { | ||
172 | sector->ceilingheight = lastpos; | ||
173 | P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
174 | } | ||
175 | return pastdest; | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | // crushing is possible | ||
180 | lastpos = sector->ceilingheight; | ||
181 | sector->ceilingheight -= speed; | ||
182 | flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
183 | |||
184 | if (flag == true) | ||
185 | { | ||
186 | if (crush == true) | ||
187 | return crushed; | ||
188 | sector->ceilingheight = lastpos; | ||
189 | P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
190 | return crushed; | ||
191 | } | ||
192 | } | ||
193 | break; | ||
194 | |||
195 | case 1: | ||
196 | // moving a ceiling up | ||
197 | if (sector->ceilingheight + speed > dest) | ||
198 | { | ||
199 | lastpos = sector->ceilingheight; | ||
200 | sector->ceilingheight = dest; | ||
201 | flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
202 | if (flag == true) | ||
203 | { | ||
204 | sector->ceilingheight = lastpos; | ||
205 | P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
206 | } | ||
207 | return pastdest; | ||
208 | } | ||
209 | else | ||
210 | { | ||
211 | lastpos = sector->ceilingheight; | ||
212 | sector->ceilingheight += speed; | ||
213 | flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk | ||
214 | } | ||
215 | break; | ||
216 | } | ||
217 | break; | ||
218 | } | ||
219 | return ok; | ||
220 | } | ||
221 | |||
222 | // | ||
223 | // T_MoveFloor() | ||
224 | // | ||
225 | // Move a floor to it's destination (up or down). | ||
226 | // Called once per tick for each moving floor. | ||
227 | // | ||
228 | // Passed a floormove_t structure that contains all pertinent info about the | ||
229 | // move. See P_SPEC.H for fields. | ||
230 | // No return. | ||
231 | // | ||
232 | // jff 02/08/98 all cases with labels beginning with gen added to support | ||
233 | // generalized line type behaviors. | ||
234 | |||
235 | void T_MoveFloor(floormove_t* floor) | ||
236 | { | ||
237 | result_e res; | ||
238 | |||
239 | res = T_MovePlane // move the floor | ||
240 | ( | ||
241 | floor->sector, | ||
242 | floor->speed, | ||
243 | floor->floordestheight, | ||
244 | floor->crush, | ||
245 | 0, | ||
246 | floor->direction | ||
247 | ); | ||
248 | |||
249 | if (!(leveltime&7)) // make the floormove sound | ||
250 | S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_stnmov); | ||
251 | |||
252 | if (res == pastdest) // if destination height is reached | ||
253 | { | ||
254 | if (floor->direction == 1) // going up | ||
255 | { | ||
256 | switch(floor->type) // handle texture/type changes | ||
257 | { | ||
258 | case donutRaise: | ||
259 | floor->sector->special = floor->newspecial; | ||
260 | floor->sector->floorpic = floor->texture; | ||
261 | break; | ||
262 | case genFloorChgT: | ||
263 | case genFloorChg0: | ||
264 | floor->sector->special = floor->newspecial; | ||
265 | //jff add to fix bug in special transfers from changes | ||
266 | floor->sector->oldspecial = floor->oldspecial; | ||
267 | //fall thru | ||
268 | case genFloorChg: | ||
269 | floor->sector->floorpic = floor->texture; | ||
270 | break; | ||
271 | default: | ||
272 | break; | ||
273 | } | ||
274 | } | ||
275 | else if (floor->direction == -1) // going down | ||
276 | { | ||
277 | switch(floor->type) // handle texture/type changes | ||
278 | { | ||
279 | case lowerAndChange: | ||
280 | floor->sector->special = floor->newspecial; | ||
281 | //jff add to fix bug in special transfers from changes | ||
282 | floor->sector->oldspecial = floor->oldspecial; | ||
283 | floor->sector->floorpic = floor->texture; | ||
284 | break; | ||
285 | case genFloorChgT: | ||
286 | case genFloorChg0: | ||
287 | floor->sector->special = floor->newspecial; | ||
288 | //jff add to fix bug in special transfers from changes | ||
289 | floor->sector->oldspecial = floor->oldspecial; | ||
290 | //fall thru | ||
291 | case genFloorChg: | ||
292 | floor->sector->floorpic = floor->texture; | ||
293 | break; | ||
294 | default: | ||
295 | break; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | floor->sector->floordata = NULL; //jff 2/22/98 | ||
300 | P_RemoveThinker(&floor->thinker);//remove this floor from list of movers | ||
301 | |||
302 | //jff 2/26/98 implement stair retrigger lockout while still building | ||
303 | // note this only applies to the retriggerable generalized stairs | ||
304 | |||
305 | if (floor->sector->stairlock==-2) // if this sector is stairlocked | ||
306 | { | ||
307 | sector_t *sec = floor->sector; | ||
308 | sec->stairlock=-1; // thinker done, promote lock to -1 | ||
309 | |||
310 | while (sec->prevsec!=-1 && sectors[sec->prevsec].stairlock!=-2) | ||
311 | sec = §ors[sec->prevsec]; // search for a non-done thinker | ||
312 | if (sec->prevsec==-1) // if all thinkers previous are done | ||
313 | { | ||
314 | sec = floor->sector; // search forward | ||
315 | while (sec->nextsec!=-1 && sectors[sec->nextsec].stairlock!=-2) | ||
316 | sec = §ors[sec->nextsec]; | ||
317 | if (sec->nextsec==-1) // if all thinkers ahead are done too | ||
318 | { | ||
319 | while (sec->prevsec!=-1) // clear all locks | ||
320 | { | ||
321 | sec->stairlock = 0; | ||
322 | sec = §ors[sec->prevsec]; | ||
323 | } | ||
324 | sec->stairlock = 0; | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | |||
329 | // make floor stop sound | ||
330 | S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_pstop); | ||
331 | } | ||
332 | } | ||
333 | |||
334 | // | ||
335 | // T_MoveElevator() | ||
336 | // | ||
337 | // Move an elevator to it's destination (up or down) | ||
338 | // Called once per tick for each moving floor. | ||
339 | // | ||
340 | // Passed an elevator_t structure that contains all pertinent info about the | ||
341 | // move. See P_SPEC.H for fields. | ||
342 | // No return. | ||
343 | // | ||
344 | // jff 02/22/98 added to support parallel floor/ceiling motion | ||
345 | // | ||
346 | void T_MoveElevator(elevator_t* elevator) | ||
347 | { | ||
348 | result_e res; | ||
349 | |||
350 | if (elevator->direction<0) // moving down | ||
351 | { | ||
352 | res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor | ||
353 | ( | ||
354 | elevator->sector, | ||
355 | elevator->speed, | ||
356 | elevator->ceilingdestheight, | ||
357 | 0, | ||
358 | 1, // move floor | ||
359 | elevator->direction | ||
360 | ); | ||
361 | if (res==ok || res==pastdest) // jff 4/7/98 don't move ceil if blocked | ||
362 | T_MovePlane | ||
363 | ( | ||
364 | elevator->sector, | ||
365 | elevator->speed, | ||
366 | elevator->floordestheight, | ||
367 | 0, | ||
368 | 0, // move ceiling | ||
369 | elevator->direction | ||
370 | ); | ||
371 | } | ||
372 | else // up | ||
373 | { | ||
374 | res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor | ||
375 | ( | ||
376 | elevator->sector, | ||
377 | elevator->speed, | ||
378 | elevator->floordestheight, | ||
379 | 0, | ||
380 | 0, // move ceiling | ||
381 | elevator->direction | ||
382 | ); | ||
383 | if (res==ok || res==pastdest) // jff 4/7/98 don't move floor if blocked | ||
384 | T_MovePlane | ||
385 | ( | ||
386 | elevator->sector, | ||
387 | elevator->speed, | ||
388 | elevator->ceilingdestheight, | ||
389 | 0, | ||
390 | 1, // move floor | ||
391 | elevator->direction | ||
392 | ); | ||
393 | } | ||
394 | |||
395 | // make floor move sound | ||
396 | if (!(leveltime&7)) | ||
397 | S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_stnmov); | ||
398 | |||
399 | if (res == pastdest) // if destination height acheived | ||
400 | { | ||
401 | elevator->sector->floordata = NULL; //jff 2/22/98 | ||
402 | elevator->sector->ceilingdata = NULL; //jff 2/22/98 | ||
403 | P_RemoveThinker(&elevator->thinker); // remove elevator from actives | ||
404 | |||
405 | // make floor stop sound | ||
406 | S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_pstop); | ||
407 | } | ||
408 | } | ||
409 | |||
410 | /////////////////////////////////////////////////////////////////////// | ||
411 | // | ||
412 | // Floor motion linedef handlers | ||
413 | // | ||
414 | /////////////////////////////////////////////////////////////////////// | ||
415 | |||
416 | // | ||
417 | // EV_DoFloor() | ||
418 | // | ||
419 | // Handle regular and extended floor types | ||
420 | // | ||
421 | // Passed the line that activated the floor and the type of floor motion | ||
422 | // Returns true if a thinker was created. | ||
423 | // | ||
424 | int EV_DoFloor | ||
425 | ( line_t* line, | ||
426 | floor_e floortype ) | ||
427 | { | ||
428 | int secnum; | ||
429 | int rtn; | ||
430 | int i; | ||
431 | sector_t* sec; | ||
432 | floormove_t* floor; | ||
433 | |||
434 | secnum = -1; | ||
435 | rtn = 0; | ||
436 | // move all floors with the same tag as the linedef | ||
437 | while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) | ||
438 | { | ||
439 | sec = §ors[secnum]; | ||
440 | |||
441 | // Don't start a second thinker on the same floor | ||
442 | if (P_SectorActive(floor_special,sec)) //jff 2/23/98 | ||
443 | continue; | ||
444 | |||
445 | // new floor thinker | ||
446 | rtn = 1; | ||
447 | floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); | ||
448 | memset(floor, 0, sizeof(*floor)); | ||
449 | P_AddThinker (&floor->thinker); | ||
450 | sec->floordata = floor; //jff 2/22/98 | ||
451 | floor->thinker.function = T_MoveFloor; | ||
452 | floor->type = floortype; | ||
453 | floor->crush = false; | ||
454 | |||
455 | // setup the thinker according to the linedef type | ||
456 | switch(floortype) | ||
457 | { | ||
458 | case lowerFloor: | ||
459 | floor->direction = -1; | ||
460 | floor->sector = sec; | ||
461 | floor->speed = FLOORSPEED; | ||
462 | floor->floordestheight = P_FindHighestFloorSurrounding(sec); | ||
463 | break; | ||
464 | |||
465 | //jff 02/03/30 support lowering floor by 24 absolute | ||
466 | case lowerFloor24: | ||
467 | floor->direction = -1; | ||
468 | floor->sector = sec; | ||
469 | floor->speed = FLOORSPEED; | ||
470 | floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; | ||
471 | break; | ||
472 | |||
473 | //jff 02/03/30 support lowering floor by 32 absolute (fast) | ||
474 | case lowerFloor32Turbo: | ||
475 | floor->direction = -1; | ||
476 | floor->sector = sec; | ||
477 | floor->speed = FLOORSPEED*4; | ||
478 | floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT; | ||
479 | break; | ||
480 | |||
481 | case lowerFloorToLowest: | ||
482 | floor->direction = -1; | ||
483 | floor->sector = sec; | ||
484 | floor->speed = FLOORSPEED; | ||
485 | floor->floordestheight = P_FindLowestFloorSurrounding(sec); | ||
486 | break; | ||
487 | |||
488 | //jff 02/03/30 support lowering floor to next lowest floor | ||
489 | case lowerFloorToNearest: | ||
490 | floor->direction = -1; | ||
491 | floor->sector = sec; | ||
492 | floor->speed = FLOORSPEED; | ||
493 | floor->floordestheight = | ||
494 | P_FindNextLowestFloor(sec,floor->sector->floorheight); | ||
495 | break; | ||
496 | |||
497 | case turboLower: | ||
498 | floor->direction = -1; | ||
499 | floor->sector = sec; | ||
500 | floor->speed = FLOORSPEED * 4; | ||
501 | floor->floordestheight = P_FindHighestFloorSurrounding(sec); | ||
502 | if (floor->floordestheight != sec->floorheight) | ||
503 | floor->floordestheight += 8*FRACUNIT; | ||
504 | break; | ||
505 | |||
506 | case raiseFloorCrush: | ||
507 | floor->crush = true; | ||
508 | case raiseFloor: | ||
509 | floor->direction = 1; | ||
510 | floor->sector = sec; | ||
511 | floor->speed = FLOORSPEED; | ||
512 | floor->floordestheight = P_FindLowestCeilingSurrounding(sec); | ||
513 | if (floor->floordestheight > sec->ceilingheight) | ||
514 | floor->floordestheight = sec->ceilingheight; | ||
515 | floor->floordestheight -= (8*FRACUNIT)*(floortype == raiseFloorCrush); | ||
516 | break; | ||
517 | |||
518 | case raiseFloorTurbo: | ||
519 | floor->direction = 1; | ||
520 | floor->sector = sec; | ||
521 | floor->speed = FLOORSPEED*4; | ||
522 | floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight); | ||
523 | break; | ||
524 | |||
525 | case raiseFloorToNearest: | ||
526 | floor->direction = 1; | ||
527 | floor->sector = sec; | ||
528 | floor->speed = FLOORSPEED; | ||
529 | floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight); | ||
530 | break; | ||
531 | |||
532 | case raiseFloor24: | ||
533 | floor->direction = 1; | ||
534 | floor->sector = sec; | ||
535 | floor->speed = FLOORSPEED; | ||
536 | floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; | ||
537 | break; | ||
538 | |||
539 | // jff 2/03/30 support straight raise by 32 (fast) | ||
540 | case raiseFloor32Turbo: | ||
541 | floor->direction = 1; | ||
542 | floor->sector = sec; | ||
543 | floor->speed = FLOORSPEED*4; | ||
544 | floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT; | ||
545 | break; | ||
546 | |||
547 | case raiseFloor512: | ||
548 | floor->direction = 1; | ||
549 | floor->sector = sec; | ||
550 | floor->speed = FLOORSPEED; | ||
551 | floor->floordestheight = floor->sector->floorheight + 512 * FRACUNIT; | ||
552 | break; | ||
553 | |||
554 | case raiseFloor24AndChange: | ||
555 | floor->direction = 1; | ||
556 | floor->sector = sec; | ||
557 | floor->speed = FLOORSPEED; | ||
558 | floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; | ||
559 | sec->floorpic = line->frontsector->floorpic; | ||
560 | sec->special = line->frontsector->special; | ||
561 | //jff 3/14/98 transfer both old and new special | ||
562 | sec->oldspecial = line->frontsector->oldspecial; | ||
563 | break; | ||
564 | |||
565 | case raiseToTexture: | ||
566 | { | ||
567 | int minsize = INT_MAX; | ||
568 | side_t* side; | ||
569 | |||
570 | /* jff 3/13/98 no ovf */ | ||
571 | if (!comp[comp_model]) minsize = 32000<<FRACBITS; | ||
572 | floor->direction = 1; | ||
573 | floor->sector = sec; | ||
574 | floor->speed = FLOORSPEED; | ||
575 | for (i = 0; i < sec->linecount; i++) | ||
576 | { | ||
577 | if (twoSided (secnum, i) ) | ||
578 | { | ||
579 | side = getSide(secnum,i,0); | ||
580 | // jff 8/14/98 don't scan texture 0, its not real | ||
581 | if (side->bottomtexture > 0 || | ||
582 | (comp[comp_model] && !side->bottomtexture)) | ||
583 | if (textureheight[side->bottomtexture] < minsize) | ||
584 | minsize = textureheight[side->bottomtexture]; | ||
585 | side = getSide(secnum,i,1); | ||
586 | // jff 8/14/98 don't scan texture 0, its not real | ||
587 | if (side->bottomtexture > 0 || | ||
588 | (comp[comp_model] && !side->bottomtexture)) | ||
589 | if (textureheight[side->bottomtexture] < minsize) | ||
590 | minsize = textureheight[side->bottomtexture]; | ||
591 | } | ||
592 | } | ||
593 | if (comp[comp_model]) | ||
594 | floor->floordestheight = floor->sector->floorheight + minsize; | ||
595 | else | ||
596 | { | ||
597 | floor->floordestheight = | ||
598 | (floor->sector->floorheight>>FRACBITS) + (minsize>>FRACBITS); | ||
599 | if (floor->floordestheight>32000) | ||
600 | floor->floordestheight = 32000; //jff 3/13/98 do not | ||
601 | floor->floordestheight<<=FRACBITS; // allow height overflow | ||
602 | } | ||
603 | } | ||
604 | break; | ||
605 | |||
606 | case lowerAndChange: | ||
607 | floor->direction = -1; | ||
608 | floor->sector = sec; | ||
609 | floor->speed = FLOORSPEED; | ||
610 | floor->floordestheight = P_FindLowestFloorSurrounding(sec); | ||
611 | floor->texture = sec->floorpic; | ||
612 | |||
613 | // jff 1/24/98 make sure floor->newspecial gets initialized | ||
614 | // in case no surrounding sector is at floordestheight | ||
615 | // --> should not affect compatibility <-- | ||
616 | floor->newspecial = sec->special; | ||
617 | //jff 3/14/98 transfer both old and new special | ||
618 | floor->oldspecial = sec->oldspecial; | ||
619 | |||
620 | //jff 5/23/98 use model subroutine to unify fixes and handling | ||
621 | sec = P_FindModelFloorSector(floor->floordestheight,sec-sectors); | ||
622 | if (sec) | ||
623 | { | ||
624 | floor->texture = sec->floorpic; | ||
625 | floor->newspecial = sec->special; | ||
626 | //jff 3/14/98 transfer both old and new special | ||
627 | floor->oldspecial = sec->oldspecial; | ||
628 | } | ||
629 | break; | ||
630 | default: | ||
631 | break; | ||
632 | } | ||
633 | } | ||
634 | return rtn; | ||
635 | } | ||
636 | |||
637 | // | ||
638 | // EV_DoChange() | ||
639 | // | ||
640 | // Handle pure change types. These change floor texture and sector type | ||
641 | // by trigger or numeric model without moving the floor. | ||
642 | // | ||
643 | // The linedef causing the change and the type of change is passed | ||
644 | // Returns true if any sector changes | ||
645 | // | ||
646 | // jff 3/15/98 added to better support generalized sector types | ||
647 | // | ||
648 | int EV_DoChange | ||
649 | ( line_t* line, | ||
650 | change_e changetype ) | ||
651 | { | ||
652 | int secnum; | ||
653 | int rtn; | ||
654 | sector_t* sec; | ||
655 | sector_t* secm; | ||
656 | |||
657 | secnum = -1; | ||
658 | rtn = 0; | ||
659 | // change all sectors with the same tag as the linedef | ||
660 | while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) | ||
661 | { | ||
662 | sec = §ors[secnum]; | ||
663 | |||
664 | rtn = 1; | ||
665 | |||
666 | // handle trigger or numeric change type | ||
667 | switch(changetype) | ||
668 | { | ||
669 | case trigChangeOnly: | ||
670 | sec->floorpic = line->frontsector->floorpic; | ||
671 | sec->special = line->frontsector->special; | ||
672 | sec->oldspecial = line->frontsector->oldspecial; | ||
673 | break; | ||
674 | case numChangeOnly: | ||
675 | secm = P_FindModelFloorSector(sec->floorheight,secnum); | ||
676 | if (secm) // if no model, no change | ||
677 | { | ||
678 | sec->floorpic = secm->floorpic; | ||
679 | sec->special = secm->special; | ||
680 | sec->oldspecial = secm->oldspecial; | ||
681 | } | ||
682 | break; | ||
683 | default: | ||
684 | break; | ||
685 | } | ||
686 | } | ||
687 | return rtn; | ||
688 | } | ||
689 | |||
690 | /* | ||
691 | * EV_BuildStairs() | ||
692 | * | ||
693 | * Handles staircase building. A sequence of sectors chosen by algorithm | ||
694 | * rise at a speed indicated to a height that increases by the stepsize | ||
695 | * each step. | ||
696 | * | ||
697 | * Passed the linedef triggering the stairs and the type of stair rise | ||
698 | * Returns true if any thinkers are created | ||
699 | * | ||
700 | * cph 2001/09/21 - compatibility nightmares again | ||
701 | * There are three different ways this function has, during its history, stepped | ||
702 | * through all the stairs to be triggered by the single switch | ||
703 | * - original Doom used a linear P_FindSectorFromLineTag, but failed to preserve | ||
704 | * the index of the previous sector found, so instead it would restart its | ||
705 | * linear search from the last sector of the previous staircase | ||
706 | * - MBF/PrBoom with comp_stairs fail to emulate this, because their | ||
707 | * P_FindSectorFromLineTag is a chained hash table implementation. Instead they | ||
708 | * start following the hash chain from the last sector of the previous | ||
709 | * staircase, which will (probably) have the wrong tag, so they miss any further | ||
710 | * stairs | ||
711 | * - Boom fixed the bug, and MBF/PrBoom without comp_stairs work right | ||
712 | */ | ||
713 | static inline int P_FindSectorFromLineTagWithLowerBound | ||
714 | (line_t* l, int start, int min) | ||
715 | { | ||
716 | /* Emulate original Doom's linear lower-bounded P_FindSectorFromLineTag | ||
717 | * as needed */ | ||
718 | do { | ||
719 | start = P_FindSectorFromLineTag(l,start); | ||
720 | } while (start >= 0 && start <= min); | ||
721 | return start; | ||
722 | } | ||
723 | |||
724 | int EV_BuildStairs | ||
725 | ( line_t* line, | ||
726 | stair_e type ) | ||
727 | { | ||
728 | /* cph 2001/09/22 - cleaned up this function to save my sanity. A separate | ||
729 | * outer loop index makes the logic much cleared, and local variables moved | ||
730 | * into the inner blocks helps too */ | ||
731 | int ssec = -1; | ||
732 | int minssec = -1; | ||
733 | int rtn = 0; | ||
734 | |||
735 | // start a stair at each sector tagged the same as the linedef | ||
736 | while ((ssec = P_FindSectorFromLineTagWithLowerBound(line,ssec,minssec)) >= 0) | ||
737 | { | ||
738 | int secnum = ssec; | ||
739 | sector_t* sec = §ors[secnum]; | ||
740 | |||
741 | // don't start a stair if the first step's floor is already moving | ||
742 | if (!P_SectorActive(floor_special,sec)) { //jff 2/22/98 | ||
743 | floormove_t* floor; | ||
744 | int texture, height; | ||
745 | fixed_t stairsize; | ||
746 | fixed_t speed; | ||
747 | int ok; | ||
748 | |||
749 | // create new floor thinker for first step | ||
750 | rtn = 1; | ||
751 | floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); | ||
752 | memset(floor, 0, sizeof(*floor)); | ||
753 | P_AddThinker (&floor->thinker); | ||
754 | sec->floordata = floor; | ||
755 | floor->thinker.function = T_MoveFloor; | ||
756 | floor->direction = 1; | ||
757 | floor->sector = sec; | ||
758 | floor->type = buildStair; //jff 3/31/98 do not leave uninited | ||
759 | |||
760 | // set up the speed and stepsize according to the stairs type | ||
761 | switch(type) | ||
762 | { | ||
763 | default: // killough -- prevent compiler warning | ||
764 | case build8: | ||
765 | speed = FLOORSPEED/4; | ||
766 | stairsize = 8*FRACUNIT; | ||
767 | if (!demo_compatibility) | ||
768 | floor->crush = false; //jff 2/27/98 fix uninitialized crush field | ||
769 | break; | ||
770 | case turbo16: | ||
771 | speed = FLOORSPEED*4; | ||
772 | stairsize = 16*FRACUNIT; | ||
773 | if (!demo_compatibility) | ||
774 | floor->crush = true; //jff 2/27/98 fix uninitialized crush field | ||
775 | break; | ||
776 | } | ||
777 | floor->speed = speed; | ||
778 | height = sec->floorheight + stairsize; | ||
779 | floor->floordestheight = height; | ||
780 | |||
781 | texture = sec->floorpic; | ||
782 | |||
783 | // Find next sector to raise | ||
784 | // 1. Find 2-sided line with same sector side[0] (lowest numbered) | ||
785 | // 2. Other side is the next sector to raise | ||
786 | // 3. Unless already moving, or different texture, then stop building | ||
787 | do | ||
788 | { | ||
789 | int i; | ||
790 | ok = 0; | ||
791 | |||
792 | for (i = 0;i < sec->linecount;i++) | ||
793 | { | ||
794 | sector_t* tsec = (sec->lines[i])->frontsector; | ||
795 | int newsecnum; | ||
796 | if ( !((sec->lines[i])->flags & ML_TWOSIDED) ) | ||
797 | continue; | ||
798 | |||
799 | newsecnum = tsec-sectors; | ||
800 | |||
801 | if (secnum != newsecnum) | ||
802 | continue; | ||
803 | |||
804 | tsec = (sec->lines[i])->backsector; | ||
805 | if (!tsec) continue; //jff 5/7/98 if no backside, continue | ||
806 | newsecnum = tsec - sectors; | ||
807 | |||
808 | // if sector's floor is different texture, look for another | ||
809 | if (tsec->floorpic != texture) | ||
810 | continue; | ||
811 | |||
812 | /* jff 6/19/98 prevent double stepsize | ||
813 | * killough 10/98: intentionally left this way [MBF comment] | ||
814 | * cph 2001/02/06: stair bug fix should be controlled by comp_stairs, | ||
815 | * except if we're emulating MBF which perversly reverted the fix | ||
816 | */ | ||
817 | if (comp[comp_stairs] || (compatibility_level == mbf_compatibility)) | ||
818 | height += stairsize; // jff 6/28/98 change demo compatibility | ||
819 | |||
820 | // if sector's floor already moving, look for another | ||
821 | if (P_SectorActive(floor_special,tsec)) //jff 2/22/98 | ||
822 | continue; | ||
823 | |||
824 | /* cph - see comment above - do this iff we didn't do so above */ | ||
825 | if (!comp[comp_stairs] && (compatibility_level != mbf_compatibility)) | ||
826 | height += stairsize; | ||
827 | |||
828 | sec = tsec; | ||
829 | secnum = newsecnum; | ||
830 | |||
831 | // create and initialize a thinker for the next step | ||
832 | floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); | ||
833 | memset(floor, 0, sizeof(*floor)); | ||
834 | P_AddThinker (&floor->thinker); | ||
835 | |||
836 | sec->floordata = floor; //jff 2/22/98 | ||
837 | floor->thinker.function = T_MoveFloor; | ||
838 | floor->direction = 1; | ||
839 | floor->sector = sec; | ||
840 | floor->speed = speed; | ||
841 | floor->floordestheight = height; | ||
842 | floor->type = buildStair; //jff 3/31/98 do not leave uninited | ||
843 | //jff 2/27/98 fix uninitialized crush field | ||
844 | if (!demo_compatibility) | ||
845 | floor->crush = type==build8? false : true; | ||
846 | ok = 1; | ||
847 | break; | ||
848 | } | ||
849 | } while(ok); // continue until no next step is found | ||
850 | |||
851 | } | ||
852 | /* killough 10/98: compatibility option */ | ||
853 | if (comp[comp_stairs]) { | ||
854 | /* cph 2001/09/22 - emulate buggy MBF comp_stairs for demos, with logic | ||
855 | * reversed since we now have a separate outer loop index. | ||
856 | * DEMOSYNC - what about boom_compatibility_compatibility? | ||
857 | */ | ||
858 | if ((compatibility_level >= mbf_compatibility) && (compatibility_level < | ||
859 | prboom_3_compatibility)) ssec = secnum; /* Trash outer loop index */ | ||
860 | else { | ||
861 | /* cph 2001/09/22 - now the correct comp_stairs - Doom used a linear | ||
862 | * search from the last secnum, so we set that as a minimum value and do | ||
863 | * a fresh tag search | ||
864 | */ | ||
865 | ssec = -1; minssec = secnum; | ||
866 | } | ||
867 | } | ||
868 | } | ||
869 | return rtn; | ||
870 | } | ||
871 | |||
872 | // | ||
873 | // EV_DoDonut() | ||
874 | // | ||
875 | // Handle donut function: lower pillar, raise surrounding pool, both to height, | ||
876 | // texture and type of the sector surrounding the pool. | ||
877 | // | ||
878 | // Passed the linedef that triggered the donut | ||
879 | // Returns whether a thinker was created | ||
880 | // | ||
881 | int EV_DoDonut(line_t* line) | ||
882 | { | ||
883 | sector_t* s1; | ||
884 | sector_t* s2; | ||
885 | sector_t* s3; | ||
886 | int secnum; | ||
887 | int rtn; | ||
888 | int i; | ||
889 | floormove_t* floor; | ||
890 | |||
891 | secnum = -1; | ||
892 | rtn = 0; | ||
893 | // do function on all sectors with same tag as linedef | ||
894 | while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) | ||
895 | { | ||
896 | s1 = §ors[secnum]; // s1 is pillar's sector | ||
897 | |||
898 | // do not start the donut if the pillar is already moving | ||
899 | if (P_SectorActive(floor_special,s1)) //jff 2/22/98 | ||
900 | continue; | ||
901 | |||
902 | s2 = getNextSector(s1->lines[0],s1); // s2 is pool's sector | ||
903 | if (!s2) continue; // note lowest numbered line around | ||
904 | // pillar must be two-sided | ||
905 | |||
906 | /* do not start the donut if the pool is already moving | ||
907 | * cph - DEMOSYNC - was !compatibility */ | ||
908 | if (!comp[comp_floors] && P_SectorActive(floor_special,s2)) | ||
909 | continue; //jff 5/7/98 | ||
910 | |||
911 | // find a two sided line around the pool whose other side isn't the pillar | ||
912 | for (i = 0;i < s2->linecount;i++) | ||
913 | { | ||
914 | //jff 3/29/98 use true two-sidedness, not the flag | ||
915 | // killough 4/5/98: changed demo_compatibility to compatibility | ||
916 | if (comp[comp_model]) | ||
917 | { | ||
918 | if ((!s2->lines[i]->flags & ML_TWOSIDED) || | ||
919 | (s2->lines[i]->backsector == s1)) | ||
920 | continue; | ||
921 | } | ||
922 | else if (!s2->lines[i]->backsector || s2->lines[i]->backsector == s1) | ||
923 | continue; | ||
924 | |||
925 | rtn = 1; //jff 1/26/98 no donut action - no switch change on return | ||
926 | |||
927 | s3 = s2->lines[i]->backsector; // s3 is model sector for changes | ||
928 | |||
929 | // Spawn rising slime | ||
930 | floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); | ||
931 | memset(floor, 0, sizeof(*floor)); | ||
932 | P_AddThinker (&floor->thinker); | ||
933 | s2->floordata = floor; //jff 2/22/98 | ||
934 | floor->thinker.function = T_MoveFloor; | ||
935 | floor->type = donutRaise; | ||
936 | floor->crush = false; | ||
937 | floor->direction = 1; | ||
938 | floor->sector = s2; | ||
939 | floor->speed = FLOORSPEED / 2; | ||
940 | floor->texture = s3->floorpic; | ||
941 | floor->newspecial = 0; | ||
942 | floor->floordestheight = s3->floorheight; | ||
943 | |||
944 | // Spawn lowering donut-hole pillar | ||
945 | floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); | ||
946 | memset(floor, 0, sizeof(*floor)); | ||
947 | P_AddThinker (&floor->thinker); | ||
948 | s1->floordata = floor; //jff 2/22/98 | ||
949 | floor->thinker.function = T_MoveFloor; | ||
950 | floor->type = lowerFloor; | ||
951 | floor->crush = false; | ||
952 | floor->direction = -1; | ||
953 | floor->sector = s1; | ||
954 | floor->speed = FLOORSPEED / 2; | ||
955 | floor->floordestheight = s3->floorheight; | ||
956 | break; | ||
957 | } | ||
958 | } | ||
959 | return rtn; | ||
960 | } | ||
961 | |||
962 | // | ||
963 | // EV_DoElevator | ||
964 | // | ||
965 | // Handle elevator linedef types | ||
966 | // | ||
967 | // Passed the linedef that triggered the elevator and the elevator action | ||
968 | // | ||
969 | // jff 2/22/98 new type to move floor and ceiling in parallel | ||
970 | // | ||
971 | int EV_DoElevator | ||
972 | ( line_t* line, | ||
973 | elevator_e elevtype ) | ||
974 | { | ||
975 | int secnum; | ||
976 | int rtn; | ||
977 | sector_t* sec; | ||
978 | elevator_t* elevator; | ||
979 | |||
980 | secnum = -1; | ||
981 | rtn = 0; | ||
982 | // act on all sectors with the same tag as the triggering linedef | ||
983 | while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) | ||
984 | { | ||
985 | sec = §ors[secnum]; | ||
986 | |||
987 | // If either floor or ceiling is already activated, skip it | ||
988 | if (sec->floordata || sec->ceilingdata) //jff 2/22/98 | ||
989 | continue; | ||
990 | |||
991 | // create and initialize new elevator thinker | ||
992 | rtn = 1; | ||
993 | elevator = Z_Malloc (sizeof(*elevator), PU_LEVSPEC, 0); | ||
994 | memset(elevator, 0, sizeof(*elevator)); | ||
995 | P_AddThinker (&elevator->thinker); | ||
996 | sec->floordata = elevator; //jff 2/22/98 | ||
997 | sec->ceilingdata = elevator; //jff 2/22/98 | ||
998 | elevator->thinker.function = T_MoveElevator; | ||
999 | elevator->type = elevtype; | ||
1000 | |||
1001 | // set up the fields according to the type of elevator action | ||
1002 | switch(elevtype) | ||
1003 | { | ||
1004 | // elevator down to next floor | ||
1005 | case elevateDown: | ||
1006 | elevator->direction = -1; | ||
1007 | elevator->sector = sec; | ||
1008 | elevator->speed = ELEVATORSPEED; | ||
1009 | elevator->floordestheight = | ||
1010 | P_FindNextLowestFloor(sec,sec->floorheight); | ||
1011 | elevator->ceilingdestheight = | ||
1012 | elevator->floordestheight + sec->ceilingheight - sec->floorheight; | ||
1013 | break; | ||
1014 | |||
1015 | // elevator up to next floor | ||
1016 | case elevateUp: | ||
1017 | elevator->direction = 1; | ||
1018 | elevator->sector = sec; | ||
1019 | elevator->speed = ELEVATORSPEED; | ||
1020 | elevator->floordestheight = | ||
1021 | P_FindNextHighestFloor(sec,sec->floorheight); | ||
1022 | elevator->ceilingdestheight = | ||
1023 | elevator->floordestheight + sec->ceilingheight - sec->floorheight; | ||
1024 | break; | ||
1025 | |||
1026 | // elevator to floor height of activating switch's front sector | ||
1027 | case elevateCurrent: | ||
1028 | elevator->sector = sec; | ||
1029 | elevator->speed = ELEVATORSPEED; | ||
1030 | elevator->floordestheight = line->frontsector->floorheight; | ||
1031 | elevator->ceilingdestheight = | ||
1032 | elevator->floordestheight + sec->ceilingheight - sec->floorheight; | ||
1033 | elevator->direction = | ||
1034 | elevator->floordestheight>sec->floorheight? 1 : -1; | ||
1035 | break; | ||
1036 | |||
1037 | default: | ||
1038 | break; | ||
1039 | } | ||
1040 | } | ||
1041 | return rtn; | ||
1042 | } | ||