diff --git a/Data/Config/Regions.xml b/Data/Config/Regions.xml
index d8c6d07..d91cfb0 100644
--- a/Data/Config/Regions.xml
+++ b/Data/Config/Regions.xml
@@ -158,7 +158,7 @@
-
+
diff --git a/Data/Spawns/chests.map b/Data/Spawns/chests.map
index a8c9b56..75f3279 100644
--- a/Data/Spawns/chests.map
+++ b/Data/Spawns/chests.map
@@ -162,3 +162,21 @@
*|treasurechestlevel1||||||3523|90|30|1|5|10|-1|4|1|1|0|0|0|0|0
*|treasurechestlevel1||||||3528|124|10|1|5|10|-1|4|1|1|0|0|0|0|0
# Level 2
+*|treasurechestlevel3||||||3642|135|0|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel2||||||3659|140|0|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel2||||||3671|165|-5|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel2||||||3741|88|4|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel2||||||3737|161|1|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel3||||||3692|163|3|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel2||||||3683|106|0|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel3||||||3667|158|3|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel2||||||3649|120|0|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel2||||||3642|94|0|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel2||||||3740|70|10|1|5|10|-1|4|1|1|0|0|0|0|0
+*|treasurechestlevel2||||||3726|76|10|1|5|10|-1|4|1|1|0|0|0|0|0
+*|treasurechestlevel1:treasurechestlevel2|treasurechestlevel2:treasurechestlevel3|||||3728|56|9|1|5|10|-1|2|1|1|1|0|0|0|0
+*|treasurechestlevel2||||||3694|114|0|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel2||||||42|114|0|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel2||||||3643|93|0|1|5|10|-1|0|1|1|0|0|0|0|0
+*|treasurechestlevel2||||||3640|108|1|1|5|10|-1|0|1|1|0|0|0|0|0
+# Level 3
diff --git a/Data/Spawns/dungeons.map b/Data/Spawns/dungeons.map
index c1f4ebd..76e202a 100644
--- a/Data/Spawns/dungeons.map
+++ b/Data/Spawns/dungeons.map
@@ -289,3 +289,35 @@
*|harpy||||||3528|107|-20|1|5|10|-1|4|1|1|0|0|0|0|0
*|harpy||||||3522|106|-20|1|5|10|-1|4|1|1|0|0|0|0|0
# Level 2
+*|seaserpent||||||3637|85|-5|1|5|10|-1|6|1|1|0|0|0|0|0
+*|troll:earthelemental||||||3694|64|0|1|5|10|-1|8|1|2|0|0|0|0|0
+*|troll:earthelemental:dullcopperelemental:shadowIronElemental||||||3705|100|0|1|5|10|-1|8|1|2|0|0|0|0|0
+*|waterelemental||||||3687|112|0|1|5|10|-1|4|1|1|0|0|0|0|0
+*|waterelemental||||||3654|119|0|1|5|10|-1|4|1|1|0|0|0|0|0
+*|troll:earthelemental:dullcopperelemental:shadowIronElemental||||||3670|108|0|1|5|10|-1|8|1|1|0|0|0|0|0
+*|airelemental:earthelemental:dullcopperelemental:shadowIronElemental||||||119|81|0|1|5|10|-1|8|1|2|0|0|0|0|0
+*|troll:earthelemental||||||3709|76|0|1|5|10|-1|8|1|2|0|0|0|0|0
+*|earthelemental||||||3728|58|9|1|5|10|-1|4|1|1|0|0|0|0|0
+*|earthelemental||||||3726|74|10|1|5|10|-1|4|1|1|0|0|0|0|0
+*|gazerlarva||||||3728|65|10|1|5|10|-1|4|1|1|0|0|0|0|0
+*|dullcopperelemental||||||3740|69|10|1|5|10|-1|4|1|1|0|0|0|0|0
+*|troll:earthelemental||||||3690|82|0|1|5|10|-1|8|1|2|0|0|0|0|0
+*|troll:earthelemental||||||3669|74|0|1|5|10|-1|8|1|1|0|0|0|0|0
+*|waterelemental||||||3645|93|0|1|5|10|-1|4|1|1|0|0|0|0|0
+*|earthelemental||||||3662|88|0|1|5|10|-1|4|1|1|0|0|0|0|0
+*|troll||||||3645|104|0|1|5|10|-1|4|1|1|0|0|0|0|0
+*|troll:earthelemental:dullcopperelemental:shadowIronElemental||||||3714|113|0|1|5|10|-1|8|1|1|0|0|0|0|0
+*|airelemental:waterelemental||||||3738|90|0|1|5|10|-1|4|1|1|0|0|0|0|0
+*|kraken||||||3716|127|-5|1|5|10|-1|4|1|1|0|0|0|0|0
+*|airelemental||||||3739|136|2|1|5|10|-1|4|1|1|0|0|0|0|0
+*|airelemental:earthelemental:dullcopperelemental:shadowIronElemental||||||3740|163|0|1|5|10|-1|8|1|2|0|0|0|0|0
+*|airelemental:earthelemental:dullcopperelemental:shadowIronElemental||||||3720|163|0|1|5|10|-1|8|1|2|0|0|0|0|0
+*|waterelemental||||||3715|135|0|1|5|10|-1|4|1|1|0|0|0|0|0
+*|fireelemental||||||3691|162|3|1|5|10|-1|4|1|1|0|0|0|0|0
+*|airelemental:earthelemental:dullcopperelemental:shadowIronElemental||||||3682|147|3|1|5|10|-1|8|1|2|0|0|0|0|0
+*|waterelemental||||||3677|130|0|1|5|10|-1|4|1|1|0|0|0|0|0
+*|waterelemental||||||3655|136|0|1|5|10|-1|4|1|1|0|0|0|0|0
+*|seaserpent||||||3663|126|-5|1|5|10|-1|4|1|1|0|0|0|0|0
+*|airelemental:earthelemental:dullcopperelemental:shadowIronElemental||||||3643|152|0|1|5|10|-1|8|1|2|0|0|0|0|0
+*|fireelemental||||||3666|162|2|1|5|10|-1|4|1|1|0|0|0|0|0
+# Level 3
diff --git a/Data/Spawns/traps.map b/Data/Spawns/traps.map
index ab45461..1b217d8 100644
--- a/Data/Spawns/traps.map
+++ b/Data/Spawns/traps.map
@@ -326,3 +326,36 @@
*|mushroomtrap||||||3614|66|-30|1|1|1|-1|8|1|2|0|0|0|0|0
*|mushroomtrap||||||3518|158|0|1|1|1|-1|8|1|2|0|0|0|0|0
# Level 2
+*|mushroomtrap||||||3708|146|2|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3715|162|1|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3740|163|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3740|150|1|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3740|133|2|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3725|94|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3715|112|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3703|1|0|1|1|1|-1|8|99|2|0|0|0|0|0
+*|mushroomtrap||||||3685|113|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3676|109|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3666|111|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3647|94|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3662|88|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3686|83|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3706|83|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3737|66|10|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3726|72|10|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3708|69|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3698|66|1|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3671|70|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3686|60|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||49|68|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3640|63|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3717|138|1|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3668|163|1|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3664|161|3|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3644|152|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3655|139|0|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3677|133|1|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3683|152|3|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3691|162|3|1|1|1|-1|8|1|2|0|0|0|0|0
+*|mushroomtrap||||||3728|62|9|1|1|1|-1|8|1|2|0|0|0|0|0
+# Level 3
diff --git a/Scripts/Engines/DungeonTraps.cs b/Scripts/Engines/DungeonTraps.cs
new file mode 100644
index 0000000..ad85e5e
--- /dev/null
+++ b/Scripts/Engines/DungeonTraps.cs
@@ -0,0 +1,301 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.Mobiles;
+using Server.Items;
+
+namespace Server.Regions
+{
+ public static class CustomDungeonTraps
+ {
+ private static Dictionary m_KarmaTimers = new Dictionary();
+
+ public static bool SavingThrow(PlayerMobile pm, string saveType)
+ {
+ int saveThrow = 0;
+ string area = "";
+
+ if (saveType == "Magic")
+ {
+ area = "magical resistance";
+ saveThrow = (int)((pm.Int + pm.Skills[SkillName.MagicResist].Value + pm.EnergyResistance) / 4);
+ }
+ else if (saveType == "Physical")
+ {
+ area = "physical endurance";
+ saveThrow = (int)((pm.Str + pm.PhysicalResistance) / 3);
+ }
+ else if (saveType == "Agility")
+ {
+ area = "quick reflexes";
+ saveThrow = pm.Dex;
+ }
+ else if (saveType == "Poison")
+ {
+ area = "poison resistance";
+ saveThrow = (int)((pm.Str + pm.Skills[SkillName.Poisoning].Value + pm.PoisonResistance) / 4);
+ }
+
+ // Cap the maximum possible save chance at 60%
+ if (saveThrow > 60)
+ {
+ saveThrow = 60;
+ }
+
+ // If their save score is higher than a random 1-100 roll, they succeed!
+ if (saveThrow >= Utility.RandomMinMax(1, 100))
+ {
+ pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 0x3B2, false, "You triggered a trap, but with your " + area + "...you avoid the brunt of it.");
+ pm.PlaySound(pm.Female ? 778 : 1049);
+ return true;
+ }
+
+ return false;
+ }
+
+ public static void TriggerRandomTrap(PlayerMobile pm)
+ {
+ // Increase this number as you add more cases below!
+ int roll = Utility.Random(6);
+
+ switch (roll)
+ {
+ case 0: ApplyPotionBreakTrap(pm); break;
+ case 1: ApplySpikeTrap(pm); break;
+ case 2: ApplyGasTrap(pm); break;
+ case 3: ApplyTripWireTrap(pm); break;
+ case 4: ApplyTransmutationTrap(pm); break;
+ case 5: ApplyKarmaTrap(pm); break;
+ }
+ }
+
+ public static void ApplyPotionBreakTrap(PlayerMobile pm)
+ {
+ if (SavingThrow(pm, "Agility"))
+ return;
+
+ pm.PlaySound(0x38D);
+
+ if (pm.Backpack != null)
+ {
+ List potions = pm.Backpack.FindItemsByType();
+
+ if (potions.Count > 0)
+ {
+ BasePotion targetPotion = potions[Utility.Random(potions.Count)];
+ targetPotion.Consume(1);
+
+ pm.FixedParticles(0x374A, 10, 15, 5021, EffectLayer.Waist);
+ pm.SendMessage(33, "A concealed tripwire snaps! A flask in your backpack breaks!");
+ return;
+ }
+ }
+
+ pm.Damage(Utility.RandomMinMax(10, 20));
+ pm.SendMessage(33, "You trip over a hidden wire and take a nasty spill!");
+ }
+
+ public static void ApplySpikeTrap(PlayerMobile pm)
+ {
+ if (SavingThrow(pm, "Physical"))
+ return;
+ pm.PlaySound(0x22C);
+ pm.FixedParticles(0x3728, 10, 10, 5021, EffectLayer.Waist);
+ pm.Damage(Utility.RandomMinMax(15, 30));
+ pm.SendMessage(33, "Spikes spring from the floor!");
+ }
+
+ public static void ApplyGasTrap(PlayerMobile pm)
+ {
+ if (SavingThrow(pm, "Poison"))
+ return;
+ pm.PlaySound(0x231);
+ pm.FixedParticles(0x3709, 10, 30, 5052, EffectLayer.Waist);
+ pm.ApplyPoison(pm, Poison.Regular);
+ pm.SendMessage(33, "You trigger a noxious gas vent!");
+ }
+ public static void ApplyTripWireTrap(PlayerMobile pm)
+ {
+ if (SavingThrow(pm, "Agility"))
+ return;
+
+ pm.PlaySound(pm.Female ? 812 : 1086);
+
+ Item dropped = GetRandomEquippedItem(pm);
+
+ if (dropped != null && dropped.LootType != LootType.Blessed)
+ {
+ // Drops it right at their feet
+ dropped.MoveToWorld(pm.Location, pm.Map);
+ pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 33, true, "You tripped over a wire and dropped one of your equipped items!");
+ }
+ else
+ {
+ // Fallback if they are completely naked or only have blessed gear
+ pm.Damage(Utility.RandomMinMax(5, 10));
+ pm.SendMessage(33, "You trip over a hidden wire and take a nasty spill!");
+ }
+ }
+
+ private static Item GetRandomEquippedItem(PlayerMobile pm)
+ {
+ List- wornItems = new List
- ();
+
+ Layer[] validLayers = { Layer.OneHanded, Layer.TwoHanded, Layer.Helm, Layer.Neck, Layer.Arms, Layer.Gloves, Layer.Ring, Layer.Bracelet, Layer.Shoes };
+
+ foreach (Layer layer in validLayers)
+ {
+ Item item = pm.FindItemOnLayer(layer);
+
+ if (item != null && item.LootType != LootType.Blessed)
+ {
+ wornItems.Add(item);
+ }
+ }
+
+ if (wornItems.Count == 0)
+ {
+ return null;
+ }
+ return wornItems[Utility.Random(wornItems.Count)];
+ }
+
+ public static void ApplyTransmutationTrap(PlayerMobile pm)
+ {
+ if (SavingThrow(pm, "Magic"))
+ return;
+
+ if (pm.Backpack != null)
+ {
+ int goldAmount = pm.Backpack.GetAmount(typeof(Gold));
+
+ if (goldAmount > 0)
+ {
+ // Calculate a 10% to 25% tax on their gold
+ int goldToDestroy = (int)(goldAmount * Utility.RandomMinMax(10, 25) / 100.0);
+
+ if (goldToDestroy > 0 && pm.Backpack.ConsumeTotal(typeof(Gold), goldToDestroy))
+ {
+ pm.PlaySound(0x1E1);
+ pm.FixedParticles(0x374A, 10, 15, 5028, EffectLayer.Waist);
+ pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 33, true, "A magical trap triggers, turning a chunk of your gold into useless dust!");
+ return;
+ }
+ }
+ }
+
+ // Fallback if they have zero gold
+ pm.PlaySound(0x1DF);
+ pm.Mana -= 20;
+ pm.SendMessage(33, "A magical trap drains your mana!");
+ }
+
+ public static void ApplyKarmaTrap(PlayerMobile pm)
+ {
+ if (SavingThrow(pm, "Magic"))
+ return;
+
+ if (pm.Karma == 0)
+ {
+ pm.PlaySound(0x1DF);
+ pm.Mana -= 20;
+ pm.SendMessage(33, "A dark energy washes over you, draining your mana!");
+ return;
+ }
+
+ KarmaCurseToken token = pm.Backpack.FindItemByType();
+
+ if (token == null)
+ {
+ pm.Karma *= -1;
+ pm.PlaySound(0x1E1);
+ pm.FixedParticles(0x374A, 10, 15, 5028, EffectLayer.Waist);
+ pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 33, true, "A mind-warping trap triggers, completely inverting your morality!");
+
+ token = new KarmaCurseToken(pm, TimeSpan.FromMinutes(3));
+ pm.Backpack.DropItem(token);
+ }
+ else
+ {
+ token.ExtendCurse(TimeSpan.FromMinutes(5));
+ pm.SendMessage(33, "The mind-warping curse intensifies, extending its duration!");
+ }
+ }
+ }
+ public class KarmaCurseToken : Item
+ {
+ private Mobile m_Owner;
+ private DateTime m_Expires;
+ private Timer m_Timer;
+
+ public KarmaCurseToken(Mobile owner, TimeSpan duration) : base(0x1EA7)
+ {
+ Movable = false;
+ Visible = false;
+ Weight = 0.0;
+ m_Owner = owner;
+ m_Expires = DateTime.UtcNow + duration;
+
+ StartTimer();
+ }
+
+ public KarmaCurseToken(Serial serial) : base(serial)
+ {
+ }
+
+ private void StartTimer()
+ {
+ if (m_Timer != null)
+ m_Timer.Stop();
+
+ TimeSpan delay = m_Expires - DateTime.UtcNow;
+
+ if (delay <= TimeSpan.Zero)
+ {
+ RemoveCurse();
+ }
+ else
+ {
+ m_Timer = Timer.DelayCall(delay, RemoveCurse);
+ }
+ }
+
+ public void ExtendCurse(TimeSpan duration)
+ {
+ m_Expires = DateTime.UtcNow + duration;
+ StartTimer();
+ }
+
+ private void RemoveCurse()
+ {
+ if (m_Owner != null && !m_Owner.Deleted)
+ {
+ m_Owner.Karma *= -1;
+ m_Owner.SendMessage(0x3B2, "The morality-warping curse fades, and your true nature returns.");
+ }
+
+ if (m_Timer != null)
+ m_Timer.Stop();
+
+ Delete();
+ }
+
+ public override void Serialize(GenericWriter writer)
+ {
+ base.Serialize(writer);
+ writer.Write((int)0);
+ writer.Write(m_Owner);
+ writer.Write(m_Expires);
+ }
+
+ public override void Deserialize(GenericReader reader)
+ {
+ base.Deserialize(reader);
+ int version = reader.ReadInt();
+ m_Owner = reader.ReadMobile();
+ m_Expires = reader.ReadDateTime();
+
+ StartTimer();
+ }
+ }
+}
diff --git a/Scripts/Regions/DungeonTrapRegion.cs b/Scripts/Regions/DungeonTrapRegion.cs
new file mode 100644
index 0000000..e6ce63e
--- /dev/null
+++ b/Scripts/Regions/DungeonTrapRegion.cs
@@ -0,0 +1,66 @@
+using System;
+using Server;
+using Server.Mobiles;
+using System.Xml;
+
+namespace Server.Regions
+{
+ public class DungeonTrapRegion : DungeonRegion
+ {
+ public DungeonTrapRegion(XmlElement xml, Map map, Region parent) : base(xml, map, parent)
+ {
+ }
+
+ public override void OnLocationChanged(Mobile m, Point3D oldLocation)
+ {
+ base.OnLocationChanged(m, oldLocation);
+
+ if (m is PlayerMobile pm && pm.Alive && pm.AccessLevel == AccessLevel.Player && m.Location != oldLocation)
+ {
+ // We are using 2% (0.02) base chance per step.
+ if (Utility.RandomDouble() < 0.02)
+ {
+ EvaluateTrapSequence(pm);
+ }
+ }
+ }
+
+ private void EvaluateTrapSequence(PlayerMobile pm)
+ {
+ // --- TIER 1: PASSIVE SEARCHING (Detect Hidden) ---
+ if (pm.Skills[SkillName.DetectHidden].Value >= 5.0)
+ {
+ if (pm.CheckSkill(SkillName.DetectHidden, 0.0, 125.0))
+ {
+ pm.PlaySound(pm.Female ? 778 : 1049); // Plays a female/male gasp or sigh
+ //pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 0x3B2, false, "You notice a hidden floor mechanism and carefully step around it.");
+ return;
+ }
+ }
+
+ // --- TIER 2: TRAP AVOIDANCE (Remove Trap) ---
+ if (pm.Skills[SkillName.RemoveTrap].Value >= 5.0)
+ {
+ if (pm.CheckSkill(SkillName.RemoveTrap, 0.0, 125.0))
+ {
+ pm.PlaySound(0x241);
+ //pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 0x3B2, false, "Your experience with traps allows you to safely bypass a hidden trigger.");
+ return;
+ }
+ }
+
+ // --- TIER 3: LUCK ---
+ // A simple scale: 1000 Luck = 10% chance to avoid. 2000 Luck = 20% chance.
+ double luckChance = pm.Luck / 10000.0;
+ if (Utility.RandomDouble() < luckChance)
+ {
+ pm.PlaySound(0x241);
+ //pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 0x3B2, false, "With luck on your side, the trap mechanism fails to trigger.");
+ return;
+ }
+
+ // If they failed all three avoidance checks the trap is sprung.
+ CustomDungeonTraps.TriggerRandomTrap(pm);
+ }
+ }
+}
diff --git a/Scripts/Settings.cs b/Scripts/Settings.cs
index 126eadf..3bc6659 100644
--- a/Scripts/Settings.cs
+++ b/Scripts/Settings.cs
@@ -19,7 +19,7 @@ namespace Server
public static int S_MaxGold = 1000; // maximum is 10,000
public static bool S_CanStealWhileHoldingThings = true;
public static bool S_MonstersSurprise = true;
- public static bool S_DungeonTraps = true;
+ public static bool S_DungeonTraps = false;
public static double S_FarmSpawnTimer = 15.0;
public static int S_HarvestRange = 1;
}