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 = &sectors[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 = &sectors[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