Merge branch 'main' into webSupport
This commit is contained in:
commit
a3458a2950
203 changed files with 1431 additions and 2096 deletions
6
.github/workflows/build-test.yml
vendored
6
.github/workflows/build-test.yml
vendored
|
|
@ -23,11 +23,11 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
|
||||
- name: Setup .NET 5
|
||||
- name: Setup .NET 6
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 5.0.401
|
||||
dotnet-version: 6.0.100
|
||||
- name: Build
|
||||
run: ./publish.cmd
|
||||
- name: Test
|
||||
run: dotnet test --no-restore
|
||||
run: dotnet test --no-restore --framework net6.0
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<Authors>Kamron Batman</Authors>
|
||||
<Company>ModernUO</Company>
|
||||
<Copyright>2019-2020</Copyright>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>preview</LangVersion>
|
||||
|
|
@ -56,9 +56,9 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Condition="!Exists('packages.config')">
|
||||
<Version>3.4.240</Version>
|
||||
<Version>3.4.244</Version>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<AdditionalFiles Include=".\Rules.ruleset" />
|
||||
|
|
|
|||
|
|
@ -133,8 +133,13 @@ LocalizedSign 0x1F28 (LabelNumber=1016109)
|
|||
|
||||
# wooden gate
|
||||
DarkWoodGate 0x0866 (Facing=WestCW)
|
||||
1131 2237 40
|
||||
1131 2237 50
|
||||
1132 2237 40
|
||||
1132 2237 50
|
||||
|
||||
# wooden gate
|
||||
DarkWoodGate 0x0868 (Facing=EastCCW)
|
||||
1133 2237 40
|
||||
1133 2237 50
|
||||
|
||||
# candelabra
|
||||
CandelabraStand 0x0B26
|
||||
|
|
@ -148,11 +153,6 @@ FancyArmoire 0x0A51
|
|||
1132 2231 40
|
||||
1132 2230 40
|
||||
|
||||
# wooden gate
|
||||
DarkWoodGate 0x0868 (Facing=EastCCW)
|
||||
1132 2237 40
|
||||
1132 2237 50
|
||||
|
||||
# book
|
||||
Static 0x1E20
|
||||
1133 2235 24
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>9</LangVersion>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ using Server.Collections;
|
|||
namespace Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkOrderedHashSet
|
||||
{
|
||||
private readonly string[] _iterations = new string[16];
|
||||
|
|
|
|||
|
|
@ -1,90 +0,0 @@
|
|||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Security.Cryptography;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server;
|
||||
using Server.Items;
|
||||
|
||||
namespace Benchmarks
|
||||
{
|
||||
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
|
||||
public class BenchmarkFeatureFlags
|
||||
{
|
||||
public Dictionary<Type, FeatureFlag<Item>> m_Dictionary;
|
||||
public ILookup<Type, FeatureFlag<Item>> m_Lookup;
|
||||
|
||||
public Type[] m_TypesToLookUp;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
RNGCryptoServiceProvider csp = new RNGCryptoServiceProvider();
|
||||
|
||||
string file = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "UOContent.dll");
|
||||
Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(file);
|
||||
|
||||
m_Dictionary = new Dictionary<Type, FeatureFlag<Item>>();
|
||||
List<FeatureFlag<Item>> m_Types = new List<FeatureFlag<Item>>();
|
||||
m_TypesToLookUp = new Type[100];
|
||||
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if (typeof(Item).IsAssignableFrom(type))
|
||||
{
|
||||
m_Dictionary.Add(type, new FeatureFlag<Item>());
|
||||
m_Types.Add(new FeatureFlag<Item>{Type = type});
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Dictionary Size: {0}", m_Dictionary.Count);
|
||||
Console.WriteLine("Lookup Size: {0}", m_Types.Count);
|
||||
|
||||
m_Dictionary.TrimExcess();
|
||||
m_Lookup = m_Types.ToLookup(f => f.Type);
|
||||
Span<byte> bytes = stackalloc byte[4];
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
csp.GetBytes(bytes);
|
||||
m_TypesToLookUp[i] = m_Types[(int)(BinaryPrimitives.ReadUInt32BigEndian(bytes) % m_Types.Count)].Type;
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public FeatureFlag<Item> TestDictionary()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
m_Dictionary.TryGetValue(typeof(ExplosionPotion), out var ff);
|
||||
if (i == 99)
|
||||
{
|
||||
return ff;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public FeatureFlag<Item> TestLookup()
|
||||
{
|
||||
FeatureFlag<Item> ff;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
ff = m_Lookup[typeof(ExplosionPotion)].GetEnumerator().Current;
|
||||
if (i == 99)
|
||||
{
|
||||
return ff;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class FeatureFlag<T> where T : Item
|
||||
{
|
||||
public Type Type { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ using Serilog.Core;
|
|||
|
||||
namespace Benchmarks
|
||||
{
|
||||
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkConsoleLogging
|
||||
{
|
||||
private const string text = "Sample message";
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ using Server.Tests.Network;
|
|||
namespace Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class OutgoingGumpPacketBenchmarks
|
||||
{
|
||||
private static readonly byte[] _layoutBuffer = GC.AllocateUninitializedArray<byte>(0x20000);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using Server.Network;
|
|||
|
||||
namespace Benchmarks
|
||||
{
|
||||
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkPacketBroadcast
|
||||
{
|
||||
public static int SendUnicodeMessage(
|
||||
|
|
|
|||
46
Projects/Benchmarks/Benchmarks/Rng/BenchmarkXoshiro.cs
Normal file
46
Projects/Benchmarks/Benchmarks/Rng/BenchmarkXoshiro.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server.Random;
|
||||
|
||||
namespace Benchmarks.Benchmarks.Rng
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkXoshiro
|
||||
{
|
||||
private Random _random;
|
||||
private Xoshiro256PlusPlus _xoshiro256PlusPlus;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
_xoshiro256PlusPlus = new Xoshiro256PlusPlus();
|
||||
_random = new Random();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int SystemRandomULong() => _random.Next(10000);
|
||||
|
||||
[Benchmark]
|
||||
public int XoshiroRandomULong() => _xoshiro256PlusPlus.Next(10000);
|
||||
|
||||
[Benchmark]
|
||||
public double SystemRandomDouble() => _random.NextDouble();
|
||||
|
||||
[Benchmark]
|
||||
public double XoshiroRandomDouble() => _xoshiro256PlusPlus.NextDouble();
|
||||
|
||||
[Benchmark]
|
||||
public int SystemRandomMinMax() => _random.Next(5000, 85000);
|
||||
|
||||
[Benchmark]
|
||||
public int XoshiroRandomMinMax()
|
||||
{
|
||||
const int min = 5000;
|
||||
const int max = 85000;
|
||||
|
||||
return min + (int)_xoshiro256PlusPlus.Next((uint)(max - min + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ using Server.Text;
|
|||
namespace Benchmarks.BenchmarkText
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkTextEncoding
|
||||
{
|
||||
private const string text =
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using Server.Buffers;
|
|||
namespace Benchmarks.BenchmarkUtilities
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkStringHelpers
|
||||
{
|
||||
private readonly string[] names =
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using BenchmarkDotNet.Running;
|
||||
using Benchmarks.Benchmarks.Rng;
|
||||
|
||||
namespace Benchmarks
|
||||
{
|
||||
|
|
@ -10,10 +11,11 @@ namespace Benchmarks
|
|||
// var packetConstruction = BenchmarkRunner.Run<BenchmarkPacketConstruction>();
|
||||
// var broadcast = BenchmarkRunner.Run<BenchmarkPacketBroadcast>();
|
||||
// var stringHelpers = BenchmarkRunner.Run<BenchmarkStringHelpers>();
|
||||
var indexList = BenchmarkRunner.Run<BenchmarkOrderedHashSet>();
|
||||
// var indexList = BenchmarkRunner.Run<BenchmarkOrderedHashSet>();
|
||||
// var textEncoding = BenchmarkRunner.Run<BenchmarkTextEncoding>();
|
||||
// var logging = BenchmarkRunner.Run<BenchmarkConsoleLogging>();
|
||||
// var gumpPacket = BenchmarkRunner.Run<OutgoingGumpPacketBenchmarks>();
|
||||
var rngTest = BenchmarkRunner.Run<BenchmarkXoshiro>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
|
@ -25,7 +24,6 @@ namespace SerializableMigration
|
|||
{
|
||||
public class DictionaryMigrationRule : ISerializableMigrationRule
|
||||
{
|
||||
private const string KEY_VALUE_PAIR_DELIMITER = "----";
|
||||
public string RuleName => nameof(DictionaryMigrationRule);
|
||||
|
||||
public bool GenerateRuleState(
|
||||
|
|
@ -78,25 +76,29 @@ namespace SerializableMigration
|
|||
extraOptions += "@Tidy";
|
||||
}
|
||||
|
||||
var keyPropertyLength = serializableKeyProperty.RuleArguments?.Length ?? 0;
|
||||
var valuePropertyLength = serializableValueProperty.RuleArguments?.Length ?? 0;
|
||||
ruleArguments = new string[keyPropertyLength + valuePropertyLength + 6];
|
||||
ruleArguments[0] = extraOptions;
|
||||
ruleArguments[1] = keySymbolType.ToDisplayString();
|
||||
ruleArguments[2] = serializableKeyProperty.Rule;
|
||||
var keyArgumentsLength = serializableKeyProperty.RuleArguments?.Length ?? 0;
|
||||
var valueArgumentsLength = serializableValueProperty.RuleArguments?.Length ?? 0;
|
||||
var index = 0;
|
||||
|
||||
if (keyPropertyLength > 0)
|
||||
ruleArguments = new string[7 + keyArgumentsLength + valueArgumentsLength];
|
||||
ruleArguments[index++] = extraOptions;
|
||||
ruleArguments[index++] = keySymbolType.ToDisplayString();
|
||||
ruleArguments[index++] = serializableKeyProperty.Rule;
|
||||
ruleArguments[index++] = keyArgumentsLength.ToString();
|
||||
|
||||
if (keyArgumentsLength > 0)
|
||||
{
|
||||
Array.Copy(serializableKeyProperty.RuleArguments!, 0, ruleArguments, 3, keyPropertyLength);
|
||||
Array.Copy(serializableKeyProperty.RuleArguments!, 0, ruleArguments, index, keyArgumentsLength);
|
||||
index += keyArgumentsLength;
|
||||
}
|
||||
|
||||
ruleArguments[3 + keyPropertyLength] = KEY_VALUE_PAIR_DELIMITER;
|
||||
ruleArguments[4 + keyPropertyLength] = valueSymbolType.ToDisplayString();
|
||||
ruleArguments[5 + keyPropertyLength] = serializableValueProperty.Rule;
|
||||
ruleArguments[index++] = valueSymbolType.ToDisplayString();
|
||||
ruleArguments[index++] = serializableValueProperty.Rule;
|
||||
ruleArguments[index++] = valueArgumentsLength.ToString();
|
||||
|
||||
if (valuePropertyLength > 0)
|
||||
if (valueArgumentsLength > 0)
|
||||
{
|
||||
Array.Copy(serializableValueProperty.RuleArguments!, 0, ruleArguments, 6 + keyPropertyLength, valuePropertyLength);
|
||||
Array.Copy(serializableValueProperty.RuleArguments!, 0, ruleArguments, index, valueArgumentsLength);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -112,20 +114,26 @@ namespace SerializableMigration
|
|||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var index = 1;
|
||||
var keyType = ruleArguments![index++];
|
||||
|
||||
var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![2]];
|
||||
var valueRuleIndex = Array.IndexOf(ruleArguments, KEY_VALUE_PAIR_DELIMITER, 4);
|
||||
if (valueRuleIndex == -1)
|
||||
var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var keyRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (keyRuleArguments.Length > 0)
|
||||
{
|
||||
throw new InvalidDataException($"Cannot find key-value delimiter in arguments for {property.Name}");
|
||||
Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length);
|
||||
index += keyRuleArguments.Length;
|
||||
}
|
||||
|
||||
var keyRuleArguments = new string[valueRuleIndex - 3];
|
||||
Array.Copy(ruleArguments, 3, keyRuleArguments, 0, keyRuleArguments.Length);
|
||||
var valueType = ruleArguments[index++];
|
||||
var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var valueRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[valueRuleIndex + 2]];
|
||||
var valueRuleArguments = new string[ruleArguments.Length - valueRuleIndex - 2];
|
||||
Array.Copy(ruleArguments, 2 + valueRuleIndex, valueRuleArguments, 0, valueRuleArguments.Length);
|
||||
if (valueRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length);
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}";
|
||||
|
|
@ -135,16 +143,16 @@ namespace SerializableMigration
|
|||
var propertyCount = $"{propertyVarPrefix}Count";
|
||||
|
||||
source.AppendLine($"{indent}{ruleArguments[1]} {propertyKeyEntry};");
|
||||
source.AppendLine($"{indent}{ruleArguments[valueRuleIndex + 1]} {propertyValueEntry};");
|
||||
source.AppendLine($"{indent}{valueType} {propertyValueEntry};");
|
||||
source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();");
|
||||
source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.Dictionary<{ruleArguments[1]}, {ruleArguments[valueRuleIndex + 1]}>({propertyCount});");
|
||||
source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.Dictionary<{keyType}, {valueType}>({propertyCount});");
|
||||
source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)");
|
||||
source.AppendLine($"{indent}{{");
|
||||
|
||||
var serializableKeyElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyKeyEntry,
|
||||
Type = ruleArguments[1],
|
||||
Type = keyType,
|
||||
Rule = keyElementRule.RuleName,
|
||||
RuleArguments = keyRuleArguments
|
||||
};
|
||||
|
|
@ -154,7 +162,7 @@ namespace SerializableMigration
|
|||
var serializableValueElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyValueEntry,
|
||||
Type = ruleArguments[valueRuleIndex + 1],
|
||||
Type = valueType,
|
||||
Rule = valueElementRule.RuleName,
|
||||
RuleArguments = valueRuleArguments
|
||||
};
|
||||
|
|
@ -175,21 +183,27 @@ namespace SerializableMigration
|
|||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var shouldTidy = ruleArguments![0].Contains("@Tidy");
|
||||
var index = 0;
|
||||
var shouldTidy = ruleArguments![index++].Contains("@Tidy");
|
||||
var keyType = ruleArguments![index++];
|
||||
|
||||
var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[2]];
|
||||
var valueRuleIndex = Array.IndexOf(ruleArguments, KEY_VALUE_PAIR_DELIMITER, 3);
|
||||
if (valueRuleIndex == -1)
|
||||
var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![index++]];
|
||||
var keyRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (keyRuleArguments.Length > 0)
|
||||
{
|
||||
throw new InvalidDataException($"Cannot find key-value delimiter in arguments for {property.Name}");
|
||||
Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length);
|
||||
index += keyRuleArguments.Length;
|
||||
}
|
||||
|
||||
var keyRuleArguments = new string[valueRuleIndex - 3];
|
||||
Array.Copy(ruleArguments, 3, keyRuleArguments, 0, keyRuleArguments.Length);
|
||||
var valueType = ruleArguments[index++];
|
||||
var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var valueRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[valueRuleIndex + 2]];
|
||||
var valueRuleArguments = new string[ruleArguments.Length - valueRuleIndex - 2];
|
||||
Array.Copy(ruleArguments, 2 + valueRuleIndex, valueRuleArguments, 0, valueRuleArguments.Length);
|
||||
if (valueRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length);
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}";
|
||||
|
|
@ -211,7 +225,7 @@ namespace SerializableMigration
|
|||
var serializableKeyElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyKeyEntry,
|
||||
Type = ruleArguments[1],
|
||||
Type = keyType,
|
||||
Rule = keyElementRule.RuleName,
|
||||
RuleArguments = keyRuleArguments
|
||||
};
|
||||
|
|
@ -221,12 +235,12 @@ namespace SerializableMigration
|
|||
var serializableValueElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyValueEntry,
|
||||
Type = ruleArguments[valueRuleIndex + 1],
|
||||
Type = valueType,
|
||||
Rule = valueElementRule.RuleName,
|
||||
RuleArguments = valueRuleArguments
|
||||
};
|
||||
|
||||
keyElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableValueElement);
|
||||
valueElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableValueElement);
|
||||
|
||||
source.AppendLine($"{indent} }}");
|
||||
source.AppendLine($"{indent}}}");
|
||||
|
|
|
|||
|
|
@ -41,12 +41,12 @@ namespace SerializableMigration
|
|||
return false;
|
||||
}
|
||||
|
||||
var typeArguments = namedTypeSymbol.TypeArguments;
|
||||
var keySymbolType = namedTypeSymbol.TypeArguments[0];
|
||||
|
||||
var keySerializedProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty(
|
||||
compilation,
|
||||
"key",
|
||||
typeArguments[0],
|
||||
keySymbolType,
|
||||
0,
|
||||
attributes,
|
||||
serializableTypes,
|
||||
|
|
@ -55,10 +55,12 @@ namespace SerializableMigration
|
|||
null
|
||||
);
|
||||
|
||||
var valueSymbolType = namedTypeSymbol.TypeArguments[1];
|
||||
|
||||
var valueSerializedProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty(
|
||||
compilation,
|
||||
"value",
|
||||
typeArguments[1],
|
||||
valueSymbolType,
|
||||
1,
|
||||
attributes,
|
||||
serializableTypes,
|
||||
|
|
@ -72,17 +74,19 @@ namespace SerializableMigration
|
|||
var index = 0;
|
||||
|
||||
// Key
|
||||
ruleArguments = new string[5 + keyArgumentsLength + valueArgumentsLength];
|
||||
ruleArguments[index++] = typeArguments[0].ToDisplayString();
|
||||
ruleArguments = new string[6 + keyArgumentsLength + valueArgumentsLength];
|
||||
ruleArguments[index++] = ""; // Extra options
|
||||
ruleArguments[index++] = keySymbolType.ToDisplayString();
|
||||
ruleArguments[index++] = keySerializedProperty.Rule;
|
||||
ruleArguments[index++] = keyArgumentsLength.ToString();
|
||||
if (keyArgumentsLength > 0)
|
||||
{
|
||||
Array.Copy(keySerializedProperty.RuleArguments!, 0, ruleArguments, index, keyArgumentsLength);
|
||||
index += keyArgumentsLength;
|
||||
}
|
||||
|
||||
// Value
|
||||
ruleArguments[index++] = typeArguments[1].ToDisplayString();
|
||||
ruleArguments[index++] = valueSymbolType.ToDisplayString();
|
||||
ruleArguments[index++] = valueSerializedProperty.Rule;
|
||||
|
||||
if (valueArgumentsLength > 0)
|
||||
|
|
@ -103,10 +107,16 @@ namespace SerializableMigration
|
|||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var keyType = ruleArguments![0];
|
||||
var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1]];
|
||||
var keyRuleArguments = new string[int.Parse(ruleArguments[2])];
|
||||
Array.Copy(ruleArguments, 3, keyRuleArguments, 0, keyRuleArguments.Length);
|
||||
var index = 1; // skip extra options
|
||||
var keyType = ruleArguments![index++];
|
||||
var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var keyRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (keyRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length);
|
||||
index += keyRuleArguments.Length;
|
||||
}
|
||||
|
||||
var serializableKeyProperty = new SerializableProperty
|
||||
{
|
||||
|
|
@ -123,11 +133,14 @@ namespace SerializableMigration
|
|||
parentReference
|
||||
);
|
||||
|
||||
var valueIndex = 3 + keyRuleArguments.Length;
|
||||
var valueType = ruleArguments[valueIndex++];
|
||||
var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[valueIndex++]];
|
||||
var valueRuleArguments = new string[ruleArguments.Length - valueIndex];
|
||||
Array.Copy(ruleArguments, valueIndex, valueRuleArguments, 0, valueRuleArguments.Length);
|
||||
var valueType = ruleArguments[index++];
|
||||
var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var valueRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (valueRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length);
|
||||
}
|
||||
|
||||
var serializableValueProperty = new SerializableProperty
|
||||
{
|
||||
|
|
@ -137,7 +150,7 @@ namespace SerializableMigration
|
|||
RuleArguments = valueRuleArguments
|
||||
};
|
||||
|
||||
keyRule.GenerateDeserializationMethod(
|
||||
valueRule.GenerateDeserializationMethod(
|
||||
source,
|
||||
indent,
|
||||
serializableValueProperty,
|
||||
|
|
@ -159,10 +172,16 @@ namespace SerializableMigration
|
|||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var keyType = ruleArguments![0];
|
||||
var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1]];
|
||||
var keyRuleArguments = new string[int.Parse(ruleArguments[2])];
|
||||
Array.Copy(ruleArguments, 3, keyRuleArguments, 0, keyRuleArguments.Length);
|
||||
var index = 1; // skip extra options
|
||||
var keyType = ruleArguments![index++];
|
||||
var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var keyRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (keyRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length);
|
||||
index += keyRuleArguments.Length;
|
||||
}
|
||||
|
||||
var serializableKeyProperty = new SerializableProperty
|
||||
{
|
||||
|
|
@ -178,11 +197,14 @@ namespace SerializableMigration
|
|||
serializableKeyProperty
|
||||
);
|
||||
|
||||
var valueIndex = 3 + keyRuleArguments.Length;
|
||||
var valueType = ruleArguments[valueIndex++];
|
||||
var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[valueIndex++]];
|
||||
var valueRuleArguments = new string[ruleArguments.Length - valueIndex];
|
||||
Array.Copy(ruleArguments, valueIndex, valueRuleArguments, 0, valueRuleArguments.Length);
|
||||
var valueType = ruleArguments[index++];
|
||||
var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var valueRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (valueRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length);
|
||||
}
|
||||
|
||||
var serializableValueProperty = new SerializableProperty
|
||||
{
|
||||
|
|
@ -192,7 +214,7 @@ namespace SerializableMigration
|
|||
RuleArguments = valueRuleArguments
|
||||
};
|
||||
|
||||
keyRule.GenerateSerializationMethod(
|
||||
valueRule.GenerateSerializationMethod(
|
||||
source,
|
||||
indent,
|
||||
serializableValueProperty
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
|
|
@ -30,7 +31,7 @@ namespace SerializableMigration
|
|||
{
|
||||
WriteIndented = true,
|
||||
AllowTrailingCommas = true,
|
||||
IgnoreNullValues = true,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.11.0" />
|
||||
<PackageReference Include="Humanizer.Core" Version="2.11.10" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.0" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Text.Encodings.Web" Version="5.0.0" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1" />
|
||||
<PackageReference Include="Humanizer.Core" Version="2.13.14" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Text.Json" Version="6.0.0" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Text.Encodings.Web" Version="6.0.0" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
|
@ -22,6 +23,7 @@
|
|||
<TargetPathWithTargetPlatformMoniker Include="$(PKGHumanizer_Core)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
|
||||
<TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Text_Json)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
|
||||
<TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Text_Encodings_Web)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
|
||||
<TargetPathWithTargetPlatformMoniker Include="$(PKGMicrosoft_Bcl_AsyncInterfaces)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ using System;
|
|||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using SerializationGenerator;
|
||||
|
||||
|
|
@ -61,7 +62,7 @@ namespace SerializationSchemaGenerator
|
|||
{
|
||||
WriteIndented = true,
|
||||
AllowTrailingCommas = true,
|
||||
IgnoreNullValues = true,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<OutDir>Output</OutDir>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
@ -14,7 +13,10 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build.Locator" Version="1.4.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.11.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="3.11.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.0.1" />
|
||||
<PackageReference Include="System.Text.Json" Version="6.0.0" />
|
||||
<PackageReference Include="System.Text.Encodings.Web" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@ namespace Server
|
|||
{
|
||||
int MaxRange { get; }
|
||||
void OnBeforeSwing(Mobile attacker, Mobile defender);
|
||||
TimeSpan OnSwing(Mobile attacker, Mobile defender);
|
||||
TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus);
|
||||
TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus = 1.0);
|
||||
void GetStatusDamage(Mobile from, out int min, out int max);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ namespace Server.Json
|
|||
{
|
||||
WriteIndented = true,
|
||||
AllowTrailingCommas = true,
|
||||
IgnoreNullValues = true,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,13 +25,13 @@ namespace Server
|
|||
{
|
||||
private RandomNumberGenerator m_Random;
|
||||
|
||||
public RandomNumberGenerator Generator => m_Random ??= new RNGCryptoServiceProvider();
|
||||
public RandomNumberGenerator Generator => m_Random ??= RandomNumberGenerator.Create();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override ulong NextULong()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
|
||||
Generator.GetBytes(buffer);
|
||||
NextBytes(buffer);
|
||||
return BinaryPrimitives.ReadUInt64BigEndian(buffer);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
<Delete Files="..\..\Distribution\zlib.dll" ContinueOnError="true" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Toolkit.HighPerformance" Version="7.1.0" />
|
||||
<PackageReference Include="Microsoft.Toolkit.HighPerformance" Version="7.1.2" />
|
||||
<PackageReference Include="PollGroup" Version="1.1.0" />
|
||||
<PackageReference Include="Zlib.Bindings" Version="1.5.0" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -164,36 +164,33 @@ namespace Server.Targeting
|
|||
{
|
||||
OnTargetOutOfRange(from, targeted);
|
||||
}
|
||||
else
|
||||
else if (!from.CanSee(targeted))
|
||||
{
|
||||
if (!from.CanSee(targeted))
|
||||
{
|
||||
OnCantSeeTarget(from, targeted);
|
||||
}
|
||||
else if (CheckLOS && !from.InLOS(targeted))
|
||||
{
|
||||
OnTargetOutOfLOS(from, targeted);
|
||||
}
|
||||
else if (item?.InSecureTrade == true)
|
||||
{
|
||||
OnTargetInSecureTrade(from, targeted);
|
||||
}
|
||||
else if (item?.IsAccessibleTo(from) == false)
|
||||
{
|
||||
OnTargetNotAccessible(from, targeted);
|
||||
}
|
||||
else if (item?.CheckTarget(from, this, targeted) == false)
|
||||
{
|
||||
OnTargetUntargetable(from, targeted);
|
||||
}
|
||||
else if (mobile?.CheckTarget(from, this, mobile) == false)
|
||||
{
|
||||
OnTargetUntargetable(from, mobile);
|
||||
}
|
||||
else if (from.Region.OnTarget(from, this, targeted))
|
||||
{
|
||||
OnTarget(from, targeted);
|
||||
}
|
||||
OnCantSeeTarget(from, targeted);
|
||||
}
|
||||
else if (CheckLOS && !from.InLOS(targeted))
|
||||
{
|
||||
OnTargetOutOfLOS(from, targeted);
|
||||
}
|
||||
else if (item?.InSecureTrade == true)
|
||||
{
|
||||
OnTargetInSecureTrade(from, targeted);
|
||||
}
|
||||
else if (item?.IsAccessibleTo(from) == false)
|
||||
{
|
||||
OnTargetNotAccessible(from, targeted);
|
||||
}
|
||||
else if (item?.CheckTarget(from, this, targeted) == false)
|
||||
{
|
||||
OnTargetUntargetable(from, targeted);
|
||||
}
|
||||
else if (mobile?.CheckTarget(from, this, mobile) == false)
|
||||
{
|
||||
OnTargetUntargetable(from, mobile);
|
||||
}
|
||||
else if (from.Region.OnTarget(from, this, targeted))
|
||||
{
|
||||
OnTarget(from, targeted);
|
||||
}
|
||||
|
||||
OnTargetFinish(from);
|
||||
|
|
|
|||
|
|
@ -63,5 +63,24 @@ namespace Server
|
|||
Utility.RandomBytes(bytes);
|
||||
return EnsureDirectory(Path.Combine(basePath, bytes.ToHexString()));
|
||||
}
|
||||
|
||||
public static void CopyDirectory(string sourcePath, string destinationPath, bool recursive = true)
|
||||
{
|
||||
var searchOptions = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
|
||||
foreach (var file in Directory.EnumerateFiles(sourcePath, "*", searchOptions))
|
||||
{
|
||||
var fi = new FileInfo(file);
|
||||
var relativePath = Path.GetRelativePath(sourcePath, fi.DirectoryName!);
|
||||
var destFolder = Path.Combine(destinationPath, relativePath);
|
||||
EnsureDirectory(destFolder);
|
||||
fi.CopyTo(Path.Combine(destFolder, fi.Name));
|
||||
}
|
||||
}
|
||||
|
||||
public static void MoveDirectory(string sourcePath, string destinationPath)
|
||||
{
|
||||
CopyDirectory(sourcePath, destinationPath);
|
||||
Directory.Delete(sourcePath, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1049,6 +1049,21 @@ namespace Server
|
|||
return min + (int)RandomSources.Source.Next((uint)(max - min + 1));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long RandomMinMax(long min, long max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
(min, max) = (max, min);
|
||||
}
|
||||
else if (min == max)
|
||||
{
|
||||
return min;
|
||||
}
|
||||
|
||||
return min + RandomSources.Source.Next(max - min + 1);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Random(int from, int count) => RandomSources.Source.Next(from, count);
|
||||
|
||||
|
|
|
|||
|
|
@ -421,7 +421,7 @@ namespace Server
|
|||
try
|
||||
{
|
||||
EventSink.InvokeWorldSavePostSnapshot(SavePath, tempPath);
|
||||
Directory.Move(tempPath, SavePath);
|
||||
PathUtility.MoveDirectory(tempPath, SavePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -666,7 +666,7 @@ namespace Server
|
|||
T entity;
|
||||
|
||||
// Add to this list when creating new serializable types
|
||||
if (typeof(BaseGuild).IsAssignableTo(typeT))
|
||||
if (typeof(BaseGuild).IsAssignableFrom(typeT))
|
||||
{
|
||||
entity = FindGuild(serial) as T;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using Server.Accounting;
|
||||
using Server.Accounting.Security;
|
||||
using Xunit;
|
||||
|
|
@ -9,12 +10,29 @@ namespace Server.Tests.Accounting.Security
|
|||
{
|
||||
private const string plainPassword = "hello-good-sir";
|
||||
|
||||
[Theory, InlineData(typeof(Argon2PasswordProtection)), InlineData(typeof(PBKDF2PasswordProtection)),
|
||||
InlineData(typeof(SHA2PasswordProtection)), InlineData(typeof(SHA1PasswordProtection)),
|
||||
InlineData(typeof(MD5PasswordProtection))]
|
||||
public void TestValidates(Type protectionType)
|
||||
[Theory]
|
||||
[InlineData(typeof(Argon2PasswordProtection), null)]
|
||||
[InlineData(typeof(PBKDF2PasswordProtection), null)]
|
||||
[InlineData(typeof(HashAlgorithmPasswordProtection), "MD5")]
|
||||
[InlineData(typeof(HashAlgorithmPasswordProtection), "SHA1")]
|
||||
[InlineData(typeof(HashAlgorithmPasswordProtection), "SHA2")]
|
||||
public void TestValidates(Type protectionType, string algorithmType)
|
||||
{
|
||||
var passwordProtection = Activator.CreateInstance(protectionType) as IPasswordProtection;
|
||||
IPasswordProtection passwordProtection;
|
||||
if (protectionType == typeof(HashAlgorithmPasswordProtection))
|
||||
{
|
||||
passwordProtection = algorithmType switch
|
||||
{
|
||||
"SHA1" => HashAlgorithmPasswordProtection.SHA1Instance,
|
||||
"SHA2" => HashAlgorithmPasswordProtection.SHA2Instance,
|
||||
_ => HashAlgorithmPasswordProtection.MD5Instance,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
passwordProtection = Activator.CreateInstance(protectionType) as IPasswordProtection;
|
||||
}
|
||||
|
||||
if (passwordProtection == null)
|
||||
{
|
||||
Assert.False(true, $"{protectionType.Name} is not an IPasswordProtection.");
|
||||
|
|
@ -25,12 +43,29 @@ namespace Server.Tests.Accounting.Security
|
|||
Assert.True(passwordProtection.ValidatePassword(encryptedPassword, plainPassword));
|
||||
}
|
||||
|
||||
[Theory, InlineData(typeof(Argon2PasswordProtection)), InlineData(typeof(PBKDF2PasswordProtection)),
|
||||
InlineData(typeof(SHA2PasswordProtection)), InlineData(typeof(SHA1PasswordProtection)),
|
||||
InlineData(typeof(MD5PasswordProtection))]
|
||||
public void TestPasswordDoesNotValidate(Type protectionType)
|
||||
[Theory]
|
||||
[InlineData(typeof(Argon2PasswordProtection), null)]
|
||||
[InlineData(typeof(PBKDF2PasswordProtection), null)]
|
||||
[InlineData(typeof(HashAlgorithmPasswordProtection), "MD5")]
|
||||
[InlineData(typeof(HashAlgorithmPasswordProtection), "SHA1")]
|
||||
[InlineData(typeof(HashAlgorithmPasswordProtection), "SHA2")]
|
||||
public void TestPasswordDoesNotValidate(Type protectionType, string algorithmType)
|
||||
{
|
||||
var passwordProtection = Activator.CreateInstance(protectionType) as IPasswordProtection;
|
||||
IPasswordProtection passwordProtection;
|
||||
if (protectionType == typeof(HashAlgorithmPasswordProtection))
|
||||
{
|
||||
passwordProtection = algorithmType switch
|
||||
{
|
||||
"SHA1" => HashAlgorithmPasswordProtection.SHA1Instance,
|
||||
"SHA2" => HashAlgorithmPasswordProtection.SHA2Instance,
|
||||
_ => HashAlgorithmPasswordProtection.MD5Instance,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
passwordProtection = Activator.CreateInstance(protectionType) as IPasswordProtection;
|
||||
}
|
||||
|
||||
if (passwordProtection == null)
|
||||
{
|
||||
Assert.False(true, $"{protectionType.Name} is not an IPasswordProtection.");
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||
|
|
|
|||
|
|
@ -55,9 +55,9 @@ namespace Server.Accounting.Security
|
|||
{
|
||||
var passwordProtection = algorithm switch
|
||||
{
|
||||
PasswordProtectionAlgorithm.MD5 => MD5PasswordProtection.Instance,
|
||||
PasswordProtectionAlgorithm.SHA1 => SHA1PasswordProtection.Instance,
|
||||
PasswordProtectionAlgorithm.SHA2 => SHA2PasswordProtection.Instance,
|
||||
PasswordProtectionAlgorithm.MD5 => HashAlgorithmPasswordProtection.MD5Instance,
|
||||
PasswordProtectionAlgorithm.SHA1 => HashAlgorithmPasswordProtection.SHA1Instance,
|
||||
PasswordProtectionAlgorithm.SHA2 => HashAlgorithmPasswordProtection.SHA2Instance,
|
||||
PasswordProtectionAlgorithm.PBKDF2 => PBKDF2PasswordProtection.Instance,
|
||||
PasswordProtectionAlgorithm.Argon2 => Argon2PasswordProtection.Instance,
|
||||
PasswordProtectionAlgorithm.None => throw new Exception("Do not use PasswordProtectionAlgorithm.None"),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2020 - ModernUO Development Team *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SHA2PasswordProtection.cs *
|
||||
* File: HashAlgorithmPasswordProtection.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
|
|
@ -19,15 +19,19 @@ using Server.Text;
|
|||
|
||||
namespace Server.Accounting.Security
|
||||
{
|
||||
public class SHA2PasswordProtection : IPasswordProtection
|
||||
public class HashAlgorithmPasswordProtection : IPasswordProtection
|
||||
{
|
||||
public static IPasswordProtection Instance = new SHA2PasswordProtection();
|
||||
private readonly SHA512CryptoServiceProvider m_SHA2HashProvider = new();
|
||||
public static IPasswordProtection MD5Instance = new HashAlgorithmPasswordProtection(MD5.Create());
|
||||
public static IPasswordProtection SHA1Instance = new HashAlgorithmPasswordProtection(SHA1.Create());
|
||||
public static IPasswordProtection SHA2Instance = new HashAlgorithmPasswordProtection(SHA512.Create());
|
||||
private readonly HashAlgorithm _hashAlgorithm;
|
||||
|
||||
public HashAlgorithmPasswordProtection(HashAlgorithm hashAlgorithm) => _hashAlgorithm = hashAlgorithm;
|
||||
|
||||
public string EncryptPassword(string plainPassword)
|
||||
{
|
||||
byte[] bytes = plainPassword.AsSpan(0, Math.Min(256, plainPassword.Length)).GetBytesAscii();
|
||||
return m_SHA2HashProvider.ComputeHash(bytes).ToHexString();
|
||||
return _hashAlgorithm.ComputeHash(bytes).ToHexString();
|
||||
}
|
||||
|
||||
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2020 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: MD5PasswordProtection.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using Server.Text;
|
||||
|
||||
namespace Server.Accounting.Security
|
||||
{
|
||||
public class MD5PasswordProtection : IPasswordProtection
|
||||
{
|
||||
public static IPasswordProtection Instance = new MD5PasswordProtection();
|
||||
#pragma warning disable CA5351
|
||||
private readonly MD5CryptoServiceProvider m_MD5HashProvider = new();
|
||||
#pragma warning restore CA5351
|
||||
|
||||
public string EncryptPassword(string plainPassword)
|
||||
{
|
||||
byte[] bytes = plainPassword.AsSpan(0, Math.Min(256, plainPassword.Length)).GetBytesAscii();
|
||||
return m_MD5HashProvider.ComputeHash(bytes).ToHexString();
|
||||
}
|
||||
|
||||
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
||||
EncryptPassword(plainPassword) == encryptedPassword;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2020 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SHA1PasswordProtection.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using Server.Text;
|
||||
|
||||
namespace Server.Accounting.Security
|
||||
{
|
||||
public class SHA1PasswordProtection : IPasswordProtection
|
||||
{
|
||||
public static IPasswordProtection Instance = new SHA1PasswordProtection();
|
||||
#pragma warning disable CA5350
|
||||
private readonly SHA1CryptoServiceProvider m_SHA1HashProvider = new();
|
||||
#pragma warning restore CA5350
|
||||
|
||||
public string EncryptPassword(string plainPassword)
|
||||
{
|
||||
byte[] bytes = plainPassword.AsSpan(0, Math.Min(256, plainPassword.Length)).GetBytesAscii();
|
||||
return m_SHA1HashProvider.ComputeHash(bytes).ToHexString();
|
||||
}
|
||||
|
||||
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
||||
EncryptPassword(plainPassword) == encryptedPassword;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,11 +7,9 @@ using Server.Gumps;
|
|||
using Server.Items;
|
||||
using Server.Menus.ItemLists;
|
||||
using Server.Menus.Questions;
|
||||
using Server.Misc;
|
||||
using Server.Mobiles;
|
||||
using Server.Multis;
|
||||
using Server.Network;
|
||||
using Server.Saves;
|
||||
using Server.Spells;
|
||||
using Server.Targeting;
|
||||
using Server.Targets;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Server.Buffers;
|
||||
|
||||
namespace Server.Compression
|
||||
|
|
@ -53,13 +52,18 @@ namespace Server.Compression
|
|||
var tempDir = PathUtility.EnsureRandomPath(Path.GetTempPath());
|
||||
|
||||
var libarchiveFile = Path.Combine(tempDir, "libarchive.zip");
|
||||
using WebClient wc = new WebClient();
|
||||
wc.DownloadFile (new Uri(_libArchiveWindowsUrl), libarchiveFile);
|
||||
// This isn't called often so we don't need to optimize
|
||||
using (HttpClient hc = new HttpClient())
|
||||
{
|
||||
var result = hc.Send(new HttpRequestMessage(HttpMethod.Get, new Uri(_libArchiveWindowsUrl)));
|
||||
using var stream = result.Content.ReadAsStream();
|
||||
using FileStream fs = new FileStream(libarchiveFile, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
stream.CopyTo(fs);
|
||||
}
|
||||
|
||||
ZipFile.ExtractToDirectory(libarchiveFile, tempDir);
|
||||
var libArchivePath = Path.Combine(tempDir, "libarchive");
|
||||
Directory.Move(Path.Combine(libArchivePath, "bin"), "bsdtar");
|
||||
Directory.Delete(libArchivePath, true);
|
||||
PathUtility.MoveDirectory(Path.Combine(libArchivePath, "bin"), Path.Combine(Core.BaseDirectory, "bsdtar"));
|
||||
File.Delete(libarchiveFile);
|
||||
|
||||
return Path.Combine(Core.BaseDirectory, "bsdtar/bsdtar.exe");
|
||||
|
|
|
|||
|
|
@ -80,9 +80,8 @@ namespace Server.Items
|
|||
|
||||
if (m_Mobile.KarmaLocked)
|
||||
{
|
||||
m_Mobile.SendLocalizedMessage(
|
||||
1060192
|
||||
); // Your karma has been locked. Your karma can no longer be raised.
|
||||
// Your karma has been locked. Your karma can no longer be raised.
|
||||
m_Mobile.SendLocalizedMessage(1060192);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -112,20 +111,17 @@ namespace Server.Items
|
|||
}
|
||||
}
|
||||
|
||||
public class AnkhWest : Item
|
||||
[Serializable(0, false)]
|
||||
public partial class AnkhWest : Item
|
||||
{
|
||||
private InternalItem m_Item;
|
||||
[SerializableField(0, getter: "private", setter: "private")]
|
||||
private InternalItem _item;
|
||||
|
||||
[Constructible]
|
||||
public AnkhWest(bool bloodied = false) : base(bloodied ? 0x1D98 : 0x3)
|
||||
{
|
||||
Movable = false;
|
||||
|
||||
m_Item = new InternalItem(bloodied, this);
|
||||
}
|
||||
|
||||
public AnkhWest(Serial serial) : base(serial)
|
||||
{
|
||||
_item = new InternalItem(bloodied, this);
|
||||
}
|
||||
|
||||
public override bool HandlesOnMovement => true; // Tell the core that we implement OnMovement
|
||||
|
|
@ -138,9 +134,9 @@ namespace Server.Items
|
|||
set
|
||||
{
|
||||
base.Hue = value;
|
||||
if (m_Item.Hue != value)
|
||||
if (_item.Hue != value)
|
||||
{
|
||||
m_Item.Hue = value;
|
||||
_item.Hue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -166,17 +162,17 @@ namespace Server.Items
|
|||
|
||||
public override void OnLocationChange(Point3D oldLocation)
|
||||
{
|
||||
if (m_Item != null)
|
||||
if (_item != null)
|
||||
{
|
||||
m_Item.Location = new Point3D(X, Y + 1, Z);
|
||||
_item.Location = new Point3D(X, Y + 1, Z);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMapChange()
|
||||
{
|
||||
if (m_Item != null)
|
||||
if (_item != null)
|
||||
{
|
||||
m_Item.Map = Map;
|
||||
_item.Map = Map;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -184,40 +180,19 @@ namespace Server.Items
|
|||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
m_Item?.Delete();
|
||||
_item?.Delete();
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
[Serializable(0, false)]
|
||||
private partial class InternalItem : Item
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Item);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
m_Item = reader.ReadEntity<InternalItem>();
|
||||
}
|
||||
|
||||
private class InternalItem : Item
|
||||
{
|
||||
private AnkhWest m_Item;
|
||||
[SerializableField(0)]
|
||||
private AnkhWest _item;
|
||||
|
||||
public InternalItem(bool bloodied, AnkhWest item) : base(bloodied ? 0x1D97 : 0x2)
|
||||
{
|
||||
Movable = false;
|
||||
|
||||
m_Item = item;
|
||||
}
|
||||
|
||||
public InternalItem(Serial serial) : base(serial)
|
||||
{
|
||||
_item = item;
|
||||
}
|
||||
|
||||
public override bool HandlesOnMovement => true; // Tell the core that we implement OnMovement
|
||||
|
|
@ -230,26 +205,26 @@ namespace Server.Items
|
|||
set
|
||||
{
|
||||
base.Hue = value;
|
||||
if (m_Item.Hue != value)
|
||||
if (_item.Hue != value)
|
||||
{
|
||||
m_Item.Hue = value;
|
||||
_item.Hue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnLocationChange(Point3D oldLocation)
|
||||
{
|
||||
if (m_Item != null)
|
||||
if (_item != null)
|
||||
{
|
||||
m_Item.Location = new Point3D(X, Y - 1, Z);
|
||||
_item.Location = new Point3D(X, Y - 1, Z);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMapChange()
|
||||
{
|
||||
if (m_Item != null)
|
||||
if (_item != null)
|
||||
{
|
||||
m_Item.Map = Map;
|
||||
_item.Map = Map;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -257,7 +232,7 @@ namespace Server.Items
|
|||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
m_Item?.Delete();
|
||||
_item?.Delete();
|
||||
}
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
|
|
@ -278,43 +253,22 @@ namespace Server.Items
|
|||
{
|
||||
Ankhs.Resurrect(m, this);
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Item);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
m_Item = reader.ReadEntity<AnkhWest>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TypeAlias("Server.Items.AnkhEast")]
|
||||
public class AnkhNorth : Item
|
||||
[Serializable(0, false)]
|
||||
public partial class AnkhNorth : Item
|
||||
{
|
||||
private InternalItem m_Item;
|
||||
[SerializableField(0, getter: "private", setter: "private")]
|
||||
private InternalItem _item;
|
||||
|
||||
[Constructible]
|
||||
public AnkhNorth(bool bloodied = false) : base(bloodied ? 0x1E5D : 0x4)
|
||||
{
|
||||
Movable = false;
|
||||
|
||||
m_Item = new InternalItem(bloodied, this);
|
||||
}
|
||||
|
||||
public AnkhNorth(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
_item = new InternalItem(bloodied, this);
|
||||
}
|
||||
|
||||
public override bool HandlesOnMovement => true; // Tell the core that we implement OnMovement
|
||||
|
|
@ -327,9 +281,9 @@ namespace Server.Items
|
|||
set
|
||||
{
|
||||
base.Hue = value;
|
||||
if (m_Item.Hue != value)
|
||||
if (_item.Hue != value)
|
||||
{
|
||||
m_Item.Hue = value;
|
||||
_item.Hue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -355,17 +309,17 @@ namespace Server.Items
|
|||
|
||||
public override void OnLocationChange(Point3D oldLocation)
|
||||
{
|
||||
if (m_Item != null)
|
||||
if (_item != null)
|
||||
{
|
||||
m_Item.Location = new Point3D(X + 1, Y, Z);
|
||||
_item.Location = new Point3D(X + 1, Y, Z);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMapChange()
|
||||
{
|
||||
if (m_Item != null)
|
||||
if (_item != null)
|
||||
{
|
||||
m_Item.Map = Map;
|
||||
_item.Map = Map;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -373,42 +327,21 @@ namespace Server.Items
|
|||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
m_Item?.Delete();
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Item);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
m_Item = reader.ReadEntity<InternalItem>();
|
||||
_item?.Delete();
|
||||
}
|
||||
|
||||
[TypeAlias("Server.Items.AnkhEast+InternalItem")]
|
||||
private class InternalItem : Item
|
||||
[Serializable(0, false)]
|
||||
private partial class InternalItem : Item
|
||||
{
|
||||
private AnkhNorth m_Item;
|
||||
[SerializableField(0)]
|
||||
private AnkhNorth _item;
|
||||
|
||||
public InternalItem(bool bloodied, AnkhNorth item)
|
||||
: base(bloodied ? 0x1E5C : 0x5)
|
||||
{
|
||||
Movable = false;
|
||||
|
||||
m_Item = item;
|
||||
}
|
||||
|
||||
public InternalItem(Serial serial) : base(serial)
|
||||
{
|
||||
_item = item;
|
||||
}
|
||||
|
||||
public override bool HandlesOnMovement => true; // Tell the core that we implement OnMovement
|
||||
|
|
@ -421,26 +354,26 @@ namespace Server.Items
|
|||
set
|
||||
{
|
||||
base.Hue = value;
|
||||
if (m_Item.Hue != value)
|
||||
if (_item.Hue != value)
|
||||
{
|
||||
m_Item.Hue = value;
|
||||
_item.Hue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnLocationChange(Point3D oldLocation)
|
||||
{
|
||||
if (m_Item != null)
|
||||
if (_item != null)
|
||||
{
|
||||
m_Item.Location = new Point3D(X - 1, Y, Z);
|
||||
_item.Location = new Point3D(X - 1, Y, Z);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMapChange()
|
||||
{
|
||||
if (m_Item != null)
|
||||
if (_item != null)
|
||||
{
|
||||
m_Item.Map = Map;
|
||||
_item.Map = Map;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -448,7 +381,7 @@ namespace Server.Items
|
|||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
m_Item?.Delete();
|
||||
_item?.Delete();
|
||||
}
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
|
|
@ -469,24 +402,6 @@ namespace Server.Items
|
|||
{
|
||||
Ankhs.Resurrect(m, this);
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Item);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
m_Item = reader.ReadEntity<AnkhNorth>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,145 +1,45 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
[Furniture]
|
||||
public class ElegantLowTable : Item
|
||||
[Serializable(0, false)]
|
||||
public partial class ElegantLowTable : Item
|
||||
{
|
||||
[Constructible]
|
||||
public ElegantLowTable() : base(0x2819) => Weight = 1.0;
|
||||
|
||||
public ElegantLowTable(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
[Furniture]
|
||||
public class PlainLowTable : Item
|
||||
[Serializable(0, false)]
|
||||
public partial class PlainLowTable : Item
|
||||
{
|
||||
[Constructible]
|
||||
public PlainLowTable() : base(0x281A) => Weight = 1.0;
|
||||
|
||||
public PlainLowTable(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
[Furniture]
|
||||
[Flippable(0xB90, 0xB7D)]
|
||||
public class LargeTable : Item
|
||||
[Serializable(0, false)]
|
||||
public partial class LargeTable : Item
|
||||
{
|
||||
[Constructible]
|
||||
public LargeTable() : base(0xB90) => Weight = 1.0;
|
||||
|
||||
public LargeTable(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
if (Weight == 4.0)
|
||||
{
|
||||
Weight = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Furniture]
|
||||
[Flippable(0xB35, 0xB34)]
|
||||
public class Nightstand : Item
|
||||
[Serializable(0, false)]
|
||||
public partial class Nightstand : Item
|
||||
{
|
||||
[Constructible]
|
||||
public Nightstand() : base(0xB35) => Weight = 1.0;
|
||||
|
||||
public Nightstand(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
if (Weight == 4.0)
|
||||
{
|
||||
Weight = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Furniture]
|
||||
[Flippable(0xB8F, 0xB7C)]
|
||||
public class YewWoodTable : Item
|
||||
[Serializable(0, false)]
|
||||
public partial class YewWoodTable : Item
|
||||
{
|
||||
[Constructible]
|
||||
public YewWoodTable() : base(0xB8F) => Weight = 1.0;
|
||||
|
||||
public YewWoodTable(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
if (Weight == 4.0)
|
||||
{
|
||||
Weight = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,32 +2,10 @@ namespace Server.Items
|
|||
{
|
||||
[Furniture]
|
||||
[Flippable(0xB4A, 0xB49, 0xB4B, 0xB4C)]
|
||||
public class WritingTable : Item
|
||||
[Serializable(0, false)]
|
||||
public partial class WritingTable : Item
|
||||
{
|
||||
[Constructible]
|
||||
public WritingTable() : base(0xB4A) => Weight = 1.0;
|
||||
|
||||
public WritingTable(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
if (Weight == 4.0)
|
||||
{
|
||||
Weight = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,8 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
public abstract class BaseWall : Item
|
||||
[Serializable(0, false)]
|
||||
public abstract partial class BaseWall : Item
|
||||
{
|
||||
public BaseWall(int itemID) : base(itemID) => Movable = false;
|
||||
|
||||
public BaseWall(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,29 +24,12 @@ namespace Server.Items
|
|||
EastWallVShort
|
||||
}
|
||||
|
||||
public class DarkWoodWall : BaseWall
|
||||
[Serializable(0, false)]
|
||||
public partial class DarkWoodWall : BaseWall
|
||||
{
|
||||
[Constructible]
|
||||
public DarkWoodWall(DarkWoodWallTypes type) : base(0x0006 + (int)type)
|
||||
{
|
||||
}
|
||||
|
||||
public DarkWoodWall(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,29 +34,12 @@ namespace Server.Items
|
|||
EastWindow2
|
||||
}
|
||||
|
||||
public class ThickGrayStoneWall : BaseWall
|
||||
[Serializable(0, false)]
|
||||
public partial class ThickGrayStoneWall : BaseWall
|
||||
{
|
||||
[Constructible]
|
||||
public ThickGrayStoneWall(ThickGrayStoneWallTypes type) : base(0x007A + (int)type)
|
||||
{
|
||||
}
|
||||
|
||||
public ThickGrayStoneWall(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,29 +40,12 @@ namespace Server.Items
|
|||
EastWallVShort
|
||||
}
|
||||
|
||||
public class ThinBrickWall : BaseWall
|
||||
[Serializable(0, false)]
|
||||
public partial class ThinBrickWall : BaseWall
|
||||
{
|
||||
[Constructible]
|
||||
public ThinBrickWall(ThinBrickWallTypes type) : base(0x0033 + (int)type)
|
||||
{
|
||||
}
|
||||
|
||||
public ThinBrickWall(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,29 +29,12 @@ namespace Server.Items
|
|||
EastWallShort2
|
||||
}
|
||||
|
||||
public class ThinStoneWall : BaseWall
|
||||
[Serializable(0, false)]
|
||||
public partial class ThinStoneWall : BaseWall
|
||||
{
|
||||
[Constructible]
|
||||
public ThinStoneWall(ThinStoneWallTypes type) : base(0x001A + (int)type)
|
||||
{
|
||||
}
|
||||
|
||||
public ThinStoneWall(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,29 +47,12 @@ namespace Server.Items
|
|||
EastWallVVShort
|
||||
}
|
||||
|
||||
public class WhiteStoneWall : BaseWall
|
||||
[Serializable(0, false)]
|
||||
public partial class WhiteStoneWall : BaseWall
|
||||
{
|
||||
[Constructible]
|
||||
public WhiteStoneWall(WhiteStoneWallTypes type) : base(0x0057 + (int)type)
|
||||
{
|
||||
}
|
||||
|
||||
public WhiteStoneWall(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Server.Collections;
|
||||
using Server.Engines.Craft;
|
||||
using Server.Ethics;
|
||||
using Server.Factions;
|
||||
|
|
@ -695,8 +695,6 @@ namespace Server.Items
|
|||
}
|
||||
}
|
||||
|
||||
public virtual TimeSpan OnSwing(Mobile attacker, Mobile defender) => OnSwing(attacker, defender, 1.0);
|
||||
|
||||
public virtual void GetStatusDamage(Mobile from, out int min, out int max)
|
||||
{
|
||||
GetBaseDamageRange(from, out var baseMin, out var baseMax);
|
||||
|
|
@ -713,7 +711,7 @@ namespace Server.Items
|
|||
}
|
||||
}
|
||||
|
||||
public virtual TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus)
|
||||
public virtual TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus = 1.0)
|
||||
{
|
||||
var canSwing = true;
|
||||
|
||||
|
|
@ -723,12 +721,12 @@ namespace Server.Items
|
|||
|
||||
if (canSwing)
|
||||
{
|
||||
canSwing = !(attacker.Spell is Spell sp) || !sp.IsCasting || !sp.BlocksMovement;
|
||||
canSwing = attacker.Spell is not Spell sp || !sp.IsCasting || !sp.BlocksMovement;
|
||||
}
|
||||
|
||||
if (canSwing)
|
||||
{
|
||||
canSwing = !(attacker is PlayerMobile p) || p.PeacedUntil <= Core.Now;
|
||||
canSwing = attacker is not PlayerMobile p || p.PeacedUntil <= Core.Now;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -786,7 +784,7 @@ namespace Server.Items
|
|||
|
||||
public override void OnAfterDuped(Item newItem)
|
||||
{
|
||||
if (!(newItem is BaseWeapon weap))
|
||||
if (newItem is not BaseWeapon weap)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -877,8 +875,8 @@ namespace Server.Items
|
|||
return true;
|
||||
}
|
||||
|
||||
if (Layer == Layer.OneHanded && layer == Layer.TwoHanded && !(item is BaseShield) &&
|
||||
!(item is BaseEquipableLight))
|
||||
if (Layer == Layer.OneHanded && layer == Layer.TwoHanded && item is not BaseShield &&
|
||||
item is not BaseEquipableLight)
|
||||
{
|
||||
m.SendLocalizedMessage(500215); // You can only wield one weapon at a time.
|
||||
return true;
|
||||
|
|
@ -1096,7 +1094,6 @@ namespace Server.Items
|
|||
var defWeapon = defender.Weapon as BaseWeapon;
|
||||
|
||||
var atkSkill = attacker.Skills[atkWeapon?.Skill ?? SkillName.Wrestling];
|
||||
// Skill defSkill = defender.Skills[defWeapon.Skill];
|
||||
|
||||
var atkValue = atkWeapon?.GetAttackSkillValue(attacker, defender) ?? 0.0;
|
||||
var defValue = defWeapon?.GetDefendSkillValue(attacker, defender) ?? 0.0;
|
||||
|
|
@ -1209,23 +1206,11 @@ namespace Server.Items
|
|||
}
|
||||
else
|
||||
{
|
||||
if (atkValue <= -50.0)
|
||||
{
|
||||
atkValue = -49.9;
|
||||
}
|
||||
|
||||
if (defValue <= -50.0)
|
||||
{
|
||||
defValue = -49.9;
|
||||
}
|
||||
|
||||
ourValue = atkValue + 50.0;
|
||||
theirValue = defValue + 50.0;
|
||||
ourValue = Math.Max(0.1, atkValue + 50.0);
|
||||
theirValue = Math.Max(0.1, defValue + 50.0);
|
||||
}
|
||||
|
||||
var chance = ourValue / (theirValue * 2.0);
|
||||
|
||||
chance *= 1.0 + (double)bonus / 100;
|
||||
var chance = ourValue / (theirValue * 2.0) * 1.0 + (double)bonus / 100;
|
||||
|
||||
if (Core.AOS && chance < 0.02)
|
||||
{
|
||||
|
|
@ -1418,7 +1403,7 @@ namespace Server.Items
|
|||
return defender.CheckSkill(SkillName.Parry, chance);
|
||||
}
|
||||
|
||||
if (defender.Weapon is Fists || defender.Weapon is BaseRanged)
|
||||
if (defender.Weapon is Server.Items.Fists or BaseRanged)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1459,9 +1444,8 @@ namespace Server.Items
|
|||
return defender.CheckSkill(SkillName.Parry, chance);
|
||||
}
|
||||
|
||||
return
|
||||
aosChance > Utility
|
||||
.RandomDouble(); // Only skillcheck if wielding a shield & there's no effect from Bushido
|
||||
// Only skillcheck if wielding a shield & there's no effect from Bushido
|
||||
return aosChance > Utility.RandomDouble();
|
||||
}
|
||||
|
||||
public virtual int AbsorbDamageAOS(Mobile attacker, Mobile defender, int damage)
|
||||
|
|
@ -1493,9 +1477,8 @@ namespace Server.Items
|
|||
|
||||
if (Confidence.IsConfident(defender))
|
||||
{
|
||||
defender.SendLocalizedMessage(
|
||||
1063117
|
||||
); // Your confidence reassures you as you successfully block your opponent's blow.
|
||||
// Your confidence reassures you as you successfully block your opponent's blow.
|
||||
defender.SendLocalizedMessage(1063117);
|
||||
|
||||
var bushido = defender.Skills.Bushido.Value;
|
||||
|
||||
|
|
@ -1590,7 +1573,7 @@ namespace Server.Items
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!(attacker is BaseCreature bc) || bc.PackInstinct == PackInstinct.None || !bc.Controlled && !bc.Summoned)
|
||||
if (attacker is not BaseCreature bc || bc.PackInstinct == PackInstinct.None || !bc.Controlled && !bc.Summoned)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1603,16 +1586,26 @@ namespace Server.Items
|
|||
}
|
||||
|
||||
var eable = defender.GetMobilesInRange<BaseCreature>(1);
|
||||
var inPack = 1 + eable
|
||||
.Where(m => m != attacker && (m.PackInstinct & bc.PackInstinct) != 0 && (m.Controlled || m.Summoned))
|
||||
.Count(m => master == (m.ControlMaster ?? m.SummonMaster) && m.Combatant == defender);
|
||||
var inPack = 1;
|
||||
foreach (var m in eable)
|
||||
{
|
||||
if (m != attacker && (m.PackInstinct & bc.PackInstinct) != 0 && (m.Controlled || m.Summoned) &&
|
||||
master == (m.ControlMaster ?? m.SummonMaster) && m.Combatant == defender)
|
||||
{
|
||||
inPack++;
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
return inPack >= 5 ? 100 :
|
||||
inPack >= 4 ? 75 :
|
||||
inPack >= 3 ? 50 :
|
||||
inPack >= 2 ? 25 : 0;
|
||||
return inPack switch
|
||||
{
|
||||
>= 5 => 100,
|
||||
4 => 75,
|
||||
3 => 50,
|
||||
2 => 25,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
|
||||
public virtual void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1.0)
|
||||
|
|
@ -1688,12 +1681,9 @@ namespace Server.Items
|
|||
|
||||
if (!attacker.Player)
|
||||
{
|
||||
if (defender is PlayerMobile pm)
|
||||
if (defender is PlayerMobile pm && pm.EnemyOfOneType != null && pm.EnemyOfOneType != attacker.GetType())
|
||||
{
|
||||
if (pm.EnemyOfOneType != null && pm.EnemyOfOneType != attacker.GetType())
|
||||
{
|
||||
percentageBonus += 100;
|
||||
}
|
||||
percentageBonus += 100;
|
||||
}
|
||||
}
|
||||
else if (!defender.Player)
|
||||
|
|
@ -1769,16 +1759,14 @@ namespace Server.Items
|
|||
{
|
||||
damage = 1;
|
||||
}
|
||||
else if (Core.AOS && damage == 0) // parried
|
||||
// Parried
|
||||
else if (Core.AOS && damage == 0 && a?.Validate(attacker) == true)
|
||||
{
|
||||
if (a?.Validate(attacker) == true) /*&& a.CheckMana( attacker, true )*/
|
||||
// Parried special moves have no mana cost
|
||||
{
|
||||
a = null;
|
||||
WeaponAbility.ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1061140); // Your attack was parried!
|
||||
}
|
||||
/*&& a.CheckMana( attacker, true )*/
|
||||
// Parried special moves have no mana cost
|
||||
a = null;
|
||||
WeaponAbility.ClearCurrentAbility(attacker);
|
||||
attacker.SendLocalizedMessage(1061140); // Your attack was parried!
|
||||
}
|
||||
|
||||
AddBlood(attacker, defender, damage);
|
||||
|
|
@ -1936,9 +1924,8 @@ namespace Server.Items
|
|||
|
||||
if (context?.Type == typeof(WraithFormSpell))
|
||||
{
|
||||
wraithLeech =
|
||||
5 + (int)(15 * attacker.Skills.SpiritSpeak.Value /
|
||||
100); // Wraith form gives an additional 5-20% mana leech
|
||||
// Wraith form gives an additional 5-20% mana leech
|
||||
wraithLeech = 5 + (int)(15 * attacker.Skills.SpiritSpeak.Value / 100);
|
||||
|
||||
// Mana leeched by the Wraith Form spell is actually stolen, not just leeched.
|
||||
defender.Mana -= AOS.Scale(damageGiven, wraithLeech);
|
||||
|
|
@ -1967,10 +1954,10 @@ namespace Server.Items
|
|||
}
|
||||
}
|
||||
|
||||
if (m_MaxHits > 0 && (MaxRange <= 1 && (defender is Slime || defender is AcidElemental) ||
|
||||
Utility.RandomDouble() < .04)) // Stratics says 50% chance, seems more like 4%..
|
||||
// Stratics says 50% chance, seems more like 4%..
|
||||
if (m_MaxHits > 0 && MaxRange <= 1 && defender is Slime or AcidElemental |Utility.RandomDouble() < .04)
|
||||
{
|
||||
if (MaxRange <= 1 && (defender is Slime || defender is AcidElemental))
|
||||
if (MaxRange <= 1 && defender is Slime or AcidElemental)
|
||||
{
|
||||
attacker.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500263); // *Acid blood scars your weapon!*
|
||||
}
|
||||
|
|
@ -1979,29 +1966,23 @@ namespace Server.Items
|
|||
{
|
||||
HitPoints += 2;
|
||||
}
|
||||
else if (m_Hits > 0)
|
||||
{
|
||||
--HitPoints;
|
||||
}
|
||||
else if (m_MaxHits > 1)
|
||||
{
|
||||
--MaxHitPoints;
|
||||
|
||||
if (Parent is Mobile mobile)
|
||||
{
|
||||
// Your equipment is severely damaged.
|
||||
mobile.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1061121);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Hits > 0)
|
||||
{
|
||||
--HitPoints;
|
||||
}
|
||||
else if (m_MaxHits > 1)
|
||||
{
|
||||
--MaxHitPoints;
|
||||
|
||||
if (Parent is Mobile mobile)
|
||||
{
|
||||
mobile.LocalOverheadMessage(
|
||||
MessageType.Regular,
|
||||
0x3B2,
|
||||
1061121 // Your equipment is severely damaged.
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2021,16 +2002,20 @@ namespace Server.Items
|
|||
|
||||
if (Core.AOS)
|
||||
{
|
||||
var physChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPhysicalArea) *
|
||||
propertyBonus);
|
||||
var physChance =
|
||||
(int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPhysicalArea) * propertyBonus);
|
||||
|
||||
var fireChance =
|
||||
(int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitFireArea) * propertyBonus);
|
||||
|
||||
var coldChance =
|
||||
(int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitColdArea) * propertyBonus);
|
||||
var poisChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPoisonArea) *
|
||||
propertyBonus);
|
||||
var nrgyChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitEnergyArea) *
|
||||
propertyBonus);
|
||||
|
||||
var poisChance =
|
||||
(int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPoisonArea) * propertyBonus);
|
||||
|
||||
var nrgyChance =
|
||||
(int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitEnergyArea) * propertyBonus);
|
||||
|
||||
if (physChance != 0 && physChance > Utility.Random(100))
|
||||
{
|
||||
|
|
@ -2092,10 +2077,10 @@ namespace Server.Items
|
|||
DoDispel(attacker, defender);
|
||||
}
|
||||
|
||||
var laChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerAttack) *
|
||||
propertyBonus);
|
||||
var ldChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerDefend) *
|
||||
propertyBonus);
|
||||
var laChance =
|
||||
(int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerAttack) * propertyBonus);
|
||||
var ldChance =
|
||||
(int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerDefend) * propertyBonus);
|
||||
|
||||
if (laChance != 0 && laChance > Utility.Random(100))
|
||||
{
|
||||
|
|
@ -2121,7 +2106,7 @@ namespace Server.Items
|
|||
it.ReceivedHonorContext?.OnTargetHit(attacker);
|
||||
}
|
||||
|
||||
if (!(this is BaseRanged))
|
||||
if (this is not BaseRanged)
|
||||
{
|
||||
if (AnimalForm.UnderTransformation(attacker, typeof(GiantSerpent)))
|
||||
{
|
||||
|
|
@ -2157,7 +2142,7 @@ namespace Server.Items
|
|||
// SDI bonus
|
||||
damageBonus += AosAttributes.GetValue(attacker, AosAttribute.SpellDamage);
|
||||
|
||||
if(PsychicAttack.Registry.TryGetValue(attacker,out var timer))
|
||||
if (PsychicAttack.Registry.TryGetValue(attacker,out var timer))
|
||||
{
|
||||
damageBonus -= timer.SpellDamageMalus;
|
||||
}
|
||||
|
|
@ -2319,13 +2304,8 @@ namespace Server.Items
|
|||
attacker.PlaySound(GetMissAttackSound(attacker, defender));
|
||||
defender.PlaySound(GetMissDefendSound(attacker, defender));
|
||||
|
||||
var ability = WeaponAbility.GetCurrentAbility(attacker);
|
||||
|
||||
ability?.OnMiss(attacker, defender);
|
||||
|
||||
var move = SpecialMove.GetCurrentMove(attacker);
|
||||
|
||||
move?.OnMiss(attacker, defender);
|
||||
WeaponAbility.GetCurrentAbility(attacker)?.OnMiss(attacker, defender);
|
||||
SpecialMove.GetCurrentMove(attacker)?.OnMiss(attacker, defender);
|
||||
|
||||
if (defender is IHonorTarget target)
|
||||
{
|
||||
|
|
@ -2417,56 +2397,38 @@ namespace Server.Items
|
|||
{
|
||||
var bonus = VirtualDamageBonus;
|
||||
|
||||
switch (m_Quality)
|
||||
bonus += m_Quality switch
|
||||
{
|
||||
case WeaponQuality.Low:
|
||||
bonus -= 20;
|
||||
break;
|
||||
case WeaponQuality.Exceptional:
|
||||
bonus += 20;
|
||||
break;
|
||||
}
|
||||
WeaponQuality.Low => -20,
|
||||
WeaponQuality.Exceptional => 20,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
switch (m_DamageLevel)
|
||||
return bonus + m_DamageLevel switch
|
||||
{
|
||||
case WeaponDamageLevel.Ruin:
|
||||
bonus += 15;
|
||||
break;
|
||||
case WeaponDamageLevel.Might:
|
||||
bonus += 20;
|
||||
break;
|
||||
case WeaponDamageLevel.Force:
|
||||
bonus += 25;
|
||||
break;
|
||||
case WeaponDamageLevel.Power:
|
||||
bonus += 30;
|
||||
break;
|
||||
case WeaponDamageLevel.Vanq:
|
||||
bonus += 35;
|
||||
break;
|
||||
}
|
||||
|
||||
return bonus;
|
||||
WeaponDamageLevel.Ruin => 15,
|
||||
WeaponDamageLevel.Might => 20,
|
||||
WeaponDamageLevel.Force => 25,
|
||||
WeaponDamageLevel.Power => 30,
|
||||
WeaponDamageLevel.Vanq => 35,
|
||||
_ => bonus
|
||||
};
|
||||
}
|
||||
|
||||
public virtual double ScaleDamageAOS(Mobile attacker, double damage, bool checkSkills)
|
||||
{
|
||||
if (checkSkills)
|
||||
{
|
||||
attacker.CheckSkill(
|
||||
SkillName.Tactics,
|
||||
0.0,
|
||||
attacker.Skills.Tactics.Cap
|
||||
); // Passively check tactics for gain
|
||||
attacker.CheckSkill(
|
||||
SkillName.Anatomy,
|
||||
0.0,
|
||||
attacker.Skills.Anatomy.Cap
|
||||
); // Passively check Anatomy for gain
|
||||
// Passively check tactics for gain
|
||||
attacker.CheckSkill(SkillName.Tactics, 0.0, attacker.Skills.Tactics.Cap);
|
||||
|
||||
// Passively check Anatomy for gain
|
||||
attacker.CheckSkill(SkillName.Anatomy, 0.0, attacker.Skills.Anatomy.Cap);
|
||||
|
||||
if (Type == WeaponType.Axe)
|
||||
{
|
||||
attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0); // Passively check Lumberjacking for gain
|
||||
// Passively check Lumberjacking for gain
|
||||
attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2536,20 +2498,16 @@ namespace Server.Items
|
|||
{
|
||||
if (checkSkills)
|
||||
{
|
||||
attacker.CheckSkill(
|
||||
SkillName.Tactics,
|
||||
0.0,
|
||||
attacker.Skills.Tactics.Cap
|
||||
); // Passively check tactics for gain
|
||||
attacker.CheckSkill(
|
||||
SkillName.Anatomy,
|
||||
0.0,
|
||||
attacker.Skills.Anatomy.Cap
|
||||
); // Passively check Anatomy for gain
|
||||
// Passively check tactics for gain
|
||||
attacker.CheckSkill(SkillName.Tactics, 0.0, attacker.Skills.Tactics.Cap);
|
||||
|
||||
// Passively check Anatomy for gain
|
||||
attacker.CheckSkill(SkillName.Anatomy, 0.0, attacker.Skills.Anatomy.Cap);
|
||||
|
||||
if (Type == WeaponType.Axe)
|
||||
{
|
||||
attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0); // Passively check Lumberjacking for gain
|
||||
// Passively check Lumberjacking for gain
|
||||
attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2633,9 +2591,9 @@ namespace Server.Items
|
|||
var damage = (int)ScaleDamageOld(attacker, GetBaseDamage(attacker), true);
|
||||
|
||||
// pre-AOS, halve damage if the defender is a player or the attacker is not a player
|
||||
if (defender is PlayerMobile || !(attacker is PlayerMobile))
|
||||
if (defender is PlayerMobile || attacker is not PlayerMobile)
|
||||
{
|
||||
damage = (int)(damage / 2.0);
|
||||
damage /= 2;
|
||||
}
|
||||
|
||||
return damage;
|
||||
|
|
@ -2643,6 +2601,11 @@ namespace Server.Items
|
|||
|
||||
public virtual void PlayHurtAnimation(Mobile from)
|
||||
{
|
||||
if (from.Mounted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int action;
|
||||
int frames;
|
||||
|
||||
|
|
@ -2667,12 +2630,10 @@ namespace Server.Items
|
|||
frames = 5;
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
|
||||
if (from.Mounted)
|
||||
{
|
||||
return;
|
||||
default:
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
from.Animate(action, frames, 1, true, false, 0);
|
||||
|
|
@ -2695,10 +2656,18 @@ namespace Server.Items
|
|||
switch (Animation)
|
||||
{
|
||||
default:
|
||||
action = Utility.Random(4, 3);
|
||||
break;
|
||||
case WeaponAnimation.ShootBow: return; // 7
|
||||
case WeaponAnimation.ShootXBow: return; // 8
|
||||
{
|
||||
action = Utility.Random(4, 3);
|
||||
break;
|
||||
}
|
||||
case WeaponAnimation.ShootBow:
|
||||
{
|
||||
return; // 7
|
||||
}
|
||||
case WeaponAnimation.ShootXBow:
|
||||
{
|
||||
return; // 8
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -2728,7 +2697,10 @@ namespace Server.Items
|
|||
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
default:
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
from.Animate(action, 7, 1, true, false, 0);
|
||||
|
|
@ -2739,11 +2711,11 @@ namespace Server.Items
|
|||
public int GetElementalDamageHue()
|
||||
{
|
||||
GetDamageTypes(null, out _, out var fire, out var cold, out var pois, out var nrgy, out _, out _);
|
||||
// Order is Cold, Energy, Fire, Poison, Physical left
|
||||
|
||||
var currentMax = 50;
|
||||
var hue = 0;
|
||||
|
||||
// Order is Cold, Energy, Fire, Poison, Physical
|
||||
if (pois >= currentMax)
|
||||
{
|
||||
hue = 1267 + (pois - 50) / 10;
|
||||
|
|
@ -2812,7 +2784,7 @@ namespace Server.Items
|
|||
* formatting show, and remove CLILOCs embedded: more like OSI
|
||||
* did with the books that had markup, etc.
|
||||
*
|
||||
* This will have a negative effect on a few event things imgame
|
||||
* This will have a negative effect on a few event things in-game
|
||||
* as is.
|
||||
*
|
||||
* If we cant find a more OSI-ish way to clean it up, we can
|
||||
|
|
@ -2828,29 +2800,10 @@ namespace Server.Items
|
|||
/* list.Add( 1062613, Utility.FixHtml( m_EngravedText ) ); */
|
||||
}
|
||||
|
||||
public override bool AllowEquippedCast(Mobile from)
|
||||
{
|
||||
if (base.AllowEquippedCast(from))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public override bool AllowEquippedCast(Mobile from) =>
|
||||
base.AllowEquippedCast(from) || Attributes.SpellChanneling != 0;
|
||||
|
||||
return Attributes.SpellChanneling != 0;
|
||||
}
|
||||
|
||||
public virtual int GetLuckBonus()
|
||||
{
|
||||
var resInfo = CraftResources.GetInfo(m_Resource);
|
||||
|
||||
var attrInfo = resInfo?.AttributeInfo;
|
||||
|
||||
if (attrInfo == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return attrInfo.WeaponLuck;
|
||||
}
|
||||
public virtual int GetLuckBonus() => CraftResources.GetInfo(m_Resource)?.AttributeInfo?.WeaponLuck ?? 0;
|
||||
|
||||
public override void GetProperties(ObjectPropertyList list)
|
||||
{
|
||||
|
|
@ -3235,17 +3188,25 @@ namespace Server.Items
|
|||
switch (Skill)
|
||||
{
|
||||
case SkillName.Swords:
|
||||
list.Add(1061172);
|
||||
break; // skill required: swordsmanship
|
||||
{
|
||||
list.Add(1061172); // skill required: swordsmanship
|
||||
break;
|
||||
}
|
||||
case SkillName.Macing:
|
||||
list.Add(1061173);
|
||||
break; // skill required: mace fighting
|
||||
{
|
||||
list.Add(1061173); // skill required: mace fighting
|
||||
break;
|
||||
}
|
||||
case SkillName.Fencing:
|
||||
list.Add(1061174);
|
||||
break; // skill required: fencing
|
||||
{
|
||||
list.Add(1061174); // skill required: fencing
|
||||
break;
|
||||
}
|
||||
case SkillName.Archery:
|
||||
list.Add(1061175);
|
||||
break; // skill required: archery
|
||||
{
|
||||
list.Add(1061175); // skill required: archery
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3351,13 +3312,7 @@ namespace Server.Items
|
|||
public virtual int GetHitAttackSound(Mobile attacker, Mobile defender)
|
||||
{
|
||||
var sound = attacker.GetAttackSound();
|
||||
|
||||
if (sound == -1)
|
||||
{
|
||||
sound = HitSound;
|
||||
}
|
||||
|
||||
return sound;
|
||||
return sound == -1 ? HitSound : sound;
|
||||
}
|
||||
|
||||
public virtual int GetHitDefendSound(Mobile attacker, Mobile defender) => defender.GetHurtSound();
|
||||
|
|
@ -3518,33 +3473,37 @@ namespace Server.Items
|
|||
var range = Core.ML ? 5 : 10;
|
||||
|
||||
var eable = from.GetMobilesInRange(range);
|
||||
var list = eable.Where(
|
||||
m =>
|
||||
from != m && defender != m && SpellHelper.ValidIndirectTarget(from, m)
|
||||
&& from.CanBeHarmful(m, false) && (!Core.ML || from.InLOS(m))
|
||||
)
|
||||
.ToList();
|
||||
using var queue = PooledRefQueue<Mobile>.Create();
|
||||
foreach (var m in eable)
|
||||
{
|
||||
if (from != m && defender != m && SpellHelper.ValidIndirectTarget(from, m)
|
||||
&& from.CanBeHarmful(m, false) && (!Core.ML || from.InLOS(m)))
|
||||
{
|
||||
queue.Enqueue(m);
|
||||
}
|
||||
}
|
||||
eable.Free();
|
||||
|
||||
if (list.Count == 0)
|
||||
if (queue.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Effects.PlaySound(from.Location, map, sound);
|
||||
|
||||
for (var i = 0; i < list.Count; ++i)
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var m = list[i];
|
||||
var m = queue.Dequeue();
|
||||
|
||||
var scalar = Core.ML ? 1.0 : (11 - from.GetDistanceToSqrt(m)) / 10;
|
||||
var damage = GetBaseDamage(from);
|
||||
|
||||
if (scalar <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var damage = GetBaseDamage(from);
|
||||
|
||||
if (scalar < 1.0)
|
||||
{
|
||||
damage *= (11 - from.GetDistanceToSqrt(m)) / 10;
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ namespace Server.Items
|
|||
}
|
||||
}
|
||||
|
||||
public override TimeSpan OnSwing(Mobile attacker, Mobile defender)
|
||||
public override TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus = 1.0)
|
||||
{
|
||||
if (!Core.AOS)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ namespace Server.Items
|
|||
|
||||
public override SkillName AccuracySkill => SkillName.Archery;
|
||||
|
||||
public override TimeSpan OnSwing(Mobile attacker, Mobile defender)
|
||||
public override TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus = 1.0)
|
||||
{
|
||||
// WeaponAbility a = WeaponAbility.GetCurrentAbility( attacker );
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.AnkhNorth.InternalItem",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Item",
|
||||
"type": "Server.Items.AnkhNorth",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
11
Projects/UOContent/Migrations/Server.Items.AnkhNorth.v0.json
Normal file
11
Projects/UOContent/Migrations/Server.Items.AnkhNorth.v0.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.AnkhNorth",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Item",
|
||||
"type": "Server.Items.AnkhNorth.InternalItem",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.AnkhWest.InternalItem",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Item",
|
||||
"type": "Server.Items.AnkhWest",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
11
Projects/UOContent/Migrations/Server.Items.AnkhWest.v0.json
Normal file
11
Projects/UOContent/Migrations/Server.Items.AnkhWest.v0.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.AnkhWest",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Item",
|
||||
"type": "Server.Items.AnkhWest.InternalItem",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.BaseWall"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.DarkWoodWall"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.ElegantLowTable"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.LargeTable"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.Nightstand"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.PlainLowTable"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.ThickGrayStoneWall"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.ThinBrickWall"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.ThinStoneWall"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.WhiteStoneWall"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.WritingTable"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.YewWoodTable"
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ namespace Server
|
|||
}
|
||||
};
|
||||
|
||||
var file = Core.FindDataFile("prof.txt");
|
||||
var file = Core.FindDataFile("prof.txt", false);
|
||||
if (!File.Exists(file))
|
||||
{
|
||||
var parent = Path.Combine(Core.BaseDirectory, "Data/Professions");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using Server.Logging;
|
||||
|
|
@ -165,12 +167,16 @@ namespace Server.Misc
|
|||
Utility.IPMatch("169.254.*", ip) ||
|
||||
Utility.IPMatch("100.64-127.*", ip));
|
||||
|
||||
private const string _ipifyUrl = "https://api.ipify.org";
|
||||
|
||||
private static IPAddress FindPublicAddress()
|
||||
{
|
||||
try
|
||||
{
|
||||
using WebClient wc = new WebClient();
|
||||
return IPAddress.Parse(wc.DownloadString("https://api.ipify.org"));
|
||||
// This isn't called often so we don't need to optimize
|
||||
using HttpClient hc = new HttpClient();
|
||||
var ipAddress = hc.GetStringAsync(_ipifyUrl).Result;
|
||||
return IPAddress.Parse(ipAddress);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Server.Collections;
|
||||
using Server.ContextMenus;
|
||||
using Server.Engines.ConPVP;
|
||||
using Server.Engines.MLQuests;
|
||||
|
|
@ -512,11 +512,11 @@ namespace Server.Mobiles
|
|||
public virtual bool DeathAdderCharmable => false;
|
||||
|
||||
// TODO: Find the pub 31 tweaks to the DispelDifficulty and apply them of course.
|
||||
public virtual double DispelDifficulty // at this skill level we dispel 50% chance
|
||||
=> 0.0;
|
||||
// at this skill level we dispel 50% chance
|
||||
public virtual double DispelDifficulty => 0.0;
|
||||
|
||||
public virtual double DispelFocus // at difficulty - focus we have 0%, at difficulty + focus we have 100%
|
||||
=> 20.0;
|
||||
// at difficulty - focus we have 0%, at difficulty + focus we have 100%
|
||||
public virtual double DispelFocus => 20.0;
|
||||
|
||||
public virtual bool DisplayWeight => Backpack is StrongBackpack;
|
||||
|
||||
|
|
@ -1169,9 +1169,8 @@ namespace Server.Mobiles
|
|||
|
||||
if (m_MLQuests == null)
|
||||
{
|
||||
return
|
||||
MLQuestSystem
|
||||
.EmptyList; // return EmptyList, but don't cache it (run construction again next time)
|
||||
// return EmptyList, but don't cache it (run construction again next time)
|
||||
return MLQuestSystem.EmptyList;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1211,7 +1210,7 @@ namespace Server.Mobiles
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!(m is BaseCreature c) || m is MilitiaFighter)
|
||||
if (m is not BaseCreature c || m is MilitiaFighter)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2153,11 +2152,8 @@ namespace Server.Mobiles
|
|||
// even if they can't offer you anything at the moment
|
||||
if (MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile mobile)
|
||||
{
|
||||
MLQuestSystem.Tell(
|
||||
this,
|
||||
mobile,
|
||||
1074893
|
||||
); // You need to mark your quest items so I don't take the wrong object. Then speak to me.
|
||||
// You need to mark your quest items so I don't take the wrong object. Then speak to me.
|
||||
MLQuestSystem.Tell(this, mobile, 1074893);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2536,8 +2532,8 @@ namespace Server.Mobiles
|
|||
|
||||
public override bool IsHarmfulCriminal(Mobile target) =>
|
||||
(!Controlled || target != m_ControlMaster) && (!Summoned || target != m_SummonMaster) &&
|
||||
(!(target is BaseCreature creature) || !creature.InitialInnocent || creature.Controlled) &&
|
||||
(!(target is PlayerMobile mobile) || mobile.PermaFlags.Count <= 0) && base.IsHarmfulCriminal(target);
|
||||
(target is not BaseCreature { InitialInnocent: true } creature || creature.Controlled) &&
|
||||
(target is not PlayerMobile mobile || mobile.PermaFlags.Count <= 0) && base.IsHarmfulCriminal(target);
|
||||
|
||||
public override void CriminalAction(bool message)
|
||||
{
|
||||
|
|
@ -2837,18 +2833,6 @@ namespace Server.Mobiles
|
|||
return null;
|
||||
}
|
||||
|
||||
public static void Cap(ref int val, int min, int max)
|
||||
{
|
||||
if (val < min)
|
||||
{
|
||||
val = min;
|
||||
}
|
||||
else if (val > max)
|
||||
{
|
||||
val = max;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (from.AccessLevel >= AccessLevel.GameMaster && !Body.IsHuman)
|
||||
|
|
@ -2903,7 +2887,8 @@ namespace Server.Mobiles
|
|||
}
|
||||
else if (Controlled && Commandable)
|
||||
{
|
||||
if (IsBonded) // Intentional difference (showing ONLY bonded when bonded instead of bonded & tame)
|
||||
// Intentional difference (showing ONLY bonded when bonded instead of bonded & tame)
|
||||
if (IsBonded)
|
||||
{
|
||||
list.Add(1049608); // (bonded)
|
||||
}
|
||||
|
|
@ -3028,7 +3013,7 @@ namespace Server.Mobiles
|
|||
{
|
||||
var de = list[i];
|
||||
|
||||
if (de.Damager == m || !(de.Damager is BaseCreature bc))
|
||||
if (de.Damager == m || de.Damager is not BaseCreature bc)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -3144,10 +3129,8 @@ namespace Server.Mobiles
|
|||
|
||||
if (rights.Count > 0)
|
||||
{
|
||||
rights[0].m_Damage =
|
||||
(int)(rights[0].m_Damage *
|
||||
1.25
|
||||
); // This would be the first valid person attacking it. Gets a 25% bonus. Per 1/19/07 Five on Friday
|
||||
// This would be the first valid person attacking it. Gets a 25% bonus. Per 1/19/07 Five on Friday
|
||||
rights[0].m_Damage = (int)(rights[0].m_Damage * 1.25);
|
||||
|
||||
if (rights.Count > 1)
|
||||
{
|
||||
|
|
@ -3155,24 +3138,14 @@ namespace Server.Mobiles
|
|||
}
|
||||
|
||||
var topDamage = rights[0].m_Damage;
|
||||
int minDamage;
|
||||
|
||||
if (hitsMax >= 3000)
|
||||
int minDamage = hitsMax switch
|
||||
{
|
||||
minDamage = topDamage / 16;
|
||||
}
|
||||
else if (hitsMax >= 1000)
|
||||
{
|
||||
minDamage = topDamage / 8;
|
||||
}
|
||||
else if (hitsMax >= 200)
|
||||
{
|
||||
minDamage = topDamage / 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
minDamage = topDamage / 2;
|
||||
}
|
||||
>= 3000 => topDamage / 16,
|
||||
>= 1000 => topDamage / 8,
|
||||
>= 200 => topDamage / 4,
|
||||
_ => topDamage / 2
|
||||
};
|
||||
|
||||
for (var i = 0; i < rights.Count; ++i)
|
||||
{
|
||||
|
|
@ -3271,127 +3244,126 @@ namespace Server.Mobiles
|
|||
GiftOfLifeSpell.HandleDeath(this);
|
||||
|
||||
CheckStatTimers();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Summoned && !NoKillAwards)
|
||||
{
|
||||
var totalFame = Fame / 100;
|
||||
var totalKarma = -Karma / 100;
|
||||
|
||||
if (Map == Map.Felucca)
|
||||
if (!Summoned && !NoKillAwards)
|
||||
{
|
||||
var totalFame = Fame / 100;
|
||||
var totalKarma = -Karma / 100;
|
||||
|
||||
if (Map == Map.Felucca)
|
||||
{
|
||||
totalFame += totalFame / 10 * 3;
|
||||
totalKarma += totalKarma / 10 * 3;
|
||||
}
|
||||
|
||||
var list = GetLootingRights(DamageEntries, HitsMax);
|
||||
var titles = new List<Mobile>();
|
||||
var fame = new List<int>();
|
||||
var karma = new List<int>();
|
||||
|
||||
var givenQuestKill = false;
|
||||
var givenFactionKill = false;
|
||||
var givenToTKill = false;
|
||||
|
||||
for (var i = 0; i < list.Count; ++i)
|
||||
{
|
||||
var ds = list[i];
|
||||
|
||||
if (!ds.m_HasRight)
|
||||
{
|
||||
totalFame += totalFame / 10 * 3;
|
||||
totalKarma += totalKarma / 10 * 3;
|
||||
continue;
|
||||
}
|
||||
|
||||
var list = GetLootingRights(DamageEntries, HitsMax);
|
||||
var titles = new List<Mobile>();
|
||||
var fame = new List<int>();
|
||||
var karma = new List<int>();
|
||||
var party = Engines.PartySystem.Party.Get(ds.m_Mobile);
|
||||
|
||||
var givenQuestKill = false;
|
||||
var givenFactionKill = false;
|
||||
var givenToTKill = false;
|
||||
|
||||
for (var i = 0; i < list.Count; ++i)
|
||||
if (party != null)
|
||||
{
|
||||
var ds = list[i];
|
||||
var divedFame = totalFame / party.Members.Count;
|
||||
var divedKarma = totalKarma / party.Members.Count;
|
||||
|
||||
if (!ds.m_HasRight)
|
||||
for (var j = 0; j < party.Members.Count; ++j)
|
||||
{
|
||||
var info = party.Members[j];
|
||||
|
||||
if (info?.Mobile != null)
|
||||
{
|
||||
var index = titles.IndexOf(info.Mobile);
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
titles.Add(info.Mobile);
|
||||
fame.Add(divedFame);
|
||||
karma.Add(divedKarma);
|
||||
}
|
||||
else
|
||||
{
|
||||
fame[index] += divedFame;
|
||||
karma[index] += divedKarma;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
titles.Add(ds.m_Mobile);
|
||||
fame.Add(totalFame);
|
||||
karma.Add(totalKarma);
|
||||
}
|
||||
|
||||
OnKilledBy(ds.m_Mobile);
|
||||
|
||||
if (!givenFactionKill)
|
||||
{
|
||||
givenFactionKill = true;
|
||||
Faction.HandleDeath(this, ds.m_Mobile);
|
||||
}
|
||||
|
||||
var region = ds.m_Mobile.Region;
|
||||
|
||||
if (!givenToTKill && (Map == Map.Tokuno || region.IsPartOf("Yomotsu Mines") ||
|
||||
region.IsPartOf("Fan Dancer's Dojo")))
|
||||
{
|
||||
givenToTKill = true;
|
||||
TreasuresOfTokuno.HandleKill(this, ds.m_Mobile);
|
||||
}
|
||||
|
||||
if (ds.m_Mobile is PlayerMobile pm)
|
||||
{
|
||||
if (MLQuestSystem.Enabled)
|
||||
{
|
||||
MLQuestSystem.HandleKill(pm, this);
|
||||
}
|
||||
|
||||
if (givenQuestKill)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var party = Engines.PartySystem.Party.Get(ds.m_Mobile);
|
||||
var qs = pm.Quest;
|
||||
|
||||
if (party != null)
|
||||
if (qs != null)
|
||||
{
|
||||
var divedFame = totalFame / party.Members.Count;
|
||||
var divedKarma = totalKarma / party.Members.Count;
|
||||
|
||||
for (var j = 0; j < party.Members.Count; ++j)
|
||||
{
|
||||
var info = party.Members[j];
|
||||
|
||||
if (info?.Mobile != null)
|
||||
{
|
||||
var index = titles.IndexOf(info.Mobile);
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
titles.Add(info.Mobile);
|
||||
fame.Add(divedFame);
|
||||
karma.Add(divedKarma);
|
||||
}
|
||||
else
|
||||
{
|
||||
fame[index] += divedFame;
|
||||
karma[index] += divedKarma;
|
||||
}
|
||||
}
|
||||
}
|
||||
qs.OnKill(this, c);
|
||||
givenQuestKill = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
titles.Add(ds.m_Mobile);
|
||||
fame.Add(totalFame);
|
||||
karma.Add(totalKarma);
|
||||
}
|
||||
|
||||
OnKilledBy(ds.m_Mobile);
|
||||
|
||||
if (!givenFactionKill)
|
||||
{
|
||||
givenFactionKill = true;
|
||||
Faction.HandleDeath(this, ds.m_Mobile);
|
||||
}
|
||||
|
||||
var region = ds.m_Mobile.Region;
|
||||
|
||||
if (!givenToTKill && (Map == Map.Tokuno || region.IsPartOf("Yomotsu Mines") ||
|
||||
region.IsPartOf("Fan Dancer's Dojo")))
|
||||
{
|
||||
givenToTKill = true;
|
||||
TreasuresOfTokuno.HandleKill(this, ds.m_Mobile);
|
||||
}
|
||||
|
||||
if (ds.m_Mobile is PlayerMobile pm)
|
||||
{
|
||||
if (MLQuestSystem.Enabled)
|
||||
{
|
||||
MLQuestSystem.HandleKill(pm, this);
|
||||
}
|
||||
|
||||
if (givenQuestKill)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var qs = pm.Quest;
|
||||
|
||||
if (qs != null)
|
||||
{
|
||||
qs.OnKill(this, c);
|
||||
givenQuestKill = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < titles.Count; ++i)
|
||||
{
|
||||
Titles.AwardFame(titles[i], fame[i], true);
|
||||
Titles.AwardKarma(titles[i], karma[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnDeath(c);
|
||||
|
||||
if (DeleteCorpseOnDeath)
|
||||
for (var i = 0; i < titles.Count; ++i)
|
||||
{
|
||||
c.Delete();
|
||||
Titles.AwardFame(titles[i], fame[i], true);
|
||||
Titles.AwardKarma(titles[i], karma[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnDeath(c);
|
||||
|
||||
if (DeleteCorpseOnDeath)
|
||||
{
|
||||
c.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDelete()
|
||||
|
|
@ -3642,17 +3614,25 @@ namespace Server.Mobiles
|
|||
|
||||
public virtual bool Rummage()
|
||||
{
|
||||
var eable = GetItemsInRange<Corpse>(2);
|
||||
var toRummage = eable.FirstOrDefault(item => item.Items.Count > 0);
|
||||
|
||||
eable.Free();
|
||||
|
||||
if (toRummage == null)
|
||||
if (Backpack == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Backpack == null)
|
||||
var eable = GetItemsInRange<Corpse>(2);
|
||||
Corpse toRummage = null;
|
||||
foreach (var c in eable)
|
||||
{
|
||||
if (c.Items.Count > 0)
|
||||
{
|
||||
toRummage = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
if (toRummage == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -3788,27 +3768,24 @@ namespace Server.Mobiles
|
|||
|
||||
public static void TeleportPets(Mobile master, Point3D loc, Map map, bool onlyBonded = false)
|
||||
{
|
||||
var move = new List<Mobile>();
|
||||
using var queue = PooledRefQueue<Mobile>.Create();
|
||||
|
||||
foreach (var m in master.GetMobilesInRange(3))
|
||||
var eable = master.GetMobilesInRange(3);
|
||||
foreach (var m in eable)
|
||||
{
|
||||
if (
|
||||
m is BaseCreature {
|
||||
Controlled: true,
|
||||
ControlOrder: OrderType.Guard or OrderType.Follow or OrderType.Come
|
||||
} pet
|
||||
)
|
||||
if (m is BaseCreature
|
||||
{ Controlled: true, ControlOrder: OrderType.Guard or OrderType.Follow or OrderType.Come } pet &&
|
||||
pet.ControlMaster == master && (!onlyBonded || pet.IsBonded))
|
||||
{
|
||||
if (pet.ControlMaster == master && (!onlyBonded || pet.IsBonded))
|
||||
{
|
||||
move.Add(pet);
|
||||
}
|
||||
queue.Enqueue(pet);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var m in move)
|
||||
eable.Free();
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
m.MoveToWorld(loc, map);
|
||||
queue.Dequeue().MoveToWorld(loc, map);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3844,18 +3821,14 @@ namespace Server.Mobiles
|
|||
|
||||
var owner = ControlMaster;
|
||||
|
||||
if (owner?.Deleted != false || owner.Map != Map || !owner.InRange(this, 12) || !CanSee(owner) ||
|
||||
!InLOS(owner))
|
||||
{
|
||||
if (OwnerAbandonTime == DateTime.MinValue)
|
||||
{
|
||||
OwnerAbandonTime = Core.Now;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (owner?.Deleted == false && owner.Map == Map && owner.InRange(this, 12) && CanSee(owner) && InLOS(owner))
|
||||
{
|
||||
OwnerAbandonTime = DateTime.MinValue;
|
||||
}
|
||||
else if (OwnerAbandonTime == DateTime.MinValue)
|
||||
{
|
||||
OwnerAbandonTime = Core.Now;
|
||||
}
|
||||
|
||||
CheckStatTimers();
|
||||
}
|
||||
|
|
@ -3961,7 +3934,7 @@ namespace Server.Mobiles
|
|||
|
||||
public void BeginDeleteTimer()
|
||||
{
|
||||
if (!(this is BaseEscortable) && !Summoned && !Deleted && !IsStabled)
|
||||
if (this is not BaseEscortable && !Summoned && !Deleted && !IsStabled)
|
||||
{
|
||||
StopDeleteTimer();
|
||||
m_DeleteTimer = new DeleteTimer(this, TimeSpan.FromDays(3.0));
|
||||
|
|
@ -4261,40 +4234,13 @@ namespace Server.Mobiles
|
|||
{
|
||||
}
|
||||
|
||||
public virtual bool CheckFoodPreference(Item f)
|
||||
{
|
||||
if (CheckFoodPreference(f, FoodType.Eggs, m_Eggs))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CheckFoodPreference(f, FoodType.Fish, m_Fish))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CheckFoodPreference(f, FoodType.GrainsAndHay, m_GrainsAndHay))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CheckFoodPreference(f, FoodType.Meat, m_Meat))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CheckFoodPreference(f, FoodType.FruitsAndVegies, m_FruitsAndVegies))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CheckFoodPreference(f, FoodType.Gold, m_Gold))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public virtual bool CheckFoodPreference(Item f) =>
|
||||
CheckFoodPreference(f, FoodType.Eggs, m_Eggs) ||
|
||||
CheckFoodPreference(f, FoodType.Fish, m_Fish) ||
|
||||
CheckFoodPreference(f, FoodType.GrainsAndHay, m_GrainsAndHay) ||
|
||||
CheckFoodPreference(f, FoodType.Meat, m_Meat) ||
|
||||
CheckFoodPreference(f, FoodType.FruitsAndVegies, m_FruitsAndVegies) ||
|
||||
CheckFoodPreference(f, FoodType.Gold, m_Gold);
|
||||
|
||||
public virtual bool CheckFoodPreference(Item fed, FoodType type, Type[] types)
|
||||
{
|
||||
|
|
@ -4396,9 +4342,8 @@ namespace Server.Mobiles
|
|||
}
|
||||
else if (Core.ML)
|
||||
{
|
||||
from.SendLocalizedMessage(
|
||||
1075268
|
||||
); // Your pet cannot form a bond with you until your animal taming ability has risen.
|
||||
// Your pet cannot form a bond with you until your animal taming ability has risen.
|
||||
from.SendLocalizedMessage(1075268);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4454,12 +4399,7 @@ namespace Server.Mobiles
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!Core.AOS && (skill == SkillName.Focus || skill == SkillName.Chivalry || skill == SkillName.Necromancy))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return Core.AOS || skill != SkillName.Focus && skill != SkillName.Chivalry && skill != SkillName.Necromancy;
|
||||
}
|
||||
|
||||
public virtual TeachResult CheckTeachSkills(
|
||||
|
|
@ -5033,8 +4973,8 @@ namespace Server.Mobiles
|
|||
return false;
|
||||
}
|
||||
|
||||
Cap(ref minLevel, 0, 5);
|
||||
Cap(ref maxLevel, 0, 5);
|
||||
minLevel = Math.Clamp(minLevel, 0, 5);
|
||||
maxLevel = Math.Clamp(maxLevel, 0, 5);
|
||||
|
||||
if (Core.AOS)
|
||||
{
|
||||
|
|
@ -5121,9 +5061,7 @@ namespace Server.Mobiles
|
|||
|
||||
if (min > max)
|
||||
{
|
||||
var hold = min;
|
||||
min = max;
|
||||
max = hold;
|
||||
(min, max) = (max, min);
|
||||
}
|
||||
|
||||
/* Example:
|
||||
|
|
@ -5204,8 +5142,8 @@ namespace Server.Mobiles
|
|||
return false;
|
||||
}
|
||||
|
||||
Cap(ref minLevel, 0, 5);
|
||||
Cap(ref maxLevel, 0, 5);
|
||||
minLevel = Math.Clamp(minLevel, 0, 5);
|
||||
maxLevel = Math.Clamp(maxLevel, 0, 5);
|
||||
|
||||
if (Core.AOS)
|
||||
{
|
||||
|
|
@ -5481,15 +5419,21 @@ namespace Server.Mobiles
|
|||
}
|
||||
|
||||
var eable = GetMobilesInRange(AuraRange);
|
||||
|
||||
var list = eable.Where(
|
||||
m =>
|
||||
m != this && CanBeHarmful(m, false) && (Core.AOS || InLOS(m)) &&
|
||||
(m is BaseCreature bc && (bc.Controlled || bc.Summoned || bc.Team != Team) || m.Player)
|
||||
);
|
||||
|
||||
foreach (var m in list)
|
||||
using var queue = PooledRefQueue<Mobile>.Create();
|
||||
foreach (var m in eable)
|
||||
{
|
||||
if (m != this && CanBeHarmful(m, false) && (Core.AOS || InLOS(m)) &&
|
||||
(m is BaseCreature bc && (bc.Controlled || bc.Summoned || bc.Team != Team) || m.Player))
|
||||
{
|
||||
queue.Enqueue(m);
|
||||
}
|
||||
}
|
||||
eable.Free();
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var m = queue.Dequeue();
|
||||
|
||||
AOS.Damage(
|
||||
m,
|
||||
this,
|
||||
|
|
@ -5503,8 +5447,6 @@ namespace Server.Mobiles
|
|||
);
|
||||
AuraEffect(m);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
public virtual void AuraEffect(Mobile m)
|
||||
|
|
@ -5599,10 +5541,8 @@ namespace Server.Mobiles
|
|||
|
||||
private DateTime m_NextHourlyCheck;
|
||||
|
||||
public LoyaltyTimer() : base(InternalDelay, InternalDelay)
|
||||
{
|
||||
public LoyaltyTimer() : base(InternalDelay, InternalDelay) =>
|
||||
m_NextHourlyCheck = Core.Now + TimeSpan.FromHours(1.0);
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
|
|
@ -5618,14 +5558,14 @@ namespace Server.Mobiles
|
|||
|
||||
m_NextHourlyCheck = Core.Now + TimeSpan.FromHours(1.0);
|
||||
|
||||
var toRelease = new List<BaseCreature>();
|
||||
using var toRelease = PooledRefQueue<BaseCreature>.Create();
|
||||
|
||||
// added array for wild creatures in house regions to be removed
|
||||
var toRemove = new List<BaseCreature>();
|
||||
using var toRemove = PooledRefQueue<Mobile>.Create();
|
||||
|
||||
foreach (var m in World.Mobiles.Values)
|
||||
{
|
||||
if (!(m is BaseCreature c))
|
||||
if (m is not BaseCreature c)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -5649,7 +5589,7 @@ namespace Server.Mobiles
|
|||
}
|
||||
else if (c.OwnerAbandonTime + c.BondingAbandonDelay <= Core.Now)
|
||||
{
|
||||
toRemove.Add(c);
|
||||
toRemove.Enqueue(c);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -5673,7 +5613,7 @@ namespace Server.Mobiles
|
|||
|
||||
if (c.Loyalty <= 0)
|
||||
{
|
||||
toRelease.Add(c);
|
||||
toRelease.Enqueue(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5686,7 +5626,7 @@ namespace Server.Mobiles
|
|||
|
||||
if (c.RemoveStep >= 20)
|
||||
{
|
||||
toRemove.Add(c);
|
||||
toRemove.Enqueue(c);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -5695,22 +5635,24 @@ namespace Server.Mobiles
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var c in toRelease)
|
||||
while (toRelease.Count > 0)
|
||||
{
|
||||
c.Say(1043255, c.Name); // ~1_NAME~ appears to have decided that is better off without a master!
|
||||
var c = toRelease.Dequeue();
|
||||
|
||||
c.Say(1043255, c.Name); // ~1_NAME~ appears to have decided that is better off without a master!
|
||||
c.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully Happy
|
||||
c.IsBonded = false;
|
||||
c.BondingBegin = DateTime.MinValue;
|
||||
c.OwnerAbandonTime = DateTime.MinValue;
|
||||
c.ControlTarget = null;
|
||||
c.AIObject
|
||||
.DoOrderRelease(); // this will prevent no release of creatures left alone with AI disabled (and consequent bug of Followers)
|
||||
// This will prevent no release of creatures left alone with AI disabled (and consequent bug of Followers)
|
||||
c.AIObject.DoOrderRelease();
|
||||
c.DropBackpack();
|
||||
}
|
||||
|
||||
foreach (var c in toRemove)
|
||||
while (toRemove.Count > 0)
|
||||
{
|
||||
c.Delete();
|
||||
toRemove.Dequeue().Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ namespace Server.Mobiles
|
|||
{
|
||||
return Utility.Random(6) switch
|
||||
{
|
||||
0 => 0,
|
||||
1 => Utility.RandomBlueHue(),
|
||||
2 => Utility.RandomGreenHue(),
|
||||
3 => Utility.RandomRedHue(),
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace Server.SkillHandlers
|
|||
m.SendLocalizedMessage(502789); // Tame which animal?
|
||||
}
|
||||
|
||||
return TimeSpan.FromHours(6.0);
|
||||
return TimeSpan.FromSeconds(30);
|
||||
}
|
||||
|
||||
public static bool CheckMastery(Mobile tamer, BaseCreature creature) =>
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ namespace Server.Spells
|
|||
|
||||
private static readonly int[] m_ManaTable = { 4, 6, 9, 11, 14, 20, 40, 50 };
|
||||
|
||||
public MagerySpell(Mobile caster, Item scroll, SpellInfo info)
|
||||
: base(caster, scroll, info)
|
||||
public MagerySpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -377,20 +377,19 @@ namespace Server.Spells
|
|||
return;
|
||||
}
|
||||
|
||||
if (!firstCircle && !Core.AOS && (this as MagerySpell)?.Circle == SpellCircle.First)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
State = SpellState.None;
|
||||
Caster.Spell = null;
|
||||
|
||||
if (State == SpellState.Casting)
|
||||
{
|
||||
if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
State = SpellState.None;
|
||||
Caster.Spell = null;
|
||||
|
||||
OnDisturb(type, true);
|
||||
|
||||
m_CastTimer?.Stop();
|
||||
|
||||
m_AnimTimer?.Stop();
|
||||
|
||||
if (Core.AOS && Caster.Player && type == DisturbType.Hurt)
|
||||
|
|
@ -402,14 +401,6 @@ namespace Server.Spells
|
|||
}
|
||||
else if (State == SpellState.Sequencing)
|
||||
{
|
||||
if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
State = SpellState.None;
|
||||
Caster.Spell = null;
|
||||
|
||||
OnDisturb(type, false);
|
||||
|
||||
Target.Cancel(Caster);
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@ namespace Server
|
|||
{
|
||||
private readonly Mobile m_Mobile;
|
||||
|
||||
public InternalTimer(Mobile m)
|
||||
: base(TimeSpan.FromMinutes(1.0))
|
||||
public InternalTimer(Mobile m) : base(TimeSpan.FromMinutes(1.0))
|
||||
{
|
||||
m_Mobile = m;
|
||||
}
|
||||
|
|
@ -1128,8 +1127,7 @@ namespace Server.Spells
|
|||
private readonly Mobile m_Target;
|
||||
private int m_Damage;
|
||||
|
||||
public SpellDamageTimer(Spell s, Mobile target, Mobile from, int damage, TimeSpan delay)
|
||||
: base(delay)
|
||||
public SpellDamageTimer(Spell s, Mobile target, Mobile from, int damage, TimeSpan delay) : base(delay)
|
||||
{
|
||||
m_Target = target;
|
||||
m_From = from;
|
||||
|
|
@ -1170,8 +1168,7 @@ namespace Server.Spells
|
|||
public SpellDamageTimerAOS(
|
||||
Spell s, TimeSpan delay, Mobile target, Mobile from, int damage, int phys, int fire, int cold,
|
||||
int pois, int nrgy, int chaos, DFAlgorithm dfa
|
||||
)
|
||||
: base(delay)
|
||||
) : base(delay)
|
||||
{
|
||||
m_Target = target;
|
||||
m_From = from;
|
||||
|
|
@ -1229,7 +1226,7 @@ namespace Server.Spells
|
|||
|
||||
public static class TransformationSpellHelper
|
||||
{
|
||||
private static readonly Dictionary<Mobile, TransformContext> m_Table = new();
|
||||
private static readonly Dictionary<Mobile, TransformContext> _table = new();
|
||||
|
||||
public static bool CheckCast(Mobile caster, Spell spell)
|
||||
{
|
||||
|
|
@ -1363,7 +1360,7 @@ namespace Server.Spells
|
|||
|
||||
public static void AddContext(Mobile m, TransformContext context)
|
||||
{
|
||||
m_Table[m] = context;
|
||||
_table[m] = context;
|
||||
}
|
||||
|
||||
public static void RemoveContext(Mobile m, bool resetGraphics)
|
||||
|
|
@ -1378,7 +1375,7 @@ namespace Server.Spells
|
|||
|
||||
public static void RemoveContext(Mobile m, TransformContext context, bool resetGraphics)
|
||||
{
|
||||
if (!m_Table.Remove(m))
|
||||
if (!_table.Remove(m))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -1402,7 +1399,7 @@ namespace Server.Spells
|
|||
|
||||
public static TransformContext GetContext(Mobile m)
|
||||
{
|
||||
m_Table.TryGetValue(m, out var context);
|
||||
_table.TryGetValue(m, out var context);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,17 +5,17 @@ namespace Server.Spells.Bushido
|
|||
{
|
||||
public class Confidence : SamuraiSpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Confidence",
|
||||
null,
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> m_Table = new();
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> _table = new();
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> m_RegenTable = new();
|
||||
|
||||
public Confidence(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
|
||||
public Confidence(Mobile caster, Item scroll) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ namespace Server.Spells.Bushido
|
|||
FinishSequence();
|
||||
}
|
||||
|
||||
public static bool IsConfident(Mobile m) => m_Table.ContainsKey(m);
|
||||
public static bool IsConfident(Mobile m) => _table.ContainsKey(m);
|
||||
|
||||
public static void BeginConfidence(Mobile m)
|
||||
{
|
||||
|
|
@ -64,12 +64,12 @@ namespace Server.Spells.Bushido
|
|||
out var timerToken
|
||||
);
|
||||
|
||||
m_Table[m] = timerToken;
|
||||
_table[m] = timerToken;
|
||||
}
|
||||
|
||||
private static bool StopConfidenceTimer(Mobile m)
|
||||
{
|
||||
if (m_Table.Remove(m, out var timerToken))
|
||||
if (_table.Remove(m, out var timerToken))
|
||||
{
|
||||
timerToken.Cancel();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@ namespace Server.Spells.Bushido
|
|||
{
|
||||
public class CounterAttack : SamuraiSpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"CounterAttack",
|
||||
null,
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> m_Table = new();
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> _table = new();
|
||||
|
||||
public CounterAttack(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
|
||||
public CounterAttack(Mobile caster, Item scroll) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -71,11 +71,11 @@ namespace Server.Spells.Bushido
|
|||
FinishSequence();
|
||||
}
|
||||
|
||||
public static bool IsCountering(Mobile m) => m_Table.ContainsKey(m);
|
||||
public static bool IsCountering(Mobile m) => _table.ContainsKey(m);
|
||||
|
||||
private static bool StopCounterTimer(Mobile m)
|
||||
{
|
||||
if (m_Table.Remove(m, out var timerToken))
|
||||
if (_table.Remove(m, out var timerToken))
|
||||
{
|
||||
timerToken.Cancel();
|
||||
return true;
|
||||
|
|
@ -97,7 +97,7 @@ namespace Server.Spells.Bushido
|
|||
out var timerToken
|
||||
);
|
||||
|
||||
m_Table[m] = timerToken;
|
||||
_table[m] = timerToken;
|
||||
}
|
||||
|
||||
public static void StopCountering(Mobile m)
|
||||
|
|
|
|||
|
|
@ -6,17 +6,16 @@ namespace Server.Spells.Bushido
|
|||
{
|
||||
public class Evasion : SamuraiSpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Evasion",
|
||||
null,
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> m_Table = new();
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> _table = new();
|
||||
|
||||
public Evasion(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
public Evasion(Mobile caster, Item scroll) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -139,7 +138,7 @@ namespace Server.Spells.Bushido
|
|||
FinishSequence();
|
||||
}
|
||||
|
||||
public static bool IsEvading(Mobile m) => m_Table.ContainsKey(m);
|
||||
public static bool IsEvading(Mobile m) => _table.ContainsKey(m);
|
||||
|
||||
public static TimeSpan GetEvadeDuration(Mobile m)
|
||||
{
|
||||
|
|
@ -217,12 +216,12 @@ namespace Server.Spells.Bushido
|
|||
out var timerToken
|
||||
);
|
||||
|
||||
m_Table[m] = timerToken;
|
||||
_table[m] = timerToken;
|
||||
}
|
||||
|
||||
private static bool StopEvasionTimer(Mobile m)
|
||||
{
|
||||
if (m_Table.Remove(m, out var timer))
|
||||
if (_table.Remove(m, out var timer))
|
||||
{
|
||||
timer.Cancel();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Server.Spells.Bushido
|
|||
{
|
||||
public class HonorableExecution : SamuraiMove
|
||||
{
|
||||
private static readonly Dictionary<Mobile, HonorableExecutionTimer> m_Table = new();
|
||||
private static readonly Dictionary<Mobile, HonorableExecutionTimer> _table = new();
|
||||
|
||||
public override int BaseMana => 0;
|
||||
public override double RequiredSkill => 25.0;
|
||||
|
|
@ -63,20 +63,20 @@ namespace Server.Spells.Bushido
|
|||
timer = new HonorableExecutionTimer(attacker, mods);
|
||||
}
|
||||
|
||||
m_Table[attacker] = timer;
|
||||
_table[attacker] = timer;
|
||||
timer.Start();
|
||||
|
||||
attacker.Delta(MobileDelta.WeaponDamage);
|
||||
CheckGain(attacker);
|
||||
}
|
||||
|
||||
public static int GetSwingBonus(Mobile target) => m_Table.TryGetValue(target, out var info) ? info.m_SwingBonus : 0;
|
||||
public static int GetSwingBonus(Mobile target) => _table.TryGetValue(target, out var info) ? info.m_SwingBonus : 0;
|
||||
|
||||
public static bool IsUnderPenalty(Mobile target) => m_Table.TryGetValue(target, out var info) && info.m_Penalty;
|
||||
public static bool IsUnderPenalty(Mobile target) => _table.TryGetValue(target, out var info) && info.m_Penalty;
|
||||
|
||||
public static void RemovePenalty(Mobile target)
|
||||
{
|
||||
if (m_Table.Remove(target, out var timer))
|
||||
if (_table.Remove(target, out var timer))
|
||||
{
|
||||
timer.Clear();
|
||||
}
|
||||
|
|
@ -98,8 +98,8 @@ namespace Server.Spells.Bushido
|
|||
}
|
||||
|
||||
public HonorableExecutionTimer(
|
||||
TimeSpan duration, Mobile from, int swingBonus, List<object> mods = null, bool penalty = false)
|
||||
: base(duration)
|
||||
TimeSpan duration, Mobile from, int swingBonus, List<object> mods = null, bool penalty = false
|
||||
) : base(duration)
|
||||
{
|
||||
m_Mobile = from;
|
||||
m_SwingBonus = swingBonus;
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@ namespace Server.Spells.Chivalry
|
|||
{
|
||||
public class CleanseByFireSpell : PaladinSpell, ISpellTargetingMobile
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Cleanse By Fire",
|
||||
"Expor Flamus",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public CleanseByFireSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public CleanseByFireSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ namespace Server.Spells.Chivalry
|
|||
{
|
||||
public class CloseWoundsSpell : PaladinSpell, ISpellTargetingMobile
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Close Wounds",
|
||||
"Obsu Vulni",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public CloseWoundsSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public CloseWoundsSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@ namespace Server.Spells.Chivalry
|
|||
{
|
||||
public class ConsecrateWeaponSpell : PaladinSpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Consecrate Weapon",
|
||||
"Consecrus Arma",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
private static readonly Dictionary<BaseWeapon, ExpireTimer> m_Table = new();
|
||||
private static readonly Dictionary<BaseWeapon, ExpireTimer> _table = new();
|
||||
|
||||
public ConsecrateWeaponSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public ConsecrateWeaponSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -86,12 +86,12 @@ namespace Server.Spells.Chivalry
|
|||
|
||||
var duration = TimeSpan.FromSeconds(seconds);
|
||||
|
||||
m_Table.TryGetValue(weapon, out var timer);
|
||||
_table.TryGetValue(weapon, out var timer);
|
||||
timer?.Stop();
|
||||
|
||||
weapon.Consecrated = true;
|
||||
|
||||
m_Table[weapon] = timer = new ExpireTimer(weapon, duration);
|
||||
_table[weapon] = timer = new ExpireTimer(weapon, duration);
|
||||
|
||||
timer.Start();
|
||||
}
|
||||
|
|
@ -112,7 +112,7 @@ namespace Server.Spells.Chivalry
|
|||
{
|
||||
m_Weapon.Consecrated = false;
|
||||
Effects.PlaySound(m_Weapon.GetWorldLocation(), m_Weapon.Map, 0x1F8);
|
||||
m_Table.Remove(m_Weapon);
|
||||
_table.Remove(m_Weapon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ namespace Server.Spells.Chivalry
|
|||
{
|
||||
public class DispelEvilSpell : PaladinSpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Dispel Evil",
|
||||
"Dispiro Malas",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public DispelEvilSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public DispelEvilSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@ namespace Server.Spells.Chivalry
|
|||
{
|
||||
public class DivineFurySpell : PaladinSpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Divine Fury",
|
||||
"Divinum Furis",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> m_Table = new();
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> _table = new();
|
||||
|
||||
public DivineFurySpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public DivineFurySpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ namespace Server.Spells.Chivalry
|
|||
out var timerToken
|
||||
);
|
||||
|
||||
m_Table[Caster] = timerToken;
|
||||
_table[Caster] = timerToken;
|
||||
|
||||
Caster.Delta(MobileDelta.WeaponDamage);
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ namespace Server.Spells.Chivalry
|
|||
|
||||
private static void RemoveTimer(Mobile m)
|
||||
{
|
||||
if (m_Table.Remove(m, out var timerToken))
|
||||
if (_table.Remove(m, out var timerToken))
|
||||
{
|
||||
timerToken.Cancel();
|
||||
}
|
||||
|
|
@ -74,6 +74,6 @@ namespace Server.Spells.Chivalry
|
|||
m.PlaySound(0xF8);
|
||||
}
|
||||
|
||||
public static bool UnderEffect(Mobile m) => m_Table.ContainsKey(m);
|
||||
public static bool UnderEffect(Mobile m) => _table.ContainsKey(m);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@ namespace Server.Spells.Chivalry
|
|||
{
|
||||
public class EnemyOfOneSpell : PaladinSpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Enemy of One",
|
||||
"Forul Solum",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> m_Table = new();
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> _table = new();
|
||||
|
||||
public EnemyOfOneSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public EnemyOfOneSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ namespace Server.Spells.Chivalry
|
|||
|
||||
Timer.StartTimer(TimeSpan.FromMinutes(delay), () => Expire_Callback(Caster), out var timerToken);
|
||||
|
||||
m_Table[Caster] = timerToken;
|
||||
_table[Caster] = timerToken;
|
||||
|
||||
if (Caster is PlayerMobile mobile)
|
||||
{
|
||||
|
|
@ -61,7 +61,7 @@ namespace Server.Spells.Chivalry
|
|||
|
||||
private static void RemoveTimer(Mobile m)
|
||||
{
|
||||
if (m_Table.Remove(m, out var timerToken))
|
||||
if (_table.Remove(m, out var timerToken))
|
||||
{
|
||||
timerToken.Cancel();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ namespace Server.Spells.Chivalry
|
|||
{
|
||||
public class HolyLightSpell : PaladinSpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Holy Light",
|
||||
"Augus Luminos",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public HolyLightSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public HolyLightSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ namespace Server.Spells.Chivalry
|
|||
{
|
||||
public class NobleSacrificeSpell : PaladinSpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Noble Sacrifice",
|
||||
"Dium Prostra",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public NobleSacrificeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public NobleSacrificeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ namespace Server.Spells.Chivalry
|
|||
{
|
||||
public class RemoveCurseSpell : PaladinSpell, ISpellTargetingMobile
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Remove Curse",
|
||||
"Extermo Vomica",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public RemoveCurseSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public RemoveCurseSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Server.Spells.Chivalry
|
|||
{
|
||||
public class SacredJourneySpell : PaladinSpell, IRecallSpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Sacred Journey",
|
||||
"Sanctum Viatas",
|
||||
-1,
|
||||
|
|
@ -21,7 +21,7 @@ namespace Server.Spells.Chivalry
|
|||
|
||||
public SacredJourneySpell(
|
||||
Mobile caster, RunebookEntry entry = null, Runebook book = null, Item scroll = null
|
||||
) : base(caster, scroll, m_Info)
|
||||
) : base(caster, scroll, _info)
|
||||
{
|
||||
m_Entry = entry;
|
||||
m_Book = book;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Server.Spells.Eighth
|
|||
{
|
||||
public class AirElementalSpell : MagerySpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Air Elemental",
|
||||
"Kal Vas Xen Hur",
|
||||
269,
|
||||
|
|
@ -16,7 +16,7 @@ namespace Server.Spells.Eighth
|
|||
Reagent.SpidersSilk
|
||||
);
|
||||
|
||||
public AirElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public AirElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Server.Spells.Eighth
|
|||
{
|
||||
public class EarthElementalSpell : MagerySpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Earth Elemental",
|
||||
"Kal Vas Xen Ylem",
|
||||
269,
|
||||
|
|
@ -16,7 +16,7 @@ namespace Server.Spells.Eighth
|
|||
Reagent.SpidersSilk
|
||||
);
|
||||
|
||||
public EarthElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public EarthElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Server.Spells.Eighth
|
|||
{
|
||||
public class EarthquakeSpell : MagerySpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Earthquake",
|
||||
"In Vas Por",
|
||||
233,
|
||||
|
|
@ -17,7 +17,7 @@ namespace Server.Spells.Eighth
|
|||
Reagent.SulfurousAsh
|
||||
);
|
||||
|
||||
public EarthquakeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public EarthquakeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Server.Spells.Eighth
|
|||
{
|
||||
public class EnergyVortexSpell : MagerySpell, ISpellTargetingPoint3D
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Energy Vortex",
|
||||
"Vas Corp Por",
|
||||
260,
|
||||
|
|
@ -17,7 +17,7 @@ namespace Server.Spells.Eighth
|
|||
Reagent.Nightshade
|
||||
);
|
||||
|
||||
public EnergyVortexSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public EnergyVortexSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ namespace Server.Spells.Eighth
|
|||
|
||||
public override void OnCast()
|
||||
{
|
||||
Caster.Target = new SpellTargetPoint3D(this);
|
||||
Caster.Target = new SpellTargetPoint3D(this, retryOnLOS: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Server.Spells.Eighth
|
|||
{
|
||||
public class FireElementalSpell : MagerySpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Fire Elemental",
|
||||
"Kal Vas Xen Flam",
|
||||
269,
|
||||
|
|
@ -17,7 +17,7 @@ namespace Server.Spells.Eighth
|
|||
Reagent.SulfurousAsh
|
||||
);
|
||||
|
||||
public FireElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public FireElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ namespace Server.Spells.Eighth
|
|||
{
|
||||
public class ResurrectionSpell : MagerySpell, ISpellTargetingMobile
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Resurrection",
|
||||
"An Corp",
|
||||
245,
|
||||
|
|
@ -16,7 +16,7 @@ namespace Server.Spells.Eighth
|
|||
Reagent.Ginseng
|
||||
);
|
||||
|
||||
public ResurrectionSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public ResurrectionSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -24,16 +24,7 @@ namespace Server.Spells.Eighth
|
|||
|
||||
public void Target(Mobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Caster.CanSee(m))
|
||||
{
|
||||
Caster.SendLocalizedMessage(500237); // Target can not be seen.
|
||||
}
|
||||
else if (m == Caster)
|
||||
if (m == Caster)
|
||||
{
|
||||
Caster.SendLocalizedMessage(501039); // Thou can not resurrect thyself.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Server.Spells.Eighth
|
|||
{
|
||||
public class SummonDaemonSpell : MagerySpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Summon Daemon",
|
||||
"Kal Vas Xen Corp",
|
||||
269,
|
||||
|
|
@ -17,7 +17,7 @@ namespace Server.Spells.Eighth
|
|||
Reagent.SulfurousAsh
|
||||
);
|
||||
|
||||
public SummonDaemonSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public SummonDaemonSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Server.Spells.Eighth
|
|||
{
|
||||
public class WaterElementalSpell : MagerySpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Water Elemental",
|
||||
"Kal Vas Xen An Flam",
|
||||
269,
|
||||
|
|
@ -16,7 +16,7 @@ namespace Server.Spells.Eighth
|
|||
Reagent.SpidersSilk
|
||||
);
|
||||
|
||||
public WaterElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public WaterElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Server.Spells.Fifth
|
|||
{
|
||||
public class BladeSpiritsSpell : MagerySpell, ISpellTargetingPoint3D
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Blade Spirits",
|
||||
"In Jux Hur Ylem",
|
||||
266,
|
||||
|
|
@ -16,7 +16,7 @@ namespace Server.Spells.Fifth
|
|||
Reagent.Nightshade
|
||||
);
|
||||
|
||||
public BladeSpiritsSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public BladeSpiritsSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ namespace Server.Spells.Fifth
|
|||
|
||||
public override void OnCast()
|
||||
{
|
||||
Caster.Target = new SpellTargetPoint3D(this);
|
||||
Caster.Target = new SpellTargetPoint3D(this, retryOnLOS: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ namespace Server.Spells.Fifth
|
|||
{
|
||||
public class DispelFieldSpell : MagerySpell, ISpellTargetingItem
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Dispel Field",
|
||||
"An Grav",
|
||||
206,
|
||||
|
|
@ -17,7 +17,7 @@ namespace Server.Spells.Fifth
|
|||
Reagent.Garlic
|
||||
);
|
||||
|
||||
public DispelFieldSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public DispelFieldSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -25,15 +25,7 @@ namespace Server.Spells.Fifth
|
|||
|
||||
public void Target(Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1005049); // That cannot be dispelled.
|
||||
}
|
||||
else if (!Caster.CanSee(item))
|
||||
{
|
||||
Caster.SendLocalizedMessage(500237); // Target can not be seen.
|
||||
}
|
||||
else if (!item.GetType().IsDefined(typeof(DispellableFieldAttribute), false))
|
||||
if (!item.GetType().IsDefined(typeof(DispellableFieldAttribute), false))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1005049); // That cannot be dispelled.
|
||||
}
|
||||
|
|
@ -62,7 +54,7 @@ namespace Server.Spells.Fifth
|
|||
|
||||
public override void OnCast()
|
||||
{
|
||||
Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12);
|
||||
Caster.Target = new SpellTargetItem(this, range: Core.ML ? 10 : 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace Server.Spells.Fifth
|
|||
{
|
||||
public class IncognitoSpell : MagerySpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Incognito",
|
||||
"Kal In Ex",
|
||||
206,
|
||||
|
|
@ -19,9 +19,9 @@ namespace Server.Spells.Fifth
|
|||
Reagent.Nightshade
|
||||
);
|
||||
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> m_Table = new();
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> _table = new();
|
||||
|
||||
public IncognitoSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public IncognitoSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ namespace Server.Spells.Fifth
|
|||
|
||||
var length = TimeSpan.FromSeconds(timeVal);
|
||||
Timer.StartTimer(length, () => EndIncognito(Caster), out var timerToken);
|
||||
m_Table[Caster] = timerToken;
|
||||
_table[Caster] = timerToken;
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Incognito, 1075819, length, Caster));
|
||||
}
|
||||
|
|
@ -127,7 +127,7 @@ namespace Server.Spells.Fifth
|
|||
|
||||
public static void StopTimer(Mobile m)
|
||||
{
|
||||
if (m_Table.Remove(m, out var timerToken))
|
||||
if (_table.Remove(m, out var timerToken))
|
||||
{
|
||||
timerToken.Cancel();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ namespace Server.Spells.Fifth
|
|||
{
|
||||
public class MagicReflectSpell : MagerySpell
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Magic Reflection",
|
||||
"In Jux Sanct",
|
||||
242,
|
||||
|
|
@ -14,9 +14,9 @@ namespace Server.Spells.Fifth
|
|||
Reagent.SpidersSilk
|
||||
);
|
||||
|
||||
private static readonly Dictionary<Mobile, ResistanceMod[]> m_Table = new();
|
||||
private static readonly Dictionary<Mobile, ResistanceMod[]> _table = new();
|
||||
|
||||
public MagicReflectSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public MagicReflectSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ namespace Server.Spells.Fifth
|
|||
{
|
||||
var targ = Caster;
|
||||
|
||||
if (m_Table.Remove(targ, out var mods))
|
||||
if (_table.Remove(targ, out var mods))
|
||||
{
|
||||
targ.PlaySound(0x1ED);
|
||||
targ.FixedParticles(0x375A, 10, 15, 5037, EffectLayer.Waist);
|
||||
|
|
@ -88,7 +88,7 @@ namespace Server.Spells.Fifth
|
|||
new ResistanceMod(ResistanceType.Energy, otherMod)
|
||||
};
|
||||
|
||||
m_Table[targ] = mods;
|
||||
_table[targ] = mods;
|
||||
|
||||
for (var i = 0; i < mods.Length; ++i)
|
||||
{
|
||||
|
|
@ -137,7 +137,7 @@ namespace Server.Spells.Fifth
|
|||
|
||||
public static void EndReflect(Mobile m)
|
||||
{
|
||||
if (!m_Table.Remove(m, out var mods))
|
||||
if (!_table.Remove(m, out var mods))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Server.Spells.Fifth
|
|||
{
|
||||
public class MindBlastSpell : MagerySpell, ISpellTargetingMobile
|
||||
{
|
||||
private static readonly SpellInfo m_Info = new(
|
||||
private static readonly SpellInfo _info = new(
|
||||
"Mind Blast",
|
||||
"Por Corp Wis",
|
||||
218,
|
||||
|
|
@ -16,11 +16,11 @@ namespace Server.Spells.Fifth
|
|||
Reagent.SulfurousAsh
|
||||
);
|
||||
|
||||
public MindBlastSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info)
|
||||
public MindBlastSpell(Mobile caster, Item scroll = null) : base(caster, scroll, _info)
|
||||
{
|
||||
if (Core.AOS)
|
||||
{
|
||||
m_Info.LeftHandEffect = m_Info.RightHandEffect = 9002;
|
||||
_info.LeftHandEffect = _info.RightHandEffect = 9002;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -30,16 +30,7 @@ namespace Server.Spells.Fifth
|
|||
|
||||
public void Target(Mobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Caster.CanSee(m))
|
||||
{
|
||||
Caster.SendLocalizedMessage(500237); // Target can not be seen.
|
||||
}
|
||||
else if (Core.AOS)
|
||||
if (Core.AOS)
|
||||
{
|
||||
if (Caster.CanBeHarmful(m) && CheckSequence())
|
||||
{
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue