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

93
Scripts/Skills/Anatomy.cs Normal file
View File

@@ -0,0 +1,93 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.SkillHandlers
{
public class Anatomy
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.Anatomy].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile m)
{
m.Target = new Anatomy.InternalTarget();
m.SendLocalizedMessage(500321); // Whom shall I examine?
return TimeSpan.FromSeconds(1.0);
}
private class InternalTarget : Target
{
public InternalTarget()
: base(8, false, TargetFlags.None)
{
}
protected override void OnTarget(Mobile from, object targeted)
{
if (from == targeted)
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500324); // You know yourself quite well enough already.
}
else if (targeted is TownCrier)
{
((TownCrier)targeted).PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500322, from.NetState); // This person looks fine to me, though he may have some news...
}
else if (targeted is BaseVendor && ((BaseVendor)targeted).IsInvulnerable)
{
((BaseVendor)targeted).PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500326, from.NetState); // That can not be inspected.
}
else if (targeted is Mobile)
{
Mobile targ = (Mobile)targeted;
int marginOfError = Math.Max(0, 25 - (int)(from.Skills[SkillName.Anatomy].Value / 4));
int str = targ.Str + Utility.RandomMinMax(-marginOfError, +marginOfError);
int dex = targ.Dex + Utility.RandomMinMax(-marginOfError, +marginOfError);
int stm = ((targ.Stam * 100) / Math.Max(targ.StamMax, 1)) + Utility.RandomMinMax(-marginOfError, +marginOfError);
int strMod = str / 10;
int dexMod = dex / 10;
int stmMod = stm / 10;
if (strMod < 0)
strMod = 0;
else if (strMod > 10)
strMod = 10;
if (dexMod < 0)
dexMod = 0;
else if (dexMod > 10)
dexMod = 10;
if (stmMod > 10)
stmMod = 10;
else if (stmMod < 0)
stmMod = 0;
if (from.CheckTargetSkill(SkillName.Anatomy, targ, 0, 100))
{
targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038045 + (strMod * 11) + dexMod, from.NetState); // That looks [strong] and [dexterous].
if (from.Skills[SkillName.Anatomy].Base >= 65.0)
targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038303 + stmMod, from.NetState); // That being is at [10,20,...] percent endurance.
}
else
{
targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042666, from.NetState); // You can not quite get a sense of their physical characteristics.
}
}
else if (targeted is Item)
{
((Item)targeted).SendLocalizedMessageTo(from, 500323, ""); // Only living things have anatomies!
}
}
}
}
}

View File

@@ -0,0 +1,428 @@
using System;
using Server.Gumps;
using Server.Mobiles;
using Server.Targeting;
namespace Server.SkillHandlers
{
public class AnimalLore
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.AnimalLore].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile m)
{
if (PetTrainingHelper.Enabled && m.HasGump(typeof(NewAnimalLoreGump)))
{
m.SendLocalizedMessage(500118); // You must wait a few moments to use another skill.
}
else
{
m.Target = new InternalTarget();
m.SendLocalizedMessage(500328); // What animal should I look at?
}
return TimeSpan.FromSeconds(1.0);
}
private class InternalTarget : Target
{
private static void SendGump(Mobile from, BaseCreature c)
{
from.CheckTargetSkill(SkillName.AnimalLore, c, 0.0, 120.0);
if (PetTrainingHelper.Enabled && from is PlayerMobile)
{
Timer.DelayCall(TimeSpan.FromSeconds(1), () =>
{
BaseGump.SendGump(new NewAnimalLoreGump((PlayerMobile)from, c));
});
}
else
{
from.CloseGump(typeof(AnimalLoreGump));
from.SendGump(new AnimalLoreGump(c));
}
}
private static void Check(Mobile from, BaseCreature c, double min)
{
if (from.CheckTargetSkill(SkillName.AnimalLore, c, min, 120.0))
SendGump(from, c);
else
from.SendLocalizedMessage(500334); // You can't think of anything you know offhand.
}
public InternalTarget()
: base(8, false, TargetFlags.None)
{
}
protected override void OnTarget(Mobile from, object targeted)
{
if (!from.Alive)
{
from.SendLocalizedMessage(500331); // The spirits of the dead are not the province of animal lore.
}
else if (targeted is BaseCreature)
{
BaseCreature c = (BaseCreature)targeted;
if (!c.IsDeadPet)
{
if (c.Body.IsAnimal || c.Body.IsMonster || c.Body.IsSea)
{
double skill = from.Skills[SkillName.AnimalLore].Value;
if(skill < 100.0)
{
if (c.Controlled)
SendGump(from, c);
else
from.SendLocalizedMessage(1049674); // At your skill level, you can only lore tamed creatures.
}
else if (skill < 110.0)
{
if (c.Controlled)
SendGump(from, c);
else if (c.Tamable)
Check(from, c, 80.0);
else
from.SendLocalizedMessage(1049675); // At your skill level, you can only lore tamed or tameable creatures.
}
else
{
if (c.Controlled)
SendGump(from, c);
else if (c.Tamable)
Check(from, c, 80.0);
else
Check(from, c, 100.0);
}
}
else
{
from.SendLocalizedMessage(500329); // That's not an animal!
}
}
else
{
from.SendLocalizedMessage(500331); // The spirits of the dead are not the province of animal lore.
}
}
else
{
from.SendLocalizedMessage(500329); // That's not an animal!
}
}
}
}
public class AnimalLoreGump : Gump
{
public static string FormatSkill(BaseCreature c, SkillName name)
{
Skill skill = c.Skills[name];
if (skill.Base < 10.0)
return "<div align=right>---</div>";
return String.Format("<div align=right>{0:F1}</div>", skill.Value);
}
public static string FormatAttributes(int cur, int max)
{
if (max == 0)
return "<div align=right>---</div>";
return String.Format("<div align=right>{0}/{1}</div>", cur, max);
}
public static string FormatStat(int val)
{
if (val == 0)
return "<div align=right>---</div>";
return String.Format("<div align=right>{0}</div>", val);
}
public static string FormatDouble(double val)
{
if (val == 0)
return "<div align=right>---</div>";
return String.Format("<div align=right>{0:F1}</div>", val);
}
public static string FormatElement(int val)
{
if (val <= 0)
return "<div align=right>---</div>";
return String.Format("<div align=right>{0}%</div>", val);
}
#region Mondain's Legacy
public static string FormatDamage(int min, int max)
{
if (min <= 0 || max <= 0)
return "<div align=right>---</div>";
return String.Format("<div align=right>{0}-{1}</div>", min, max);
}
#endregion
private const int LabelColor = 0x24E5;
public AnimalLoreGump(BaseCreature c)
: base(250, 50)
{
AddPage(0);
AddImage(100, 100, 2080);
AddImage(118, 137, 2081);
AddImage(118, 207, 2081);
AddImage(118, 277, 2081);
AddImage(118, 347, 2083);
AddHtml(147, 108, 210, 18, String.Format("<center><i>{0}</i></center>", c.Name), false, false);
AddButton(240, 77, 2093, 2093, 2, GumpButtonType.Reply, 0);
AddImage(140, 138, 2091);
AddImage(140, 335, 2091);
int pages = (Core.AOS ? 5 : 3);
int page = 0;
#region Attributes
AddPage(++page);
AddImage(128, 152, 2086);
AddHtmlLocalized(147, 150, 160, 18, 1049593, 200, false, false); // Attributes
AddHtmlLocalized(153, 168, 160, 18, 1049578, LabelColor, false, false); // Hits
AddHtml(280, 168, 75, 18, FormatAttributes(c.Hits, c.HitsMax), false, false);
AddHtmlLocalized(153, 186, 160, 18, 1049579, LabelColor, false, false); // Stamina
AddHtml(280, 186, 75, 18, FormatAttributes(c.Stam, c.StamMax), false, false);
AddHtmlLocalized(153, 204, 160, 18, 1049580, LabelColor, false, false); // Mana
AddHtml(280, 204, 75, 18, FormatAttributes(c.Mana, c.ManaMax), false, false);
AddHtmlLocalized(153, 222, 160, 18, 1028335, LabelColor, false, false); // Strength
AddHtml(320, 222, 35, 18, FormatStat(c.Str), false, false);
AddHtmlLocalized(153, 240, 160, 18, 3000113, LabelColor, false, false); // Dexterity
AddHtml(320, 240, 35, 18, FormatStat(c.Dex), false, false);
AddHtmlLocalized(153, 258, 160, 18, 3000112, LabelColor, false, false); // Intelligence
AddHtml(320, 258, 35, 18, FormatStat(c.Int), false, false);
if (Core.AOS)
{
int y = 276;
if (Core.SE)
{
double bd = Items.BaseInstrument.GetBaseDifficulty(c);
if (c.Uncalmable)
bd = 0;
AddHtmlLocalized(153, 276, 160, 18, 1070793, LabelColor, false, false); // Barding Difficulty
AddHtml(320, y, 35, 18, FormatDouble(bd), false, false);
y += 18;
}
AddImage(128, y + 2, 2086);
AddHtmlLocalized(147, y, 160, 18, 1049594, 200, false, false); // Loyalty Rating
y += 18;
AddHtmlLocalized(153, y, 160, 18, (!c.Controlled || c.Loyalty == 0) ? 1061643 : 1049595 + (c.Loyalty / 10), LabelColor, false, false);
}
else
{
AddImage(128, 278, 2086);
AddHtmlLocalized(147, 276, 160, 18, 3001016, 200, false, false); // Miscellaneous
AddHtmlLocalized(153, 294, 160, 18, 1049581, LabelColor, false, false); // Armor Rating
AddHtml(320, 294, 35, 18, FormatStat(c.VirtualArmor), false, false);
}
AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1);
AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, pages);
#endregion
#region Resistances
if (Core.AOS)
{
AddPage(++page);
AddImage(128, 152, 2086);
AddHtmlLocalized(147, 150, 160, 18, 1061645, 200, false, false); // Resistances
AddHtmlLocalized(153, 168, 160, 18, 1061646, LabelColor, false, false); // Physical
AddHtml(320, 168, 35, 18, FormatElement(c.PhysicalResistance), false, false);
AddHtmlLocalized(153, 186, 160, 18, 1061647, LabelColor, false, false); // Fire
AddHtml(320, 186, 35, 18, FormatElement(c.FireResistance), false, false);
AddHtmlLocalized(153, 204, 160, 18, 1061648, LabelColor, false, false); // Cold
AddHtml(320, 204, 35, 18, FormatElement(c.ColdResistance), false, false);
AddHtmlLocalized(153, 222, 160, 18, 1061649, LabelColor, false, false); // Poison
AddHtml(320, 222, 35, 18, FormatElement(c.PoisonResistance), false, false);
AddHtmlLocalized(153, 240, 160, 18, 1061650, LabelColor, false, false); // Energy
AddHtml(320, 240, 35, 18, FormatElement(c.EnergyResistance), false, false);
AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1);
AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1);
}
#endregion
#region Damage
if (Core.AOS)
{
AddPage(++page);
AddImage(128, 152, 2086);
AddHtmlLocalized(147, 150, 160, 18, 1017319, 200, false, false); // Damage
AddHtmlLocalized(153, 168, 160, 18, 1061646, LabelColor, false, false); // Physical
AddHtml(320, 168, 35, 18, FormatElement(c.PhysicalDamage), false, false);
AddHtmlLocalized(153, 186, 160, 18, 1061647, LabelColor, false, false); // Fire
AddHtml(320, 186, 35, 18, FormatElement(c.FireDamage), false, false);
AddHtmlLocalized(153, 204, 160, 18, 1061648, LabelColor, false, false); // Cold
AddHtml(320, 204, 35, 18, FormatElement(c.ColdDamage), false, false);
AddHtmlLocalized(153, 222, 160, 18, 1061649, LabelColor, false, false); // Poison
AddHtml(320, 222, 35, 18, FormatElement(c.PoisonDamage), false, false);
AddHtmlLocalized(153, 240, 160, 18, 1061650, LabelColor, false, false); // Energy
AddHtml(320, 240, 35, 18, FormatElement(c.EnergyDamage), false, false);
#region Mondain's Legacy
if (Core.ML)
{
AddHtmlLocalized(153, 258, 160, 18, 1076750, LabelColor, false, false); // Base Damage
AddHtml(300, 258, 55, 18, FormatDamage(c.DamageMin, c.DamageMax), false, false);
}
#endregion
AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1);
AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1);
}
#endregion
#region Skills
AddPage(++page);
AddImage(128, 152, 2086);
AddHtmlLocalized(147, 150, 160, 18, 3001030, 200, false, false); // Combat Ratings
AddHtmlLocalized(153, 168, 160, 18, 1044103, LabelColor, false, false); // Wrestling
AddHtml(320, 168, 35, 18, FormatSkill(c, SkillName.Wrestling), false, false);
AddHtmlLocalized(153, 186, 160, 18, 1044087, LabelColor, false, false); // Tactics
AddHtml(320, 186, 35, 18, FormatSkill(c, SkillName.Tactics), false, false);
AddHtmlLocalized(153, 204, 160, 18, 1044086, LabelColor, false, false); // Magic Resistance
AddHtml(320, 204, 35, 18, FormatSkill(c, SkillName.MagicResist), false, false);
AddHtmlLocalized(153, 222, 160, 18, 1044061, LabelColor, false, false); // Anatomy
AddHtml(320, 222, 35, 18, FormatSkill(c, SkillName.Anatomy), false, false);
#region Mondain's Legacy
if (c is CuSidhe)
{
AddHtmlLocalized(153, 240, 160, 18, 1044077, LabelColor, false, false); // Healing
AddHtml(320, 240, 35, 18, FormatSkill(c, SkillName.Healing), false, false);
}
else
{
AddHtmlLocalized(153, 240, 160, 18, 1044090, LabelColor, false, false); // Poisoning
AddHtml(320, 240, 35, 18, FormatSkill(c, SkillName.Poisoning), false, false);
}
#endregion
AddImage(128, 260, 2086);
AddHtmlLocalized(147, 258, 160, 18, 3001032, 200, false, false); // Lore & Knowledge
AddHtmlLocalized(153, 276, 160, 18, 1044085, LabelColor, false, false); // Magery
AddHtml(320, 276, 35, 18, FormatSkill(c, SkillName.Magery), false, false);
AddHtmlLocalized(153, 294, 160, 18, 1044076, LabelColor, false, false); // Evaluating Intelligence
AddHtml(320, 294, 35, 18, FormatSkill(c, SkillName.EvalInt), false, false);
AddHtmlLocalized(153, 312, 160, 18, 1044106, LabelColor, false, false); // Meditation
AddHtml(320, 312, 35, 18, FormatSkill(c, SkillName.Meditation), false, false);
AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1);
AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1);
#endregion
#region Misc
AddPage(++page);
AddImage(128, 152, 2086);
AddHtmlLocalized(147, 150, 160, 18, 1049563, 200, false, false); // Preferred Foods
int foodPref = 3000340;
if ((c.FavoriteFood & FoodType.FruitsAndVegies) != 0)
foodPref = 1049565; // Fruits and Vegetables
else if ((c.FavoriteFood & FoodType.GrainsAndHay) != 0)
foodPref = 1049566; // Grains and Hay
else if ((c.FavoriteFood & FoodType.Fish) != 0)
foodPref = 1049568; // Fish
else if ((c.FavoriteFood & FoodType.Meat) != 0)
foodPref = 1049564; // Meat
else if ((c.FavoriteFood & FoodType.Eggs) != 0)
foodPref = 1044477; // Eggs
AddHtmlLocalized(153, 168, 160, 18, foodPref, LabelColor, false, false);
AddImage(128, 188, 2086);
AddHtmlLocalized(147, 186, 160, 18, 1049569, 200, false, false); // Pack Instincts
int packInstinct = 3000340;
if ((c.PackInstinct & PackInstinct.Canine) != 0)
packInstinct = 1049570; // Canine
else if ((c.PackInstinct & PackInstinct.Ostard) != 0)
packInstinct = 1049571; // Ostard
else if ((c.PackInstinct & PackInstinct.Feline) != 0)
packInstinct = 1049572; // Feline
else if ((c.PackInstinct & PackInstinct.Arachnid) != 0)
packInstinct = 1049573; // Arachnid
else if ((c.PackInstinct & PackInstinct.Daemon) != 0)
packInstinct = 1049574; // Daemon
else if ((c.PackInstinct & PackInstinct.Bear) != 0)
packInstinct = 1049575; // Bear
else if ((c.PackInstinct & PackInstinct.Equine) != 0)
packInstinct = 1049576; // Equine
else if ((c.PackInstinct & PackInstinct.Bull) != 0)
packInstinct = 1049577; // Bull
AddHtmlLocalized(153, 204, 160, 18, packInstinct, LabelColor, false, false);
if (!Core.AOS)
{
AddImage(128, 224, 2086);
AddHtmlLocalized(147, 222, 160, 18, 1049594, 200, false, false); // Loyalty Rating
AddHtmlLocalized(153, 240, 160, 18, (!c.Controlled || c.Loyalty == 0) ? 1061643 : 1049595 + (c.Loyalty / 10), LabelColor, false, false);
}
AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, 1);
AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1);
#endregion
}
}
}

View File

