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