1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2002 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:
30  *      Teleportation.
31  *
32  *-----------------------------------------------------------------------------*/
33 
34 #include "doomdef.h"
35 #include "doomstat.h"
36 #include "p_spec.h"
37 #include "p_maputl.h"
38 #include "p_map.h"
39 #include "r_main.h"
40 #include "p_tick.h"
41 #include "s_sound.h"
42 #include "sounds.h"
43 #include "p_user.h"
44 #include "r_demo.h"
45 
P_TeleportDestination(line_t * line)46 static mobj_t* P_TeleportDestination(line_t* line)
47 {
48   int i;
49   for (i = -1; (i = P_FindSectorFromLineTag(line, i)) >= 0;) {
50     register thinker_t* th = NULL;
51     while ((th = P_NextThinker(th,th_misc)) != NULL)
52       if (th->function == P_MobjThinker) {
53         register mobj_t* m = (mobj_t*)th;
54         if (m->type == MT_TELEPORTMAN  &&
55             m->subsector->sector-sectors == i)
56             return m;
57       }
58   }
59   return NULL;
60 }
61 //
62 // TELEPORTATION
63 //
64 // killough 5/3/98: reformatted, cleaned up
65 
EV_Teleport(line_t * line,int side,mobj_t * thing)66 int EV_Teleport(line_t *line, int side, mobj_t *thing)
67 {
68   mobj_t    *m;
69 
70   // don't teleport missiles
71   // Don't teleport if hit back of line,
72   //  so you can get out of teleporter.
73   if (side || thing->flags & MF_MISSILE)
74     return 0;
75 
76   // killough 1/31/98: improve performance by using
77   // P_FindSectorFromLineTag instead of simple linear search.
78 
79   if ((m = P_TeleportDestination(line)) != NULL)
80         {
81           fixed_t oldx = thing->x, oldy = thing->y, oldz = thing->z;
82           player_t *player = thing->player;
83 
84           // killough 5/12/98: exclude voodoo dolls:
85           if (player && player->mo != thing)
86             player = NULL;
87 
88           if (!P_TeleportMove(thing, m->x, m->y, false)) /* killough 8/9/98 */
89             return 0;
90 
91           if (compatibility_level != finaldoom_compatibility)
92             thing->z = thing->floorz;
93 
94           if (player)
95             player->viewz = thing->z + player->viewheight;
96 
97           // spawn teleport fog and emit sound at source
98           S_StartSound(P_SpawnMobj(oldx, oldy, oldz, MT_TFOG), sfx_telept);
99 
100           // spawn teleport fog and emit sound at destination
101           S_StartSound(P_SpawnMobj(m->x +
102                                     20*finecosine[m->angle>>ANGLETOFINESHIFT],
103                                    m->y +
104                                     20*finesine[m->angle>>ANGLETOFINESHIFT],
105                                    thing->z, MT_TFOG),
106                        sfx_telept);
107 
108     /* don't move for a bit
109      * cph - DEMOSYNC - BOOM had (player) here? */
110           if (thing->player)
111             thing->reactiontime = 18;
112 
113           thing->angle = m->angle;
114 
115           thing->momx = thing->momy = thing->momz = 0;
116 
117     /* killough 10/98: kill all bobbing momentum too */
118     if (player)
119       player->momx = player->momy = 0;
120 
121      // e6y
122      if (player && player->mo == thing)
123       R_ResetAfterTeleport(player);
124 
125           return 1;
126         }
127   return 0;
128 }
129 
130 //
131 // Silent TELEPORTATION, by Lee Killough
132 // Primarily for rooms-over-rooms etc.
133 //
134 
EV_SilentTeleport(line_t * line,int side,mobj_t * thing)135 int EV_SilentTeleport(line_t *line, int side, mobj_t *thing)
136 {
137   mobj_t    *m;
138 
139   // don't teleport missiles
140   // Don't teleport if hit back of line,
141   // so you can get out of teleporter.
142 
143   if (side || thing->flags & MF_MISSILE)
144     return 0;
145 
146   if ((m = P_TeleportDestination(line)) != NULL)
147         {
148           // Height of thing above ground, in case of mid-air teleports:
149           fixed_t z = thing->z - thing->floorz;
150 
151           // Get the angle between the exit thing and source linedef.
152           // Rotate 90 degrees, so that walking perpendicularly across
153           // teleporter linedef causes thing to exit in the direction
154           // indicated by the exit thing.
155           angle_t angle =
156             R_PointToAngle2(0, 0, line->dx, line->dy) - m->angle + ANG90;
157 
158           // Sine, cosine of angle adjustment
159           fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
160           fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
161 
162           // Momentum of thing crossing teleporter linedef
163           fixed_t momx = thing->momx;
164           fixed_t momy = thing->momy;
165 
166           // Whether this is a player, and if so, a pointer to its player_t
167           player_t *player = thing->player;
168 
169           // Attempt to teleport, aborting if blocked
170           if (!P_TeleportMove(thing, m->x, m->y, false)) /* killough 8/9/98 */
171             return 0;
172 
173           // Rotate thing according to difference in angles
174           thing->angle += angle;
175 
176           // Adjust z position to be same height above ground as before
177           thing->z = z + thing->floorz;
178 
179           // Rotate thing's momentum to come out of exit just like it entered
180           thing->momx = FixedMul(momx, c) - FixedMul(momy, s);
181           thing->momy = FixedMul(momy, c) + FixedMul(momx, s);
182 
183           // Adjust player's view, in case there has been a height change
184           // Voodoo dolls are excluded by making sure player->mo == thing.
185           if (player && player->mo == thing)
186             {
187               // Save the current deltaviewheight, used in stepping
188               fixed_t deltaviewheight = player->deltaviewheight;
189 
190               // Clear deltaviewheight, since we don't want any changes
191               player->deltaviewheight = 0;
192 
193               // Set player's view according to the newly set parameters
194               P_CalcHeight(player);
195 
196               // Reset the delta to have the same dynamics as before
197               player->deltaviewheight = deltaviewheight;
198             }
199 
200           // e6y
201           if (player && player->mo == thing)
202             R_ResetAfterTeleport(player);
203 
204           return 1;
205         }
206   return 0;
207 }
208 
209 //
210 // Silent linedef-based TELEPORTATION, by Lee Killough
211 // Primarily for rooms-over-rooms etc.
212 // This is the complete player-preserving kind of teleporter.
213 // It has advantages over the teleporter with thing exits.
214 //
215 
216 // maximum fixed_t units to move object to avoid hiccups
217 #define FUDGEFACTOR 10
218 
EV_SilentLineTeleport(line_t * line,int side,mobj_t * thing,boolean reverse)219 int EV_SilentLineTeleport(line_t *line, int side, mobj_t *thing,
220                           boolean reverse)
221 {
222   int i;
223   line_t *l;
224 
225   if (side || thing->flags & MF_MISSILE)
226     return 0;
227 
228   for (i = -1; (i = P_FindLineFromLineTag(line, i)) >= 0;)
229     if ((l=lines+i) != line && l->backsector)
230       {
231         // Get the thing's position along the source linedef
232         fixed_t pos = D_abs(line->dx) > D_abs(line->dy) ?
233           FixedDiv(thing->x - line->v1->x, line->dx) :
234           FixedDiv(thing->y - line->v1->y, line->dy) ;
235 
236         // Get the angle between the two linedefs, for rotating
237         // orientation and momentum. Rotate 180 degrees, and flip
238         // the position across the exit linedef, if reversed.
239         angle_t angle = (reverse ? pos = FRACUNIT-pos, 0 : ANG180) +
240           R_PointToAngle2(0, 0, l->dx, l->dy) -
241           R_PointToAngle2(0, 0, line->dx, line->dy);
242 
243         // Interpolate position across the exit linedef
244         fixed_t x = l->v2->x - FixedMul(pos, l->dx);
245         fixed_t y = l->v2->y - FixedMul(pos, l->dy);
246 
247         // Sine, cosine of angle adjustment
248         fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
249         fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
250 
251         // Maximum distance thing can be moved away from interpolated
252         // exit, to ensure that it is on the correct side of exit linedef
253         int fudge = FUDGEFACTOR;
254 
255         // Whether this is a player, and if so, a pointer to its player_t.
256         // Voodoo dolls are excluded by making sure thing->player->mo==thing.
257         player_t *player = thing->player && thing->player->mo == thing ?
258           thing->player : NULL;
259 
260         // Whether walking towards first side of exit linedef steps down
261         int stepdown =
262           l->frontsector->floorheight < l->backsector->floorheight;
263 
264         // Height of thing above ground
265         fixed_t z = thing->z - thing->floorz;
266 
267         // Side to exit the linedef on positionally.
268         //
269         // Notes:
270         //
271         // This flag concerns exit position, not momentum. Due to
272         // roundoff error, the thing can land on either the left or
273         // the right side of the exit linedef, and steps must be
274         // taken to make sure it does not end up on the wrong side.
275         //
276         // Exit momentum is always towards side 1 in a reversed
277         // teleporter, and always towards side 0 otherwise.
278         //
279         // Exiting positionally on side 1 is always safe, as far
280         // as avoiding oscillations and stuck-in-wall problems,
281         // but may not be optimum for non-reversed teleporters.
282         //
283         // Exiting on side 0 can cause oscillations if momentum
284         // is towards side 1, as it is with reversed teleporters.
285         //
286         // Exiting on side 1 slightly improves player viewing
287         // when going down a step on a non-reversed teleporter.
288 
289         int side = reverse || (player && stepdown);
290 
291         // Make sure we are on correct side of exit linedef.
292         while (P_PointOnLineSide(x, y, l) != side && --fudge>=0)
293           if (D_abs(l->dx) > D_abs(l->dy))
294             y -= l->dx < 0 != side ? -1 : 1;
295           else
296             x += l->dy < 0 != side ? -1 : 1;
297 
298         // Attempt to teleport, aborting if blocked
299         if (!P_TeleportMove(thing, x, y, false)) /* killough 8/9/98 */
300           return 0;
301 
302         // e6y
303         if (player && player->mo == thing)
304           R_ResetAfterTeleport(player);
305 
306         // Adjust z position to be same height above ground as before.
307         // Ground level at the exit is measured as the higher of the
308         // two floor heights at the exit linedef.
309         thing->z = z + sides[l->sidenum[stepdown]].sector->floorheight;
310 
311         // Rotate thing's orientation according to difference in linedef angles
312         thing->angle += angle;
313 
314         // Momentum of thing crossing teleporter linedef
315         x = thing->momx;
316         y = thing->momy;
317 
318         // Rotate thing's momentum to come out of exit just like it entered
319         thing->momx = FixedMul(x, c) - FixedMul(y, s);
320         thing->momy = FixedMul(y, c) + FixedMul(x, s);
321 
322         // Adjust a player's view, in case there has been a height change
323         if (player)
324           {
325             // Save the current deltaviewheight, used in stepping
326             fixed_t deltaviewheight = player->deltaviewheight;
327 
328             // Clear deltaviewheight, since we don't want any changes now
329             player->deltaviewheight = 0;
330 
331             // Set player's view according to the newly set parameters
332             P_CalcHeight(player);
333 
334             // Reset the delta to have the same dynamics as before
335             player->deltaviewheight = deltaviewheight;
336           }
337 
338         // e6y
339         if (player && player->mo == thing)
340           R_ResetAfterTeleport(player);
341 
342         return 1;
343       }
344   return 0;
345 }
346