1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 2005-2014 Simon Howard
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // DESCRIPTION:
16 //	Plats (i.e. elevator platforms) code, raising/lowering.
17 //
18 
19 #include <stdio.h>
20 
21 #include "i_system.h"
22 #include "z_zone.h"
23 #include "m_random.h"
24 
25 #include "doomdef.h"
26 #include "p_local.h"
27 
28 #include "s_sound.h"
29 
30 // State.
31 #include "doomstat.h"
32 #include "r_state.h"
33 
34 // Data.
35 #include "sounds.h"
36 
37 
38 plat_t* activeplats[MAXPLATS];
39 
40 
41 
42 //
43 // Move a plat up and down
44 //
T_PlatRaise(plat_t * plat)45 void T_PlatRaise(plat_t* plat)
46 {
47     result_e	res;
48 
49     switch(plat->status)
50     {
51     case up:
52         res = T_MovePlane(plat->sector, plat->speed, plat->high, plat->crush, 0, 1);
53 
54         if(plat->type == raiseAndChange
55             || plat->type == raiseToNearestAndChange)
56         {
57             if(!(leveltime&7))
58                 S_StartSound(&plat->sector->soundorg, sfx_stnmov);
59         }
60 
61         // villsa [STRIFE]
62         if(plat->type == slowDWUS)
63         {
64             if(!(leveltime&7))
65                 S_StartSound(&plat->sector->soundorg, sfx_stnmov);
66         }
67 
68 
69         if(res == crushed && (!plat->crush))
70         {
71             plat->count = plat->wait;
72             plat->status = down;
73             S_StartSound(&plat->sector->soundorg, sfx_pstart);
74         }
75         else
76         {
77             if(res == pastdest)
78             {
79                 plat->count = plat->wait;
80                 plat->status = waiting;
81                 S_StartSound(&plat->sector->soundorg, sfx_pstop);
82 
83                 switch(plat->type)
84                 {
85                 case blazeDWUS:
86                 case downWaitUpStay:
87                 case raiseAndChange:
88                 case slowDWUS:  // villsa [STRIFE]
89                 case raiseToNearestAndChange:
90                     P_RemoveActivePlat(plat);
91                     break;
92 
93                 default:
94                     break;
95                 }
96             }
97         }
98         break;
99 
100     case down:
101         res = T_MovePlane(plat->sector, plat->speed, plat->low, false, 0, -1);
102 
103         // villsa [STRIFE]
104         if(plat->type == slowDWUS)
105         {
106             if(!(leveltime&7))
107                 S_StartSound(&plat->sector->soundorg, sfx_stnmov);
108         }
109 
110         if(res == pastdest)
111         {
112             plat->count = plat->wait;
113             plat->status = waiting;
114             S_StartSound(&plat->sector->soundorg,sfx_pstop);
115 
116             // villsa [STRIFE]
117             if(plat->type == upWaitDownStay)
118                 P_RemoveActivePlat(plat);
119         }
120         break;
121 
122     case waiting:
123         if(!--plat->count)
124         {
125             if(plat->sector->floorheight == plat->low)
126                 plat->status = up;
127             else
128                 plat->status = down;
129             S_StartSound(&plat->sector->soundorg,sfx_pstart);
130         }
131 
132     case in_stasis:
133         break;
134     }
135 }
136 
137 
138 //
139 // EV_DoPlat
140 //
141 // Do Platforms "amount" is only used for SOME platforms.
142 //
EV_DoPlat(line_t * line,plattype_e type,int amount)143 int EV_DoPlat(line_t* line, plattype_e type, int amount)
144 {
145     plat_t*     plat;
146     int         secnum;
147     int         rtn;
148     sector_t*   sec;
149 
150     secnum = -1;
151     rtn = 0;
152 
153 
154     //	Activate all <type> plats that are in_stasis
155     switch(type)
156     {
157     case perpetualRaise:
158         P_ActivateInStasis(line->tag);
159         break;
160 
161     default:
162         break;
163     }
164 
165     while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
166     {
167         sec = &sectors[secnum];
168 
169         if (sec->specialdata)
170             continue;
171 
172         // Find lowest & highest floors around sector
173         rtn = 1;
174         plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0);
175         P_AddThinker(&plat->thinker);
176 
177         plat->type = type;
178         plat->sector = sec;
179         plat->sector->specialdata = plat;
180         plat->thinker.function.acp1 = (actionf_p1) T_PlatRaise;
181         plat->crush = false;
182         plat->tag = line->tag;
183 
184         switch(type)
185         {
186         case raiseToNearestAndChange:
187             plat->speed = PLATSPEED/2;
188             sec->floorpic = sides[line->sidenum[0]].sector->floorpic;
189             plat->high = P_FindNextHighestFloor(sec,sec->floorheight);
190             plat->wait = 0;
191             plat->status = up;
192 
193             // NO MORE DAMAGE, IF APPLICABLE
194             sec->special = 0;
195 
196             S_StartSound(&sec->soundorg, sfx_stnmov);
197             break;
198 
199         case raiseAndChange:
200             plat->speed = PLATSPEED/2;
201             sec->floorpic = sides[line->sidenum[0]].sector->floorpic;
202             plat->high = sec->floorheight + amount * FRACUNIT;
203             plat->wait = 0;
204             plat->status = up;
205 
206             S_StartSound(&sec->soundorg, sfx_stnmov);
207             break;
208 
209             // villsa [STRIFE]
210         case upWaitDownStay:
211             plat->speed = PLATSPEED * 4;
212             plat->high = P_FindNextHighestFloor(sec, sec->floorheight);
213             plat->low = sec->floorheight;
214             plat->wait = TICRATE * PLATWAIT;
215             plat->status = up;
216             S_StartSound(&sec->soundorg, sfx_pstart);
217             break;
218 
219         case downWaitUpStay:
220             plat->speed = PLATSPEED * 4;
221             plat->low = P_FindLowestFloorSurrounding(sec);
222 
223             if(plat->low > sec->floorheight)
224                 plat->low = sec->floorheight;
225 
226             plat->high = sec->floorheight;
227             plat->wait = TICRATE * PLATWAIT;
228             plat->status = down;
229             S_StartSound(&sec->soundorg, sfx_pstart);
230             break;
231 
232             // villsa [STRIFE]
233         case slowDWUS:
234             plat->speed = PLATSPEED;
235             plat->low = P_FindLowestFloorSurrounding(sec);
236 
237             if(plat->low > sec->floorheight)
238                 plat->low = sec->floorheight;
239 
240             plat->high = sec->floorheight;
241             plat->wait = TICRATE * (PLATWAIT * 10);
242             plat->status = down;
243             S_StartSound(&sec->soundorg,sfx_pstart);
244             break;
245 
246         case blazeDWUS:
247             plat->speed = PLATSPEED * 8;
248             plat->low = P_FindLowestFloorSurrounding(sec);
249 
250             if(plat->low > sec->floorheight)
251                 plat->low = sec->floorheight;
252 
253             plat->high = sec->floorheight;
254             plat->wait = TICRATE * PLATWAIT;
255             plat->status = down;
256             S_StartSound(&sec->soundorg, sfx_pstart);
257             break;
258 
259         case perpetualRaise:
260             plat->speed = PLATSPEED;
261             plat->low = P_FindLowestFloorSurrounding(sec);
262 
263             if(plat->low > sec->floorheight)
264                 plat->low = sec->floorheight;
265 
266             plat->high = P_FindHighestFloorSurrounding(sec);
267 
268             if(plat->high < sec->floorheight)
269                 plat->high = sec->floorheight;
270 
271             plat->wait = TICRATE * PLATWAIT;
272             plat->status = P_Random() & 1;
273 
274             S_StartSound(&sec->soundorg, sfx_pstart);
275             break;
276         }
277 
278         P_AddActivePlat(plat);
279     }
280     return rtn;
281 }
282 
283 
284 //
285 // P_ActivateInStasis
286 //
P_ActivateInStasis(int tag)287 void P_ActivateInStasis(int tag)
288 {
289     int i;
290 
291     for(i = 0; i < MAXPLATS; i++)
292         if(activeplats[i]
293         && (activeplats[i])->tag == tag
294             && (activeplats[i])->status == in_stasis)
295         {
296             (activeplats[i])->status = (activeplats[i])->oldstatus;
297             (activeplats[i])->thinker.function.acp1
298                 = (actionf_p1)T_PlatRaise;
299         }
300 }
301 
302 //
303 // EV_StopPlat
304 //
EV_StopPlat(line_t * line)305 void EV_StopPlat(line_t* line)
306 {
307     int j;
308 
309     for(j = 0; j < MAXPLATS; j++)
310         if (activeplats[j]
311         && ((activeplats[j])->status != in_stasis)
312             && ((activeplats[j])->tag == line->tag))
313         {
314             (activeplats[j])->oldstatus = (activeplats[j])->status;
315             (activeplats[j])->status = in_stasis;
316             (activeplats[j])->thinker.function.acv = (actionf_v)NULL;
317         }
318 }
319 
320 //
321 // P_AddActivePlat
322 //
P_AddActivePlat(plat_t * plat)323 void P_AddActivePlat(plat_t* plat)
324 {
325     int i;
326 
327     for(i = 0; i < MAXPLATS; i++)
328     {
329         if (activeplats[i] == NULL)
330         {
331             activeplats[i] = plat;
332             return;
333         }
334     }
335 
336     I_Error("P_AddActivePlat: no more plats!");
337 }
338 
339 //
340 // P_RemoveActivePlat
341 //
P_RemoveActivePlat(plat_t * plat)342 void P_RemoveActivePlat(plat_t* plat)
343 {
344     int i;
345     for(i = 0; i < MAXPLATS; i++)
346     {
347         if(plat == activeplats[i])
348         {
349             (activeplats[i])->sector->specialdata = NULL;
350             P_RemoveThinker(&(activeplats[i])->thinker);
351             activeplats[i] = NULL;
352 
353             return;
354         }
355     }
356 
357     I_Error("P_RemoveActivePlat: can't find plat!");
358 }
359