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
17 // P_plats.c
18
19 #include "doomdef.h"
20 #include "i_system.h"
21 #include "m_random.h"
22 #include "p_local.h"
23 #include "s_sound.h"
24 #include "v_video.h"
25
26 plat_t *activeplats[MAXPLATS];
27
28 //==================================================================
29 //
30 // Move a plat up and down
31 //
32 //==================================================================
T_PlatRaise(plat_t * plat)33 void T_PlatRaise(plat_t * plat)
34 {
35 result_e res;
36
37 switch (plat->status)
38 {
39 case up:
40 res = T_MovePlane(plat->sector, plat->speed,
41 plat->high, plat->crush, 0, 1);
42 if (!(leveltime & 31))
43 {
44 S_StartSound(&plat->sector->soundorg, sfx_stnmov);
45 }
46 if (plat->type == raiseAndChange
47 || plat->type == raiseToNearestAndChange)
48 {
49 if (!(leveltime & 7))
50 {
51 S_StartSound(&plat->sector->soundorg,
52 sfx_stnmov);
53 }
54 }
55 if (res == crushed && (!plat->crush))
56 {
57 plat->count = plat->wait;
58 plat->status = down;
59 S_StartSound(&plat->sector->soundorg, sfx_pstart);
60 }
61 else if (res == pastdest)
62 {
63 plat->count = plat->wait;
64 plat->status = waiting;
65 S_StartSound(&plat->sector->soundorg, sfx_pstop);
66 switch (plat->type)
67 {
68 case downWaitUpStay:
69 P_RemoveActivePlat(plat);
70 break;
71 case raiseAndChange:
72 P_RemoveActivePlat(plat);
73 break;
74 default:
75 break;
76 }
77 }
78 break;
79 case down:
80 res =
81 T_MovePlane(plat->sector, plat->speed, plat->low, false, 0,
82 -1);
83 if (res == pastdest)
84 {
85 plat->count = plat->wait;
86 plat->status = waiting;
87 S_StartSound(&plat->sector->soundorg, sfx_pstop);
88 }
89 else
90 {
91 if (!(leveltime & 31))
92 {
93 S_StartSound(&plat->sector->soundorg,
94 sfx_stnmov);
95 }
96 }
97 break;
98 case waiting:
99 if (!--plat->count)
100 {
101 if (plat->sector->floorheight == plat->low)
102 plat->status = up;
103 else
104 plat->status = down;
105 S_StartSound(&plat->sector->soundorg, sfx_pstart);
106 }
107 case in_stasis:
108 break;
109 }
110 }
111
112 //==================================================================
113 //
114 // Do Platforms
115 // "amount" is only used for SOME platforms.
116 //
117 //==================================================================
EV_DoPlat(line_t * line,plattype_e type,int amount)118 int EV_DoPlat(line_t * line, plattype_e type, int amount)
119 {
120 plat_t *plat;
121 int secnum;
122 int rtn;
123 sector_t *sec;
124
125 secnum = -1;
126 rtn = 0;
127
128 //
129 // Activate all <type> plats that are in_stasis
130 //
131 switch (type)
132 {
133 case perpetualRaise:
134 P_ActivateInStasis(line->tag);
135 break;
136 default:
137 break;
138 }
139
140 while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
141 {
142 sec = §ors[secnum];
143 if (sec->specialdata)
144 continue;
145
146 //
147 // Find lowest & highest floors around sector
148 //
149 rtn = 1;
150 plat = Z_Malloc(sizeof(*plat), PU_LEVSPEC, 0);
151 P_AddThinker(&plat->thinker);
152
153 plat->type = type;
154 plat->sector = sec;
155 plat->sector->specialdata = plat;
156 plat->thinker.function = T_PlatRaise;
157 plat->crush = false;
158 plat->tag = line->tag;
159 switch (type)
160 {
161 case raiseToNearestAndChange:
162 plat->speed = PLATSPEED / 2;
163 sec->floorpic = sides[line->sidenum[0]].sector->floorpic;
164 plat->high = P_FindNextHighestFloor(sec, sec->floorheight);
165 plat->wait = 0;
166 plat->status = up;
167 sec->special = 0; // NO MORE DAMAGE, IF APPLICABLE
168 S_StartSound(&sec->soundorg, sfx_stnmov);
169 break;
170 case raiseAndChange:
171 plat->speed = PLATSPEED / 2;
172 sec->floorpic = sides[line->sidenum[0]].sector->floorpic;
173 plat->high = sec->floorheight + amount * FRACUNIT;
174 plat->wait = 0;
175 plat->status = up;
176 S_StartSound(&sec->soundorg, sfx_stnmov);
177 break;
178 case downWaitUpStay:
179 plat->speed = PLATSPEED * 4;
180 plat->low = P_FindLowestFloorSurrounding(sec);
181 if (plat->low > sec->floorheight)
182 plat->low = sec->floorheight;
183 plat->high = sec->floorheight;
184 plat->wait = 35 * PLATWAIT;
185 plat->status = down;
186 S_StartSound(&sec->soundorg, sfx_pstart);
187 break;
188 case perpetualRaise:
189 plat->speed = PLATSPEED;
190 plat->low = P_FindLowestFloorSurrounding(sec);
191 if (plat->low > sec->floorheight)
192 plat->low = sec->floorheight;
193 plat->high = P_FindHighestFloorSurrounding(sec);
194 if (plat->high < sec->floorheight)
195 plat->high = sec->floorheight;
196 plat->wait = 35 * PLATWAIT;
197 plat->status = P_Random() & 1;
198 S_StartSound(&sec->soundorg, sfx_pstart);
199 break;
200 }
201 P_AddActivePlat(plat);
202 }
203 return rtn;
204 }
205
P_ActivateInStasis(int tag)206 void P_ActivateInStasis(int tag)
207 {
208 int i;
209
210 for (i = 0; i < MAXPLATS; i++)
211 if (activeplats[i] &&
212 (activeplats[i])->tag == tag &&
213 (activeplats[i])->status == in_stasis)
214 {
215 (activeplats[i])->status = (activeplats[i])->oldstatus;
216 (activeplats[i])->thinker.function = T_PlatRaise;
217 }
218 }
219
EV_StopPlat(line_t * line)220 void EV_StopPlat(line_t * line)
221 {
222 int j;
223
224 for (j = 0; j < MAXPLATS; j++)
225 if (activeplats[j] && ((activeplats[j])->status != in_stasis) &&
226 ((activeplats[j])->tag == line->tag))
227 {
228 (activeplats[j])->oldstatus = (activeplats[j])->status;
229 (activeplats[j])->status = in_stasis;
230 (activeplats[j])->thinker.function = NULL;
231 }
232 }
233
P_AddActivePlat(plat_t * plat)234 void P_AddActivePlat(plat_t * plat)
235 {
236 int i;
237 for (i = 0; i < MAXPLATS; i++)
238 if (activeplats[i] == NULL)
239 {
240 activeplats[i] = plat;
241 return;
242 }
243 I_Error("P_AddActivePlat: no more plats!");
244 }
245
P_RemoveActivePlat(plat_t * plat)246 void P_RemoveActivePlat(plat_t * plat)
247 {
248 int i;
249 for (i = 0; i < MAXPLATS; i++)
250 if (plat == activeplats[i])
251 {
252 (activeplats[i])->sector->specialdata = NULL;
253 P_RemoveThinker(&(activeplats[i])->thinker);
254 activeplats[i] = NULL;
255 return;
256 }
257 I_Error("P_RemoveActivePlat: can't find plat!");
258 }
259