diff options
Diffstat (limited to 'src/p_telept.c')
-rw-r--r-- | src/p_telept.c | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/src/p_telept.c b/src/p_telept.c new file mode 100644 index 0000000..744e901 --- /dev/null +++ b/src/p_telept.c | |||
@@ -0,0 +1,345 @@ | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | } | ||