Overwrite

Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
Unstable Kitsune
2023-11-28 23:20:26 -05:00
parent 3cd54811de
commit b918192e4e
11608 changed files with 2644205 additions and 47 deletions

View File

@@ -0,0 +1,46 @@
#region References
using System;
using Server.Mobiles;
#endregion
namespace Server.Services.Virtues
{
public class CompassionVirtue
{
private static readonly TimeSpan LossDelay = TimeSpan.FromDays(7.0);
private const int LossAmount = 500;
public static void Initialize()
{
VirtueGump.Register(105, OnVirtueUsed);
}
public static void OnVirtueUsed(Mobile from)
{
from.SendLocalizedMessage(1053001); // This virtue is not activated through the virtue menu.
}
public static void CheckAtrophy(Mobile from)
{
var pm = from as PlayerMobile;
if (pm == null)
return;
try
{
if (pm.LastCompassionLoss + LossDelay < DateTime.UtcNow)
{
VirtueHelper.Atrophy(from, VirtueName.Compassion, LossAmount);
//OSI has no cliloc message for losing compassion. Weird.
pm.LastCompassionLoss = DateTime.UtcNow;
}
}
catch
{ }
}
}
}

View File

@@ -0,0 +1,506 @@
#region References
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Server.Engines.CannedEvil;
using Server.Items;
using Server.Mobiles;
using Server.Multis;
using Server.Network;
using Server.Regions;
#endregion
namespace Server.Services.Virtues
{
public static class HonestyVirtue
{
/// <summary>
/// Set this to false if you are having memory shortages. True means points are validated at compile time and reduces run time processing
/// to randomly choose a point. Making it false will dramatically decrease program memory usage and compile time, however will choose
/// each random point at runtime.
/// </summary>
public static readonly bool UseSpawnArea = false;
public static bool Enabled { get; set; }
public static int MaxGeneration { get; set; }
public static bool TrammelGeneration { get; set; }
private static readonly string[] _Regions =
{"Britain", "Minoc", "Magincia", "Trinsic", "Jhelom", "Moonglow", "Skara Brae", "Yew"};
private const TileFlag _Filter = TileFlag.Wet | TileFlag.Roof | TileFlag.Impassable;
private static readonly List<Item> _Items;
private static SpawnArea _FeluccaArea, _TrammelArea;
static HonestyVirtue()
{
Enabled = Config.Get("Honesty.Enabled", true);
MaxGeneration = Config.Get("Honesty.MaxGeneration", 1000);
TrammelGeneration = !Siege.SiegeShard && Config.Get("Honesty.TrammelGeneration", true);
_Items = new List<Item>(MaxGeneration);
}
private static void GenerateImages()
{
if (!Directory.Exists("Honesty"))
{
Directory.CreateDirectory("Honesty");
}
if (_FeluccaArea != null)
{
_FeluccaArea.Image.Save("Honesty/Felucca.png", ImageFormat.Png);
}
if (_TrammelArea != null)
{
_TrammelArea.Image.Save("Honesty/Trammel.png", ImageFormat.Png);
}
}
public static void Initialize()
{
EventSink.ItemDeleted += OnItemDeleted;
EventSink.AfterWorldSave += OnAfterSave;
VirtueGump.Register(106, OnVirtueUsed);
if (Enabled)
{
_Items.AddRange(World.Items.Values.Where(item => item.HonestyItem));
GenerateHonestyItems();
if (UseSpawnArea)
{
Task.Factory.StartNew(GenerateImages);
}
}
}
public static bool IsHonestyItem(Item item)
{
return item.HasSocket<HonestyItemSocket>();
}
private static void OnItemDeleted(ItemDeletedEventArgs e)
{
if (IsHonestyItem(e.Item))
{
_Items.Remove(e.Item);
}
}
private static void OnAfterSave(AfterWorldSaveEventArgs e)
{
World.WaitForWriteCompletion();
PruneTaken();
if (Enabled)
{
GenerateHonestyItems();
}
}
public static void OnVirtueUsed(Mobile from)
{
if (Enabled)
{
from.SendLocalizedMessage(1053001); // This virtue is not activated through the virtue menu.
}
}
private static void PruneTaken()
{
_Items.RemoveAll(ItemFlags.GetTaken);
}
/*
private static bool ValidateSpawnPoint(Map map, int x, int y, int z)
{
return TreasureMap.ValidateLocation(x, y, map);
}
*/
private static Point3D GetRandom(Map map)
{
if (map == null)
return Point3D.Zero;
var fw = map.MapID <= 1 ? 5119 : map.Width;
var fh = map.MapID <= 1 ? 4095 : map.Height;
int x, y, z = 0;
do
{
x = Utility.RandomMinMax(0, fw);
y = Utility.RandomMinMax(0, fh);
z = map.Tiles.GetLandTile(x, y).Z;
}
while (!ValidateSpawnPoint(map, x, y, z));
return new Point3D(x, y, z);
}
private static bool ValidateSpawnPoint(Map map, int x, int y, int z)
{
var lt = map.Tiles.GetLandTile(x, y);
var ld = TileData.LandTable[lt.ID];
if (lt.Ignored || (ld.Flags & TileFlag.Impassable) > 0 || (ld.Flags & TileFlag.Wet) > 0 || (ld.Flags & TileFlag.Roof) > 0)
{
return false;
}
for (var i = 0; i < HousePlacement.RoadIDs.Length; i += 2)
{
if (lt.ID >= HousePlacement.RoadIDs[i] && lt.ID <= HousePlacement.RoadIDs[i + 1])
{
return false;
}
}
var p = new Point3D(x, y, lt.Z);
var reg = Region.Find(p, map);
//no-go in towns, houses, dungeons and champspawns
if (reg != null)
{
if (reg.IsPartOf<TownRegion>() || reg.IsPartOf<DungeonRegion>() || reg.IsPartOf<ChampionSpawnRegion>() ||
reg.IsPartOf<HouseRegion>())
{
return false;
}
}
//check for house within 5 tiles
for (p.X = x - 5; p.X <= x + 5; p.X++)
{
for (p.Y = y - 5; p.Y <= y + 5; p.Y++)
{
if (BaseHouse.FindHouseAt(p, map, Region.MaxZ - p.Z) != null)
{
return false;
}
}
}
return true;
}
private static void GenerateHonestyItems()
{
CheckChests();
Utility.PushColor(ConsoleColor.Yellow);
Console.WriteLine("[Honesty]: Generating...");
Utility.PopColor();
var sw = new Stopwatch();
var s = 0.0;
if (UseSpawnArea)
{
if (_FeluccaArea == null)
{
Utility.PushColor(ConsoleColor.Yellow);
Console.Write("[Honesty]: Felucca - Reticulating splines...");
Utility.PopColor();
sw.Restart();
_FeluccaArea = SpawnArea.Instantiate(Map.Felucca.DefaultRegion, _Filter, ValidateSpawnPoint, true);
sw.Stop();
s += sw.Elapsed.TotalSeconds;
Utility.PushColor(ConsoleColor.Green);
Console.WriteLine("done ({0:F2} seconds)", sw.Elapsed.TotalSeconds);
Utility.PopColor();
}
if (_TrammelArea == null && TrammelGeneration)
{
Utility.PushColor(ConsoleColor.Yellow);
Console.Write("[Honesty]: Trammel - Reticulating splines...");
Utility.PopColor();
sw.Restart();
_TrammelArea = SpawnArea.Instantiate(Map.Trammel.DefaultRegion, _Filter, ValidateSpawnPoint, true);
sw.Stop();
s += sw.Elapsed.TotalSeconds;
Utility.PushColor(ConsoleColor.Green);
Console.WriteLine("done ({0:F2} seconds)", sw.Elapsed.TotalSeconds);
Utility.PopColor();
}
}
try
{
Map facet;
Point3D loc;
Item item;
var count = MaxGeneration - _Items.Count;
if (count > 0)
{
Utility.PushColor(ConsoleColor.Yellow);
Console.Write("[Honesty]: Creating {0:#,0} lost items...", count);
Utility.PopColor();
sw.Restart();
var spawned = new Item[count];
for (var i = 0; i < spawned.Length; i++)
{
try
{
item = Loot.RandomArmorOrShieldOrWeapon();
if (item != null && !item.Deleted)
{
spawned[i] = item;
}
}
catch
{ }
}
for (var i = 0; i < spawned.Length; i++)
{
item = spawned[i];
if (item == null)
{
continue;
}
try
{
if (UseSpawnArea)
{
var area = _TrammelArea != null && Utility.RandomBool() ? _TrammelArea : _FeluccaArea;
facet = area.Facet;
loc = area.GetRandom();
}
else
{
facet = TrammelGeneration && Utility.RandomBool() ? Map.Trammel : Map.Felucca;
loc = GetRandom(facet);
}
if (loc == Point3D.Zero)
{
continue;
}
RunicReforging.GenerateRandomItem(item, 0, 100, 1000);
item.AttachSocket(new HonestyItemSocket());
item.HonestyItem = true;
_Items.Add(item);
ItemFlags.SetTaken(item, false);
item.OnBeforeSpawn(loc, facet);
item.MoveToWorld(loc, facet);
item.OnAfterSpawn();
}
catch
{
item.Delete();
}
finally
{
spawned[i] = null;
}
}
sw.Stop();
s += sw.Elapsed.TotalSeconds;
Utility.PushColor(ConsoleColor.Green);
Console.WriteLine("done ({0:F2} seconds)", sw.Elapsed.TotalSeconds);
Utility.PopColor();
}
}
catch (Exception e)
{
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine(e);
Utility.PopColor();
}
Utility.PushColor(ConsoleColor.Yellow);
Console.Write("[Honesty]:");
Utility.PopColor();
Utility.PushColor(ConsoleColor.Green);
Console.WriteLine(" Generation completed in {0:F2} seconds.", s);
Utility.PopColor();
}
public static void AssignOwner(HonestyItemSocket socket)
{
if (socket != null)
{
socket.HonestyRegion = _Regions[Utility.Random(_Regions.Length)];
if (!String.IsNullOrWhiteSpace(socket.HonestyRegion) && BaseVendor.AllVendors.Count >= 10)
{
var attempts = BaseVendor.AllVendors.Count / 10;
BaseVendor m;
do
{
m = BaseVendor.AllVendors[Utility.Random(BaseVendor.AllVendors.Count)];
}
while ((m == null || m.Map != socket.Owner.Map || !m.Region.IsPartOf(socket.HonestyRegion)) && --attempts >= 0);
socket.HonestyOwner = m;
}
}
}
private static void CheckChests()
{
foreach (var loc in _ChestLocations)
{
CheckLocation(loc, Map.Trammel);
CheckLocation(loc, Map.Felucca);
}
}
private static void CheckLocation(Point3D pnt, Map map)
{
var eable = map.GetItemsInRange(pnt, 0);
foreach (var item in eable)
{
if (item is HonestyChest)
{
eable.Free();
return;
}
}
eable.Free();
var chest = new HonestyChest();
chest.MoveToWorld(pnt, map);
}
private static readonly Point3D[] _ChestLocations =
{
new Point3D(1809, 2825, 0), new Point3D(1323, 3768, 0), new Point3D(3784, 2247, 20), new Point3D(591, 2144, 0),
new Point3D(1648, 1603, 20), new Point3D(2509, 544, 0), new Point3D(4463, 1156, 0), new Point3D(650, 824, 0)
};
}
public class HonestyChest : Container
{
public override int LabelNumber { get { return 1151529; } } // lost and found box
[Constructable]
public HonestyChest()
: base(0x9A9)
{
Movable = false;
}
public HonestyChest(Serial serial)
: base(serial)
{ }
public override void OnDoubleClick(Mobile m)
{ }
public override bool OnDragDrop(Mobile from, Item dropped)
{
return CheckGain(from, dropped);
}
public override bool OnDragDropInto(Mobile from, Item item, Point3D p)
{
return CheckGain(from, item);
}
public bool CheckGain(Mobile from, Item item)
{
if (from == null || from.Deleted)
{
return false;
}
if (item == null || !item.HonestyItem)
{
PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1151530, from.NetState); // This is not a lost item.
return false;
}
var reg = Region.Find(Location, Map);
var gainedPath = false;
var honestySocket = item.GetSocket<HonestyItemSocket>();
if (honestySocket != null && honestySocket.HonestyRegion == reg.Name)
{
VirtueHelper.Award(from, VirtueName.Honesty, 60, ref gainedPath);
}
else
{
VirtueHelper.Award(from, VirtueName.Honesty, 30, ref gainedPath);
}
PrivateOverheadMessage(
MessageType.Regular,
0x3B2,
1151523,
from.NetState); // You place the item in the lost and found. You have gained some Honesty!
if (gainedPath)
{
from.SendMessage("You have gained a path in Honesty!");
}
item.Delete();
return true;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,483 @@
#region References
using System;
using Server.Gumps;
using Server.Mobiles;
using Server.Regions;
using Server.Targeting;
#endregion
namespace Server.Services.Virtues
{
public interface IHonorTarget
{
HonorContext ReceivedHonorContext { get; set; }
}
public class HonorVirtue
{
private static readonly TimeSpan UseDelay = TimeSpan.FromMinutes(5.0);
public static void Initialize()
{
VirtueGump.Register(107, OnVirtueUsed);
}
public static void ActivateEmbrace(PlayerMobile pm)
{
var duration = GetHonorDuration(pm);
int usedPoints;
if (pm.Virtues.Honor < 4399)
usedPoints = 400;
else if (pm.Virtues.Honor < 10599)
usedPoints = 600;
else
usedPoints = 1000;
VirtueHelper.Atrophy(pm, VirtueName.Honor, usedPoints);
pm.HonorActive = true;
pm.SendLocalizedMessage(1063235); // You embrace your honor
BuffInfo.AddBuff(
pm,
new BuffInfo(
BuffIcon.Honored,
1075649,
BuffInfo.Blank,
TimeSpan.FromSeconds(duration),
pm,
"You have embraced your honor",
true));
Timer.DelayCall(
TimeSpan.FromSeconds(duration),
m =>
{
m.HonorActive = false;
m.LastHonorUse = DateTime.UtcNow;
m.SendLocalizedMessage(1063236); // You no longer embrace your honor
},
pm);
}
private static void OnVirtueUsed(Mobile from)
{
if (from.Alive)
{
from.SendLocalizedMessage(1063160); // Target what you wish to honor.
from.Target = new InternalTarget();
}
}
private static int GetHonorDuration(PlayerMobile from)
{
switch (VirtueHelper.GetLevel(from, VirtueName.Honor))
{
case VirtueLevel.Seeker:
return 30;
case VirtueLevel.Follower:
return 90;
case VirtueLevel.Knight:
return 300;
default:
return 0;
}
}
private static void EmbraceHonor(PlayerMobile pm)
{
if (pm.HonorActive)
{
pm.SendLocalizedMessage(1063230); // You must wait awhile before you can embrace honor again.
return;
}
if (GetHonorDuration(pm) == 0)
{
pm.SendLocalizedMessage(1063234); // You do not have enough honor to do that
return;
}
var waitTime = DateTime.UtcNow - pm.LastHonorUse;
if (waitTime < UseDelay)
{
var remainingTime = UseDelay - waitTime;
var remainingMinutes = (int)Math.Ceiling(remainingTime.TotalMinutes);
pm.SendLocalizedMessage(
1063240,
remainingMinutes.ToString()); // You must wait ~1_HONOR_WAIT~ minutes before embracing honor again
return;
}
pm.SendGump(new HonorSelf(pm));
}
private static void Honor(PlayerMobile source, Mobile target)
{
var honorTarget = target as IHonorTarget;
var reg = (GuardedRegion)source.Region.GetRegion(typeof(GuardedRegion));
var map = source.Map;
if (honorTarget == null)
return;
if (honorTarget.ReceivedHonorContext != null)
{
if (honorTarget.ReceivedHonorContext.Source == source)
{
source.SendLocalizedMessage(
1115882); // You don't need to declare again. You are already under Honorable Combat with this target.
return;
}
if (honorTarget.ReceivedHonorContext.CheckDistance())
{
source.SendLocalizedMessage(1063233); // Somebody else is honoring this opponent
return;
}
}
if (target.Hits < target.HitsMax)
{
source.SendLocalizedMessage(1063166); // You cannot honor this monster because it is too damaged.
return;
}
var cret = target as BaseCreature;
if (target.Body.IsHuman && (cret == null || (!cret.AlwaysAttackable && !cret.AlwaysMurderer)))
{
if (reg == null || reg.IsDisabled())
{
//Allow honor on blue if Out of guardzone
}
else if (map != null && (map.Rules & MapRules.HarmfulRestrictions) == 0)
{
//Allow honor on blue if in Fel
}
else
{
source.SendLocalizedMessage(1001018); // You cannot perform negative acts
return; //cannot honor in trammel town on blue
}
}
if (Core.ML && target is PlayerMobile)
{
source.SendLocalizedMessage(1075614); // You cannot honor other players.
return;
}
if (source.SentHonorContext != null)
source.SentHonorContext.Cancel();
new HonorContext(source, target);
source.Direction = source.GetDirectionTo(target);
source.SendLocalizedMessage(1115884); // You Started Honorable Combat!
if (!source.Mounted && !source.IsBodyMod)
source.Animate(32, 5, 1, true, true, 0);
BuffInfo.AddBuff(source, new BuffInfo(BuffIcon.Honored, 1075649, 1153815, String.Format("{0}", target.Name, true)));
BuffInfo.AddBuff(source, new BuffInfo(BuffIcon.Perfection, 1153786, 1151394, String.Format("0\t{0}", target.Name)));
}
private class InternalTarget : Target
{
public InternalTarget()
: base(12, false, TargetFlags.None)
{
CheckLOS = true;
}
protected override void OnTarget(Mobile from, object targeted)
{
var pm = from as PlayerMobile;
if (pm == null)
return;
if (targeted == pm)
{
EmbraceHonor(pm);
}
else if (targeted is Mobile)
Honor(pm, (Mobile)targeted);
}
protected override void OnTargetOutOfRange(Mobile from, object targeted)
{
from.SendLocalizedMessage(1063232); // You are too far away to honor your opponent
}
}
}
public class HonorContext
{
private readonly PlayerMobile m_Source;
private readonly Mobile m_Target;
private readonly Point3D m_InitialLocation;
private readonly Map m_InitialMap;
private readonly InternalTimer m_Timer;
private double m_HonorDamage;
private int m_TotalDamage;
private int m_Perfection;
private FirstHit m_FirstHit;
private bool m_Poisoned;
public HonorContext(PlayerMobile source, Mobile target)
{
m_Source = source;
m_Target = target;
m_FirstHit = FirstHit.NotDelivered;
m_Poisoned = false;
m_InitialLocation = source.Location;
m_InitialMap = source.Map;
source.SentHonorContext = this;
((IHonorTarget)target).ReceivedHonorContext = this;
m_Timer = new InternalTimer(this);
m_Timer.Start();
source.m_hontime = (DateTime.UtcNow + TimeSpan.FromMinutes(40));
Timer.DelayCall(
TimeSpan.FromMinutes(40),
m =>
{
if (m.m_hontime < DateTime.UtcNow && m.SentHonorContext != null)
{
Cancel();
}
},
source);
}
private enum FirstHit
{
NotDelivered,
Delivered,
Granted
}
public PlayerMobile Source { get { return m_Source; } }
public Mobile Target { get { return m_Target; } }
public int PerfectionDamageBonus { get { return m_Perfection; } }
public int PerfectionLuckBonus { get { return (m_Perfection * m_Perfection) / 10; } }
public void OnSourceDamaged(Mobile from, int amount)
{
if (from != m_Target)
return;
if (m_FirstHit == FirstHit.NotDelivered)
m_FirstHit = FirstHit.Granted;
}
public void OnTargetPoisoned()
{
m_Poisoned = true; // Set this flag for OnTargetDamaged which will be called next
}
public void OnTargetDamaged(Mobile from, int amount)
{
if (m_FirstHit == FirstHit.NotDelivered)
m_FirstHit = FirstHit.Delivered;
if (m_Poisoned)
{
m_HonorDamage += amount * 0.8;
m_Poisoned = false; // Reset the flag
return;
}
m_TotalDamage += amount;
if (from == m_Source)
{
if (m_Target.CanSee(m_Source) && m_Target.InLOS(m_Source) &&
(m_Source.InRange(m_Target, 1) || (m_Source.Location == m_InitialLocation && m_Source.Map == m_InitialMap)))
{
m_HonorDamage += amount;
}
else
{
m_HonorDamage += amount * 0.8;
}
}
else if (from is BaseCreature && ((BaseCreature)from).GetMaster() == m_Source)
{
m_HonorDamage += amount * 0.8;
}
}
public void OnTargetHit(Mobile from)
{
if (from != m_Source || m_Perfection == 100)
return;
var bushido = (int)from.Skills.Bushido.Value;
if (bushido < 50)
return;
var damagebonus = bushido / 10;
m_Perfection += damagebonus;
if (m_Perfection >= 100)
{
m_Perfection = 100;
m_Source.SendLocalizedMessage(1063254); // You have Achieved Perfection in inflicting damage to this opponent!
BuffInfo.AddBuff(
m_Target,
new BuffInfo(
BuffIcon.AchievePerfection,
1075651,
1075652,
TimeSpan.FromSeconds(5),
from,
String.Format("{0}\t{1}", m_Perfection, from.Name)));
}
else
{
m_Source.SendLocalizedMessage(1063255); // You gain in Perfection as you precisely strike your opponent.
BuffInfo.AddBuff(
from,
new BuffInfo(BuffIcon.Perfection, 1153786, 1151394, String.Format("{0}\t{1}", m_Target.Name, m_Perfection)));
}
}
public void OnTargetMissed(Mobile from)
{
BuffInfo.RemoveBuff(from, BuffIcon.Perfection);
if (from != m_Source || m_Perfection == 0)
return;
m_Perfection -= 25;
if (m_Perfection <= 0)
{
m_Perfection = 0;
m_Source.SendLocalizedMessage(1063256); // You have lost all Perfection in fighting this opponent.
}
else
{
m_Source.SendLocalizedMessage(1063257); // You have lost some Perfection in fighting this opponent.
}
}
public void OnSourceBeneficialAction(Mobile to)
{
if (to != m_Target)
return;
BuffInfo.RemoveBuff(m_Source, BuffIcon.Perfection);
if (m_Perfection >= 0)
{
m_Perfection = 0;
m_Source.SendLocalizedMessage(1063256); // You have lost all Perfection in fighting this opponent.
}
}
public void OnSourceKilled()
{ }
public void OnTargetKilled()
{
Cancel();
var targetFame = m_Target.Fame;
if (m_Perfection > 0)
{
var restore = Math.Min(m_Perfection * (targetFame + 5000) / 25000, 10);
m_Source.Hits += restore;
m_Source.Stam += restore;
m_Source.Mana += restore;
}
if (m_Source.Virtues.Honor > targetFame)
return;
var dGain = (targetFame / 100) * (m_HonorDamage / m_TotalDamage); //Initial honor gain is 100th of the monsters honor
if (m_HonorDamage == m_TotalDamage && m_FirstHit == FirstHit.Granted)
dGain = dGain * 1.5; //honor gain is increased alot more if the combat was fully honorable
else
dGain = dGain * 0.9;
var gain = Math.Min((int)dGain, 200);
if (gain < 1)
gain = 1; // Minimum gain of 1 honor when the honor is under the monsters fame
if (VirtueHelper.IsHighestPath(m_Source, VirtueName.Honor))
{
m_Source.SendLocalizedMessage(1063228); // You cannot gain more Honor.
return;
}
var gainedPath = false;
if (VirtueHelper.Award(m_Source, VirtueName.Honor, gain, ref gainedPath))
{
if (gainedPath)
m_Source.SendLocalizedMessage(1063226); // You have gained a path in Honor!
else
m_Source.SendLocalizedMessage(1063225); // You have gained in Honor.
}
}
public bool CheckDistance()
{
return true;
}
public void Cancel()
{
m_Source.SentHonorContext = null;
((IHonorTarget)m_Target).ReceivedHonorContext = null;
m_Timer.Stop();
BuffInfo.RemoveBuff(m_Source, BuffIcon.Perfection);
BuffInfo.RemoveBuff(m_Source, BuffIcon.Honored);
}
private class InternalTimer : Timer
{
private readonly HonorContext m_Context;
public InternalTimer(HonorContext context)
: base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0))
{
m_Context = context;
}
protected override void OnTick()
{
m_Context.CheckDistance();
}
}
}
}

View File

@@ -0,0 +1,364 @@
#region References
using System;
using System.Collections.Generic;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
#endregion
namespace Server.Services.Virtues
{
public class HumilityVirtue
{
public static Dictionary<Mobile, HumilityHuntContext> HuntTable { get; set; }
public static Dictionary<Mobile, Mobile> ActiveTable { get; set; }
public static void Initialize()
{
HuntTable = new Dictionary<Mobile, HumilityHuntContext>();
ActiveTable = new Dictionary<Mobile, Mobile>();
VirtueGump.Register(108, OnVirtueUsed);
EventSink.Speech += EventSink_Speech;
}
public static void EventSink_Speech(SpeechEventArgs e)
{
var speech = e.Speech;
if (speech.IndexOf("lum lum lum", StringComparison.OrdinalIgnoreCase) >= 0)
{
HumilityHunt(e.Mobile);
}
}
public static void OnVirtueUsed(Mobile from)
{
if (VirtueHelper.GetLevel(from, VirtueName.Humility) < VirtueLevel.Seeker)
from.SendLocalizedMessage(1155812); // You must be at least a Seeker of Humility to Invoke this ability.
else if (from.Alive)
{
from.SendLocalizedMessage(1155817); // Target the pet you wish to embrace with your Humility.
from.BeginTarget(
10,
false,
TargetFlags.None,
(m, targeted) =>
{
if (targeted is BaseCreature)
{
var bc = (BaseCreature)targeted;
if (!bc.Alive)
{
from.SendLocalizedMessage(1155815); // You cannot embrace Humility on the dead!
}
else if (VirtueHelper.GetLevel(m, VirtueName.Humility) < VirtueLevel.Seeker)
{
from.SendLocalizedMessage(1155812); // You must be at least a Seeker of Humility to Invoke this ability.
}
else if (!bc.Controlled && !bc.Summoned)
{
from.SendLocalizedMessage(1155813); // You can only embrace your Humility on a pet.
}
else if (ActiveTable.ContainsKey(bc))
{
from.SendLocalizedMessage(1156047); // That pet has already embraced Humility.
}
else
{
VirtueHelper.Atrophy(from, VirtueName.Humility, 3200);
from.SendLocalizedMessage(1155818); // You have lost some Humility.
ActiveTable[bc] = from;
m.PrivateOverheadMessage(
MessageType.Regular,
1150,
1155819,
from.NetState); // *Your pet surges with the power of your Humility!*
bc.FixedEffect(0x373A, 10, 16);
BuffInfo.AddBuff(
from,
new BuffInfo(
BuffIcon.Humility,
1156049,
1156050,
TimeSpan.FromMinutes(20),
from,
String.Format("{0}\t{1}", bc.Name, GetRegenBonus(bc)))); // Pet: ~1_NAME~<br>+~2_VAL~ HPR<br>
CheckTimer();
bc.ResetStatTimers();
Timer.DelayCall(
TimeSpan.FromMinutes(20),
mob =>
{
if (mob != null && ActiveTable.ContainsKey(mob))
{
var user = ActiveTable[mob];
ActiveTable.Remove(mob);
BuffInfo.RemoveBuff(user, BuffIcon.Humility);
user.PrivateOverheadMessage(
MessageType.Regular,
1150,
1155823,
from.NetState); // *Your pet's power returns to normal*
CheckTimer();
}
},
bc);
}
}
else
{
from.SendLocalizedMessage(1155813); // You can only embrace your Humility on a pet.
}
});
}
}
private static Timer _Timer;
public static void CheckTimer()
{
if (ActiveTable == null || ActiveTable.Count == 0)
{
if (_Timer != null)
{
_Timer.Stop();
_Timer = null;
}
}
else
{
if (_Timer == null)
{
_Timer = Timer.DelayCall(
TimeSpan.FromSeconds(3),
TimeSpan.FromSeconds(3),
() =>
{
foreach (var mob in ActiveTable.Keys)
{
mob.FixedParticles(0x376A, 9, 32, 5005, EffectLayer.Waist);
}
});
_Timer.Start();
}
}
}
public static int GetRegenBonus(Mobile mobile)
{
if (ActiveTable == null || !ActiveTable.ContainsKey(mobile))
return 0;
var user = ActiveTable[mobile];
if (user != null)
{
if (VirtueHelper.IsKnight(user, VirtueName.Humility))
return 30;
if (VirtueHelper.IsFollower(user, VirtueName.Humility))
return 20;
if (VirtueHelper.IsSeeker(user, VirtueName.Humility))
return 10;
}
return 0;
}
public static void HumilityHunt(Mobile from)
{
if (!from.Alive)
return;
if (HuntTable.ContainsKey(from))
{
if (!HuntTable[from].Expiring)
{
HuntTable[from].Expiring = true;
from.SendLocalizedMessage(1155800); // You have ended your journey on the Path of Humility.
}
else
from.SendLocalizedMessage(
1155796); // You have already ended your journey on the Path of Humility. You must wait before you restart your path.
}
else
{
var pm = from as PlayerMobile;
if (pm != null)
{
HuntTable[pm] = new HumilityHuntContext(pm, new List<Mobile>(pm.AllFollowers));
pm.SendLocalizedMessage(
1155802,
"70"); // You have begun your journey on the Path of Humility. Your resists have been debuffed by ~1_DEBUFF~.
pm.SendLocalizedMessage(
1155858); // You are now on a Humility Hunt. For each kill while you forgo the protection of resists," you shall continue on your path to Humility. You may end your Hunt by speaking ""Lum Lum Lum"" at any time.
BuffInfo.AddBuff(pm, new BuffInfo(BuffIcon.HumilityDebuff, 1025327, 1155806, "70"));
}
}
}
public static void RegisterKill(Mobile attacker, BaseCreature killed, int count)
{
var points = Math.Min(60, Math.Max(1, (killed.Fame / 5000) * 10)) / count;
if (attacker != null && HuntTable.ContainsKey(attacker))
{
var gainedPath = false;
if (VirtueHelper.Award(attacker, VirtueName.Humility, points, ref gainedPath))
{
if (gainedPath)
attacker.SendLocalizedMessage(1155811); // You have gained a path in Humility!
else
attacker.SendLocalizedMessage(1155809); // You have gained in Humility!
}
else
attacker.SendLocalizedMessage(1155808); // You cannot gain more Humility.
}
}
public static bool IsInHunt(Mobile m)
{
return HuntTable != null && HuntTable.ContainsKey(m);
}
public static bool IsInHunt(PlayerMobile pm)
{
return HuntTable.ContainsKey(pm);
}
public static void TryAddPetToHunt(Mobile owner, Mobile pet)
{
if (HuntTable.ContainsKey(owner))
{
if (pet is BaseCreature && ((BaseCreature)pet).GetMaster() == owner)
{
HuntTable[owner].AddPet(pet);
}
}
}
public static void OnHuntExpired(Mobile m)
{
Timer.DelayCall(
TimeSpan.FromSeconds(60),
() =>
{
if (HuntTable.ContainsKey(m))
HuntTable.Remove(m);
});
}
public class HumilityHuntContext
{
public Mobile Owner { get; set; }
public Dictionary<Mobile, ResistanceMod[]> Table;
private bool _Expiring;
public ResistanceMod[] GetMod
{
get
{
return new[]
{
new ResistanceMod(ResistanceType.Physical, -70), new ResistanceMod(ResistanceType.Fire, -70),
new ResistanceMod(ResistanceType.Poison, -70), new ResistanceMod(ResistanceType.Cold, -70),
new ResistanceMod(ResistanceType.Energy, -70)
};
}
}
public bool Expiring
{
get { return _Expiring; }
set
{
if (!_Expiring && value)
{
Timer.DelayCall(TimeSpan.FromSeconds(30), DoExpire);
}
_Expiring = value;
}
}
public HumilityHuntContext(Mobile owner, List<Mobile> pets)
{
Owner = owner;
Table = new Dictionary<Mobile, ResistanceMod[]>();
var mod = GetMod;
owner.FixedEffect(0x373A, 10, 16);
foreach (var mods in mod)
owner.AddResistanceMod(mods);
Table[owner] = mod;
pets.ForEach(
m =>
{
mod = GetMod;
foreach (var mods in mod)
m.AddResistanceMod(mods);
m.FixedEffect(0x373A, 10, 16);
Table[m] = mod;
});
}
public void AddPet(Mobile pet)
{
if (!_Expiring && !Table.ContainsKey(pet))
{
var mod = GetMod;
pet.FixedEffect(0x373A, 10, 16);
foreach (var mods in mod)
pet.AddResistanceMod(mods);
Table[pet] = mod;
}
}
private void DoExpire()
{
foreach (var kvp in Table)
{
foreach (var mod in kvp.Value)
kvp.Key.RemoveResistanceMod(mod);
BuffInfo.RemoveBuff(kvp.Key, BuffIcon.HumilityDebuff);
}
Table.Clear();
OnHuntExpired(Owner);
}
}
}
}

