using System; using System.Collections.Generic; using Server; using Server.Mobiles; using Server.Engines.DungeonTraps; namespace Server.Regions { public class GreetingDungeonRegion : NoTravelSpellsAllowedRegion { // 1. Initialize the pool of available traps private static readonly BaseRegionTrap[] _dungeonTraps = [ new TripwireTrap(), new ExplosionTrap(), new FlameTrap(), new GasTrap() ]; // 2. Track how many safe steps a player has remaining to prevent trap spam private readonly Dictionary _safeSteps = new(); public GreetingDungeonRegion(string name, Map map, int priority, params Rectangle3D[] area) : base(name, map, priority, area) { } public override bool MountsAllowed => false; public override void OnEnter(Mobile m) { base.OnEnter(m); if (m.Player) { m.SendMessage($"You entered {this.Name}."); // Give players a 10-step grace period right at the entrance _safeSteps[m] = 10; } if (m is PlayerMobile player && player.Mounted) { if (player.Mount is BaseMount) { Server.Custom.AutoStable.StoreMount(player); } else { BaseMount.Dismount(player); player.SendMessage("Mounts are not permitted in this Dungeon."); } } } public override void OnExit(Mobile m) { base.OnExit(m); if (m is PlayerMobile player) { Server.Custom.AutoStable.RestoreMount(player); // Clean up the dictionary when they leave to free up memory _safeSteps.Remove(player); } } // 3. Evaluate every step taken inside the region public override void OnLocationChanged(Mobile m, Point3D oldLocation) { base.OnLocationChanged(m, oldLocation); if (!Settings.S_RegionDungeonTraps) { return; } // Only check for traps if they are an alive player who actually moved to a new tile if (m is PlayerMobile pm && pm.Alive && pm.Location != oldLocation && pm.AccessLevel == AccessLevel.Player) { CheckForTraps(pm); } } private void CheckForTraps(PlayerMobile pm) { // 4. Handle Safe Steps Cooldown if (!_safeSteps.TryGetValue(pm, out int safeStepsLeft)) { safeStepsLeft = 0; } if (safeStepsLeft > 0) { _safeSteps[pm] = safeStepsLeft - 1; return; // Player is still in their grace period } double baseChance = ValidSettings.RegionDungeonTrapsChance(); // 6. Roll for Trap Trigger if (Utility.RandomDouble() * 100.0 <= baseChance) { // Pick a random trap from the pool BaseRegionTrap trap = _dungeonTraps[Utility.Random(_dungeonTraps.Length)]; // Fire the trap logic cascade (Remove Trap -> Dodge -> AR/MR -> Damage) trap.Trigger(pm); // Reset the player's safe steps to prevent back-to-back trap triggers _safeSteps[pm] = Utility.RandomMinMax(8, 12); } } } }