diff --git a/src/am_map.cpp b/src/am_map.cpp index 46a2d5a84..81e45c685 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2224,6 +2224,154 @@ bool AM_Check3DFloors(line_t *line) return false; } +// [TP] Check whether a sector can trigger a special that satisfies the provided function. +// If found, specialptr and argsptr will be filled by the special and the arguments +// If needUseActivated is true, the special must be activated by use. +bool AM_checkSectorActions (sector_t *sector, bool (*function)(int, int *), int *specialptr, int **argsptr, bool needUseActivated) +{ + for (ASectorAction* action = sector->SecActTarget; action; action = barrier_cast(action->tracer)) + { + if ((action->IsActivatedByUse() || false == needUseActivated) + && (*function)(action->special, action->args) + && action->CanTrigger (players[consoleplayer].mo)) + { + *specialptr = action->special; + *argsptr = action->args; + return true; + } + } + + return false; +} + +// [TP] Check whether there's a boundary on the provided line for a special that satisfies the provided function. +// It's a boundary if the line can activate the special or the line's bordering sectors can activate it. +// If found, specialptr and argsptr will be filled with special and args if given. +bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int *), int *specialptr = NULL, int **argsptr = NULL) +{ + if (specialptr == NULL) + { + static int sink; + specialptr = &sink; + } + + if (argsptr == NULL) + { + static int *sink; + argsptr = &sink; + } + + // Check if the line special qualifies for this + if ((line.activation & SPAC_PlayerActivate) && (*function)(line.special, line.args)) + { + *specialptr = line.special; + *argsptr = line.args; + return true; + } + + // Check sector actions in the line's front sector -- the action has to be use-activated in order to + // show up if this is a one-sided line, because the player cannot trigger sector actions by crossing + // a one-sided line (since that's impossible, duh). + if (AM_checkSectorActions(line.frontsector, function, specialptr, argsptr, line.backsector == NULL)) + return true; + + // If it has a back sector, check sector actions in that. + return (line.backsector && AM_checkSectorActions(line.backsector, function, specialptr, argsptr, false)); +} + +bool AM_isTeleportSpecial (int special, int *) +{ + return (special == Teleport || + special == Teleport_NoFog || + special == Teleport_ZombieChanger || + special == Teleport_Line); +} + +bool AM_isTeleportBoundary (line_t &line) +{ + return AM_checkSpecialBoundary(line, &AM_isTeleportSpecial); +} + +bool AM_isExitSpecial (int special, int *) +{ + return (special == Teleport_NewMap || + special == Teleport_EndGame || + special == Exit_Normal || + special == Exit_Secret); +} + +bool AM_isExitBoundary (line_t& line) +{ + return AM_checkSpecialBoundary(line, &AM_isExitSpecial); +} + +bool AM_isTriggerSpecial (int special, int *) +{ + return LineSpecialsInfo[special] != NULL + && LineSpecialsInfo[special]->max_args >= 0 + && special != Door_Open + && special != Door_Close + && special != Door_CloseWaitOpen + && special != Door_Raise + && special != Door_Animated + && special != Generic_Door; +} + +bool AM_isTriggerBoundary (line_t &line) +{ + return AM_checkSpecialBoundary(line, &AM_isTriggerSpecial); +} + +bool AM_isLockSpecial (int special, int* args) +{ + return special == Door_LockedRaise + || special == ACS_LockedExecute + || special == ACS_LockedExecuteDoor + || (special == Door_Animated && args[3] != 0) + || (special == Generic_Door && args[4] != 0) + || (special == FS_Execute && args[2] != 0); +} + +bool AM_isLockBoundary (line_t &line, int *lockptr = NULL) +{ + if (lockptr == NULL) + { + static int sink; + lockptr = &sink; + } + + if (line.locknumber) + { + *lockptr = line.locknumber; + return true; + } + + int special; + int *args; + bool result = AM_checkSpecialBoundary(line, &AM_isLockSpecial, &special, &args); + + if (result) + { + switch (special) + { + case FS_Execute: + *lockptr = args[2]; + break; + + case Door_Animated: + case Door_LockedRaise: + *lockptr = args[3]; + break; + + default: + *lockptr = args[4]; + break; + } + } + + return result; +} + //============================================================================= // // Determines visible lines, draws them. @@ -2271,49 +2419,19 @@ void AM_drawWalls (bool allmap) AM_drawMline(&l, AMColors.SecretWallColor); else AM_drawMline(&l, AMColors.WallColor); - } - else if (lines[i].locknumber > 0 && AMColors.displayLocks) - { // [Dusk] specials w/ locknumbers - lock = lines[i].locknumber; - color = P_GetMapColorForLock(lock); - - AMColor c; - if (color >= 0) c.FromRGB(RPART(color), GPART(color), BPART(color)); - else c = AMColors[AMColors.LockedColor]; - - AM_drawMline (&l, c); - } - else if ((lines[i].special == Teleport || - lines[i].special == Teleport_NoFog || - lines[i].special == Teleport_ZombieChanger || - lines[i].special == Teleport_Line) && - (lines[i].activation & SPAC_PlayerActivate) && - AMColors.isValid(AMColors.IntraTeleportColor)) + } + else if (AM_isTeleportBoundary(lines[i]) && AMColors.isValid(AMColors.IntraTeleportColor)) { // intra-level teleporters AM_drawMline(&l, AMColors.IntraTeleportColor); } - else if ((lines[i].special == Teleport_NewMap || - lines[i].special == Teleport_EndGame || - lines[i].special == Exit_Normal || - lines[i].special == Exit_Secret) && - AMColors.isValid(AMColors.InterTeleportColor)) + else if (AM_isExitBoundary(lines[i]) && AMColors.isValid(AMColors.InterTeleportColor)) { // inter-level/game-ending teleporters AM_drawMline(&l, AMColors.InterTeleportColor); } - else if (lines[i].special == Door_LockedRaise || - lines[i].special == ACS_LockedExecute || - lines[i].special == ACS_LockedExecuteDoor || - (lines[i].special == Door_Animated && lines[i].args[3] != 0) || - (lines[i].special == Generic_Door && lines[i].args[4] != 0)) + else if (AM_isLockBoundary(lines[i], &lock)) { if (AMColors.displayLocks) { - int P_GetMapColorForLock(int lock); - - if (lines[i].special==Door_LockedRaise || lines[i].special==Door_Animated) - lock=lines[i].args[3]; - else lock=lines[i].args[4]; - color = P_GetMapColorForLock(lock); AMColor c; @@ -2328,16 +2446,9 @@ void AM_drawWalls (bool allmap) AM_drawMline (&l, AMColors.LockedColor); // locked special } } - else if (am_showtriggerlines && AMColors.isValid(AMColors.SpecialWallColor) - && LineSpecialsInfo[lines[i].special] != NULL - && LineSpecialsInfo[lines[i].special]->max_args >= 0 - && lines[i].special != Door_Open - && lines[i].special != Door_Close - && lines[i].special != Door_CloseWaitOpen - && lines[i].special != Door_Raise - && lines[i].special != Door_Animated - && lines[i].special != Generic_Door - && (lines[i].activation & SPAC_PlayerActivate)) + else if (am_showtriggerlines + && AMColors.isValid(AMColors.SpecialWallColor) + && AM_isTriggerBoundary(lines[i])) { AM_drawMline(&l, AMColors.SpecialWallColor); // wall with special non-door action the player can do } diff --git a/src/g_shared/a_sectoraction.cpp b/src/g_shared/a_sectoraction.cpp index 570818e19..bb582dd28 100644 --- a/src/g_shared/a_sectoraction.cpp +++ b/src/g_shared/a_sectoraction.cpp @@ -39,6 +39,14 @@ IMPLEMENT_CLASS (ASectorAction) +ASectorAction::ASectorAction (bool activatedByUse) : + ActivatedByUse (activatedByUse) {} + +bool ASectorAction::IsActivatedByUse() const +{ + return ActivatedByUse; +} + void ASectorAction::Destroy () { // Remove ourself from this sector's list of actions @@ -102,12 +110,17 @@ bool ASectorAction::DoTriggerAction (AActor *triggerer, int activationType) return false; } +bool ASectorAction::CanTrigger (AActor *triggerer) const +{ + return special && + ((triggerer->player && !(flags & MF_FRIENDLY)) || + ((flags & MF_AMBUSH) && (triggerer->flags2 & MF2_MCROSS)) || + ((flags2 & MF2_DORMANT) && (triggerer->flags2 & MF2_PCROSS))); +} + bool ASectorAction::CheckTrigger (AActor *triggerer) const { - if (special && - ((triggerer->player && !(flags & MF_FRIENDLY)) || - ((flags & MF_AMBUSH) && (triggerer->flags2 & MF2_MCROSS)) || - ((flags2 & MF2_DORMANT) && (triggerer->flags2 & MF2_PCROSS)))) + if (CanTrigger(triggerer)) { bool res = !!P_ExecuteSpecial(special, NULL, triggerer, false, args[0], args[1], args[2], args[3], args[4]); @@ -196,6 +209,7 @@ class ASecActUse : public ASectorAction { DECLARE_CLASS (ASecActUse, ASectorAction) public: + ASecActUse() : ASectorAction (true) {} bool DoTriggerAction (AActor *triggerer, int activationType); }; @@ -214,6 +228,7 @@ class ASecActUseWall : public ASectorAction { DECLARE_CLASS (ASecActUseWall, ASectorAction) public: + ASecActUseWall() : ASectorAction (true) {} bool DoTriggerAction (AActor *triggerer, int activationType); }; diff --git a/src/r_defs.h b/src/r_defs.h index a93622b41..b741b5f6b 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -194,14 +194,19 @@ class ASectorAction : public AActor { DECLARE_CLASS (ASectorAction, AActor) public: + ASectorAction (bool activatedByUse = false); void Destroy (); void BeginPlay (); void Activate (AActor *source); void Deactivate (AActor *source); bool TriggerAction(AActor *triggerer, int activationType); + bool CanTrigger (AActor *triggerer) const; + bool IsActivatedByUse() const; protected: virtual bool DoTriggerAction(AActor *triggerer, int activationType); bool CheckTrigger(AActor *triggerer) const; +private: + bool ActivatedByUse; }; class ASkyViewpoint;