View File

@@ -0,0 +1,258 @@
#region References
using System;
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
#endregion
namespace Server.Services.Virtues
{
public class JusticeVirtue
{
private static readonly TimeSpan LossDelay = TimeSpan.FromDays(7.0);
private const int LossAmount = 950;
public static void Initialize()
{
VirtueGump.Register(109, OnVirtueUsed);
}
public static bool CheckMapRegion(Mobile first, Mobile second)
{
var map = first.Map;
if (second.Map != map)
return false;
return GetMapRegion(map, first.Location) == GetMapRegion(map, second.Location);
}
public static int GetMapRegion(Map map, Point3D loc)
{
if (map == null || map.MapID >= 2)
return 0;
if (loc.X < 5120)
return 0;
if (loc.Y < 2304)
return 1;
return 2;
}
public static void OnVirtueUsed(Mobile from)
{
if (!from.CheckAlive())
return;
var protector = from as PlayerMobile;
if (protector == null)
return;
if (!VirtueHelper.IsSeeker(protector, VirtueName.Justice))
{
protector.SendLocalizedMessage(1049610); // You must reach the first path in this virtue to invoke it.
}
else if (!protector.CanBeginAction(typeof(JusticeVirtue)))
{
protector.SendLocalizedMessage(1049370); // You must wait a while before offering your protection again.
}
else if (protector.JusticeProtectors.Count > 0)
{
protector.SendLocalizedMessage(1049542); // You cannot protect someone while being protected.
}
else if (protector.Map != Map.Felucca)
{
protector.SendLocalizedMessage(1049372); // You cannot use this ability here.
}
else
{
protector.BeginTarget(14, false, TargetFlags.None, OnVirtueTargeted);
protector.SendLocalizedMessage(1049366); // Choose the player you wish to protect.
}
}
public static void OnVirtueTargeted(Mobile from, object obj)
{
var protector = from as PlayerMobile;
var pm = obj as PlayerMobile;
if (protector == null)
return;
if (!VirtueHelper.IsSeeker(protector, VirtueName.Justice))
protector.SendLocalizedMessage(1049610); // You must reach the first path in this virtue to invoke it.
else if (!protector.CanBeginAction(typeof(JusticeVirtue)))
protector.SendLocalizedMessage(1049370); // You must wait a while before offering your protection again.
else if (protector.JusticeProtectors.Count > 0)
protector.SendLocalizedMessage(1049542); // You cannot protect someone while being protected.
else if (protector.Map != Map.Felucca)
protector.SendLocalizedMessage(1049372); // You cannot use this ability here.
else if (pm == null)
protector.SendLocalizedMessage(1049678); // Only players can be protected.
else if (pm.Map != Map.Felucca)
protector.SendLocalizedMessage(1049372); // You cannot use this ability here.
else if (pm == protector || pm.Criminal || pm.Murderer)
protector.SendLocalizedMessage(1049436); // That player cannot be protected.
else if (pm.JusticeProtectors.Count > 0)
protector.SendLocalizedMessage(1049369); // You cannot protect that player right now.
else if (pm.HasGump(typeof(AcceptProtectorGump)))
protector.SendLocalizedMessage(1049369); // You cannot protect that player right now.
else
pm.SendGump(new AcceptProtectorGump(protector, pm));
}
public static void OnVirtueAccepted(PlayerMobile protector, PlayerMobile protectee)
{
if (!VirtueHelper.IsSeeker(protector, VirtueName.Justice))
{
protector.SendLocalizedMessage(1049610); // You must reach the first path in this virtue to invoke it.
}
else if (!protector.CanBeginAction(typeof(JusticeVirtue)))
{
protector.SendLocalizedMessage(1049370); // You must wait a while before offering your protection again.
}
else if (protector.JusticeProtectors.Count > 0)
{
protector.SendLocalizedMessage(1049542); // You cannot protect someone while being protected.
}
else if (protector.Map != Map.Felucca)
{
protector.SendLocalizedMessage(1049372); // You cannot use this ability here.
}
else if (protectee.Map != Map.Felucca)
{
protector.SendLocalizedMessage(1049372); // You cannot use this ability here.
}
else if (protectee == protector || protectee.Criminal || protectee.Murderer)
{
protector.SendLocalizedMessage(1049436); // That player cannot be protected.
}
else if (protectee.JusticeProtectors.Count > 0)
{
protector.SendLocalizedMessage(1049369); // You cannot protect that player right now.
}
else
{
protectee.JusticeProtectors.Add(protector);
var args = String.Format("{0}\t{1}", protector.Name, protectee.Name);
protectee.SendLocalizedMessage(1049451, args); // You are now being protected by ~1_NAME~.
protector.SendLocalizedMessage(1049452, args); // You are now protecting ~2_NAME~.
}
}
public static void OnVirtueRejected(PlayerMobile protector, PlayerMobile protectee)
{
var args = String.Format("{0}\t{1}", protector.Name, protectee.Name);
protectee.SendLocalizedMessage(1049453, args); // You have declined protection from ~1_NAME~.
protector.SendLocalizedMessage(1049454, args); // ~2_NAME~ has declined your protection.
if (protector.BeginAction(typeof(JusticeVirtue)))
Timer.DelayCall(TimeSpan.FromMinutes(15.0), RejectDelay_Callback, protector);
}
public static void RejectDelay_Callback(PlayerMobile state)
{
if (state != null)
state.EndAction(typeof(JusticeVirtue));
}
public static void CheckAtrophy(Mobile from)
{
var pm = from as PlayerMobile;
if (pm == null)
return;
try
{
if ((pm.LastJusticeLoss + LossDelay) < DateTime.UtcNow)
{
if (VirtueHelper.Atrophy(from, VirtueName.Justice, LossAmount))
from.SendLocalizedMessage(1049373); // You have lost some Justice.
pm.LastJusticeLoss = DateTime.UtcNow;
}
}
catch
{ }
}
}
public class AcceptProtectorGump : Gump
{
private readonly PlayerMobile m_Protector;
private readonly PlayerMobile m_Protectee;
public AcceptProtectorGump(PlayerMobile protector, PlayerMobile protectee)
: base(150, 50)
{
m_Protector = protector;
m_Protectee = protectee;
Closable = false;
AddPage(0);
AddBackground(0, 0, 396, 218, 3600);
AddImageTiled(15, 15, 365, 190, 2624);
AddAlphaRegion(15, 15, 365, 190);
AddHtmlLocalized(
30,
20,
360,
25,
1049365,
0x7FFF,
false,
false); // Another player is offering you their <a href="?ForceTopic88">protection</a>:
AddLabel(90, 55, 1153, protector.Name);
AddImage(50, 45, 9005);
AddImageTiled(80, 80, 200, 1, 9107);
AddImageTiled(95, 82, 200, 1, 9157);
AddRadio(30, 110, 9727, 9730, true, 1);
AddHtmlLocalized(65, 115, 300, 25, 1049444, 0x7FFF, false, false); // Yes, I would like their protection.
AddRadio(30, 145, 9727, 9730, false, 0);
AddHtmlLocalized(65, 148, 300, 25, 1049445, 0x7FFF, false, false); // No thanks, I can take care of myself.
AddButton(160, 175, 247, 248, 2, GumpButtonType.Reply, 0);
AddImage(215, 0, 50581);
AddImageTiled(15, 14, 365, 1, 9107);
AddImageTiled(380, 14, 1, 190, 9105);
AddImageTiled(15, 205, 365, 1, 9107);
AddImageTiled(15, 14, 1, 190, 9105);
AddImageTiled(0, 0, 395, 1, 9157);
AddImageTiled(394, 0, 1, 217, 9155);
AddImageTiled(0, 216, 395, 1, 9157);
AddImageTiled(0, 0, 1, 217, 9155);
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (info.ButtonID == 2)
{
var okay = info.IsSwitched(1);
if (okay)
JusticeVirtue.OnVirtueAccepted(m_Protector, m_Protectee);
else
JusticeVirtue.OnVirtueRejected(m_Protector, m_Protectee);
}
}
}
}