@@ -0,0 +1,490 @@
#region References
using System;
using System.Collections;
using Server.Engines.XmlSpawner2;
using Server.Factions;
using Server.Mobiles;
using Server.Network;
using Server.Spells;
using Server.Spells.Spellweaving;
using Server.Targeting;
#endregion
namespace Server.SkillHandlers
{
public class AnimalTaming
{
private static readonly Hashtable m_BeingTamed = new Hashtable();
public static bool DisableMessage { get; set; }
public static bool DeferredTarget { get; set; }
static AnimalTaming()
{
DeferredTarget = true;
DisableMessage = false;
}
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.AnimalTaming].Callback = OnUse;
}
public static TimeSpan OnUse(Mobile m)
{
m.RevealingAction();
if (!DisableMessage)
{
m.SendLocalizedMessage(502789); // Tame which animal?
}
if (DeferredTarget)
{
Timer.DelayCall(() => m.Target = new InternalTarget(m));
}
else
{
m.Target = new InternalTarget(m);
}
// We're not sure why this is getting hung up. Now, its 30 second timeout + 10 seconds (max) to tame
return TimeSpan.FromSeconds(40.0);
}
public static bool MustBeSubdued(BaseCreature bc)
{
if (bc.Owners.Count > 0)
{
return false;
} //Checks to see if the animal has been tamed before
return bc.SubdueBeforeTame && (bc.Hits > ((double)bc.HitsMax / 10));
}
public static void ScaleStats(BaseCreature bc, double scalar)
{
if (bc.RawStr > 0)
{
bc.RawStr = (int)Math.Max(1, bc.RawStr * scalar);
}
if (bc.RawDex > 0)
{
bc.RawDex = (int)Math.Max(1, bc.RawDex * scalar);
}
if (bc.RawInt > 0)
{
bc.RawInt = (int)Math.Max(1, bc.RawInt * scalar);
}
if (bc.HitsMaxSeed > 0)
{
bc.HitsMaxSeed = (int)Math.Max(1, bc.HitsMaxSeed * scalar);
bc.Hits = bc.Hits;
}
if (bc.StamMaxSeed > 0)
{
bc.StamMaxSeed = (int)Math.Max(1, bc.StamMaxSeed * scalar);
bc.Stam = bc.Stam;
}
}
public static void ScaleSkills(BaseCreature bc, double scalar, bool firstTame)
{
ScaleSkills(bc, scalar, scalar, firstTame);
}
public static void ScaleSkills(BaseCreature bc, double scalar, double capScalar, bool firstTame)
{
for (int i = 0; i < bc.Skills.Length; ++i)
{
if (!Core.TOL || firstTame)
{
bc.Skills[i].Cap = Math.Max(100.0, bc.Skills[i].Base * capScalar);
}
bc.Skills[i].Base *= scalar;
if (bc.Skills[i].Base > bc.Skills[i].Cap)
{
bc.Skills[i].Cap = bc.Skills[i].Base;
}
}
}
private class InternalTarget : Target
{
private bool m_SetSkillTime = true;
public InternalTarget(Mobile m)
: base(Core.AOS ? 3 : 2, false, TargetFlags.None)
{
BeginTimeout(m, TimeSpan.FromSeconds(30.0));
}
protected override void OnTargetFinish(Mobile from)
{
if (m_SetSkillTime)
{
from.NextSkillTime = Core.TickCount;
}
}
protected override void OnTarget(Mobile from, object targeted)
{
from.RevealingAction();
if (targeted is Mobile)
{
if (targeted is BaseCreature)
{
BaseCreature creature = (BaseCreature)targeted;
if (!creature.Tamable)
{
creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049655, from.NetState);
// That creature cannot be tamed.
}
else if (creature.Controlled)
{
creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502804, from.NetState);
// That animal looks tame already.
}
else if (from.Female && !creature.AllowFemaleTamer)
{
creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049653, from.NetState);
// That creature can only be tamed by males.
}
else if (!from.Female && !creature.AllowMaleTamer)
{
creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049652, from.NetState);
// That creature can only be tamed by females.
}
else if (creature is CuSidhe && from.Race != Race.Elf)
{
creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502801, from.NetState); // You can't tame that!
}
else if (from.Followers + creature.ControlSlots > from.FollowersMax)
{
from.SendLocalizedMessage(1049611); // You have too many followers to tame that creature.
}
else if (creature.Owners.Count >= BaseCreature.MaxOwners && !creature.Owners.Contains(from))
{
creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1005615, from.NetState);
// This animal has had too many owners and is too upset for you to tame.
}
else if (MustBeSubdued(creature))
{
creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1054025, from.NetState);
// You must subdue this creature before you can tame it!
}
else if (DarkWolfFamiliar.CheckMastery(from, creature) || from.Skills[SkillName.AnimalTaming].Value >= creature.CurrentTameSkill)
{
FactionWarHorse warHorse = creature as FactionWarHorse;
if (warHorse != null)
{
Faction faction = Faction.Find(from);
if (faction == null || faction != warHorse.Faction)
{
creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042590, from.NetState);
// You cannot tame this creature.
return;
}
}
if (m_BeingTamed.Contains(targeted))
{
creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502802, from.NetState);
// Someone else is already taming this.
}
else if (creature.CanAngerOnTame && 0.95 >= Utility.RandomDouble())
{
creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502805, from.NetState);
// You seem to anger the beast!
creature.PlaySound(creature.GetAngerSound());
creature.Direction = creature.GetDirectionTo(from);
if (!Core.SA)
{
if (creature.BardPacified && Utility.RandomDouble() > .24)
{
Timer.DelayCall(TimeSpan.FromSeconds(2.0), () => creature.BardPacified = true);
}
else
{
creature.BardEndTime = DateTime.UtcNow;
}
creature.BardPacified = false;
}
if (creature.AIObject != null)
{
creature.AIObject.DoMove(creature.Direction);
}
if (from is PlayerMobile &&
!(((PlayerMobile)from).HonorActive ||
TransformationSpellHelper.UnderTransformation(from, typeof(EtherealVoyageSpell))))
{
creature.Combatant = from;
}
}
else
{
m_SetSkillTime = false;
m_BeingTamed[targeted] = from;
from.LocalOverheadMessage(MessageType.Emote, 0x59, 1010597); // You start to tame the creature.
from.NonlocalOverheadMessage(MessageType.Emote, 0x59, 1010598); // *begins taming a creature.*
new InternalTimer(from, creature, Utility.Random(3, 2)).Start();
}
}
else
{
creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502806, from.NetState);
// You have no chance of taming this creature.
}
}
else
{
((Mobile)targeted).PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502469, from.NetState);
// That being cannot be tamed.
}
}
else
{
from.SendLocalizedMessage(502801); // You can't tame that!
}
}
private class InternalTimer : Timer
{
private readonly Mobile m_Tamer;
private readonly BaseCreature m_Creature;
private readonly int m_MaxCount;
private readonly DateTime m_StartTime;
private int m_Count;
private bool m_Paralyzed;
public InternalTimer(Mobile tamer, BaseCreature creature, int count)
: base(TimeSpan.FromSeconds(3.0), TimeSpan.FromSeconds(3.0), count)
{
m_Tamer = tamer;
m_Creature = creature;
m_MaxCount = count;
m_Paralyzed = creature.Paralyzed;
m_StartTime = DateTime.UtcNow;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
m_Count++;
DamageEntry de = m_Creature.FindMostRecentDamageEntry(false);
bool alreadyOwned = m_Creature.Owners.Contains(m_Tamer);
if (!m_Tamer.InRange(m_Creature, Core.AOS ? 7 : 6))
{
m_BeingTamed.Remove(m_Creature);
m_Tamer.NextSkillTime = Core.TickCount;
m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502795, m_Tamer.NetState);
// You are too far away to continue taming.
Stop();
}
else if (!m_Tamer.CheckAlive())
{
m_BeingTamed.Remove(m_Creature);
m_Tamer.NextSkillTime = Core.TickCount;
m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502796, m_Tamer.NetState);
// You are dead, and cannot continue taming.
Stop();
}
else if (!m_Tamer.CanSee(m_Creature) || !m_Tamer.InLOS(m_Creature) || !CanPath())
{
m_BeingTamed.Remove(m_Creature);
m_Tamer.NextSkillTime = Core.TickCount;
m_Tamer.SendLocalizedMessage(1049654);
// You do not have a clear path to the animal you are taming, and must cease your attempt.
Stop();
}
else if (!m_Creature.Tamable)
{
m_BeingTamed.Remove(m_Creature);
m_Tamer.NextSkillTime = Core.TickCount;
m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049655, m_Tamer.NetState);
// That creature cannot be tamed.
Stop();
}
else if (m_Creature.Controlled)
{
m_BeingTamed.Remove(m_Creature);
m_Tamer.NextSkillTime = Core.TickCount;
m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502804, m_Tamer.NetState);
// That animal looks tame already.
Stop();
}
else if (m_Creature.Owners.Count >= BaseCreature.MaxOwners && !m_Creature.Owners.Contains(m_Tamer))
{
m_BeingTamed.Remove(m_Creature);
m_Tamer.NextSkillTime = Core.TickCount;
m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1005615, m_Tamer.NetState);
// This animal has had too many owners and is too upset for you to tame.
Stop();
}
else if (MustBeSubdued(m_Creature))
{
m_BeingTamed.Remove(m_Creature);
m_Tamer.NextSkillTime = Core.TickCount;
m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1054025, m_Tamer.NetState);
// You must subdue this creature before you can tame it!
Stop();
}
else if (de != null && de.LastDamage > m_StartTime)
{
m_BeingTamed.Remove(m_Creature);
m_Tamer.NextSkillTime = Core.TickCount;
m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502794, m_Tamer.NetState);
// The animal is too angry to continue taming.
Stop();
}
else if (m_Count < m_MaxCount)
{
m_Tamer.RevealingAction();
switch (Utility.Random(3))
{
case 0:
m_Tamer.PublicOverheadMessage(MessageType.Regular, 0x3B2, Utility.Random(502790, 4));
break;
case 1:
m_Tamer.PublicOverheadMessage(MessageType.Regular, 0x3B2, Utility.Random(1005608, 6));
break;
case 2:
m_Tamer.PublicOverheadMessage(MessageType.Regular, 0x3B2, Utility.Random(1010593, 4));
break;
}
if (!alreadyOwned) // Passively check animal lore for gain
{
m_Tamer.CheckTargetSkill(SkillName.AnimalLore, m_Creature, 0.0, 120.0);
}
if (m_Creature.Paralyzed)
{
m_Paralyzed = true;
}
}
else
{
m_Tamer.RevealingAction();
m_Tamer.NextSkillTime = Core.TickCount;
m_BeingTamed.Remove(m_Creature);
if (m_Creature.Paralyzed)
{
m_Paralyzed = true;
}
if (!alreadyOwned) // Passively check animal lore for gain
{
m_Tamer.CheckTargetSkill(SkillName.AnimalLore, m_Creature, 0.0, 120.0);
}
double minSkill = m_Creature.CurrentTameSkill + (m_Creature.Owners.Count * 6.0);
bool necroMastery = DarkWolfFamiliar.CheckMastery(m_Tamer, m_Creature);
if (minSkill > -24.9 && necroMastery)
{
minSkill = -24.9; // 50% at 0.0?
}
minSkill += 24.9;
if (necroMastery || alreadyOwned ||
m_Tamer.CheckTargetSkill(SkillName.AnimalTaming, m_Creature, minSkill - 25.0, minSkill + 25.0))
{
if (m_Creature.Owners.Count == 0) // First tame
{
if (m_Creature is GreaterDragon)
{
ScaleSkills(m_Creature, 0.72, 0.90, true); // 72% of original skills trainable to 90%
m_Creature.Skills[SkillName.Magery].Base = m_Creature.Skills[SkillName.Magery].Cap;
// Greater dragons have a 90% cap reduction and 90% skill reduction on magery
}
else if (m_Paralyzed)
{
ScaleSkills(m_Creature, 0.86, true); // 86% of original skills if they were paralyzed during the taming
}
else
{
ScaleSkills(m_Creature, 0.90, true); // 90% of original skills
}
}
else
{
ScaleSkills(m_Creature, 0.90, false); // 90% of original skills
}
if (alreadyOwned)
{
m_Tamer.SendLocalizedMessage(502797); // That wasn't even challenging.
}
else
{
m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502799, m_Tamer.NetState);
// It seems to accept you as master.
}
m_Creature.SetControlMaster(m_Tamer);
m_Creature.IsBonded = false;
m_Creature.OnAfterTame(m_Tamer);
if (!m_Creature.Owners.Contains(m_Tamer))
{
m_Creature.Owners.Add(m_Tamer);
}
PetTrainingHelper.GetAbilityProfile(m_Creature, true).OnTame();
EventSink.InvokeTameCreature(new TameCreatureEventArgs(m_Tamer, m_Creature));
}
else
{
m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502798, m_Tamer.NetState);
// You fail to tame the creature.
}
}
}
private bool CanPath()
{
IPoint3D p = m_Tamer;
if (p == null)
{
return false;
}
if (m_Creature.InRange(new Point3D(p), 1))
{
return true;
}
MovementPath path = new MovementPath(m_Creature, new Point3D(p));
return path.Success;
}
}
}
}
}

167
Scripts/Skills/ArmsLore.cs Normal file
View File

@@ -0,0 +1,167 @@
using System;
using Server.Items;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.SkillHandlers
{
public class ArmsLore
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.ArmsLore].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile m)
{
m.Target = new InternalTarget();
m.SendLocalizedMessage(500349); // What item do you wish to get information about?
return TimeSpan.FromSeconds(1.0);
}
[PlayerVendorTarget]
private class InternalTarget : Target
{
public InternalTarget()
: base(2, false, TargetFlags.None)
{
this.AllowNonlocal = true;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is BaseWeapon)
{
if (from.CheckTargetSkill(SkillName.ArmsLore, targeted, 0, 100))
{
BaseWeapon weap = (BaseWeapon)targeted;
if (weap.MaxHitPoints != 0)
{
int hp = (int)((weap.HitPoints / (double)weap.MaxHitPoints) * 10);
if (hp < 0)
hp = 0;
else if (hp > 9)
hp = 9;
from.SendLocalizedMessage(1038285 + hp);
}
int damage = (weap.MaxDamage + weap.MinDamage) / 2;
int hand = (weap.Layer == Layer.OneHanded ? 0 : 1);
if (damage < 3)
damage = 0;
else
damage = (int)Math.Ceiling(Math.Min(damage, 30) / 5.0);
/*
else if ( damage < 6 )
damage = 1;
else if ( damage < 11 )
damage = 2;
else if ( damage < 16 )
damage = 3;
else if ( damage < 21 )
damage = 4;
else if ( damage < 26 )
damage = 5;
else
damage = 6;
* */
WeaponType type = weap.Type;
if (type == WeaponType.Ranged)
from.SendLocalizedMessage(1038224 + (damage * 9));
else if (type == WeaponType.Piercing)
from.SendLocalizedMessage(1038218 + hand + (damage * 9));
else if (type == WeaponType.Slashing)
from.SendLocalizedMessage(1038220 + hand + (damage * 9));
else if (type == WeaponType.Bashing)
from.SendLocalizedMessage(1038222 + hand + (damage * 9));
else
from.SendLocalizedMessage(1038216 + hand + (damage * 9));
if (weap.Poison != null && weap.PoisonCharges > 0)
from.SendLocalizedMessage(1038284); // It appears to have poison smeared on it.
}
else
{
from.SendLocalizedMessage(500353); // You are not certain...
}
}
else if (targeted is BaseArmor)
{
if (from.CheckTargetSkill(SkillName.ArmsLore, targeted, 0, 100))
{
BaseArmor arm = (BaseArmor)targeted;
if (arm.MaxHitPoints != 0)
{
int hp = (int)((arm.HitPoints / (double)arm.MaxHitPoints) * 10);
if (hp < 0)
hp = 0;
else if (hp > 9)
hp = 9;
from.SendLocalizedMessage(1038285 + hp);
}
from.SendLocalizedMessage(1038295 + (int)Math.Ceiling(Math.Min(arm.ArmorRating, 35) / 5.0));
/*
if ( arm.ArmorRating < 1 )
from.SendLocalizedMessage( 1038295 ); // This armor offers no defense against attackers.
else if ( arm.ArmorRating < 6 )
from.SendLocalizedMessage( 1038296 ); // This armor provides almost no protection.
else if ( arm.ArmorRating < 11 )
from.SendLocalizedMessage( 1038297 ); // This armor provides very little protection.
else if ( arm.ArmorRating < 16 )
from.SendLocalizedMessage( 1038298 ); // This armor offers some protection against blows.
else if ( arm.ArmorRating < 21 )
from.SendLocalizedMessage( 1038299 ); // This armor serves as sturdy protection.
else if ( arm.ArmorRating < 26 )
from.SendLocalizedMessage( 1038300 ); // This armor is a superior defense against attack.
else if ( arm.ArmorRating < 31 )
from.SendLocalizedMessage( 1038301 ); // This armor offers excellent protection.
else
from.SendLocalizedMessage( 1038302 ); // This armor is superbly crafted to provide maximum protection.
* */
}
else
{
from.SendLocalizedMessage(500353); // You are not certain...
}
}
else if (targeted is SwampDragon && ((SwampDragon)targeted).HasBarding)
{
SwampDragon pet = (SwampDragon)targeted;
if (from.CheckTargetSkill(SkillName.ArmsLore, targeted, 0, 100))
{
int perc = (4 * pet.BardingHP) / pet.BardingMaxHP;
if (perc < 0)
perc = 0;
else if (perc > 4)
perc = 4;
pet.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1053021 - perc, from.NetState);
}
else
{
from.SendLocalizedMessage(500353); // You are not certain...
}
}
else
{
from.SendLocalizedMessage(500352); // This is neither weapon nor armor.
}
}
}
}
}

336
Scripts/Skills/Begging.cs Normal file
View File

@@ -0,0 +1,336 @@
#region References
using System;
using Server.Items;
using Server.Misc;
using Server.Network;
using Server.Targeting;
#endregion
namespace Server.SkillHandlers
{
public class Begging
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.Begging].Callback = OnUse;
}
public static TimeSpan OnUse(Mobile m)
{
m.RevealingAction();
m.SendLocalizedMessage(500397); // To whom do you wish to grovel?
Timer.DelayCall(() => m.Target = new InternalTarget());
return TimeSpan.FromHours(1.0);
}
private class InternalTarget : Target
{
private bool m_SetSkillTime = true;
public InternalTarget()
: base(12, false, TargetFlags.None)
{ }
protected override void OnTargetFinish(Mobile from)
{
if (m_SetSkillTime)
{
from.NextSkillTime = Core.TickCount;
}
}
protected override void OnTarget(Mobile from, object targeted)
{
from.RevealingAction();
int number = -1;
if (targeted is Mobile)
{
Mobile targ = (Mobile)targeted;
if (targ.Player) // We can't beg from players
{
number = 500398; // Perhaps just asking would work better.
}
else if (!targ.Body.IsHuman) // Make sure the NPC is human
{
number = 500399; // There is little chance of getting money from that!
}
else if (!from.InRange(targ, 2))
{
if (!targ.Female)
{
number = 500401; // You are too far away to beg from him.
}
else
{
number = 500402; // You are too far away to beg from her.
}
}
else if (!Core.ML && from.Mounted) // If we're on a mount, who would give us money? TODO: guessed it's removed since ML
{
number = 500404; // They seem unwilling to give you any money.
}
else
{
// Face eachother
from.Direction = from.GetDirectionTo(targ);
targ.Direction = targ.GetDirectionTo(from);
from.Animate(32, 5, 1, true, false, 0); // Bow
new InternalTimer(from, targ).Start();
m_SetSkillTime = false;
}
}
else // Not a Mobile
{
number = 500399; // There is little chance of getting money from that!
}
if (number != -1)
{
from.SendLocalizedMessage(number);
}
}
private class InternalTimer : Timer
{
private readonly Mobile m_From;
private readonly Mobile m_Target;
public InternalTimer(Mobile from, Mobile target)
: base(TimeSpan.FromSeconds(2.0))
{
m_From = from;
m_Target = target;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
Container theirPack = m_Target.Backpack;
double badKarmaChance = 0.5 - ((double)m_From.Karma / 8570);
if (theirPack == null && m_Target.Race != Race.Elf)
{
m_From.SendLocalizedMessage(500404); // They seem unwilling to give you any money.
}
else if (m_From.Karma < 0 && badKarmaChance > Utility.RandomDouble())
{
m_Target.PublicOverheadMessage(MessageType.Regular, m_Target.SpeechHue, 500406);
// Thou dost not look trustworthy... no gold for thee today!
}
else if (m_From.CheckTargetSkill(SkillName.Begging, m_Target, 0.0, 100.0))
{
if (m_Target.Race != Race.Elf)
{
int toConsume = theirPack.GetAmount(typeof(Gold)) / 10;
int max = 10 + (m_From.Fame / 2500);
if (max > 14)
{
max = 14;
}
else if (max < 10)
{
max = 10;
}
if (toConsume > max)
{
toConsume = max;
}
if (toConsume > 0)
{
int consumed = theirPack.ConsumeUpTo(typeof(Gold), toConsume);
if (consumed > 0)
{
m_Target.PublicOverheadMessage(MessageType.Regular, m_Target.SpeechHue, 500405);
// I feel sorry for thee...
Gold gold = new Gold(consumed);
m_From.AddToBackpack(gold);
m_From.PlaySound(gold.GetDropSound());
if (m_From.Karma > -3000)
{
int toLose = m_From.Karma + 3000;
if (toLose > 40)
{
toLose = 40;
}
Titles.AwardKarma(m_From, -toLose, true);
}
}
else
{
m_Target.PublicOverheadMessage(MessageType.Regular, m_Target.SpeechHue, 500407);
// I have not enough money to give thee any!
}
}
else
{
m_Target.PublicOverheadMessage(MessageType.Regular, m_Target.SpeechHue, 500407);
// I have not enough money to give thee any!
}
}
else
{
double chance = Utility.RandomDouble();
Item reward = null;
string rewardName = "";
if (chance >= .99)
{
int rand = Utility.Random(8);
if (rand == 0)
{
reward = new BegBedRoll();
rewardName = "a bedroll";
}
else if (rand == 1)
{
reward = new BegCookies();
rewardName = "a plate of cookies.";
}
else if (rand == 2)
{
reward = new BegFishSteak();
rewardName = "a fish steak.";
}
else if (rand == 3)
{
reward = new BegFishingPole();
rewardName = "a fishing pole.";
}
else if (rand == 4)
{
reward = new BegFlowerGarland();
rewardName = "a flower garland.";
}
else if (rand == 5)
{
reward = new BegSake();
rewardName = "a bottle of Sake.";
}
else if (rand == 6)
{
reward = new BegTurnip();
rewardName = "a turnip.";
}
else if (rand == 7)
{
reward = new BegWine();
rewardName = "a Bottle of wine.";
}
else if (rand == 8)
{
reward = new BegWinePitcher();
rewardName = "a Pitcher of wine.";
}
}
else if (chance >= .76)
{
int rand = Utility.Random(6);
if (rand == 0)
{
reward = new BegStew();
rewardName = "a bowl of stew.";
}
else if (rand == 1)
{
reward = new BegCheeseWedge();
rewardName = "a wedge of cheese.";
}
else if (rand == 2)
{
reward = new BegDates();
rewardName = "a bunch of dates.";
}
else if (rand == 3)
{
reward = new BegLantern();
rewardName = "a lantern.";
}
else if (rand == 4)
{
reward = new BegLiquorPitcher();
rewardName = "a Pitcher of liquor";
}
else if (rand == 5)
{
reward = new BegPizza();
rewardName = "pizza";
}
else if (rand == 6)
{
reward = new BegShirt();
rewardName = "a shirt.";
}
}
else if (chance >= .25)
{
int rand = Utility.Random(1);
if (rand == 0)
{
reward = new BegFrenchBread();
rewardName = "french bread.";
}
else
{
reward = new BegWaterPitcher();
rewardName = "a Pitcher of water.";
}
}
if (reward == null)
{
reward = new Gold(1);
}
m_Target.Say(1074854); // Here, take this...
m_From.AddToBackpack(reward);
m_From.SendLocalizedMessage(1074853, rewardName); // You have been given ~1_name~
if (m_From.Karma > -3000)
{
int toLose = m_From.Karma + 3000;
if (toLose > 40)
{
toLose = 40;
}
Titles.AwardKarma(m_From, -toLose, true);
}
}
}
else
{
m_Target.SendLocalizedMessage(500404); // They seem unwilling to give you any money.
}
m_From.NextSkillTime = Core.TickCount + 10000;
}
}
}
}
}

