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