Merge branch 'main' into webSupport

This commit is contained in:
Kamron Batman 2021-11-21 18:18:51 -08:00 committed by GitHub
commit a3458a2950
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
203 changed files with 1431 additions and 2096 deletions

View file

@ -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

View file

@ -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" />

View file

@ -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

View file

@ -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>

View file

@ -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];

View file

@ -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;
}
}
}

View file

@ -1,9 +0,0 @@
using System;
namespace Server
{
public class FeatureFlag<T> where T : Item
{
public Type Type { get; set; }
}
}

View file

@ -6,7 +6,7 @@ using Serilog.Core;
namespace Benchmarks
{
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
[SimpleJob(RuntimeMoniker.Net60)]
public class BenchmarkConsoleLogging
{
private const string text = "Sample message";

View file

@ -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);

View file

@ -7,7 +7,7 @@ using Server.Network;
namespace Benchmarks
{
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
[SimpleJob(RuntimeMoniker.Net60)]
public class BenchmarkPacketBroadcast
{
public static int SendUnicodeMessage(

View 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));
}
}
}

View file

@ -5,7 +5,7 @@ using Server.Text;
namespace Benchmarks.BenchmarkText
{
[MemoryDiagnoser]
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
[SimpleJob(RuntimeMoniker.Net60)]
public class BenchmarkTextEncoding
{
private const string text =

View file

@ -7,7 +7,7 @@ using Server.Buffers;
namespace Benchmarks.BenchmarkUtilities
{
[MemoryDiagnoser]
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
[SimpleJob(RuntimeMoniker.Net60)]
public class BenchmarkStringHelpers
{
private readonly string[] names =

View file

@ -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>();
}
}
}

View file

@ -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}}}");

View file

@ -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

View file

@ -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
};

View file

@ -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>

View file

@ -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
};

View file

@ -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>

View file

@ -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" />

View file

@ -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);
}

View file

@ -34,7 +34,7 @@ namespace Server.Json
{
WriteIndented = true,
AllowTrailingCommas = true,
IgnoreNullValues = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
ReadCommentHandling = JsonCommentHandling.Skip,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};

View file

@ -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);
}

View file

@ -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>

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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.");

View file

@ -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" />

View file

@ -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"),

View file

@ -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) =>

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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");

View file

@ -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>();
}
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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;

View file

@ -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)
{

View file

@ -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 );

View file

@ -0,0 +1,11 @@
{
"version": 0,
"type": "Server.Items.AnkhNorth.InternalItem",
"properties": [
{
"name": "Item",
"type": "Server.Items.AnkhNorth",
"rule": "SerializableInterfaceMigrationRule"
}
]
}

View file

@ -0,0 +1,11 @@
{
"version": 0,
"type": "Server.Items.AnkhNorth",
"properties": [
{
"name": "Item",
"type": "Server.Items.AnkhNorth.InternalItem",
"rule": "SerializableInterfaceMigrationRule"
}
]
}

View file

@ -0,0 +1,11 @@
{
"version": 0,
"type": "Server.Items.AnkhWest.InternalItem",
"properties": [
{
"name": "Item",
"type": "Server.Items.AnkhWest",
"rule": "SerializableInterfaceMigrationRule"
}
]
}

View file

@ -0,0 +1,11 @@
{
"version": 0,
"type": "Server.Items.AnkhWest",
"properties": [
{
"name": "Item",
"type": "Server.Items.AnkhWest.InternalItem",
"rule": "SerializableInterfaceMigrationRule"
}
]
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.BaseWall"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.DarkWoodWall"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.ElegantLowTable"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.LargeTable"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.Nightstand"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.PlainLowTable"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.ThickGrayStoneWall"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.ThinBrickWall"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.ThinStoneWall"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.WhiteStoneWall"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.WritingTable"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.YewWoodTable"
}

View file

@ -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");

View file

@ -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
{

View file

@ -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();
}
}
}

View file

@ -25,7 +25,6 @@ namespace Server.Mobiles
{
return Utility.Random(6) switch
{
0 => 0,
1 => Utility.RandomBlueHue(),
2 => Utility.RandomGreenHue(),
3 => Utility.RandomRedHue(),

View file

@ -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) =>

View file

@ -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)
{
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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;

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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)
{
}

View file

@ -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)
{
}

View file

@ -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);
}
}
}

View file

@ -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)
{
}

View file

@ -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);
}
}

View file

@ -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();
}

View file

@ -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)
{
}

View file

@ -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)
{
}

View file

@ -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)
{
}

View file

@ -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;

View file

@ -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)
{
}

View file

@ -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)
{
}

View file

@ -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)
{
}

View file

@ -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);
}
}
}

View file

@ -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)
{
}

View file

@ -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.
}

View file

@ -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)
{
}

View file

@ -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)
{
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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();
}

View file

@ -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;
}

View file

@ -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