1 /*
2 ** p_pillar.cpp
3 ** Handles pillars
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2006 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 **    notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 **    notice, this list of conditions and the following disclaimer in the
17 **    documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 **    derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34 
35 #include "doomdef.h"
36 #include "p_local.h"
37 #include "p_spec.h"
38 #include "g_level.h"
39 #include "s_sndseq.h"
40 #include "farchive.h"
41 #include "r_data/r_interpolate.h"
42 
43 IMPLEMENT_POINTY_CLASS (DPillar)
44 	DECLARE_POINTER(m_Interp_Floor)
45 	DECLARE_POINTER(m_Interp_Ceiling)
46 END_POINTERS
47 
48 inline FArchive &operator<< (FArchive &arc, DPillar::EPillar &type)
49 {
50 	BYTE val = (BYTE)type;
51 	arc << val;
52 	type = (DPillar::EPillar)val;
53 	return arc;
54 }
55 
DPillar()56 DPillar::DPillar ()
57 {
58 }
59 
Destroy()60 void DPillar::Destroy()
61 {
62 	if (m_Interp_Ceiling != NULL)
63 	{
64 		m_Interp_Ceiling->DelRef();
65 		m_Interp_Ceiling = NULL;
66 	}
67 	if (m_Interp_Floor != NULL)
68 	{
69 		m_Interp_Floor->DelRef();
70 		m_Interp_Floor = NULL;
71 	}
72 	Super::Destroy();
73 }
74 
Serialize(FArchive & arc)75 void DPillar::Serialize (FArchive &arc)
76 {
77 	Super::Serialize (arc);
78 	arc << m_Type
79 		<< m_FloorSpeed
80 		<< m_CeilingSpeed
81 		<< m_FloorTarget
82 		<< m_CeilingTarget
83 		<< m_Crush
84 		<< m_Hexencrush
85 		<< m_Interp_Floor
86 		<< m_Interp_Ceiling;
87 }
88 
Tick()89 void DPillar::Tick ()
90 {
91 	int r, s;
92 	fixed_t oldfloor, oldceiling;
93 
94 	oldfloor = m_Sector->floorplane.d;
95 	oldceiling = m_Sector->ceilingplane.d;
96 
97 	if (m_Type == pillarBuild)
98 	{
99 		r = MoveFloor (m_FloorSpeed, m_FloorTarget, m_Crush, 1, m_Hexencrush);
100 		s = MoveCeiling (m_CeilingSpeed, m_CeilingTarget, m_Crush, -1, m_Hexencrush);
101 	}
102 	else
103 	{
104 		r = MoveFloor (m_FloorSpeed, m_FloorTarget, m_Crush, -1, m_Hexencrush);
105 		s = MoveCeiling (m_CeilingSpeed, m_CeilingTarget, m_Crush, 1, m_Hexencrush);
106 	}
107 
108 	if (r == pastdest && s == pastdest)
109 	{
110 		SN_StopSequence (m_Sector, CHAN_FLOOR);
111 		Destroy ();
112 	}
113 	else
114 	{
115 		if (r == crushed)
116 		{
117 			MoveFloor (m_FloorSpeed, oldfloor, -1, -1, m_Hexencrush);
118 		}
119 		if (s == crushed)
120 		{
121 			MoveCeiling (m_CeilingSpeed, oldceiling, -1, 1, m_Hexencrush);
122 		}
123 	}
124 }
125 
DPillar(sector_t * sector,EPillar type,fixed_t speed,fixed_t floordist,fixed_t ceilingdist,int crush,bool hexencrush)126 DPillar::DPillar (sector_t *sector, EPillar type, fixed_t speed,
127 				  fixed_t floordist, fixed_t ceilingdist, int crush, bool hexencrush)
128 	: DMover (sector)
129 {
130 	fixed_t newheight;
131 	vertex_t *spot;
132 
133 	sector->floordata = sector->ceilingdata = this;
134 	m_Interp_Floor = sector->SetInterpolation(sector_t::FloorMove, true);
135 	m_Interp_Ceiling = sector->SetInterpolation(sector_t::CeilingMove, true);
136 
137 	m_Type = type;
138 	m_Crush = crush;
139 	m_Hexencrush = hexencrush;
140 
141 	if (type == pillarBuild)
142 	{
143 		// If the pillar height is 0, have the floor and ceiling meet halfway
144 		if (floordist == 0)
145 		{
146 			newheight = (sector->CenterFloor () + sector->CenterCeiling ()) / 2;
147 			m_FloorTarget = sector->floorplane.PointToDist (sector->soundorg[0], sector->soundorg[1], newheight);
148 			m_CeilingTarget = sector->ceilingplane.PointToDist (sector->soundorg[0], sector->soundorg[1], newheight);
149 			floordist = newheight - sector->CenterFloor ();
150 		}
151 		else
152 		{
153 			newheight = sector->CenterFloor () + floordist;
154 			m_FloorTarget = sector->floorplane.PointToDist (sector->soundorg[0], sector->soundorg[1], newheight);
155 			m_CeilingTarget = sector->ceilingplane.PointToDist (sector->soundorg[0], sector->soundorg[1], newheight);
156 		}
157 		ceilingdist = sector->CenterCeiling () - newheight;
158 	}
159 	else
160 	{
161 		// If one of the heights is 0, figure it out based on the
162 		// surrounding sectors
163 		if (floordist == 0)
164 		{
165 			newheight = sector->FindLowestFloorSurrounding (&spot);
166 			m_FloorTarget = sector->floorplane.PointToDist (spot, newheight);
167 			floordist = sector->floorplane.ZatPoint (spot) - newheight;
168 		}
169 		else
170 		{
171 			newheight = sector->floorplane.ZatPoint (0, 0) - floordist;
172 			m_FloorTarget = sector->floorplane.PointToDist (0, 0, newheight);
173 		}
174 		if (ceilingdist == 0)
175 		{
176 			newheight = sector->FindHighestCeilingSurrounding (&spot);
177 			m_CeilingTarget = sector->ceilingplane.PointToDist (spot, newheight);
178 			ceilingdist = newheight - sector->ceilingplane.ZatPoint (spot);
179 		}
180 		else
181 		{
182 			newheight = sector->ceilingplane.ZatPoint (0, 0) + ceilingdist;
183 			m_CeilingTarget = sector->ceilingplane.PointToDist (0, 0, newheight);
184 		}
185 	}
186 
187 	// The speed parameter applies to whichever part of the pillar
188 	// travels the farthest. The other part's speed is then set so
189 	// that it arrives at its destination at the same time.
190 	if (floordist > ceilingdist)
191 	{
192 		m_FloorSpeed = speed;
193 		m_CeilingSpeed = Scale (speed, ceilingdist, floordist);
194 	}
195 	else
196 	{
197 		m_CeilingSpeed = speed;
198 		m_FloorSpeed = Scale (speed, floordist, ceilingdist);
199 	}
200 
201 	if (!(m_Sector->Flags & SECF_SILENTMOVE))
202 	{
203 		if (sector->seqType >= 0)
204 		{
205 			SN_StartSequence(sector, CHAN_FLOOR, sector->seqType, SEQ_PLATFORM, 0);
206 		}
207 		else if (sector->SeqName != NAME_None)
208 		{
209 			SN_StartSequence(sector, CHAN_FLOOR, sector->SeqName, 0);
210 		}
211 		else
212 		{
213 			SN_StartSequence(sector, CHAN_FLOOR, "Floor", 0);
214 		}
215 	}
216 }
217 
EV_DoPillar(DPillar::EPillar type,line_t * line,int tag,fixed_t speed,fixed_t height,fixed_t height2,int crush,bool hexencrush)218 bool EV_DoPillar (DPillar::EPillar type, line_t *line, int tag,
219 				  fixed_t speed, fixed_t height, fixed_t height2, int crush, bool hexencrush)
220 {
221 	int secnum;
222 	sector_t *sec;
223 	bool rtn = false;
224 
225 	// check if a manual trigger; if so do just the sector on the backside
226 	FSectorTagIterator itr(tag, line);
227 	while ((secnum = itr.Next()) >= 0)
228 	{
229 		sec = &sectors[secnum];
230 
231 		if (sec->PlaneMoving(sector_t::floor) || sec->PlaneMoving(sector_t::ceiling))
232 			continue;
233 
234 		fixed_t flor, ceil;
235 
236 		flor = sec->CenterFloor ();
237 		ceil = sec->CenterCeiling ();
238 
239 		if (type == DPillar::pillarBuild && flor == ceil)
240 			continue;
241 
242 		if (type == DPillar::pillarOpen && flor != ceil)
243 			continue;
244 
245 		rtn = true;
246 		new DPillar (sec, type, speed, height, height2, crush, hexencrush);
247 	}
248 	return rtn;
249 }
250