Reorganizes Project (#41)
This commit is contained in:
parent
08bf44af9a
commit
3614a66aee
3499 changed files with 79 additions and 55 deletions
41
Projects/Scripts/Engines/Virtues/Compassion.cs
Normal file
41
Projects/Scripts/Engines/Virtues/Compassion.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class CompassionVirtue
|
||||
{
|
||||
private const int LossAmount = 500;
|
||||
private static TimeSpan LossDelay = TimeSpan.FromDays(7.0);
|
||||
|
||||
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)
|
||||
{
|
||||
if (!(from is PlayerMobile pm))
|
||||
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
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
409
Projects/Scripts/Engines/Virtues/Honor.cs
Normal file
409
Projects/Scripts/Engines/Virtues/Honor.cs
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
using System;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Regions;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class HonorVirtue
|
||||
{
|
||||
private static readonly TimeSpan UseDelay = TimeSpan.FromMinutes(5.0);
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
VirtueGump.Register(107, OnVirtueUsed);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
TimeSpan waitTime = DateTime.UtcNow - pm.LastHonorUse;
|
||||
if (waitTime < UseDelay)
|
||||
{
|
||||
TimeSpan remainingTime = UseDelay - waitTime;
|
||||
int 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));
|
||||
}
|
||||
|
||||
public static void ActivateEmbrace(PlayerMobile pm)
|
||||
{
|
||||
int 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
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(duration),
|
||||
delegate
|
||||
{
|
||||
pm.HonorActive = false;
|
||||
pm.LastHonorUse = DateTime.UtcNow;
|
||||
pm.SendLocalizedMessage(1063236); // You no longer embrace your honor
|
||||
});
|
||||
}
|
||||
|
||||
private static void Honor(PlayerMobile source, Mobile target)
|
||||
{
|
||||
IHonorTarget honorTarget = target as IHonorTarget;
|
||||
GuardedRegion reg = source.Region.GetRegion<GuardedRegion>();
|
||||
Map map = source.Map;
|
||||
|
||||
if (honorTarget == null)
|
||||
return;
|
||||
|
||||
if (honorTarget.ReceivedHonorContext != null)
|
||||
{
|
||||
if (honorTarget.ReceivedHonorContext.Source == source)
|
||||
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;
|
||||
}
|
||||
|
||||
if (target.Body.IsHuman && (!(target is BaseCreature cret) || !cret.AlwaysAttackable && !cret.AlwaysMurderer))
|
||||
{
|
||||
if (reg?.IsDisabled() != true)
|
||||
{
|
||||
//Allow honor on blue if Out of guardzone
|
||||
}
|
||||
else if ((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;
|
||||
}
|
||||
|
||||
source.SentHonorContext?.Cancel();
|
||||
|
||||
new HonorContext(source, target);
|
||||
|
||||
source.Direction = source.GetDirectionTo(target);
|
||||
|
||||
if (!source.Mounted)
|
||||
source.Animate(32, 5, 1, true, true, 0);
|
||||
}
|
||||
|
||||
private class InternalTarget : Target
|
||||
{
|
||||
public InternalTarget() : base(12, false, TargetFlags.None)
|
||||
{
|
||||
CheckLOS = true;
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
if (!(from is PlayerMobile pm))
|
||||
return;
|
||||
|
||||
if (targeted == pm)
|
||||
EmbraceHonor(pm);
|
||||
else if (targeted is Mobile mobile)
|
||||
Honor(pm, mobile);
|
||||
}
|
||||
|
||||
protected override void OnTargetOutOfRange(Mobile from, object targeted)
|
||||
{
|
||||
from.SendLocalizedMessage(1063232); // You are too far away to honor your opponent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface IHonorTarget
|
||||
{
|
||||
HonorContext ReceivedHonorContext{ get; set; }
|
||||
}
|
||||
|
||||
public class HonorContext
|
||||
{
|
||||
private FirstHit m_FirstHit;
|
||||
private double m_HonorDamage;
|
||||
private Point3D m_InitialLocation;
|
||||
private Map m_InitialMap;
|
||||
private bool m_Poisoned;
|
||||
|
||||
private InternalTimer m_Timer;
|
||||
private int m_TotalDamage;
|
||||
|
||||
public HonorContext(PlayerMobile source, Mobile target)
|
||||
{
|
||||
Source = source;
|
||||
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),
|
||||
delegate
|
||||
{
|
||||
if (source.m_hontime < DateTime.UtcNow && source.SentHonorContext != null) Cancel();
|
||||
});
|
||||
}
|
||||
|
||||
public PlayerMobile Source{ get; }
|
||||
|
||||
public Mobile Target{ get; }
|
||||
|
||||
public int PerfectionDamageBonus{ get; private set; }
|
||||
|
||||
public int PerfectionLuckBonus => PerfectionDamageBonus * PerfectionDamageBonus / 10;
|
||||
|
||||
public void OnSourceDamaged(Mobile from, int amount)
|
||||
{
|
||||
if (from != 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 == Source)
|
||||
{
|
||||
if (Target.CanSee(Source) && Target.InLOS(Source) && (Source.InRange(Target, 1)
|
||||
|| Source.Location == m_InitialLocation &&
|
||||
Source.Map == m_InitialMap))
|
||||
m_HonorDamage += amount;
|
||||
else
|
||||
m_HonorDamage += amount * 0.8;
|
||||
}
|
||||
else if (from is BaseCreature creature && creature.GetMaster() == Source)
|
||||
{
|
||||
m_HonorDamage += amount * 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnTargetHit(Mobile from)
|
||||
{
|
||||
if (from != Source || PerfectionDamageBonus == 100)
|
||||
return;
|
||||
|
||||
int bushido = (int)from.Skills.Bushido.Value;
|
||||
if (bushido < 50)
|
||||
return;
|
||||
|
||||
PerfectionDamageBonus += bushido / 10;
|
||||
|
||||
if (PerfectionDamageBonus >= 100)
|
||||
{
|
||||
PerfectionDamageBonus = 100;
|
||||
Source.SendLocalizedMessage(1063254); // You have Achieved Perfection in inflicting damage to this opponent!
|
||||
}
|
||||
else
|
||||
{
|
||||
Source.SendLocalizedMessage(1063255); // You gain in Perfection as you precisely strike your opponent.
|
||||
}
|
||||
}
|
||||
|
||||
public void OnTargetMissed(Mobile from)
|
||||
{
|
||||
if (from != Source || PerfectionDamageBonus == 0)
|
||||
return;
|
||||
|
||||
PerfectionDamageBonus -= 25;
|
||||
|
||||
if (PerfectionDamageBonus <= 0)
|
||||
{
|
||||
PerfectionDamageBonus = 0;
|
||||
Source.SendLocalizedMessage(1063256); // You have lost all Perfection in fighting this opponent.
|
||||
}
|
||||
else
|
||||
{
|
||||
Source.SendLocalizedMessage(1063257); // You have lost some Perfection in fighting this opponent.
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSourceBeneficialAction(Mobile to)
|
||||
{
|
||||
if (to != Target)
|
||||
return;
|
||||
|
||||
if (PerfectionDamageBonus >= 0)
|
||||
{
|
||||
PerfectionDamageBonus = 0;
|
||||
Source.SendLocalizedMessage(1063256); // You have lost all Perfection in fighting this opponent.
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSourceKilled()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnTargetKilled()
|
||||
{
|
||||
Cancel();
|
||||
|
||||
int targetFame = Target.Fame;
|
||||
|
||||
if (PerfectionDamageBonus > 0)
|
||||
{
|
||||
int restore = Math.Min(PerfectionDamageBonus * (targetFame + 5000) / 25000, 10);
|
||||
|
||||
Source.Hits += restore;
|
||||
Source.Stam += restore;
|
||||
Source.Mana += restore;
|
||||
}
|
||||
|
||||
if (Source.Virtues.Honor > targetFame)
|
||||
return;
|
||||
|
||||
double dGain =
|
||||
targetFame / 100.0 * (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;
|
||||
|
||||
int 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(Source, VirtueName.Honor))
|
||||
{
|
||||
Source.SendLocalizedMessage(1063228); // You cannot gain more Honor.
|
||||
return;
|
||||
}
|
||||
|
||||
bool gainedPath = false;
|
||||
if (VirtueHelper.Award(Source, VirtueName.Honor, gain, ref gainedPath))
|
||||
{
|
||||
if (gainedPath)
|
||||
Source.SendLocalizedMessage(1063226); // You have gained a path in Honor!
|
||||
else
|
||||
Source.SendLocalizedMessage(1063225); // You have gained in Honor.
|
||||
}
|
||||
}
|
||||
|
||||
public bool CheckDistance()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
Source.SentHonorContext = null;
|
||||
((IHonorTarget)Target).ReceivedHonorContext = null;
|
||||
|
||||
m_Timer.Stop();
|
||||
}
|
||||
|
||||
private enum FirstHit
|
||||
{
|
||||
NotDelivered,
|
||||
Delivered,
|
||||
Granted
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
237
Projects/Scripts/Engines/Virtues/Justice.cs
Normal file
237
Projects/Scripts/Engines/Virtues/Justice.cs
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
using System;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class JusticeVirtue
|
||||
{
|
||||
private const int LossAmount = 950;
|
||||
private static TimeSpan LossDelay = TimeSpan.FromDays(7.0);
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
VirtueGump.Register(109, OnVirtueUsed);
|
||||
}
|
||||
|
||||
public static bool CheckMapRegion(Mobile first, Mobile second)
|
||||
{
|
||||
Map 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;
|
||||
|
||||
if (!(from is PlayerMobile protector))
|
||||
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<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)
|
||||
{
|
||||
PlayerMobile protector = from as PlayerMobile;
|
||||
PlayerMobile 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<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.Kills >= 5)
|
||||
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<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<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.Kills >= 5)
|
||||
{
|
||||
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);
|
||||
|
||||
string args = $"{protector.Name}\t{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)
|
||||
{
|
||||
string args = $"{protector.Name}\t{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<JusticeVirtue>())
|
||||
Timer.DelayCall(TimeSpan.FromMinutes(15.0), protector.EndAction<JusticeVirtue>);
|
||||
}
|
||||
|
||||
public static void CheckAtrophy(Mobile from)
|
||||
{
|
||||
if (!(from is PlayerMobile pm))
|
||||
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
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AcceptProtectorGump : Gump
|
||||
{
|
||||
private PlayerMobile m_Protectee;
|
||||
private PlayerMobile m_Protector;
|
||||
|
||||
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); // 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); // Yes, I would like their protection.
|
||||
|
||||
AddRadio(30, 145, 9727, 9730, false, 0);
|
||||
AddHtmlLocalized(65, 148, 300, 25, 1049445, 0x7FFF); // No thanks, I can take care of myself.
|
||||
|
||||
AddButton(160, 175, 247, 248, 2);
|
||||
|
||||
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)
|
||||
{
|
||||
bool okay = info.IsSwitched(1);
|
||||
|
||||
if (okay)
|
||||
JusticeVirtue.OnVirtueAccepted(m_Protector, m_Protectee);
|
||||
else
|
||||
JusticeVirtue.OnVirtueRejected(m_Protector, m_Protectee);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
189
Projects/Scripts/Engines/Virtues/Sacrifice.cs
Normal file
189
Projects/Scripts/Engines/Virtues/Sacrifice.cs
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
using System;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class SacrificeVirtue
|
||||
{
|
||||
private const int LossAmount = 500;
|
||||
private static TimeSpan GainDelay = TimeSpan.FromDays(1.0);
|
||||
private static TimeSpan LossDelay = TimeSpan.FromDays(7.0);
|
||||
|
||||
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)
|
||||
{
|
||||
if (!(from is PlayerMobile pm))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
if (pm.LastSacrificeLoss + LossDelay < DateTime.UtcNow)
|
||||
{
|
||||
if (VirtueHelper.Atrophy(from, VirtueName.Sacrifice, LossAmount))
|
||||
from.SendLocalizedMessage(1052041); // You have lost some Sacrifice.
|
||||
|
||||
VirtueLevel level = VirtueHelper.GetLevel(from, VirtueName.Sacrifice);
|
||||
|
||||
pm.AvailableResurrects = (int)level;
|
||||
pm.LastSacrificeLoss = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
public static void Resurrect(Mobile from)
|
||||
{
|
||||
if (from.Alive)
|
||||
return;
|
||||
|
||||
if (!(from is PlayerMobile pm))
|
||||
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<ResurrectGump>();
|
||||
from.SendGump(new ResurrectGump(from, true));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sacrifice(Mobile from, object targeted)
|
||||
{
|
||||
if (!from.CheckAlive())
|
||||
return;
|
||||
|
||||
if (!(from is PlayerMobile pm))
|
||||
return;
|
||||
|
||||
if (!(targeted is Mobile targ))
|
||||
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;
|
||||
|
||||
bool 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 creature && (creature.Controlled || creature.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
142
Projects/Scripts/Engines/Virtues/Valor.cs
Normal file
142
Projects/Scripts/Engines/Virtues/Valor.cs
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
using System;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Mobiles;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class ValorVirtue
|
||||
{
|
||||
private const int LossAmount = 250;
|
||||
private static TimeSpan LossDelay = TimeSpan.FromDays(7.0);
|
||||
|
||||
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)
|
||||
{
|
||||
if (!(from is PlayerMobile pm))
|
||||
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
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
public static void Valor(Mobile from, object targ)
|
||||
{
|
||||
if (!(targ is IdolOfTheChampion idol) || idol.Deleted || idol.Spawn?.Deleted != false)
|
||||
{
|
||||
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
|
||||
{
|
||||
VirtueLevel vl = VirtueHelper.GetLevel(from, VirtueName.Valor);
|
||||
if (idol.Spawn.Active)
|
||||
{
|
||||
if (idol.Spawn.Champion != null) //TODO: Message?
|
||||
return;
|
||||
|
||||
int needed, consumed;
|
||||
switch (idol.Spawn.GetSubLevel())
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
181
Projects/Scripts/Engines/Virtues/VirtueGump.cs
Normal file
181
Projects/Scripts/Engines/Virtues/VirtueGump.cs
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public delegate void OnVirtueUsed(Mobile from);
|
||||
|
||||
public class VirtueGump : Gump
|
||||
{
|
||||
private static Dictionary<int, OnVirtueUsed> m_Callbacks = new Dictionary<int, OnVirtueUsed>();
|
||||
|
||||
private static int[] m_Table = {
|
||||
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 Mobile m_Beholder, 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);
|
||||
AddButton(186, 269, 2071, 2071, 2);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static void EventSink_VirtueItemRequest(VirtueItemRequestEventArgs e)
|
||||
{
|
||||
if (e.Beholder != e.Beheld)
|
||||
return;
|
||||
|
||||
e.Beholder.CloseGump<VirtueGump>();
|
||||
|
||||
if (e.Beholder.Kills >= 5)
|
||||
{
|
||||
e.Beholder.SendLocalizedMessage(1049609); // Murderers cannot invoke this virtue.
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Callbacks.TryGetValue(e.GumpID, out OnVirtueUsed callback))
|
||||
callback(e.Beholder);
|
||||
else
|
||||
e.Beholder.SendLocalizedMessage(1052066); // That virtue is not active yet.
|
||||
}
|
||||
|
||||
|
||||
private static void EventSink_VirtueMacroRequest(VirtueMacroRequestEventArgs e)
|
||||
{
|
||||
int 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)
|
||||
{
|
||||
Mobile beholder = e.Beholder;
|
||||
Mobile beheld = e.Beheld;
|
||||
|
||||
if (beholder == beheld && beholder.Kills >= 5)
|
||||
{
|
||||
beholder.SendLocalizedMessage(1049609); // Murderers cannot invoke this virtue.
|
||||
}
|
||||
else if (beholder.Map == beheld.Map && beholder.InRange(beheld, 12))
|
||||
{
|
||||
beholder.CloseGump<VirtueGump>();
|
||||
beholder.SendGump(new VirtueGump(beholder, beheld));
|
||||
}
|
||||
}
|
||||
|
||||
private int GetHueFor(int index)
|
||||
{
|
||||
if (m_Beheld.Virtues.GetValue(index) == 0)
|
||||
return 2402;
|
||||
|
||||
int value = m_Beheld.Virtues.GetValue(index);
|
||||
|
||||
if (value < 4000)
|
||||
return 2402;
|
||||
|
||||
if (value >= 30000)
|
||||
value = 20000; //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];
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState state, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID == 1 && m_Beholder == m_Beheld)
|
||||
m_Beholder.SendGump(new VirtueStatusGump(m_Beholder));
|
||||
}
|
||||
|
||||
private class InternalEntry : GumpImage
|
||||
{
|
||||
private static 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(NetState ns)
|
||||
{
|
||||
return $"{{ gumppic {X} {Y} {GumpID} hue={Hue} class=VirtueGumpItem }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
base.AppendTo(ns, disp);
|
||||
|
||||
disp.AppendLayout(m_Class);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
163
Projects/Scripts/Engines/Virtues/VirtueHelper.cs
Normal file
163
Projects/Scripts/Engines/Virtues/VirtueHelper.cs
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
using System;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum VirtueLevel
|
||||
{
|
||||
None,
|
||||
Seeker,
|
||||
Follower,
|
||||
Knight
|
||||
}
|
||||
|
||||
public enum VirtueName
|
||||
{
|
||||
Humility,
|
||||
Sacrifice,
|
||||
Compassion,
|
||||
Spirituality,
|
||||
Valor,
|
||||
Honor,
|
||||
Justice,
|
||||
Honesty
|
||||
}
|
||||
|
||||
public class VirtueHelper
|
||||
{
|
||||
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)
|
||||
{
|
||||
int v = from.Virtues.GetValue((int)virtue);
|
||||
int vl;
|
||||
int vmax = GetMaxAmount(virtue);
|
||||
|
||||
if (v < 4000)
|
||||
vl = 0;
|
||||
else if (v >= vmax)
|
||||
vl = 3;
|
||||
else
|
||||
vl = (v + 9999) / 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)
|
||||
{
|
||||
int current = from.Virtues.GetValue((int)virtue);
|
||||
|
||||
int maxAmount = GetMaxAmount(virtue);
|
||||
|
||||
if (current >= maxAmount)
|
||||
return false;
|
||||
|
||||
if (current + amount >= maxAmount)
|
||||
amount = maxAmount - current;
|
||||
|
||||
VirtueLevel oldLevel = GetLevel(from, virtue);
|
||||
|
||||
from.Virtues.SetValue((int)virtue, current + amount);
|
||||
|
||||
gainedPath = GetLevel(from, virtue) != oldLevel;
|
||||
|
||||
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)
|
||||
{
|
||||
int 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;
|
||||
}
|
||||
|
||||
public static void AwardVirtue(PlayerMobile pm, VirtueName virtue, int amount)
|
||||
{
|
||||
if (virtue == VirtueName.Compassion)
|
||||
{
|
||||
if (pm.CompassionGains > 0 && DateTime.UtcNow > pm.NextCompassionDay)
|
||||
{
|
||||
pm.NextCompassionDay = DateTime.MinValue;
|
||||
pm.CompassionGains = 0;
|
||||
}
|
||||
|
||||
if (pm.CompassionGains >= 5)
|
||||
{
|
||||
pm.SendLocalizedMessage(1053004); // You must wait about a day before you can gain in compassion again.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool gainedPath = false;
|
||||
string virtueName = Enum.GetName(typeof(VirtueName), virtue);
|
||||
|
||||
if (Award(pm, virtue, amount, ref gainedPath))
|
||||
{
|
||||
// TODO: Localize?
|
||||
if (gainedPath)
|
||||
pm.SendMessage("You have gained a path in {0}!", virtueName);
|
||||
else
|
||||
pm.SendMessage("You have gained in {0}.", virtueName);
|
||||
|
||||
if (virtue == VirtueName.Compassion)
|
||||
{
|
||||
pm.NextCompassionDay = DateTime.UtcNow + TimeSpan.FromDays(1.0);
|
||||
++pm.CompassionGains;
|
||||
|
||||
if (pm.CompassionGains >= 5)
|
||||
pm.SendLocalizedMessage(
|
||||
1053004); // You must wait about a day before you can gain in compassion again.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Localize?
|
||||
pm.SendMessage("You have achieved the highest path of {0} and can no longer gain any further.", virtueName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
Projects/Scripts/Engines/Virtues/VirtueInfoGump.cs
Normal file
102
Projects/Scripts/Engines/Virtues/VirtueInfoGump.cs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class VirtueInfoGump : Gump
|
||||
{
|
||||
private Mobile m_Beholder;
|
||||
private int m_Desc;
|
||||
private string m_Page;
|
||||
private VirtueName m_Virtue;
|
||||
|
||||
public VirtueInfoGump(Mobile beholder, VirtueName virtue, int description, string webPage = null) : base(0, 0)
|
||||
{
|
||||
m_Beholder = beholder;
|
||||
m_Virtue = virtue;
|
||||
m_Desc = description;
|
||||
m_Page = webPage;
|
||||
|
||||
int 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);
|
||||
|
||||
int 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 (int 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);
|
||||
AddHtmlLocalized(75, 95, 220, 140, description);
|
||||
AddHtmlLocalized(70, 224, 229, 60, valueDesc);
|
||||
|
||||
AddButton(65, 277, 1209, 1209, 1);
|
||||
|
||||
AddButton(280, 43, 4014, 4014, 2);
|
||||
|
||||
AddHtmlLocalized(83, 275, 400, 40, webPage == null ? 1052055 : 1052052); // 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
107
Projects/Scripts/Engines/Virtues/VirtueStatusGump.cs
Normal file
107
Projects/Scripts/Engines/Virtues/VirtueStatusGump.cs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class VirtueStatusGump : Gump
|
||||
{
|
||||
private 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");
|
||||
|
||||
AddHtmlLocalized(80, 100, 100, 40, 1051000); // Humility
|
||||
AddHtmlLocalized(80, 129, 100, 40, 1051001); // Sacrifice
|
||||
AddHtmlLocalized(80, 159, 100, 40, 1051002); // Compassion
|
||||
AddHtmlLocalized(80, 189, 100, 40, 1051003); // Spirituality
|
||||
AddHtmlLocalized(200, 100, 200, 40, 1051004); // Valor
|
||||
AddHtmlLocalized(200, 129, 200, 40, 1051005); // Honor
|
||||
AddHtmlLocalized(200, 159, 200, 40, 1051006); // Justice
|
||||
AddHtmlLocalized(200, 189, 200, 40, 1051007); // Honesty
|
||||
|
||||
AddHtmlLocalized(75, 224, 220, 60, 1052062); // Click on a blue gem to view your status in that virtue.
|
||||
|
||||
AddButton(60, 100, 1210, 1210, 1);
|
||||
AddButton(60, 129, 1210, 1210, 2);
|
||||
AddButton(60, 159, 1210, 1210, 3);
|
||||
AddButton(60, 189, 1210, 1210, 4);
|
||||
AddButton(180, 100, 1210, 1210, 5);
|
||||
AddButton(180, 129, 1210, 1210, 6);
|
||||
AddButton(180, 159, 1210, 1210, 7);
|
||||
AddButton(180, 189, 1210, 1210, 8);
|
||||
|
||||
AddButton(280, 43, 4014, 4014, 9);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState state, RelayInfo info)
|
||||
{
|
||||
switch (info.ButtonID)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
m_Beholder.SendGump(new VirtueInfoGump(m_Beholder, VirtueName.Humility, 1052051));
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
m_Beholder.SendGump(new VirtueInfoGump(m_Beholder, VirtueName.Sacrifice, 1052053,
|
||||
@"http://update.uo.com/design_389.html"));
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
m_Beholder.SendGump(new VirtueInfoGump(m_Beholder, VirtueName.Compassion, 1053000,
|
||||
@"http://update.uo.com/design_412.html"));
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
m_Beholder.SendGump(new VirtueInfoGump(m_Beholder, VirtueName.Spirituality, 1052056));
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
m_Beholder.SendGump(new VirtueInfoGump(m_Beholder, VirtueName.Valor, 1054033,
|
||||
@"http://update.uo.com/design_427.html"));
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
m_Beholder.SendGump(new VirtueInfoGump(m_Beholder, VirtueName.Honor, 1052058,
|
||||
@"http://guide.uo.com/virtues_2.html"));
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
m_Beholder.SendGump(new VirtueInfoGump(m_Beholder, VirtueName.Justice, 1052059,
|
||||
@"http://update.uo.com/design_413.html"));
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
m_Beholder.SendGump(new VirtueInfoGump(m_Beholder, VirtueName.Honesty, 1052060));
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
{
|
||||
m_Beholder.SendGump(new VirtueGump(m_Beholder, m_Beholder));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue