p_telept.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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. #include "doomdef.h"
  34. #include "doomstat.h"
  35. #include "p_spec.h"
  36. #include "p_maputl.h"
  37. #include "p_map.h"
  38. #include "r_main.h"
  39. #include "p_tick.h"
  40. #include "s_sound.h"
  41. #include "sounds.h"
  42. #include "p_user.h"
  43. #include "r_demo.h"
  44. static mobj_t* P_TeleportDestination(line_t* line)
  45. {
  46. int i;
  47. for (i = -1; (i = P_FindSectorFromLineTag(line, i)) >= 0;) {
  48. register thinker_t* th = NULL;
  49. while ((th = P_NextThinker(th,th_misc)) != NULL)
  50. if (th->function == P_MobjThinker) {
  51. register mobj_t* m = (mobj_t*)th;
  52. if (m->type == MT_TELEPORTMAN &&
  53. m->subsector->sector-sectors == i)
  54. return m;
  55. }
  56. }
  57. return NULL;
  58. }
  59. //
  60. // TELEPORTATION
  61. //
  62. // killough 5/3/98: reformatted, cleaned up
  63. int EV_Teleport(line_t *line, int side, mobj_t *thing)
  64. {
  65. mobj_t *m;
  66. // don't teleport missiles
  67. // Don't teleport if hit back of line,
  68. // so you can get out of teleporter.
  69. if (side || thing->flags & MF_MISSILE)
  70. return 0;
  71. // killough 1/31/98: improve performance by using
  72. // P_FindSectorFromLineTag instead of simple linear search.
  73. if ((m = P_TeleportDestination(line)) != NULL)
  74. {
  75. fixed_t oldx = thing->x, oldy = thing->y, oldz = thing->z;
  76. player_t *player = thing->player;
  77. // killough 5/12/98: exclude voodoo dolls:
  78. if (player && player->mo != thing)
  79. player = NULL;
  80. if (!P_TeleportMove(thing, m->x, m->y, false)) /* killough 8/9/98 */
  81. return 0;
  82. if (compatibility_level != finaldoom_compatibility)
  83. thing->z = thing->floorz;
  84. if (player)
  85. player->viewz = thing->z + player->viewheight;
  86. // spawn teleport fog and emit sound at source
  87. S_StartSound(P_SpawnMobj(oldx, oldy, oldz, MT_TFOG), sfx_telept);
  88. // spawn teleport fog and emit sound at destination
  89. S_StartSound(P_SpawnMobj(m->x +
  90. 20*finecosine[m->angle>>ANGLETOFINESHIFT],
  91. m->y +
  92. 20*finesine[m->angle>>ANGLETOFINESHIFT],
  93. thing->z, MT_TFOG),
  94. sfx_telept);
  95. /* don't move for a bit
  96. * cph - DEMOSYNC - BOOM had (player) here? */
  97. if (thing->player)
  98. thing->reactiontime = 18;
  99. thing->angle = m->angle;
  100. thing->momx = thing->momy = thing->momz = 0;
  101. /* killough 10/98: kill all bobbing momentum too */
  102. if (player)
  103. player->momx = player->momy = 0;
  104. // e6y
  105. if (player && player->mo == thing)
  106. R_ResetAfterTeleport(player);
  107. return 1;
  108. }
  109. return 0;
  110. }
  111. //
  112. // Silent TELEPORTATION, by Lee Killough
  113. // Primarily for rooms-over-rooms etc.
  114. //
  115. int EV_SilentTeleport(line_t *line, int side, mobj_t *thing)
  116. {
  117. mobj_t *m;
  118. // don't teleport missiles
  119. // Don't teleport if hit back of line,
  120. // so you can get out of teleporter.
  121. if (side || thing->flags & MF_MISSILE)
  122. return 0;
  123. if ((m = P_TeleportDestination(line)) != NULL)
  124. {
  125. // Height of thing above ground, in case of mid-air teleports:
  126. fixed_t z = thing->z - thing->floorz;
  127. // Get the angle between the exit thing and source linedef.
  128. // Rotate 90 degrees, so that walking perpendicularly across
  129. // teleporter linedef causes thing to exit in the direction
  130. // indicated by the exit thing.
  131. angle_t angle =
  132. R_PointToAngle2(0, 0, line->dx, line->dy) - m->angle + ANG90;
  133. // Sine, cosine of angle adjustment
  134. fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
  135. fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
  136. // Momentum of thing crossing teleporter linedef
  137. fixed_t momx = thing->momx;
  138. fixed_t momy = thing->momy;
  139. // Whether this is a player, and if so, a pointer to its player_t
  140. player_t *player = thing->player;
  141. // Attempt to teleport, aborting if blocked
  142. if (!P_TeleportMove(thing, m->x, m->y, false)) /* killough 8/9/98 */
  143. return 0;
  144. // Rotate thing according to difference in angles
  145. thing->angle += angle;
  146. // Adjust z position to be same height above ground as before
  147. thing->z = z + thing->floorz;
  148. // Rotate thing's momentum to come out of exit just like it entered
  149. thing->momx = FixedMul(momx, c) - FixedMul(momy, s);
  150. thing->momy = FixedMul(momy, c) + FixedMul(momx, s);
  151. // Adjust player's view, in case there has been a height change
  152. // Voodoo dolls are excluded by making sure player->mo == thing.
  153. if (player && player->mo == thing)
  154. {
  155. // Save the current deltaviewheight, used in stepping
  156. fixed_t deltaviewheight = player->deltaviewheight;
  157. // Clear deltaviewheight, since we don't want any changes
  158. player->deltaviewheight = 0;
  159. // Set player's view according to the newly set parameters
  160. P_CalcHeight(player);
  161. // Reset the delta to have the same dynamics as before
  162. player->deltaviewheight = deltaviewheight;
  163. }
  164. // e6y
  165. if (player && player->mo == thing)
  166. R_ResetAfterTeleport(player);
  167. return 1;
  168. }
  169. return 0;
  170. }
  171. //
  172. // Silent linedef-based TELEPORTATION, by Lee Killough
  173. // Primarily for rooms-over-rooms etc.
  174. // This is the complete player-preserving kind of teleporter.
  175. // It has advantages over the teleporter with thing exits.
  176. //
  177. // maximum fixed_t units to move object to avoid hiccups
  178. #define FUDGEFACTOR 10
  179. int EV_SilentLineTeleport(line_t *line, int side, mobj_t *thing,
  180. boolean reverse)
  181. {
  182. int i;
  183. line_t *l;
  184. if (side || thing->flags & MF_MISSILE)
  185. return 0;
  186. for (i = -1; (i = P_FindLineFromLineTag(line, i)) >= 0;)
  187. if ((l=lines+i) != line && l->backsector)
  188. {
  189. // Get the thing's position along the source linedef
  190. fixed_t pos = D_abs(line->dx) > D_abs(line->dy) ?
  191. FixedDiv(thing->x - line->v1->x, line->dx) :
  192. FixedDiv(thing->y - line->v1->y, line->dy) ;
  193. // Get the angle between the two linedefs, for rotating
  194. // orientation and momentum. Rotate 180 degrees, and flip
  195. // the position across the exit linedef, if reversed.
  196. angle_t angle = (reverse ? pos = FRACUNIT-pos, 0 : ANG180) +
  197. R_PointToAngle2(0, 0, l->dx, l->dy) -
  198. R_PointToAngle2(0, 0, line->dx, line->dy);
  199. // Interpolate position across the exit linedef
  200. fixed_t x = l->v2->x - FixedMul(pos, l->dx);
  201. fixed_t y = l->v2->y - FixedMul(pos, l->dy);
  202. // Sine, cosine of angle adjustment
  203. fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
  204. fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
  205. // Maximum distance thing can be moved away from interpolated
  206. // exit, to ensure that it is on the correct side of exit linedef
  207. int fudge = FUDGEFACTOR;
  208. // Whether this is a player, and if so, a pointer to its player_t.
  209. // Voodoo dolls are excluded by making sure thing->player->mo==thing.
  210. player_t *player = thing->player && thing->player->mo == thing ?
  211. thing->player : NULL;
  212. // Whether walking towards first side of exit linedef steps down
  213. int stepdown =
  214. l->frontsector->floorheight < l->backsector->floorheight;
  215. // Height of thing above ground
  216. fixed_t z = thing->z - thing->floorz;
  217. // Side to exit the linedef on positionally.
  218. //
  219. // Notes:
  220. //
  221. // This flag concerns exit position, not momentum. Due to
  222. // roundoff error, the thing can land on either the left or
  223. // the right side of the exit linedef, and steps must be
  224. // taken to make sure it does not end up on the wrong side.
  225. //
  226. // Exit momentum is always towards side 1 in a reversed
  227. // teleporter, and always towards side 0 otherwise.
  228. //
  229. // Exiting positionally on side 1 is always safe, as far
  230. // as avoiding oscillations and stuck-in-wall problems,
  231. // but may not be optimum for non-reversed teleporters.
  232. //
  233. // Exiting on side 0 can cause oscillations if momentum
  234. // is towards side 1, as it is with reversed teleporters.
  235. //
  236. // Exiting on side 1 slightly improves player viewing
  237. // when going down a step on a non-reversed teleporter.
  238. int theside = reverse || (player && stepdown);
  239. // Make sure we are on correct side of exit linedef.
  240. while (P_PointOnLineSide(x, y, l) != theside && --fudge>=0)
  241. if (D_abs(l->dx) > D_abs(l->dy))
  242. y -= l->dx < 0 != theside ? -1 : 1;
  243. else
  244. x += l->dy < 0 != theside ? -1 : 1;
  245. // Attempt to teleport, aborting if blocked
  246. if (!P_TeleportMove(thing, x, y, false)) /* killough 8/9/98 */
  247. return 0;
  248. // e6y
  249. if (player && player->mo == thing)
  250. R_ResetAfterTeleport(player);
  251. // Adjust z position to be same height above ground as before.
  252. // Ground level at the exit is measured as the higher of the
  253. // two floor heights at the exit linedef.
  254. thing->z = z + sides[l->sidenum[stepdown]].sector->floorheight;
  255. // Rotate thing's orientation according to difference in linedef angles
  256. thing->angle += angle;
  257. // Momentum of thing crossing teleporter linedef
  258. x = thing->momx;
  259. y = thing->momy;
  260. // Rotate thing's momentum to come out of exit just like it entered
  261. thing->momx = FixedMul(x, c) - FixedMul(y, s);
  262. thing->momy = FixedMul(y, c) + FixedMul(x, s);
  263. // Adjust a player's view, in case there has been a height change
  264. if (player)
  265. {
  266. // Save the current deltaviewheight, used in stepping
  267. fixed_t deltaviewheight = player->deltaviewheight;
  268. // Clear deltaviewheight, since we don't want any changes now
  269. player->deltaviewheight = 0;
  270. // Set player's view according to the newly set parameters
  271. P_CalcHeight(player);
  272. // Reset the delta to have the same dynamics as before
  273. player->deltaviewheight = deltaviewheight;
  274. }
  275. // e6y
  276. if (player && player->mo == thing)
  277. R_ResetAfterTeleport(player);
  278. return 1;
  279. }
  280. return 0;
  281. }