View File

@@ -0,0 +1,197 @@
#region References
using System;
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
#endregion
namespace Server.Services.Virtues
{
public class SacrificeVirtue
{
private static readonly TimeSpan GainDelay = TimeSpan.FromDays(1.0);
private static readonly TimeSpan LossDelay = TimeSpan.FromDays(7.0);
private const int LossAmount = 500;
public static void Initialize()
{
VirtueGump.Register(110, OnVirtueUsed);
}
public static void OnVirtueUsed(Mobile from)
{
if (!from.Hidden)
{
if (from.Alive)
from.Target = new InternalTarget();
else
Resurrect(from);
}
else
from.SendLocalizedMessage(1052015); // You cannot do that while hidden.
}
public static void CheckAtrophy(Mobile from)
{
var pm = from as PlayerMobile;
if (pm == null)
return;
try
{
if ((pm.LastSacrificeLoss + LossDelay) < DateTime.UtcNow)
{
if (VirtueHelper.Atrophy(from, VirtueName.Sacrifice, LossAmount))
from.SendLocalizedMessage(1052041); // You have lost some Sacrifice.
var level = VirtueHelper.GetLevel(from, VirtueName.Sacrifice);
pm.AvailableResurrects = (int)level;
pm.LastSacrificeLoss = DateTime.UtcNow;
}
}
catch
{ }
}
public static void Resurrect(Mobile from)
{
if (from.Alive)
return;
var pm = from as PlayerMobile;
if (pm == null)
return;
if (from.Criminal)
{
from.SendLocalizedMessage(1052007); // You cannot use this ability while flagged as a criminal.
}
else if (!VirtueHelper.IsSeeker(from, VirtueName.Sacrifice))
{
from.SendLocalizedMessage(1052004); // You cannot use this ability.
}
else if (pm.AvailableResurrects <= 0)
{
from.SendLocalizedMessage(1052005); // You do not have any resurrections left.
}
else
{
/*
* We need to wait for them to accept the gump or they can just use
* Sacrifice and cancel to have items in their backpack for free.
*/
from.CloseGump(typeof(ResurrectGump));
from.SendGump(new ResurrectGump(from, true));
}
}
public static void Sacrifice(Mobile from, object targeted)
{
if (!from.CheckAlive())
return;
var pm = from as PlayerMobile;
if (pm == null)
return;
var targ = targeted as Mobile;
if (targ == null)
return;
if (!ValidateCreature(targ))
{
from.SendLocalizedMessage(1052014); // You cannot sacrifice your fame for that creature.
}
else if (((targ.Hits * 100) / Math.Max(targ.HitsMax, 1)) < 90)
{
from.SendLocalizedMessage(1052013); // You cannot sacrifice for this monster because it is too damaged.
}
else if (from.Hidden)
{
from.SendLocalizedMessage(1052015); // You cannot do that while hidden.
}
else if (VirtueHelper.IsHighestPath(from, VirtueName.Sacrifice))
{
from.SendLocalizedMessage(1052068); // You have already attained the highest path in this virtue.
}
else if (from.Fame < 2500)
{
from.SendLocalizedMessage(1052017); // You do not have enough fame to sacrifice.
}
else if (DateTime.UtcNow < (pm.LastSacrificeGain + GainDelay))
{
from.SendLocalizedMessage(1052016); // You must wait approximately one day before sacrificing again.
}
else
{
int toGain;
if (from.Fame < 5000)
toGain = 500;
else if (from.Fame < 10000)
toGain = 1000;
else
toGain = 2000;
from.Fame = 0;
// I have seen the error of my ways!
targ.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1052009);
from.SendLocalizedMessage(1052010); // You have set the creature free.
Timer.DelayCall(TimeSpan.FromSeconds(1.0), targ.Delete);
pm.LastSacrificeGain = DateTime.UtcNow;
var gainedPath = false;
if (VirtueHelper.Award(from, VirtueName.Sacrifice, toGain, ref gainedPath))
{
if (gainedPath)
{
from.SendLocalizedMessage(1052008); // You have gained a path in Sacrifice!
if (pm.AvailableResurrects < 3)
++pm.AvailableResurrects;
}
else
{
from.SendLocalizedMessage(1054160); // You have gained in sacrifice.
}
}
from.SendLocalizedMessage(1052016); // You must wait approximately one day before sacrificing again.
}
}
public static bool ValidateCreature(Mobile m)
{
if (m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned))
return false;
return (m is Lich || m is Succubus || m is Daemon || m is EvilMage || m is EnslavedGargoyle ||
m is GargoyleEnforcer);
}
private class InternalTarget : Target
{
public InternalTarget()
: base(8, false, TargetFlags.None)
{ }
protected override void OnTarget(Mobile from, object targeted)
{
Sacrifice(from, targeted);
}
}
}
}

