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 = §ors[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