1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: p_pillar.cpp 4469 2014-01-03 23:38:29Z dr_sean $
5 //
6 // Copyright (C) 1998-2006 by Randy Heit (ZDoom).
7 // Copyright (C) 2006-2014 by The Odamex Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // DESCRIPTION:
20 //	[RH] p_pillar.c: New file to handle pillars
21 //
22 //-----------------------------------------------------------------------------
23 
24 
25 #include "z_zone.h"
26 #include "doomdef.h"
27 #include "p_local.h"
28 #include "p_spec.h"
29 #include "g_level.h"
30 #include "s_sound.h"
31 
32 extern bool predicting;
33 
P_SetPillarDestroy(DPillar * pillar)34 void P_SetPillarDestroy(DPillar *pillar)
35 {
36 	if (!pillar)
37 		return;
38 
39 	pillar->m_Status = DPillar::destroy;
40 
41 	if (clientside && pillar->m_Sector)
42 	{
43 		pillar->m_Sector->ceilingdata = NULL;
44 		pillar->m_Sector->floordata = NULL;
45 		pillar->Destroy();
46 	}
47 }
48 
IMPLEMENT_SERIAL(DPillar,DMover)49 IMPLEMENT_SERIAL (DPillar, DMover)
50 
51 DPillar::DPillar () :
52 	m_Status(init)
53 {
54 }
55 
Serialize(FArchive & arc)56 void DPillar::Serialize (FArchive &arc)
57 {
58 	Super::Serialize (arc);
59 	if (arc.IsStoring ())
60 	{
61 		arc << m_Type
62 			<< m_Status
63 			<< m_FloorSpeed
64 			<< m_CeilingSpeed
65 			<< m_FloorTarget
66 			<< m_CeilingTarget
67 			<< m_Crush;
68 	}
69 	else
70 	{
71 		arc >> m_Type
72 			>> m_Status
73 			>> m_FloorSpeed
74 			>> m_CeilingSpeed
75 			>> m_FloorTarget
76 			>> m_CeilingTarget
77 			>> m_Crush;
78 	}
79 }
80 
PlayPillarSound()81 void DPillar::PlayPillarSound()
82 {
83 	if (predicting || !m_Sector)
84 		return;
85 
86 	if (m_Status == init)
87 		S_Sound(m_Sector->soundorg, CHAN_BODY, "plats/pt1_mid", 1, ATTN_NORM);
88 	else if (m_Status == finished)
89 		S_StopSound(m_Sector->soundorg);
90 }
91 
RunThink()92 void DPillar::RunThink ()
93 {
94 	int r, s;
95 
96 	if (m_Type == pillarBuild)
97 	{
98 		r = MoveFloor (m_FloorSpeed, m_FloorTarget, m_Crush, 1);
99 		s = MoveCeiling (m_CeilingSpeed, m_CeilingTarget, m_Crush, -1);
100 	}
101 	else
102 	{
103 		r = MoveFloor (m_FloorSpeed, m_FloorTarget, m_Crush, -1);
104 		s = MoveCeiling (m_CeilingSpeed, m_CeilingTarget, m_Crush, 1);
105 	}
106 
107 	if (r == pastdest && s == pastdest)
108 	{
109 		m_Status = finished;
110 		PlayPillarSound();
111 		P_SetPillarDestroy(this);
112 	}
113 }
114 
DPillar(sector_t * sector,EPillar type,fixed_t speed,fixed_t height,fixed_t height2,bool crush)115 DPillar::DPillar (sector_t *sector, EPillar type, fixed_t speed,
116 				  fixed_t height, fixed_t height2, bool crush)
117 	: DMover (sector), m_Status(init)
118 {
119 	fixed_t	ceilingdist, floordist;
120 
121 	sector->floordata = sector->ceilingdata = this;
122 
123 	fixed_t floorheight = P_FloorHeight(sector);
124 	fixed_t ceilingheight = P_CeilingHeight(sector);
125 
126 	m_Type = type;
127 	m_Crush = crush;
128 
129 	if (type == pillarBuild)
130 	{
131 		// If the pillar height is 0, have the floor and ceiling meet halfway
132 		if (height == 0)
133 		{
134 			m_FloorTarget = m_CeilingTarget =
135 				 (ceilingheight - floorheight) / 2 + floorheight;
136 			floordist = m_FloorTarget - floorheight;
137 		}
138 		else
139 		{
140 			m_FloorTarget = m_CeilingTarget = floorheight + height;
141 			floordist = height;
142 		}
143 		ceilingdist = ceilingheight - m_CeilingTarget;
144 	}
145 	else
146 	{
147 		// If one of the heights is 0, figure it out based on the
148 		// surrounding sectors
149 		if (height == 0)
150 		{
151 			m_FloorTarget = P_FindLowestFloorSurrounding (sector);
152 			floordist = floorheight - m_FloorTarget;
153 		}
154 		else
155 		{
156 			floordist = height;
157 			m_FloorTarget = floorheight - height;
158 		}
159 		if (height2 == 0)
160 		{
161 			m_CeilingTarget = P_FindHighestCeilingSurrounding (sector);
162 			ceilingdist = m_CeilingTarget - ceilingheight;
163 		}
164 		else
165 		{
166 			m_CeilingTarget = ceilingheight + height2;
167 			ceilingdist = height2;
168 		}
169 	}
170 
171 	// The speed parameter applies to whichever part of the pillar
172 	// travels the farthest. The other part's speed is then set so
173 	// that it arrives at its destination at the same time.
174 	if (floordist > ceilingdist)
175 	{
176 		m_FloorSpeed = speed;
177 		m_CeilingSpeed = FixedDiv (FixedMul (speed, ceilingdist), floordist);
178 	}
179 	else
180 	{
181 		m_CeilingSpeed = speed;
182 		m_FloorSpeed = FixedDiv (FixedMul (speed, floordist), ceilingdist);
183 	}
184 
185 	PlayPillarSound();
186 }
187 
EV_DoPillar(DPillar::EPillar type,int tag,fixed_t speed,fixed_t height,fixed_t height2,bool crush)188 BOOL EV_DoPillar (DPillar::EPillar type, int tag, fixed_t speed, fixed_t height,
189 				  fixed_t height2, bool crush)
190 {
191 	BOOL rtn = false;
192 	int secnum = -1;
193 
194 	while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
195 	{
196 		sector_t *sec = &sectors[secnum];
197 		fixed_t floorheight = P_FloorHeight(sec);
198 		fixed_t ceilingheight = P_CeilingHeight(sec);
199 
200 		if (sec->floordata || sec->ceilingdata)
201 			continue;
202 
203 		if (type == DPillar::pillarBuild && floorheight == ceilingheight)
204 			continue;
205 
206 		if (type == DPillar::pillarOpen && floorheight != ceilingheight)
207 			continue;
208 
209 		rtn = true;
210 		new DPillar (sec, type, speed, height, height2, crush);
211 		P_AddMovingCeiling(sec);
212 	}
213 	return rtn;
214 }
215 
216 VERSION_CONTROL (p_pillar_cpp, "$Id: p_pillar.cpp 4469 2014-01-03 23:38:29Z dr_sean $")
217 
218