View File

@@ -0,0 +1,238 @@
#region References
using System;
using System.Collections.Generic;
using Server.Mobiles;
using Server.Targeting;
#endregion
namespace Server.Services.Virtues
{
public class SpiritualityVirtue
{
public static Dictionary<Mobile, SpiritualityContext> ActiveTable { get; set; }
public static void Initialize()
{
ActiveTable = new Dictionary<Mobile, SpiritualityContext>();
VirtueGump.Register(111, OnVirtueUsed);
}
public static void OnVirtueUsed(Mobile from)
{
if (!from.Alive)
return;
if (VirtueHelper.GetLevel(from, VirtueName.Spirituality) < VirtueLevel.Seeker)
from.SendLocalizedMessage(1155829); // You must be a Seeker of Spirituality to invoke this Virtue.
else
{
from.SendLocalizedMessage(1155827); // Target whom you wish to embrace with your Spirituality
from.BeginTarget(
10,
false,
TargetFlags.None,
(mobile, targeted) =>
{
if (targeted is Mobile)
{
var m = (Mobile)targeted;
if (VirtueHelper.GetLevel(from, VirtueName.Spirituality) < VirtueLevel.Seeker)
{
from.SendLocalizedMessage(1155812); // You must be at least a Seeker of Humility to Invoke this ability.
}
else if (!m.Alive)
{
from.SendLocalizedMessage(1155828); // Thy target must be among the living.
}
else if (m is BaseCreature && !((BaseCreature)m).Controlled && !((BaseCreature)m).Summoned)
{
from.SendLocalizedMessage(1155837); // You can only embrace players and pets with Spirituality.
}
else if (IsEmbracee(m))
{
from.SendLocalizedMessage(1155836); // They are already embraced by Spirituality.
}
else if (m.MeleeDamageAbsorb > 0)
{
from.SendLocalizedMessage(
1156039); // You may not use the Spirituality Virtue while the Attunement spell is active.
}
else if (m is BaseCreature || m is PlayerMobile)
{
var context = new SpiritualityContext(from, m);
ActiveTable[from] = context;
m.SendLocalizedMessage(1155839); // Your spirit has been embraced! You feel more powerful!
from.SendLocalizedMessage(1155835); // You have lost some Spirituality.
BuffInfo.AddBuff(
m,
new BuffInfo(
BuffIcon.Spirituality,
1155824,
1155825,
String.Format(
"{0}\t{1}",
context.Reduction.ToString(),
context.Pool.ToString()))); // ~1_VAL~% Reduction to Incoming Damage<br>~2_VAL~ Shield HP Remaining
VirtueHelper.Atrophy(from, VirtueName.Spirituality, 3200);
Timer.DelayCall(
TimeSpan.FromMinutes(20),
() =>
{
if (ActiveTable != null && ActiveTable.ContainsKey(from))
{
ActiveTable.Remove(from);
m.SendLocalizedMessage(1155840); // Your spirit is no longer embraced. You feel less powerful.
BuffInfo.RemoveBuff(m, BuffIcon.Spirituality);
}
});
}
}
else
from.SendLocalizedMessage(1155837); // You can only embrace players and pets with Spirituality.
});
}
}
public static bool IsEmbracee(Mobile m)
{
if (ActiveTable == null)
return false;
return GetContext(m) != null;
}
public static bool IsEmbracer(Mobile m)
{
if (ActiveTable == null)
return false;
return ActiveTable.ContainsKey(m);
}
public static SpiritualityContext GetContext(Mobile m)
{
if (ActiveTable == null)
return null;
foreach (var context in ActiveTable.Values)
{
if (context.Mobile == m)
return context;
}
return null;
}
public static void GetDamageReduction(Mobile victim, ref int damage)
{
if (ActiveTable == null)
return;
var context = GetContext(victim);
if (context != null)
{
var reduction = context.Reduction / 100.0;
damage = (int)(damage - (damage * reduction));
context.Pool -= damage;
victim.FixedEffect(0x373A, 10, 16);
BuffInfo.RemoveBuff(victim, BuffIcon.Spirituality);
if (context.Pool <= 0)
{
victim.SendLocalizedMessage(1155840); // Your spirit is no longer embraced. You feel less powerful.
if (ActiveTable.ContainsKey(victim) && ActiveTable[victim] == context)
{
ActiveTable.Remove(victim);
}
}
else
BuffInfo.AddBuff(
victim,
new BuffInfo(
BuffIcon.Spirituality,
1155824,
1155825,
String.Format(
"{0}\t{1}",
context.Reduction,
context.Pool))); // ~1_VAL~% Reduction to Incoming Damage<br>~2_VAL~ Shield HP Remaining
}
}
public static void OnHeal(Mobile mobile, int amount)
{
var points = Math.Min(50, amount);
var gainedPath = false;
if (VirtueHelper.Award(mobile, VirtueName.Spirituality, points, ref gainedPath))
{
if (gainedPath)
mobile.SendLocalizedMessage(1155833); // You have gained a path in Spirituality!
else
mobile.SendLocalizedMessage(1155832); // You have gained in Spirituality.
}
else
mobile.SendLocalizedMessage(1155831); // You cannot gain more Spirituality.
}
public class SpiritualityContext
{
public Mobile Mobile { get; set; }
public Mobile Protector { get; set; }
public int Pool { get; set; }
public int Reduction { get; set; }
public SpiritualityContext(Mobile protector, Mobile m)
{
Protector = protector;
Mobile = m;
Pool = GetPool(protector);
Reduction = GetReduction(protector);
}
private static int GetPool(Mobile user)
{
if (VirtueHelper.IsKnight(user, VirtueName.Spirituality))
return 200;
if (VirtueHelper.IsFollower(user, VirtueName.Spirituality))
return 100;
if (VirtueHelper.IsSeeker(user, VirtueName.Spirituality))
return 50;
return 0;
}
public static int GetReduction(Mobile m)
{
if (VirtueHelper.IsKnight(m, VirtueName.Spirituality))
return 20;
if (VirtueHelper.IsFollower(m, VirtueName.Spirituality))
return 10;
if (VirtueHelper.IsSeeker(m, VirtueName.Spirituality))
return 5;
return 0;
}
}
}
}

