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(); } } }