class SectorAction : Actor { // self class uses health to define the activation type. enum EActivation { SECSPAC_Enter = 1<< 0, SECSPAC_Exit = 1<< 1, SECSPAC_HitFloor = 1<< 2, SECSPAC_HitCeiling = 1<< 3, SECSPAC_Use = 1<< 4, SECSPAC_UseWall = 1<< 5, SECSPAC_EyesDive = 1<< 6, SECSPAC_EyesSurface = 1<< 7, SECSPAC_EyesBelowC = 1<< 8, SECSPAC_EyesAboveC = 1<< 9, SECSPAC_HitFakeFloor = 1<<10, SECSPAC_DamageFloor = 1<<11, SECSPAC_DamageCeiling = 1<<12, SECSPAC_DeathFloor = 1<<13, SECSPAC_DeathCeiling = 1<<14, SECSPAC_Damage3D = 1<<15, SECSPAC_Death3D = 1<<16 }; default { +NOBLOCKMAP +NOSECTOR +NOGRAVITY +DONTSPLASH } override void OnDestroy () { if (CurSector != null) { // Remove ourself from self CurSector's list of actions if (CurSector.SecActTarget == self) { CurSector.SecActTarget = SectorAction(tracer); } else { Actor probe = CurSector.SecActTarget; if (null != probe) { while (probe.tracer != self && probe.tracer != null) { probe = probe.tracer; } if (probe.tracer == self) { probe.tracer = tracer; } } } } Super.OnDestroy(); } override void BeginPlay () { Super.BeginPlay (); // Add ourself to self CurSector's list of actions tracer = CurSector.SecActTarget; CurSector.SecActTarget = self; } override void Activate (Actor source) { bDormant = false; // Projectiles cannot trigger } override void Deactivate (Actor source) { bDormant = true; // Projectiles can trigger } virtual bool TriggerAction (Actor triggerer, int activationType) { if ((activationType & health) && CanTrigger(triggerer)) { return triggerer.A_CallSpecial(special, args[0], args[1], args[2], args[3], args[4]); } return false; } virtual bool CanTrigger (Actor triggerer) { return special && ((triggerer.player && !bFriendly) || (bAmbush && triggerer.bActivateMCross) || (bDormant && triggerer.bActivatePCross)); } } // Triggered when entering CurSector ------------------------------------------- class SecActEnter : SectorAction { Default { Health SECSPAC_Enter; } } // Triggered when leaving CurSector -------------------------------------------- class SecActExit : SectorAction { Default { Health SECSPAC_Exit; } } // Triggered when hitting CurSector's floor ------------------------------------ class SecActHitFloor : SectorAction { Default { Health SECSPAC_HitFloor; } } // Triggered when hitting CurSector's ceiling ---------------------------------- class SecActHitCeil : SectorAction { Default { Health SECSPAC_HitCeiling; } } // Triggered when using inside CurSector --------------------------------------- class SecActUse : SectorAction { Default { Health SECSPAC_Use; } } // Triggered when using a CurSector's wall ------------------------------------- class SecActUseWall : SectorAction { Default { Health SECSPAC_UseWall; } } // Triggered when eyes go below fake floor ---------------------------------- class SecActEyesDive : SectorAction { Default { Health SECSPAC_EyesDive; } } // Triggered when eyes go above fake floor ---------------------------------- class SecActEyesSurface : SectorAction { Default { Health SECSPAC_EyesSurface; } } // Triggered when eyes go below fake ceiling ---------------------------------- class SecActEyesBelowC : SectorAction { Default { Health SECSPAC_EyesBelowC; } } // Triggered when eyes go above fake ceiling ---------------------------------- class SecActEyesAboveC : SectorAction { Default { Health SECSPAC_EyesAboveC; } } // Triggered when hitting fake floor ---------------------------------- class SecActHitFakeFloor : SectorAction { Default { Health SECSPAC_HitFakeFloor; } } // Triggered when sector's floor is damaged ---------------------------------- class SecActDamageFloor : SectorAction { Default { Health SECSPAC_DamageFloor; } // [ZZ] damage is unconditional, so this as well override bool CanTrigger (Actor triggerer) { return !!special; } } // Triggered when sector's ceiling is damaged ---------------------------------- class SecActDamageCeiling : SectorAction { Default { Health SECSPAC_DamageCeiling; } // [ZZ] damage is unconditional, so this as well override bool CanTrigger (Actor triggerer) { return !!special; } } // Triggered when sector's floor is reduced to 0 hp ---------------------------------- class SecActDeathFloor : SectorAction { Default { Health SECSPAC_DeathFloor; } // [ZZ] damage is unconditional, so this as well override bool CanTrigger (Actor triggerer) { return !!special; } } // Triggered when sector's ceiling is reduced to 0 hp ---------------------------------- class SecActDeathCeiling : SectorAction { Default { Health SECSPAC_DeathCeiling; } // [ZZ] damage is unconditional, so this as well override bool CanTrigger (Actor triggerer) { return !!special; } } // Triggered when controlled 3d floor is damaged ---------------------------------- class SecActDamage3D : SectorAction { Default { Health SECSPAC_Damage3D; } // [ZZ] damage is unconditional, so this as well override bool CanTrigger (Actor triggerer) { return !!special; } } // Triggered when controlled 3d floor is reduced to 0 hp ---------------------------------- class SecActDeath3D : SectorAction { Default { Health SECSPAC_Death3D; } // [ZZ] damage is unconditional, so this as well override bool CanTrigger (Actor triggerer) { return !!special; } } //========================================================================== // // Music changer. Uses the sector action class to do its job // //========================================================================== class MusicChanger : SectorAction { override bool TriggerAction (Actor triggerer, int activationType) { if (activationType & SECSPAC_Enter && triggerer.player != null) { if (triggerer.player.MUSINFOactor != self) { triggerer.player.MUSINFOactor = self; triggerer.player.MUSINFOtics = 30; } } return false; } override void PostBeginPlay() { // The music changer should consider itself activated if the player // spawns in its sector as well as if it enters the sector during a P_TryMove. Super.PostBeginPlay(); for (int i = 0; i < MAXPLAYERS; ++i) { if (playeringame[i] && players[i].mo && players[i].mo.CurSector == self.CurSector) { TriggerAction(players[i].mo, SECSPAC_Enter); } } } }