View File

@@ -0,0 +1,143 @@
#region References
using System;
using Server.Engines.CannedEvil;
using Server.Mobiles;
using Server.Targeting;
#endregion
namespace Server.Services.Virtues
{
public class ValorVirtue
{
private static readonly TimeSpan LossDelay = TimeSpan.FromDays(7.0);
private const int LossAmount = 250;
public static void Initialize()
{
VirtueGump.Register(112, OnVirtueUsed);
}
public static void OnVirtueUsed(Mobile from)
{
if (from.Alive)
{
from.SendLocalizedMessage(1054034); // Target the Champion Idol of the Champion you wish to challenge!.
from.Target = new InternalTarget();
}
}
public static void CheckAtrophy(Mobile from)
{
var pm = from as PlayerMobile;
if (pm == null)
return;
try
{
if ((pm.LastValorLoss + LossDelay) < DateTime.UtcNow)
{
if (VirtueHelper.Atrophy(from, VirtueName.Valor, LossAmount))
from.SendLocalizedMessage(1054040); // You have lost some Valor.
pm.LastValorLoss = DateTime.UtcNow;
}
}
catch
{ }
}
public static void Valor(Mobile from, object targ)
{
var idol = targ as IdolOfTheChampion;
if (idol == null || idol.Deleted || idol.Spawn == null || idol.Spawn.Deleted)
from.SendLocalizedMessage(1054035); // You must target a Champion Idol to challenge the Champion's spawn!
else if (from.Hidden)
from.SendLocalizedMessage(1052015); // You cannot do that while hidden.
else if (idol.Spawn.HasBeenAdvanced)
from.SendLocalizedMessage(1054038); // The Champion of this region has already been challenged!
else
{
var vl = VirtueHelper.GetLevel(from, VirtueName.Valor);
if (idol.Spawn.Active)
{
if (idol.Spawn.Champion != null) //TODO: Message?
return;
int needed, consumed;
switch (idol.Spawn.Rank)
{
case 0:
{
needed = consumed = 2500;
break;
}
case 1:
{
needed = consumed = 5000;
break;
}
case 2:
{
needed = 10000;
consumed = 7500;
break;
}
default:
{
needed = 20000;
consumed = 10000;
break;
}
}
if (from.Virtues.GetValue((int)VirtueName.Valor) >= needed)
{
VirtueHelper.Atrophy(from, VirtueName.Valor, consumed);
from.SendLocalizedMessage(1054037); // Your challenge is heard by the Champion of this region! Beware its wrath!
idol.Spawn.HasBeenAdvanced = true;
idol.Spawn.AdvanceLevel();
}
else
from.SendLocalizedMessage(
1054039); // The Champion of this region ignores your challenge. You must further prove your valor.
}
else
{
if (vl == VirtueLevel.Knight)
{
VirtueHelper.Atrophy(from, VirtueName.Valor, 11000);
from.SendLocalizedMessage(1054037); // Your challenge is heard by the Champion of this region! Beware its wrath!
idol.Spawn.EndRestart();
//idol.Spawn.HasBeenAdvanced = true;
}
else
{
from.SendLocalizedMessage(
1054036); // You must be a Knight of Valor to summon the champion's spawn in this manner!
}
}
}
}
private class InternalTarget : Target
{
public InternalTarget()
: base(14, false, TargetFlags.None)
{ }
protected override void OnTarget(Mobile from, object targeted)
{
Valor(from, targeted);
}
}
}
}

