#W# Rework: Complete rework of ThiefPedestals.
This commit is contained in:
parent
a440cb72d1
commit
bc3c5143b9
4 changed files with 443 additions and 221 deletions
|
|
@ -8,35 +8,12 @@ using Server.Network;
|
||||||
namespace Server.Custom
|
namespace Server.Custom
|
||||||
{
|
{
|
||||||
[SerializationGenerator(0)]
|
[SerializationGenerator(0)]
|
||||||
public partial class ThiefPedestal1 : ThiefPedestal { [Constructible] public ThiefPedestal1() : base(1) { } public ThiefPedestal1(Serial serial) : base(serial) { } }
|
public partial class ThiefPedestalProp : Item
|
||||||
|
|
||||||
[SerializationGenerator(0)]
|
|
||||||
public partial class ThiefPedestal2 : ThiefPedestal { [Constructible] public ThiefPedestal2() : base(2) { } public ThiefPedestal2(Serial serial) : base(serial) { } }
|
|
||||||
|
|
||||||
[SerializationGenerator(0)]
|
|
||||||
public partial class ThiefPedestal3 : ThiefPedestal { [Constructible] public ThiefPedestal3() : base(3) { } public ThiefPedestal3(Serial serial) : base(serial) { } }
|
|
||||||
|
|
||||||
[SerializationGenerator(0)]
|
|
||||||
public partial class ThiefPedestal4 : ThiefPedestal { [Constructible] public ThiefPedestal4() : base(4) { } public ThiefPedestal4(Serial serial) : base(serial) { } }
|
|
||||||
|
|
||||||
[SerializationGenerator(0)]
|
|
||||||
public partial class ThiefPedestal5 : ThiefPedestal { [Constructible] public ThiefPedestal5() : base(5) { } public ThiefPedestal5(Serial serial) : base(serial) { } }
|
|
||||||
|
|
||||||
[SerializationGenerator(0)]
|
|
||||||
public partial class ThiefPedestal6 : ThiefPedestal { [Constructible] public ThiefPedestal6() : base(6) { } public ThiefPedestal6(Serial serial) : base(serial) { } }
|
|
||||||
// ==========================================
|
|
||||||
// 1. THE CUSTOM BAG
|
|
||||||
// ==========================================
|
|
||||||
[SerializationGenerator(0)]
|
|
||||||
public partial class ThiefPedestalBag : Bag
|
|
||||||
{
|
{
|
||||||
// Links this bag to the pedestal that spawned it
|
|
||||||
[SerializableField(0)]
|
[SerializableField(0)]
|
||||||
private ThiefPedestal m_Pedestal;
|
private ThiefPedestal m_Pedestal;
|
||||||
|
|
||||||
private Timer m_DecayTimer;
|
public ThiefPedestalProp(ThiefPedestal pedestal) : base(0xE76)
|
||||||
|
|
||||||
public ThiefPedestalBag(ThiefPedestal pedestal)
|
|
||||||
{
|
{
|
||||||
m_Pedestal = pedestal;
|
m_Pedestal = pedestal;
|
||||||
Hue = 0x8A5;
|
Hue = 0x8A5;
|
||||||
|
|
@ -44,99 +21,53 @@ namespace Server.Custom
|
||||||
Movable = false;
|
Movable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the player successfully heists the entire bag
|
public override void OnDoubleClick(Mobile from)
|
||||||
public void ClearTether()
|
|
||||||
{
|
{
|
||||||
m_Pedestal = null;
|
if (m_Pedestal != null && !m_Pedestal.Deleted)
|
||||||
m_DecayTimer?.Stop();
|
|
||||||
m_DecayTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Triggers every time an item is removed from the bag
|
|
||||||
public override void OnItemRemoved(Item item)
|
|
||||||
{
|
|
||||||
base.OnItemRemoved(item); // Match the new single-parameter signature
|
|
||||||
|
|
||||||
// If the bag was already successfully stolen, act like a normal bag
|
|
||||||
if (m_Pedestal == null) return;
|
|
||||||
|
|
||||||
// Attempt to find the thief (if it went into their backpack, they are the RootParent)
|
|
||||||
Mobile from = item.RootParent as Mobile;
|
|
||||||
|
|
||||||
if (Items.Count == 0)
|
|
||||||
{
|
{
|
||||||
// Mechanic 1: The bag is empty. Destroy it immediately.
|
m_Pedestal.OnDoubleClick(from);
|
||||||
if (from != null)
|
|
||||||
{
|
|
||||||
from.SendMessage(89, "As you take the last item, the bag crumbles to dust!");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Pedestal.SinkAndDestroy();
|
|
||||||
Delete();
|
|
||||||
}
|
|
||||||
else if (m_DecayTimer == null)
|
|
||||||
{
|
|
||||||
// Mechanic 2: The bag was disturbed but not emptied. Start a 5-minute decay.
|
|
||||||
if (from != null)
|
|
||||||
{
|
|
||||||
from.SendMessage(33, "The bag's magical tether has been disturbed! It begins to rapidly decay.");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_DecayTimer = Timer.DelayCall(TimeSpan.FromMinutes(1), () =>
|
|
||||||
{
|
|
||||||
if (m_Pedestal != null && !Deleted)
|
|
||||||
{
|
|
||||||
m_Pedestal.SinkAndDestroy();
|
|
||||||
Delete();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ThiefPedestalBag(Serial serial) : base(serial) { }
|
public ThiefPedestalProp(Serial serial) : base(serial) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// 2. THE PEDESTAL
|
|
||||||
// ==========================================
|
|
||||||
[SerializationGenerator(0)]
|
[SerializationGenerator(0)]
|
||||||
public partial class ThiefPedestal : Item
|
public partial class ThiefPedestal : Item
|
||||||
{
|
{
|
||||||
[SerializableField(0)]
|
[SerializableField(0)]
|
||||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
private int m_TrapDifficulty;
|
||||||
private int m_Level;
|
|
||||||
|
|
||||||
[SerializableField(1)]
|
[SerializableField(1)]
|
||||||
private ThiefPedestalBag m_LootBag;
|
private ThiefPedestalProp m_PropBag;
|
||||||
|
|
||||||
|
// Tracks how many times a player has failed
|
||||||
|
[SerializableField(2)]
|
||||||
|
private int m_Tries;
|
||||||
|
|
||||||
[Constructible]
|
[Constructible]
|
||||||
public ThiefPedestal() : this(1) { }
|
public ThiefPedestal() : base(0x32F2)
|
||||||
|
|
||||||
[Constructible]
|
|
||||||
public ThiefPedestal(int level) : base(0x32F2)
|
|
||||||
{
|
{
|
||||||
Movable = false;
|
Movable = false;
|
||||||
m_Level = level;
|
|
||||||
Name = "an ancient pedestal";
|
Name = "an ancient pedestal";
|
||||||
//SpawnBag();
|
|
||||||
|
m_TrapDifficulty = Utility.RandomMinMax(1, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SinkAndDestroy()
|
public void SinkAndDestroy()
|
||||||
{
|
{
|
||||||
if (Deleted) return;
|
if (Deleted) return;
|
||||||
|
|
||||||
Effects.SendLocationEffect(Location, Map, 0x3728, 10); // Puff of smoke
|
Effects.SendLocationEffect(Location, Map, 0x3728, 10);
|
||||||
Effects.PlaySound(Location, Map, 0x247); // Sound of grinding stone
|
Effects.PlaySound(Location, Map, 0x247);
|
||||||
Delete();
|
Delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnDelete()
|
public override void OnDelete()
|
||||||
{
|
{
|
||||||
// If the pedestal is deleted by a GM or Spawner, clean up the tethered bag
|
if (m_PropBag != null && !m_PropBag.Deleted)
|
||||||
if (m_LootBag != null && !m_LootBag.Deleted)
|
|
||||||
{
|
{
|
||||||
m_LootBag.Delete();
|
m_PropBag.Delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnDelete();
|
base.OnDelete();
|
||||||
|
|
@ -148,14 +79,13 @@ namespace Server.Custom
|
||||||
|
|
||||||
if (Map != null && Map != Map.Internal)
|
if (Map != null && Map != Map.Internal)
|
||||||
{
|
{
|
||||||
if (m_LootBag == null || m_LootBag.Deleted)
|
if (m_PropBag == null || m_PropBag.Deleted)
|
||||||
{
|
{
|
||||||
SpawnBag();
|
SpawnPropBag();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If a GM changes the facet, move the bag with it
|
m_PropBag.MoveToWorld(new Point3D(X, Y, Z + 6), Map);
|
||||||
m_LootBag.MoveToWorld(new Point3D(X, Y, Z + 6), Map);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -164,119 +94,104 @@ namespace Server.Custom
|
||||||
{
|
{
|
||||||
base.OnLocationChange(oldLocation);
|
base.OnLocationChange(oldLocation);
|
||||||
|
|
||||||
// If a GM uses the [Move command, drag the bag with the pedestal
|
if (Map != null && Map != Map.Internal && m_PropBag != null && !m_PropBag.Deleted)
|
||||||
if (Map != null && Map != Map.Internal && m_LootBag != null && !m_LootBag.Deleted)
|
|
||||||
{
|
{
|
||||||
m_LootBag.MoveToWorld(new Point3D(X, Y, Z + ItemData.Height), Map);
|
m_PropBag.MoveToWorld(new Point3D(X, Y, Z + 6), Map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SpawnBag()
|
public void SpawnPropBag()
|
||||||
{
|
{
|
||||||
if (m_LootBag != null && !m_LootBag.Deleted) return;
|
if (m_PropBag != null && !m_PropBag.Deleted) return;
|
||||||
if (Map == null || Map == Map.Internal) return;
|
if (Map == null || Map == Map.Internal) return;
|
||||||
m_LootBag = new ThiefPedestalBag(this);
|
|
||||||
|
|
||||||
// Fill it with scaling gold and gems
|
m_PropBag = new ThiefPedestalProp(this);
|
||||||
m_LootBag.DropItem(new Gold(m_Level * 500, m_Level * 1000));
|
m_PropBag.MoveToWorld(new Point3D(X, Y, Z + 6), Map);
|
||||||
|
|
||||||
for (int i = 0; i < m_Level; i++)
|
|
||||||
{
|
|
||||||
m_LootBag.DropItem(Loot.RandomGem());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move the bag to the exact top of the pedestal dynamically
|
|
||||||
m_LootBag.MoveToWorld(new Point3D(X, Y, Z + 6), Map);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnDoubleClick(Mobile from)
|
public override void OnDoubleClick(Mobile from)
|
||||||
{
|
{
|
||||||
if (!from.InRange(GetWorldLocation(), 1))
|
if (!from.InRange(GetWorldLocation(), 1))
|
||||||
{
|
{
|
||||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
|
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_LootBag == null || m_LootBag.Deleted)
|
if (m_PropBag == null || m_PropBag.Deleted)
|
||||||
{
|
{
|
||||||
from.SendMessage("The pedestal is currently empty. The mechanism is resetting.");
|
from.SendMessage("The pedestal is currently empty. The mechanism is resetting.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate max tries: Base 5 attempts, +1 attempt for every 200 Luck
|
||||||
|
int playerLuck = Math.Max(0, from.Luck);
|
||||||
|
int maxTries = 5 + (playerLuck / 200);
|
||||||
|
|
||||||
|
if (m_Tries >= maxTries)
|
||||||
|
{
|
||||||
|
from.SendMessage(33, "Your fingers were not nimble enough and the counterweight slams down! The mechanism destroys the loot.");
|
||||||
|
m_PropBag.Delete();
|
||||||
|
m_PropBag = null;
|
||||||
|
Timer.DelayCall(TimeSpan.FromSeconds(3), SinkAndDestroy);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
from.SendMessage("You attempt to carefully swap the bag with a counterweight...");
|
from.SendMessage("You attempt to carefully swap the bag with a counterweight...");
|
||||||
|
|
||||||
// --- THE UNIFIED TIER MATH ---
|
// 1. Snooping / Trap Check (Linear 0-125 Chance)
|
||||||
double minSkill = m_Level switch
|
if (!from.CheckSkill(SkillName.Snooping, 0, 125))
|
||||||
{
|
{
|
||||||
1 => 15.0,
|
m_Tries++;
|
||||||
2 => 35.0,
|
|
||||||
3 => 55.0,
|
|
||||||
4 => 75.0,
|
|
||||||
5 => 90.0,
|
|
||||||
6 => 100.1,
|
|
||||||
_ => m_Level * 16.7
|
|
||||||
};
|
|
||||||
|
|
||||||
double maxSkill = minSkill + 25.0;
|
// If Snooping fails, roll RemoveTrap to see if they dodge the explosion/poison
|
||||||
|
if (from.CheckSkill(SkillName.RemoveTrap, 0, 125))
|
||||||
// 1. Snooping Check
|
{
|
||||||
if (from.Skills.Snooping.Value < minSkill)
|
from.SendMessage(54, "You trigger a pressure plate, but your knowledge of traps allows you to pull your hands back just in time!");
|
||||||
{
|
}
|
||||||
from.SendMessage(33, "You don't even understand how this pressure plate works!");
|
else
|
||||||
TriggerTrap(from);
|
{
|
||||||
|
from.SendMessage(33, "You miscalculate the exact weight needed for the pressure plate!");
|
||||||
|
TriggerTrap(from);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!from.CheckSkill(SkillName.Snooping, minSkill, maxSkill))
|
// 2. Stealing Check (Linear 0-125 Chance)
|
||||||
|
if (!from.CheckSkill(SkillName.Stealing, 0, 125))
|
||||||
{
|
{
|
||||||
from.SendMessage(33, "You miscalculate the exact weight needed for the pressure plate!");
|
m_Tries++;
|
||||||
TriggerTrap(from);
|
from.SendMessage(33, "Your hand slips during the swap! You carefully reset your grip to try again.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Stealing Check
|
// 3. Success
|
||||||
if (from.Skills.Stealing.Value < minSkill)
|
|
||||||
{
|
|
||||||
from.SendMessage(33, "Your hands aren't fast enough for a heist of this caliber!");
|
|
||||||
TriggerTrap(from);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!from.CheckSkill(SkillName.Stealing, minSkill, maxSkill))
|
|
||||||
{
|
|
||||||
from.SendMessage(33, "Your hand slips during the swap!");
|
|
||||||
TriggerTrap(from);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Success!
|
|
||||||
from.SendMessage(89, "In a blur of motion, you swap the bag with a stone! The trap remains silent.");
|
from.SendMessage(89, "In a blur of motion, you swap the bag with a stone! The trap remains silent.");
|
||||||
from.PlaySound(0x248);
|
from.PlaySound(0x248);
|
||||||
|
|
||||||
m_LootBag.ClearTether(); // Untether the bag so it stops decaying
|
m_PropBag.Delete();
|
||||||
m_LootBag.Movable = true;
|
m_PropBag = null;
|
||||||
from.AddToBackpack(m_LootBag);
|
|
||||||
m_LootBag = null;
|
ThiefPedestalLootBag loot = new ThiefPedestalLootBag();
|
||||||
|
from.AddToBackpack(loot);
|
||||||
|
|
||||||
Timer.DelayCall(TimeSpan.FromSeconds(3), SinkAndDestroy);
|
Timer.DelayCall(TimeSpan.FromSeconds(3), SinkAndDestroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TriggerTrap(Mobile m)
|
private void TriggerTrap(Mobile m)
|
||||||
{
|
{
|
||||||
// 50/50 chance to either deal physical damage or apply poison
|
// Note: The trap no longer deletes the bag! It only punishes the player's health.
|
||||||
if (Utility.RandomBool())
|
if (Utility.RandomBool())
|
||||||
{
|
{
|
||||||
// --- POISON TRAP ---
|
m.PlaySound(0x22F);
|
||||||
m.PlaySound(0x22F); // Poison gas sound
|
Effects.SendLocationEffect(Location, Map, 0x3728, 15);
|
||||||
Effects.SendLocationEffect(Location, Map, 0x3728, 15); // Puff of smoke visual
|
|
||||||
|
|
||||||
Poison trapPoison = m_Level switch
|
Poison trapPoison = m_TrapDifficulty switch
|
||||||
{
|
{
|
||||||
1 => Poison.Lesser,
|
1 => Poison.Lesser,
|
||||||
2 => Poison.Regular,
|
2 => Poison.Regular,
|
||||||
3 => Poison.Greater,
|
3 => Poison.Greater,
|
||||||
4 => Poison.Deadly,
|
4 => Poison.Deadly,
|
||||||
_ => Poison.Lethal // Level 5 and 6 apply Lethal poison
|
_ => Poison.Lethal
|
||||||
};
|
};
|
||||||
|
|
||||||
m.ApplyPoison(m, trapPoison);
|
m.ApplyPoison(m, trapPoison);
|
||||||
|
|
@ -284,26 +199,13 @@ namespace Server.Custom
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// --- EXPLOSION TRAP ---
|
m.PlaySound(0x207);
|
||||||
m.PlaySound(0x207); // Explosion sound
|
Effects.SendLocationEffect(Location, Map, 0x36BD, 15);
|
||||||
Effects.SendLocationEffect(Location, Map, 0x36BD, 15); // Large explosion visual
|
|
||||||
|
|
||||||
int damage = Utility.RandomMinMax(20, 35);
|
int damage = Utility.RandomMinMax(20, 35);
|
||||||
|
|
||||||
// 100% Physical damage to respect UOR armor ratings
|
|
||||||
AOS.Damage(m, damage, 100, 0, 0, 0, 0);
|
AOS.Damage(m, damage, 100, 0, 0, 0, 0);
|
||||||
m.SendMessage(33, "The pedestal detonates, blasting you with shrapnel!");
|
m.SendMessage(33, "The pedestal detonates, blasting you with shrapnel!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy the bag so players cannot just tank the hit and grab the loot
|
|
||||||
if (m_LootBag != null && !m_LootBag.Deleted)
|
|
||||||
{
|
|
||||||
m_LootBag.Delete();
|
|
||||||
m_LootBag = null;
|
|
||||||
m.SendMessage(33, "The trap's mechanism destroys the loot in the process!");
|
|
||||||
|
|
||||||
Timer.DelayCall(TimeSpan.FromSeconds(3), SinkAndDestroy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ThiefPedestal(Serial serial) : base(serial) { }
|
public ThiefPedestal(Serial serial) : base(serial) { }
|
||||||
|
|
@ -311,9 +213,9 @@ namespace Server.Custom
|
||||||
[AfterDeserialization]
|
[AfterDeserialization]
|
||||||
private void AfterDeserialization()
|
private void AfterDeserialization()
|
||||||
{
|
{
|
||||||
if (m_LootBag == null || m_LootBag.Deleted)
|
if (m_PropBag == null || m_PropBag.Deleted)
|
||||||
{
|
{
|
||||||
SpawnBag();
|
SpawnPropBag();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
using System;
|
||||||
|
using ModernUO.Serialization;
|
||||||
|
|
||||||
|
namespace Server.Items;
|
||||||
|
|
||||||
|
[SerializationGenerator(0, false)]
|
||||||
|
public partial class ThiefPedestalLootBag : Bag
|
||||||
|
{
|
||||||
|
private static int GetWeightedTier()
|
||||||
|
{
|
||||||
|
var roll = Utility.Random(100);
|
||||||
|
|
||||||
|
if (roll < 25) return 0; // 25% chance (Rolls 0-24)
|
||||||
|
else if (roll < 55) return 1; // 30% chance (Rolls 25-54)
|
||||||
|
else if (roll < 75) return 2; // 20% chance (Rolls 55-74)
|
||||||
|
else if (roll < 90) return 3; // 15% chance (Rolls 75-89)
|
||||||
|
else if (roll < 96) return 4; // 6% chance (Rolls 90-95)
|
||||||
|
else if (roll < 99) return 5; // 3% chance (Rolls 96-98)
|
||||||
|
else return 6; // 1% chance (Rolls 99)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetRandomLevel(out int attributeCount, out int min, out int max)
|
||||||
|
{
|
||||||
|
var pwr = GetWeightedTier();
|
||||||
|
|
||||||
|
if (pwr == 1)
|
||||||
|
{
|
||||||
|
attributeCount = 1;
|
||||||
|
min = 10;
|
||||||
|
max = 20;
|
||||||
|
}
|
||||||
|
else if (pwr == 2)
|
||||||
|
{
|
||||||
|
attributeCount = Utility.RandomMinMax(1, 2);
|
||||||
|
min = 20;
|
||||||
|
max = 40;
|
||||||
|
}
|
||||||
|
else if (pwr == 3)
|
||||||
|
{
|
||||||
|
attributeCount = Utility.RandomMinMax(2, 3);
|
||||||
|
min = 30;
|
||||||
|
max = 60;
|
||||||
|
}
|
||||||
|
else if (pwr == 4)
|
||||||
|
{
|
||||||
|
attributeCount = Utility.RandomMinMax(2, 4);
|
||||||
|
min = 40;
|
||||||
|
max = 80;
|
||||||
|
}
|
||||||
|
else if (pwr == 5)
|
||||||
|
{
|
||||||
|
attributeCount = Utility.RandomMinMax(3, 5);
|
||||||
|
min = 60;
|
||||||
|
max = 80;
|
||||||
|
}
|
||||||
|
else if (pwr == 6)
|
||||||
|
{
|
||||||
|
attributeCount = Utility.RandomMinMax(4, 5);
|
||||||
|
min = 60;
|
||||||
|
max = 100;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
attributeCount = 1;
|
||||||
|
min = 5;
|
||||||
|
max = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetRandomResists(out int phy, out int fire, out int cold, out int poison, out int energy)
|
||||||
|
{
|
||||||
|
var pwr = GetWeightedTier();
|
||||||
|
|
||||||
|
if (pwr == 1)
|
||||||
|
{
|
||||||
|
phy = Utility.RandomMinMax(1, 3);
|
||||||
|
fire = Utility.RandomMinMax(1, 3);
|
||||||
|
cold = Utility.RandomMinMax(1, 3);
|
||||||
|
poison = Utility.RandomMinMax(1, 3);
|
||||||
|
energy = Utility.RandomMinMax(1, 3);
|
||||||
|
}
|
||||||
|
else if (pwr == 2)
|
||||||
|
{
|
||||||
|
phy = Utility.RandomMinMax(2, 5);
|
||||||
|
fire = Utility.RandomMinMax(2, 5);
|
||||||
|
cold = Utility.RandomMinMax(2, 5);
|
||||||
|
poison = Utility.RandomMinMax(2, 5);
|
||||||
|
energy = Utility.RandomMinMax(2, 5);
|
||||||
|
}
|
||||||
|
else if (pwr == 3)
|
||||||
|
{
|
||||||
|
phy = Utility.RandomMinMax(4, 7);
|
||||||
|
fire = Utility.RandomMinMax(4, 7);
|
||||||
|
cold = Utility.RandomMinMax(4, 7);
|
||||||
|
poison = Utility.RandomMinMax(4, 7);
|
||||||
|
energy = Utility.RandomMinMax(4, 7);
|
||||||
|
}
|
||||||
|
else if (pwr == 4)
|
||||||
|
{
|
||||||
|
phy = Utility.RandomMinMax(6, 10);
|
||||||
|
fire = Utility.RandomMinMax(6, 10);
|
||||||
|
cold = Utility.RandomMinMax(6, 10);
|
||||||
|
poison = Utility.RandomMinMax(6, 10);
|
||||||
|
energy = Utility.RandomMinMax(6, 10);
|
||||||
|
}
|
||||||
|
else if (pwr == 5)
|
||||||
|
{
|
||||||
|
phy = Utility.RandomMinMax(9, 12);
|
||||||
|
fire = Utility.RandomMinMax(9, 12);
|
||||||
|
cold = Utility.RandomMinMax(9, 12);
|
||||||
|
poison = Utility.RandomMinMax(9, 12);
|
||||||
|
energy = Utility.RandomMinMax(9, 12);
|
||||||
|
}
|
||||||
|
else if (pwr == 6)
|
||||||
|
{
|
||||||
|
phy = Utility.RandomMinMax(12, 15);
|
||||||
|
fire = Utility.RandomMinMax(12, 15);
|
||||||
|
cold = Utility.RandomMinMax(12, 15);
|
||||||
|
poison = Utility.RandomMinMax(12, 15);
|
||||||
|
energy = Utility.RandomMinMax(12, 15);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
phy = 0;
|
||||||
|
fire = 0;
|
||||||
|
cold = 0;
|
||||||
|
poison = 0;
|
||||||
|
energy = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Constructible]
|
||||||
|
public ThiefPedestalLootBag()
|
||||||
|
{
|
||||||
|
int bagTier = GetWeightedTier();
|
||||||
|
|
||||||
|
int weaponCount = Utility.RandomMinMax(0, bagTier);
|
||||||
|
for (var i = 0; i < weaponCount; i++)
|
||||||
|
{
|
||||||
|
var weapon = Loot.RandomWeapon();
|
||||||
|
GetRandomLevel(out var attributeCount, out var min, out var max);
|
||||||
|
BaseRunicTool.ApplyAttributesTo(weapon, attributeCount, min, max);
|
||||||
|
DropItem(weapon);
|
||||||
|
}
|
||||||
|
|
||||||
|
int armorCount = Utility.RandomMinMax(0, bagTier);
|
||||||
|
for (var i = 0; i < armorCount; i++)
|
||||||
|
{
|
||||||
|
var armor = Loot.RandomArmorOrShield();
|
||||||
|
GetRandomLevel(out var attributeCount, out var min, out var max);
|
||||||
|
BaseRunicTool.ApplyAttributesTo(armor, attributeCount, min, max);
|
||||||
|
GetRandomResists(out var phy, out var fire, out var cold, out var poison, out var energy);
|
||||||
|
armor.PhysicalBonus = phy;
|
||||||
|
armor.FireBonus = fire;
|
||||||
|
armor.ColdBonus = cold;
|
||||||
|
armor.PoisonBonus = poison;
|
||||||
|
armor.EnergyBonus = energy;
|
||||||
|
DropItem(armor);
|
||||||
|
}
|
||||||
|
|
||||||
|
int jewelryCount = Utility.RandomMinMax(0, bagTier);
|
||||||
|
for (var i = 0; i < jewelryCount; i++)
|
||||||
|
{
|
||||||
|
var jewelry = Loot.RandomJewelry();
|
||||||
|
GetRandomLevel(out var attributeCount, out var min, out var max);
|
||||||
|
BaseRunicTool.ApplyAttributesTo(jewelry, attributeCount, min, max);
|
||||||
|
DropItem(jewelry);
|
||||||
|
}
|
||||||
|
|
||||||
|
int reagentCount = Utility.RandomMinMax(0, bagTier);
|
||||||
|
for (var i = 0; i < reagentCount; i++)
|
||||||
|
{
|
||||||
|
var reagents = Loot.RandomReagent();
|
||||||
|
reagents.Amount = Math.Max(1, GetWeightedTier() * 2);
|
||||||
|
DropItem(reagents);
|
||||||
|
}
|
||||||
|
int necroreagentCount = Utility.RandomMinMax(0, bagTier);
|
||||||
|
for (var i = 0; i < necroreagentCount; i++)
|
||||||
|
{
|
||||||
|
var necroreagents = Loot.RandomNecromancyReagent();
|
||||||
|
necroreagents.Amount = Math.Max(1, GetWeightedTier() * 2);
|
||||||
|
DropItem(necroreagents);
|
||||||
|
}
|
||||||
|
|
||||||
|
int gemCount = Utility.RandomMinMax(0, bagTier);
|
||||||
|
for (var i = 0; i < gemCount; i++)
|
||||||
|
{
|
||||||
|
var gems = Loot.RandomGem();
|
||||||
|
gems.Amount = Math.Max(1, bagTier * 2);
|
||||||
|
DropItem(gems);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mageScrollCount = Utility.RandomMinMax(0, bagTier);
|
||||||
|
int mlevel = 0;
|
||||||
|
if (bagTier < 3)
|
||||||
|
{
|
||||||
|
mlevel = 42;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mlevel = 63;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < mageScrollCount; i++)
|
||||||
|
{
|
||||||
|
var scroll = Loot.RandomScroll(0, mlevel, SpellbookType.Regular);
|
||||||
|
scroll.Amount = Math.Max(1, bagTier);
|
||||||
|
DropItem(scroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
int necroScrollCount = Utility.RandomMinMax(0, bagTier);
|
||||||
|
int nlevel = 0;
|
||||||
|
if (bagTier < 3)
|
||||||
|
{
|
||||||
|
nlevel = 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nlevel = 15;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < necroScrollCount; i++)
|
||||||
|
{
|
||||||
|
var scroll = Loot.RandomScroll(0, nlevel, SpellbookType.Necromancer);
|
||||||
|
scroll.Amount = Math.Max(1, bagTier);
|
||||||
|
DropItem(scroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = Math.Max(1, bagTier); i > 0; i--)
|
||||||
|
{
|
||||||
|
DropItem(Loot.RandomPotion());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = Math.Max(1, bagTier); i > 0; i--)
|
||||||
|
{
|
||||||
|
DropItem(Loot.RandomClothing());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bagTier > 3)
|
||||||
|
{
|
||||||
|
if (Utility.RandomBool())
|
||||||
|
{
|
||||||
|
DropItem(new Arrow((bagTier + (Utility.RandomMinMax(10, 20)))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DropItem(new Bolt((bagTier + (Utility.RandomMinMax(10, 20)))));
|
||||||
|
}
|
||||||
|
DropItem(new BlankScroll(Math.Max(1, GetWeightedTier())));
|
||||||
|
}
|
||||||
|
|
||||||
|
int minGold = 100 + (bagTier * 100);
|
||||||
|
int maxGold = minGold + 99;
|
||||||
|
DropItem(new Gold(Utility.RandomMinMax(minGold, maxGold)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,60 +3,130 @@ using ModernUO.Serialization;
|
||||||
|
|
||||||
namespace Server.Items;
|
namespace Server.Items;
|
||||||
|
|
||||||
// ==============================================================
|
|
||||||
// LEVEL 4: 99% Trapped / 99% Locked (1% Lottery Ticket!)
|
|
||||||
// ==============================================================
|
|
||||||
[SerializationGenerator(0, false)]
|
[SerializationGenerator(0, false)]
|
||||||
public partial class RandomLootBag : Bag
|
public partial class RandomLootBag : Bag
|
||||||
{
|
{
|
||||||
private static void GetRandomAOSStats(out int attributeCount, out int min, out int max)
|
private static int GetWeightedTier()
|
||||||
{
|
{
|
||||||
var rnd = Utility.Random(15);
|
var roll = Utility.Random(100);
|
||||||
|
|
||||||
if (rnd < 1)
|
if (roll < 25) return 0; // 25% chance (Rolls 0-24)
|
||||||
{
|
else if (roll < 55) return 1; // 30% chance (Rolls 25-54)
|
||||||
attributeCount = Utility.RandomMinMax(2, 5);
|
else if (roll < 75) return 2; // 20% chance (Rolls 55-74)
|
||||||
min = 20;
|
else if (roll < 90) return 3; // 15% chance (Rolls 75-89)
|
||||||
max = 70;
|
else if (roll < 96) return 4; // 6% chance (Rolls 90-95)
|
||||||
}
|
else if (roll < 99) return 5; // 3% chance (Rolls 96-98)
|
||||||
else if (rnd < 3)
|
else return 6; // 1% chance (Rolls 99)
|
||||||
{
|
}
|
||||||
attributeCount = Utility.RandomMinMax(2, 4);
|
|
||||||
min = 20;
|
private static void GetRandomLevel(out int attributeCount, out int min, out int max)
|
||||||
max = 50;
|
{
|
||||||
}
|
var pwr = GetWeightedTier();
|
||||||
else if (rnd < 6)
|
|
||||||
{
|
if (pwr == 1)
|
||||||
attributeCount = Utility.RandomMinMax(2, 3);
|
|
||||||
min = 20;
|
|
||||||
max = 40;
|
|
||||||
}
|
|
||||||
else if (rnd < 10)
|
|
||||||
{
|
|
||||||
attributeCount = Utility.RandomMinMax(1, 2);
|
|
||||||
min = 10;
|
|
||||||
max = 30;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
attributeCount = 1;
|
attributeCount = 1;
|
||||||
min = 10;
|
min = 10;
|
||||||
max = 20;
|
max = 20;
|
||||||
}
|
}
|
||||||
|
else if (pwr == 2)
|
||||||
|
{
|
||||||
|
attributeCount = Utility.RandomMinMax(1, 2);
|
||||||
|
min = 20;
|
||||||
|
max = 40;
|
||||||
|
}
|
||||||
|
else if (pwr == 3)
|
||||||
|
{
|
||||||
|
attributeCount = Utility.RandomMinMax(2, 3);
|
||||||
|
min = 30;
|
||||||
|
max = 60;
|
||||||
|
}
|
||||||
|
else if (pwr == 4)
|
||||||
|
{
|
||||||
|
attributeCount = Utility.RandomMinMax(2, 4);
|
||||||
|
min = 40;
|
||||||
|
max = 80;
|
||||||
|
}
|
||||||
|
else if (pwr == 5)
|
||||||
|
{
|
||||||
|
attributeCount = Utility.RandomMinMax(3, 5);
|
||||||
|
min = 60;
|
||||||
|
max = 80;
|
||||||
|
}
|
||||||
|
else if (pwr == 6)
|
||||||
|
{
|
||||||
|
attributeCount = Utility.RandomMinMax(4, 5);
|
||||||
|
min = 60;
|
||||||
|
max = 100;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
attributeCount = 1;
|
||||||
|
min = 5;
|
||||||
|
max = 10;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GetRandomResists(out int phy, out int fire, out int cold, out int poison, out int energy)
|
private static void GetRandomResists(out int phy, out int fire, out int cold, out int poison, out int energy)
|
||||||
{
|
{
|
||||||
var phyR = Utility.Random(1, 15);
|
var pwr = GetWeightedTier();
|
||||||
phy = phyR;
|
|
||||||
var fireR = Utility.Random(1, 15);
|
if (pwr == 1)
|
||||||
fire = fireR;
|
{
|
||||||
var coldR = Utility.Random(1, 15);
|
phy = Utility.RandomMinMax(1, 3);
|
||||||
cold = coldR;
|
fire = Utility.RandomMinMax(1, 3);
|
||||||
var poisonR = Utility.Random(1, 15);
|
cold = Utility.RandomMinMax(1, 3);
|
||||||
poison = poisonR;
|
poison = Utility.RandomMinMax(1, 3);
|
||||||
var energyR = Utility.Random(1, 15);
|
energy = Utility.RandomMinMax(1, 3);
|
||||||
energy = energyR;
|
}
|
||||||
|
else if (pwr == 2)
|
||||||
|
{
|
||||||
|
phy = Utility.RandomMinMax(2, 5);
|
||||||
|
fire = Utility.RandomMinMax(2, 5);
|
||||||
|
cold = Utility.RandomMinMax(2, 5);
|
||||||
|
poison = Utility.RandomMinMax(2, 5);
|
||||||
|
energy = Utility.RandomMinMax(2, 5);
|
||||||
|
}
|
||||||
|
else if (pwr == 3)
|
||||||
|
{
|
||||||
|
phy = Utility.RandomMinMax(4, 7);
|
||||||
|
fire = Utility.RandomMinMax(4, 7);
|
||||||
|
cold = Utility.RandomMinMax(4, 7);
|
||||||
|
poison = Utility.RandomMinMax(4, 7);
|
||||||
|
energy = Utility.RandomMinMax(4, 7);
|
||||||
|
}
|
||||||
|
else if (pwr == 4)
|
||||||
|
{
|
||||||
|
phy = Utility.RandomMinMax(6, 10);
|
||||||
|
fire = Utility.RandomMinMax(6, 10);
|
||||||
|
cold = Utility.RandomMinMax(6, 10);
|
||||||
|
poison = Utility.RandomMinMax(6, 10);
|
||||||
|
energy = Utility.RandomMinMax(6, 10);
|
||||||
|
}
|
||||||
|
else if (pwr == 5)
|
||||||
|
{
|
||||||
|
phy = Utility.RandomMinMax(9, 12);
|
||||||
|
fire = Utility.RandomMinMax(9, 12);
|
||||||
|
cold = Utility.RandomMinMax(9, 12);
|
||||||
|
poison = Utility.RandomMinMax(9, 12);
|
||||||
|
energy = Utility.RandomMinMax(9, 12);
|
||||||
|
}
|
||||||
|
else if (pwr == 6)
|
||||||
|
{
|
||||||
|
phy = Utility.RandomMinMax(12, 15);
|
||||||
|
fire = Utility.RandomMinMax(12, 15);
|
||||||
|
cold = Utility.RandomMinMax(12, 15);
|
||||||
|
poison = Utility.RandomMinMax(12, 15);
|
||||||
|
energy = Utility.RandomMinMax(12, 15);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
phy = 0;
|
||||||
|
fire = 0;
|
||||||
|
cold = 0;
|
||||||
|
poison = 0;
|
||||||
|
energy = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Constructible]
|
[Constructible]
|
||||||
|
|
@ -65,7 +135,7 @@ public partial class RandomLootBag : Bag
|
||||||
for (var i = Utility.Random(10) + 1; i > 0; i--)
|
for (var i = Utility.Random(10) + 1; i > 0; i--)
|
||||||
{
|
{
|
||||||
var weapon = Loot.RandomWeapon();
|
var weapon = Loot.RandomWeapon();
|
||||||
GetRandomAOSStats(out var attributeCount, out var min, out var max);
|
GetRandomLevel(out var attributeCount, out var min, out var max);
|
||||||
BaseRunicTool.ApplyAttributesTo(weapon, attributeCount, min, max);
|
BaseRunicTool.ApplyAttributesTo(weapon, attributeCount, min, max);
|
||||||
DropItem(weapon);
|
DropItem(weapon);
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +143,7 @@ public partial class RandomLootBag : Bag
|
||||||
for ( var i = Utility.Random(10) + 1; i > 0; i--)
|
for ( var i = Utility.Random(10) + 1; i > 0; i--)
|
||||||
{
|
{
|
||||||
var armor = Loot.RandomArmorOrShield();
|
var armor = Loot.RandomArmorOrShield();
|
||||||
GetRandomAOSStats(out var attributeCount, out var min, out var max);
|
GetRandomLevel(out var attributeCount, out var min, out var max);
|
||||||
BaseRunicTool.ApplyAttributesTo(armor, attributeCount, min, max);
|
BaseRunicTool.ApplyAttributesTo(armor, attributeCount, min, max);
|
||||||
GetRandomResists(out var phy, out var fire, out var cold, out var poison, out var energy);
|
GetRandomResists(out var phy, out var fire, out var cold, out var poison, out var energy);
|
||||||
armor.PhysicalBonus = phy;
|
armor.PhysicalBonus = phy;
|
||||||
|
|
@ -87,7 +157,7 @@ public partial class RandomLootBag : Bag
|
||||||
for (var i = Utility.Random(10) + 1; i > 0; i--)
|
for (var i = Utility.Random(10) + 1; i > 0; i--)
|
||||||
{
|
{
|
||||||
var jewelry = Loot.RandomJewelry();
|
var jewelry = Loot.RandomJewelry();
|
||||||
GetRandomAOSStats(out var attributeCount, out var min, out var max);
|
GetRandomLevel(out var attributeCount, out var min, out var max);
|
||||||
BaseRunicTool.ApplyAttributesTo(jewelry, attributeCount, min, max);
|
BaseRunicTool.ApplyAttributesTo(jewelry, attributeCount, min, max);
|
||||||
DropItem(jewelry);
|
DropItem(jewelry);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
Run.sh
5
Run.sh
|
|
@ -5,11 +5,6 @@ then
|
||||||
echo "| A Server is already running!! "
|
echo "| A Server is already running!! "
|
||||||
echo "--------------------------------"
|
echo "--------------------------------"
|
||||||
else
|
else
|
||||||
echo "________________________________"
|
|
||||||
echo "| Compiling server files."
|
|
||||||
echo "--------------------------------"
|
|
||||||
dotnet publish Projects/Application/Application.csproj -c Release -r linux-x64 --self-contained=false
|
|
||||||
echo ""
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "________________________________"
|
echo "________________________________"
|
||||||
echo "| Starting Server...."
|
echo "| Starting Server...."
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue