diff --git a/src/actor.h b/src/actor.h index 7fb4e4cc8..043da9b7c 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1182,6 +1182,8 @@ public: AActor *BlockingMobj; // Actor that blocked the last move line_t *BlockingLine; // Line that blocked the last move + sector_t *BlockingCeiling; // Sector that blocked the last move (ceiling plane slope) + sector_t *BlockingFloor; // Sector that blocked the last move (floor plane slope) int PoisonDamage; // Damage received per tic from poison. FName PoisonDamageType; // Damage type dealt by poison. diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 5c6096f84..47506bfc0 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -345,7 +345,7 @@ void P_PlayerOnSpecial3DFloor(player_t* player) // Checks whether the player's feet touch a solid 3D floor in the sector // //========================================================================== -bool P_CheckFor3DFloorHit(AActor * mo, double z) +bool P_CheckFor3DFloorHit(AActor * mo, double z, bool trigger) { if ((mo->player && (mo->player->cheats & CF_PREDICTING))) return false; @@ -357,7 +357,8 @@ bool P_CheckFor3DFloorHit(AActor * mo, double z) { if (fabs(z - rover->top.plane->ZatPoint(mo)) < EQUAL_EPSILON) { - rover->model->TriggerSectorActions (mo, SECSPAC_HitFloor); + mo->BlockingFloor = rover->model; + if (trigger) rover->model->TriggerSectorActions (mo, SECSPAC_HitFloor); return true; } } @@ -371,7 +372,7 @@ bool P_CheckFor3DFloorHit(AActor * mo, double z) // Checks whether the player's head touches a solid 3D floor in the sector // //========================================================================== -bool P_CheckFor3DCeilingHit(AActor * mo, double z) +bool P_CheckFor3DCeilingHit(AActor * mo, double z, bool trigger) { if ((mo->player && (mo->player->cheats & CF_PREDICTING))) return false; @@ -383,7 +384,8 @@ bool P_CheckFor3DCeilingHit(AActor * mo, double z) { if(fabs(z - rover->bottom.plane->ZatPoint(mo)) < EQUAL_EPSILON) { - rover->model->TriggerSectorActions (mo, SECSPAC_HitCeiling); + mo->BlockingCeiling = rover->model; + if (trigger) rover->model->TriggerSectorActions (mo, SECSPAC_HitCeiling); return true; } } diff --git a/src/p_3dfloors.h b/src/p_3dfloors.h index f46aa913e..e260f9f5f 100644 --- a/src/p_3dfloors.h +++ b/src/p_3dfloors.h @@ -117,8 +117,8 @@ struct lightlist_t class player_t; void P_PlayerOnSpecial3DFloor(player_t* player); -bool P_CheckFor3DFloorHit(AActor * mo, double z); -bool P_CheckFor3DCeilingHit(AActor * mo, double z); +bool P_CheckFor3DFloorHit(AActor * mo, double z, bool trigger); +bool P_CheckFor3DCeilingHit(AActor * mo, double z, bool trigger); void P_Recalculate3DFloors(sector_t *); void P_RecalculateAttached3DFloors(sector_t * sec); void P_RecalculateLights(sector_t *sector); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 67aa64eef..a1730c7ce 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -711,7 +711,7 @@ bool P_Move (AActor *actor) { actor->floorsector->TriggerSectorActions(actor, SECSPAC_HitFloor); } - P_CheckFor3DFloorHit(actor, actor->Z()); + P_CheckFor3DFloorHit(actor, actor->Z(), true); } } } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 25f77fc79..fe40348c1 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -296,6 +296,8 @@ DEFINE_FIELD(AActor, lastbump) DEFINE_FIELD(AActor, DesignatedTeam) DEFINE_FIELD(AActor, BlockingMobj) DEFINE_FIELD(AActor, BlockingLine) +DEFINE_FIELD(AActor, BlockingCeiling) +DEFINE_FIELD(AActor, BlockingFloor) DEFINE_FIELD(AActor, PoisonDamage) DEFINE_FIELD(AActor, PoisonDamageType) DEFINE_FIELD(AActor, PoisonDuration) @@ -478,6 +480,8 @@ void AActor::Serialize(FSerializer &arc) A("smokecounter", smokecounter) ("blockingmobj", BlockingMobj) A("blockingline", BlockingLine) + A("blockingceiling", BlockingCeiling) + A("blockingfloor", BlockingFloor) A("visibletoteam", VisibleToTeam) A("pushfactor", pushfactor) A("species", Species) @@ -2552,6 +2556,21 @@ double P_XYMovement (AActor *mo, DVector2 scroll) AActor *BlockingMobj = mo->BlockingMobj; line_t *BlockingLine = mo->BlockingLine; + // [ZZ] + if (!BlockingLine && !BlockingMobj) // hit floor or ceiling while XY movement - sector actions + { + int hitpart = -1; + sector_t* hitsector = nullptr; + secplane_t* hitplane = nullptr; + if (tm.ceilingsector && mo->Z() + mo->Height > tm.ceilingsector->ceilingplane.ZatPoint(tm.pos.XY())) + mo->BlockingCeiling = tm.ceilingsector; + if (tm.floorsector && mo->Z() < tm.floorsector->floorplane.ZatPoint(tm.pos.XY())) + mo->BlockingFloor = tm.floorsector; + // the following two only set the appropriate field - to avoid issues caused by running actions right in the middle of XY movement + P_CheckFor3DFloorHit(mo, mo->floorz, false); + P_CheckFor3DCeilingHit(mo, mo->ceilingz, false); + } + if (!(mo->flags & MF_MISSILE) && (mo->BounceFlags & BOUNCE_MBF) && (BlockingMobj != NULL ? P_BounceActor(mo, BlockingMobj, false) : P_BounceWall(mo))) { @@ -2738,25 +2757,15 @@ explode: } else onsky = true; } - if (!mo->BlockingLine && !BlockingMobj) // hit floor or ceiling while XY movement + if (mo->BlockingCeiling) // hit floor or ceiling while XY movement { - int hitpart = -1; - sector_t* hitsector = nullptr; - // check against floor - if (tm.floorsector && mo->Z() < tm.floorsector->floorplane.ZatPoint(tm.pos.XY())) - { - hitpart = SECPART_Floor; - hitsector = tm.floorsector; - if (hitsector->healthfloor > 0 && P_CheckSectorVulnerable(hitsector, hitpart)) - P_DamageSector(hitsector, mo, mo->GetMissileDamage((mo->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1), mo->DamageType, hitpart, mo->Pos()); - } - if (tm.ceilingsector && mo->Z() + mo->Height > tm.ceilingsector->ceilingplane.ZatPoint(tm.pos.XY())) - { - hitpart = SECPART_Ceiling; - hitsector = tm.ceilingsector; - if (hitsector->healthceiling > 0 && P_CheckSectorVulnerable(hitsector, hitpart)) - P_DamageSector(hitsector, mo, mo->GetMissileDamage((mo->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1), mo->DamageType, hitpart, mo->Pos()); - } + if (mo->BlockingCeiling->healthceiling > 0 && P_CheckSectorVulnerable(mo->BlockingCeiling, SECPART_Ceiling)) + P_DamageSector(mo->BlockingCeiling, mo, mo->GetMissileDamage((mo->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1), mo->DamageType, SECPART_Ceiling, mo->Pos()); + } + if (mo->BlockingFloor) + { + if (mo->BlockingFloor->healthfloor > 0 && P_CheckSectorVulnerable(mo->BlockingFloor, SECPART_Floor)) + P_DamageSector(mo->BlockingFloor, mo, mo->GetMissileDamage((mo->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1), mo->DamageType, SECPART_Floor, mo->Pos()); } P_ExplodeMissile (mo, mo->BlockingLine, BlockingMobj, onsky); return Oldfloorz; @@ -3110,13 +3119,14 @@ void P_ZMovement (AActor *mo, double oldfloorz) mo->Sector->SecActTarget != NULL && mo->Sector->floorplane.ZatPoint(mo) == mo->floorz) { // [RH] Let the sector do something to the actor - mo->Sector->TriggerSectorActions (mo, SECSPAC_HitFloor); + mo->Sector->TriggerSectorActions(mo, SECSPAC_HitFloor); } - P_CheckFor3DFloorHit(mo, mo->floorz); + P_CheckFor3DFloorHit(mo, mo->floorz, true); // [RH] Need to recheck this because the sector action might have // teleported the actor so it is no longer below the floor. if (mo->Z() <= mo->floorz) { + mo->BlockingFloor = mo->Sector; if ((mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP)) { mo->SetZ(mo->floorz); @@ -3223,11 +3233,12 @@ void P_ZMovement (AActor *mo, double oldfloorz) { // [RH] Let the sector do something to the actor mo->Sector->TriggerSectorActions (mo, SECSPAC_HitCeiling); } - P_CheckFor3DCeilingHit(mo, mo->ceilingz); + P_CheckFor3DCeilingHit(mo, mo->ceilingz, true); // [RH] Need to recheck this because the sector action might have // teleported the actor so it is no longer above the ceiling. if (mo->Top() > mo->ceilingz) { + mo->BlockingCeiling = mo->Sector; mo->SetZ(mo->ceilingz - mo->Height); if (mo->BounceFlags & BOUNCE_Ceilings) { // ceiling bounce @@ -4505,12 +4516,21 @@ void AActor::Tick () } // Handle X and Y velocities - BlockingMobj = NULL; + BlockingMobj = nullptr; + sector_t* oldBlockingCeiling = BlockingCeiling; + sector_t* oldBlockingFloor = BlockingFloor; + BlockingFloor = nullptr; + BlockingCeiling = nullptr; double oldfloorz = P_XYMovement (this, cumm); if (ObjectFlags & OF_EuthanizeMe) { // actor was destroyed return; } + // [ZZ] trigger hit floor/hit ceiling actions from XY movement + if (BlockingFloor && BlockingFloor != oldBlockingFloor && (!player || !(player->cheats & CF_PREDICTING)) && BlockingFloor->SecActTarget) + BlockingFloor->TriggerSectorActions(this, SECSPAC_HitFloor); + if (BlockingCeiling && BlockingCeiling != oldBlockingCeiling && (!player || !(player->cheats & CF_PREDICTING)) && BlockingCeiling->SecActTarget) + BlockingCeiling->TriggerSectorActions(this, SECSPAC_HitCeiling); if (Vel.X == 0 && Vel.Y == 0) // Actors at rest { if (flags2 & MF2_BLASTED) @@ -4756,11 +4776,11 @@ void AActor::CheckSectorTransition(sector_t *oldsec) } if (Z() == floorz) { - P_CheckFor3DFloorHit(this, Z()); + P_CheckFor3DFloorHit(this, Z(), true); } if (Top() == ceilingz) { - P_CheckFor3DCeilingHit(this, Top()); + P_CheckFor3DCeilingHit(this, Top(), true); } } } diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 2ce2e7663..df284fc8c 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -183,6 +183,8 @@ class Actor : Thinker native native int DesignatedTeam; native Actor BlockingMobj; native Line BlockingLine; + native Sector BlockingCeiling; + native Sector BlockingFloor; native int PoisonDamage; native name PoisonDamageType; native int PoisonDuration;