View File

@@ -0,0 +1,181 @@
#region References
using System;
using System.Collections;
using Server.Gumps;
using Server.Network;
#endregion
namespace Server.Services.Virtues
{
public delegate void OnVirtueUsed(Mobile from);
public class VirtueGump : Gump
{
private static readonly Hashtable m_Callbacks = new Hashtable();
private static readonly int[] m_Table = new int[24]
{
0x0481, 0x0963, 0x0965, 0x060A, 0x060F, 0x002A, 0x08A4, 0x08A7, 0x0034, 0x0965, 0x08FD, 0x0480, 0x00EA, 0x0845,
0x0020, 0x0011, 0x0269, 0x013D, 0x08A1, 0x08A3, 0x0042, 0x0543, 0x0547, 0x0061
};
private readonly Mobile m_Beholder;
private readonly Mobile m_Beheld;
public VirtueGump(Mobile beholder, Mobile beheld)
: base(0, 0)
{
m_Beholder = beholder;
m_Beheld = beheld;
Serial = beheld.Serial;
AddPage(0);
AddImage(30, 40, 104);
AddPage(1);
Add(new InternalEntry(61, 71, 108, GetHueFor(0))); // Humility
Add(new InternalEntry(123, 46, 112, GetHueFor(4))); // Valor
Add(new InternalEntry(187, 70, 107, GetHueFor(5))); // Honor
Add(new InternalEntry(35, 135, 110, GetHueFor(1))); // Sacrifice
Add(new InternalEntry(211, 133, 105, GetHueFor(2))); // Compassion
Add(new InternalEntry(61, 195, 111, GetHueFor(3))); // Spiritulaity
Add(new InternalEntry(186, 195, 109, GetHueFor(6))); // Justice
Add(new InternalEntry(121, 221, 106, GetHueFor(7))); // Honesty
if (m_Beholder == m_Beheld)
{
AddButton(57, 269, 2027, 2027, 1, GumpButtonType.Reply, 0);
AddButton(186, 269, 2071, 2071, 2, GumpButtonType.Reply, 0);
}
}
public static void Initialize()
{
EventSink.VirtueGumpRequest += EventSink_VirtueGumpRequest;
EventSink.VirtueItemRequest += EventSink_VirtueItemRequest;
EventSink.VirtueMacroRequest += EventSink_VirtueMacroRequest;
}
public static void Register(int gumpID, OnVirtueUsed callback)
{
m_Callbacks[gumpID] = callback;
}
public override void OnResponse(NetState state, RelayInfo info)
{
if (info.ButtonID == 1 && m_Beholder == m_Beheld)
m_Beholder.SendGump(new VirtueStatusGump(m_Beholder));
}
private static void EventSink_VirtueItemRequest(VirtueItemRequestEventArgs e)
{
if (e.Beholder != e.Beheld)
return;
e.Beholder.CloseGump(typeof(VirtueGump));
if (e.Beholder.Murderer)
{
e.Beholder.SendLocalizedMessage(1049609); // Murderers cannot invoke this virtue.
return;
}
var callback = (OnVirtueUsed)m_Callbacks[e.GumpID];
if (callback != null)
callback(e.Beholder);
else
e.Beholder.SendLocalizedMessage(1052066); // That virtue is not active yet.
}
private static void EventSink_VirtueMacroRequest(VirtueMacroRequestEventArgs e)
{
var virtueID = 0;
switch (e.VirtueID)
{
case 0: // Honor
virtueID = 107;
break;
case 1: // Sacrifice
virtueID = 110;
break;
case 2: // Valor;
virtueID = 112;
break;
}
EventSink_VirtueItemRequest(new VirtueItemRequestEventArgs(e.Mobile, e.Mobile, virtueID));
}
private static void EventSink_VirtueGumpRequest(VirtueGumpRequestEventArgs e)
{
var beholder = e.Beholder;
var beheld = e.Beheld;
if (beholder == beheld && beholder.Murderer)
{
beholder.SendLocalizedMessage(1049609); // Murderers cannot invoke this virtue.
}
else if (beholder.Map == beheld.Map && beholder.InRange(beheld, 12))
{
beholder.CloseGump(typeof(VirtueGump));
beholder.SendGump(new VirtueGump(beholder, beheld));
}
}
private int GetHueFor(int index)
{
if (m_Beheld.Virtues.GetValue(index) == 0)
return 2402;
var value = m_Beheld.Virtues.GetValue(index);
if (value < 4000)
return 2402;
if (value >= 30000)
value = 30000; //Sanity
int vl;
if (value < 10000)
vl = 0;
else if (value >= 20000 && index == 5)
vl = 2;
else if (value >= 21000 && index != 1)
vl = 2;
else if (value >= 22000 && index == 1)
vl = 2;
else
vl = 1;
return m_Table[(index * 3) + vl];
}
private class InternalEntry : GumpImage
{
private static readonly byte[] m_Class = StringToBuffer(" class=VirtueGumpItem");
public InternalEntry(int x, int y, int gumpID, int hue)
: base(x, y, gumpID, hue)
{ }
public override string Compile()
{
return String.Format("{{ gumppic {0} {1} {2} hue={3} class=VirtueGumpItem }}", X, Y, GumpID, Hue);
}
public override void AppendTo(IGumpWriter disp)
{
base.AppendTo(disp);
disp.AppendLayout(m_Class);
}
}
}
}

View File

@@ -0,0 +1,134 @@
#region References
using System;
using System.Linq;
using Server.Items;
#endregion
namespace Server.Services.Virtues
{
public enum VirtueLevel
{
None,
Seeker,
Follower,
Knight
}
public enum VirtueName
{
Humility,
Sacrifice,
Compassion,
Spirituality,
Valor,
Honor,
Justice,
Honesty
}
public class VirtueHelper
{
public static readonly VirtueName[] Virtues = //
Enum.GetValues(typeof(VirtueName)).Cast<VirtueName>().ToArray();
public static bool HasAny(Mobile from, VirtueName virtue)
{
return (from.Virtues.GetValue((int)virtue) > 0);
}
public static bool IsHighestPath(Mobile from, VirtueName virtue)
{
return (from.Virtues.GetValue((int)virtue) >= GetMaxAmount(virtue));
}
public static VirtueLevel GetLevel(Mobile from, VirtueName virtue)
{
var v = from.Virtues.GetValue((int)virtue);
int vl;
var vmax = GetMaxAmount(virtue);
if (v < 4000)
vl = 0;
else if (v >= vmax)
vl = 3;
else
vl = (v + 10000) / 10000;
return (VirtueLevel)vl;
}
public static int GetMaxAmount(VirtueName virtue)
{
if (virtue == VirtueName.Honor)
return 20000;
if (virtue == VirtueName.Sacrifice)
return 22000;
return 21000;
}
public static bool Award(Mobile from, VirtueName virtue, int amount, ref bool gainedPath)
{
var current = from.Virtues.GetValue((int)virtue);
var maxAmount = GetMaxAmount(virtue);
if (current >= maxAmount)
return false;
if (from.FindItemOnLayer(Layer.TwoHanded) is VirtueShield)
amount = amount + (int)(amount * 1.5);
if ((current + amount) >= maxAmount)
amount = maxAmount - current;
var oldLevel = GetLevel(from, virtue);
from.Virtues.SetValue((int)virtue, current + amount);
var newLevel = GetLevel(from, virtue);
gainedPath = (newLevel != oldLevel);
if (gainedPath)
{
EventSink.InvokeVirtueLevelChange(new VirtueLevelChangeEventArgs(from, (int)oldLevel, (int)newLevel, (int)virtue));
}
return true;
}
public static bool Atrophy(Mobile from, VirtueName virtue)
{
return Atrophy(from, virtue, 1);
}
public static bool Atrophy(Mobile from, VirtueName virtue, int amount)
{
var current = from.Virtues.GetValue((int)virtue);
if ((current - amount) >= 0)
from.Virtues.SetValue((int)virtue, current - amount);
else
from.Virtues.SetValue((int)virtue, 0);
return (current > 0);
}
public static bool IsSeeker(Mobile from, VirtueName virtue)
{
return (GetLevel(from, virtue) >= VirtueLevel.Seeker);
}
public static bool IsFollower(Mobile from, VirtueName virtue)
{
return (GetLevel(from, virtue) >= VirtueLevel.Follower);
}
public static bool IsKnight(Mobile from, VirtueName virtue)
{
return (GetLevel(from, virtue) >= VirtueLevel.Knight);
}
}
}

View File

@@ -0,0 +1,115 @@
#region References
using Server.Gumps;
using Server.Network;
#endregion
namespace Server.Services.Virtues
{
public class VirtueInfoGump : Gump
{
private readonly Mobile m_Beholder;
private readonly int m_Desc;
private readonly string m_Page;
private readonly VirtueName m_Virtue;
public VirtueInfoGump(Mobile beholder, VirtueName virtue, int description)
: this(beholder, virtue, description, null)
{ }
public VirtueInfoGump(Mobile beholder, VirtueName virtue, int description, string webPage)
: base(0, 0)
{
m_Beholder = beholder;
m_Virtue = virtue;
m_Desc = description;
m_Page = webPage;
var value = beholder.Virtues.GetValue((int)virtue);
AddPage(0);
AddImage(30, 40, 2080);
AddImage(47, 77, 2081);
AddImage(47, 147, 2081);
AddImage(47, 217, 2081);
AddImage(47, 267, 2083);
AddImage(70, 213, 2091);
AddPage(1);
var maxValue = VirtueHelper.GetMaxAmount(m_Virtue);
int valueDesc;
int dots;
if (value < 4000)
dots = value / 400;
else if (value < 10000)
dots = (value - 4000) / 600;
else if (value < maxValue)
dots = (value - 10000) / ((maxValue - 10000) / 10);
else
dots = 10;
for (var i = 0; i < 10; ++i)
AddImage(95 + (i * 17), 50, i < dots ? 2362 : 2360);
if (value < 1)
valueDesc = 1052044; // You have not started on the path of this Virtue.
else if (value < 400)
valueDesc = 1052045; // You have barely begun your journey through the path of this Virtue.
else if (value < 2000)
valueDesc = 1052046; // You have progressed in this Virtue, but still have much to do.
else if (value < 3600)
valueDesc = 1052047; // Your journey through the path of this Virtue is going well.
else if (value < 4000)
valueDesc = 1052048; // You feel very close to achieving your next path in this Virtue.
else if (dots < 1)
valueDesc = 1052049; // You have achieved a path in this Virtue.
else if (dots < 9)
valueDesc = 1052047; // Your journey through the path of this Virtue is going well.
else if (dots < 10)
valueDesc = 1052048; // You feel very close to achieving your next path in this Virtue.
else
valueDesc = 1052050; // You have achieved the highest path in this Virtue.
AddHtmlLocalized(157, 73, 200, 40, 1051000 + (int)virtue, false, false);
AddHtmlLocalized(75, 95, 220, 140, description, false, false);
AddHtmlLocalized(70, 224, 229, 60, valueDesc, false, false);
AddButton(65, 277, 1209, 1209, 1, GumpButtonType.Reply, 0);
AddButton(280, 43, 4014, 4014, 2, GumpButtonType.Reply, 0);
AddHtmlLocalized(
83,
275,
400,
40,
(webPage == null) ? 1052055 : 1052052,
false,
false); // This virtue is not yet defined. OR -click to learn more (opens webpage)
}
public override void OnResponse(NetState state, RelayInfo info)
{
switch (info.ButtonID)
{
case 1:
{
m_Beholder.SendGump(new VirtueInfoGump(m_Beholder, m_Virtue, m_Desc, m_Page));
if (m_Page != null)
state.Send(new LaunchBrowser(m_Page)); //No message about web browser starting on OSI
break;
}
case 2:
{
m_Beholder.SendGump(new VirtueStatusGump(m_Beholder));
break;
}
}
}
}
}

View File

@@ -0,0 +1,145 @@
#region References
using Server.Gumps;
using Server.Network;
#endregion
namespace Server.Services.Virtues
{
public class VirtueStatusGump : Gump
{
private readonly Mobile m_Beholder;
public VirtueStatusGump(Mobile beholder)
: base(0, 0)
{
m_Beholder = beholder;
AddPage(0);
AddImage(30, 40, 2080);
AddImage(47, 77, 2081);
AddImage(47, 147, 2081);
AddImage(47, 217, 2081);
AddImage(47, 267, 2083);
AddImage(70, 213, 2091);
AddPage(1);
AddHtml(140, 73, 200, 20, "The Virtues", false, false);
AddHtmlLocalized(80, 100, 100, 40, 1051000, false, false); // Humility
AddHtmlLocalized(80, 129, 100, 40, 1051001, false, false); // Sacrifice
AddHtmlLocalized(80, 159, 100, 40, 1051002, false, false); // Compassion
AddHtmlLocalized(80, 189, 100, 40, 1051003, false, false); // Spirituality
AddHtmlLocalized(200, 100, 200, 40, 1051004, false, false); // Valor
AddHtmlLocalized(200, 129, 200, 40, 1051005, false, false); // Honor
AddHtmlLocalized(200, 159, 200, 40, 1051006, false, false); // Justice
AddHtmlLocalized(200, 189, 200, 40, 1051007, false, false); // Honesty
AddHtmlLocalized(75, 224, 220, 60, 1052062, false, false); // Click on a blue gem to view your status in that virtue.
AddButton(60, 100, 1210, 1210, 1, GumpButtonType.Reply, 0);
AddButton(60, 129, 1210, 1210, 2, GumpButtonType.Reply, 0);
AddButton(60, 159, 1210, 1210, 3, GumpButtonType.Reply, 0);
AddButton(60, 189, 1210, 1210, 4, GumpButtonType.Reply, 0);
AddButton(180, 100, 1210, 1210, 5, GumpButtonType.Reply, 0);
AddButton(180, 129, 1210, 1210, 6, GumpButtonType.Reply, 0);
AddButton(180, 159, 1210, 1210, 7, GumpButtonType.Reply, 0);
AddButton(180, 189, 1210, 1210, 8, GumpButtonType.Reply, 0);
AddButton(280, 43, 4014, 4014, 9, GumpButtonType.Reply, 0);
}
public override void OnResponse(NetState state, RelayInfo info)
{
switch (info.ButtonID)
{
case 1:
{
m_Beholder.SendGump(
new VirtueInfoGump(
m_Beholder,
VirtueName.Humility,
1052051,
@"http://uo.com/wiki/ultima-online-wiki/gameplay/npc-commercial-transactions/the-virtues/#humility"));
break;
}
case 2:
{
m_Beholder.SendGump(
new VirtueInfoGump(
m_Beholder,
VirtueName.Sacrifice,
1052053,
@"http://uo.com/wiki/ultima-online-wiki/gameplay/npc-commercial-transactions/the-virtues/#sacrafice"));
break;
}
case 3:
{
m_Beholder.SendGump(
new VirtueInfoGump(
m_Beholder,
VirtueName.Compassion,
1053000,
@"http://uo.com/wiki/ultima-online-wiki/gameplay/npc-commercial-transactions/the-virtues/#compassion"));
break;
}
case 4:
{
m_Beholder.SendGump(
new VirtueInfoGump(
m_Beholder,
VirtueName.Spirituality,
1052056,
@"http://uo.com/wiki/ultima-online-wiki/gameplay/npc-commercial-transactions/the-virtues/#spirituality"));
break;
}
case 5:
{
m_Beholder.SendGump(
new VirtueInfoGump(
m_Beholder,
VirtueName.Valor,
1054033,
@"http://uo.com/wiki/ultima-online-wiki/gameplay/npc-commercial-transactions/the-virtues/#valor"));
break;
}
case 6:
{
m_Beholder.SendGump(
new VirtueInfoGump(
m_Beholder,
VirtueName.Honor,
1052058,
@"http://uo.com/wiki/ultima-online-wiki/gameplay/npc-commercial-transactions/the-virtues/#honor"));
break;
}
case 7:
{
m_Beholder.SendGump(
new VirtueInfoGump(
m_Beholder,
VirtueName.Justice,
1052059,
@"http://uo.com/wiki/ultima-online-wiki/gameplay/npc-commercial-transactions/the-virtues/#justice"));
break;
}
case 8:
{
m_Beholder.SendGump(
new VirtueInfoGump(
m_Beholder,
VirtueName.Honesty,
1052060,
@"http://uo.com/wiki/ultima-online-wiki/gameplay/npc-commercial-transactions/the-virtues/#honesty"));
break;
}
case 9:
{
m_Beholder.SendGump(new VirtueGump(m_Beholder, m_Beholder));
break;
}
}
}
}
}