BritainKnights/Scripts/Skills/SkillCheck.cs

574 lines
No EOL
19 KiB
C#

using System;
using Server;
using Server.Mobiles;
namespace Server.Misc
{
public enum Trades
{
Alchemy = 0,
Blacksmith = 1,
Carpentry = 2,
Cartography = 3,
Cooking = 4,
Fishing = 5,
Fletching = 6,
Inscribe = 7,
Lumberjacking = 8,
Mining = 9,
Tailoring = 10,
Tinkering = 11,
Musicianship = 12,
Magery = 13
}
public class SkillCheck
{
private static readonly bool AntiMacroCode = Server.Misc.Settings.AllowMacroing();
public static TimeSpan AntiMacroExpire = TimeSpan.FromMinutes( 5.0 ); //How long do we remember targets/locations?
public const int Allowance = 3; //How many times may we use the same location/target for gain
private const int LocationSize = 5; //The size of eeach location, make this smaller so players dont have to move as far
private static bool[] UseAntiMacro = new bool[]
{
// true if this skill uses the anti-macro code, false if it does not
false,// Archery
false,// Bludgeoning
false,// Fencing
false,// Swords
false,// Tactics
false,// Parry
false,// Concentration
true,// Discordance
false,// Dodging
false,// Hand-to-Hand
true,// Healing
true,// Hiding
true,// Lockpicking
true,// Magery
true,// MagicResist
true,// Meditation
true,// Musicianship
true,// Peacemaking
true,// Poisoning
true,// Provocation
true,// RemoveTrap
true,// Searching
true,// Stealing
true,// Stealth
true// Tracking
};
public static void Initialize()
{
Mobile.SkillCheckLocationHandler = new SkillCheckLocationHandler( Mobile_SkillCheckLocation );
Mobile.SkillCheckDirectLocationHandler = new SkillCheckDirectLocationHandler( Mobile_SkillCheckDirectLocation );
Mobile.SkillCheckTargetHandler = new SkillCheckTargetHandler( Mobile_SkillCheckTarget );
Mobile.SkillCheckDirectTargetHandler = new SkillCheckDirectTargetHandler( Mobile_SkillCheckDirectTarget );
}
public static string TradeName( Trades trade )
{
if ( trade == Trades.Alchemy ){ return "Alchemy"; }
else if ( trade == Trades.Blacksmith ){ return "Blacksmithing"; }
else if ( trade == Trades.Carpentry ){ return "Carpentry"; }
else if ( trade == Trades.Cartography ){ return "Cartography"; }
else if ( trade == Trades.Cooking ){ return "Cooking"; }
else if ( trade == Trades.Fishing ){ return "Fishing"; }
else if ( trade == Trades.Fletching ){ return "Fletching"; }
else if ( trade == Trades.Inscribe ){ return "Inscription"; }
else if ( trade == Trades.Lumberjacking ){ return "Lumberjacking"; }
else if ( trade == Trades.Mining ){ return "Mining"; }
else if ( trade == Trades.Tailoring ){ return "Tailoring"; }
else if ( trade == Trades.Tinkering ){ return "Tinkering"; }
else if ( trade == Trades.Magery ){ return "Magery"; }
else if ( trade == Trades.Musicianship ){ return "Musicianship"; }
return "";
}
public static double TradeSkill( Mobile m, Trades trade, bool raw )
{
double value = 10.0;
if ( m is PlayerMobile )
{
PlayerMobile pm = (PlayerMobile)m;
if ( trade == Trades.Alchemy ){ value += (m.Int*0.75)+(m.Dex*0.25); if ( !raw && pm.NpcGuild == NpcGuild.AlchemistsGuild ){ value += 20; } }
else if ( trade == Trades.Blacksmith ){ value += (m.Str*0.85)+(m.Dex*0.15); if ( !raw && pm.NpcGuild == NpcGuild.BlacksmithsGuild ){ value += 20; } }
else if ( trade == Trades.Carpentry ){ value += (m.Dex*0.6)+(m.Str*0.4); if ( !raw && pm.NpcGuild == NpcGuild.CarpentryGuild ){ value += 20; } }
else if ( trade == Trades.Cartography ){ value += (m.Int*0.7)+(m.Dex*0.3); if ( !raw && pm.NpcGuild == NpcGuild.LibrariansGuild ){ value += 20; } }
else if ( trade == Trades.Cooking ){ value += (m.Int*0.75)+(m.Dex*0.25); if ( !raw ){ value += 10; } }
else if ( trade == Trades.Fishing ){ value += (m.Str*0.6)+(m.Dex*0.4); if ( !raw && pm.NpcGuild == NpcGuild.MarinersGuild ){ value += 20; } }
else if ( trade == Trades.Fletching ){ value += (m.Dex*0.7)+(m.Str*0.3); if ( !raw && pm.NpcGuild == NpcGuild.RangersGuild ){ value += 20; } }
else if ( trade == Trades.Inscribe ){ value += (m.Int*0.85)+(m.Dex*0.15); if ( !raw && pm.NpcGuild == NpcGuild.LibrariansGuild ){ value += 20; } }
else if ( trade == Trades.Lumberjacking ){ value += (m.Str*0.8)+(m.Dex*0.2); if ( !raw && pm.NpcGuild == NpcGuild.CarpentryGuild ){ value += 20; } }
else if ( trade == Trades.Mining ){ value += (double)(m.Str); if ( !raw && pm.NpcGuild == NpcGuild.BlacksmithsGuild ){ value += 20; } }
else if ( trade == Trades.Tailoring ){ value += (m.Dex*0.65)+(m.Int*0.35); if ( !raw && pm.NpcGuild == NpcGuild.TailorsGuild ){ value += 20; } }
else if ( trade == Trades.Tinkering ){ value += (m.Dex*0.5)+(m.Int*0.5); if ( !raw && pm.NpcGuild == NpcGuild.TinkersGuild ){ value += 20; } }
}
if ( value > 100 )
value = 100;
return value;
}
public static string TradeStat( Trades trade )
{
string stat = "STR";
if ( trade == Trades.Alchemy ){ if ( Utility.RandomMinMax(1,100) <= 75 ){ stat = "INT"; } else { stat = "DEX"; } }
else if ( trade == Trades.Blacksmith ){ if ( Utility.RandomMinMax(1,100) <= 85 ){ stat = "STR"; } else { stat = "DEX"; } }
else if ( trade == Trades.Carpentry ){ if ( Utility.RandomMinMax(1,100) <= 60 ){ stat = "DEX"; } else { stat = "STR"; } }
else if ( trade == Trades.Cartography ){ if ( Utility.RandomMinMax(1,100) <= 70 ){ stat = "INT"; } else { stat = "DEX"; } }
else if ( trade == Trades.Cooking ){ if ( Utility.RandomMinMax(1,100) <= 75 ){ stat = "INT"; } else { stat = "DEX"; } }
else if ( trade == Trades.Fishing ){ if ( Utility.RandomMinMax(1,100) <= 60 ){ stat = "STR"; } else { stat = "DEX"; } }
else if ( trade == Trades.Fletching ){ if ( Utility.RandomMinMax(1,100) <= 70 ){ stat = "DEX"; } else { stat = "STR"; } }
else if ( trade == Trades.Inscribe ){ if ( Utility.RandomMinMax(1,100) <= 85 ){ stat = "INT"; } else { stat = "DEX"; } }
else if ( trade == Trades.Lumberjacking ){ if ( Utility.RandomMinMax(1,100) <= 80 ){ stat = "STR"; } else { stat = "DEX"; } }
else if ( trade == Trades.Mining ){ stat = "STR"; }
else if ( trade == Trades.Tailoring ){ if ( Utility.RandomMinMax(1,100) <= 65 ){ stat = "DEX"; } else { stat = "INT"; } }
else if ( trade == Trades.Tinkering ){ if ( Utility.RandomMinMax(1,100) <= 50 ){ stat = "DEX"; } else { stat = "INT"; } }
return stat;
}
public static double GetRandomNumber( double minimum, double maximum )
{
Random random = new Random();
return random.NextDouble() * (maximum - minimum) + minimum;
}
public static bool TestTrade( Mobile m, Trades trade, double min, double max )
{
if ( trade == Trades.Magery )
{
if ( m.Skills[SkillName.Magery].Value >= GetRandomNumber( min, max ) )
return true;
else
return false;
}
else if ( trade == Trades.Musicianship )
{
if ( m.Skills[SkillName.Musicianship].Value >= GetRandomNumber( min, max ) )
return true;
else
return false;
}
else if ( TradeSkill( m, trade, false ) >= GetRandomNumber( min, max ) )
{
double gc = (double)(m.Skills.Cap - m.Skills.Total) / m.Skills.Cap;
gc += ( 100 - TradeSkill( m, trade, true ) ) / 100;
gc /= 2;
gc += 0.5;
gc /= 2;
gc *= 1.0;
if ( gc < 0.01 )
gc = 0.01;
if ( gc >= Utility.RandomDouble() )
TradeStatGain( m, TradeStat( trade ) );
return true;
}
return false;
}
public static void TradeStatGain( Mobile from, string stat )
{
if ( stat == "STR" && from.StrLock == StatLockType.Up && (0.5 / 33.3) > Utility.RandomDouble() )
GainStat( from, Stat.Str );
else if ( stat == "DEX" && from.DexLock == StatLockType.Up && (0.5 / 33.3) > Utility.RandomDouble() )
GainStat( from, Stat.Dex );
else if ( stat == "INT" && from.IntLock == StatLockType.Up && (0.5 / 33.3) > Utility.RandomDouble() )
GainStat( from, Stat.Int );
}
public static bool IsGuildSkill( Mobile from, SkillName skillName )
{
if ( from is PlayerMobile )
{
PlayerMobile pm = (PlayerMobile)from;
if ( pm.NpcGuild == NpcGuild.MagesGuild )
{
if ( skillName == SkillName.Concentration ){ return true; }
else if ( skillName == SkillName.Magery ){ return true; }
else if ( skillName == SkillName.Meditation ){ return true; }
}
else if ( pm.NpcGuild == NpcGuild.WarriorsGuild )
{
if ( skillName == SkillName.Fencing ){ return true; }
else if ( skillName == SkillName.Bludgeoning ){ return true; }
else if ( skillName == SkillName.Parry ){ return true; }
else if ( skillName == SkillName.Swords ){ return true; }
else if ( skillName == SkillName.Tactics ){ return true; }
}
else if ( pm.NpcGuild == NpcGuild.ThievesGuild )
{
if ( skillName == SkillName.Hiding ){ return true; }
else if ( skillName == SkillName.Lockpicking ){ return true; }
else if ( skillName == SkillName.Stealing ){ return true; }
else if ( skillName == SkillName.Stealth ){ return true; }
}
else if ( pm.NpcGuild == NpcGuild.RangersGuild )
{
if ( skillName == SkillName.Archery ){ return true; }
else if ( skillName == SkillName.Tracking ){ return true; }
else if ( skillName == SkillName.Tactics ){ return true; }
}
else if ( pm.NpcGuild == NpcGuild.HealersGuild )
{
if ( skillName == SkillName.Healing ){ return true; }
}
else if ( pm.NpcGuild == NpcGuild.BardsGuild )
{
if ( skillName == SkillName.Discordance ){ return true; }
else if ( skillName == SkillName.Musicianship ){ return true; }
else if ( skillName == SkillName.Peacemaking ){ return true; }
else if ( skillName == SkillName.Provocation ){ return true; }
}
else if ( pm.NpcGuild == NpcGuild.AssassinsGuild )
{
if ( skillName == SkillName.Fencing ){ return true; }
else if ( skillName == SkillName.Hiding ){ return true; }
else if ( skillName == SkillName.Poisoning ){ return true; }
else if ( skillName == SkillName.Stealth ){ return true; }
}
}
return false;
}
public static bool IsHealSkill( Mobile from, SkillName skillName )
{
if ( from is PlayerMobile )
{
PlayerMobile pm = (PlayerMobile)from;
if ( pm.NpcGuild == NpcGuild.HealersGuild )
if ( skillName == SkillName.Healing ){ return true; }
}
return false;
}
public static bool Mobile_SkillCheckLocation( Mobile from, SkillName skillName, double minSkill, double maxSkill )
{
Skill skill = from.Skills[skillName];
if ( skill == null )
return false;
double value = skill.Value;
if ( value < minSkill )
return false; // Too difficult
else if ( value >= maxSkill )
return true; // No challenge
double chance = (value - minSkill) / (maxSkill - minSkill);
Point2D loc = new Point2D( from.Location.X / LocationSize, from.Location.Y / LocationSize );
return CheckSkill( from, skill, loc, chance );
}
public static bool Mobile_SkillCheckDirectLocation( Mobile from, SkillName skillName, double chance )
{
Skill skill = from.Skills[skillName];
if ( skill == null )
return false;
if ( chance < 0.0 )
return false; // Too difficult
else if ( chance >= 1.0 )
return true; // No challenge
Point2D loc = new Point2D( from.Location.X / LocationSize, from.Location.Y / LocationSize );
return CheckSkill( from, skill, loc, chance );
}
public static bool CheckSkill( Mobile from, Skill skill, object amObj, double chance )
{
SkillName skillName = skill.SkillName;
if ( from.Skills.Cap == 0 )
return false;
double gainer = 2.0;
if ( from is PlayerMobile )
{
if ( IsGuildSkill( from, skillName ) )
{
switch( Utility.RandomMinMax( 0, 5 ) )
{
case 0: gainer = 1.5; break;
case 1: gainer = 1.4; break;
case 2: gainer = 1.3; break;
case 3: gainer = 1.2; break;
case 4: gainer = 1.1; break;
case 5: gainer = 1.0; break;
}
}
}
if ( IsHealSkill( from, skillName ) )
gainer = 1.0;
bool success = ( chance >= Utility.RandomDouble() );
double gc = (double)(from.Skills.Cap - from.Skills.Total) / from.Skills.Cap;
gc += ( skill.Cap - skill.Base ) / skill.Cap;
gc /= gainer;
gc += ( 1.0 - chance ) * ( success ? 0.5 : 0.2 );
gc /= gainer;
gc *= skill.Info.GainFactor;
if ( gc < 0.01 )
gc = 0.01;
if ( from is BaseCreature && ((BaseCreature)from).Controlled )
gc *= 2;
if ( from.Alive && ( ( gc >= Utility.RandomDouble() && AllowGain( from, skill, amObj ) ) || skill.Base < 10.0 ) )
Gain( from, skill );
return success;
}
public static bool Mobile_SkillCheckTarget( Mobile from, SkillName skillName, object target, double minSkill, double maxSkill )
{
Skill skill = from.Skills[skillName];
if ( skill == null )
return false;
double value = skill.Value;
if ( value < minSkill )
return false; // Too difficult
else if ( value >= maxSkill )
return true; // No challenge
double chance = (value - minSkill) / (maxSkill - minSkill);
return CheckSkill( from, skill, target, chance );
}
public static bool Mobile_SkillCheckDirectTarget( Mobile from, SkillName skillName, object target, double chance )
{
Skill skill = from.Skills[skillName];
if ( skill == null )
return false;
if ( chance < 0.0 )
return false; // Too difficult
else if ( chance >= 1.0 )
return true; // No challenge
return CheckSkill( from, skill, target, chance );
}
private static bool AllowGain( Mobile from, Skill skill, object obj )
{
if ( AntiMacroCode && from is PlayerMobile && UseAntiMacro[skill.Info.SkillID] )
return ((PlayerMobile)from).AntiMacroCheck( skill, obj );
else
return true;
}
public enum Stat { Str, Dex, Int }
public static void Gain( Mobile from, Skill skill )
{
if ( from is BaseCreature && ((BaseCreature)from).IsDeadPet )
return;
if ( skill.Base < skill.Cap && skill.Lock == SkillLock.Up )
{
int toGain = 1;
if ( skill.Base <= 10.0 )
toGain = Utility.Random( 4 ) + 1;
Skills skills = from.Skills;
if ( from.Player && ( skills.Total / skills.Cap ) >= Utility.RandomDouble() )//( skills.Total >= skills.Cap )
{
for ( int i = 0; i < skills.Length; ++i )
{
Skill toLower = skills[i];
if ( toLower != skill && toLower.Lock == SkillLock.Down && toLower.BaseFixedPoint >= toGain )
{
toLower.BaseFixedPoint -= toGain;
break;
}
}
}
if ( !from.Player || (skills.Total + toGain) <= skills.Cap )
{
skill.BaseFixedPoint += toGain;
}
}
if ( skill.Lock == SkillLock.Up )
{
SkillInfo info = skill.Info;
if ( from.StrLock == StatLockType.Up && (info.StrGain / 33.3) > Utility.RandomDouble() )
GainStat( from, Stat.Str );
else if ( from.DexLock == StatLockType.Up && (info.DexGain / 33.3) > Utility.RandomDouble() )
GainStat( from, Stat.Dex );
else if ( from.IntLock == StatLockType.Up && (info.IntGain / 33.3) > Utility.RandomDouble() )
GainStat( from, Stat.Int );
}
}
public static bool CanLower( Mobile from, Stat stat )
{
switch ( stat )
{
case Stat.Str: return ( from.StrLock == StatLockType.Down && from.RawStr > 10 );
case Stat.Dex: return ( from.DexLock == StatLockType.Down && from.RawDex > 10 );
case Stat.Int: return ( from.IntLock == StatLockType.Down && from.RawInt > 10 );
}
return false;
}
public static bool CanRaise( Mobile from, Stat stat )
{
if ( !(from is BaseCreature && ((BaseCreature)from).Controlled) )
{
if ( from.RawStatTotal >= from.StatCap )
return false;
}
switch ( stat )
{
case Stat.Str: return ( from.StrLock == StatLockType.Up && from.RawStr < 125 );
case Stat.Dex: return ( from.DexLock == StatLockType.Up && from.RawDex < 125 );
case Stat.Int: return ( from.IntLock == StatLockType.Up && from.RawInt < 125 );
}
return false;
}
public static void IncreaseStat( Mobile from, Stat stat, bool atrophy )
{
atrophy = atrophy || (from.RawStatTotal >= from.StatCap);
switch ( stat )
{
case Stat.Str:
{
if ( atrophy )
{
if ( CanLower( from, Stat.Dex ) && (from.RawDex < from.RawInt || !CanLower( from, Stat.Int )) )
--from.RawDex;
else if ( CanLower( from, Stat.Int ) )
--from.RawInt;
}
if ( CanRaise( from, Stat.Str ) )
++from.RawStr;
break;
}
case Stat.Dex:
{
if ( atrophy )
{
if ( CanLower( from, Stat.Str ) && (from.RawStr < from.RawInt || !CanLower( from, Stat.Int )) )
--from.RawStr;
else if ( CanLower( from, Stat.Int ) )
--from.RawInt;
}
if ( CanRaise( from, Stat.Dex ) )
++from.RawDex;
break;
}
case Stat.Int:
{
if ( atrophy )
{
if ( CanLower( from, Stat.Str ) && (from.RawStr < from.RawDex || !CanLower( from, Stat.Dex )) )
--from.RawStr;
else if ( CanLower( from, Stat.Dex ) )
--from.RawDex;
}
if ( CanRaise( from, Stat.Int ) )
++from.RawInt;
break;
}
}
}
private static TimeSpan m_StatGainDelay = TimeSpan.FromMinutes( 15.0 );
private static TimeSpan m_PetStatGainDelay = TimeSpan.FromMinutes( 5.0 );
public static void GainStat( Mobile from, Stat stat )
{
switch( stat )
{
case Stat.Str:
{
if ( from is BaseCreature && ((BaseCreature)from).Controlled ) {
if ( (from.LastStrGain + m_PetStatGainDelay) >= DateTime.Now )
return;
}
else if( (from.LastStrGain + m_StatGainDelay) >= DateTime.Now )
return;
from.LastStrGain = DateTime.Now;
break;
}
case Stat.Dex:
{
if ( from is BaseCreature && ((BaseCreature)from).Controlled ) {
if ( (from.LastDexGain + m_PetStatGainDelay) >= DateTime.Now )
return;
}
else if( (from.LastDexGain + m_StatGainDelay) >= DateTime.Now )
return;
from.LastDexGain = DateTime.Now;
break;
}
case Stat.Int:
{
if ( from is BaseCreature && ((BaseCreature)from).Controlled ) {
if ( (from.LastIntGain + m_PetStatGainDelay) >= DateTime.Now )
return;
}
else if( (from.LastIntGain + m_StatGainDelay) >= DateTime.Now )
return;
from.LastIntGain = DateTime.Now;
break;
}
}
bool atrophy = ( (from.RawStatTotal / (double)from.StatCap) >= Utility.RandomDouble() );
IncreaseStat( from, stat, atrophy );
}
}
}