1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id:$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
11 //
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
16 //
17 // $Log:$
18 //
19 // DESCRIPTION:
20 // Teleportation.
21 //
22 //-----------------------------------------------------------------------------
23
24
25 #include "templates.h"
26 #include "doomtype.h"
27 #include "doomdef.h"
28 #include "s_sound.h"
29 #include "p_local.h"
30 #include "p_terrain.h"
31 #include "r_state.h"
32 #include "gi.h"
33 #include "a_sharedglobal.h"
34 #include "m_random.h"
35 #include "i_system.h"
36 #include "doomstat.h"
37
38 #define FUDGEFACTOR 10
39
40 static FRandom pr_teleport ("Teleport");
41
42 extern void P_CalcHeight (player_t *player);
43
44 CVAR (Bool, telezoom, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
45
IMPLEMENT_CLASS(ATeleportFog)46 IMPLEMENT_CLASS (ATeleportFog)
47
48 void ATeleportFog::PostBeginPlay ()
49 {
50 Super::PostBeginPlay ();
51 S_Sound (this, CHAN_BODY, "misc/teleport", 1, ATTN_NORM);
52 switch (gameinfo.gametype)
53 {
54 case GAME_Hexen:
55 case GAME_Heretic:
56 SetState(FindState(NAME_Raven));
57 break;
58
59 case GAME_Strife:
60 SetState(FindState(NAME_Strife));
61 break;
62
63 default:
64 break;
65 }
66 }
67
68 //==========================================================================
69 //
70 // P_SpawnTeleportFog
71 //
72 // The beginning of customizable teleport fog
73 // (not active yet)
74 //
75 //==========================================================================
76
P_SpawnTeleportFog(AActor * mobj,fixed_t x,fixed_t y,fixed_t z,bool beforeTele,bool setTarget)77 void P_SpawnTeleportFog(AActor *mobj, fixed_t x, fixed_t y, fixed_t z, bool beforeTele, bool setTarget)
78 {
79 AActor *mo;
80 if ((beforeTele ? mobj->TeleFogSourceType : mobj->TeleFogDestType) == NULL)
81 {
82 //Do nothing.
83 mo = NULL;
84 }
85 else
86 {
87 mo = Spawn((beforeTele ? mobj->TeleFogSourceType : mobj->TeleFogDestType), x, y, z, ALLOW_REPLACE);
88 }
89
90 if (mo != NULL && setTarget)
91 mo->target = mobj;
92
93 }
94
95 //
96 // TELEPORTATION
97 //
98
P_Teleport(AActor * thing,fixed_t x,fixed_t y,fixed_t z,angle_t angle,int flags)99 bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, int flags)
100 {
101 bool predicting = (thing->player && (thing->player->cheats & CF_PREDICTING));
102
103 fixedvec3 old;
104 fixed_t aboveFloor;
105 player_t *player;
106 angle_t an;
107 sector_t *destsect;
108 bool resetpitch = false;
109 fixed_t floorheight, ceilingheight;
110 fixed_t missilespeed = 0;
111
112 old = thing->Pos();
113 aboveFloor = thing->Z() - thing->floorz;
114 destsect = P_PointInSector (x, y);
115 // killough 5/12/98: exclude voodoo dolls:
116 player = thing->player;
117 if (player && player->mo != thing)
118 player = NULL;
119 floorheight = destsect->floorplane.ZatPoint (x, y);
120 ceilingheight = destsect->ceilingplane.ZatPoint (x, y);
121 if (thing->flags & MF_MISSILE)
122 { // We don't measure z velocity, because it doesn't change.
123 missilespeed = xs_CRoundToInt(TVector2<double>(thing->velx, thing->vely).Length());
124 }
125 if (flags & TELF_KEEPHEIGHT)
126 {
127 z = floorheight + aboveFloor;
128 }
129 else if (z == ONFLOORZ)
130 {
131 if (player)
132 {
133 if (thing->flags & MF_NOGRAVITY && aboveFloor)
134 {
135 z = floorheight + aboveFloor;
136 if (z + thing->height > ceilingheight)
137 {
138 z = ceilingheight - thing->height;
139 }
140 }
141 else
142 {
143 z = floorheight;
144 if (!(flags & TELF_KEEPORIENTATION))
145 {
146 resetpitch = false;
147 }
148 }
149 }
150 else if (thing->flags & MF_MISSILE)
151 {
152 z = floorheight + aboveFloor;
153 if (z + thing->height > ceilingheight)
154 {
155 z = ceilingheight - thing->height;
156 }
157 }
158 else
159 {
160 z = floorheight;
161 }
162 }
163 if (!P_TeleportMove (thing, x, y, z, false))
164 {
165 return false;
166 }
167 if (player)
168 {
169 player->viewz = thing->Z() + player->viewheight;
170 if (resetpitch)
171 {
172 player->mo->pitch = 0;
173 }
174 }
175 if (!(flags & TELF_KEEPORIENTATION))
176 {
177 thing->angle = angle;
178 }
179 else
180 {
181 angle = thing->angle;
182 }
183 // Spawn teleport fog at source and destination
184 if ((flags & TELF_SOURCEFOG) && !predicting)
185 {
186 P_SpawnTeleportFog(thing, old, true, true); //Passes the actor through which then pulls the TeleFog metadata types based on properties.
187 }
188 if (flags & TELF_DESTFOG)
189 {
190 if (!predicting)
191 {
192 fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
193 an = angle >> ANGLETOFINESHIFT;
194 P_SpawnTeleportFog(thing, x + 20 * finecosine[an], y + 20 * finesine[an], thing->Z() + fogDelta, false, true);
195
196 }
197 if (thing->player)
198 {
199 // [RH] Zoom player's field of vision
200 // [BC] && bHaltVelocity.
201 if (telezoom && thing->player->mo == thing && !(flags & TELF_KEEPVELOCITY))
202 thing->player->FOV = MIN (175.f, thing->player->DesiredFOV + 45.f);
203 }
204 }
205 // [BC] && bHaltVelocity.
206 if (thing->player && ((flags & TELF_DESTFOG) || !(flags & TELF_KEEPORIENTATION)) && !(flags & TELF_KEEPVELOCITY))
207 {
208 // Freeze player for about .5 sec
209 if (thing->Inventory == NULL || !thing->Inventory->GetNoTeleportFreeze())
210 thing->reactiontime = 18;
211 }
212 if (thing->flags & MF_MISSILE)
213 {
214 angle >>= ANGLETOFINESHIFT;
215 thing->velx = FixedMul (missilespeed, finecosine[angle]);
216 thing->vely = FixedMul (missilespeed, finesine[angle]);
217 }
218 // [BC] && bHaltVelocity.
219 else if (!(flags & TELF_KEEPORIENTATION) && !(flags & TELF_KEEPVELOCITY))
220 { // no fog doesn't alter the player's momentum
221 thing->velx = thing->vely = thing->velz = 0;
222 // killough 10/98: kill all bobbing velocity too
223 if (player)
224 player->velx = player->vely = 0;
225 }
226 return true;
227 }
228
SelectTeleDest(int tid,int tag,bool norandom)229 static AActor *SelectTeleDest (int tid, int tag, bool norandom)
230 {
231 AActor *searcher;
232
233 // If tid is non-zero, select a destination from a matching actor at random.
234 // If tag is also non-zero, the selection is restricted to actors in sectors
235 // with a matching tag. If tid is zero and tag is non-zero, then the old Doom
236 // behavior is used instead (return the first teleport dest found in a tagged
237 // sector).
238
239 // Compatibility hack for some maps that fell victim to a bug in the teleport code in 2.0.9x
240 if (ib_compatflags & BCOMPATF_BADTELEPORTERS) tag = 0;
241
242 if (tid != 0)
243 {
244 NActorIterator iterator (NAME_TeleportDest, tid);
245 int count = 0;
246 while ( (searcher = iterator.Next ()) )
247 {
248 if (tag == 0 || tagManager.SectorHasTag(searcher->Sector, tag))
249 {
250 count++;
251 }
252 }
253
254 // If teleport dests were not found, the sector tag is ignored for the
255 // following compatibility searches.
256 // Do this only when tag is 0 because this is the only case that was defined in Hexen.
257 if (count == 0)
258 {
259 if (tag == 0)
260 {
261 // Try to find a matching map spot (fixes Hexen MAP10)
262 NActorIterator it2 (NAME_MapSpot, tid);
263 searcher = it2.Next ();
264 if (searcher == NULL)
265 {
266 // Try to find a matching non-blocking spot of any type (fixes Caldera MAP13)
267 FActorIterator it3 (tid);
268 searcher = it3.Next ();
269 while (searcher != NULL && (searcher->flags & MF_SOLID))
270 {
271 searcher = it3.Next ();
272 }
273 return searcher;
274 }
275 }
276 }
277 else
278 {
279 if (count != 1 && !norandom)
280 {
281 count = 1 + (pr_teleport() % count);
282 }
283 searcher = NULL;
284 while (count > 0)
285 {
286 searcher = iterator.Next ();
287 if (tag == 0 || tagManager.SectorHasTag(searcher->Sector, tag))
288 {
289 count--;
290 }
291 }
292 }
293 return searcher;
294 }
295
296 if (tag != 0)
297 {
298 int secnum;
299
300 FSectorTagIterator itr(tag);
301 while ((secnum = itr.Next()) >= 0)
302 {
303 // Scanning the snext links of things in the sector will not work, because
304 // TeleportDests have MF_NOSECTOR set. So you have to search *everything*.
305 // If there is more than one sector with a matching tag, then the destination
306 // in the lowest-numbered sector is returned, rather than the earliest placed
307 // teleport destination. This means if 50 sectors have a matching tag and
308 // only the last one has a destination, *every* actor is scanned at least 49
309 // times. Yuck.
310 TThinkerIterator<AActor> it2(NAME_TeleportDest);
311 while ((searcher = it2.Next()) != NULL)
312 {
313 if (searcher->Sector == sectors + secnum)
314 {
315 return searcher;
316 }
317 }
318 }
319 }
320
321 return NULL;
322 }
323
EV_Teleport(int tid,int tag,line_t * line,int side,AActor * thing,int flags)324 bool EV_Teleport (int tid, int tag, line_t *line, int side, AActor *thing, int flags)
325 {
326 AActor *searcher;
327 fixed_t z;
328 angle_t angle = 0;
329 fixed_t s = 0, c = 0;
330 fixed_t velx = 0, vely = 0;
331 angle_t badangle = 0;
332
333 if (thing == NULL)
334 { // Teleport function called with an invalid actor
335 return false;
336 }
337 bool predicting = (thing->player && (thing->player->cheats & CF_PREDICTING));
338 if (thing->flags2 & MF2_NOTELEPORT)
339 {
340 return false;
341 }
342 if (side != 0)
343 { // Don't teleport if hit back of line, so you can get out of teleporter.
344 return 0;
345 }
346 searcher = SelectTeleDest(tid, tag, predicting);
347 if (searcher == NULL)
348 {
349 return false;
350 }
351 // [RH] Lee Killough's changes for silent teleporters from BOOM
352 if ((flags & TELF_KEEPORIENTATION) && line)
353 {
354 // Get the angle between the exit thing and source linedef.
355 // Rotate 90 degrees, so that walking perpendicularly across
356 // teleporter linedef causes thing to exit in the direction
357 // indicated by the exit thing.
358 angle = R_PointToAngle2 (0, 0, line->dx, line->dy) - searcher->angle + ANG90;
359
360 // Sine, cosine of angle adjustment
361 s = finesine[angle>>ANGLETOFINESHIFT];
362 c = finecosine[angle>>ANGLETOFINESHIFT];
363
364 // Velocity of thing crossing teleporter linedef
365 velx = thing->velx;
366 vely = thing->vely;
367
368 z = searcher->Z();
369 }
370 else if (searcher->IsKindOf (PClass::FindClass(NAME_TeleportDest2)))
371 {
372 z = searcher->Z();
373 }
374 else
375 {
376 z = ONFLOORZ;
377 }
378 if ((i_compatflags2 & COMPATF2_BADANGLES) && (thing->player != NULL))
379 {
380 badangle = 1 << ANGLETOFINESHIFT;
381 }
382 if (P_Teleport (thing, searcher->X(), searcher->Y(), z, searcher->angle + badangle, flags))
383 {
384 // [RH] Lee Killough's changes for silent teleporters from BOOM
385 if (!(flags & TELF_DESTFOG) && line && (flags & TELF_KEEPORIENTATION))
386 {
387 // Rotate thing according to difference in angles
388 thing->angle += angle;
389
390 // Rotate thing's velocity to come out of exit just like it entered
391 thing->velx = FixedMul(velx, c) - FixedMul(vely, s);
392 thing->vely = FixedMul(vely, c) + FixedMul(velx, s);
393 }
394 if ((velx | vely) == 0 && thing->player != NULL && thing->player->mo == thing && !predicting)
395 {
396 thing->player->mo->PlayIdle ();
397 }
398 return true;
399 }
400 return false;
401 }
402
403 //
404 // Silent linedef-based TELEPORTATION, by Lee Killough
405 // Primarily for rooms-over-rooms etc.
406 // This is the complete player-preserving kind of teleporter.
407 // It has advantages over the teleporter with thing exits.
408 //
409
410 // [RH] Modified to support different source and destination ids.
411 // [RH] Modified some more to be accurate.
EV_SilentLineTeleport(line_t * line,int side,AActor * thing,int id,INTBOOL reverse)412 bool EV_SilentLineTeleport (line_t *line, int side, AActor *thing, int id, INTBOOL reverse)
413 {
414 int i;
415 line_t *l;
416
417 if (side || thing->flags2 & MF2_NOTELEPORT || !line || line->sidedef[1] == NULL)
418 return false;
419
420 FLineIdIterator itr(id);
421 while ((i = itr.Next()) >= 0)
422 {
423 if (line-lines == i)
424 continue;
425
426 if ((l=lines+i) != line && l->backsector)
427 {
428 // Get the thing's position along the source linedef
429 SDWORD pos; // 30.2 fixed
430 fixed_t nposx, nposy; // offsets from line
431 {
432 SQWORD den;
433
434 den = (SQWORD)line->dx*line->dx + (SQWORD)line->dy*line->dy;
435 if (den == 0)
436 {
437 pos = 0;
438 nposx = 0;
439 nposy = 0;
440 }
441 else
442 {
443 SQWORD num = (SQWORD)(thing->X()-line->v1->x)*line->dx +
444 (SQWORD)(thing->Y()-line->v1->y)*line->dy;
445 if (num <= 0)
446 {
447 pos = 0;
448 }
449 else if (num >= den)
450 {
451 pos = 1<<30;
452 }
453 else
454 {
455 pos = (SDWORD)(num / (den>>30));
456 }
457 nposx = thing->X() - line->v1->x - MulScale30 (line->dx, pos);
458 nposy = thing->Y() - line->v1->y - MulScale30 (line->dy, pos);
459 }
460 }
461
462 // Get the angle between the two linedefs, for rotating
463 // orientation and velocity. Rotate 180 degrees, and flip
464 // the position across the exit linedef, if reversed.
465 angle_t angle =
466 R_PointToAngle2(0, 0, l->dx, l->dy) -
467 R_PointToAngle2(0, 0, line->dx, line->dy);
468
469 if (!reverse)
470 {
471 angle += ANGLE_180;
472 pos = (1<<30) - pos;
473 }
474
475 // Sine, cosine of angle adjustment
476 fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
477 fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
478
479 fixed_t x, y;
480
481 // Rotate position along normal to match exit linedef
482 x = DMulScale16 (nposx, c, -nposy, s);
483 y = DMulScale16 (nposy, c, nposx, s);
484
485 // Interpolate position across the exit linedef
486 x += l->v1->x + MulScale30 (pos, l->dx);
487 y += l->v1->y + MulScale30 (pos, l->dy);
488
489 // Whether this is a player, and if so, a pointer to its player_t.
490 // Voodoo dolls are excluded by making sure thing->player->mo==thing.
491 player_t *player = thing->player && thing->player->mo == thing ?
492 thing->player : NULL;
493
494 // Whether walking towards first side of exit linedef steps down
495 bool stepdown = l->frontsector->floorplane.ZatPoint(x, y) < l->backsector->floorplane.ZatPoint(x, y);
496
497 // Height of thing above ground
498 fixed_t z = thing->Z() - thing->floorz;
499
500 // Side to exit the linedef on positionally.
501 //
502 // Notes:
503 //
504 // This flag concerns exit position, not momentum. Due to
505 // roundoff error, the thing can land on either the left or
506 // the right side of the exit linedef, and steps must be
507 // taken to make sure it does not end up on the wrong side.
508 //
509 // Exit momentum is always towards side 1 in a reversed
510 // teleporter, and always towards side 0 otherwise.
511 //
512 // Exiting positionally on side 1 is always safe, as far
513 // as avoiding oscillations and stuck-in-wall problems,
514 // but may not be optimum for non-reversed teleporters.
515 //
516 // Exiting on side 0 can cause oscillations if momentum
517 // is towards side 1, as it is with reversed teleporters.
518 //
519 // Exiting on side 1 slightly improves player viewing
520 // when going down a step on a non-reversed teleporter.
521
522 int side = reverse || (player && stepdown);
523 int fudge = FUDGEFACTOR;
524
525 // Make sure we are on correct side of exit linedef.
526 while (P_PointOnLineSidePrecise(x, y, l) != side && --fudge >= 0)
527 {
528 if (abs(l->dx) > abs(l->dy))
529 y -= (l->dx < 0) != side ? -1 : 1;
530 else
531 x += (l->dy < 0) != side ? -1 : 1;
532 }
533
534 // Adjust z position to be same height above ground as before.
535 // Ground level at the exit is measured as the higher of the
536 // two floor heights at the exit linedef.
537 z = z + l->sidedef[stepdown]->sector->floorplane.ZatPoint(x, y);
538
539 // Attempt to teleport, aborting if blocked
540 if (!P_TeleportMove (thing, x, y, z, false))
541 {
542 return false;
543 }
544
545 if (thing == players[consoleplayer].camera)
546 {
547 R_ResetViewInterpolation ();
548 }
549
550 // Rotate thing's orientation according to difference in linedef angles
551 thing->angle += angle;
552
553 // Velocity of thing crossing teleporter linedef
554 x = thing->velx;
555 y = thing->vely;
556
557 // Rotate thing's velocity to come out of exit just like it entered
558 thing->velx = DMulScale16 (x, c, -y, s);
559 thing->vely = DMulScale16 (y, c, x, s);
560
561 // Adjust a player's view, in case there has been a height change
562 if (player && player->mo == thing)
563 {
564 // Adjust player's local copy of velocity
565 x = player->velx;
566 y = player->vely;
567 player->velx = DMulScale16 (x, c, -y, s);
568 player->vely = DMulScale16 (y, c, x, s);
569
570 // Save the current deltaviewheight, used in stepping
571 fixed_t deltaviewheight = player->deltaviewheight;
572
573 // Clear deltaviewheight, since we don't want any changes now
574 player->deltaviewheight = 0;
575
576 // Set player's view according to the newly set parameters
577 P_CalcHeight(player);
578
579 // Reset the delta to have the same dynamics as before
580 player->deltaviewheight = deltaviewheight;
581 }
582
583 return true;
584 }
585 }
586 return false;
587 }
588
589 // [RH] Teleport anything matching other_tid to dest_tid
EV_TeleportOther(int other_tid,int dest_tid,bool fog)590 bool EV_TeleportOther (int other_tid, int dest_tid, bool fog)
591 {
592 bool didSomething = false;
593
594 if (other_tid != 0 && dest_tid != 0)
595 {
596 AActor *victim;
597 FActorIterator iterator (other_tid);
598
599 while ( (victim = iterator.Next ()) )
600 {
601 didSomething |= EV_Teleport (dest_tid, 0, NULL, 0, victim,
602 fog ? (TELF_DESTFOG | TELF_SOURCEFOG) : TELF_KEEPORIENTATION);
603 }
604 }
605
606 return didSomething;
607 }
608
DoGroupForOne(AActor * victim,AActor * source,AActor * dest,bool floorz,bool fog)609 static bool DoGroupForOne (AActor *victim, AActor *source, AActor *dest, bool floorz, bool fog)
610 {
611 int an = (dest->angle - source->angle) >> ANGLETOFINESHIFT;
612 fixed_t offX = victim->X() - source->X();
613 fixed_t offY = victim->Y() - source->Y();
614 angle_t offAngle = victim->angle - source->angle;
615 fixed_t newX = DMulScale16 (offX, finecosine[an], -offY, finesine[an]);
616 fixed_t newY = DMulScale16 (offX, finesine[an], offY, finecosine[an]);
617
618 bool res =
619 P_Teleport (victim, dest->X() + newX,
620 dest->Y() + newY,
621 floorz ? ONFLOORZ : dest->Z() + victim->Z() - source->Z(),
622 0, fog ? (TELF_DESTFOG | TELF_SOURCEFOG) : TELF_KEEPORIENTATION);
623 // P_Teleport only changes angle if fog is true
624 victim->angle = dest->angle + offAngle;
625
626 return res;
627 }
628
629 #if 0
630 static void MoveTheDecal (DBaseDecal *decal, fixed_t z, AActor *source, AActor *dest)
631 {
632 int an = (dest->angle - source->angle) >> ANGLETOFINESHIFT;
633 fixed_t offX = decal->x - source->x;
634 fixed_t offY = decal->y - source->y;
635 fixed_t newX = DMulScale16 (offX, finecosine[an], -offY, finesine[an]);
636 fixed_t newY = DMulScale16 (offX, finesine[an], offY, finecosine[an]);
637
638 decal->Relocate (dest->x + newX, dest->y + newY, dest->z + z - source->z);
639 }
640 #endif
641
642 // [RH] Teleport a group of actors centered around source_tid so
643 // that they become centered around dest_tid instead.
EV_TeleportGroup(int group_tid,AActor * victim,int source_tid,int dest_tid,bool moveSource,bool fog)644 bool EV_TeleportGroup (int group_tid, AActor *victim, int source_tid, int dest_tid, bool moveSource, bool fog)
645 {
646 AActor *sourceOrigin, *destOrigin;
647 {
648 FActorIterator iterator (source_tid);
649 sourceOrigin = iterator.Next ();
650 }
651 if (sourceOrigin == NULL)
652 { // If there is no source origin, behave like TeleportOther
653 return EV_TeleportOther (group_tid, dest_tid, fog);
654 }
655
656 {
657 NActorIterator iterator (NAME_TeleportDest, dest_tid);
658 destOrigin = iterator.Next ();
659 }
660 if (destOrigin == NULL)
661 {
662 return false;
663 }
664
665 bool didSomething = false;
666 bool floorz = !destOrigin->IsKindOf (PClass::FindClass("TeleportDest2"));
667
668 // Use the passed victim if group_tid is 0
669 if (group_tid == 0 && victim != NULL)
670 {
671 didSomething = DoGroupForOne (victim, sourceOrigin, destOrigin, floorz, fog);
672 }
673 else
674 {
675 FActorIterator iterator (group_tid);
676
677 // For each actor with tid matching arg0, move it to the same
678 // position relative to destOrigin as it is relative to sourceOrigin
679 // before the teleport.
680 while ( (victim = iterator.Next ()) )
681 {
682 didSomething |= DoGroupForOne (victim, sourceOrigin, destOrigin, floorz, fog);
683 }
684 }
685
686 if (moveSource && didSomething)
687 {
688 didSomething |=
689 P_Teleport (sourceOrigin, destOrigin->X(), destOrigin->Y(),
690 floorz ? ONFLOORZ : destOrigin->Z(), 0, TELF_KEEPORIENTATION);
691 sourceOrigin->angle = destOrigin->angle;
692 }
693
694 return didSomething;
695 }
696
697 // [RH] Teleport a group of actors in a sector. Source_tid is used as a
698 // reference point so that they end up in the same position relative to
699 // dest_tid. Group_tid can be used to not teleport all actors in the sector.
EV_TeleportSector(int tag,int source_tid,int dest_tid,bool fog,int group_tid)700 bool EV_TeleportSector (int tag, int source_tid, int dest_tid, bool fog, int group_tid)
701 {
702 AActor *sourceOrigin, *destOrigin;
703 {
704 FActorIterator iterator (source_tid);
705 sourceOrigin = iterator.Next ();
706 }
707 if (sourceOrigin == NULL)
708 {
709 return false;
710 }
711 {
712 NActorIterator iterator (NAME_TeleportDest, dest_tid);
713 destOrigin = iterator.Next ();
714 }
715 if (destOrigin == NULL)
716 {
717 return false;
718 }
719
720 bool didSomething = false;
721 bool floorz = !destOrigin->IsKindOf (PClass::FindClass("TeleportDest2"));
722 int secnum;
723
724 secnum = -1;
725 FSectorTagIterator itr(tag);
726 while ((secnum = itr.Next()) >= 0)
727 {
728 msecnode_t *node;
729 const sector_t * const sec = §ors[secnum];
730
731 for (node = sec->touching_thinglist; node; )
732 {
733 AActor *actor = node->m_thing;
734 msecnode_t *next = node->m_snext;
735
736 // possibly limit actors by group
737 if (actor != NULL && (group_tid == 0 || actor->tid == group_tid))
738 {
739 didSomething |= DoGroupForOne (actor, sourceOrigin, destOrigin, floorz, fog);
740 }
741 node = next;
742 }
743
744 #if 0
745 if (group_tid == 0 && !fog)
746 {
747 int lineindex;
748 for (lineindex = sec->linecount-1; lineindex >= 0; --lineindex)
749 {
750 line_t *line = sec->lines[lineindex];
751 int wallnum;
752
753 wallnum = line->sidenum[(line->backsector == sec)];
754 if (wallnum != -1)
755 {
756 side_t *wall = &sides[wallnum];
757 ADecal *decal = wall->BoundActors;
758
759 while (decal != NULL)
760 {
761 ADecal *next = (ADecal *)decal->snext;
762 MoveTheDecal (decal, decal->GetRealZ (wall), sourceOrigin, destOrigin);
763 decal = next;
764 }
765 }
766 }
767 }
768 #endif
769 }
770 return didSomething;
771 }
772