View File

@@ -0,0 +1,211 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Factions;
using Server.Mobiles;
using Server.Multis;
using Server.Targeting;
using Server.Engines.VvV;
using Server.Items;
using Server.Spells;
using Server.Network;
namespace Server.Items
{
public interface IRevealableItem
{
bool CheckReveal(Mobile m);
bool CheckPassiveDetect(Mobile m);
void OnRevealed(Mobile m);
bool CheckWhenHidden { get; }
}
}
namespace Server.SkillHandlers
{
public class DetectHidden
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.DetectHidden].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile src)
{
src.SendLocalizedMessage(500819);//Where will you search?
src.Target = new InternalTarget();
return TimeSpan.FromSeconds(10.0);
}
public class InternalTarget : Target
{
public InternalTarget()
: base(12, true, TargetFlags.None)
{
}
protected override void OnTarget(Mobile src, object targ)
{
bool foundAnyone = false;
Point3D p;
if (targ is Mobile)
p = ((Mobile)targ).Location;
else if (targ is Item)
p = ((Item)targ).Location;
else if (targ is IPoint3D)
p = new Point3D((IPoint3D)targ);
else
p = src.Location;
double srcSkill = src.Skills[SkillName.DetectHidden].Value;
int range = Math.Max(2, (int)(srcSkill / 10.0));
if (!src.CheckSkill(SkillName.DetectHidden, 0.0, 100.0))
range /= 2;
BaseHouse house = BaseHouse.FindHouseAt(p, src.Map, 16);
bool inHouse = house != null && house.IsFriend(src);
if (inHouse)
range = 22;
if (range > 0)
{
IPooledEnumerable inRange = src.Map.GetMobilesInRange(p, range);
foreach (Mobile trg in inRange)
{
if (trg.Hidden && src != trg)
{
double ss = srcSkill + Utility.Random(21) - 10;
double ts = trg.Skills[SkillName.Hiding].Value + Utility.Random(21) - 10;
double shadow = Server.Spells.SkillMasteries.ShadowSpell.GetDifficultyFactor(trg);
bool houseCheck = inHouse && house.IsInside(trg);
if (src.AccessLevel >= trg.AccessLevel && (ss >= ts || houseCheck) && Utility.RandomDouble() > shadow)
{
if ((trg is ShadowKnight && (trg.X != p.X || trg.Y != p.Y)) ||
(!houseCheck && !CanDetect(src, trg)))
continue;
trg.RevealingAction();
trg.SendLocalizedMessage(500814); // You have been revealed!
trg.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500814, trg.NetState);
foundAnyone = true;
}
}
}
inRange.Free();
IPooledEnumerable itemsInRange = src.Map.GetItemsInRange(p, range);
foreach (Item item in itemsInRange)
{
if (item is LibraryBookcase && Server.Engines.Khaldun.GoingGumshoeQuest3.CheckBookcase(src, item))
{
foundAnyone = true;
}
else
{
IRevealableItem dItem = item as IRevealableItem;
if (dItem == null || (item.Visible && dItem.CheckWhenHidden))
continue;
if (dItem.CheckReveal(src))
{
dItem.OnRevealed(src);
foundAnyone = true;
}
}
}
itemsInRange.Free();
}
if (!foundAnyone)
{
src.SendLocalizedMessage(500817); // You can see nothing hidden there.
}
}
}
public static void DoPassiveDetect(Mobile src)
{
if (src == null || src.Map == null || src.Location == Point3D.Zero || src.IsStaff())
return;
double ss = src.Skills[SkillName.DetectHidden].Value;
if (ss <= 0)
return;
IPooledEnumerable eable = src.Map.GetMobilesInRange(src.Location, 4);
if (eable == null)
return;
foreach (Mobile m in eable)
{
if (m == null || m == src || m is ShadowKnight || !CanDetect(src, m))
continue;
double ts = (m.Skills[SkillName.Hiding].Value + m.Skills[SkillName.Stealth].Value) / 2;
if (src.Race == Race.Elf)
ss += 20;
if (src.AccessLevel >= m.AccessLevel && Utility.Random(1000) < (ss - ts) + 1)
{
m.RevealingAction();
m.SendLocalizedMessage(500814); // You have been revealed!
}
}
eable.Free();
eable = src.Map.GetItemsInRange(src.Location, 8);
foreach (Item item in eable)
{
if (!item.Visible && item is IRevealableItem && ((IRevealableItem)item).CheckPassiveDetect(src))
{
src.SendLocalizedMessage(1153493); // Your keen senses detect something hidden in the area...
}
}
eable.Free();
}
public static bool CanDetect(Mobile src, Mobile target)
{
if (src.Map == null || target.Map == null || !src.CanBeHarmful(target, false))
return false;
// No invulnerable NPC's
if (src.Blessed || (src is BaseCreature && ((BaseCreature)src).IsInvulnerable))
return false;
if (target.Blessed || (target is BaseCreature && ((BaseCreature)target).IsInvulnerable))
return false;
// pet owner, guild/alliance, party
if (!Server.Spells.SpellHelper.ValidIndirectTarget(target, src))
return false;
// Checked aggressed/aggressors
if (src.Aggressed.Any(x => x.Defender == target) || src.Aggressors.Any(x => x.Attacker == target))
return true;
// In Fel or Follow the same rules as indirect spells such as wither
return src.Map.Rules == MapRules.FeluccaRules;
}
}
}

View File

@@ -0,0 +1,450 @@
#region References
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Server.Engines.XmlSpawner2;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
using Server.Engines.Quests;
#endregion
namespace Server.SkillHandlers
{
public class Discordance
{
private static readonly Dictionary<Mobile, DiscordanceInfo> m_Table = new Dictionary<Mobile, DiscordanceInfo>();
public static bool UnderEffects(Mobile m)
{
return m != null && m_Table.ContainsKey(m) && !m_Table[m].m_PVP;
}
public static bool UnderPVPEffects(Mobile m)
{
return m != null && m_Table.ContainsKey(m) && m_Table[m].m_PVP;
}
public static void RemoveEffects(Mobile m)
{
if (m_Table.ContainsKey(m))
{
m_Table.Remove(m);
}
}
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.Discordance].Callback = OnUse;
}
public static TimeSpan OnUse(Mobile m)
{
m.RevealingAction();
BaseInstrument.PickInstrument(m, OnPickedInstrument);
return TimeSpan.FromSeconds(1.0); // Cannot use another skill for 1 second
}
public static void OnPickedInstrument(Mobile from, BaseInstrument instrument)
{
from.RevealingAction();
from.SendLocalizedMessage(1049541); // Choose the target for your song of discordance.
from.Target = new DiscordanceTarget(from, instrument);
from.NextSkillTime = Core.TickCount + 6000;
}
public static bool GetEffect(Mobile targ, ref int effect)
{
return GetEffect(targ, ref effect, false);
}
public static bool GetEffect(Mobile targ, ref int effect, bool pvp)
{
if (!m_Table.ContainsKey(targ) || m_Table[targ].m_PVP != pvp)
{
return false;
}
DiscordanceInfo info = m_Table[targ];
effect = info.m_Effect;
return true;
}
private static void ProcessDiscordance(DiscordanceInfo info)
{
Mobile from = info.m_From;
Mobile targ = info.m_Target;
bool ends = false;
if (info.m_PVP && info.m_Expires < DateTime.UtcNow)
{
DiscordanceInfo.RemoveDiscord(info);
}
else
{
// According to uoherald bard must remain alive, visible, and
// within range of the target or the effect ends in 15 seconds.
if (!targ.Alive || targ.Deleted || targ.IsDeadBondedPet || !from.Alive || from.Hidden || targ.Hidden || from.IsDeadBondedPet)
{
ends = true;
}
else
{
int range = (int)targ.GetDistanceToSqrt(from);
int maxRange = BaseInstrument.GetBardRange(from, SkillName.Discordance);
Map targetMap = targ.Map;
if (targ is BaseMount && ((BaseMount)targ).Rider != null)
{
Mobile rider = ((BaseMount)targ).Rider;
range = (int)rider.GetDistanceToSqrt(from);
targetMap = rider.Map;
}
if (from.Map != targetMap || range > maxRange)
{
ends = true;
}
}
if (ends && info.m_Ending && info.m_EndTime < DateTime.UtcNow)
{
DiscordanceInfo.RemoveDiscord(info);
}
else
{
if (ends && !info.m_Ending)
{
info.m_Ending = true;
info.m_EndTime = DateTime.UtcNow + TimeSpan.FromSeconds(15);
}
else if (!ends)
{
info.m_Ending = false;
info.m_EndTime = DateTime.UtcNow;
}
targ.FixedEffect(0x376A, 1, 32);
}
}
}
public class DiscordanceTarget : Target
{
private readonly BaseInstrument m_Instrument;
public DiscordanceTarget(Mobile from, BaseInstrument inst)
: base(BaseInstrument.GetBardRange(from, SkillName.Discordance), false, TargetFlags.None)
{
m_Instrument = inst;
}
protected override void OnTarget(Mobile from, object target)
{
from.RevealingAction();
from.NextSkillTime = Core.TickCount + 1000;
if (!m_Instrument.IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(1062488); // The instrument you are trying to play is no longer in your backpack!
}
else if (target is Mobile)
{
Mobile targ = (Mobile)target;
if (targ == from || !from.CanBeHarmful(targ, false) ||
(targ is BaseCreature && ((BaseCreature)targ).BardImmune && ((BaseCreature)targ).ControlMaster != from))
{
from.SendLocalizedMessage(1049535); // A song of discord would have no effect on that.
}
else if (m_Table.ContainsKey(targ)) //Already discorded
{
from.SendLocalizedMessage(1049537); // Your target is already in discord.
}
else if (!targ.Player || (from is BaseCreature && ((BaseCreature)from).CanDiscord) || (Core.EJ && targ.Player && from.Player && CanDiscordPVP(from)))
{
double diff = m_Instrument.GetDifficultyFor(targ) - 10.0;
double music = from.Skills[SkillName.Musicianship].Value;
if (from is BaseCreature)
music = 120.0;
int masteryBonus = 0;
if (music > 100.0)
{
diff -= (music - 100.0) * 0.5;
}
if (from is PlayerMobile)
{
masteryBonus = Spells.SkillMasteries.BardSpell.GetMasteryBonus((PlayerMobile)from, SkillName.Discordance);
}
if (masteryBonus > 0)
{
diff -= (diff * ((double)masteryBonus / 100));
}
if (!BaseInstrument.CheckMusicianship(from))
{
from.SendLocalizedMessage(500612); // You play poorly, and there is no effect.
m_Instrument.PlayInstrumentBadly(from);
m_Instrument.ConsumeUse(from);
}
else if (from.CheckTargetSkill(SkillName.Discordance, target, diff - 25.0, diff + 25.0))
{
from.SendLocalizedMessage(1049539); // You play the song surpressing your targets strength
if (targ.Player)
targ.SendLocalizedMessage(1072061); // You hear jarring music, suppressing your strength.
m_Instrument.PlayInstrumentWell(from);
m_Instrument.ConsumeUse(from);
DiscordanceInfo info;
if (Core.EJ && targ.Player && from.Player)
{
info = new DiscordanceInfo(from, targ, 0, null, true, from.Skills.CurrentMastery == SkillName.Discordance ? 6 : 4);
from.DoHarmful(targ);
}
else
{
ArrayList mods = new ArrayList();
int effect;
double scalar;
if (Core.AOS)
{
double discord = from.Skills[SkillName.Discordance].Value;
effect = (int)Math.Max(-28.0, (discord / -4.0));
if (Core.SE && BaseInstrument.GetBaseDifficulty(targ) >= 160.0)
{
effect /= 2;
}
scalar = (double)effect / 100;
mods.Add(new ResistanceMod(ResistanceType.Physical, effect));
mods.Add(new ResistanceMod(ResistanceType.Fire, effect));
mods.Add(new ResistanceMod(ResistanceType.Cold, effect));
mods.Add(new ResistanceMod(ResistanceType.Poison, effect));
mods.Add(new ResistanceMod(ResistanceType.Energy, effect));
for (int i = 0; i < targ.Skills.Length; ++i)
{
if (targ.Skills[i].Value > 0)
{
mods.Add(new DefaultSkillMod((SkillName)i, true, targ.Skills[i].Value * scalar));
}
}
}
else
{
effect = (int)(from.Skills[SkillName.Discordance].Value / -5.0);
scalar = effect * 0.01;
mods.Add(new StatMod(StatType.Str, "DiscordanceStr", (int)(targ.RawStr * scalar), TimeSpan.Zero));
mods.Add(new StatMod(StatType.Int, "DiscordanceInt", (int)(targ.RawInt * scalar), TimeSpan.Zero));
mods.Add(new StatMod(StatType.Dex, "DiscordanceDex", (int)(targ.RawDex * scalar), TimeSpan.Zero));
for (int i = 0; i < targ.Skills.Length; ++i)
{
if (targ.Skills[i].Value > 0)
{
mods.Add(new DefaultSkillMod((SkillName)i, true, Math.Max(100, targ.Skills[i].Value) * scalar));
}
}
}
info = new DiscordanceInfo(from, targ, Math.Abs(effect), mods);
#region Bard Mastery Quest
if (from is PlayerMobile)
{
BaseQuest quest = QuestHelper.GetQuest((PlayerMobile)from, typeof(WieldingTheSonicBladeQuest));
if (quest != null)
{
foreach (BaseObjective objective in quest.Objectives)
objective.Update(targ);
}
}
#endregion
}
info.m_Timer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromSeconds(1.25), ProcessDiscordance, info);
m_Table[targ] = info;
from.NextSkillTime = Core.TickCount + (8000 - ((masteryBonus / 5) * 1000));
}
else
{
if (from is BaseCreature && PetTrainingHelper.Enabled)
from.CheckSkill(SkillName.Discordance, 0, from.Skills[SkillName.Discordance].Cap);
from.SendLocalizedMessage(1049540); // You attempt to disrupt your target, but fail.
if (targ.Player)
targ.SendLocalizedMessage(1072064); // You hear jarring music, but it fails to disrupt you.
m_Instrument.PlayInstrumentBadly(from);
m_Instrument.ConsumeUse(from);
from.NextSkillTime = Core.TickCount + 5000;
}
}
else
{
m_Instrument.PlayInstrumentBadly(from);
}
}
else
{
from.SendLocalizedMessage(1049535); // A song of discord would have no effect on that.
}
}
private bool CanDiscordPVP(Mobile m)
{
return !m_Table.Values.Any(info => info.m_From == m && info.m_PVP);
}
}
private class DiscordanceInfo
{
public readonly Mobile m_From;
public readonly Mobile m_Target;
public readonly int m_Effect;
public readonly ArrayList m_Mods;
public DateTime m_EndTime;
public bool m_Ending;
public Timer m_Timer;
// Pub 103 PVP Additions
public DateTime m_Expires;
public readonly bool m_PVP;
public DiscordanceInfo(Mobile from, Mobile creature, int effect, ArrayList mods)
: this(from, creature, effect, mods, false, 0)
{
}
public DiscordanceInfo(Mobile from, Mobile creature, int effect, ArrayList mods, bool pvp, int duration)
{
m_From = from;
m_Target = creature;
m_EndTime = DateTime.UtcNow;
m_Ending = false;
m_Effect = effect;
m_Mods = mods;
m_PVP = pvp;
if (m_PVP)
{
m_Expires = DateTime.UtcNow + TimeSpan.FromSeconds(duration);
}
Apply();
}
public void Apply()
{
if (m_PVP)
{
foreach (var item in m_Target.Items)
{
var bonuses = RunicReforging.GetAosSkillBonuses(item);
if (bonuses != null)
{
bonuses.Remove();
}
}
}
else
{
for (int i = 0; i < m_Mods.Count; ++i)
{
object mod = m_Mods[i];
if (mod is ResistanceMod)
{
m_Target.AddResistanceMod((ResistanceMod)mod);
}
else if (mod is StatMod)
{
m_Target.AddStatMod((StatMod)mod);
}
else if (mod is SkillMod)
{
m_Target.AddSkillMod((SkillMod)mod);
}
}
}
}
public void Clear()
{
if (m_PVP)
{
Timer.DelayCall(() =>
{
foreach (var item in m_Target.Items)
{
var bonuses = RunicReforging.GetAosSkillBonuses(item);
if (bonuses != null)
{
bonuses.AddTo(m_Target);
}
}
});
}
else
{
for (int i = 0; i < m_Mods.Count; ++i)
{
object mod = m_Mods[i];
if (mod is ResistanceMod)
{
m_Target.RemoveResistanceMod((ResistanceMod)mod);
}
else if (mod is StatMod)
{
m_Target.RemoveStatMod(((StatMod)mod).Name);
}
else if (mod is SkillMod)
{
m_Target.RemoveSkillMod((SkillMod)mod);
}
}
}
}
public static void RemoveDiscord(DiscordanceInfo info)
{
if (info.m_Timer != null)
{
info.m_Timer.Stop();
}
var targ = info.m_Target;
info.Clear();
Discordance.RemoveEffects(targ);
}
}
}
}

