diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index ceffe907a2..c9ad986885 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -105,7 +105,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i morphed->flags |= actor->flags & (MF_SHADOW|MF_NOGRAVITY); morphed->flags2 |= actor->flags2 & MF2_FLY; morphed->flags3 |= actor->flags3 & MF3_GHOST; - Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->x, actor->y, actor->z + TELEFOGHEIGHT, ALLOW_REPLACE); + AActor *eflash = Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->x, actor->y, actor->z + TELEFOGHEIGHT, ALLOW_REPLACE); actor->player = NULL; actor->flags &= ~(MF_SOLID|MF_SHOOTABLE); actor->flags |= MF_UNMORPHED; @@ -151,6 +151,8 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i p->camera = morphed; } morphed->ScoreIcon = actor->ScoreIcon; // [GRB] + if (eflash) + eflash->target = p->mo; return true; } @@ -305,9 +307,11 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, } angle = mo->angle >> ANGLETOFINESHIFT; + AActor *eflash = NULL; if (exit_flash != NULL) { - Spawn(exit_flash, pmo->x + 20*finecosine[angle], pmo->y + 20*finesine[angle], pmo->z + TELEFOGHEIGHT, ALLOW_REPLACE); + eflash = Spawn(exit_flash, pmo->x + 20*finecosine[angle], pmo->y + 20*finesine[angle], pmo->z + TELEFOGHEIGHT, ALLOW_REPLACE); + if (eflash) eflash->target = mo; } mo->SetupWeaponSlots(); // Use original class's weapon slots. beastweap = player->ReadyWeapon; @@ -406,7 +410,9 @@ bool P_MorphMonster (AActor *actor, const PClass *spawntype, int duration, int s actor->flags &= ~(MF_SOLID|MF_SHOOTABLE); actor->flags |= MF_UNMORPHED; actor->renderflags |= RF_INVISIBLE; - Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->x, actor->y, actor->z + TELEFOGHEIGHT, ALLOW_REPLACE); + AActor *eflash = Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->x, actor->y, actor->z + TELEFOGHEIGHT, ALLOW_REPLACE); + if (eflash) + eflash->target = morphed; return true; } @@ -466,7 +472,9 @@ bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force) DObject::StaticPointerSubstitution (beast, actor); const PClass *exit_flash = beast->MorphExitFlash; beast->Destroy (); - Spawn(exit_flash, beast->x, beast->y, beast->z + TELEFOGHEIGHT, ALLOW_REPLACE); + AActor *eflash = Spawn(exit_flash, beast->x, beast->y, beast->z + TELEFOGHEIGHT, ALLOW_REPLACE); + if (eflash) + eflash->target = actor; return true; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 3afc89b110..9bec4ed55e 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2750,10 +2750,10 @@ void P_NightmareRespawn (AActor *mobj) mo->PrevZ = z; // Do not interpolate Z position if we changed it since spawning. // spawn a teleport fog at old spot because of removal of the body? - P_SpawnTeleportFog(mobj, mobj->x, mobj->y, mobj->z + TELEFOGHEIGHT, true); + P_SpawnTeleportFog(mobj, mobj->x, mobj->y, mobj->z + TELEFOGHEIGHT, true, true); // spawn a teleport fog at the new spot - P_SpawnTeleportFog(mobj, x, y, z + TELEFOGHEIGHT, false); + P_SpawnTeleportFog(mobj, x, y, z + TELEFOGHEIGHT, false, true); // remove the old monster mobj->Destroy (); diff --git a/src/p_things.cpp b/src/p_things.cpp index 50e15a1a86..95a52f8a8b 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -94,7 +94,7 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, mobj->angle = (angle != ANGLE_MAX ? angle : spot->angle); if (fog) { - P_SpawnTeleportFog(mobj, spot->x, spot->y, spot->z + TELEFOGHEIGHT, false); + P_SpawnTeleportFog(mobj, spot->x, spot->y, spot->z + TELEFOGHEIGHT, false, true); } if (mobj->flags & MF_SPECIAL) mobj->flags |= MF_DROPPED; // Don't respawn @@ -132,8 +132,8 @@ bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog) { if (fog) { - P_SpawnTeleportFog(source, x, y, z); - P_SpawnTeleportFog(source, oldx, oldy, oldz, false); + P_SpawnTeleportFog(source, x, y, z, false, true); + P_SpawnTeleportFog(source, oldx, oldy, oldz, true, true); } source->PrevX = x; source->PrevY = y; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index b1da8f546c..d98bb48573 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3056,8 +3056,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) if (flags & RSF_FOG) { - P_SpawnTeleportFog(self, oldx, oldy, oldz, true); - P_SpawnTeleportFog(self, self->x, self->y, self->z, false); + P_SpawnTeleportFog(self, oldx, oldy, oldz, true, true); + P_SpawnTeleportFog(self, self->x, self->y, self->z, false, true); } if (self->CountsAsKill()) { @@ -4228,9 +4228,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) //=========================================================================== // -// A_Teleport(optional state teleportstate, optional class targettype, -// optional class fogtype, optional int flags, optional fixed mindist, -// optional fixed maxdist) +// A_Teleport([state teleportstate, [class targettype, +// [class fogtype, [int flags, [fixed mindist, +// [fixed maxdist]]]]]]) // // Attempts to teleport to a targettype at least mindist away and at most // maxdist away (0 means unlimited). If successful, spawn a fogtype at old @@ -4253,13 +4253,25 @@ enum T_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) { - ACTION_PARAM_START(6); + ACTION_PARAM_START(7); ACTION_PARAM_STATE(TeleportState, 0); ACTION_PARAM_CLASS(TargetType, 1); ACTION_PARAM_CLASS(FogType, 2); ACTION_PARAM_INT(Flags, 3); ACTION_PARAM_FIXED(MinDist, 4); ACTION_PARAM_FIXED(MaxDist, 5); + ACTION_PARAM_INT(ptr, 6); + + AActor *ref = COPY_AAPTR(self, ptr); + + if (!ref) + { + ACTION_SET_RESULT(false); + return; + } + + if (ref->flags2 & MF2_NOTELEPORT) + return; // Randomly choose not to teleport like A_Srcr2Decide. if (Flags & TF_RANDOMDECIDE) @@ -4269,7 +4281,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) 192, 120, 120, 120, 64, 64, 32, 16, 0 }; - unsigned int chanceindex = self->health / ((self->SpawnHealth()/8 == 0) ? 1 : self->SpawnHealth()/8); + unsigned int chanceindex = ref->health / ((ref->SpawnHealth()/8 == 0) ? 1 : ref->SpawnHealth()/8); if (chanceindex >= countof(chance)) { @@ -4280,37 +4292,42 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) } DSpotState *state = DSpotState::GetSpotState(); - if (state == NULL) return; + if (state == NULL) + return; - if (!TargetType) TargetType = PClass::FindClass("BossSpot"); + if (!TargetType) + TargetType = PClass::FindClass("BossSpot"); - AActor * spot = state->GetSpotWithMinMaxDistance(TargetType, self->x, self->y, MinDist, MaxDist); - if (spot == NULL) return; + AActor * spot = state->GetSpotWithMinMaxDistance(TargetType, ref->x, ref->y, MinDist, MaxDist); + if (spot == NULL) + return; - fixed_t prevX = self->x; - fixed_t prevY = self->y; - fixed_t prevZ = self->z; + fixed_t prevX = ref->x; + fixed_t prevY = ref->y; + fixed_t prevZ = ref->z; fixed_t aboveFloor = spot->z - spot->floorz; fixed_t finalz = spot->floorz + aboveFloor; - if (spot->z + self->height > spot->ceilingz) - finalz = spot->ceilingz - self->height; + if (spot->z + ref->height > spot->ceilingz) + finalz = spot->ceilingz - ref->height; else if (spot->z < spot->floorz) finalz = spot->floorz; //Take precedence and cooperate with telefragging first. - bool teleResult = P_TeleportMove(self, spot->x, spot->y, finalz, Flags & TF_TELEFRAG); + bool teleResult = P_TeleportMove(ref, spot->x, spot->y, finalz, Flags & TF_TELEFRAG); - if (Flags & TF_FORCED) + if (!teleResult && (Flags & TF_FORCED)) { //If for some reason the original move didn't work, regardless of telefrag, force it to move. - self->SetOrigin(spot->x, spot->y, finalz); + ref->SetOrigin(spot->x, spot->y, finalz); teleResult = true; } + AActor *fog1 = NULL, *fog2 = NULL; if (teleResult) { + //If a fog type is defined in the parameter, or the user wants to use the actor's predefined fogs, //and if there's no desire to be fogless, spawn a fog based upon settings. if (FogType || (Flags & TF_USEACTORFOG)) @@ -4318,31 +4335,40 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) if (!(Flags & TF_NOSRCFOG)) { if (Flags & TF_USEACTORFOG) - P_SpawnTeleportFog(self, prevX, prevY, prevZ, true); + P_SpawnTeleportFog(ref, prevX, prevY, prevZ, true, true); else - Spawn(FogType, prevX, prevY, prevZ, ALLOW_REPLACE); + { + fog1 = Spawn(FogType, prevX, prevY, prevZ, ALLOW_REPLACE); + if (fog1 != NULL) + fog1->target = ref; + } } if (!(Flags & TF_NODESTFOG)) { if (Flags & TF_USEACTORFOG) - P_SpawnTeleportFog(self, self->x, self->y, self->z, false); + P_SpawnTeleportFog(ref, ref->x, ref->y, ref->z, false, true); else - Spawn(FogType, self->x, self->y, self->z, ALLOW_REPLACE); + { + fog2 = Spawn(FogType, prevX, prevY, prevZ, ALLOW_REPLACE); + if (fog2 != NULL) + fog2->target = ref; + } } + } if (Flags & TF_USESPOTZ) - self->z = spot->z; + ref->z = spot->z; else - self->z = self->floorz; + ref->z = ref->floorz; if (!(Flags & TF_KEEPANGLE)) - self->angle = spot->angle; + ref->angle = spot->angle; if (!(Flags & TF_KEEPVELOCITY)) - self->velx = self->vely = self->velz = 0; + ref->velx = ref->vely = ref->velz = 0; - if (!(Flags & TF_NOJUMP)) + if (!(Flags & TF_NOJUMP)) //The state jump should only happen with the calling actor. { ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! if (TeleportState == NULL) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 8a31b05c0b..5d3fcf2ec3 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -248,7 +248,7 @@ ACTOR Actor native //: Thinker action native A_CheckCeiling(state label); action native A_PlayerSkinCheck(state label); action native A_BasicAttack(int meleedamage, sound meleesound, class missiletype, float missileheight); - action native A_Teleport(state teleportstate = "", class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, float mindist = 0, float maxdist = 0); + action native A_Teleport(state teleportstate = "", class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, float mindist = 0, float maxdist = 0, int ptr = AAPTR_DEFAULT); action native A_Warp(int ptr_destination, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0, int flags = 0, state success_state = ""); action native A_ThrowGrenade(class itemtype, float zheight = 0, float xyvel = 0, float zvel = 0, bool useammo = true); action native A_Weave(int xspeed, int yspeed, float xdist, float ydist);