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