93
Scripts/Skills/EvalInt.cs Normal file
View File

@@ -0,0 +1,93 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.SkillHandlers
{
public class EvalInt
{
public static void Initialize()
{
SkillInfo.Table[16].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile m)
{
m.Target = new EvalInt.InternalTarget();
m.SendLocalizedMessage(500906); // What do you wish to evaluate?
return TimeSpan.FromSeconds(1.0);
}
private class InternalTarget : Target
{
public InternalTarget()
: base(8, false, TargetFlags.None)
{
}
protected override void OnTarget(Mobile from, object targeted)
{
if (from == targeted)
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500910); // Hmm, that person looks really silly.
}
else if (targeted is TownCrier)
{
((TownCrier)targeted).PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500907, from.NetState); // He looks smart enough to remember the news. Ask him about it.
}
else if (targeted is BaseVendor && ((BaseVendor)targeted).IsInvulnerable)
{
((BaseVendor)targeted).PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500909, from.NetState); // That person could probably calculate the cost of what you buy from them.
}
else if (targeted is Mobile)
{
Mobile targ = (Mobile)targeted;
int marginOfError = Math.Max(0, 20 - (int)(from.Skills[SkillName.EvalInt].Value / 5));
int intel = targ.Int + Utility.RandomMinMax(-marginOfError, +marginOfError);
int mana = ((targ.Mana * 100) / Math.Max(targ.ManaMax, 1)) + Utility.RandomMinMax(-marginOfError, +marginOfError);
int intMod = intel / 10;
int mnMod = mana / 10;
if (intMod > 10)
intMod = 10;
else if (intMod < 0)
intMod = 0;
if (mnMod > 10)
mnMod = 10;
else if (mnMod < 0)
mnMod = 0;
int body;
if (targ.Body.IsHuman)
body = targ.Female ? 11 : 0;
else
body = 22;
if (from.CheckTargetSkill(SkillName.EvalInt, targ, 0.0, 120.0))
{
targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038169 + intMod + body, from.NetState); // He/She/It looks [slighly less intelligent than a rock.] [Of Average intellect] [etc...]
if (from.Skills[SkillName.EvalInt].Base >= 76.0)
targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038202 + mnMod, from.NetState); // That being is at [10,20,...] percent mental strength.
}
else
{
targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038166 + (body / 11), from.NetState); // You cannot judge his/her/its mental abilities.
}
}
else if (targeted is Item)
{
((Item)targeted).SendLocalizedMessageTo(from, 500908, ""); // It looks smarter than a rock, but dumber than a piece of wood.
}
}
}
}
}

View File

@@ -0,0 +1,173 @@
using System;
using System.Linq;
using System.Text;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.SkillHandlers
{
public interface IForensicTarget
{
void OnForensicEval(Mobile m);
}
public class ForensicEvaluation
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.Forensics].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile m)
{
m.Target = new ForensicTarget();
m.RevealingAction();
m.SendLocalizedMessage(501000); // Show me the crime.
return TimeSpan.FromSeconds(1.0);
}
public class ForensicTarget : Target
{
public ForensicTarget()
: base(10, false, TargetFlags.None)
{
}
protected override void OnTarget(Mobile from, object target)
{
double skill = from.Skills[SkillName.Forensics].Value;
double minSkill = 30.0;
if (target is Corpse)
{
if (skill < minSkill)
{
from.SendLocalizedMessage(501003); //You notice nothing unusual.
return;
}
if (from.CheckTargetSkill(SkillName.Forensics, target, minSkill, 55.0))
{
Corpse c = (Corpse)target;
if (c.m_Forensicist != null)
from.SendLocalizedMessage(1042750, c.m_Forensicist); // The forensicist ~1_NAME~ has already discovered that:
else
c.m_Forensicist = from.Name;
if (((Body)c.Amount).IsHuman)
from.SendLocalizedMessage(1042751, (c.Killer == null ? "no one" : c.Killer.Name));//This person was killed by ~1_KILLER_NAME~
if (c.Looters.Count > 0)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < c.Looters.Count; i++)
{
if (i > 0)
sb.Append(", ");
sb.Append(((Mobile)c.Looters[i]).Name);
}
from.SendLocalizedMessage(1042752, sb.ToString());//This body has been distrubed by ~1_PLAYER_NAMES~
}
else
{
from.SendLocalizedMessage(501002);//The corpse has not be desecrated.
}
}
else
{
from.SendLocalizedMessage(501001);//You cannot determain anything useful.
}
}
else if (target is Mobile)
{
if (skill < 36.0)
{
from.SendLocalizedMessage(501003);//You notice nothing unusual.
}
else if (from.CheckTargetSkill(SkillName.Forensics, target, 36.0, 100.0))
{
if (target is PlayerMobile && ((PlayerMobile)target).NpcGuild == NpcGuild.ThievesGuild)
{
from.SendLocalizedMessage(501004);//That individual is a thief!
}
else
{
from.SendLocalizedMessage(501003);//You notice nothing unusual.
}
}
else
{
from.SendLocalizedMessage(501001);//You cannot determain anything useful.
}
}
else if (target is ILockpickable)
{
if (skill < 41.0)
{
from.SendLocalizedMessage(501003); //You notice nothing unusual.
}
else if (from.CheckTargetSkill(SkillName.Forensics, target, 41.0, 100.0))
{
ILockpickable p = (ILockpickable)target;
if (p.Picker != null)
{
from.SendLocalizedMessage(1042749, p.Picker.Name);//This lock was opened by ~1_PICKER_NAME~
}
else
{
from.SendLocalizedMessage(501003);//You notice nothing unusual.
}
}
else
{
from.SendLocalizedMessage(501001);//You cannot determain anything useful.
}
}
else if (Core.SA && target is Item)
{
Item item = (Item)target;
if (item is IForensicTarget)
{
((IForensicTarget)item).OnForensicEval(from);
}
else if (skill < 41.0)
{
from.SendLocalizedMessage(501001);//You cannot determain anything useful.
return;
}
var honestySocket = item.GetSocket<HonestyItemSocket>();
if (honestySocket != null)
{
if (honestySocket.HonestyOwner == null)
Server.Services.Virtues.HonestyVirtue.AssignOwner(honestySocket);
if (from.CheckTargetSkill(SkillName.Forensics, target, 41.0, 100.0))
{
string region = honestySocket.HonestyRegion == null ? "an unknown place" : honestySocket.HonestyRegion;
if (from.Skills.Forensics.Value >= 61.0)
{
from.SendLocalizedMessage(1151521, String.Format("{0}\t{1}", honestySocket.HonestyOwner.Name, region)); // This item belongs to ~1_val~ who lives in ~2_val~.
}
else
{
from.SendLocalizedMessage(1151522, region); // You find seeds from a familiar plant stuck to the item which suggests that this item is from ~1_val~.
}
}
}
}
}
}
}
}

129
Scripts/Skills/Hiding.cs Normal file
View File

@@ -0,0 +1,129 @@
using System;
using Server.Multis;
using Server.Network;
namespace Server.SkillHandlers
{
public class Hiding
{
private static bool m_CombatOverride;
public static bool CombatOverride
{
get
{
return m_CombatOverride;
}
set
{
m_CombatOverride = value;
}
}
public static void Initialize()
{
SkillInfo.Table[21].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile m)
{
if (m.Spell != null)
{
m.SendLocalizedMessage(501238); // You are busy doing something else and cannot hide.
return TimeSpan.FromSeconds(1.0);
}
if (Server.Engines.VvV.ManaSpike.UnderEffects(m))
{
return TimeSpan.FromSeconds(1.0);
}
if (Core.ML && m.Target != null)
{
Targeting.Target.Cancel(m);
}
double bonus = 0.0;
BaseHouse house = BaseHouse.FindHouseAt(m);
if (house != null && house.IsFriend(m))
{
bonus = 100.0;
}
else if (!Core.AOS)
{
if (house == null)
house = BaseHouse.FindHouseAt(new Point3D(m.X - 1, m.Y, 127), m.Map, 16);
if (house == null)
house = BaseHouse.FindHouseAt(new Point3D(m.X + 1, m.Y, 127), m.Map, 16);
if (house == null)
house = BaseHouse.FindHouseAt(new Point3D(m.X, m.Y - 1, 127), m.Map, 16);
if (house == null)
house = BaseHouse.FindHouseAt(new Point3D(m.X, m.Y + 1, 127), m.Map, 16);
if (house != null)
bonus = 50.0;
}
//int range = 18 - (int)(m.Skills[SkillName.Hiding].Value / 10);
int skill = Math.Min(100, (int)m.Skills[SkillName.Hiding].Value);
int range = Math.Min((int)((100 - skill) / 2) + 8, 18); //Cap of 18 not OSI-exact, intentional difference
bool badCombat = (!m_CombatOverride && m.Combatant is Mobile && m.InRange(m.Combatant.Location, range) && ((Mobile)m.Combatant).InLOS(m.Combatant));
bool ok = (!badCombat /*&& m.CheckSkill( SkillName.Hiding, 0.0 - bonus, 100.0 - bonus )*/);
if (ok)
{
if (!m_CombatOverride)
{
IPooledEnumerable eable = m.GetMobilesInRange(range);
foreach (Mobile check in eable)
{
if (check.InLOS(m) && check.Combatant == m)
{
badCombat = true;
ok = false;
break;
}
}
eable.Free();
}
ok = (!badCombat && m.CheckSkill(SkillName.Hiding, 0.0 - bonus, 100.0 - bonus));
}
if (badCombat)
{
m.RevealingAction();
m.LocalOverheadMessage(MessageType.Regular, 0x22, 501237); // You can't seem to hide right now.
return TimeSpan.Zero;
//return TimeSpan.FromSeconds(1.0);
}
else
{
if (ok)
{
m.Hidden = true;
m.Warmode = false;
Server.Spells.Sixth.InvisibilitySpell.RemoveTimer(m);
Server.Items.InvisibilityPotion.RemoveTimer(m);
m.LocalOverheadMessage(MessageType.Regular, 0x1F4, 501240); // You have hidden yourself well.
}
else
{
m.RevealingAction();
m.LocalOverheadMessage(MessageType.Regular, 0x22, 501241); // You can't seem to hide here.
}
return TimeSpan.FromSeconds(10.0);
}
}
}
}

171
Scripts/Skills/Inscribe.cs Normal file
View File

@@ -0,0 +1,171 @@
using System;
using System.Collections;
using Server.Items;
using Server.Targeting;
namespace Server.SkillHandlers
{
public class Inscribe
{
private static readonly Hashtable m_UseTable = new Hashtable();
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.Inscribe].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile m)
{
Target target = new InternalTargetSrc();
m.Target = target;
m.SendLocalizedMessage(1046295); // Target the book you wish to copy.
target.BeginTimeout(m, TimeSpan.FromMinutes(1.0));
return TimeSpan.FromSeconds(1.0);
}
public static Mobile GetUser(BaseBook book)
{
return (Mobile)m_UseTable[book];
}
public static bool IsEmpty(BaseBook book)
{
foreach (BookPageInfo page in book.Pages)
{
foreach (string line in page.Lines)
{
if (line.Trim().Length != 0)
return false;
}
}
return true;
}
public static void Copy(BaseBook bookSrc, BaseBook bookDst)
{
bookDst.Title = bookSrc.Title;
bookDst.Author = bookSrc.Author;
BookPageInfo[] pagesSrc = bookSrc.Pages;
BookPageInfo[] pagesDst = bookDst.Pages;
for (int i = 0; i < pagesSrc.Length && i < pagesDst.Length; i++)
{
BookPageInfo pageSrc = pagesSrc[i];
BookPageInfo pageDst = pagesDst[i];
int length = pageSrc.Lines.Length;
pageDst.Lines = new string[length];
for (int j = 0; j < length; j++)
pageDst.Lines[j] = pageSrc.Lines[j];
}
}
private static void SetUser(BaseBook book, Mobile mob)
{
m_UseTable[book] = mob;
}
private static void CancelUser(BaseBook book)
{
m_UseTable.Remove(book);
}
private class InternalTargetSrc : Target
{
public InternalTargetSrc()
: base(3, false, TargetFlags.None)
{
}
protected override void OnTarget(Mobile from, object targeted)
{
BaseBook book = targeted as BaseBook;
if (book != null)
{
if (Inscribe.IsEmpty(book))
from.SendLocalizedMessage(501611); // Can't copy an empty book.
else if (Inscribe.GetUser(book) != null)
from.SendLocalizedMessage(501621); // Someone else is inscribing that item.
else
{
Target target = new InternalTargetDst(book);
from.Target = target;
from.SendLocalizedMessage(501612); // Select a book to copy this to.
target.BeginTimeout(from, TimeSpan.FromMinutes(1.0));
Inscribe.SetUser(book, from);
}
}
else if (targeted is Server.Engines.Khaldun.MysteriousBook)
{
((Server.Engines.Khaldun.MysteriousBook)targeted).OnInscribeTarget(from);
}
else
{
from.SendLocalizedMessage(1046296); // That is not a book
}
}
protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
{
if (cancelType == TargetCancelType.Timeout)
from.SendLocalizedMessage(501619); // You have waited too long to make your inscribe selection, your inscription attempt has timed out.
}
}
private class InternalTargetDst : Target
{
private readonly BaseBook m_BookSrc;
public InternalTargetDst(BaseBook bookSrc)
: base(3, false, TargetFlags.None)
{
this.m_BookSrc = bookSrc;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (this.m_BookSrc.Deleted)
return;
BaseBook bookDst = targeted as BaseBook;
if (bookDst == null)
from.SendLocalizedMessage(1046296); // That is not a book
else if (Inscribe.IsEmpty(this.m_BookSrc))
from.SendLocalizedMessage(501611); // Can't copy an empty book.
else if (bookDst == this.m_BookSrc)
from.SendLocalizedMessage(501616); // Cannot copy a book onto itself.
else if (!bookDst.Writable)
from.SendLocalizedMessage(501614); // Cannot write into that book.
else if (Inscribe.GetUser(bookDst) != null)
from.SendLocalizedMessage(501621); // Someone else is inscribing that item.
else
{
if (from.CheckTargetSkill(SkillName.Inscribe, bookDst, 0, 50))
{
Inscribe.Copy(this.m_BookSrc, bookDst);
from.SendLocalizedMessage(501618); // You make a copy of the book.
from.PlaySound(0x249);
}
else
{
from.SendLocalizedMessage(501617); // You fail to make a copy of the book.
}
}
}
protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
{
if (cancelType == TargetCancelType.Timeout)
from.SendLocalizedMessage(501619); // You have waited too long to make your inscribe selection, your inscription attempt has timed out.
}
protected override void OnTargetFinish(Mobile from)
{
Inscribe.CancelUser(this.m_BookSrc);
}
}
}
}

View File

@@ -0,0 +1,195 @@
using System;
using Server.Mobiles;
using Server.Targeting;
using System.Collections.Generic;
using Server.Network;
using Server.SkillHandlers;
namespace Server.Items
{
public class ItemIdentification
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.ItemID].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile from)
{
from.SendLocalizedMessage(500343); // What do you wish to appraise and identify?
from.Target = new InternalTarget();
return TimeSpan.FromSeconds(1.0);
}
[PlayerVendorTarget]
private class InternalTarget : Target
{
public InternalTarget()
: base(8, false, TargetFlags.None)
{
this.AllowNonlocal = true;
}
protected override void OnTarget(Mobile from, object o)
{
Item item = o as Item;
Mobile m = o as Mobile;
if (item == null && m == null)
{
from.SendLocalizedMessage(500353); // You are not certain...
return;
}
if (!from.CheckTargetSkill(SkillName.ItemID, o, 0, 100))
{
from.PrivateOverheadMessage(MessageType.Emote, 0x3B2, 1041352, from.NetState); // You have no idea how much it might be worth.
return;
}
if (m != null)
{
from.PrivateOverheadMessage(MessageType.Emote, 0x3B2, 1041349, AffixType.Append, " " + m.Name, "", from.NetState); // It appears to be:
return;
}
if (item.Name != null)
{
from.PrivateOverheadMessage(MessageType.Emote, 0x3B2, false, item.Name, from.NetState);
item.PrivateOverheadMessage(MessageType.Label, 0x3B2, false, item.Name, from.NetState);
}
else
{
from.PrivateOverheadMessage(MessageType.Emote, 0x3B2, item.LabelNumber, from.NetState);
item.PrivateOverheadMessage(MessageType.Label, 0x3B2, item.LabelNumber, from.NetState);
}
if (Core.AOS)
{
if (item is Meteorite)
{
if (((Meteorite)item).Polished)
{
from.SendLocalizedMessage(1158697); // The brilliance of the meteorite shimmers in the light as you rotate it in your hands! Brightly hued veins of exotic minerals reflect against the polished surface. You think to yourself you have never seen anything so full of splendor!
}
else
{
from.SendLocalizedMessage(1158696); // The rock seems to be otherwordly. Judging by the pitting and charring, it appears to have crash landed here from the sky! The rock feels surprisingly dense given its size. Perhaps if you polished it with an oil cloth you may discover what is inside...
}
return;
}
from.PrivateOverheadMessage(MessageType.Emote, 0x3B2, 1041351, AffixType.Append, " " + GetPriceFor(item).ToString(), "", from.NetState); // You guess the value of that item at:
if (item is BaseWeapon || item is BaseArmor || item is BaseJewel || item is BaseHat)
{
if (Imbuing.TimesImbued(item) > 0)
{
from.PrivateOverheadMessage(MessageType.Emote, 0x3B2, 1111877, from.NetState); // You conclude that item cannot be magically unraveled. The magic in that item has been weakened due to either low durability or the imbuing process.
}
else
{
int weight = Imbuing.GetTotalWeight(item, -1, false, true);
string imbIngred = null;
double skill = from.Skills[SkillName.Imbuing].Base;
bool badSkill = false;
if (!Imbuing.CanUnravelItem(from, item, false))
{
weight = 0;
}
if (weight > 0 && weight <= 200)
{
imbIngred = "Magical Residue";
}
else if (weight > 200 && weight < 480)
{
imbIngred = "Enchanted Essence";
if (skill < 45.0)
badSkill = true;
}
else if (weight >= 480)
{
imbIngred = "Relic Fragment";
if (skill < 95.0)
badSkill = true;
}
if (imbIngred != null)
{
if (badSkill)
{
from.PrivateOverheadMessage(MessageType.Emote, 0x3B2, 1111875, from.NetState); // Your Imbuing skill is not high enough to identify the imbuing ingredient.
}
else
{
from.PrivateOverheadMessage(MessageType.Emote, 0x3B2, 1111874, imbIngred, from.NetState); //You conclude that item will magically unravel into: ~1_ingredient~
}
}
else // Cannot be Unravelled
{
from.PrivateOverheadMessage(MessageType.Emote, 0x3B2, 1111876, from.NetState); //You conclude that item cannot be magically unraveled. It appears to possess little to no magic.
}
}
}
else
{
from.LocalOverheadMessage(MessageType.Emote, 0x3B2, 1111878); //You conclude that item cannot be magically unraveled.
}
}
else if (o is Item)
{
if (from.CheckTargetSkill(SkillName.ItemID, o, 0, 100))
{
if (o is BaseWeapon)
((BaseWeapon)o).Identified = true;
else if (o is BaseArmor)
((BaseArmor)o).Identified = true;
if (!Core.AOS)
((Item)o).OnSingleClick(from);
}
else
{
from.SendLocalizedMessage(500353); // You are not certain...
}
}
else if (o is Mobile)
{
((Mobile)o).OnSingleClick(from);
}
else
{
from.SendLocalizedMessage(500353); // You are not certain...
}
Server.Engines.XmlSpawner2.XmlAttach.RevealAttachments(from, o);
}
public static int GetPriceFor(Item item)
{
Type type = item.GetType();
if (GenericBuyInfo.BuyPrices.ContainsKey(type))
{
return GenericBuyInfo.BuyPrices[item.GetType()] * item.Amount;
}
if (TypeCostCache == null)
TypeCostCache = new Dictionary<Type, int>();
if (!TypeCostCache.ContainsKey(type))
TypeCostCache[type] = Utility.RandomMinMax(2, 7);
return TypeCostCache[type];
}
public static Dictionary<Type, int> TypeCostCache { get; set; }
}
}
}

View File

@@ -0,0 +1,106 @@
using System;
using Server.Items;
namespace Server.SkillHandlers
{
class Meditation
{
public static void Initialize()
{
SkillInfo.Table[46].Callback = new SkillUseCallback(OnUse);
}
public static bool CheckOkayHolding(Item item)
{
if (item == null)
return true;
if (item is Spellbook || item is Runebook)
return true;
if (Core.AOS && item is BaseWeapon && ((BaseWeapon)item).Attributes.SpellChanneling != 0)
return true;
if (Core.AOS && item is BaseArmor && ((BaseArmor)item).Attributes.SpellChanneling != 0)
return true;
return false;
}
public static TimeSpan OnUse(Mobile m)
{
m.RevealingAction();
if (m.Target != null)
{
m.SendLocalizedMessage(501845); // You are busy doing something else and cannot focus.
return TimeSpan.FromSeconds(5.0);
}
else if (!Core.AOS && m.Hits < (m.HitsMax / 10)) // Less than 10% health
{
m.SendLocalizedMessage(501849); // The mind is strong but the body is weak.
return TimeSpan.FromSeconds(5.0);
}
else if (m.Mana >= m.ManaMax)
{
m.SendLocalizedMessage(501846); // You are at peace.
return TimeSpan.FromSeconds(Core.AOS ? 10.0 : 5.0);
}
else if (Core.AOS && Server.Misc.RegenRates.GetArmorOffset(m) > 0)
{
m.SendLocalizedMessage(500135); // Regenative forces cannot penetrate your armor!
return TimeSpan.FromSeconds(10.0);
}
else
{
Item oneHanded = m.FindItemOnLayer(Layer.OneHanded);
Item twoHanded = m.FindItemOnLayer(Layer.TwoHanded);
if (Core.AOS && m.Player)
{
if (!CheckOkayHolding(oneHanded))
m.AddToBackpack(oneHanded);
if (!CheckOkayHolding(twoHanded))
m.AddToBackpack(twoHanded);
}
else if (!CheckOkayHolding(oneHanded) || !CheckOkayHolding(twoHanded))
{
m.SendLocalizedMessage(502626); // Your hands must be free to cast spells or meditate.
return TimeSpan.FromSeconds(2.5);
}
double skillVal = m.Skills[SkillName.Meditation].Value;
double chance = (50.0 + ((skillVal - (m.ManaMax - m.Mana)) * 2)) / 100;
// must bypass normal checks so passive skill checks aren't triggered
CrystalBallOfKnowledge.TellSkillDifficultyActive(m, SkillName.Meditation, chance);
if (chance > Utility.RandomDouble())
{
m.CheckSkill(SkillName.Meditation, 0.0, 100.0);
m.SendLocalizedMessage(501851); // You enter a meditative trance.
m.Meditating = true;
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.ActiveMeditation, 1075657));
if (m.Player || m.Body.IsHuman)
m.PlaySound(0xF9);
m.ResetStatTimers();
}
else
{
m.SendLocalizedMessage(501850); // You cannot focus your concentration.
}
return TimeSpan.FromSeconds(10.0);
}
}
}
}

View File

@@ -0,0 +1,252 @@
#region References
using System;
using Server.Engines.XmlSpawner2;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
using Server.Engines.Quests;
#endregion
namespace Server.SkillHandlers
{
public class Peacemaking
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.Peacemaking].Callback = OnUse;
}
public static TimeSpan OnUse(Mobile m)
{
m.RevealingAction();
BaseInstrument.PickInstrument(m, OnPickedInstrument);
return TimeSpan.FromSeconds(1.0); // Cannot use another skill for 1 second
}
public static void OnPickedInstrument(Mobile from, BaseInstrument instrument)
{
from.RevealingAction();
from.SendLocalizedMessage(1049525); // Whom do you wish to calm?
from.Target = new InternalTarget(from, instrument);
from.NextSkillTime = Core.TickCount + 21600000;
}
public static bool UnderEffects(Mobile m)
{
return m is BaseCreature && ((BaseCreature)m).BardPacified;
}
public class InternalTarget : Target
{
private readonly BaseInstrument m_Instrument;
private bool m_SetSkillTime = true;
public InternalTarget(Mobile from, BaseInstrument instrument)
: base(BaseInstrument.GetBardRange(from, SkillName.Peacemaking), false, TargetFlags.None)
{
m_Instrument = instrument;
}
protected override void OnTargetFinish(Mobile from)
{
if (m_SetSkillTime)
{
from.NextSkillTime = Core.TickCount;
}
}
protected override void OnTarget(Mobile from, object targeted)
{
from.RevealingAction();
if (!(targeted is Mobile))
{
from.SendLocalizedMessage(1049528); // You cannot calm that!
}
else if (!m_Instrument.IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(1062488); // The instrument you are trying to play is no longer in your backpack!
}
else
{
m_SetSkillTime = false;
int masteryBonus = 0;
if (from is PlayerMobile)
masteryBonus = Spells.SkillMasteries.BardSpell.GetMasteryBonus((PlayerMobile)from, SkillName.Peacemaking);
if (targeted == from)
{
// Standard mode : reset combatants for everyone in the area
if (from.Player && !BaseInstrument.CheckMusicianship(from))
{
from.SendLocalizedMessage(500612); // You play poorly, and there is no effect.
m_Instrument.PlayInstrumentBadly(from);
m_Instrument.ConsumeUse(from);
from.NextSkillTime = Core.TickCount + (10000 - ((masteryBonus / 5) * 1000));
}
else if (!from.CheckSkill(SkillName.Peacemaking, 0.0, 120.0))
{
from.SendLocalizedMessage(500613); // You attempt to calm everyone, but fail.
m_Instrument.PlayInstrumentBadly(from);
m_Instrument.ConsumeUse(from);
from.NextSkillTime = Core.TickCount + (10000 - ((masteryBonus / 5) * 1000));
}
else
{
from.NextSkillTime = Core.TickCount + 5000;
m_Instrument.PlayInstrumentWell(from);
m_Instrument.ConsumeUse(from);
Map map = from.Map;
if (map != null)
{
int range = BaseInstrument.GetBardRange(from, SkillName.Peacemaking);
bool calmed = false;
IPooledEnumerable eable = from.GetMobilesInRange(range);
foreach (Mobile m in eable)
{
if ((m is BaseCreature && ((BaseCreature)m).Uncalmable) ||
(m is BaseCreature && ((BaseCreature)m).AreaPeaceImmune) || m == from || !from.CanBeHarmful(m, false))
{
continue;
}
calmed = true;
m.SendLocalizedMessage(500616); // You hear lovely music, and forget to continue battling!
m.Combatant = null;
m.Warmode = false;
if (m is BaseCreature && !((BaseCreature)m).BardPacified)
{
((BaseCreature)m).Pacify(from, DateTime.UtcNow + TimeSpan.FromSeconds(1.0));
}
}
eable.Free();
if (!calmed)
{
from.SendLocalizedMessage(1049648); // You play hypnotic music, but there is nothing in range for you to calm.
}
else
{
from.SendLocalizedMessage(500615); // You play your hypnotic music, stopping the battle.
}
}
}
}
else
{
// Target mode : pacify a single target for a longer duration
Mobile targ = (Mobile)targeted;
if (!from.CanBeHarmful(targ, false))
{
from.SendLocalizedMessage(1049528);
m_SetSkillTime = true;
}
else if (targ is BaseCreature && ((BaseCreature)targ).Uncalmable)
{
from.SendLocalizedMessage(1049526); // You have no chance of calming that creature.
m_SetSkillTime = true;
}
else if (targ is BaseCreature && ((BaseCreature)targ).BardPacified)
{
from.SendLocalizedMessage(1049527); // That creature is already being calmed.
m_SetSkillTime = true;
}
else if (from.Player && !BaseInstrument.CheckMusicianship(from))
{
from.SendLocalizedMessage(500612); // You play poorly, and there is no effect.
from.NextSkillTime = Core.TickCount + 5000;
m_Instrument.PlayInstrumentBadly(from);
m_Instrument.ConsumeUse(from);
}
else
{
double diff = m_Instrument.GetDifficultyFor(targ) - 10.0;
double music = from.Skills[SkillName.Musicianship].Value;
if (music > 100.0)
{
diff -= (music - 100.0) * 0.5;
}
if (masteryBonus > 0)
diff -= (diff * ((double)masteryBonus / 100));
if (!from.CheckTargetSkill(SkillName.Peacemaking, targ, diff - 25.0, diff + 25.0))
{
from.SendLocalizedMessage(1049531); // You attempt to calm your target, but fail.
m_Instrument.PlayInstrumentBadly(from);
m_Instrument.ConsumeUse(from);
from.NextSkillTime = Core.TickCount + (10000 - ((masteryBonus / 5) * 1000));
}
else
{
m_Instrument.PlayInstrumentWell(from);
m_Instrument.ConsumeUse(from);
from.NextSkillTime = Core.TickCount + (5000 - ((masteryBonus / 5) * 1000));
if (targ is BaseCreature)
{
BaseCreature bc = (BaseCreature)targ;
from.SendLocalizedMessage(1049532); // You play hypnotic music, calming your target.
targ.Combatant = null;
targ.Warmode = false;
double seconds = 100 - (diff / 1.5);
if (seconds > 120)
{
seconds = 120;
}
else if (seconds < 10)
{
seconds = 10;
}
bc.Pacify(from, DateTime.UtcNow + TimeSpan.FromSeconds(seconds));
#region Bard Mastery Quest
if (from is PlayerMobile)
{
BaseQuest quest = QuestHelper.GetQuest((PlayerMobile)from, typeof(TheBeaconOfHarmonyQuest));
if (quest != null)
{
foreach (BaseObjective objective in quest.Objectives)
objective.Update(bc);
}
}
#endregion
}
else
{
from.SendLocalizedMessage(1049532); // You play hypnotic music, calming your target.
targ.SendLocalizedMessage(500616); // You hear lovely music, and forget to continue battling!
targ.Combatant = null;
targ.Warmode = false;
}
}
}
}
}
}
}
}
}

172
Scripts/Skills/Poisoning.cs Normal file
View File

@@ -0,0 +1,172 @@
using System;
using Server.Items;
using Server.Targeting;
namespace Server.SkillHandlers
{
public class Poisoning
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.Poisoning].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile m)
{
m.Target = new InternalTargetPoison();
m.SendLocalizedMessage(502137); // Select the poison you wish to use
return TimeSpan.FromSeconds(10.0); // 10 second delay before beign able to re-use a skill
}
private class InternalTargetPoison : Target
{
public InternalTargetPoison()
: base(2, false, TargetFlags.None)
{
}
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is BasePoisonPotion)
{
from.SendLocalizedMessage(502142); // To what do you wish to apply the poison?
from.Target = new InternalTarget((BasePoisonPotion)targeted);
}
else // Not a Poison Potion
{
from.SendLocalizedMessage(502139); // That is not a poison potion.
}
}
private class InternalTarget : Target
{
private readonly BasePoisonPotion m_Potion;
public InternalTarget(BasePoisonPotion potion)
: base(2, false, TargetFlags.None)
{
m_Potion = potion;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (m_Potion.Deleted)
return;
bool startTimer = false;
if (targeted is Food || targeted is FukiyaDarts || targeted is Shuriken)
{
startTimer = true;
}
else if (targeted is BaseWeapon)
{
BaseWeapon weapon = (BaseWeapon)targeted;
if (Core.AOS)
{
startTimer = (weapon.PrimaryAbility == WeaponAbility.InfectiousStrike || weapon.SecondaryAbility == WeaponAbility.InfectiousStrike);
}
else if (weapon.Layer == Layer.OneHanded)
{
// Only Bladed or Piercing weapon can be poisoned
startTimer = (weapon.Type == WeaponType.Slashing || weapon.Type == WeaponType.Piercing);
}
}
if (startTimer)
{
new InternalTimer(from, (Item)targeted, m_Potion).Start();
from.PlaySound(0x4F);
m_Potion.Consume();
from.AddToBackpack(new Bottle());
}
else // Target can't be poisoned
{
if (Core.AOS)
from.SendLocalizedMessage(1060204); // You cannot poison that! You can only poison infectious weapons, food or drink.
else
from.SendLocalizedMessage(502145); // You cannot poison that! You can only poison bladed or piercing weapons, food or drink.
}
}
private class InternalTimer : Timer
{
private readonly Mobile m_From;
private readonly Item m_Target;
private readonly Poison m_Poison;
private readonly double m_MinSkill;
private readonly double m_MaxSkill;
public InternalTimer(Mobile from, Item target, BasePoisonPotion potion)
: base(TimeSpan.FromSeconds(2.0))
{
m_From = from;
m_Target = target;
m_Poison = potion.Poison;
m_MinSkill = potion.MinPoisoningSkill;
m_MaxSkill = potion.MaxPoisoningSkill;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
if (m_From.CheckTargetSkill(SkillName.Poisoning, m_Target, m_MinSkill, m_MaxSkill))
{
if (m_Target is Food)
{
((Food)m_Target).Poison = m_Poison;
}
else if (m_Target is BaseWeapon)
{
((BaseWeapon)m_Target).Poison = m_Poison;
((BaseWeapon)m_Target).PoisonCharges = 18 - (m_Poison.RealLevel * 2);
}
else if (m_Target is FukiyaDarts)
{
((FukiyaDarts)m_Target).Poison = m_Poison;
((FukiyaDarts)m_Target).PoisonCharges = Math.Min(18 - (m_Poison.RealLevel * 2), ((FukiyaDarts)m_Target).UsesRemaining);
}
else if (m_Target is Shuriken)
{
((Shuriken)m_Target).Poison = m_Poison;
((Shuriken)m_Target).PoisonCharges = Math.Min(18 - (m_Poison.RealLevel * 2), ((Shuriken)m_Target).UsesRemaining);
}
m_From.SendLocalizedMessage(1010517); // You apply the poison
Misc.Titles.AwardKarma(m_From, -20, true);
}
else // Failed
{
// 5% of chance of getting poisoned if failed
if (m_From.Skills[SkillName.Poisoning].Base < 80.0 && Utility.Random(20) == 0)
{
m_From.SendLocalizedMessage(502148); // You make a grave mistake while applying the poison.
m_From.ApplyPoison(m_From, m_Poison);
}
else
{
if (m_Target is BaseWeapon)
{
BaseWeapon weapon = (BaseWeapon)m_Target;
if (weapon.Type == WeaponType.Slashing)
m_From.SendLocalizedMessage(1010516); // You fail to apply a sufficient dose of poison on the blade
else
m_From.SendLocalizedMessage(1010518); // You fail to apply a sufficient dose of poison
}
else
{
m_From.SendLocalizedMessage(1010518); // You fail to apply a sufficient dose of poison
}
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,220 @@
#region References
using System;
using Server.Engines.XmlSpawner2;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
using Server.Engines.Quests;
#endregion
namespace Server.SkillHandlers
{
public class Provocation
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.Provocation].Callback = OnUse;
}
public static TimeSpan OnUse(Mobile m)
{
m.RevealingAction();
BaseInstrument.PickInstrument(m, OnPickedInstrument);
return TimeSpan.FromSeconds(1.0); // Cannot use another skill for 1 second
}
public static void OnPickedInstrument(Mobile from, BaseInstrument instrument)
{
from.RevealingAction();
from.SendLocalizedMessage(501587); // Whom do you wish to incite?
from.Target = new InternalFirstTarget(from, instrument);
}
public class InternalFirstTarget : Target
{
private readonly BaseInstrument m_Instrument;
public InternalFirstTarget(Mobile from, BaseInstrument instrument)
: base(BaseInstrument.GetBardRange(from, SkillName.Provocation), false, TargetFlags.None)
{
m_Instrument = instrument;
}
protected override void OnTarget(Mobile from, object targeted)
{
from.RevealingAction();
if (targeted is BaseCreature && from.CanBeHarmful((Mobile)targeted, true))
{
BaseCreature creature = (BaseCreature)targeted;
if (!m_Instrument.IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(1062488); // The instrument you are trying to play is no longer in your backpack!
}
else if (from is PlayerMobile && creature.Controlled)
{
from.SendLocalizedMessage(501590); // They are too loyal to their master to be provoked.
}
else if (creature.IsParagon && BaseInstrument.GetBaseDifficulty(creature) >= 160.0)
{
from.SendLocalizedMessage(1049446); // You have no chance of provoking those creatures.
}
else
{
from.RevealingAction();
m_Instrument.PlayInstrumentWell(from);
from.SendLocalizedMessage(1008085);
// You play your music and your target becomes angered. Whom do you wish them to attack?
from.Target = new InternalSecondTarget(from, m_Instrument, creature);
}
}
else
{
from.SendLocalizedMessage(501589); // You can't incite that!
}
}
}
public class InternalSecondTarget : Target
{
private readonly BaseCreature m_Creature;
private readonly BaseInstrument m_Instrument;
public InternalSecondTarget(Mobile from, BaseInstrument instrument, BaseCreature creature)
: base(BaseInstrument.GetBardRange(from, SkillName.Provocation), false, TargetFlags.None)
{
m_Instrument = instrument;
m_Creature = creature;
}
protected override void OnTarget(Mobile from, object targeted)
{
from.RevealingAction();
if (targeted is BaseCreature || (from is BaseCreature && ((BaseCreature)from).CanProvoke))
{
BaseCreature creature = targeted as BaseCreature;
Mobile target = targeted as Mobile;
bool questTargets = QuestTargets(creature, from);
if (!m_Instrument.IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(1062488); // The instrument you are trying to play is no longer in your backpack!
}
else if (m_Creature.Unprovokable)
{
from.SendLocalizedMessage(1049446); // You have no chance of provoking those creatures.
}
else if (creature != null && creature.Unprovokable && !(creature is DemonKnight) && !questTargets)
{
from.SendLocalizedMessage(1049446); // You have no chance of provoking those creatures.
}
else if (m_Creature.Map != target.Map ||
!m_Creature.InRange(target, BaseInstrument.GetBardRange(from, SkillName.Provocation)))
{
from.SendLocalizedMessage(1049450);
// The creatures you are trying to provoke are too far away from each other for your music to have an effect.
}
else if (m_Creature != target)
{
from.NextSkillTime = Core.TickCount + 10000;
double diff = ((m_Instrument.GetDifficultyFor(m_Creature) + m_Instrument.GetDifficultyFor(target)) * 0.5) - 5.0;
double music = from.Skills[SkillName.Musicianship].Value;
int masteryBonus = 0;
if (from is PlayerMobile)
masteryBonus = Spells.SkillMasteries.BardSpell.GetMasteryBonus((PlayerMobile)from, SkillName.Provocation);
if (masteryBonus > 0)
diff -= (diff * ((double)masteryBonus / 100));
if (music > 100.0)
{
diff -= (music - 100.0) * 0.5;
}
if (questTargets || (from.CanBeHarmful(m_Creature, true) && from.CanBeHarmful(target, true)))
{
if (from.Player && !BaseInstrument.CheckMusicianship(from))
{
from.NextSkillTime = Core.TickCount + (10000 - ((masteryBonus / 5) * 1000));
from.SendLocalizedMessage(500612); // You play poorly, and there is no effect.
m_Instrument.PlayInstrumentBadly(from);
m_Instrument.ConsumeUse(from);
}
else
{
//from.DoHarmful( m_Creature );
//from.DoHarmful( creature );
if (!from.CheckTargetSkill(SkillName.Provocation, target, diff - 25.0, diff + 25.0))
{
from.NextSkillTime = Core.TickCount + (10000 - ((masteryBonus / 5) * 1000));
from.SendLocalizedMessage(501599); // Your music fails to incite enough anger.
m_Instrument.PlayInstrumentBadly(from);
m_Instrument.ConsumeUse(from);
}
else
{
from.SendLocalizedMessage(501602); // Your music succeeds, as you start a fight.
m_Instrument.PlayInstrumentWell(from);
m_Instrument.ConsumeUse(from);
m_Creature.Provoke(from, target, true);
#region Bard Mastery Quest
if (questTargets)
{
BaseQuest quest = QuestHelper.GetQuest((PlayerMobile)from, typeof(IndoctrinationOfABattleRouserQuest));
if (quest != null)
{
foreach (BaseObjective objective in quest.Objectives)
objective.Update(creature);
}
}
#endregion
}
}
}
}
else
{
from.SendLocalizedMessage(501593); // You can't tell someone to attack themselves!
}
}
else
{
from.SendLocalizedMessage(501589); // You can't incite that!
}
}
public bool QuestTargets(BaseCreature creature, Mobile from)
{
if (creature != null)
{
Mobile getmaster = creature.GetMaster();
if (getmaster != null)
{
if (getmaster is PlayerMobile)
return false;
}
if (from is PlayerMobile && (m_Creature.GetType() == typeof(Rabbit) || m_Creature.GetType() == typeof(JackRabbit)) && ((creature is WanderingHealer) || (creature is EvilWanderingHealer)))
return true;
return false;
}
else
{
return false;
}
}
}
}
}

View File

@@ -0,0 +1,411 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Factions;
using Server.Items;
using Server.Network;
using Server.Targeting;
using Server.Engines.VvV;
using Server.Guilds;
using Server.Mobiles;
namespace Server.SkillHandlers
{
public interface IRemoveTrapTrainingKit
{
void OnRemoveTrap(Mobile m);
}
public class RemoveTrap
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.RemoveTrap].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile m)
{
if (!Core.EJ && m.Skills[SkillName.Lockpicking].Value < 50)
{
m.SendLocalizedMessage(502366); // You do not know enough about locks. Become better at picking locks.
}
else if (!Core.EJ && m.Skills[SkillName.DetectHidden].Value < 50)
{
m.SendLocalizedMessage(502367); // You are not perceptive enough. Become better at detect hidden.
}
else
{
m.Target = new InternalTarget();
m.SendLocalizedMessage(502368); // Wich trap will you attempt to disarm?
}
return TimeSpan.FromSeconds(10.0); // 10 second delay before beign able to re-use a skill
}
private class InternalTarget : Target
{
public InternalTarget()
: base(2, false, TargetFlags.None)
{
}
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is Mobile)
{
from.SendLocalizedMessage(502816); // You feel that such an action would be inappropriate
}
else if (targeted is IRemoveTrapTrainingKit)
{
((IRemoveTrapTrainingKit)targeted).OnRemoveTrap(from);
}
else if (targeted is LockableContainer && ((LockableContainer)targeted).Locked)
{
from.SendLocalizedMessage(501283); // That is locked.
}
else if (targeted is TrapableContainer)
{
TrapableContainer targ = (TrapableContainer)targeted;
from.Direction = from.GetDirectionTo(targ);
if (targ.TrapType == Server.Items.TrapType.None)
{
from.SendLocalizedMessage(502373); // That doesn't appear to be trapped
}
else if (targ is TreasureMapChest && TreasureMapInfo.NewSystem)
{
var tChest = (TreasureMapChest)targ;
if (tChest.Owner != from)
{
from.SendLocalizedMessage(1159010); // That is not your chest!
}
else if (IsDisarming(from, tChest))
{
from.SendLocalizedMessage(1159059); // You are already manipulating the trigger mechanism...
}
else if (IsBeingDisarmed(tChest))
{
from.SendLocalizedMessage(1159063); // That trap is already being disarmed.
}
else if (tChest.AncientGuardians.Any(g => !g.Deleted))
{
from.PrivateOverheadMessage(MessageType.Regular, 1150, 1159060, from.NetState); // *Your attempt fails as the the mechanism jams and you are attacked by an Ancient Chest Guardian!*
}
else
{
from.PlaySound(0x241);
from.PrivateOverheadMessage(MessageType.Regular, 1150, 1159057, from.NetState); // *You delicately manipulate the trigger mechanism...*
StartChestDisarmTimer(from, tChest);
}
}
else
{
from.PlaySound(0x241);
if (from.CheckTargetSkill(SkillName.RemoveTrap, targ, targ.TrapPower, targ.TrapPower + 10))
{
targ.TrapPower = 0;
targ.TrapLevel = 0;
targ.TrapType = TrapType.None;
targ.InvalidateProperties();
from.SendLocalizedMessage(502377); // You successfully render the trap harmless
}
else
{
from.SendLocalizedMessage(502372); // You fail to disarm the trap... but you don't set it off
}
}
}
else if (targeted is BaseFactionTrap)
{
BaseFactionTrap trap = (BaseFactionTrap)targeted;
Faction faction = Faction.Find(from);
FactionTrapRemovalKit kit = (from.Backpack == null ? null : from.Backpack.FindItemByType(typeof(FactionTrapRemovalKit)) as FactionTrapRemovalKit);
bool isOwner = (trap.Placer == from || (trap.Faction != null && trap.Faction.IsCommander(from)));
if (faction == null)
{
from.SendLocalizedMessage(1010538); // You may not disarm faction traps unless you are in an opposing faction
}
else if (faction == trap.Faction && trap.Faction != null && !isOwner)
{
from.SendLocalizedMessage(1010537); // You may not disarm traps set by your own faction!
}
else if (!isOwner && kit == null)
{
from.SendLocalizedMessage(1042530); // You must have a trap removal kit at the base level of your pack to disarm a faction trap.
}
else
{
if ((Core.ML && isOwner) || (from.CheckTargetSkill(SkillName.RemoveTrap, trap, 80.0, 100.0) && from.CheckTargetSkill(SkillName.Tinkering, trap, 80.0, 100.0)))
{
from.PrivateOverheadMessage(MessageType.Regular, trap.MessageHue, trap.DisarmMessage, from.NetState);
if (!isOwner)
{
int silver = faction.AwardSilver(from, trap.SilverFromDisarm);
if (silver > 0)
from.SendLocalizedMessage(1008113, true, silver.ToString("N0")); // You have been granted faction silver for removing the enemy trap :
}
trap.Delete();
}
else
{
from.SendLocalizedMessage(502372); // You fail to disarm the trap... but you don't set it off
}
if (!isOwner && kit != null)
kit.ConsumeCharge(from);
}
}
else if (targeted is VvVTrap)
{
VvVTrap trap = targeted as VvVTrap;
if (!ViceVsVirtueSystem.IsVvV(from))
{
from.SendLocalizedMessage(1155496); // This item can only be used by VvV participants!
}
else
{
if (from == trap.Owner || ((from.Skills[SkillName.RemoveTrap].Value - 80.0) / 20.0) > Utility.RandomDouble())
{
VvVTrapKit kit = new VvVTrapKit(trap.TrapType);
trap.Delete();
if (!from.AddToBackpack(kit))
kit.MoveToWorld(from.Location, from.Map);
if (trap.Owner != null && from != trap.Owner)
{
Guild fromG = from.Guild as Guild;
Guild ownerG = trap.Owner.Guild as Guild;
if (fromG != null && fromG != ownerG && !fromG.IsAlly(ownerG) && ViceVsVirtueSystem.Instance != null
&& ViceVsVirtueSystem.Instance.Battle != null && ViceVsVirtueSystem.Instance.Battle.OnGoing)
{
ViceVsVirtueSystem.Instance.Battle.Update(from, UpdateType.Disarm);
}
}
from.PrivateOverheadMessage(Server.Network.MessageType.Regular, 1154, 1155413, from.NetState);
}
else if (.1 > Utility.RandomDouble())
{
trap.Detonate(from);
}
}
}
else if (targeted is GoblinFloorTrap)
{
GoblinFloorTrap targ = (GoblinFloorTrap)targeted;
if (from.InRange(targ.Location, 3))
{
from.Direction = from.GetDirectionTo(targ);
if (targ.Owner == null)
{
Item item = new FloorTrapComponent();
if (from.Backpack == null || !from.Backpack.TryDropItem(from, item, false))
item.MoveToWorld(from.Location, from.Map);
}
targ.Delete();
from.SendLocalizedMessage(502377); // You successfully render the trap harmless
}
}
else
{
from.SendLocalizedMessage(502373); // That does'nt appear to be trapped
}
}
protected override void OnTargetOutOfRange(Mobile from, object targeted)
{
if (targeted is TreasureMapChest && TreasureMapInfo.NewSystem)
{
// put here to prevent abuse
if (from.NextSkillTime > Core.TickCount)
{
from.NextSkillTime = Core.TickCount;
}
from.SendLocalizedMessage(1159058); // You are too far away from the chest to manipulate the trigger mechanism.
}
else
{
base.OnTargetOutOfRange(from, targeted);
}
}
}
public static Dictionary<Mobile, RemoveTrapTimer> _Table;
public static void StartChestDisarmTimer(Mobile from, TreasureMapChest chest)
{
if (_Table == null)
{
_Table = new Dictionary<Mobile, RemoveTrapTimer>();
}
_Table[from] = new RemoveTrapTimer(from, chest, from.Skills[SkillName.RemoveTrap].Value >= 100);
}
public static void EndChestDisarmTimer(Mobile from)
{
if (_Table != null && _Table.ContainsKey(from))
{
var timer = _Table[from];
if (timer != null)
{
timer.Stop();
}
_Table.Remove(from);
if (_Table.Count == 0)
{
_Table = null;
}
}
}
public static bool IsDisarming(Mobile from, TreasureMapChest chest)
{
if (_Table == null)
return false;
return _Table.ContainsKey(from);
}
public static bool IsBeingDisarmed(TreasureMapChest chest)
{
if (_Table == null)
return false;
return _Table.Values.Any(timer => timer.Chest == chest);
}
}
public class RemoveTrapTimer : Timer
{
public Mobile From { get; set; }
public TreasureMapChest Chest { get; set; }
public DateTime SafetyEndTime { get; set; } // Used for 100 Remove Trap
public int Stage { get; set; } // Used for 99.9- Remove Trap
public bool GMRemover { get; set; }
public RemoveTrapTimer(Mobile from, TreasureMapChest chest, bool gmRemover)
: base(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10))
{
From = from;
Chest = chest;
GMRemover = gmRemover;
if (gmRemover)
{
TimeSpan duration;
switch ((TreasureLevel)chest.Level)
{
default:
case TreasureLevel.Stash: duration = TimeSpan.FromSeconds(20); break;
case TreasureLevel.Supply: duration = TimeSpan.FromSeconds(60); break;
case TreasureLevel.Cache: duration = TimeSpan.FromSeconds(180); break;
case TreasureLevel.Hoard: duration = TimeSpan.FromSeconds(420); break;
case TreasureLevel.Trove: duration = TimeSpan.FromSeconds(540); break;
}
SafetyEndTime = Chest.DigTime + duration;
}
Start();
}
protected override void OnTick()
{
if (Chest.Deleted)
{
RemoveTrap.EndChestDisarmTimer(From);
}
if (!From.Alive)
{
From.SendLocalizedMessage(1159061); // Your ghostly fingers cannot manipulate the mechanism...
RemoveTrap.EndChestDisarmTimer(From);
}
else if (!From.InRange(Chest.GetWorldLocation(), 16) || Chest.Deleted)
{
From.SendLocalizedMessage(1159058); // You are too far away from the chest to manipulate the trigger mechanism.
RemoveTrap.EndChestDisarmTimer(From);
}
else if (GMRemover)
{
From.RevealingAction();
if (SafetyEndTime < DateTime.UtcNow)
{
DisarmTrap();
}
else
{
if (From.CheckTargetSkill(SkillName.RemoveTrap, Chest, 80, 120 + (Chest.Level * 10)))
{
DisarmTrap();
}
else
{
Chest.SpawnAncientGuardian(From);
}
}
RemoveTrap.EndChestDisarmTimer(From);
}
else
{
From.RevealingAction();
var min = (double)Math.Ceiling(From.Skills[SkillName.RemoveTrap].Value * .75);
if (From.CheckTargetSkill(SkillName.RemoveTrap, Chest, min, min > 50 ? min + 50 : 100))
{
DisarmTrap();
RemoveTrap.EndChestDisarmTimer(From);
}
else
{
Chest.SpawnAncientGuardian(From);
if (From.Alive)
{
From.PrivateOverheadMessage(MessageType.Regular, 1150, 1159057, From.NetState); // *You delicately manipulate the trigger mechanism...*
}
}
}
}
private void DisarmTrap()
{
Chest.TrapPower = 0;
Chest.TrapLevel = 0;
Chest.TrapType = TrapType.None;
Chest.InvalidateProperties();
From.PrivateOverheadMessage(MessageType.Regular, 1150, 1159009, From.NetState); // You successfully disarm the trap!
}
}
}

View File

@@ -0,0 +1,16 @@
using System;
namespace Server
{
public enum SkillCat
{
None,
Miscellaneous,
Combat,
TradeSkills,
Magic,
Wilderness,
Thievery,
Bard
}
}

100
Scripts/Skills/Snooping.cs Normal file
View File

@@ -0,0 +1,100 @@
using System;
using Server.Items;
using Server.Misc;
using Server.Mobiles;
using Server.Network;
using Server.Regions;
namespace Server.SkillHandlers
{
public class Snooping
{
public static void Configure()
{
Container.SnoopHandler = new ContainerSnoopHandler(Container_Snoop);
}
public static bool CheckSnoopAllowed(Mobile from, Mobile to)
{
Map map = from.Map;
if (to.Player)
return from.CanBeHarmful(to, false, true); // normal restrictions
if (map != null && (map.Rules & MapRules.HarmfulRestrictions) == 0)
return true; // felucca you can snoop anybody
GuardedRegion reg = (GuardedRegion)to.Region.GetRegion(typeof(GuardedRegion));
if (reg == null || reg.IsDisabled())
return true; // not in town? we can snoop any npc
BaseCreature cret = to as BaseCreature;
if (to.Body.IsHuman && (cret == null || (!cret.AlwaysAttackable && !cret.AlwaysMurderer)))
return false; // in town we cannot snoop blue human npcs
return true;
}
public static void Container_Snoop(Container cont, Mobile from)
{
if (from.IsStaff() || from.InRange(cont.GetWorldLocation(), 1))
{
Mobile root = cont.RootParent as Mobile;
if (root != null && !root.Alive)
return;
if (from.IsPlayer() && root is BaseCreature && !(cont is StrongBackpack))
return;
if (root != null && root.IsStaff() && from.IsPlayer())
{
from.SendLocalizedMessage(500209); // You can not peek into the container.
return;
}
if (root != null && from.IsPlayer() && !CheckSnoopAllowed(from, root))
{
from.SendLocalizedMessage(1001018); // You cannot perform negative acts on your target.
return;
}
if (root != null && from.IsPlayer() && from.Skills[SkillName.Snooping].Value < Utility.Random(100))
{
Map map = from.Map;
if (map != null)
{
string message = String.Format("You notice {0} peeking into your belongings!", from.Name);
root.Send(new AsciiMessage(-1, -1, MessageType.Label, 946, 3, "", message));
}
}
if (from.IsPlayer())
Titles.AwardKarma(from, -4, true);
if (from.IsStaff() || from.CheckTargetSkill(SkillName.Snooping, cont, 0.0, 100.0))
{
if (cont is TrapableContainer && ((TrapableContainer)cont).ExecuteTrap(from))
return;
cont.DisplayTo(from);
}
else
{
from.SendLocalizedMessage(500210); // You failed to peek into the container.
if (from.Skills[SkillName.Hiding].Value / 2 < Utility.Random(100))
from.RevealingAction();
}
}
else
{
from.SendLocalizedMessage(500446); // That is too far away.
}
}
}
}

View File

