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