1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 1993-2008 Raven Software
4 // Copyright(C) 2005-2014 Simon Howard
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 #include "doomdef.h"
17 #include "p_local.h"
18 #include "s_sound.h"
19 #include "v_video.h"
20
21 //==================================================================
22 //==================================================================
23 //
24 // FLOORS
25 //
26 //==================================================================
27 //==================================================================
28
29
30
31 //==================================================================
32 //
33 // Move a plane (floor or ceiling) and check for crushing
34 //
35 //==================================================================
T_MovePlane(sector_t * sector,fixed_t speed,fixed_t dest,boolean crush,int floorOrCeiling,int direction)36 result_e T_MovePlane(sector_t * sector, fixed_t speed,
37 fixed_t dest, boolean crush, int floorOrCeiling,
38 int direction)
39 {
40 boolean flag;
41 fixed_t lastpos;
42
43 // [AM] Store old sector heights for interpolation.
44 sector->oldfloorheight = sector->floorheight;
45 sector->oldceilingheight = sector->ceilingheight;
46 sector->oldgametic = gametic;
47
48 switch (floorOrCeiling)
49 {
50 case 0: // FLOOR
51 switch (direction)
52 {
53 case -1: // DOWN
54 if (sector->floorheight - speed < dest)
55 {
56 lastpos = sector->floorheight;
57 sector->floorheight = dest;
58 flag = P_ChangeSector(sector, crush);
59 if (flag == true)
60 {
61 sector->floorheight = lastpos;
62 P_ChangeSector(sector, crush);
63 //return crushed;
64 }
65 return pastdest;
66 }
67 else
68 {
69 lastpos = sector->floorheight;
70 sector->floorheight -= speed;
71 flag = P_ChangeSector(sector, crush);
72 if (flag == true)
73 {
74 sector->floorheight = lastpos;
75 P_ChangeSector(sector, crush);
76 return crushed;
77 }
78 }
79 break;
80
81 case 1: // UP
82 if (sector->floorheight + speed > dest)
83 {
84 lastpos = sector->floorheight;
85 sector->floorheight = dest;
86 flag = P_ChangeSector(sector, crush);
87 if (flag == true)
88 {
89 sector->floorheight = lastpos;
90 P_ChangeSector(sector, crush);
91 //return crushed;
92 }
93 return pastdest;
94 }
95 else // COULD GET CRUSHED
96 {
97 lastpos = sector->floorheight;
98 sector->floorheight += speed;
99 flag = P_ChangeSector(sector, crush);
100 if (flag == true)
101 {
102 if (crush == true)
103 return crushed;
104 sector->floorheight = lastpos;
105 P_ChangeSector(sector, crush);
106 return crushed;
107 }
108 }
109 break;
110 }
111 break;
112
113 case 1: // CEILING
114 switch (direction)
115 {
116 case -1: // DOWN
117 if (sector->ceilingheight - speed < dest)
118 {
119 lastpos = sector->ceilingheight;
120 sector->ceilingheight = dest;
121 flag = P_ChangeSector(sector, crush);
122 if (flag == true)
123 {
124 sector->ceilingheight = lastpos;
125 P_ChangeSector(sector, crush);
126 //return crushed;
127 }
128 return pastdest;
129 }
130 else // COULD GET CRUSHED
131 {
132 lastpos = sector->ceilingheight;
133 sector->ceilingheight -= speed;
134 flag = P_ChangeSector(sector, crush);
135 if (flag == true)
136 {
137 if (crush == true)
138 return crushed;
139 sector->ceilingheight = lastpos;
140 P_ChangeSector(sector, crush);
141 return crushed;
142 }
143 }
144 break;
145
146 case 1: // UP
147 if (sector->ceilingheight + speed > dest)
148 {
149 lastpos = sector->ceilingheight;
150 sector->ceilingheight = dest;
151 flag = P_ChangeSector(sector, crush);
152 if (flag == true)
153 {
154 sector->ceilingheight = lastpos;
155 P_ChangeSector(sector, crush);
156 //return crushed;
157 }
158 return pastdest;
159 }
160 else
161 {
162 lastpos = sector->ceilingheight;
163 sector->ceilingheight += speed;
164 flag = P_ChangeSector(sector, crush);
165 #if 0
166 if (flag == true)
167 {
168 sector->ceilingheight = lastpos;
169 P_ChangeSector(sector, crush);
170 return crushed;
171 }
172 #endif
173 }
174 break;
175 }
176 break;
177
178 }
179 return ok;
180 }
181
182 //==================================================================
183 //
184 // MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN)
185 //
186 //==================================================================
T_MoveFloor(floormove_t * floor)187 void T_MoveFloor(floormove_t * floor)
188 {
189 result_e res;
190
191 res = T_MovePlane(floor->sector, floor->speed,
192 floor->floordestheight, floor->crush, 0,
193 floor->direction);
194 if (!(leveltime & 7))
195 {
196 S_StartSound(&floor->sector->soundorg, sfx_dormov);
197 }
198
199 if (res == pastdest)
200 {
201 floor->sector->specialdata = NULL;
202 if (floor->type == raiseBuildStep)
203 {
204 S_StartSound(&floor->sector->soundorg, sfx_pstop);
205 }
206 if (floor->direction == 1)
207 switch (floor->type)
208 {
209 case donutRaise:
210 floor->sector->special = floor->newspecial;
211 floor->sector->floorpic = floor->texture;
212 default:
213 break;
214 }
215 else if (floor->direction == -1)
216 switch (floor->type)
217 {
218 case lowerAndChange:
219 floor->sector->special = floor->newspecial;
220 floor->sector->floorpic = floor->texture;
221 default:
222 break;
223 }
224 P_RemoveThinker(&floor->thinker);
225 }
226
227 }
228
229 //==================================================================
230 //
231 // HANDLE FLOOR TYPES
232 //
233 //==================================================================
EV_DoFloor(line_t * line,floor_e floortype)234 int EV_DoFloor(line_t * line, floor_e floortype)
235 {
236 int secnum;
237 int rtn;
238 int i;
239 sector_t *sec;
240 floormove_t *floor;
241
242 secnum = -1;
243 rtn = 0;
244 while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
245 {
246 sec = §ors[secnum];
247
248 // ALREADY MOVING? IF SO, KEEP GOING...
249 if (sec->specialdata)
250 continue;
251
252 //
253 // new floor thinker
254 //
255 rtn = 1;
256 floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
257 P_AddThinker(&floor->thinker);
258 sec->specialdata = floor;
259 floor->thinker.function = T_MoveFloor;
260 floor->type = floortype;
261 floor->crush = false;
262 switch (floortype)
263 {
264 case lowerFloor:
265 floor->direction = -1;
266 floor->sector = sec;
267 floor->speed = FLOORSPEED;
268 floor->floordestheight = P_FindHighestFloorSurrounding(sec);
269 break;
270 case lowerFloorToLowest:
271 floor->direction = -1;
272 floor->sector = sec;
273 floor->speed = FLOORSPEED;
274 floor->floordestheight = P_FindLowestFloorSurrounding(sec);
275 break;
276 case turboLower:
277 floor->direction = -1;
278 floor->sector = sec;
279 floor->speed = FLOORSPEED * 4;
280 floor->floordestheight = (8 * FRACUNIT) +
281 P_FindHighestFloorSurrounding(sec);
282 break;
283 case raiseFloorCrush:
284 floor->crush = true;
285 case raiseFloor:
286 floor->direction = 1;
287 floor->sector = sec;
288 floor->speed = FLOORSPEED;
289 floor->floordestheight = P_FindLowestCeilingSurrounding(sec);
290 if (floor->floordestheight > sec->ceilingheight)
291 floor->floordestheight = sec->ceilingheight;
292 floor->floordestheight -= (8 * FRACUNIT) *
293 (floortype == raiseFloorCrush);
294 break;
295 case raiseFloorToNearest:
296 floor->direction = 1;
297 floor->sector = sec;
298 floor->speed = FLOORSPEED;
299 floor->floordestheight =
300 P_FindNextHighestFloor(sec, sec->floorheight);
301 break;
302 case raiseFloor24:
303 floor->direction = 1;
304 floor->sector = sec;
305 floor->speed = FLOORSPEED;
306 floor->floordestheight = floor->sector->floorheight +
307 24 * FRACUNIT;
308 break;
309 case raiseFloor24AndChange:
310 floor->direction = 1;
311 floor->sector = sec;
312 floor->speed = FLOORSPEED;
313 floor->floordestheight = floor->sector->floorheight +
314 24 * FRACUNIT;
315 sec->floorpic = line->frontsector->floorpic;
316 sec->special = line->frontsector->special;
317 break;
318 case raiseToTexture:
319 {
320 int minsize = INT_MAX;
321 side_t *side;
322
323 floor->direction = 1;
324 floor->sector = sec;
325 floor->speed = FLOORSPEED;
326 for (i = 0; i < sec->linecount; i++)
327 if (twoSided(secnum, i))
328 {
329 side = getSide(secnum, i, 0);
330 if (side->bottomtexture >= 0)
331 if (textureheight[side->bottomtexture] <
332 minsize)
333 minsize =
334 textureheight[side->bottomtexture];
335 side = getSide(secnum, i, 1);
336 if (side->bottomtexture >= 0)
337 if (textureheight[side->bottomtexture] <
338 minsize)
339 minsize =
340 textureheight[side->bottomtexture];
341 }
342 floor->floordestheight = floor->sector->floorheight +
343 minsize;
344 }
345 break;
346 case lowerAndChange:
347 floor->direction = -1;
348 floor->sector = sec;
349 floor->speed = FLOORSPEED;
350 floor->floordestheight = P_FindLowestFloorSurrounding(sec);
351 floor->texture = sec->floorpic;
352 for (i = 0; i < sec->linecount; i++)
353 if (twoSided(secnum, i))
354 {
355 if (getSide(secnum, i, 0)->sector - sectors == secnum)
356 {
357 sec = getSector(secnum, i, 1);
358 floor->texture = sec->floorpic;
359 floor->newspecial = sec->special;
360 break;
361 }
362 else
363 {
364 sec = getSector(secnum, i, 0);
365 floor->texture = sec->floorpic;
366 floor->newspecial = sec->special;
367 break;
368 }
369 }
370 default:
371 break;
372 }
373 }
374 return rtn;
375 }
376
377 //==================================================================
378 //
379 // BUILD A STAIRCASE!
380 //
381 //==================================================================
EV_BuildStairs(line_t * line,fixed_t stepDelta)382 int EV_BuildStairs(line_t * line, fixed_t stepDelta)
383 {
384 int secnum;
385 int height;
386 int i;
387 int newsecnum;
388 int texture;
389 int ok;
390 int rtn;
391 sector_t *sec, *tsec;
392 floormove_t *floor;
393
394 secnum = -1;
395 rtn = 0;
396 while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
397 {
398 sec = §ors[secnum];
399
400 // ALREADY MOVING? IF SO, KEEP GOING...
401 if (sec->specialdata)
402 continue;
403
404 //
405 // new floor thinker
406 //
407 rtn = 1;
408 height = sec->floorheight + stepDelta;
409 floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
410 P_AddThinker(&floor->thinker);
411 sec->specialdata = floor;
412 floor->thinker.function = T_MoveFloor;
413 floor->type = raiseBuildStep;
414 floor->direction = 1;
415 floor->sector = sec;
416 floor->speed = FLOORSPEED;
417 floor->floordestheight = height;
418
419 texture = sec->floorpic;
420
421 //
422 // Find next sector to raise
423 // 1. Find 2-sided line with same sector side[0]
424 // 2. Other side is the next sector to raise
425 //
426 do
427 {
428 ok = 0;
429 for (i = 0; i < sec->linecount; i++)
430 {
431 if (!((sec->lines[i])->flags & ML_TWOSIDED))
432 continue;
433
434 tsec = (sec->lines[i])->frontsector;
435 newsecnum = tsec - sectors;
436 if (secnum != newsecnum)
437 continue;
438 tsec = (sec->lines[i])->backsector;
439 newsecnum = tsec - sectors;
440 if (tsec->floorpic != texture)
441 continue;
442
443 height += stepDelta;
444 if (tsec->specialdata)
445 continue;
446
447 sec = tsec;
448 secnum = newsecnum;
449 floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
450 P_AddThinker(&floor->thinker);
451 sec->specialdata = floor;
452 floor->thinker.function = T_MoveFloor;
453 floor->type = raiseBuildStep;
454 floor->direction = 1;
455 floor->sector = sec;
456 floor->speed = FLOORSPEED;
457 floor->floordestheight = height;
458 ok = 1;
459 break;
460 }
461 }
462 while (ok);
463 }
464 return (rtn);
465 }
466