@@ -0,0 +1,242 @@
#region References
using System;
using System.Collections.Generic;
using Server.Items;
using Server.Network;
using Server.Spells;
using Server.Mobiles;
#endregion
namespace Server.SkillHandlers
{
internal class SpiritSpeak
{
public static void Initialize()
{
SkillInfo.Table[32].Callback = OnUse;
}
public static Dictionary<Mobile, Timer> _Table;
public static TimeSpan OnUse(Mobile m)
{
if (Core.AOS)
{
if (m.Spell != null && m.Spell.IsCasting)
{
m.SendLocalizedMessage(502642); // You are already casting a spell.
}
else if (BeginSpiritSpeak(m))
{
return TimeSpan.FromSeconds(5.0);
}
return TimeSpan.Zero;
}
m.RevealingAction();
if (m.CheckSkill(SkillName.SpiritSpeak, 0, 100))
{
if (!m.CanHearGhosts)
{
Timer t = new SpiritSpeakTimer(m);
double secs = m.Skills[SkillName.SpiritSpeak].Base / 50;
secs *= 90;
if (secs < 15)
{
secs = 15;
}
t.Delay = TimeSpan.FromSeconds(secs); //15seconds to 3 minutes
t.Start();
m.CanHearGhosts = true;
}
m.PlaySound(0x24A);
m.SendLocalizedMessage(502444); //You contact the neitherworld.
}
else
{
m.SendLocalizedMessage(502443); //You fail to contact the neitherworld.
m.CanHearGhosts = false;
}
return TimeSpan.FromSeconds(1.0);
}
private class SpiritSpeakTimer : Timer
{
private readonly Mobile m_Owner;
public SpiritSpeakTimer(Mobile m)
: base(TimeSpan.FromMinutes(2.0))
{
m_Owner = m;
Priority = TimerPriority.FiveSeconds;
}
protected override void OnTick()
{
m_Owner.CanHearGhosts = false;
m_Owner.SendLocalizedMessage(502445); //You feel your contact with the neitherworld fading.
}
}
public static bool BeginSpiritSpeak(Mobile m)
{
if (_Table == null || !_Table.ContainsKey(m))
{
m.Freeze(TimeSpan.FromSeconds(1));
m.Animate(AnimationType.Spell, 1);
m.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1062074, "", false); // Anh Mi Sah Ko
m.PlaySound(0x24A);
if (_Table == null)
_Table = new Dictionary<Mobile, Timer>();
_Table[m] = new SpiritSpeakTimerNew(m);
return true;
}
return false;
}
public static bool IsInSpiritSpeak(Mobile m)
{
return _Table != null && _Table.ContainsKey(m);
}
public static void Remove(Mobile m)
{
if (_Table != null && _Table.ContainsKey(m))
{
if(_Table[m] != null)
_Table[m].Stop();
m.SendSpeedControl(SpeedControlType.Disable);
_Table.Remove(m);
if (_Table.Count == 0)
_Table = null;
}
}
public static void CheckDisrupt(Mobile m)
{
if (!Core.AOS)
return;
if (_Table != null && _Table.ContainsKey(m))
{
if (m is PlayerMobile)
{
m.SendLocalizedMessage(500641); // Your concentration is disturbed, thus ruining thy spell.
}
m.FixedEffect(0x3735, 6, 30);
m.PlaySound(0x5C);
m.NextSkillTime = Core.TickCount;
Remove(m);
}
}
private class SpiritSpeakTimerNew : Timer
{
public Mobile Caster { get; set; }
public SpiritSpeakTimerNew(Mobile m)
: base(TimeSpan.FromSeconds(1))
{
Start();
Caster = m;
}
protected override void OnTick()
{
Corpse toChannel = null;
IPooledEnumerable eable = Caster.GetObjectsInRange(3);
foreach (object objs in eable)
{
if (objs is Corpse && !((Corpse)objs).Channeled && !((Corpse)objs).Animated)
{
toChannel = (Corpse)objs;
break;
}
else if (objs is Server.Engines.Khaldun.SageHumbolt)
{
if (((Server.Engines.Khaldun.SageHumbolt)objs).OnSpiritSpeak(Caster))
{
eable.Free();
SpiritSpeak.Remove(Caster);
Stop();
return;
}
}
}
eable.Free();
int max, min, mana, number;
if (toChannel != null)
{
min = 1 + (int)(Caster.Skills[SkillName.SpiritSpeak].Value * 0.25);
max = min + 4;
mana = 0;
number = 1061287; // You channel energy from a nearby corpse to heal your wounds.
}
else
{
min = 1 + (int)(Caster.Skills[SkillName.SpiritSpeak].Value * 0.25);
max = min + 4;
mana = 10;
number = 1061286; // You channel your own spiritual energy to heal your wounds.
}
if (Caster.Mana < mana)
{
Caster.SendLocalizedMessage(1061285); // You lack the mana required to use this skill.
}
else
{
Caster.CheckSkill(SkillName.SpiritSpeak, 0.0, 120.0);
if (Utility.RandomDouble() > (Caster.Skills[SkillName.SpiritSpeak].Value / 100.0))
{
Caster.SendLocalizedMessage(502443); // You fail your attempt at contacting the netherworld.
}
else
{
if (toChannel != null)
{
toChannel.Channeled = true;
toChannel.Hue = 0x835;
}
Caster.Mana -= mana;
Caster.SendLocalizedMessage(number);
if (min > max)
{
min = max;
}
Caster.Hits += Utility.RandomMinMax(min, max);
Caster.FixedParticles(0x375A, 1, 15, 9501, 2100, 4, EffectLayer.Waist);
}
}
SpiritSpeak.Remove(Caster);
Stop();
}
}
}
}

646
Scripts/Skills/Stealing.cs Normal file
View File

@@ -0,0 +1,646 @@
#region References
using System;
using System.Collections;
using Server.Factions;
using Server.Items;
using Server.Mobiles;
using Server.Network;
using Server.Spells;
using Server.Spells.Fifth;
using Server.Spells.Ninjitsu;
using Server.Spells.Seventh;
using Server.Targeting;
using Server.Engines.VvV;
#endregion
namespace Server.SkillHandlers
{
public delegate void ItemStolenEventHandler(ItemStolenEventArgs e);
public class Stealing
{
public static void Initialize()
{
SkillInfo.Table[33].Callback = OnUse;
}
public static event ItemStolenEventHandler ItemStolen;
public static readonly bool ClassicMode = false;
public static readonly bool SuspendOnMurder = false;
public static bool IsInGuild(Mobile m)
{
return (m is PlayerMobile && ((PlayerMobile)m).NpcGuild == NpcGuild.ThievesGuild);
}
public static bool IsInnocentTo(Mobile from, Mobile to)
{
return (Notoriety.Compute(from, to) == Notoriety.Innocent);
}
private class StealingTarget : Target
{
private readonly Mobile m_Thief;
public StealingTarget(Mobile thief)
: base(1, false, TargetFlags.None)
{
m_Thief = thief;
AllowNonlocal = true;
}
private Item TryStealItem(Item toSteal, ref bool caught)
{
Item stolen = null;
object root = toSteal.RootParent;
StealableArtifactsSpawner.StealableInstance si = null;
if (toSteal.Parent == null || !toSteal.Movable)
{
si = toSteal is AddonComponent ? StealableArtifactsSpawner.GetStealableInstance(((AddonComponent)toSteal).Addon) : StealableArtifactsSpawner.GetStealableInstance(toSteal);
}
if (!IsEmptyHanded(m_Thief))
{
m_Thief.SendLocalizedMessage(1005584); // Both hands must be free to steal.
}
else if (root is Mobile && ((Mobile)root).Player && !IsInGuild(m_Thief))
{
m_Thief.SendLocalizedMessage(1005596); // You must be in the thieves guild to steal from other players.
}
else if (SuspendOnMurder && root is Mobile && ((Mobile)root).Player && IsInGuild(m_Thief) && m_Thief.Kills > 0)
{
m_Thief.SendLocalizedMessage(502706); // You are currently suspended from the thieves guild.
}
else if (root is BaseVendor && ((BaseVendor)root).IsInvulnerable)
{
m_Thief.SendLocalizedMessage(1005598); // You can't steal from shopkeepers.
}
else if (root is PlayerVendor)
{
m_Thief.SendLocalizedMessage(502709); // You can't steal from vendors.
}
else if (!m_Thief.CanSee(toSteal))
{
m_Thief.SendLocalizedMessage(500237); // Target can not be seen.
}
else if (m_Thief.Backpack == null || !m_Thief.Backpack.CheckHold(m_Thief, toSteal, false, true))
{
m_Thief.SendLocalizedMessage(1048147); // Your backpack can't hold anything else.
}
#region Sigils
else if (toSteal is Sigil)
{
PlayerState pl = PlayerState.Find(m_Thief);
Faction faction = (pl == null ? null : pl.Faction);
Sigil sig = (Sigil)toSteal;
if (!m_Thief.InRange(toSteal.GetWorldLocation(), 1))
{
m_Thief.SendLocalizedMessage(502703); // You must be standing next to an item to steal it.
}
else if (root != null) // not on the ground
{
m_Thief.SendLocalizedMessage(502710); // You can't steal that!
}
else if (faction != null)
{
if (!m_Thief.CanBeginAction(typeof(IncognitoSpell)))
{
m_Thief.SendLocalizedMessage(1010581); // You cannot steal the sigil when you are incognito
}
else if (DisguiseTimers.IsDisguised(m_Thief))
{
m_Thief.SendLocalizedMessage(1010583); // You cannot steal the sigil while disguised
}
else if (!m_Thief.CanBeginAction(typeof(PolymorphSpell)))
{
m_Thief.SendLocalizedMessage(1010582); // You cannot steal the sigil while polymorphed
}
else if (TransformationSpellHelper.UnderTransformation(m_Thief))
{
m_Thief.SendLocalizedMessage(1061622); // You cannot steal the sigil while in that form.
}
else if (AnimalForm.UnderTransformation(m_Thief))
{
m_Thief.SendLocalizedMessage(1063222); // You cannot steal the sigil while mimicking an animal.
}
else if (pl.IsLeaving)
{
m_Thief.SendLocalizedMessage(1005589); // You are currently quitting a faction and cannot steal the town sigil
}
else if (sig.IsBeingCorrupted && sig.LastMonolith.Faction == faction)
{
m_Thief.SendLocalizedMessage(1005590); // You cannot steal your own sigil
}
else if (sig.IsPurifying)
{
m_Thief.SendLocalizedMessage(1005592); // You cannot steal this sigil until it has been purified
}
else if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, 80.0, 80.0))
{
if (Sigil.ExistsOn(m_Thief))
{
m_Thief.SendLocalizedMessage(1010258);
// The sigil has gone back to its home location because you already have a sigil.
}
else if (m_Thief.Backpack == null || !m_Thief.Backpack.CheckHold(m_Thief, sig, false, true))
{
m_Thief.SendLocalizedMessage(1010259); // The sigil has gone home because your backpack is full
}
else
{
if (sig.IsBeingCorrupted)
{
sig.GraceStart = DateTime.UtcNow; // begin grace period
}
m_Thief.SendLocalizedMessage(1010586); // YOU STOLE THE SIGIL!!! (woah, calm down now)
if (sig.LastMonolith != null && sig.LastMonolith.Sigil != null)
{
sig.LastMonolith.Sigil = null;
sig.LastStolen = DateTime.UtcNow;
}
return sig;
}
}
else
{
m_Thief.SendLocalizedMessage(1005594); // You do not have enough skill to steal the sigil
}
}
else
{
m_Thief.SendLocalizedMessage(1005588); // You must join a faction to do that
}
}
#endregion
#region VvV Sigils
else if (toSteal is VvVSigil && ViceVsVirtueSystem.Instance != null)
{
VvVPlayerEntry entry = ViceVsVirtueSystem.Instance.GetPlayerEntry<VvVPlayerEntry>(m_Thief);
VvVSigil sig = (VvVSigil)toSteal;
if (!m_Thief.InRange(toSteal.GetWorldLocation(), 1))
{
m_Thief.SendLocalizedMessage(502703); // You must be standing next to an item to steal it.
}
else if (root != null) // not on the ground
{
m_Thief.SendLocalizedMessage(502710); // You can't steal that!
}
else if (entry != null)
{
if (!m_Thief.CanBeginAction(typeof(IncognitoSpell)))
{
m_Thief.SendLocalizedMessage(1010581); // You cannot steal the sigil when you are incognito
}
else if (DisguiseTimers.IsDisguised(m_Thief))
{
m_Thief.SendLocalizedMessage(1010583); // You cannot steal the sigil while disguised
}
else if (!m_Thief.CanBeginAction(typeof(PolymorphSpell)))
{
m_Thief.SendLocalizedMessage(1010582); // You cannot steal the sigil while polymorphed
}
else if (TransformationSpellHelper.UnderTransformation(m_Thief))
{
m_Thief.SendLocalizedMessage(1061622); // You cannot steal the sigil while in that form.
}
else if (AnimalForm.UnderTransformation(m_Thief))
{
m_Thief.SendLocalizedMessage(1063222); // You cannot steal the sigil while mimicking an animal.
}
else if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, 100.0, 120.0))
{
if (m_Thief.Backpack == null || !m_Thief.Backpack.CheckHold(m_Thief, sig, false, true))
{
m_Thief.SendLocalizedMessage(1010259); // The sigil has gone home because your backpack is full
}
else
{
m_Thief.SendLocalizedMessage(1010586); // YOU STOLE THE SIGIL!!! (woah, calm down now)
sig.OnStolen(entry);
return sig;
}
}
else
{
m_Thief.SendLocalizedMessage(1005594); // You do not have enough skill to steal the sigil
}
}
else
{
m_Thief.SendLocalizedMessage(1155415); // Only participants in Vice vs Virtue may use this item.
}
}
#endregion
else if (si == null && (toSteal.Parent == null || !toSteal.Movable) && !ItemFlags.GetStealable(toSteal))
{
m_Thief.SendLocalizedMessage(502710); // You can't steal that!
}
else if ((toSteal.LootType == LootType.Newbied || toSteal.CheckBlessed(root)) && !ItemFlags.GetStealable(toSteal))
{
m_Thief.SendLocalizedMessage(502710); // You can't steal that!
}
else if (Core.AOS && si == null && toSteal is Container && !ItemFlags.GetStealable(toSteal))
{
m_Thief.SendLocalizedMessage(502710); // You can't steal that!
}
else if (!m_Thief.InRange(toSteal.GetWorldLocation(), 1))
{
m_Thief.SendLocalizedMessage(502703); // You must be standing next to an item to steal it.
}
else if (si != null && m_Thief.Skills[SkillName.Stealing].Value < 100.0)
{
m_Thief.SendLocalizedMessage(1060025, "", 0x66D); // You're not skilled enough to attempt the theft of this item.
}
else if (toSteal.Parent is Mobile)
{
m_Thief.SendLocalizedMessage(1005585); // You cannot steal items which are equiped.
}
else if (root == m_Thief)
{
m_Thief.SendLocalizedMessage(502704); // You catch yourself red-handed.
}
else if (root is Mobile && ((Mobile)root).IsStaff())
{
m_Thief.SendLocalizedMessage(502710); // You can't steal that!
}
else if (root is Mobile && !m_Thief.CanBeHarmful((Mobile)root))
{ }
else if (root is Corpse)
{
m_Thief.SendLocalizedMessage(502710); // You can't steal that!
}
else
{
double w = toSteal.Weight + toSteal.TotalWeight;
if (w > 10)
{
m_Thief.SendMessage("That is too heavy to steal.");
}
else
{
if (toSteal.Stackable && toSteal.Amount > 1)
{
int maxAmount = (int)((m_Thief.Skills[SkillName.Stealing].Value / 10.0) / toSteal.Weight);
if (maxAmount < 1)
{
maxAmount = 1;
}
else if (maxAmount > toSteal.Amount)
{
maxAmount = toSteal.Amount;
}
int amount = Utility.RandomMinMax(1, maxAmount);
if (amount >= toSteal.Amount)
{
int pileWeight = (int)Math.Ceiling(toSteal.Weight * toSteal.Amount);
pileWeight *= 10;
if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, pileWeight - 22.5, pileWeight + 27.5))
{
stolen = toSteal;
}
}
else
{
int pileWeight = (int)Math.Ceiling(toSteal.Weight * amount);
pileWeight *= 10;
if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, pileWeight - 22.5, pileWeight + 27.5))
{
stolen = Mobile.LiftItemDupe(toSteal, toSteal.Amount - amount);
if (stolen == null)
{
stolen = toSteal;
}
}
}
}
else
{
int iw = (int)Math.Ceiling(w);
iw *= 10;
if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, iw - 22.5, iw + 27.5))
{
stolen = toSteal;
}
}
// Non-movable stealable (not in fillable container) items cannot result in the stealer getting caught
if (stolen != null && (root is FillableContainer || stolen.Movable))
{
double skillValue = m_Thief.Skills[SkillName.Stealing].Value;
if (root is FillableContainer)
{
caught = (Utility.Random((int)(skillValue / 2.5)) == 0); // 1 of 48 chance at 120
}
else
{
caught = (skillValue < Utility.Random(150));
}
}
else
{
caught = false;
}
if (stolen != null)
{
m_Thief.SendLocalizedMessage(502724); // You succesfully steal the item.
ItemFlags.SetTaken(stolen, true);
ItemFlags.SetStealable(stolen, false);
stolen.Movable = true;
InvokeItemStoken(new ItemStolenEventArgs(stolen, m_Thief));
if (si != null)
{
toSteal.Movable = true;
si.Item = null;
}
}
else
{
m_Thief.SendLocalizedMessage(502723); // You fail to steal the item.
}
}
}
return stolen;
}
protected override void OnTarget(Mobile from, object target)
{
from.RevealingAction();
Item stolen = null;
object root = null;
bool caught = false;
if (target is Item)
{
root = ((Item)target).RootParent;
stolen = TryStealItem((Item)target, ref caught);
}
else if (target is Mobile)
{
Container pack = ((Mobile)target).Backpack;
if (pack != null && pack.Items.Count > 0)
{
int randomIndex = Utility.Random(pack.Items.Count);
root = target;
stolen = TryStealItem(pack.Items[randomIndex], ref caught);
}
#region Monster Stealables
if (target is BaseCreature && from is PlayerMobile)
{
Server.Engines.CreatureStealing.StealingHandler.HandleSteal(target as BaseCreature, from as PlayerMobile);
}
#endregion
}
else
{
m_Thief.SendLocalizedMessage(502710); // You can't steal that!
}
if (stolen != null)
{
if (stolen is AddonComponent)
{
BaseAddon addon = ((AddonComponent)stolen).Addon as BaseAddon;
from.AddToBackpack(addon.Deed);
addon.Delete();
}
else
{
from.AddToBackpack(stolen);
}
if (!(stolen is Container || stolen.Stackable))
{
// do not return stolen containers or stackable items
StolenItem.Add(stolen, m_Thief, root as Mobile);
}
}
if (caught)
{
if (root == null)
{
m_Thief.CriminalAction(false);
}
else if (root is Corpse && ((Corpse)root).IsCriminalAction(m_Thief))
{
m_Thief.CriminalAction(false);
}
else if (root is Mobile)
{
Mobile mobRoot = (Mobile)root;
if (!IsInGuild(mobRoot) && IsInnocentTo(m_Thief, mobRoot))
{
m_Thief.CriminalAction(false);
}
string message = String.Format("You notice {0} trying to steal from {1}.", m_Thief.Name, mobRoot.Name);
foreach (NetState ns in m_Thief.GetClientsInRange(8))
{
if (ns.Mobile != m_Thief)
{
ns.Mobile.SendMessage(message);
}
}
}
}
else if (root is Corpse && ((Corpse)root).IsCriminalAction(m_Thief))
{
m_Thief.CriminalAction(false);
}
if (root is Mobile && ((Mobile)root).Player && m_Thief is PlayerMobile && IsInnocentTo(m_Thief, (Mobile)root) &&
!IsInGuild((Mobile)root))
{
PlayerMobile pm = (PlayerMobile)m_Thief;
pm.PermaFlags.Add((Mobile)root);
pm.Delta(MobileDelta.Noto);
}
}
}
public static bool IsEmptyHanded(Mobile from)
{
if (from.FindItemOnLayer(Layer.OneHanded) != null)
{
return false;
}
if (from.FindItemOnLayer(Layer.TwoHanded) != null)
{
return false;
}
return true;
}
public static TimeSpan OnUse(Mobile m)
{
if (!IsEmptyHanded(m))
{
m.SendLocalizedMessage(1005584); // Both hands must be free to steal.
}
else
{
m.Target = new StealingTarget(m);
m.RevealingAction();
m.SendLocalizedMessage(502698); // Which item do you want to steal?
}
return TimeSpan.FromSeconds(10.0);
}
public static void InvokeItemStoken(ItemStolenEventArgs e)
{
if (ItemStolen != null)
{
ItemStolen(e);
}
}
}
public class StolenItem
{
public static readonly TimeSpan StealTime = TimeSpan.FromMinutes(2.0);
private readonly Item m_Stolen;
private readonly Mobile m_Thief;
private readonly Mobile m_Victim;
private DateTime m_Expires;
public Item Stolen { get { return m_Stolen; } }
public Mobile Thief { get { return m_Thief; } }
public Mobile Victim { get { return m_Victim; } }
public DateTime Expires { get { return m_Expires; } }
public bool IsExpired { get { return (DateTime.UtcNow >= m_Expires); } }
public StolenItem(Item stolen, Mobile thief, Mobile victim)
{
m_Stolen = stolen;
m_Thief = thief;
m_Victim = victim;
m_Expires = DateTime.UtcNow + StealTime;
}
private static readonly Queue m_Queue = new Queue();
public static void Add(Item item, Mobile thief, Mobile victim)
{
Clean();
m_Queue.Enqueue(new StolenItem(item, thief, victim));
}
public static bool IsStolen(Item item)
{
Mobile victim = null;
return IsStolen(item, ref victim);
}
public static bool IsStolen(Item item, ref Mobile victim)
{
Clean();
foreach (StolenItem si in m_Queue)
{
if (si.m_Stolen == item && !si.IsExpired)
{
victim = si.m_Victim;
return true;
}
}
return false;
}
public static void ReturnOnDeath(Mobile killed, Container corpse)
{
Clean();
foreach (StolenItem si in m_Queue)
{
if (si.m_Stolen.RootParent == corpse && si.m_Victim != null && !si.IsExpired)
{
if (si.m_Victim.AddToBackpack(si.m_Stolen))
{
si.m_Victim.SendLocalizedMessage(1010464); // the item that was stolen is returned to you.
}
else
{
si.m_Victim.SendLocalizedMessage(1010463); // the item that was stolen from you falls to the ground.
}
si.m_Expires = DateTime.UtcNow; // such a hack
}
}
}
public static void Clean()
{
while (m_Queue.Count > 0)
{
StolenItem si = (StolenItem)m_Queue.Peek();
if (si.IsExpired)
{
m_Queue.Dequeue();
}
else
{
break;
}
}
}
}
public class ItemStolenEventArgs : EventArgs
{
public Item Item { get; set; }
public Mobile Mobile { get; set; }
public ItemStolenEventArgs(Item item, Mobile thief)
{
Mobile = thief;
Item = item;
}
}
}

