From 1799ae91c92f24b03036c29ee7570f4679902a5f Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Tue, 7 Apr 2015 11:14:02 -0500 Subject: [PATCH 1/2] - Allow teleport fogs to set the teleporting actors as their targets, so modders can create interactions between the two. - Fixed: P_MoveThing had source and destination fog spawning backwards. - Fixed a case where the NOTELEPORT flag would be ignored on A_Teleport. - Added pointer selection to A_Teleport. Defaults to AAPTR_DEFAULT (calling actor). State jumps will only be done by the calling actor. --- src/p_mobj.cpp | 4 +- src/p_things.cpp | 6 +-- src/thingdef/thingdef_codeptr.cpp | 82 ++++++++++++++++++++----------- wadsrc/static/actors/actor.txt | 2 +- 4 files changed, 60 insertions(+), 34 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2571413c85..bbf6e16bfc 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2699,10 +2699,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 faf1091d55..982a57f167 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 cb59f8a1fa..3d218083ea 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3077,8 +3077,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()) { @@ -4249,9 +4249,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 @@ -4274,13 +4274,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) @@ -4290,7 +4302,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)) { @@ -4301,37 +4313,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)) @@ -4339,31 +4356,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 7d8fad5bf9..0bd9ed31a9 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); From 43053b89a5cc3cd4ce717a129005c29433e0db61 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sun, 26 Apr 2015 10:06:13 -0500 Subject: [PATCH 2/2] - Set the morphing and unmorphing actor as target for the teleport fog. This will allow for better interactions on what should happen between the morphee without needing to make monster AI needing to search for them in particular or rely upon TIDs. --- src/g_shared/a_morph.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index e3433f12ef..c42523997f 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; @@ -156,6 +156,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; } @@ -310,9 +312,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; @@ -411,7 +415,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; } @@ -471,7 +477,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; }