492 lines
17 KiB
C#
492 lines
17 KiB
C#
using System;
|
|
using Server;
|
|
using Server.Items;
|
|
using Server.Network;
|
|
using Server.Mobiles;
|
|
using Server.Targeting;
|
|
|
|
namespace Server.Engines.XmlSpawner2
|
|
{
|
|
public class XmlUse : XmlAttachment
|
|
{
|
|
private bool m_BlockDefaultUse;
|
|
private string m_Condition; // additional condition required for use
|
|
private string m_TargetingAction; // action performed when the target cursor is brought up
|
|
private string m_TargetCondition; // condition test applied when target is selected to determine whether it is appropriate
|
|
private string m_TargetFailureAction; // action performed if target condition is not met
|
|
private string m_SuccessAction; // action performed on successful use or targeting
|
|
private string m_FailureAction; // action performed if the player cannot use the object for reasons other than range, refractory, or maxuses
|
|
private string m_RefractoryAction; // action performed if the object is used before the refractory interval expires
|
|
private string m_MaxUsesAction; // action performed if the object is used when the maxuses are exceeded
|
|
private int m_NUses = 0;
|
|
private int m_MaxRange = 3; // must be within 3 tiles to use by default
|
|
private int m_MaxTargetRange = 30; // must be within 30 tiles to target by default
|
|
private int m_MaxUses = 0;
|
|
private TimeSpan m_Refractory = TimeSpan.Zero;
|
|
public DateTime m_EndTime;
|
|
private bool m_RequireLOS = false;
|
|
private bool m_AllowCarried = true;
|
|
private bool m_TargetingEnabled = false;
|
|
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool TargetingEnabled { get { return m_TargetingEnabled; } set { m_TargetingEnabled = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool AllowCarried { get { return m_AllowCarried; } set { m_AllowCarried = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool RequireLOS { get { return m_RequireLOS; } set { m_RequireLOS = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int MaxRange { get { return m_MaxRange; } set { m_MaxRange = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int MaxTargetRange { get { return m_MaxTargetRange; } set { m_MaxTargetRange = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int NUses { get { return m_NUses; } set { m_NUses = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int MaxUses { get { return m_MaxUses; } set { m_MaxUses = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public TimeSpan Refractory { get { return m_Refractory; } set { m_Refractory = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool BlockDefaultUse { get { return m_BlockDefaultUse; } set { m_BlockDefaultUse = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public string Condition { get { return m_Condition; } set { m_Condition = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public string TargetCondition { get { return m_TargetCondition; } set { m_TargetCondition = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public string TargetingAction { get { return m_TargetingAction; } set { m_TargetingAction = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public string TargetFailureAction { get { return m_TargetFailureAction; } set { m_TargetFailureAction = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public string SuccessAction { get { return m_SuccessAction; } set { m_SuccessAction = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public string FailureAction { get { return m_FailureAction; } set { m_FailureAction = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public string RefractoryAction { get { return m_RefractoryAction; } set { m_RefractoryAction = value; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public string MaxUsesAction { get { return m_MaxUsesAction; } set { m_MaxUsesAction = value; } }
|
|
|
|
public XmlUse(ASerial serial)
|
|
: base(serial)
|
|
{
|
|
}
|
|
[Attachable]
|
|
public XmlUse()
|
|
{
|
|
}
|
|
|
|
[Attachable]
|
|
public XmlUse(int maxuses)
|
|
{
|
|
MaxUses = maxuses;
|
|
}
|
|
|
|
[Attachable]
|
|
public XmlUse(int maxuses, double refractory)
|
|
{
|
|
MaxUses = maxuses;
|
|
Refractory = TimeSpan.FromSeconds(refractory);
|
|
}
|
|
|
|
public override void Serialize(GenericWriter writer)
|
|
{
|
|
base.Serialize(writer);
|
|
|
|
writer.Write((int)3);
|
|
// version 3
|
|
writer.Write(m_MaxTargetRange);
|
|
// version 2
|
|
writer.Write(m_TargetingEnabled);
|
|
writer.Write(m_TargetingAction);
|
|
writer.Write(m_TargetCondition);
|
|
writer.Write(m_TargetFailureAction);
|
|
// version 1
|
|
writer.Write(m_AllowCarried);
|
|
// version 0
|
|
writer.Write(m_RequireLOS);
|
|
writer.Write(m_MaxRange);
|
|
writer.Write(m_Refractory);
|
|
writer.Write(m_EndTime - DateTime.UtcNow);
|
|
writer.Write(m_MaxUses);
|
|
writer.Write(m_NUses);
|
|
writer.Write(m_BlockDefaultUse);
|
|
writer.Write(m_Condition);
|
|
writer.Write(m_SuccessAction);
|
|
writer.Write(m_FailureAction);
|
|
writer.Write(m_RefractoryAction);
|
|
writer.Write(m_MaxUsesAction);
|
|
}
|
|
|
|
public override void Deserialize(GenericReader reader)
|
|
{
|
|
base.Deserialize(reader);
|
|
|
|
int version = reader.ReadInt();
|
|
switch (version)
|
|
{
|
|
case 3:
|
|
m_MaxTargetRange = reader.ReadInt();
|
|
goto case 2;
|
|
case 2:
|
|
m_TargetingEnabled = reader.ReadBool();
|
|
m_TargetingAction = reader.ReadString();
|
|
m_TargetCondition = reader.ReadString();
|
|
m_TargetFailureAction = reader.ReadString();
|
|
goto case 1;
|
|
case 1:
|
|
m_AllowCarried = reader.ReadBool();
|
|
goto case 0;
|
|
case 0:
|
|
// version 0
|
|
m_RequireLOS = reader.ReadBool();
|
|
m_MaxRange = reader.ReadInt();
|
|
Refractory = reader.ReadTimeSpan();
|
|
TimeSpan remaining = reader.ReadTimeSpan();
|
|
m_EndTime = DateTime.UtcNow + remaining;
|
|
m_MaxUses = reader.ReadInt();
|
|
m_NUses = reader.ReadInt();
|
|
m_BlockDefaultUse = reader.ReadBool();
|
|
m_Condition = reader.ReadString();
|
|
m_SuccessAction = reader.ReadString();
|
|
m_FailureAction = reader.ReadString();
|
|
m_RefractoryAction = reader.ReadString();
|
|
m_MaxUsesAction = reader.ReadString();
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void ExecuteActions(Mobile mob, object target, string actions)
|
|
{
|
|
if (actions == null || actions.Length <= 0) return;
|
|
// execute any action associated with it
|
|
// allow for multiple action strings on a single line separated by a semicolon
|
|
|
|
string[] args = actions.Split(';');
|
|
|
|
for (int j = 0; j < args.Length; j++)
|
|
{
|
|
ExecuteAction(mob, target, args[j]);
|
|
}
|
|
|
|
}
|
|
|
|
private void ExecuteAction(Mobile mob, object target, string action)
|
|
{
|
|
if (action == null || action.Length <= 0) return;
|
|
|
|
string status_str = null;
|
|
Server.Mobiles.XmlSpawner.SpawnObject TheSpawn = new Server.Mobiles.XmlSpawner.SpawnObject(null, 0);
|
|
|
|
TheSpawn.TypeName = action;
|
|
string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, target, mob, action);
|
|
string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName);
|
|
|
|
Point3D loc = new Point3D(0, 0, 0);
|
|
Map map = null;
|
|
|
|
|
|
if (target is Item)
|
|
{
|
|
Item ti = target as Item;
|
|
if (ti.Parent == null)
|
|
{
|
|
loc = ti.Location;
|
|
map = ti.Map;
|
|
}
|
|
else if (ti.RootParent is Item)
|
|
{
|
|
loc = ((Item)ti.RootParent).Location;
|
|
map = ((Item)ti.RootParent).Map;
|
|
}
|
|
else if (ti.RootParent is Mobile)
|
|
{
|
|
loc = ((Mobile)ti.RootParent).Location;
|
|
map = ((Mobile)ti.RootParent).Map;
|
|
}
|
|
|
|
}
|
|
else if (target is Mobile)
|
|
{
|
|
Mobile ti = target as Mobile;
|
|
|
|
loc = ti.Location;
|
|
map = ti.Map;
|
|
|
|
}
|
|
|
|
if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName))
|
|
{
|
|
BaseXmlSpawner.SpawnTypeKeyword(target, TheSpawn, typeName, substitutedtypeName, true, mob, loc, map, out status_str);
|
|
}
|
|
else
|
|
{
|
|
// its a regular type descriptor so find out what it is
|
|
Type type = SpawnerType.GetType(typeName);
|
|
try
|
|
{
|
|
string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/");
|
|
object o = Server.Mobiles.XmlSpawner.CreateObject(type, arglist[0]);
|
|
|
|
if (o == null)
|
|
{
|
|
status_str = "invalid type specification: " + arglist[0];
|
|
}
|
|
else
|
|
if (o is Mobile)
|
|
{
|
|
Mobile m = (Mobile)o;
|
|
if (m is BaseCreature)
|
|
{
|
|
BaseCreature c = (BaseCreature)m;
|
|
c.Home = loc; // Spawners location is the home point
|
|
}
|
|
|
|
m.Location = loc;
|
|
m.Map = map;
|
|
|
|
BaseXmlSpawner.ApplyObjectStringProperties(null, substitutedtypeName, m, mob, target, out status_str);
|
|
}
|
|
else
|
|
if (o is Item)
|
|
{
|
|
Item item = (Item)o;
|
|
BaseXmlSpawner.AddSpawnItem(null, target, TheSpawn, item, loc, map, mob, false, substitutedtypeName, out status_str);
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
ReportError(mob, status_str);
|
|
}
|
|
|
|
private void ReportError(Mobile mob, string status_str)
|
|
{
|
|
if (status_str != null && mob != null && !mob.Deleted && mob is PlayerMobile && mob.AccessLevel > AccessLevel.Player)
|
|
{
|
|
mob.SendMessage(33, String.Format("{0}:{1}", Name, status_str));
|
|
}
|
|
}
|
|
|
|
// return true to allow use
|
|
private bool CheckCondition(Mobile from, object target)
|
|
{
|
|
// test the condition if there is one
|
|
if (Condition != null && Condition.Length > 0)
|
|
{
|
|
string status_str;
|
|
|
|
return BaseXmlSpawner.CheckPropertyString(null, target, Condition, from, out status_str);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// return true to allow use
|
|
private bool CheckTargetCondition(Mobile from, object target)
|
|
{
|
|
// test the condition if there is one
|
|
if (TargetCondition != null && TargetCondition.Length > 0)
|
|
{
|
|
string status_str;
|
|
|
|
return BaseXmlSpawner.CheckPropertyString(null, target, TargetCondition, from, out status_str);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// return true to allow use
|
|
private bool CheckRange(Mobile from, object target)
|
|
{
|
|
if (from == null || !(target is IEntity) || MaxRange < 0) return false;
|
|
|
|
Map map = ((IEntity)target).Map;
|
|
Point3D loc = ((IEntity)target).Location;
|
|
|
|
if (map != from.Map) return false;
|
|
|
|
// check for allowed use in pack
|
|
if (target is Item)
|
|
{
|
|
Item targetitem = (Item)target;
|
|
// is it carried by the user?
|
|
if (targetitem.RootParent == from)
|
|
{
|
|
return AllowCarried;
|
|
}
|
|
else
|
|
// block use in other containers or on other mobiles
|
|
if (targetitem.Parent != null)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool haslos = true;
|
|
if (RequireLOS)
|
|
{
|
|
// check los as well
|
|
haslos = from.InLOS(target);
|
|
}
|
|
|
|
return from.InRange(loc, MaxRange) && haslos;
|
|
}
|
|
|
|
public bool CheckMaxUses
|
|
{
|
|
get
|
|
{
|
|
// is there a use limit?
|
|
if (MaxUses > 0 && NUses >= MaxUses) return false;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public bool CheckRefractory
|
|
{
|
|
get
|
|
{
|
|
// is there a refractory limit?
|
|
// if it is still refractory then return
|
|
if (Refractory > TimeSpan.Zero && DateTime.UtcNow < m_EndTime) return false;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public void OutOfRange(Mobile from)
|
|
{
|
|
if (from == null) return;
|
|
|
|
from.SendLocalizedMessage(500446); // That is too far away.
|
|
}
|
|
|
|
public class XmlUseTarget : Target
|
|
{
|
|
private object m_objectused;
|
|
private XmlUse m_xa;
|
|
|
|
public XmlUseTarget(int range, object objectused, XmlUse xa)
|
|
: base(range, true, TargetFlags.None)
|
|
{
|
|
m_objectused = objectused;
|
|
m_xa = xa;
|
|
CheckLOS = false;
|
|
}
|
|
protected override void OnTarget(Mobile from, object targeted)
|
|
{
|
|
if (from == null || targeted == null || m_xa == null) return;
|
|
|
|
// success
|
|
if (m_xa.CheckTargetCondition(from, targeted))
|
|
{
|
|
m_xa.ExecuteActions(from, targeted, m_xa.SuccessAction);
|
|
|
|
m_xa.m_EndTime = DateTime.UtcNow + m_xa.Refractory;
|
|
m_xa.NUses++;
|
|
}
|
|
else
|
|
{
|
|
m_xa.ExecuteActions(from, targeted, m_xa.TargetFailureAction);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
private void TryToTarget(Mobile from, object target, XmlUse xa)
|
|
{
|
|
if (from == null) return;
|
|
|
|
ExecuteActions(from, target, TargetingAction);
|
|
|
|
if (xa != null)
|
|
{
|
|
from.Target = new XmlUseTarget(xa.MaxTargetRange, target, xa);
|
|
}
|
|
}
|
|
|
|
private void TryToUse(Mobile from, object target)
|
|
{
|
|
if (CheckRange(from, target) && CheckCondition(from, target) && CheckMaxUses && CheckRefractory)
|
|
{
|
|
// check for targeting
|
|
if (TargetingEnabled)
|
|
{
|
|
TryToTarget(from, target, this);
|
|
}
|
|
else
|
|
{
|
|
// success
|
|
ExecuteActions(from, target, SuccessAction);
|
|
|
|
m_EndTime = DateTime.UtcNow + Refractory;
|
|
NUses++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// failure
|
|
if (!CheckRange(from, target))
|
|
{
|
|
OutOfRange(from);
|
|
}
|
|
else if (!CheckRefractory)
|
|
{
|
|
ExecuteActions(from, target, RefractoryAction);
|
|
}
|
|
else if (!CheckMaxUses)
|
|
{
|
|
ExecuteActions(from, target, MaxUsesAction);
|
|
}
|
|
|
|
else
|
|
{
|
|
ExecuteActions(from, target, FailureAction);
|
|
}
|
|
}
|
|
}
|
|
|
|
// disable the default use of the target
|
|
public override bool BlockDefaultOnUse(Mobile from, object target)
|
|
{
|
|
return (BlockDefaultUse || !(CheckRange(from, target) && CheckCondition(from, target) && CheckMaxUses && CheckRefractory));
|
|
}
|
|
|
|
// this is called when the attachment is on the user
|
|
public override void OnUser(object target)
|
|
{
|
|
Mobile from = AttachedTo as Mobile;
|
|
|
|
TryToUse(from, target);
|
|
|
|
}
|
|
|
|
|
|
// this is called when the attachment is on the target being used
|
|
public override void OnUse(Mobile from)
|
|
{
|
|
object target = AttachedTo;
|
|
|
|
// if a target tries to use itself, then ignore it, it will be handled by OnUser
|
|
if (target == from) return;
|
|
|
|
TryToUse(from, target);
|
|
}
|
|
}
|
|
}
|