1 /**\file
2 *\section License
3 * License: GPL
4 * Online License Link: http://www.gnu.org/licenses/gpl.html
5 *
6 *\author Copyright © 2003-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
7 *\author Copyright © 2006-2013 Daniel Swanson <danij@dengine.net>
8 *\author Copyright © 1999 Activision
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor,
23 * Boston, MA 02110-1301 USA
24 */
25
26 /**
27 * p_telept.c:
28 */
29
30 // HEADER FILES ------------------------------------------------------------
31
32 #include <string.h>
33
34 #include "jhexen.h"
35
36 #include "dmu_lib.h"
37 #include "g_common.h"
38 #include "p_map.h"
39
40 // MACROS ------------------------------------------------------------------
41
42 // TYPES -------------------------------------------------------------------
43
44 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
45
46 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
47
48 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
49
50 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
51
52 // PUBLIC DATA DEFINITIONS -------------------------------------------------
53
54 // PRIVATE DATA DEFINITIONS ------------------------------------------------
55
56 // CODE --------------------------------------------------------------------
57
P_ArtiTeleportOther(player_t * plr)58 void P_ArtiTeleportOther(player_t* plr)
59 {
60 mobj_t* mo;
61
62 if(!plr || !plr->plr->mo)
63 return;
64
65 if((mo = P_SpawnPlayerMissile(MT_TELOTHER_FX1, plr->plr->mo)))
66 {
67 mo->target = plr->plr->mo;
68 }
69 }
70
P_TeleportToPlayerStarts(mobj_t * mo)71 void P_TeleportToPlayerStarts(mobj_t* mo)
72 {
73 const playerstart_t* start;
74
75 if(!mo) return;
76
77 // Get a random player start.
78 if((start = P_GetPlayerStart(0, -1, false)))
79 {
80 const mapspot_t* spot = &mapSpots[start->spot];
81 P_Teleport(mo, spot->origin[VX], spot->origin[VY], spot->angle, true);
82 }
83 }
84
P_TeleportToDeathmatchStarts(mobj_t * mo)85 void P_TeleportToDeathmatchStarts(mobj_t* mo)
86 {
87 const playerstart_t* start;
88
89 if(!mo) return;
90
91 // First, try a random deathmatch start.
92 if((start = P_GetPlayerStart(0, -1, true)))
93 {
94 const mapspot_t* spot = &mapSpots[start->spot];
95 P_Teleport(mo, spot->origin[VX], spot->origin[VY], spot->angle, true);
96 }
97 else
98 {
99 P_TeleportToPlayerStarts(mo);
100 }
101 }
102
P_SpawnTeleFog(coord_t x,coord_t y,angle_t angle)103 mobj_t* P_SpawnTeleFog(coord_t x, coord_t y, angle_t angle)
104 {
105 return P_SpawnMobjXYZ(MT_TFOG, x, y, TELEFOGHEIGHT, angle, MSF_Z_FLOOR);
106 }
107
P_Teleport(mobj_t * mo,coord_t x,coord_t y,angle_t angle,dd_bool useFog)108 dd_bool P_Teleport(mobj_t* mo, coord_t x, coord_t y, angle_t angle, dd_bool useFog)
109 {
110 coord_t oldpos[3], aboveFloor, fogDelta;
111 unsigned int an;
112 angle_t oldAngle;
113 mobj_t* fog;
114
115 memcpy(oldpos, mo->origin, sizeof(oldpos));
116 oldAngle = mo->angle;
117
118 aboveFloor = mo->origin[VZ] - mo->floorZ;
119 if(!P_TeleportMove(mo, x, y, false))
120 return false;
121
122 // $voodoodolls Must be the real player.
123 if(mo->player && mo->player->plr->mo == mo)
124 {
125 player_t* player = mo->player;
126
127 player->plr->flags |= DDPF_FIXANGLES | DDPF_FIXORIGIN | DDPF_FIXMOM;
128 if(player->powers[PT_FLIGHT] && aboveFloor > 0)
129 {
130 mo->origin[VZ] = mo->floorZ + aboveFloor;
131 if(mo->origin[VZ] + mo->height > mo->ceilingZ)
132 {
133 mo->origin[VZ] = mo->ceilingZ - mo->height;
134 }
135 }
136 else
137 {
138 mo->origin[VZ] = mo->floorZ;
139 if(useFog)
140 player->plr->lookDir = 0;
141 }
142 player->viewHeight = (coord_t) cfg.common.plrViewHeight;
143 player->viewHeightDelta = 0;
144 player->viewZ = mo->origin[VZ] + player->viewHeight;
145 player->viewOffset[VX] = player->viewOffset[VY] = player->viewOffset[VZ] = 0;
146 player->bob = 0;
147 }
148 else if(mo->flags & MF_MISSILE)
149 {
150 mo->origin[VZ] = mo->floorZ + aboveFloor;
151 if(mo->origin[VZ] + mo->height > mo->ceilingZ)
152 {
153 mo->origin[VZ] = mo->ceilingZ - mo->height;
154 }
155 }
156 else
157 {
158 mo->origin[VZ] = mo->floorZ;
159 }
160
161 // Spawn teleport fog at source and destination
162 if(useFog)
163 {
164 fogDelta = (mo->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT);
165 if((fog = P_SpawnMobjXYZ(MT_TFOG, oldpos[VX], oldpos[VY],
166 oldpos[VZ] + fogDelta, oldAngle + ANG180, 0)))
167 S_StartSound(SFX_TELEPORT, fog);
168
169 an = angle >> ANGLETOFINESHIFT;
170 if((fog = P_SpawnMobjXYZ(MT_TFOG,
171 x + 20 * FIX2FLT(finecosine[an]),
172 y + 20 * FIX2FLT(finesine[an]),
173 mo->origin[VZ] + fogDelta, angle + ANG180, 0)))
174 S_StartSound(SFX_TELEPORT, fog);
175
176 if(mo->player && !mo->player->powers[PT_SPEED])
177 { // Freeze player for about .5 sec
178 mo->reactionTime = 18;
179 }
180 mo->angle = angle;
181 }
182
183 if(mo->flags2 & MF2_FLOORCLIP)
184 {
185 mo->floorClip = 0;
186
187 if(FEQUAL(mo->origin[VZ], P_GetDoublep(Mobj_Sector(mo), DMU_FLOOR_HEIGHT)))
188 {
189 const terraintype_t* tt = P_MobjFloorTerrain(mo);
190 if(tt->flags & TTF_FLOORCLIP)
191 {
192 mo->floorClip = 10;
193 }
194 }
195 }
196
197 if(mo->flags & MF_MISSILE)
198 {
199 angle >>= ANGLETOFINESHIFT;
200 mo->mom[MX] = mo->info->speed * FIX2FLT(finecosine[angle]);
201 mo->mom[MY] = mo->info->speed * FIX2FLT(finesine[angle]);
202 }
203 else if(useFog) // No fog doesn't alter the player's momentums.
204 {
205 mo->mom[MX] = mo->mom[MY] = mo->mom[MZ] = 0;
206 }
207
208 P_MobjClearSRVO(mo);
209
210 return true;
211 }
212
EV_Teleport(int tid,mobj_t * thing,dd_bool fog)213 dd_bool EV_Teleport(int tid, mobj_t* thing, dd_bool fog)
214 {
215 int i, count, searcher;
216 mobj_t* mo = 0;
217
218 // Clients cannot teleport on their own.
219 if(IS_CLIENT)
220 return 0;
221
222 if(!thing)
223 return false;
224
225 if(thing->flags2 & MF2_NOTELEPORT)
226 return false;
227
228 count = 0;
229 searcher = -1;
230 while(P_FindMobjFromTID(tid, &searcher) != NULL)
231 count++;
232
233 if(count == 0)
234 return false;
235
236 count = 1 + (P_Random() % count);
237 searcher = -1;
238 for(i = 0; i < count; ++i)
239 {
240 mo = P_FindMobjFromTID(tid, &searcher);
241 }
242
243 if (!mo)
244 {
245 App_Log(DE2_MAP_WARNING, "Can't find teleport mapspot");
246 return false;
247 }
248
249 return P_Teleport(thing, mo->origin[VX], mo->origin[VY], mo->angle, fog);
250 }
251
252 #if __JHERETIC__ || __JHEXEN__
P_ArtiTele(player_t * player)253 void P_ArtiTele(player_t *player)
254 {
255 playerstart_t const *start;
256
257 if((start = P_GetPlayerStart(0, gfw_Rule(deathmatch)? -1 : 0, gfw_Rule(deathmatch))))
258 {
259 mapspot_t const *spot = &mapSpots[start->spot];
260 P_Teleport(player->plr->mo, spot->origin[VX], spot->origin[VY], spot->angle, true);
261
262 #if __JHEXEN__
263 if(player->morphTics)
264 {
265 // Teleporting away will undo any morph effects (pig)
266 P_UndoPlayerMorph(player);
267 }
268 #else
269 S_StartSound(SFX_WPNUP, NULL);
270 #endif
271 }
272 }
273 #endif
274