131
Scripts/Skills/Stealth.cs Normal file
View File

@@ -0,0 +1,131 @@
using System;
using Server.Items;
using Server.Mobiles;
namespace Server.SkillHandlers
{
public class Stealth
{
private static readonly int[,] m_ArmorTable = new int[,]
{
// Gorget Gloves Helmet Arms Legs Chest Shield
/* Cloth */ { 0, 0, 0, 0, 0, 0, 0 },
/* Leather */ { 0, 0, 0, 0, 0, 0, 0 },
/* Studded */ { 2, 2, 0, 4, 6, 10, 0 },
/* Bone */ { 0, 5, 10, 10, 15, 25, 0 },
/* Spined */ { 0, 0, 0, 0, 0, 0, 0 },
/* Horned */ { 0, 0, 0, 0, 0, 0, 0 },
/* Barbed */ { 0, 0, 0, 0, 0, 0, 0 },
/* Ring */ { 0, 5, 0, 10, 15, 25, 0 },
/* Chain */ { 0, 0, 10, 0, 15, 25, 0 },
/* Plate */ { 5, 5, 10, 10, 15, 25, 0 },
/* Dragon */ { 0, 5, 10, 10, 15, 25, 0 }
};
public static double HidingRequirement
{
get
{
return (Core.ML ? 30.0 : (Core.SE ? 50.0 : 80.0));
}
}
public static int[,] ArmorTable
{
get
{
return m_ArmorTable;
}
}
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.Stealth].Callback = new SkillUseCallback(OnUse);
}
public static int GetArmorRating(Mobile m)
{
if (!Core.AOS)
return (int)m.ArmorRating;
int ar = 0;
for (int i = 0; i < m.Items.Count; i++)
{
BaseArmor armor = m.Items[i] as BaseArmor;
if (armor == null)
continue;
int materialType = (int)armor.MaterialType;
int bodyPosition = (int)armor.BodyPosition;
if (materialType >= m_ArmorTable.GetLength(0) || bodyPosition >= m_ArmorTable.GetLength(1))
continue;
if (armor.ArmorAttributes.MageArmor == 0)
ar += m_ArmorTable[materialType, bodyPosition];
}
return ar;
}
public static TimeSpan OnUse(Mobile m)
{
if (!m.Hidden)
{
m.SendLocalizedMessage(502725); // You must hide first
}
else if (m.Flying)
{
m.SendLocalizedMessage(1113415); // You cannot use this ability while flying.
m.RevealingAction();
BuffInfo.RemoveBuff(m, BuffIcon.HidingAndOrStealth);
}
else if (m.Skills[SkillName.Hiding].Base < HidingRequirement)
{
m.SendLocalizedMessage(502726); // You are not hidden well enough. Become better at hiding.
m.RevealingAction();
BuffInfo.RemoveBuff(m, BuffIcon.HidingAndOrStealth);
}
else if (!m.CanBeginAction(typeof(Stealth)))
{
m.SendLocalizedMessage(1063086); // You cannot use this skill right now.
m.RevealingAction();
BuffInfo.RemoveBuff(m, BuffIcon.HidingAndOrStealth);
}
else
{
int armorRating = GetArmorRating(m);
if (armorRating >= (Core.AOS ? 42 : 26)) //I have a hunch '42' was chosen cause someone's a fan of DNA
{
m.SendLocalizedMessage(502727); // You could not hope to move quietly wearing this much armor.
m.RevealingAction();
BuffInfo.RemoveBuff(m, BuffIcon.HidingAndOrStealth);
}
else if (m.CheckSkill(SkillName.Stealth, -20.0 + (armorRating * 2), (Core.AOS ? 60.0 : 80.0) + (armorRating * 2)))
{
int steps = (int)(m.Skills[SkillName.Stealth].Value / (Core.AOS ? 5.0 : 10.0));
if (steps < 1)
steps = 1;
m.AllowedStealthSteps = steps;
m.IsStealthing = true;
m.SendLocalizedMessage(502730); // You begin to move quietly.
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.HidingAndOrStealth, 1044107, 1075655));
return TimeSpan.FromSeconds(10.0);
}
else
{
m.SendLocalizedMessage(502731); // You fail in your attempt to move unnoticed.
m.RevealingAction();
BuffInfo.RemoveBuff(m, BuffIcon.HidingAndOrStealth);
}
}
return TimeSpan.FromSeconds(10.0);
}
}
}

95
Scripts/Skills/TasteID.cs Normal file
View File

@@ -0,0 +1,95 @@
using System;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.SkillHandlers
{
public class TasteID
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.TasteID].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile m)
{
m.Target = new InternalTarget();
m.SendLocalizedMessage(502807); // What would you like to taste?
return TimeSpan.FromSeconds(1.0);
}
[PlayerVendorTarget]
private class InternalTarget : Target
{
public InternalTarget()
: base(2, false, TargetFlags.None)
{
this.AllowNonlocal = true;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is Mobile)
{
from.SendLocalizedMessage(502816); // You feel that such an action would be inappropriate.
}
else if (targeted is Food)
{
Food food = (Food)targeted;
if (from.CheckTargetSkill(SkillName.TasteID, food, 0, 100))
{
if (food.Poison != null)
{
food.SendLocalizedMessageTo(from, 1038284); // It appears to have poison smeared on it.
}
else
{
// No poison on the food
food.SendLocalizedMessageTo(from, 1010600); // You detect nothing unusual about this substance.
}
}
else
{
// Skill check failed
food.SendLocalizedMessageTo(from, 502823); // You cannot discern anything about this substance.
}
}
else if (targeted is BasePotion)
{
BasePotion potion = (BasePotion)targeted;
potion.SendLocalizedMessageTo(from, 502813); // You already know what kind of potion that is.
potion.SendLocalizedMessageTo(from, potion.LabelNumber);
}
else if (targeted is PotionKeg)
{
PotionKeg keg = (PotionKeg)targeted;
if (keg.Held <= 0)
{
keg.SendLocalizedMessageTo(from, 502228); // There is nothing in the keg to taste!
}
else
{
keg.SendLocalizedMessageTo(from, 502229); // You are already familiar with this keg's contents.
keg.SendLocalizedMessageTo(from, keg.LabelNumber);
}
}
else
{
// The target is not food or potion or potion keg.
from.SendLocalizedMessage(502820); // That's not something you can taste.
}
}
protected override void OnTargetOutOfRange(Mobile from, object targeted)
{
from.SendLocalizedMessage(502815); // You are too far away to taste that.
}
}
}
}

394
Scripts/Skills/Tracking.cs Normal file
View File

@@ -0,0 +1,394 @@
using System;
using System.Collections.Generic;
using Server.Gumps;
using Server.Network;
using Server.Spells;
using Server.Spells.Necromancy;
namespace Server.SkillHandlers
{
public delegate bool TrackTypeDelegate(Mobile m);
public class Tracking
{
private static readonly Dictionary<Mobile, TrackingInfo> m_Table = new Dictionary<Mobile, TrackingInfo>();
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.Tracking].Callback = new SkillUseCallback(OnUse);
}
public static TimeSpan OnUse(Mobile m)
{
m.SendLocalizedMessage(1011350); // What do you wish to track?
m.CloseGump(typeof(TrackWhatGump));
m.CloseGump(typeof(TrackWhoGump));
m.SendGump(new TrackWhatGump(m));
return TimeSpan.FromSeconds(10.0); // 10 second delay before beign able to re-use a skill
}
public static void AddInfo(Mobile tracker, Mobile target)
{
TrackingInfo info = new TrackingInfo(tracker, target);
m_Table[tracker] = info;
}
public static double GetStalkingBonus(Mobile tracker, Mobile target)
{
TrackingInfo info = null;
m_Table.TryGetValue(tracker, out info);
if (info == null || info.m_Target != target || info.m_Map != target.Map)
return 0.0;
int xDelta = info.m_Location.X - target.X;
int yDelta = info.m_Location.Y - target.Y;
double bonus = Math.Sqrt((xDelta * xDelta) + (yDelta * yDelta));
m_Table.Remove(tracker); //Reset as of Pub 40, counting it as bug for Core.SE.
if (Core.ML)
return Math.Min(bonus, 10 + tracker.Skills.Tracking.Value / 10);
return bonus;
}
public static void ClearTrackingInfo(Mobile tracker)
{
m_Table.Remove(tracker);
}
public class TrackingInfo
{
public Mobile m_Tracker;
public Mobile m_Target;
public Point2D m_Location;
public Map m_Map;
public TrackingInfo(Mobile tracker, Mobile target)
{
this.m_Tracker = tracker;
this.m_Target = target;
this.m_Location = new Point2D(target.X, target.Y);
this.m_Map = target.Map;
}
}
}
public class TrackWhatGump : Gump
{
private readonly Mobile m_From;
private readonly bool m_Success;
public TrackWhatGump(Mobile from)
: base(20, 30)
{
this.m_From = from;
this.m_Success = from.CheckSkill(SkillName.Tracking, 0.0, 21.1);
this.AddPage(0);
this.AddBackground(0, 0, 440, 135, 5054);
this.AddBackground(10, 10, 420, 75, 2620);
this.AddBackground(10, 85, 420, 25, 3000);
this.AddItem(20, 20, 9682);
this.AddButton(20, 110, 4005, 4007, 1, GumpButtonType.Reply, 0);
this.AddHtmlLocalized(20, 90, 100, 20, 1018087, false, false); // Animals
this.AddItem(120, 20, 9607);
this.AddButton(120, 110, 4005, 4007, 2, GumpButtonType.Reply, 0);
this.AddHtmlLocalized(120, 90, 100, 20, 1018088, false, false); // Monsters
this.AddItem(220, 20, 8454);
this.AddButton(220, 110, 4005, 4007, 3, GumpButtonType.Reply, 0);
this.AddHtmlLocalized(220, 90, 100, 20, 1018089, false, false); // Human NPCs
this.AddItem(320, 20, 8455);
this.AddButton(320, 110, 4005, 4007, 4, GumpButtonType.Reply, 0);
this.AddHtmlLocalized(320, 90, 100, 20, 1018090, false, false); // Players
}
public override void OnResponse(NetState state, RelayInfo info)
{
if (info.ButtonID >= 1 && info.ButtonID <= 4)
TrackWhoGump.DisplayTo(this.m_Success, this.m_From, info.ButtonID - 1);
}
}
public class TrackWhoGump : Gump
{
private static readonly TrackTypeDelegate[] m_Delegates = new TrackTypeDelegate[]
{
new TrackTypeDelegate(IsAnimal),
new TrackTypeDelegate(IsMonster),
new TrackTypeDelegate(IsHumanNPC),
new TrackTypeDelegate(IsPlayer)
};
private readonly Mobile m_From;
private readonly int m_Range;
private readonly List<Mobile> m_List;
private TrackWhoGump(Mobile from, List<Mobile> list, int range)
: base(20, 30)
{
this.m_From = from;
this.m_List = list;
this.m_Range = range;
this.AddPage(0);
this.AddBackground(0, 0, 440, 155, 5054);
this.AddBackground(10, 10, 420, 75, 2620);
this.AddBackground(10, 85, 420, 45, 3000);
if (list.Count > 4)
{
this.AddBackground(0, 155, 440, 155, 5054);
this.AddBackground(10, 165, 420, 75, 2620);
this.AddBackground(10, 240, 420, 45, 3000);
if (list.Count > 8)
{
this.AddBackground(0, 310, 440, 155, 5054);
this.AddBackground(10, 320, 420, 75, 2620);
this.AddBackground(10, 395, 420, 45, 3000);
}
}
for (int i = 0; i < list.Count && i < 12; ++i)
{
Mobile m = list[i];
this.AddItem(20 + ((i % 4) * 100), 20 + ((i / 4) * 155), ShrinkTable.Lookup(m));
this.AddButton(20 + ((i % 4) * 100), 130 + ((i / 4) * 155), 4005, 4007, i + 1, GumpButtonType.Reply, 0);
if (m.Name != null)
this.AddHtml(20 + ((i % 4) * 100), 90 + ((i / 4) * 155), 90, 40, m.Name, false, false);
}
}
public static void DisplayTo(bool success, Mobile from, int type)
{
if (!success)
{
from.SendLocalizedMessage(1018092); // You see no evidence of those in the area.
return;
}
Map map = from.Map;
if (map == null)
return;
TrackTypeDelegate check = m_Delegates[type];
from.CheckSkill(SkillName.Tracking, 21.1, 100.0); // Passive gain
int range = 10 + (int)(from.Skills[SkillName.Tracking].Value / 10);
List<Mobile> list = new List<Mobile>();
IPooledEnumerable eable = from.GetMobilesInRange(range);
foreach (Mobile m in eable)
{
// Ghosts can no longer be tracked
if (m != from && (!Core.AOS || m.Alive) && (!m.Hidden || m.IsPlayer() || from.AccessLevel > m.AccessLevel) && check(m) && CheckDifficulty(from, m))
list.Add(m);
}
eable.Free();
if (list.Count > 0)
{
list.Sort(new InternalSorter(from));
from.SendGump(new TrackWhoGump(from, list, range));
from.SendLocalizedMessage(1018093); // Select the one you would like to track.
}
else
{
if (type == 0)
from.SendLocalizedMessage(502991); // You see no evidence of animals in the area.
else if (type == 1)
from.SendLocalizedMessage(502993); // You see no evidence of creatures in the area.
else
from.SendLocalizedMessage(502995); // You see no evidence of people in the area.
}
}
public override void OnResponse(NetState state, RelayInfo info)
{
int index = info.ButtonID - 1;
if (index >= 0 && index < this.m_List.Count && index < 12)
{
Mobile m = this.m_List[index];
this.m_From.QuestArrow = new TrackArrow(this.m_From, m, this.m_Range * 2);
if (Core.SE)
Tracking.AddInfo(this.m_From, m);
}
}
// Tracking players uses tracking and detect hidden vs. hiding and stealth
private static bool CheckDifficulty(Mobile from, Mobile m)
{
if (!Core.AOS || !m.Player)
return true;
int tracking = from.Skills[SkillName.Tracking].Fixed;
int detectHidden = from.Skills[SkillName.DetectHidden].Fixed;
if (Core.ML && m.Race == Race.Elf)
tracking /= 2; //The 'Guide' says that it requires twice as Much tracking SKILL to track an elf. Not the total difficulty to track.
int hiding = m.Skills[SkillName.Hiding].Fixed;
int stealth = m.Skills[SkillName.Stealth].Fixed;
int divisor = hiding + stealth;
// Necromancy forms affect tracking difficulty
if (TransformationSpellHelper.UnderTransformation(m, typeof(HorrificBeastSpell)))
divisor -= 200;
else if (TransformationSpellHelper.UnderTransformation(m, typeof(VampiricEmbraceSpell)) && divisor < 500)
divisor = 500;
else if (TransformationSpellHelper.UnderTransformation(m, typeof(WraithFormSpell)) && divisor <= 2000)
divisor += 200;
int chance;
if (divisor > 0)
{
if (Core.SE)
chance = 50 * (tracking * 2 + detectHidden) / divisor;
else
chance = 50 * (tracking + detectHidden + 10 * Utility.RandomMinMax(1, 20)) / divisor;
}
else
chance = 100;
return chance > Utility.Random(100);
}
private static bool IsAnimal(Mobile m)
{
return (!m.Player && m.Body.IsAnimal);
}
private static bool IsMonster(Mobile m)
{
return (!m.Player && m.Body.IsMonster);
}
private static bool IsHumanNPC(Mobile m)
{
return (!m.Player && m.Body.IsHuman);
}
private static bool IsPlayer(Mobile m)
{
return m.Player;
}
private class InternalSorter : IComparer<Mobile>
{
private readonly Mobile m_From;
public InternalSorter(Mobile from)
{
this.m_From = from;
}
public int Compare(Mobile x, Mobile y)
{
if (x == null && y == null)
return 0;
else if (x == null)
return -1;
else if (y == null)
return 1;
return this.m_From.GetDistanceToSqrt(x).CompareTo(this.m_From.GetDistanceToSqrt(y));
}
}
}
public class TrackArrow : QuestArrow
{
private readonly Timer m_Timer;
private Mobile m_From;
public TrackArrow(Mobile from, IEntity target, int range)
: base(from, target)
{
this.m_From = from;
this.m_Timer = new TrackTimer(from, target, range, this);
this.m_Timer.Start();
}
public override void OnClick(bool rightClick)
{
if (rightClick)
{
Tracking.ClearTrackingInfo(this.m_From);
this.m_From = null;
this.Stop();
}
}
public override void OnStop()
{
this.m_Timer.Stop();
if (this.m_From != null)
{
Tracking.ClearTrackingInfo(this.m_From);
this.m_From.SendLocalizedMessage(503177); // You have lost your quarry.
}
}
}
public class TrackTimer : Timer
{
private readonly Mobile m_From;
private readonly IEntity m_Target;
private readonly int m_Range;
private readonly QuestArrow m_Arrow;
private int m_LastX, m_LastY;
public TrackTimer(Mobile from, IEntity target, int range, QuestArrow arrow)
: base(TimeSpan.FromSeconds(0.25), TimeSpan.FromSeconds(2.5))
{
this.m_From = from;
this.m_Target = target;
this.m_Range = range;
this.m_Arrow = arrow;
}
protected override void OnTick()
{
if (!this.m_Arrow.Running)
{
this.Stop();
return;
}
else if (this.m_From.NetState == null || this.m_From.Deleted || this.m_Target.Deleted || this.m_From.Map != this.m_Target.Map || !this.m_From.InRange(this.m_Target, this.m_Range) || this.m_Target is Mobile && (((Mobile)this.m_Target).Hidden && ((Mobile)this.m_Target).AccessLevel > this.m_From.AccessLevel))
{
this.m_Arrow.Stop();
this.Stop();
return;
}
if (this.m_LastX != this.m_Target.Location.X || this.m_LastY != this.m_Target.Location.Y)
{
this.m_LastX = this.m_Target.Location.X;
this.m_LastY = this.m_Target.Location.Y;
this.m_Arrow.Update();
}
}
}
}