1 /*
2 ** a_sectoraction.cpp
3 ** Actors that hold specials to be executed upon conditions in a sector
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 "r_defs.h"
36 #include "p_lnspec.h"
37 
38 // The base class for sector actions ----------------------------------------
39 
IMPLEMENT_CLASS(ASectorAction)40 IMPLEMENT_CLASS (ASectorAction)
41 
42 ASectorAction::ASectorAction (bool activatedByUse) :
43 	ActivatedByUse (activatedByUse) {}
44 
IsActivatedByUse() const45 bool ASectorAction::IsActivatedByUse() const
46 {
47 	return ActivatedByUse;
48 }
49 
Destroy()50 void ASectorAction::Destroy ()
51 {
52 	// Remove ourself from this sector's list of actions
53 	AActor *probe = Sector->SecActTarget;
54 	union
55 	{
56 		AActor **act;
57 		ASectorAction **secact;
58 	} prev;
59 	prev.secact = &Sector->SecActTarget;
60 
61 	while (probe && probe != this)
62 	{
63 		prev.act = &probe->tracer;
64 		probe = probe->tracer;
65 	}
66 	if (probe != NULL)
67 	{
68 		*prev.act = probe->tracer;
69 	}
70 
71 	Super::Destroy ();
72 }
73 
BeginPlay()74 void ASectorAction::BeginPlay ()
75 {
76 	Super::BeginPlay ();
77 
78 	// Add ourself to this sector's list of actions
79 	tracer = Sector->SecActTarget;
80 	Sector->SecActTarget = this;
81 }
82 
Activate(AActor * source)83 void ASectorAction::Activate (AActor *source)
84 {
85 	flags2 &= ~MF2_DORMANT;	// Projectiles cannot trigger
86 }
87 
Deactivate(AActor * source)88 void ASectorAction::Deactivate (AActor *source)
89 {
90 	flags2 |= MF2_DORMANT;	// Projectiles can trigger
91 }
92 
TriggerAction(AActor * triggerer,int activationType)93 bool ASectorAction::TriggerAction(AActor *triggerer, int activationType)
94 {
95 	if (DoTriggerAction(triggerer, activationType))
96 	{
97 		if (flags4 & MF4_STANDSTILL)
98 		{
99 			Destroy();
100 		}
101 	}
102 	return false;
103 }
104 
DoTriggerAction(AActor * triggerer,int activationType)105 bool ASectorAction::DoTriggerAction (AActor *triggerer, int activationType)
106 {
107 	if (tracer != NULL)
108 		return barrier_cast<ASectorAction *>(tracer)->DoTriggerAction (triggerer, activationType);
109 	else
110 		return false;
111 }
112 
CanTrigger(AActor * triggerer) const113 bool ASectorAction::CanTrigger (AActor *triggerer) const
114 {
115 	return special &&
116 		((triggerer->player && !(flags & MF_FRIENDLY)) ||
117 		((flags & MF_AMBUSH) && (triggerer->flags2 & MF2_MCROSS)) ||
118 		((flags2 & MF2_DORMANT) && (triggerer->flags2 & MF2_PCROSS)));
119 }
120 
CheckTrigger(AActor * triggerer) const121 bool ASectorAction::CheckTrigger (AActor *triggerer) const
122 {
123 	if (CanTrigger(triggerer))
124 	{
125 		bool res = !!P_ExecuteSpecial(special, NULL, triggerer, false, args[0], args[1],
126 			args[2], args[3], args[4]);
127 		return res;
128 	}
129 	return false;
130 }
131 
132 // Triggered when entering sector -------------------------------------------
133 
134 class ASecActEnter : public ASectorAction
135 {
136 	DECLARE_CLASS (ASecActEnter, ASectorAction)
137 public:
138 	bool DoTriggerAction (AActor *triggerer, int activationType);
139 };
140 
IMPLEMENT_CLASS(ASecActEnter)141 IMPLEMENT_CLASS (ASecActEnter)
142 
143 
144 bool ASecActEnter::DoTriggerAction (AActor *triggerer, int activationType)
145 {
146 	bool didit = (activationType & SECSPAC_Enter) ? CheckTrigger (triggerer) : false;
147 	return didit | Super::DoTriggerAction (triggerer, activationType);
148 }
149 
150 // Triggered when leaving sector --------------------------------------------
151 
152 class ASecActExit : public ASectorAction
153 {
154 	DECLARE_CLASS (ASecActExit, ASectorAction)
155 public:
156 	bool DoTriggerAction (AActor *triggerer, int activationType);
157 };
158 
IMPLEMENT_CLASS(ASecActExit)159 IMPLEMENT_CLASS (ASecActExit)
160 
161 
162 bool ASecActExit::DoTriggerAction (AActor *triggerer, int activationType)
163 {
164 	bool didit = (activationType & SECSPAC_Exit) ? CheckTrigger (triggerer) : false;
165 	return didit | Super::DoTriggerAction (triggerer, activationType);
166 }
167 
168 // Triggered when hitting sector's floor ------------------------------------
169 
170 class ASecActHitFloor : public ASectorAction
171 {
172 	DECLARE_CLASS (ASecActHitFloor, ASectorAction)
173 public:
174 	bool DoTriggerAction (AActor *triggerer, int activationType);
175 };
176 
177 // Skull Tag uses 9999 for a special that is triggered whenever
178 // the player is on the sector's floor. I think this is more useful.
IMPLEMENT_CLASS(ASecActHitFloor)179 IMPLEMENT_CLASS (ASecActHitFloor)
180 
181 
182 bool ASecActHitFloor::DoTriggerAction (AActor *triggerer, int activationType)
183 {
184 	bool didit = (activationType & SECSPAC_HitFloor) ? CheckTrigger (triggerer) : false;
185 	return didit | Super::DoTriggerAction (triggerer, activationType);
186 }
187 
188 // Triggered when hitting sector's ceiling ----------------------------------
189 
190 class ASecActHitCeil : public ASectorAction
191 {
192 	DECLARE_CLASS (ASecActHitCeil, ASectorAction)
193 public:
194 	bool DoTriggerAction (AActor *triggerer, int activationType);
195 };
196 
IMPLEMENT_CLASS(ASecActHitCeil)197 IMPLEMENT_CLASS (ASecActHitCeil)
198 
199 
200 bool ASecActHitCeil::DoTriggerAction (AActor *triggerer, int activationType)
201 {
202 	bool didit = (activationType & SECSPAC_HitCeiling) ? CheckTrigger (triggerer) : false;
203 	return didit | Super::DoTriggerAction (triggerer, activationType);
204 }
205 
206 // Triggered when using inside sector ---------------------------------------
207 
208 class ASecActUse : public ASectorAction
209 {
210 	DECLARE_CLASS (ASecActUse, ASectorAction)
211 public:
ASecActUse()212 	ASecActUse() : ASectorAction (true) {}
213 	bool DoTriggerAction (AActor *triggerer, int activationType);
214 };
215 
IMPLEMENT_CLASS(ASecActUse)216 IMPLEMENT_CLASS (ASecActUse)
217 
218 
219 bool ASecActUse::DoTriggerAction (AActor *triggerer, int activationType)
220 {
221 	bool didit = (activationType & SECSPAC_Use) ? CheckTrigger (triggerer) : false;
222 	return didit | Super::DoTriggerAction (triggerer, activationType);
223 }
224 
225 // Triggered when using a sector's wall -------------------------------------
226 
227 class ASecActUseWall : public ASectorAction
228 {
229 	DECLARE_CLASS (ASecActUseWall, ASectorAction)
230 public:
ASecActUseWall()231 	ASecActUseWall() : ASectorAction (true) {}
232 	bool DoTriggerAction (AActor *triggerer, int activationType);
233 };
234 
IMPLEMENT_CLASS(ASecActUseWall)235 IMPLEMENT_CLASS (ASecActUseWall)
236 
237 
238 bool ASecActUseWall::DoTriggerAction (AActor *triggerer, int activationType)
239 {
240 	bool didit = (activationType & SECSPAC_UseWall) ? CheckTrigger (triggerer) : false;
241 	return didit | Super::DoTriggerAction (triggerer, activationType);
242 }
243 
244 // Triggered when eyes go below fake floor ----------------------------------
245 
246 class ASecActEyesDive : public ASectorAction
247 {
248 	DECLARE_CLASS (ASecActEyesDive, ASectorAction)
249 public:
250 	bool DoTriggerAction (AActor *triggerer, int activationType);
251 };
252 
IMPLEMENT_CLASS(ASecActEyesDive)253 IMPLEMENT_CLASS (ASecActEyesDive)
254 
255 
256 bool ASecActEyesDive::DoTriggerAction (AActor *triggerer, int activationType)
257 {
258 	bool didit = (activationType & SECSPAC_EyesDive) ? CheckTrigger (triggerer) : false;
259 	return didit | Super::DoTriggerAction (triggerer, activationType);
260 }
261 
262 // Triggered when eyes go above fake floor ----------------------------------
263 
264 class ASecActEyesSurface : public ASectorAction
265 {
266 	DECLARE_CLASS (ASecActEyesSurface, ASectorAction)
267 public:
268 	bool DoTriggerAction (AActor *triggerer, int activationType);
269 };
270 
IMPLEMENT_CLASS(ASecActEyesSurface)271 IMPLEMENT_CLASS (ASecActEyesSurface)
272 
273 
274 bool ASecActEyesSurface::DoTriggerAction (AActor *triggerer, int activationType)
275 {
276 	bool didit = (activationType & SECSPAC_EyesSurface) ? CheckTrigger (triggerer) : false;
277 	return didit | Super::DoTriggerAction (triggerer, activationType);
278 }
279 
280 // Triggered when eyes go below fake floor ----------------------------------
281 
282 class ASecActEyesBelowC : public ASectorAction
283 {
284 	DECLARE_CLASS (ASecActEyesBelowC, ASectorAction)
285 public:
286 	bool DoTriggerAction (AActor *triggerer, int activationType);
287 };
288 
IMPLEMENT_CLASS(ASecActEyesBelowC)289 IMPLEMENT_CLASS (ASecActEyesBelowC)
290 
291 
292 bool ASecActEyesBelowC::DoTriggerAction (AActor *triggerer, int activationType)
293 {
294 	bool didit = (activationType & SECSPAC_EyesBelowC) ? CheckTrigger (triggerer) : false;
295 	return didit | Super::DoTriggerAction (triggerer, activationType);
296 }
297 
298 // Triggered when eyes go above fake floor ----------------------------------
299 
300 class ASecActEyesAboveC : public ASectorAction
301 {
302 	DECLARE_CLASS (ASecActEyesAboveC, ASectorAction)
303 public:
304 	bool DoTriggerAction (AActor *triggerer, int activationType);
305 };
306 
IMPLEMENT_CLASS(ASecActEyesAboveC)307 IMPLEMENT_CLASS (ASecActEyesAboveC)
308 
309 
310 bool ASecActEyesAboveC::DoTriggerAction (AActor *triggerer, int activationType)
311 {
312 	bool didit = (activationType & SECSPAC_EyesAboveC) ? CheckTrigger (triggerer) : false;
313 	return didit | Super::DoTriggerAction (triggerer, activationType);
314 }
315 
316 // Triggered when eyes go below fake floor ----------------------------------
317 
318 class ASecActHitFakeFloor : public ASectorAction
319 {
320 	DECLARE_CLASS (ASecActHitFakeFloor, ASectorAction)
321 public:
322 	bool DoTriggerAction (AActor *triggerer, int activationType);
323 };
324 
IMPLEMENT_CLASS(ASecActHitFakeFloor)325 IMPLEMENT_CLASS (ASecActHitFakeFloor)
326 
327 
328 bool ASecActHitFakeFloor::DoTriggerAction (AActor *triggerer, int activationType)
329 {
330 	bool didit = (activationType & SECSPAC_HitFakeFloor) ? CheckTrigger (triggerer) : false;
331 	return didit | Super::DoTriggerAction (triggerer, activationType);
332 }
333