diff --git a/Directory.Build.props b/Directory.Build.props index 6155f9b1a..0ac231599 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -58,7 +58,7 @@ - 3.4.231 + 3.4.240 all diff --git a/Distribution/Data/Professions/AOS/prof.txt b/Distribution/Data/Professions/AOS/prof.txt new file mode 100644 index 000000000..50dc7dec1 --- /dev/null +++ b/Distribution/Data/Professions/AOS/prof.txt @@ -0,0 +1,85 @@ +Begin + Name Paladin + TrueName "Paladin" + NameId 1061177 + DescId 1061227 + Desc 5 + TopLevel true + Gump 5587 + Type Profession + Skill Chivalry 50 + Skill Tactics 50 + Skill Wrestling 0 + Stat Str 30 + Stat Dex 25 + Stat Int 25 +End + +Begin + Name Necromancer + TrueName "Necromancer" + NameId 1061178 + DescId 1061228 + Desc 4 + TopLevel true + Gump 5557 + Type Profession + Skill Necromancy 50 + Skill Swordsmanship 30 + Skill Wrestling 0 + Skill Tactics 20 + Stat Str 25 + Stat Dex 20 + Stat Int 45 +End + +Begin + Name Warrior + TrueName "Warrior" + NameId 1061180 + DescId 1061230 + Desc 1 + TopLevel true + Gump 5577 + Type Profession + Skill Tactics 50 + Skill Healing 45 + Skill Swordsmanship 5 + Stat Str 35 + Stat Dex 35 + Stat Int 10 +End + +Begin + Name Mage + TrueName "Mage" + NameId 1061179 + DescId 1061229 + Desc 2 + TopLevel true + Gump 5569 + Type Profession + Skill Magery 50 + Skill Meditation 50 + Skill Wrestling 0 + Stat Str 25 + Stat Dex 10 + Stat Int 45 +End + +Begin + Name Blacksmith + TrueName "Blacksmith" + NameId 1061181 + DescId 1061231 + Desc 3 + TopLevel true + Gump 5555 + Type Profession + Skill Blacksmith 50 + Skill Tinkering 45 + Skill Mining 5 + Stat Str 60 + Stat Dex 10 + Stat Int 10 +End \ No newline at end of file diff --git a/Distribution/Data/Professions/None/prof.txt b/Distribution/Data/Professions/None/prof.txt new file mode 100644 index 000000000..2225b8b16 --- /dev/null +++ b/Distribution/Data/Professions/None/prof.txt @@ -0,0 +1,50 @@ +Begin + Name Warrior + TrueName "Warrior" + NameId 1061180 + DescId 1061230 + Desc 1 + TopLevel true + Gump 5577 + Type Profession + Skill Tactics 50 + Skill Healing 45 + Skill Swordsmanship 5 + Stat Str 35 + Stat Dex 35 + Stat Int 10 +End + +Begin + Name Mage + TrueName "Mage" + NameId 1061179 + DescId 1061229 + Desc 2 + TopLevel true + Gump 5569 + Type Profession + Skill Magery 50 + Skill Meditation 50 + Skill Wrestling 0 + Stat Str 25 + Stat Dex 10 + Stat Int 45 +End + +Begin + Name Blacksmith + TrueName "Blacksmith" + NameId 1061181 + DescId 1061231 + Desc 3 + TopLevel true + Gump 5555 + Type Profession + Skill Blacksmith 50 + Skill Tinkering 45 + Skill Mining 5 + Stat Str 60 + Stat Dex 10 + Stat Int 10 +End diff --git a/Distribution/Data/Professions/SA/Prof.txt b/Distribution/Data/Professions/SA/Prof.txt new file mode 100644 index 000000000..d73afe23f --- /dev/null +++ b/Distribution/Data/Professions/SA/Prof.txt @@ -0,0 +1,125 @@ +Begin + Name Samurai + TrueName "Samurai" + NameId 1062948 + DescId 1062950 + Desc 6 + TopLevel true + Gump 5591 + Type Profession + Skill Bushido 30 + Skill Swordsmanship 30 + Skill Focus 30 + Skill Parrying 30 + Stat Str 40 + Stat Dex 30 + Stat Int 20 +End + +Begin + Name Ninja + TrueName "Ninja" + NameId 1062949 + DescId 1062951 + Desc 7 + TopLevel true + Gump 5589 + Type Profession + Skill Ninjitsu 30 + Skill Hiding 30 + Skill Fencing 30 + Skill Stealth 30 + Stat Str 40 + Stat Dex 30 + Stat Int 20 +End + +Begin + Name Paladin + TrueName "Paladin" + NameId 1061177 + DescId 1061227 + Desc 5 + TopLevel true + Gump 5587 + Type Profession + Skill Chivalry 30 + Skill Tactics 30 + Skill Focus 30 + Skill Swordsmanship 30 + Stat Str 45 + Stat Dex 20 + Stat Int 25 +End + +Begin + Name Necromancer + TrueName "Necromancer" + NameId 1061178 + DescId 1061228 + Desc 4 + TopLevel true + Gump 5557 + Type Profession + Skill Necromancy 30 + Skill Spirit Speak 30 + Skill Swordsmanship 30 + Skill Meditation 30 + Stat Str 25 + Stat Dex 20 + Stat Int 45 +End + +Begin + Name Warrior + TrueName "Warrior" + NameId 1061180 + DescId 1061230 + Desc 1 + TopLevel true + Gump 5577 + Type Profession + Skill Tactics 30 + Skill Healing 30 + Skill Swordsmanship 30 + Skill Anatomy 30 + Stat Str 45 + Stat Dex 35 + Stat Int 10 +End + +Begin + Name Mage + TrueName "Mage" + NameId 1061179 + DescId 1061229 + Desc 2 + TopLevel true + Gump 5569 + Type Profession + Skill Magery 30 + Skill Meditation 30 + Skill Evaluate Intelligence 30 + Skill Wrestling 30 + Stat Str 25 + Stat Dex 20 + Stat Int 45 +End + +Begin + Name Blacksmith + TrueName "Blacksmith" + NameId 1061181 + DescId 1061231 + Desc 3 + TopLevel true + Gump 5555 + Type Profession + Skill Blacksmith 30 + Skill Tinkering 30 + Skill Mining 30 + Skill Tailoring 30 + Stat Str 60 + Stat Dex 15 + Stat Int 15 +End \ No newline at end of file diff --git a/Distribution/Data/Professions/SE/Prof.txt b/Distribution/Data/Professions/SE/Prof.txt new file mode 100644 index 000000000..dc01538c0 --- /dev/null +++ b/Distribution/Data/Professions/SE/Prof.txt @@ -0,0 +1,118 @@ +Begin + Name Samurai + TrueName "Samurai" + NameId 1062948 + DescId 1062950 + Desc 6 + TopLevel true + Gump 5591 + Type Profession + Skill Bushido 50 + Skill Swordsmanship 50 + Skill Wrestling 0 + Stat Str 40 + Stat Dex 30 + Stat Int 10 +End + +Begin + Name Ninja + TrueName "Ninja" + NameId 1062949 + DescId 1062951 + Desc 7 + TopLevel true + Gump 5589 + Type Profession + Skill Ninjitsu 50 + Skill Hiding 50 + Skill Wrestling 0 + Stat Str 40 + Stat Dex 30 + Stat Int 10 +End + +Begin + Name Paladin + TrueName "Paladin" + NameId 1061177 + DescId 1061227 + Desc 5 + TopLevel true + Gump 5587 + Type Profession + Skill Chivalry 50 + Skill Tactics 50 + Skill Wrestling 0 + Stat Str 45 + Stat Dex 20 + Stat Int 15 +End + +Begin + Name Necromancer + TrueName "Necromancer" + NameId 1061178 + DescId 1061228 + Desc 4 + TopLevel true + Gump 5557 + Type Profession + Skill Necromancy 50 + Skill Swordsmanship 30 + Skill Tactics 20 + Stat Str 25 + Stat Dex 20 + Stat Int 35 +End + +Begin + Name Warrior + TrueName "Warrior" + NameId 1061180 + DescId 1061230 + Desc 1 + TopLevel true + Gump 5577 + Type Profession + Skill Tactics 50 + Skill Healing 45 + Skill Swordsmanship 5 + Stat Str 35 + Stat Dex 35 + Stat Int 10 +End + +Begin + Name Mage + TrueName "Mage" + NameId 1061179 + DescId 1061229 + Desc 2 + TopLevel true + Gump 5569 + Type Profession + Skill Magery 50 + Skill Meditation 50 + Skill Wrestling 0 + Stat Str 25 + Stat Dex 10 + Stat Int 45 +End + +Begin + Name Blacksmith + TrueName "Blacksmith" + NameId 1061181 + DescId 1061231 + Desc 3 + TopLevel true + Gump 5555 + Type Profession + Skill Blacksmith 50 + Skill Tinkering 45 + Skill Mining 5 + Stat Str 60 + Stat Dex 10 + Stat Int 10 +End \ No newline at end of file diff --git a/Distribution/Data/Professions/all-profession-skill-names.txt b/Distribution/Data/Professions/all-profession-skill-names.txt new file mode 100644 index 000000000..57f93a935 --- /dev/null +++ b/Distribution/Data/Professions/all-profession-skill-names.txt @@ -0,0 +1,58 @@ +Alchemy, +Anatomy, +AnimalLore, +ItemID, +ArmsLore, +Parrying, +Begging, +Blacksmith, +Bowcraft, +Peacemaking, +Camping, +Carpentry, +Cartography, +Cooking, +DetectHidden, +Enticement, +EvaluateIntelligence, +Healing, +Fishing, +ForensicEvaluation, +Herding, +Hiding, +Provocation, +Inscription, +Lockpicking, +Magery, +ResistingSpells, +Tactics, +Snooping, +Musicianship, +Poisoning, +Archery, +SpiritSpeak, +Stealing, +Tailoring, +AnimalTaming, +TasteIdentification, +Tinkering, +Tracking, +Veterinary, +Swordsmanship, +MaceFighting, +Fencing, +Wrestling, +Lumberjacking, +Mining, +Meditation, +Stealth, +Disarm, +Necromancy, +Focus, +Chivalry, +Bushido, +Ninjitsu, +Spellweaving, +Mysticism, +Imbuing, +Throwing diff --git a/Projects/Server.Tests/Server.Tests.csproj b/Projects/Server.Tests/Server.Tests.csproj index 12e6fd669..b6339a9a0 100644 --- a/Projects/Server.Tests/Server.Tests.csproj +++ b/Projects/Server.Tests/Server.Tests.csproj @@ -11,6 +11,9 @@ + + Data\Professions\LBR\prof.txt + diff --git a/Projects/Server/Events/CharacterCreatedEvent.cs b/Projects/Server/Events/CharacterCreatedEvent.cs index b919193ea..dc089daae 100644 --- a/Projects/Server/Events/CharacterCreatedEvent.cs +++ b/Projects/Server/Events/CharacterCreatedEvent.cs @@ -23,9 +23,9 @@ namespace Server public class CharacterCreatedEventArgs { public CharacterCreatedEventArgs( - NetState state, IAccount a, string name, bool female, int hue, int str, int dex, - int intel, CityInfo city, SkillNameValue[] skills, int shirtHue, int pantsHue, int hairID, int hairHue, - int beardID, int beardHue, int profession, Race race + NetState state, IAccount a, string name, bool female, int hue, StatNameValue[] stats, CityInfo city, + SkillNameValue[] skills, int shirtHue, int pantsHue, int hairID, int hairHue, int beardID, int beardHue, + int profession, Race race ) { State = state; @@ -33,9 +33,7 @@ namespace Server Name = name; Female = female; Hue = hue; - Str = str; - Dex = dex; - Int = intel; + Stats = stats; City = city; Skills = skills; ShirtHue = shirtHue; @@ -60,11 +58,7 @@ namespace Server public int Hue { get; } - public int Str { get; } - - public int Dex { get; } - - public int Int { get; } + public StatNameValue[] Stats { get; } public CityInfo City { get; } @@ -87,18 +81,8 @@ namespace Server public Race Race { get; } } - public struct SkillNameValue - { - public SkillName Name { get; } - - public int Value { get; } - - public SkillNameValue(SkillName name, int value) - { - Name = name; - Value = value; - } - } + public readonly record struct SkillNameValue(SkillName Name, int Value); + public readonly record struct StatNameValue(StatType Name, int Value); public static partial class EventSink { diff --git a/Projects/Server/ExpansionInfo.cs b/Projects/Server/ExpansionInfo.cs index 7f38b22c7..18407c052 100644 --- a/Projects/Server/ExpansionInfo.cs +++ b/Projects/Server/ExpansionInfo.cs @@ -158,6 +158,30 @@ namespace Server public class ExpansionInfo { + public static string GetEraFolder(string parentDirectory) + { + var expansion = Core.Expansion; + var folders = Directory.GetDirectories( + parentDirectory, + "*", + new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive } + ); + + while (expansion-- >= 0) + { + foreach (var folder in folders) + { + var di = new DirectoryInfo(folder); + if (di.Name.InsensitiveEquals(expansion.ToString())) + { + return folder; + } + } + } + + return null; + } + static ExpansionInfo() { var path = Path.Combine(Core.BaseDirectory, "Data/expansion.json"); diff --git a/Projects/Server/Main.cs b/Projects/Server/Main.cs index 49f48e669..1eac5d8e8 100644 --- a/Projects/Server/Main.cs +++ b/Projects/Server/Main.cs @@ -17,6 +17,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Reflection; using System.Runtime; using System.Runtime.InteropServices; @@ -248,6 +249,17 @@ namespace Server { fullPath = Path.Combine(p, path); + if (IsLinux) + { + var fi = new FileInfo(fullPath); + fullPath = fi.Directory!.EnumerateFiles( + fi.Name, + new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive } + ).FirstOrDefault()?.FullName; + + break; + } + if (File.Exists(fullPath)) { break; diff --git a/Projects/Server/Network/NetState/NetState.cs b/Projects/Server/Network/NetState/NetState.cs index 943ff4f10..47c6bf381 100755 --- a/Projects/Server/Network/NetState/NetState.cs +++ b/Projects/Server/Network/NetState/NetState.cs @@ -160,6 +160,8 @@ namespace Server.Network set => _packetEncoder = value; } + public int CurrentPacket { get; internal set; } + public bool SentFirstPacket { get; set; } public bool BlockAllPackets { get; set; } diff --git a/Projects/Server/Network/Packets/IncomingAccountPackets.cs b/Projects/Server/Network/Packets/IncomingAccountPackets.cs index dd34c9099..4444b95ad 100644 --- a/Projects/Server/Network/Packets/IncomingAccountPackets.cs +++ b/Projects/Server/Network/Packets/IncomingAccountPackets.cs @@ -73,40 +73,20 @@ namespace Server.Network int genderRace = reader.ReadByte(); - int str = reader.ReadByte(); - int dex = reader.ReadByte(); - int intl = reader.ReadByte(); - int is1 = reader.ReadByte(); - int vs1 = reader.ReadByte(); - int is2 = reader.ReadByte(); - int vs2 = reader.ReadByte(); - int is3 = reader.ReadByte(); - int vs3 = reader.ReadByte(); + var stats = new StatNameValue[] + { + new(StatType.Str, reader.ReadByte()), + new(StatType.Dex, reader.ReadByte()), + new(StatType.Int, reader.ReadByte()) + }; - SkillNameValue[] skills; - - // We have protocol changes by now, so this is ok + var skills = new SkillNameValue[state.NewCharacterCreation ? 4 : 3]; + skills[0] = new SkillNameValue((SkillName)reader.ReadByte(), reader.ReadByte()); + skills[1] = new SkillNameValue((SkillName)reader.ReadByte(), reader.ReadByte()); + skills[2] = new SkillNameValue((SkillName)reader.ReadByte(), reader.ReadByte()); if (state.NewCharacterCreation) { - int is4 = reader.ReadByte(); - int vs4 = reader.ReadByte(); - - skills = new[] - { - new SkillNameValue((SkillName)is1, vs1), - new SkillNameValue((SkillName)is2, vs2), - new SkillNameValue((SkillName)is3, vs3), - new SkillNameValue((SkillName)is4, vs4) - }; - } - else - { - skills = new[] - { - new SkillNameValue((SkillName)is1, vs1), - new SkillNameValue((SkillName)is2, vs2), - new SkillNameValue((SkillName)is3, vs3) - }; + skills[3] = new SkillNameValue((SkillName)reader.ReadByte(), reader.ReadByte()); } int hue = reader.ReadUInt16(); @@ -171,9 +151,7 @@ namespace Server.Network name, female, hue, - str, - dex, - intl, + stats, info[cityIndex], skills, shirtHue, diff --git a/Projects/Server/Server.csproj b/Projects/Server/Server.csproj index bf42d652f..cf357a582 100755 --- a/Projects/Server/Server.csproj +++ b/Projects/Server/Server.csproj @@ -34,7 +34,7 @@ - + diff --git a/Projects/Server/Skills.cs b/Projects/Server/Skills.cs index 082e548fd..077205507 100644 --- a/Projects/Server/Skills.cs +++ b/Projects/Server/Skills.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; using Server.Network; @@ -384,7 +385,8 @@ namespace Server { public SkillInfo( int skillID, string name, double strScale, double dexScale, double intScale, string title, - SkillUseCallback callback, double strGain, double dexGain, double intGain, double gainFactor + SkillUseCallback callback, double strGain, double dexGain, double intGain, double gainFactor, + string professionSkillName = null ) { Name = name; @@ -398,7 +400,7 @@ namespace Server DexGain = dexGain; IntGain = intGain; GainFactor = gainFactor; - + ProfessionSkillName = professionSkillName ?? Name.Replace(" ", ""); StatTotal = strScale + dexScale + intScale; } @@ -426,25 +428,27 @@ namespace Server public double GainFactor { get; set; } + public string ProfessionSkillName { get; set; } + public static SkillInfo[] Table { get; set; } = { new(0, "Alchemy", 0.0, 5.0, 5.0, "Alchemist", null, 0.0, 0.5, 0.5, 1.0), new(1, "Anatomy", 0.0, 0.0, 0.0, "Biologist", null, 0.15, 0.15, 0.7, 1.0), new(2, "Animal Lore", 0.0, 0.0, 0.0, "Naturalist", null, 0.0, 0.0, 1.0, 1.0), - new(3, "Item Identification", 0.0, 0.0, 0.0, "Merchant", null, 0.0, 0.0, 1.0, 1.0), + new(3, "Item Identification", 0.0, 0.0, 0.0, "Merchant", null, 0.0, 0.0, 1.0, 1.0, "ItemID"), new(4, "Arms Lore", 0.0, 0.0, 0.0, "Weapon Master", null, 0.75, 0.15, 0.1, 1.0), new(5, "Parrying", 7.5, 2.5, 0.0, "Duelist", null, 0.75, 0.25, 0.0, 1.0), new(6, "Begging", 0.0, 0.0, 0.0, "Beggar", null, 0.0, 0.0, 0.0, 1.0), - new(7, "Blacksmithy", 10.0, 0.0, 0.0, "Blacksmith", null, 1.0, 0.0, 0.0, 1.0), - new(8, "Bowcraft/Fletching", 6.0, 16.0, 0.0, "Bowyer", null, 0.6, 1.6, 0.0, 1.0), + new(7, "Blacksmithy", 10.0, 0.0, 0.0, "Blacksmith", null, 1.0, 0.0, 0.0, 1.0, "Blacksmith"), + new(8, "Bowcraft/Fletching", 6.0, 16.0, 0.0, "Bowyer", null, 0.6, 1.6, 0.0, 1.0, "Bowcraft"), new(9, "Peacemaking", 0.0, 0.0, 0.0, "Pacifier", null, 0.0, 0.0, 0.0, 1.0), new(10, "Camping", 20.0, 15.0, 15.0, "Explorer", null, 2.0, 1.5, 1.5, 1.0), new(11, "Carpentry", 20.0, 5.0, 0.0, "Carpenter", null, 2.0, 0.5, 0.0, 1.0), new(12, "Cartography", 0.0, 7.5, 7.5, "Cartographer", null, 0.0, 0.75, 0.75, 1.0), new(13, "Cooking", 0.0, 20.0, 30.0, "Chef", null, 0.0, 2.0, 3.0, 1.0), new(14, "Detecting Hidden", 0.0, 0.0, 0.0, "Scout", null, 0.0, 0.4, 0.6, 1.0), - new(15, "Discordance", 0.0, 2.5, 2.5, "Demoralizer", null, 0.0, 0.25, 0.25, 1.0), - new(16, "Evaluating Intelligence", 0.0, 0.0, 0.0, "Scholar", null, 0.0, 0.0, 1.0, 1.0), + new(15, "Discordance", 0.0, 2.5, 2.5, "Demoralizer", null, 0.0, 0.25, 0.25, 1.0, "Enticement"), + new(16, "Evaluating Intelligence", 0.0, 0.0, 0.0, "Scholar", null, 0.0, 0.0, 1.0, 1.0, "EvaluateIntelligence"), new(17, "Healing", 6.0, 6.0, 8.0, "Healer", null, 0.6, 0.6, 0.8, 1.0), new(18, "Fishing", 0.0, 0.0, 0.0, "Fisherman", null, 0.5, 0.5, 0.0, 1.0), new(19, "Forensic Evaluation", 0.0, 0.0, 0.0, "Detective", null, 0.0, 0.2, 0.8, 1.0), @@ -476,7 +480,7 @@ namespace Server new(45, "Mining", 20.0, 0.0, 0.0, "Miner", null, 2.0, 0.0, 0.0, 1.0), new(46, "Meditation", 0.0, 0.0, 0.0, "Stoic", null, 0.0, 0.0, 0.0, 1.0), new(47, "Stealth", 0.0, 0.0, 0.0, "Rogue", null, 0.0, 0.0, 0.0, 1.0), - new(48, "Remove Trap", 0.0, 0.0, 0.0, "Trap Specialist", null, 0.0, 0.0, 0.0, 1.0), + new(48, "Remove Trap", 0.0, 0.0, 0.0, "Trap Specialist", null, 0.0, 0.0, 0.0, 1.0, "Disarm"), new(49, "Necromancy", 0.0, 0.0, 0.0, "Necromancer", null, 0.0, 0.0, 0.0, 1.0), new(50, "Focus", 0.0, 0.0, 0.0, "Driven", null, 0.0, 0.0, 0.0, 1.0), new(51, "Chivalry", 0.0, 0.0, 0.0, "Paladin", null, 0.0, 0.0, 0.0, 1.0), @@ -892,16 +896,16 @@ namespace Server } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public SkillsEnumerator GetEnumerator() => new(m_Skills); + public Enumerator GetEnumerator() => new(m_Skills); - public ref struct SkillsEnumerator + public ref struct Enumerator { private readonly Skill[] _skills; private int _index; private Skill _current; [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal SkillsEnumerator(Skill[] skills) + internal Enumerator(Skill[] skills) { _skills = skills; _index = 0; diff --git a/Projects/UOContent/Engines/Craft/DefTinkering.cs b/Projects/UOContent/Engines/Craft/DefTinkering.cs index 19324ef38..dbe6f497a 100644 --- a/Projects/UOContent/Engines/Craft/DefTinkering.cs +++ b/Projects/UOContent/Engines/Craft/DefTinkering.cs @@ -35,7 +35,7 @@ namespace Server.Engines.Craft public override double GetChanceAtMin(CraftItem item) { - if (item.NameNumber == 1044258 || item.NameNumber == 1046445) // potion keg and faction trap removal kit + if (item.NameNumber is 1044258 or 1046445) // potion keg and faction trap removal kit { return 0.5; // 50% } diff --git a/Projects/UOContent/Items/Armor/Cloth/GargishClothArmsType1.cs b/Projects/UOContent/Items/Armor/Cloth/GargishClothArmsType1.cs new file mode 100644 index 000000000..819d4e44e --- /dev/null +++ b/Projects/UOContent/Items/Armor/Cloth/GargishClothArmsType1.cs @@ -0,0 +1,25 @@ +namespace Server.Items +{ + [Serializable(0)] + [TypeAlias("Server.Items.GargishClothArms", "Server.Items.GargishClothArmsArmor")] + public partial class GargishClothArmsType1 : BaseArmor + { + [Constructible] + public GargishClothArmsType1() : base(0x404) => Weight = 2.0; + + public override int BasePhysicalResistance => 5; + public override int BaseFireResistance => 7; + public override int BaseColdResistance => 6; + public override int BasePoisonResistance => 6; + public override int BaseEnergyResistance => 6; + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + public override int AosStrReq => 20; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Cloth; + public override CraftResource DefaultResource => CraftResource.None; + public override ArmorMeditationAllowance DefMedAllowance => ArmorMeditationAllowance.All; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Armor/Cloth/GargishClothArmsType2.cs b/Projects/UOContent/Items/Armor/Cloth/GargishClothArmsType2.cs new file mode 100644 index 000000000..c46c5ebf0 --- /dev/null +++ b/Projects/UOContent/Items/Armor/Cloth/GargishClothArmsType2.cs @@ -0,0 +1,25 @@ +namespace Server.Items +{ + [Serializable(0)] + [TypeAlias("Server.Items.FemaleGargishClothArms", "Server.Items.FemaleGargishClothArmsArmor")] + public partial class GargishClothArmsType2 : BaseArmor + { + [Constructible] + public GargishClothArmsType2() : base(0x403) => Weight = 2.0; + + public override int BasePhysicalResistance => 5; + public override int BaseFireResistance => 7; + public override int BaseColdResistance => 6; + public override int BasePoisonResistance => 6; + public override int BaseEnergyResistance => 6; + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + public override int AosStrReq => 20; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Cloth; + public override CraftResource DefaultResource => CraftResource.None; + public override ArmorMeditationAllowance DefMedAllowance => ArmorMeditationAllowance.All; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Armor/Cloth/GargishClothChestType1.cs b/Projects/UOContent/Items/Armor/Cloth/GargishClothChestType1.cs new file mode 100644 index 000000000..4785b91bb --- /dev/null +++ b/Projects/UOContent/Items/Armor/Cloth/GargishClothChestType1.cs @@ -0,0 +1,25 @@ +namespace Server.Items +{ + [Serializable(0)] + [TypeAlias("Server.Items.GargishClothChest", "Server.Items.GargishClothChestArmor")] + public partial class GargishClothChestType1 : BaseArmor + { + [Constructible] + public GargishClothChestType1() : base(0x406) => Weight = 2.0; + + public override int BasePhysicalResistance => 5; + public override int BaseFireResistance => 7; + public override int BaseColdResistance => 6; + public override int BasePoisonResistance => 6; + public override int BaseEnergyResistance => 6; + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + public override int AosStrReq => 25; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Cloth; + public override CraftResource DefaultResource => CraftResource.None; + public override ArmorMeditationAllowance DefMedAllowance => ArmorMeditationAllowance.All; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Armor/Cloth/GargishClothChestType2.cs b/Projects/UOContent/Items/Armor/Cloth/GargishClothChestType2.cs new file mode 100644 index 000000000..a1ba296a2 --- /dev/null +++ b/Projects/UOContent/Items/Armor/Cloth/GargishClothChestType2.cs @@ -0,0 +1,25 @@ +namespace Server.Items +{ + [Serializable(0)] + [TypeAlias("Server.Items.FemaleGargishClothChest", "Server.Items.FemaleGargishClothChestArmor")] + public partial class GargishClothChestType2 : BaseArmor + { + [Constructible] + public GargishClothChestType2() : base(0x405) => Weight = 2.0; + + public override int BasePhysicalResistance => 5; + public override int BaseFireResistance => 7; + public override int BaseColdResistance => 6; + public override int BasePoisonResistance => 6; + public override int BaseEnergyResistance => 6; + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + public override int AosStrReq => 25; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Cloth; + public override CraftResource DefaultResource => CraftResource.None; + public override ArmorMeditationAllowance DefMedAllowance => ArmorMeditationAllowance.All; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Armor/Cloth/GargishClothKiltType1.cs b/Projects/UOContent/Items/Armor/Cloth/GargishClothKiltType1.cs new file mode 100644 index 000000000..b3b8c1093 --- /dev/null +++ b/Projects/UOContent/Items/Armor/Cloth/GargishClothKiltType1.cs @@ -0,0 +1,25 @@ +namespace Server.Items +{ + [Serializable(0)] + [TypeAlias("Server.Items.GargishClothKilt", "Server.Items.GargishClothKiltArmor")] + public partial class GargishClothKiltType1 : BaseArmor + { + [Constructible] + public GargishClothKiltType1() : base(0x408) => Weight = 2.0; + + public override int BasePhysicalResistance => 5; + public override int BaseFireResistance => 7; + public override int BaseColdResistance => 6; + public override int BasePoisonResistance => 6; + public override int BaseEnergyResistance => 6; + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + public override int AosStrReq => 20; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Cloth; + public override CraftResource DefaultResource => CraftResource.None; + public override ArmorMeditationAllowance DefMedAllowance => ArmorMeditationAllowance.All; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Armor/Cloth/GargishClothKiltType2.cs b/Projects/UOContent/Items/Armor/Cloth/GargishClothKiltType2.cs new file mode 100644 index 000000000..e18718dc1 --- /dev/null +++ b/Projects/UOContent/Items/Armor/Cloth/GargishClothKiltType2.cs @@ -0,0 +1,25 @@ +namespace Server.Items +{ + [Serializable(0)] + [TypeAlias("Server.Items.GargishClothKilt", "Server.Items.GargishClothKiltArmor")] + public partial class GargishClothKiltType2 : BaseArmor + { + [Constructible] + public GargishClothKiltType2() : base(0x407) => Weight = 2.0; + + public override int BasePhysicalResistance => 5; + public override int BaseFireResistance => 7; + public override int BaseColdResistance => 6; + public override int BasePoisonResistance => 6; + public override int BaseEnergyResistance => 6; + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + public override int AosStrReq => 20; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Cloth; + public override CraftResource DefaultResource => CraftResource.None; + public override ArmorMeditationAllowance DefMedAllowance => ArmorMeditationAllowance.All; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Armor/Cloth/GargishClothLegsType1.cs b/Projects/UOContent/Items/Armor/Cloth/GargishClothLegsType1.cs new file mode 100644 index 000000000..45084fbc3 --- /dev/null +++ b/Projects/UOContent/Items/Armor/Cloth/GargishClothLegsType1.cs @@ -0,0 +1,25 @@ +namespace Server.Items +{ + [Serializable(0)] + [TypeAlias("Server.Items.GargishClothLegs", "Server.Items.GargishClothLegsArmor")] + public partial class GargishClothLegsType1 : BaseArmor + { + [Constructible] + public GargishClothLegsType1() : base(0x40A) => Weight = 2.0; + + public override int BasePhysicalResistance => 5; + public override int BaseFireResistance => 7; + public override int BaseColdResistance => 6; + public override int BasePoisonResistance => 6; + public override int BaseEnergyResistance => 6; + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + public override int AosStrReq => 20; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Cloth; + public override CraftResource DefaultResource => CraftResource.None; + public override ArmorMeditationAllowance DefMedAllowance => ArmorMeditationAllowance.All; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Armor/Cloth/GargishClothLegsType2.cs b/Projects/UOContent/Items/Armor/Cloth/GargishClothLegsType2.cs new file mode 100644 index 000000000..bad26d399 --- /dev/null +++ b/Projects/UOContent/Items/Armor/Cloth/GargishClothLegsType2.cs @@ -0,0 +1,25 @@ +namespace Server.Items +{ + [Serializable(0)] + [TypeAlias("Server.Items.FemaleGargishClothLegs", "Server.Items.FemaleGargishClothLegsArmor")] + public partial class GargishClothLegsType2 : BaseArmor + { + [Constructible] + public GargishClothLegsType2() : base(0x409) => Weight = 2.0; + + public override int BasePhysicalResistance => 5; + public override int BaseFireResistance => 7; + public override int BaseColdResistance => 6; + public override int BasePoisonResistance => 6; + public override int BaseEnergyResistance => 6; + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + public override int AosStrReq => 20; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Cloth; + public override CraftResource DefaultResource => CraftResource.None; + public override ArmorMeditationAllowance DefMedAllowance => ArmorMeditationAllowance.All; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Armor/Stone/GargishStoneArmsType1.cs b/Projects/UOContent/Items/Armor/Stone/GargishStoneArmsType1.cs new file mode 100644 index 000000000..e9223b58f --- /dev/null +++ b/Projects/UOContent/Items/Armor/Stone/GargishStoneArmsType1.cs @@ -0,0 +1,26 @@ +namespace Server.Items +{ + [Serializable(0, false)] + [TypeAlias("Server.Items.GargishStoneArms")] + public partial class GargishStoneArmsType1 : BaseArmor + { + [Constructible] + public GargishStoneArmsType1() : base(0x284) => Weight = 10.0; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 4; + public override int BasePoisonResistance => 8; + public override int BaseEnergyResistance => 6; + + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + + public override int AosStrReq => 40; + public override int OldStrReq => 40; + public override int ArmorBase => 40; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Stone; + } +} diff --git a/Projects/UOContent/Items/Armor/Stone/GargishStoneArmsType2.cs b/Projects/UOContent/Items/Armor/Stone/GargishStoneArmsType2.cs new file mode 100644 index 000000000..ec9a5cefc --- /dev/null +++ b/Projects/UOContent/Items/Armor/Stone/GargishStoneArmsType2.cs @@ -0,0 +1,26 @@ +namespace Server.Items +{ + [Serializable(0, false)] + [TypeAlias("Server.Items.FemaleGargishStoneArms")] + public partial class GargishStoneArmsType2 : BaseArmor + { + [Constructible] + public GargishStoneArmsType2() : base(0x283) => Weight = 10.0; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 4; + public override int BasePoisonResistance => 8; + public override int BaseEnergyResistance => 6; + + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + + public override int AosStrReq => 40; + public override int OldStrReq => 40; + public override int ArmorBase => 40; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Stone; + } +} diff --git a/Projects/UOContent/Items/Armor/Stone/GargishStoneChestType1.cs b/Projects/UOContent/Items/Armor/Stone/GargishStoneChestType1.cs new file mode 100644 index 000000000..8aafab468 --- /dev/null +++ b/Projects/UOContent/Items/Armor/Stone/GargishStoneChestType1.cs @@ -0,0 +1,26 @@ +namespace Server.Items +{ + [Serializable(0, false)] + [TypeAlias("Server.Items.GargishStoneChest")] + public partial class GargishStoneChestType1 : BaseArmor + { + [Constructible] + public GargishStoneChestType1() : base(0x286) => Weight = 15.0; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 4; + public override int BasePoisonResistance => 8; + public override int BaseEnergyResistance => 6; + + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + + public override int AosStrReq => 40; + public override int OldStrReq => 40; + public override int ArmorBase => 40; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Stone; + } +} diff --git a/Projects/UOContent/Items/Armor/Stone/GargishStoneChestType2.cs b/Projects/UOContent/Items/Armor/Stone/GargishStoneChestType2.cs new file mode 100644 index 000000000..78fa08650 --- /dev/null +++ b/Projects/UOContent/Items/Armor/Stone/GargishStoneChestType2.cs @@ -0,0 +1,27 @@ +namespace Server.Items +{ + [Serializable(0, false)] + [TypeAlias("Server.Items.FemaleGargishStoneChest")] + public partial class GargishStoneChestType2 : BaseArmor + { + [Constructible] + public GargishStoneChestType2() : base(0x285) => Weight = 15.0; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 4; + public override int BasePoisonResistance => 8; + public override int BaseEnergyResistance => 6; + + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + + public override int AosStrReq => 40; + public override int OldStrReq => 40; + + public override int ArmorBase => 40; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Stone; + } +} diff --git a/Projects/UOContent/Items/Armor/Stone/GargishStoneKiltType1.cs b/Projects/UOContent/Items/Armor/Stone/GargishStoneKiltType1.cs new file mode 100644 index 000000000..cf826661f --- /dev/null +++ b/Projects/UOContent/Items/Armor/Stone/GargishStoneKiltType1.cs @@ -0,0 +1,26 @@ +namespace Server.Items +{ + [Serializable(0, false)] + [TypeAlias("Server.Items.GargishStoneKilt")] + public partial class GargishStoneKiltType1 : BaseArmor + { + [Constructible] + public GargishStoneKiltType1() : base(0x288) => Weight = 10.0; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 4; + public override int BasePoisonResistance => 8; + public override int BaseEnergyResistance => 6; + + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + + public override int AosStrReq => 40; + public override int OldStrReq => 40; + public override int ArmorBase => 40; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Stone; + } +} diff --git a/Projects/UOContent/Items/Armor/Stone/GargishStoneKiltType2.cs b/Projects/UOContent/Items/Armor/Stone/GargishStoneKiltType2.cs new file mode 100644 index 000000000..7ca6f2363 --- /dev/null +++ b/Projects/UOContent/Items/Armor/Stone/GargishStoneKiltType2.cs @@ -0,0 +1,27 @@ +namespace Server.Items +{ + [Serializable(0, false)] + [TypeAlias("Server.Items.FemaleGargishStoneKilt")] + public partial class GargishStoneKiltType2 : BaseArmor + { + [Constructible] + public GargishStoneKiltType2() : base(0x287) => Weight = 10.0; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 4; + public override int BasePoisonResistance => 8; + public override int BaseEnergyResistance => 6; + + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + + public override int AosStrReq => 40; + public override int OldStrReq => 40; + + public override int ArmorBase => 40; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Stone; + } +} diff --git a/Projects/UOContent/Items/Armor/Stone/GargishStoneLegsType1.cs b/Projects/UOContent/Items/Armor/Stone/GargishStoneLegsType1.cs new file mode 100644 index 000000000..3974d969a --- /dev/null +++ b/Projects/UOContent/Items/Armor/Stone/GargishStoneLegsType1.cs @@ -0,0 +1,26 @@ +namespace Server.Items +{ + [Serializable(0, false)] + [TypeAlias("Server.Items.GargishStoneLegs")] + public partial class GargishStoneLegsType1 : BaseArmor + { + [Constructible] + public GargishStoneLegsType1() : base(0x28A) => Weight = 15.0; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 4; + public override int BasePoisonResistance => 8; + public override int BaseEnergyResistance => 6; + + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + + public override int AosStrReq => 40; + public override int OldStrReq => 40; + public override int ArmorBase => 40; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Stone; + } +} diff --git a/Projects/UOContent/Items/Armor/Stone/GargishStoneLegsType2.cs b/Projects/UOContent/Items/Armor/Stone/GargishStoneLegsType2.cs new file mode 100644 index 000000000..90707fc02 --- /dev/null +++ b/Projects/UOContent/Items/Armor/Stone/GargishStoneLegsType2.cs @@ -0,0 +1,27 @@ +namespace Server.Items +{ + [Serializable(0, false)] + [TypeAlias("Server.Items.FemaleGargishStoneLegs")] + public partial class GargishStoneLegsType2 : BaseArmor + { + [Constructible] + public GargishStoneLegsType2() : base(0x289) => Weight = 15.0; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 4; + public override int BasePoisonResistance => 8; + public override int BaseEnergyResistance => 6; + + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + + public override int AosStrReq => 40; + public override int OldStrReq => 40; + + public override int ArmorBase => 40; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Stone; + } +} diff --git a/Projects/UOContent/Items/Clothing/BaseClothing.cs b/Projects/UOContent/Items/Clothing/BaseClothing.cs index de0ad630b..251d86ad0 100644 --- a/Projects/UOContent/Items/Clothing/BaseClothing.cs +++ b/Projects/UOContent/Items/Clothing/BaseClothing.cs @@ -624,7 +624,7 @@ namespace Server.Items public override void OnAfterDuped(Item newItem) { - if (!(newItem is BaseClothing clothing)) + if (newItem is not BaseClothing clothing) { return; } diff --git a/Projects/UOContent/Items/Shields/GargishWoodenShield.cs b/Projects/UOContent/Items/Shields/GargishWoodenShield.cs new file mode 100644 index 000000000..a64473eb5 --- /dev/null +++ b/Projects/UOContent/Items/Shields/GargishWoodenShield.cs @@ -0,0 +1,21 @@ +namespace Server.Items +{ + [Flippable(0x4200, 0x4207)] + [Serializable(0)] + public partial class GargishWoodenShield : BaseShield + { + [Constructible] + public GargishWoodenShield() : base(0x4200) => Weight = 5.0; + + public override int BasePhysicalResistance => 0; + public override int BaseFireResistance => 0; + public override int BaseColdResistance => 0; + public override int BasePoisonResistance => 0; + public override int BaseEnergyResistance => 1; + public override int InitMinHits => 20; + public override int InitMaxHits => 25; + public override int AosStrReq => 20; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tools/TinkerTools.cs b/Projects/UOContent/Items/Skill Items/Tools/TinkerTools.cs index 4a9b35add..872bc099a 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/TinkerTools.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/TinkerTools.cs @@ -3,7 +3,8 @@ using Server.Engines.Craft; namespace Server.Items { [Flippable(0x1EB8, 0x1EB9)] - public class TinkerTools : BaseTool + [Serializable(0, false)] + public partial class TinkerTools : BaseTool { [Constructible] public TinkerTools() : base(0x1EB8) => Weight = 1.0; @@ -11,58 +12,18 @@ namespace Server.Items [Constructible] public TinkerTools(int uses) : base(uses, 0x1EB8) => Weight = 1.0; - public TinkerTools(Serial serial) : base(serial) - { - } - public override CraftSystem CraftSystem => DefTinkering.CraftSystem; - - 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(); - } } - public class TinkersTools : BaseTool + [Serializable(0, false)] + public partial class TinkersTools : BaseTool { [Constructible] - public TinkersTools() - : base(0x1EBC) => - Weight = 1.0; + public TinkersTools() : base(0x1EBC) => Weight = 1.0; [Constructible] - public TinkersTools(int uses) - : base(uses, 0x1EBC) => - Weight = 1.0; - - public TinkersTools(Serial serial) - : base(serial) - { - } + public TinkersTools(int uses) : base(uses, 0x1EBC) => Weight = 1.0; public override CraftSystem CraftSystem => DefTinkering.CraftSystem; - - 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(); - } } } diff --git a/Projects/UOContent/Items/Weapons/Axes/DualShortAxes.cs b/Projects/UOContent/Items/Weapons/Axes/DualShortAxes.cs new file mode 100644 index 000000000..d3dfb4d18 --- /dev/null +++ b/Projects/UOContent/Items/Weapons/Axes/DualShortAxes.cs @@ -0,0 +1,24 @@ +namespace Server.Items +{ + [Flippable(0x8FD, 0x4068)] + [Serializable(0)] + public partial class DualShortAxes : BaseAxe + { + [Constructible] + public DualShortAxes() : base(0x8FD) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.InfectiousStrike; + public override int AosStrengthReq => 35; + public override int AosMinDamage => 14; + public override int AosMaxDamage => 17; + public override float MlSpeed => 3.00f; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Weapons/Maces/DiscMace.cs b/Projects/UOContent/Items/Weapons/Maces/DiscMace.cs new file mode 100644 index 000000000..7152cc377 --- /dev/null +++ b/Projects/UOContent/Items/Weapons/Maces/DiscMace.cs @@ -0,0 +1,24 @@ +namespace Server.Items +{ + [Flippable(0x903, 0x406E)] + [Serializable(0)] + public partial class DiscMace : BaseBashing + { + [Constructible] + public DiscMace() : base(0x903) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + public override int AosStrengthReq => 45; + public override int AosMinDamage => 11; + public override int AosMaxDamage => 15; + public override float MlSpeed => 2.75f; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Weapons/SpearsAndForks/DualPointedSpear.cs b/Projects/UOContent/Items/Weapons/SpearsAndForks/DualPointedSpear.cs new file mode 100644 index 000000000..2aee19229 --- /dev/null +++ b/Projects/UOContent/Items/Weapons/SpearsAndForks/DualPointedSpear.cs @@ -0,0 +1,24 @@ +namespace Server.Items +{ + [Flippable(0x904, 0x406D)] + [Serializable(0)] + public partial class DualPointedSpear : BaseSpear + { + [Constructible] + public DualPointedSpear() : base(0x904) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + public override int AosStrengthReq => 50; + public override int AosMinDamage => 11; + public override int AosMaxDamage => 14; + public override float MlSpeed => 2.25f; + + public override int InitMinHits => 31; + public override int InitMaxHits => 80; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Weapons/Staves/GlassStaff.cs b/Projects/UOContent/Items/Weapons/Staves/GlassStaff.cs new file mode 100644 index 000000000..03d3b0bbc --- /dev/null +++ b/Projects/UOContent/Items/Weapons/Staves/GlassStaff.cs @@ -0,0 +1,23 @@ +namespace Server.Items +{ + [Flippable(0x905, 0x4070)] + [Serializable(0)] + public partial class GlassStaff : BaseStaff + { + [Constructible] + public GlassStaff() : base(0x905) => + Weight = 4.0; + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; + public override int AosStrengthReq => 20; + public override int AosMinDamage => 11; + public override int AosMaxDamage => 14; + public override float MlSpeed => 2.25f; + + public override int InitMinHits => 31; + public override int InitMaxHits => 70; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Weapons/Staves/SerpentstoneStaff.cs b/Projects/UOContent/Items/Weapons/Staves/SerpentstoneStaff.cs new file mode 100644 index 000000000..a75b82ae4 --- /dev/null +++ b/Projects/UOContent/Items/Weapons/Staves/SerpentstoneStaff.cs @@ -0,0 +1,25 @@ +namespace Server.Items +{ + [Flippable(0x906, 0x406F)] + [TypeAlias("Server.Items.SerpentStoneStaff")] + [Serializable(0)] + public partial class SerpentstoneStaff : BaseStaff + { + [Constructible] + public SerpentstoneStaff() : base(0x906) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; + public override int AosStrengthReq => 35; + public override int AosMinDamage => 16; + public override int AosMaxDamage => 19; + public override float MlSpeed => 3.50f; + + public override int InitMinHits => 31; + public override int InitMaxHits => 50; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Weapons/Staves/ShepherdsCrook.cs b/Projects/UOContent/Items/Weapons/Staves/ShepherdsCrook.cs index 12278e291..054c53c07 100644 --- a/Projects/UOContent/Items/Weapons/Staves/ShepherdsCrook.cs +++ b/Projects/UOContent/Items/Weapons/Staves/ShepherdsCrook.cs @@ -53,33 +53,31 @@ namespace Server.Items protected override void OnTarget(Mobile from, object targ) { - if (targ is BaseCreature bc) + if (targ is not BaseCreature bc) { - if (IsHerdable(bc)) - { - if (bc.Controlled) - { - bc.PrivateOverheadMessage( - MessageType.Regular, - 0x3B2, - 502467, - from.NetState - ); // That animal looks tame already. - } - else - { - from.SendLocalizedMessage(502475); // Click where you wish the animal to go. - from.Target = new InternalTarget(bc); - } - } - else - { - from.SendLocalizedMessage(502468); // That is not a herdable animal. - } + from.SendLocalizedMessage(502472); // You don't seem to be able to persuade that to move. + return; + } + + if (!IsHerdable(bc)) + { + from.SendLocalizedMessage(502468); // That is not a herdable animal. + return; + } + + if (bc.Controlled) + { + bc.PrivateOverheadMessage( + MessageType.Regular, + 0x3B2, + 502467, // That animal looks tame already. + from.NetState + ); } else { - from.SendLocalizedMessage(502472); // You don't seem to be able to persuade that to move. + from.SendLocalizedMessage(502475); // Click where you wish the animal to go. + from.Target = new InternalTarget(bc); } } @@ -136,9 +134,9 @@ namespace Server.Items m_Creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, - 502471, + 502471, // That wasn't even challenging. from.NetState - ); // That wasn't even challenging. + ); } if (from.CheckTargetSkill(SkillName.Herding, m_Creature, min, max)) diff --git a/Projects/UOContent/Items/Weapons/Swords/BloodBlade.cs b/Projects/UOContent/Items/Weapons/Swords/BloodBlade.cs new file mode 100644 index 000000000..4bcf21831 --- /dev/null +++ b/Projects/UOContent/Items/Weapons/Swords/BloodBlade.cs @@ -0,0 +1,29 @@ +namespace Server.Items +{ + [Flippable(0x8FE, 0x4072)] + [Serializable(0)] + public partial class BloodBlade : BaseSword + { + [Constructible] + public BloodBlade() : base(0x8FE) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; + public override int AosStrengthReq => 10; + public override int AosMinDamage => 10; + public override int AosMaxDamage => 12; + public override float MlSpeed => 2.00f; + + public override int DefHitSound => 0x23C; + public override int DefMissSound => 0x238; + public override int InitMinHits => 31; + public override int InitMaxHits => 90; + public override SkillName DefSkill => SkillName.Fencing; + public override WeaponType DefType => WeaponType.Piercing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Weapons/Swords/DreadSword.cs b/Projects/UOContent/Items/Weapons/Swords/DreadSword.cs new file mode 100644 index 000000000..9f2df661f --- /dev/null +++ b/Projects/UOContent/Items/Weapons/Swords/DreadSword.cs @@ -0,0 +1,26 @@ +namespace Server.Items +{ + [Flippable(0x90B, 0x4074)] + [Serializable(0)] + public partial class DreadSword : BaseSword + { + [Constructible] + public DreadSword() : base(0x90B) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; + public override int AosStrengthReq => 35; + public override int AosMinDamage => 14; + public override int AosMaxDamage => 18; + public override float MlSpeed => 3.50f; + + public override int DefHitSound => 0x237; + public override int DefMissSound => 0x23A; + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Weapons/Swords/GargishTalwar.cs b/Projects/UOContent/Items/Weapons/Swords/GargishTalwar.cs new file mode 100644 index 000000000..713e684b6 --- /dev/null +++ b/Projects/UOContent/Items/Weapons/Swords/GargishTalwar.cs @@ -0,0 +1,26 @@ +namespace Server.Items +{ + [Flippable(0x908, 0x4075)] + [Serializable(0)] + public partial class GargishTalwar : BaseSword + { + [Constructible] + public GargishTalwar() : base(0x908) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; + public override int AosStrengthReq => 40; + public override int AosMinDamage => 16; + public override int AosMaxDamage => 19; + public override float MlSpeed => 3.50f; + + public override int DefHitSound => 0x237; + public override int DefMissSound => 0x238; + public override int InitMinHits => 31; + public override int InitMaxHits => 80; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Items/Weapons/Swords/GlassSword.cs b/Projects/UOContent/Items/Weapons/Swords/GlassSword.cs new file mode 100644 index 000000000..1bb290332 --- /dev/null +++ b/Projects/UOContent/Items/Weapons/Swords/GlassSword.cs @@ -0,0 +1,24 @@ +namespace Server.Items +{ + [Flippable(0x90C, 0x4073)] + [Serializable(0)] + public partial class GlassSword : BaseSword + { + [Constructible] + public GlassSword() : base(0x90C) => Weight = 6.0; + + public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; + public override int AosStrengthReq => 20; + public override int AosMinDamage => 11; + public override int AosMaxDamage => 15; + public override float MlSpeed => 2.75f; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x23A; + public override int InitMinHits => 31; + public override int InitMaxHits => 90; + + public override int RequiredRaces => Race.AllowGargoylesOnly; + } +} diff --git a/Projects/UOContent/Migrations/Server.Items.BloodBlade.v0.json b/Projects/UOContent/Migrations/Server.Items.BloodBlade.v0.json new file mode 100644 index 000000000..56d90713f --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.BloodBlade.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.BloodBlade" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.DiscMace.v0.json b/Projects/UOContent/Migrations/Server.Items.DiscMace.v0.json new file mode 100644 index 000000000..98a23931e --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.DiscMace.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.DiscMace" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.DreadSword.v0.json b/Projects/UOContent/Migrations/Server.Items.DreadSword.v0.json new file mode 100644 index 000000000..a57fdb8e9 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.DreadSword.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.DreadSword" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.DualPointedSpear.v0.json b/Projects/UOContent/Migrations/Server.Items.DualPointedSpear.v0.json new file mode 100644 index 000000000..713fdcf83 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.DualPointedSpear.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.DualPointedSpear" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.DualShortAxes.v0.json b/Projects/UOContent/Migrations/Server.Items.DualShortAxes.v0.json new file mode 100644 index 000000000..4b442af12 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.DualShortAxes.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.DualShortAxes" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishClothArmsType1.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishClothArmsType1.v0.json new file mode 100644 index 000000000..2c8a60038 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishClothArmsType1.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishClothArmsType1" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishClothArmsType2.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishClothArmsType2.v0.json new file mode 100644 index 000000000..ad10e7655 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishClothArmsType2.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishClothArmsType2" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishClothChestType1.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishClothChestType1.v0.json new file mode 100644 index 000000000..7bbf21fcf --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishClothChestType1.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishClothChestType1" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishClothChestType2.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishClothChestType2.v0.json new file mode 100644 index 000000000..97322169b --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishClothChestType2.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishClothChestType2" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishClothKiltType1.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishClothKiltType1.v0.json new file mode 100644 index 000000000..bd434b331 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishClothKiltType1.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishClothKiltType1" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishClothKiltType2.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishClothKiltType2.v0.json new file mode 100644 index 000000000..313a481bd --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishClothKiltType2.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishClothKiltType2" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishClothLegsType1.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishClothLegsType1.v0.json new file mode 100644 index 000000000..00b41e840 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishClothLegsType1.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishClothLegsType1" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishClothLegsType2.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishClothLegsType2.v0.json new file mode 100644 index 000000000..20ae6f861 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishClothLegsType2.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishClothLegsType2" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishStoneArmsType1.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishStoneArmsType1.v0.json new file mode 100644 index 000000000..b5b79efab --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishStoneArmsType1.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishStoneArmsType1" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishStoneArmsType2.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishStoneArmsType2.v0.json new file mode 100644 index 000000000..5d4a5e397 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishStoneArmsType2.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishStoneArmsType2" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishStoneChestType1.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishStoneChestType1.v0.json new file mode 100644 index 000000000..7eaf66017 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishStoneChestType1.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishStoneChestType1" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishStoneChestType2.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishStoneChestType2.v0.json new file mode 100644 index 000000000..fb4c260d2 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishStoneChestType2.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishStoneChestType2" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishStoneKiltType1.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishStoneKiltType1.v0.json new file mode 100644 index 000000000..a73fe1eb3 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishStoneKiltType1.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishStoneKiltType1" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishStoneKiltType2.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishStoneKiltType2.v0.json new file mode 100644 index 000000000..51600018c --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishStoneKiltType2.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishStoneKiltType2" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishStoneLegsType1.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishStoneLegsType1.v0.json new file mode 100644 index 000000000..8bb36ca4c --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishStoneLegsType1.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishStoneLegsType1" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishStoneLegsType2.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishStoneLegsType2.v0.json new file mode 100644 index 000000000..fbb0a499c --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishStoneLegsType2.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishStoneLegsType2" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishTalwar.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishTalwar.v0.json new file mode 100644 index 000000000..eea41e567 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishTalwar.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishTalwar" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GargishWoodenShield.v0.json b/Projects/UOContent/Migrations/Server.Items.GargishWoodenShield.v0.json new file mode 100644 index 000000000..ae0ebdc87 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GargishWoodenShield.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GargishWoodenShield" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GlassStaff.v0.json b/Projects/UOContent/Migrations/Server.Items.GlassStaff.v0.json new file mode 100644 index 000000000..3b6407a0a --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GlassStaff.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GlassStaff" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.GlassSword.v0.json b/Projects/UOContent/Migrations/Server.Items.GlassSword.v0.json new file mode 100644 index 000000000..7778923e5 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.GlassSword.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.GlassSword" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.SerpentstoneStaff.v0.json b/Projects/UOContent/Migrations/Server.Items.SerpentstoneStaff.v0.json new file mode 100644 index 000000000..27adaf3bd --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.SerpentstoneStaff.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.SerpentstoneStaff" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.Talwar.v0.json b/Projects/UOContent/Migrations/Server.Items.Talwar.v0.json new file mode 100644 index 000000000..d69b5f76b --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.Talwar.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.Talwar" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.TinkerTools.v0.json b/Projects/UOContent/Migrations/Server.Items.TinkerTools.v0.json new file mode 100644 index 000000000..0a058eb5d --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.TinkerTools.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.TinkerTools" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.TinkersTools.v0.json b/Projects/UOContent/Migrations/Server.Items.TinkersTools.v0.json new file mode 100644 index 000000000..4b6531b80 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.TinkersTools.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.TinkersTools" +} \ No newline at end of file diff --git a/Projects/UOContent/Misc/CharacterCreation.cs b/Projects/UOContent/Misc/CharacterCreation.cs index 5ac18d60b..0b58f83a8 100644 --- a/Projects/UOContent/Misc/CharacterCreation.cs +++ b/Projects/UOContent/Misc/CharacterCreation.cs @@ -1,6 +1,7 @@ using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; using Server.Accounting; -using Server.Factions; using Server.Items; using Server.Logging; using Server.Mobiles; @@ -12,20 +13,78 @@ namespace Server.Misc { private static readonly ILogger logger = LogFactory.GetLogger(typeof(CharacterCreation)); + // Allowed skills that are not race or era specific + private static readonly HashSet _allowedStartingSkills = new() + { + SkillName.Alchemy, + SkillName.Anatomy, + SkillName.AnimalLore, + SkillName.AnimalTaming, + SkillName.Archery, + SkillName.ArmsLore, + SkillName.Begging, + SkillName.Blacksmith, + SkillName.Fletching, + SkillName.Bushido, + SkillName.Camping, + SkillName.Carpentry, + SkillName.Cartography, + SkillName.Chivalry, + SkillName.Cooking, + SkillName.DetectHidden, + SkillName.Discordance, + SkillName.EvalInt, + SkillName.Fencing, + SkillName.Fishing, + SkillName.Focus, + SkillName.Forensics, + SkillName.Healing, + SkillName.Herding, + SkillName.Hiding, + SkillName.Imbuing, + SkillName.Inscribe, + SkillName.ItemID, + SkillName.Lockpicking, + SkillName.Lumberjacking, + SkillName.Macing, + SkillName.Magery, + SkillName.Meditation, + SkillName.Mining, + SkillName.Musicianship, + SkillName.Mysticism, + SkillName.Necromancy, + SkillName.Ninjitsu, + SkillName.Parry, + SkillName.Peacemaking, + SkillName.Poisoning, + SkillName.Provocation, + SkillName.MagicResist, + SkillName.Snooping, + SkillName.SpiritSpeak, + SkillName.Stealing, + SkillName.Swords, + SkillName.Tactics, + SkillName.Tailoring, + SkillName.TasteID, + SkillName.Throwing, + SkillName.Tinkering, + SkillName.Tracking, + SkillName.Veterinary, + SkillName.Wrestling + }; + private static readonly TimeSpan BadStartMessageDelay = TimeSpan.FromSeconds(3.5); - private static readonly CityInfo m_NewHavenInfo = + private static readonly CityInfo _newHavenInfo = new("New Haven", "The Bountiful Harvest Inn", 3503, 2574, 14, Map.Trammel); - private static Mobile m_Mobile; - public static void Initialize() { // Register our event handler EventSink.CharacterCreated += EventSink_CharacterCreated; } - private static void AddBackpack(Mobile m) + private static void AddBackpack(this Mobile m) { var pack = m.Backpack; @@ -37,564 +96,10 @@ namespace Server.Misc m.AddItem(pack); } - PackItem(new RedBook("a book", m.Name, 20, true)); - PackItem(new Gold(1000)); // Starting gold can be customized here - PackItem(new Dagger()); - PackItem(new Candle()); - } - - private static Item MakeNewbie(Item item) - { - if (!Core.AOS) - { - item.LootType = LootType.Newbied; - } - - return item; - } - - private static void PlaceItemIn(Container parent, int x, int y, Item item) - { - parent.AddItem(item); - item.Location = new Point3D(x, y, 0); - } - - private static Item MakePotionKeg(PotionEffect type, int hue) - { - var keg = new PotionKeg(); - - keg.Held = 100; - keg.Type = type; - keg.Hue = hue; - - return MakeNewbie(keg); - } - - private static void FillBankAOS(Mobile m) - { - var bank = m.BankBox; - - // The new AOS bankboxes don't have powerscrolls, they are automatically 'applied': - - for (var i = 0; i < PowerScroll.Skills.Count; ++i) - { - m.Skills[PowerScroll.Skills[i]].Cap = 120.0; - } - - m.StatCap = 250; - - Container cont; - - // Begin box of money - cont = new WoodenBox { ItemID = 0xE7D, Hue = 0x489 }; - - PlaceItemIn(cont, 16, 51, new BankCheck(500000)); - PlaceItemIn(cont, 28, 51, new BankCheck(250000)); - PlaceItemIn(cont, 40, 51, new BankCheck(100000)); - PlaceItemIn(cont, 52, 51, new BankCheck(100000)); - PlaceItemIn(cont, 64, 51, new BankCheck(50000)); - - PlaceItemIn(cont, 16, 115, new Silver(9000)); - PlaceItemIn(cont, 34, 115, new Gold(60000)); - - PlaceItemIn(bank, 18, 169, cont); - // End box of money - - // Begin bag of potion kegs - cont = new Backpack { Name = "Various Potion Kegs" }; - - PlaceItemIn(cont, 45, 149, MakePotionKeg(PotionEffect.CureGreater, 0x2D)); - PlaceItemIn(cont, 69, 149, MakePotionKeg(PotionEffect.HealGreater, 0x499)); - PlaceItemIn(cont, 93, 149, MakePotionKeg(PotionEffect.PoisonDeadly, 0x46)); - PlaceItemIn(cont, 117, 149, MakePotionKeg(PotionEffect.RefreshTotal, 0x21)); - PlaceItemIn(cont, 141, 149, MakePotionKeg(PotionEffect.ExplosionGreater, 0x74)); - - PlaceItemIn(cont, 93, 82, new Bottle(1000)); - - PlaceItemIn(bank, 53, 169, cont); - // End bag of potion kegs - - // Begin bag of tools - cont = new Bag { Name = "Tool Bag" }; - - PlaceItemIn(cont, 30, 35, new TinkerTools(1000)); - PlaceItemIn(cont, 60, 35, new HousePlacementTool()); - PlaceItemIn(cont, 90, 35, new DovetailSaw(1000)); - PlaceItemIn(cont, 30, 68, new Scissors()); - PlaceItemIn(cont, 45, 68, new MortarPestle(1000)); - PlaceItemIn(cont, 75, 68, new ScribesPen(1000)); - PlaceItemIn(cont, 90, 68, new SmithHammer(1000)); - PlaceItemIn(cont, 30, 118, new TwoHandedAxe()); - PlaceItemIn(cont, 60, 118, new FletcherTools(1000)); - PlaceItemIn(cont, 90, 118, new SewingKit(1000)); - - PlaceItemIn(cont, 36, 51, new RunicHammer(CraftResource.DullCopper, 1000)); - PlaceItemIn(cont, 42, 51, new RunicHammer(CraftResource.ShadowIron, 1000)); - PlaceItemIn(cont, 48, 51, new RunicHammer(CraftResource.Copper, 1000)); - PlaceItemIn(cont, 54, 51, new RunicHammer(CraftResource.Bronze, 1000)); - PlaceItemIn(cont, 61, 51, new RunicHammer(CraftResource.Gold, 1000)); - PlaceItemIn(cont, 67, 51, new RunicHammer(CraftResource.Agapite, 1000)); - PlaceItemIn(cont, 73, 51, new RunicHammer(CraftResource.Verite, 1000)); - PlaceItemIn(cont, 79, 51, new RunicHammer(CraftResource.Valorite, 1000)); - - PlaceItemIn(cont, 36, 55, new RunicSewingKit(CraftResource.SpinedLeather, 1000)); - PlaceItemIn(cont, 42, 55, new RunicSewingKit(CraftResource.HornedLeather, 1000)); - PlaceItemIn(cont, 48, 55, new RunicSewingKit(CraftResource.BarbedLeather, 1000)); - - PlaceItemIn(bank, 118, 169, cont); - // End bag of tools - - // Begin bag of archery ammo - cont = new Bag { Name = "Bag Of Archery Ammo" }; - - PlaceItemIn(cont, 48, 76, new Arrow(5000)); - PlaceItemIn(cont, 72, 76, new Bolt(5000)); - - PlaceItemIn(bank, 118, 124, cont); - // End bag of archery ammo - - // Begin bag of treasure maps - cont = new Bag { Name = "Bag Of Treasure Maps" }; - - PlaceItemIn(cont, 30, 35, new TreasureMap(1, Map.Trammel)); - PlaceItemIn(cont, 45, 35, new TreasureMap(2, Map.Trammel)); - PlaceItemIn(cont, 60, 35, new TreasureMap(3, Map.Trammel)); - PlaceItemIn(cont, 75, 35, new TreasureMap(4, Map.Trammel)); - PlaceItemIn(cont, 90, 35, new TreasureMap(5, Map.Trammel)); - PlaceItemIn(cont, 90, 35, new TreasureMap(6, Map.Trammel)); - - PlaceItemIn(cont, 30, 50, new TreasureMap(1, Map.Trammel)); - PlaceItemIn(cont, 45, 50, new TreasureMap(2, Map.Trammel)); - PlaceItemIn(cont, 60, 50, new TreasureMap(3, Map.Trammel)); - PlaceItemIn(cont, 75, 50, new TreasureMap(4, Map.Trammel)); - PlaceItemIn(cont, 90, 50, new TreasureMap(5, Map.Trammel)); - PlaceItemIn(cont, 90, 50, new TreasureMap(6, Map.Trammel)); - - PlaceItemIn(cont, 55, 100, new Lockpick(30)); - PlaceItemIn(cont, 60, 100, new Pickaxe()); - - PlaceItemIn(bank, 98, 124, cont); - // End bag of treasure maps - - // Begin bag of raw materials - cont = new Bag { Hue = 0x835, Name = "Raw Materials Bag" }; - - PlaceItemIn(cont, 92, 60, new BarbedLeather(5000)); - PlaceItemIn(cont, 92, 68, new HornedLeather(5000)); - PlaceItemIn(cont, 92, 76, new SpinedLeather(5000)); - PlaceItemIn(cont, 92, 84, new Leather(5000)); - - PlaceItemIn(cont, 30, 118, new Cloth(5000)); - PlaceItemIn(cont, 30, 84, new Board(5000)); - PlaceItemIn(cont, 57, 80, new BlankScroll(500)); - - PlaceItemIn(cont, 30, 35, new DullCopperIngot(5000)); - PlaceItemIn(cont, 37, 35, new ShadowIronIngot(5000)); - PlaceItemIn(cont, 44, 35, new CopperIngot(5000)); - PlaceItemIn(cont, 51, 35, new BronzeIngot(5000)); - PlaceItemIn(cont, 58, 35, new GoldIngot(5000)); - PlaceItemIn(cont, 65, 35, new AgapiteIngot(5000)); - PlaceItemIn(cont, 72, 35, new VeriteIngot(5000)); - PlaceItemIn(cont, 79, 35, new ValoriteIngot(5000)); - PlaceItemIn(cont, 86, 35, new IronIngot(5000)); - - PlaceItemIn(cont, 30, 59, new RedScales(5000)); - PlaceItemIn(cont, 36, 59, new YellowScales(5000)); - PlaceItemIn(cont, 42, 59, new BlackScales(5000)); - PlaceItemIn(cont, 48, 59, new GreenScales(5000)); - PlaceItemIn(cont, 54, 59, new WhiteScales(5000)); - PlaceItemIn(cont, 60, 59, new BlueScales(5000)); - - PlaceItemIn(bank, 98, 169, cont); - // End bag of raw materials - - // Begin bag of spell casting stuff - cont = new Backpack { Hue = 0x480, Name = "Spell Casting Stuff" }; - - PlaceItemIn(cont, 45, 105, new Spellbook(ulong.MaxValue)); - PlaceItemIn(cont, 65, 105, new NecromancerSpellbook(0xFFFFUL)); - PlaceItemIn(cont, 85, 105, new BookOfChivalry()); - PlaceItemIn(cont, 105, 105, new BookOfBushido()); // Default ctor = full - PlaceItemIn(cont, 125, 105, new BookOfNinjitsu()); // Default ctor = full - - var runebook = new Runebook(10); - runebook.CurCharges = runebook.MaxCharges; - PlaceItemIn(cont, 145, 105, runebook); - - Item toHue = new BagOfReagents(150) { Hue = 0x2D }; - PlaceItemIn(cont, 45, 150, toHue); - - toHue = new BagOfNecroReagents(150) { Hue = 0x488 }; - PlaceItemIn(cont, 65, 150, toHue); - - PlaceItemIn(cont, 140, 150, new BagOfAllReagents(500)); - - for (var i = 0; i < 9; ++i) - { - PlaceItemIn(cont, 45 + i * 10, 75, new RecallRune()); - } - - PlaceItemIn(cont, 141, 74, new FireHorn()); - - PlaceItemIn(bank, 78, 169, cont); - // End bag of spell casting stuff - - // Begin bag of ethereals - cont = new Backpack { Hue = 0x490, Name = "Bag Of Ethy's!" }; - - PlaceItemIn(cont, 45, 66, new EtherealHorse()); - PlaceItemIn(cont, 69, 82, new EtherealOstard()); - PlaceItemIn(cont, 93, 99, new EtherealLlama()); - PlaceItemIn(cont, 117, 115, new EtherealKirin()); - PlaceItemIn(cont, 45, 132, new EtherealUnicorn()); - PlaceItemIn(cont, 69, 66, new EtherealRidgeback()); - PlaceItemIn(cont, 93, 82, new EtherealSwampDragon()); - PlaceItemIn(cont, 117, 99, new EtherealBeetle()); - - PlaceItemIn(bank, 38, 124, cont); - // End bag of ethereals - - // Begin first bag of artifacts - cont = new Backpack { Hue = 0x48F, Name = "Bag of Artifacts" }; - - PlaceItemIn(cont, 45, 66, new TitansHammer()); - PlaceItemIn(cont, 69, 82, new InquisitorsResolution()); - PlaceItemIn(cont, 93, 99, new BladeOfTheRighteous()); - PlaceItemIn(cont, 117, 115, new ZyronicClaw()); - - PlaceItemIn(bank, 58, 124, cont); - // End first bag of artifacts - - // Begin second bag of artifacts - cont = new Backpack { Hue = 0x48F, Name = "Bag of Artifacts" }; - - PlaceItemIn(cont, 45, 66, new GauntletsOfNobility()); - PlaceItemIn(cont, 69, 82, new MidnightBracers()); - PlaceItemIn(cont, 93, 99, new VoiceOfTheFallenKing()); - PlaceItemIn(cont, 117, 115, new OrnateCrownOfTheHarrower()); - PlaceItemIn(cont, 45, 132, new HelmOfInsight()); - PlaceItemIn(cont, 69, 66, new HolyKnightsBreastplate()); - PlaceItemIn(cont, 93, 82, new ArmorOfFortune()); - PlaceItemIn(cont, 117, 99, new TunicOfFire()); - PlaceItemIn(cont, 45, 115, new LeggingsOfBane()); - PlaceItemIn(cont, 69, 132, new ArcaneShield()); - PlaceItemIn(cont, 93, 66, new Aegis()); - PlaceItemIn(cont, 117, 82, new RingOfTheVile()); - PlaceItemIn(cont, 45, 99, new BraceletOfHealth()); - PlaceItemIn(cont, 69, 115, new RingOfTheElements()); - PlaceItemIn(cont, 93, 132, new OrnamentOfTheMagician()); - PlaceItemIn(cont, 117, 66, new DivineCountenance()); - PlaceItemIn(cont, 45, 82, new JackalsCollar()); - PlaceItemIn(cont, 69, 99, new HuntersHeaddress()); - PlaceItemIn(cont, 93, 115, new HatOfTheMagi()); - PlaceItemIn(cont, 117, 132, new ShadowDancerLeggings()); - PlaceItemIn(cont, 45, 66, new SpiritOfTheTotem()); - PlaceItemIn(cont, 69, 82, new BladeOfInsanity()); - PlaceItemIn(cont, 93, 99, new AxeOfTheHeavens()); - PlaceItemIn(cont, 117, 115, new TheBeserkersMaul()); - PlaceItemIn(cont, 45, 132, new Frostbringer()); - PlaceItemIn(cont, 69, 66, new BreathOfTheDead()); - PlaceItemIn(cont, 93, 82, new TheDragonSlayer()); - PlaceItemIn(cont, 117, 99, new BoneCrusher()); - PlaceItemIn(cont, 45, 115, new StaffOfTheMagi()); - PlaceItemIn(cont, 69, 132, new SerpentsFang()); - PlaceItemIn(cont, 93, 66, new LegacyOfTheDreadLord()); - PlaceItemIn(cont, 117, 82, new TheTaskmaster()); - PlaceItemIn(cont, 45, 99, new TheDryadBow()); - - PlaceItemIn(bank, 78, 124, cont); - // End second bag of artifacts - - // Begin bag of minor artifacts - cont = new Backpack { Hue = 0x48F, Name = "Bag of Minor Artifacts" }; - - PlaceItemIn(cont, 45, 66, new LunaLance()); - PlaceItemIn(cont, 69, 82, new VioletCourage()); - PlaceItemIn(cont, 93, 99, new CavortingClub()); - PlaceItemIn(cont, 117, 115, new CaptainQuacklebushsCutlass()); - PlaceItemIn(cont, 45, 132, new NightsKiss()); - PlaceItemIn(cont, 69, 66, new ShipModelOfTheHMSCape()); - PlaceItemIn(cont, 93, 82, new AdmiralsHeartyRum()); - PlaceItemIn(cont, 117, 99, new CandelabraOfSouls()); - PlaceItemIn(cont, 45, 115, new IolosLute()); - PlaceItemIn(cont, 69, 132, new GwennosHarp()); - PlaceItemIn(cont, 93, 66, new ArcticDeathDealer()); - PlaceItemIn(cont, 117, 82, new EnchantedTitanLegBone()); - PlaceItemIn(cont, 45, 99, new NoxRangersHeavyCrossbow()); - PlaceItemIn(cont, 69, 115, new BlazeOfDeath()); - PlaceItemIn(cont, 93, 132, new DreadPirateHat()); - PlaceItemIn(cont, 117, 66, new BurglarsBandana()); - PlaceItemIn(cont, 45, 82, new GoldBricks()); - PlaceItemIn(cont, 69, 99, new AlchemistsBauble()); - PlaceItemIn(cont, 93, 115, new PhillipsWoodenSteed()); - PlaceItemIn(cont, 117, 132, new PolarBearMask()); - PlaceItemIn(cont, 45, 66, new BowOfTheJukaKing()); - PlaceItemIn(cont, 69, 82, new GlovesOfThePugilist()); - PlaceItemIn(cont, 93, 99, new OrcishVisage()); - PlaceItemIn(cont, 117, 115, new StaffOfPower()); - PlaceItemIn(cont, 45, 132, new ShieldOfInvulnerability()); - PlaceItemIn(cont, 69, 66, new HeartOfTheLion()); - PlaceItemIn(cont, 93, 82, new ColdBlood()); - PlaceItemIn(cont, 117, 99, new GhostShipAnchor()); - PlaceItemIn(cont, 45, 115, new SeahorseStatuette()); - PlaceItemIn(cont, 69, 132, new WrathOfTheDryad()); - PlaceItemIn(cont, 93, 66, new PixieSwatter()); - - for (var i = 0; i < 10; i++) - { - PlaceItemIn(cont, 117, 128, new MessageInABottle(Utility.RandomBool() ? Map.Trammel : Map.Felucca, 4)); - } - - PlaceItemIn(bank, 18, 124, cont); - - if (Core.SE) - { - cont = new Bag { Hue = 0x501, Name = "Tokuno Minor Artifacts" }; - - PlaceItemIn(cont, 42, 70, new Exiler()); - PlaceItemIn(cont, 38, 53, new HanzosBow()); - PlaceItemIn(cont, 45, 40, new TheDestroyer()); - PlaceItemIn(cont, 92, 80, new DragonNunchaku()); - PlaceItemIn(cont, 42, 56, new PeasantsBokuto()); - PlaceItemIn(cont, 44, 71, new TomeOfEnlightenment()); - PlaceItemIn(cont, 35, 35, new ChestOfHeirlooms()); - PlaceItemIn(cont, 29, 0, new HonorableSwords()); - PlaceItemIn(cont, 49, 85, new AncientUrn()); - PlaceItemIn(cont, 51, 58, new FluteOfRenewal()); - PlaceItemIn(cont, 70, 51, new PigmentsOfTokuno()); - PlaceItemIn(cont, 40, 79, new AncientSamuraiDo()); - PlaceItemIn(cont, 51, 61, new LegsOfStability()); - PlaceItemIn(cont, 88, 78, new GlovesOfTheSun()); - PlaceItemIn(cont, 55, 62, new AncientFarmersKasa()); - PlaceItemIn(cont, 55, 83, new ArmsOfTacticalExcellence()); - PlaceItemIn(cont, 50, 85, new DaimyosHelm()); - PlaceItemIn(cont, 52, 78, new BlackLotusHood()); - PlaceItemIn(cont, 52, 79, new DemonForks()); - PlaceItemIn(cont, 33, 49, new PilferedDancerFans()); - - PlaceItemIn(bank, 58, 124, cont); - } - - if (Core.SE) // This bag came only after SE. - { - cont = new Bag { Name = "Bag of Bows" }; - - PlaceItemIn(cont, 31, 84, new Bow()); - PlaceItemIn(cont, 78, 74, new CompositeBow()); - PlaceItemIn(cont, 53, 71, new Crossbow()); - PlaceItemIn(cont, 56, 39, new HeavyCrossbow()); - PlaceItemIn(cont, 82, 72, new RepeatingCrossbow()); - PlaceItemIn(cont, 49, 45, new Yumi()); - - for (var i = 0; i < cont.Items.Count; i++) - { - if (cont.Items[i] is BaseRanged bow) - { - bow.Attributes.WeaponSpeed = 35; - bow.Attributes.WeaponDamage = 35; - } - } - - PlaceItemIn(bank, 108, 135, cont); - } - } - - private static void FillBankbox(Mobile m) - { - if (Core.AOS) - { - FillBankAOS(m); - return; - } - - var bank = m.BankBox; - - bank.DropItem(new BankCheck(1000000)); - - // Full spellbook - var book = new Spellbook { Content = ulong.MaxValue }; - - bank.DropItem(book); - - var bag = new Bag(); - - for (var i = 0; i < 5; ++i) - { - bag.DropItem(new Moonstone(MoonstoneType.Felucca)); - } - - // Felucca moonstones - bank.DropItem(bag); - - bag = new Bag(); - - for (var i = 0; i < 5; ++i) - { - bag.DropItem(new Moonstone(MoonstoneType.Trammel)); - } - - // Trammel moonstones - bank.DropItem(bag); - - // Treasure maps - bank.DropItem(new TreasureMap(1, Map.Trammel)); - bank.DropItem(new TreasureMap(2, Map.Trammel)); - bank.DropItem(new TreasureMap(3, Map.Trammel)); - bank.DropItem(new TreasureMap(4, Map.Trammel)); - bank.DropItem(new TreasureMap(5, Map.Trammel)); - - // Bag containing 50 of each reagent - bank.DropItem(new BagOfReagents()); - - // Craft tools - bank.DropItem(MakeNewbie(new Scissors())); - bank.DropItem(MakeNewbie(new SewingKit(1000))); - bank.DropItem(MakeNewbie(new SmithHammer(1000))); - bank.DropItem(MakeNewbie(new FletcherTools(1000))); - bank.DropItem(MakeNewbie(new DovetailSaw(1000))); - bank.DropItem(MakeNewbie(new MortarPestle(1000))); - bank.DropItem(MakeNewbie(new ScribesPen(1000))); - bank.DropItem(MakeNewbie(new TinkerTools(1000))); - - // A few dye tubs - bank.DropItem(new Dyes()); - bank.DropItem(new DyeTub()); - bank.DropItem(new DyeTub()); - bank.DropItem(new BlackDyeTub()); - - var darkRedTub = new DyeTub { DyedHue = 0x485, Redyable = false }; - bank.DropItem(darkRedTub); - - // Some food - bank.DropItem(MakeNewbie(new Apple(1000))); - - // Resources - bank.DropItem(MakeNewbie(new Feather(1000))); - bank.DropItem(MakeNewbie(new BoltOfCloth(1000))); - bank.DropItem(MakeNewbie(new BlankScroll(1000))); - bank.DropItem(MakeNewbie(new Hides(1000))); - bank.DropItem(MakeNewbie(new Bandage(1000))); - bank.DropItem(MakeNewbie(new Bottle(1000))); - bank.DropItem(MakeNewbie(new Log(1000))); - - bank.DropItem(MakeNewbie(new IronIngot(5000))); - bank.DropItem(MakeNewbie(new DullCopperIngot(5000))); - bank.DropItem(MakeNewbie(new ShadowIronIngot(5000))); - bank.DropItem(MakeNewbie(new CopperIngot(5000))); - bank.DropItem(MakeNewbie(new BronzeIngot(5000))); - bank.DropItem(MakeNewbie(new GoldIngot(5000))); - bank.DropItem(MakeNewbie(new AgapiteIngot(5000))); - bank.DropItem(MakeNewbie(new VeriteIngot(5000))); - bank.DropItem(MakeNewbie(new ValoriteIngot(5000))); - - // Reagents - bank.DropItem(MakeNewbie(new BlackPearl(1000))); - bank.DropItem(MakeNewbie(new Bloodmoss(1000))); - bank.DropItem(MakeNewbie(new Garlic(1000))); - bank.DropItem(MakeNewbie(new Ginseng(1000))); - bank.DropItem(MakeNewbie(new MandrakeRoot(1000))); - bank.DropItem(MakeNewbie(new Nightshade(1000))); - bank.DropItem(MakeNewbie(new SulfurousAsh(1000))); - bank.DropItem(MakeNewbie(new SpidersSilk(1000))); - - // Some extra starting gold - bank.DropItem(MakeNewbie(new Gold(9000))); - - // 5 blank recall runes - for (var i = 0; i < 5; ++i) - { - bank.DropItem(MakeNewbie(new RecallRune())); - } - - AddPowerScrolls(bank); - } - - private static void AddPowerScrolls(BankBox bank) - { - var bag = new Bag(); - - for (var i = 0; i < PowerScroll.Skills.Count; ++i) - { - bag.DropItem(new PowerScroll(PowerScroll.Skills[i], 120.0)); - } - - bag.DropItem(new StatCapScroll(250)); - - bank.DropItem(bag); - } - - private static void AddShirt(Mobile m, int shirtHue) - { - var hue = Utility.ClipDyedHue(shirtHue & 0x3FFF); - - if (m.Race == Race.Elf) - { - EquipItem(new ElvenShirt(hue), true); - } - else - { - switch (Utility.Random(3)) - { - case 0: - EquipItem(new Shirt(hue), true); - break; - case 1: - EquipItem(new FancyShirt(hue), true); - break; - case 2: - EquipItem(new Doublet(hue), true); - break; - } - } - } - - private static void AddPants(Mobile m, int pantsHue) - { - var hue = Utility.ClipDyedHue(pantsHue & 0x3FFF); - - if (m.Race == Race.Elf) - { - EquipItem(new ElvenPants(hue), true); - } - else - { - if (m.Female) - { - switch (Utility.Random(2)) - { - case 0: - EquipItem(new Skirt(hue), true); - break; - case 1: - EquipItem(new Kilt(hue), true); - break; - } - } - else - { - switch (Utility.Random(2)) - { - case 0: - EquipItem(new LongPants(hue), true); - break; - case 1: - EquipItem(new ShortPants(hue), true); - break; - } - } - } - } - - private static void AddShoes(Mobile m) - { - if (m.Race == Race.Elf) - { - EquipItem(new ElvenBoots(), true); - } - else - { - EquipItem(new Shoes(Utility.RandomYellowHue()), true); - } + m.PackItem(new RedBook("a book", m.Name, 20, true)); + m.PackItem(new Gold(1000)); // Starting gold can be customized here + m.PackItem(new Dagger()); + m.PackItem(new Candle()); } private static Mobile CreateMobile(Account a) @@ -638,7 +143,6 @@ namespace Server.Misc } args.Mobile = newChar; - m_Mobile = newChar; newChar.Player = true; newChar.AccessLevel = args.Account.AccessLevel; @@ -661,10 +165,10 @@ namespace Server.Misc SetName(newChar, args.Name); - AddBackpack(newChar); + newChar.AddBackpack(); - SetStats(newChar, state, args.Str, args.Dex, args.Int); - SetSkills(newChar, args.Skills, args.Profession); + SetStats(newChar, state, args.Stats, args.Profession); + SetSkills(newChar, args.Skills, args.Profession, args.ShirtHue, args.PantsHue); var race = newChar.Race; @@ -680,16 +184,9 @@ namespace Server.Misc newChar.FacialHairHue = race.ClipHairHue(args.BeardHue & 0x3FFF); } - if (args.Profession <= 3) - { - AddShirt(newChar, args.ShirtHue); - AddPants(newChar, args.PantsHue); - AddShoes(newChar); - } - if (TestCenter.Enabled) { - FillBankbox(newChar); + TestCenter.FillBankbox(newChar); } if (young) @@ -717,13 +214,13 @@ namespace Server.Misc } public static bool VerifyProfession(int profession) => - profession >= 0 && (profession < 4 || Core.AOS && profession < 6 || Core.SE && profession < 8); + profession >= 0 && profession < ProfessionInfo.Professions.Length; private static CityInfo GetStartLocation(CharacterCreatedEventArgs args, bool isYoung) { if (Core.ML) { - return m_NewHavenInfo; // We don't get the client Version until AFTER Character creation + return _newHavenInfo; // We don't get the client Version until AFTER Character creation } var useHaven = isYoung; @@ -731,9 +228,11 @@ namespace Server.Misc var flags = args.State?.Flags ?? ClientFlags.None; var m = args.Mobile; - switch (args.Profession) + var profession = ProfessionInfo.Professions[args.Profession]; + + switch (profession?.Name.ToLowerInvariant()) { - case 4: // Necro + case "necromancer": { if ((flags & ClientFlags.Malas) != 0) { @@ -753,11 +252,11 @@ namespace Server.Misc break; } - case 5: // Paladin + case "paladin": { - return m_NewHavenInfo; + return _newHavenInfo; } - case 6: // Samurai + case "samurai": { if ((flags & ClientFlags.Tokuno) != 0) { @@ -777,7 +276,7 @@ namespace Server.Misc break; } - case 7: // Ninja + case "ninja": { if ((flags & ClientFlags.Tokuno) != 0) { @@ -799,51 +298,34 @@ namespace Server.Misc } } - return useHaven ? m_NewHavenInfo : args.City; + return useHaven ? _newHavenInfo : args.City; } - private static void FixStats(ref int str, ref int dex, ref int intel, int max) + private static void SetStats(Mobile m, NetState state, StatNameValue[] stats, int prof) { - var vMax = max - 30; + var maxStats = state.NewCharacterCreation ? 90 : 80; - var vStr = Math.Max(str - 10, 0); - var vDex = Math.Max(dex - 10, 0); - var vInt = Math.Max(intel - 10, 0); + var str = 0; + var dex = 0; + var intel = 0; - var total = vStr + vDex + vInt; - - if (total == 0 || total == vMax) + if (prof > 0) { - return; + stats = ProfessionInfo.Professions[prof]?.Stats ?? stats; } - var scalar = vMax / (double)total; + for (var i = 0; i < stats.Length; i++) + { + var (statType, value) = stats[i]; + switch (statType) + { + case StatType.Str: str = value; break; + case StatType.Dex: dex = value; break; + case StatType.Int: intel = value; break; + } + } - vStr = (int)(vStr * scalar); - vDex = (int)(vDex * scalar); - vInt = (int)(vInt * scalar); - - FixStat(ref vStr, vStr + vDex + vInt - vMax, vMax); - FixStat(ref vDex, vStr + vDex + vInt - vMax, vMax); - FixStat(ref vInt, vStr + vDex + vInt - vMax, vMax); - - str = vStr + 10; - dex = vDex + 10; - intel = vInt + 10; - } - - private static void FixStat(ref int stat, int diff, int max) - { - stat = Math.Clamp(stat + diff, 0, max); - } - - private static void SetStats(Mobile m, NetState state, int str, int dex, int intel) - { - var max = state.NewCharacterCreation ? 90 : 80; - - FixStats(ref str, ref dex, ref intel, max); - - if (str < 10 || str > 60 || dex < 10 || dex > 60 || intel < 10 || intel > 60 || str + dex + intel != max) + if (str is < 10 or > 60 || dex is < 10 or > 60 || intel is < 10 or > 60 || str + dex + intel != maxStats) { str = 10; dex = 10; @@ -865,170 +347,63 @@ namespace Server.Misc m.Name = name; } - private static bool ValidSkills(SkillNameValue[] skills) + private static bool ValidateSkills(int raceFlag, SkillNameValue[] skills) { var total = 0; for (var i = 0; i < skills.Length; ++i) { - if (skills[i].Value < 0 || skills[i].Value > 50) + var (name, value) = skills[i]; + var notValid = value is < 0 or > 50 || !_allowedStartingSkills.Contains(name) || + !Core.AOS && name is SkillName.Necromancy or SkillName.Chivalry || + !Core.SE && name is SkillName.Ninjitsu or SkillName.Bushido || + Core.SA && (raceFlag == Race.AllowGargoylesOnly && name == SkillName.Archery || + raceFlag != Race.AllowGargoylesOnly && name == SkillName.Throwing) || + !Core.SA && name is SkillName.Throwing or SkillName.Imbuing; + + if (notValid) { - return false; + skills[i] = default; + continue; } - total += skills[i].Value; + total += value; for (var j = i + 1; j < skills.Length; ++j) { - if (skills[j].Value > 0 && skills[j].Name == skills[i].Name) + var (nameCheck, valueCheck) = skills[j]; + if (valueCheck > 0 && nameCheck == name) { return false; } } } - return total == 100 || total == 120; + return total is 100 or 120; } - private static void SetSkills(Mobile m, SkillNameValue[] skills, int prof) + private static void SetSkills(Mobile m, SkillNameValue[] skills, int prof, int shirtHue, int pantsHue) { - switch (prof) + ProfessionInfo profession = null; + if (prof > 0) { - case 1: // Warrior - { - skills = new[] - { - new SkillNameValue(SkillName.Anatomy, 30), - new SkillNameValue(SkillName.Healing, 45), - new SkillNameValue(SkillName.Swords, 35), - new SkillNameValue(SkillName.Tactics, 50) - }; - - break; - } - case 2: // Magician - { - skills = new[] - { - new SkillNameValue(SkillName.EvalInt, 30), - new SkillNameValue(SkillName.Wrestling, 30), - new SkillNameValue(SkillName.Magery, 50), - new SkillNameValue(SkillName.Meditation, 50) - }; - - break; - } - case 3: // Blacksmith - { - skills = new[] - { - new SkillNameValue(SkillName.Mining, 30), - new SkillNameValue(SkillName.ArmsLore, 30), - new SkillNameValue(SkillName.Blacksmith, 50), - new SkillNameValue(SkillName.Tinkering, 50) - }; - - break; - } - case 4: // Necromancer - { - skills = new[] - { - new SkillNameValue(SkillName.Necromancy, 50), - new SkillNameValue(SkillName.Focus, 30), - new SkillNameValue(SkillName.SpiritSpeak, 30), - new SkillNameValue(SkillName.Swords, 30), - new SkillNameValue(SkillName.Tactics, 20) - }; - - break; - } - case 5: // Paladin - { - skills = new[] - { - new SkillNameValue(SkillName.Chivalry, 51), - new SkillNameValue(SkillName.Swords, 49), - new SkillNameValue(SkillName.Focus, 30), - new SkillNameValue(SkillName.Tactics, 30) - }; - - break; - } - case 6: // Samurai - { - skills = new[] - { - new SkillNameValue(SkillName.Bushido, 50), - new SkillNameValue(SkillName.Swords, 50), - new SkillNameValue(SkillName.Anatomy, 30), - new SkillNameValue(SkillName.Healing, 30) - }; - break; - } - case 7: // Ninja - { - skills = new[] - { - new SkillNameValue(SkillName.Ninjitsu, 50), - new SkillNameValue(SkillName.Hiding, 50), - new SkillNameValue(SkillName.Fencing, 30), - new SkillNameValue(SkillName.Stealth, 30) - }; - break; - } - default: - { - if (!ValidSkills(skills)) - { - return; - } - - break; - } + profession = ProfessionInfo.Professions[prof]; + skills = ProfessionInfo.Professions[prof]?.Skills ?? skills; + } + else if (!ValidateSkills(m.Race.RaceFlag, skills)) // This does not check for skills that are not allowed by expansion + { + return; } var addSkillItems = true; var elf = m.Race == Race.Elf; var gargoyle = m.Race == Race.Gargoyle; - switch (prof) + switch (profession?.Name.ToLowerInvariant()) { - case 1: // Warrior + case "necromancer": { - if (elf) - { - EquipItem(new Circlet()); - EquipItem(new HideGorget()); - EquipItem(new HideChest()); - EquipItem(new HidePauldrons()); - EquipItem(new HideGloves()); - EquipItem(new HidePants()); - EquipItem(new ElvenBoots()); - } - else if (gargoyle) - { - //EquipItem(new DreadSword()); //NOT IMPLEMENTED - EquipItem(new GargishLeatherChestType1()); - EquipItem(new GargishLeatherArmsType1()); - EquipItem(new GargishLeatherKiltType1()); - EquipItem(new GargishLeatherLegsType1()); - } - else - { - EquipItem(new Bascinet()); - EquipItem(new StuddedGorget()); - EquipItem(new StuddedChest()); - EquipItem(new StuddedArms()); - EquipItem(new StuddedGloves()); - EquipItem(new StuddedLegs()); - EquipItem(new ThighBoots()); - } - break; - } - case 4: // Necromancer - { - Container regs = new BagOfNecroReagents(); + Container regs = new BagOfNecroReagents { LootType = LootType.Regular }; if (!Core.AOS) { @@ -1038,221 +413,250 @@ namespace Server.Misc } } - PackItem(regs); + m.PackItem(regs); - regs.LootType = LootType.Regular; - - EquipItem(new BoneHelm()); + EquipItem(m, new BoneHelm()); if (elf) { - EquipItem(new ElvenMachete()); - EquipItem(NecroHue(new LeafChest())); - EquipItem(NecroHue(new LeafArms())); - EquipItem(NecroHue(new LeafGloves())); - EquipItem(NecroHue(new LeafGorget())); - EquipItem(NecroHue(new LeafLegs())); - EquipItem(new ElvenBoots()); + EquipItem(m, new ElvenMachete()); + EquipItem(m, NecroHue(new LeafChest())); + EquipItem(m, NecroHue(new LeafArms())); + EquipItem(m, NecroHue(new LeafGloves())); + EquipItem(m, NecroHue(new LeafGorget())); + EquipItem(m, NecroHue(new LeafLegs())); + EquipItem(m, new ElvenBoots()); } else if (gargoyle) { - //EquipItem(new GlassSword()); //NOT IMPLEMENTED - EquipItem(new GargishLeatherChestType1()); - EquipItem(new GargishLeatherArmsType1()); - EquipItem(new GargishLeatherKiltType1()); - EquipItem(new GargishLeatherLegsType1()); + EquipItem(m, new GlassSword()); + EquipItem(m, NecroHue(m.Female ? new GargishLeatherChestType2() : new GargishLeatherChestType1())); + EquipItem(m, NecroHue(m.Female ? new GargishLeatherArmsType2() : new GargishLeatherArmsType1())); + EquipItem(m, NecroHue(m.Female ? new GargishLeatherKiltType2() : new GargishLeatherKiltType1())); + EquipItem(m, NecroHue(m.Female ? new GargishLeatherLegsType2() : new GargishLeatherLegsType1())); } else { - EquipItem(new BoneHarvester()); - EquipItem(NecroHue(new LeatherChest())); - EquipItem(NecroHue(new LeatherArms())); - EquipItem(NecroHue(new LeatherGloves())); - EquipItem(NecroHue(new LeatherGorget())); - EquipItem(NecroHue(new LeatherLegs())); - EquipItem(NecroHue(new Skirt())); - EquipItem(new Sandals(0x8FD)); + EquipItem(m, new BoneHarvester()); + EquipItem(m, NecroHue(new LeatherChest())); + EquipItem(m, NecroHue(new LeatherArms())); + EquipItem(m, NecroHue(new LeatherGloves())); + EquipItem(m, NecroHue(new LeatherGorget())); + EquipItem(m, NecroHue(new LeatherLegs())); + EquipItem(m, NecroHue(new Skirt())); + EquipItem(m, new Sandals(0x8FD)); } - Spellbook - book = new NecromancerSpellbook( - (ulong)0x8981 - ); // animate dead, evil omen, pain spike, summon familiar, wraith form - - PackItem(book); - - book.LootType = LootType.Blessed; + // animate dead, evil omen, pain spike, summon familiar, wraith form + m.PackItem(new NecromancerSpellbook(0x8981ul) { LootType = LootType.Blessed }); addSkillItems = false; break; } - case 5: // Paladin + case "paladin": { if (elf) { - EquipItem(new ElvenMachete()); - EquipItem(new WingedHelm()); - EquipItem(new LeafGorget()); - EquipItem(new LeafArms()); - EquipItem(new LeafChest()); - EquipItem(new LeafLegs()); - EquipItem(new LeafGloves()); - EquipItem(new ElvenBoots()); // Verify hue + EquipItem(m, new ElvenMachete()); + EquipItem(m, new WingedHelm()); + EquipItem(m, new LeafGorget()); + EquipItem(m, new LeafArms()); + EquipItem(m, new LeafChest()); + EquipItem(m, new LeafLegs()); + EquipItem(m, new LeafGloves()); + EquipItem(m, new ElvenBoots()); // Verify hue } else if (gargoyle) { - //EquipItem(new GlassSword()); // IMPLEMENTION NEEDED - //EquipItem(new GargishStoneChestType1()); - //EquipItem(new GargishStoneArmsType1()); - //EquipItem(new GargishStoneKiltType1()); - //EquipItem(new GargishStoneLegsType1()); + EquipItem(m, new GlassSword()); + EquipItem(m, m.Female ? new GargishStoneChestType2() : new GargishStoneChestType1()); + EquipItem(m, m.Female ? new GargishStoneArmsType2() : new GargishStoneArmsType1()); + EquipItem(m, m.Female ? new GargishStoneKiltType2() : new GargishStoneKiltType1()); + EquipItem(m, m.Female ? new GargishStoneLegsType2() : new GargishStoneLegsType1()); } else { - EquipItem(new Broadsword()); - EquipItem(new Helmet()); - EquipItem(new PlateGorget()); - EquipItem(new RingmailArms()); - EquipItem(new RingmailChest()); - EquipItem(new RingmailLegs()); - EquipItem(new RingmailGloves()); - EquipItem(new ThighBoots(0x748)); - EquipItem(new Cloak(0xCF)); - EquipItem(new BodySash(0xCF)); + EquipItem(m, new Broadsword()); + EquipItem(m, new Helmet()); + EquipItem(m, new PlateGorget()); + EquipItem(m, new RingmailArms()); + EquipItem(m, new RingmailChest()); + EquipItem(m, new RingmailLegs()); + EquipItem(m, new RingmailGloves()); + EquipItem(m, new ThighBoots(0x748)); + EquipItem(m, new Cloak(0xCF)); + EquipItem(m, new BodySash(0xCF)); } - Spellbook book = new BookOfChivalry(); - - PackItem(book); - - book.LootType = LootType.Blessed; + m.PackItem(new BookOfChivalry { LootType = LootType.Blessed }); addSkillItems = false; break; } - - case 6: // Samurai + case "samurai": { addSkillItems = false; if (elf) { - EquipItem(new RavenHelm()); - EquipItem(new HakamaShita(0x2C3)); - EquipItem(new Hakama(0x2C3)); - EquipItem(new SamuraiTabi(0x2C3)); - EquipItem(new TattsukeHakama(0x22D)); - EquipItem(new Bokuto()); + EquipItem(m, new RavenHelm()); + EquipItem(m, new HakamaShita(0x2C3)); + EquipItem(m, new Hakama(0x2C3)); + EquipItem(m, new SamuraiTabi(0x2C3)); + EquipItem(m, new TattsukeHakama(0x22D)); + EquipItem(m, new Bokuto()); } else if (gargoyle) { - //EquipItem(new GargishTalwar()); // IMPLEMENTION NEEDED - EquipItem(new GargishLeatherChestType1()); - EquipItem(new GargishLeatherArmsType1()); - EquipItem(new GargishLeatherKiltType1()); - EquipItem(new GargishLeatherLegsType1()); + EquipItem(m, new GargishTalwar()); + EquipItem(m, m.Female ? new GargishLeatherChestType2() : new GargishLeatherChestType1()); + EquipItem(m, m.Female ? new GargishLeatherArmsType2() : new GargishLeatherArmsType1()); + EquipItem(m, m.Female ? new GargishLeatherKiltType2() : new GargishLeatherKiltType1()); + EquipItem(m, m.Female ? new GargishLeatherLegsType2() : new GargishLeatherLegsType1()); } else { - EquipItem(new LeatherJingasa()); - EquipItem(new HakamaShita(0x2C3)); - EquipItem(new Hakama(0x2C3)); - EquipItem(new SamuraiTabi(0x2C3)); - EquipItem(new TattsukeHakama(0x22D)); - EquipItem(new Bokuto()); + EquipItem(m, new LeatherJingasa()); + EquipItem(m, new HakamaShita(0x2C3)); + EquipItem(m, new Hakama(0x2C3)); + EquipItem(m, new SamuraiTabi(0x2C3)); + EquipItem(m, new TattsukeHakama(0x22D)); + EquipItem(m, new Bokuto()); } - PackItem(new Scissors()); - PackItem(new Bandage(50)); - - Spellbook book = new BookOfBushido(); - PackItem(book); + m.PackItem(new Scissors()); + m.PackItem(new Bandage(50)); + m.PackItem(new BookOfBushido()); break; } - case 7: // Ninja + case "ninja": { addSkillItems = false; - int[] hues = { 0x1A8, 0xEC, 0x99, 0x90, 0xB5, 0x336, 0x89 }; // TODO: Verify that's ALL the hues for that above. if (elf) { - EquipItem(new AssassinSpike()); - EquipItem(new TattsukeHakama(hues.RandomElement())); - EquipItem(new HakamaShita(0x2C3)); - EquipItem(new NinjaTabi(0x2C3)); - EquipItem(new Kasa()); + EquipItem(m, new AssassinSpike()); + EquipItem(m, new TattsukeHakama(hues.RandomElement())); + EquipItem(m, new HakamaShita(0x2C3)); + EquipItem(m, new NinjaTabi(0x2C3)); + EquipItem(m, new Kasa()); } else if (gargoyle) { - //EquipItem(new DualPointedSpear()); //IMPLEMENTION NEEDED - EquipItem(new GargishLeatherChestType1()); - EquipItem(new GargishLeatherArmsType1()); - EquipItem(new GargishLeatherKiltType1()); - EquipItem(new GargishLeatherLegsType1()); + EquipItem(m, new DualPointedSpear()); + EquipItem(m, m.Female ? new GargishLeatherChestType2() : new GargishLeatherChestType1()); + EquipItem(m, m.Female ? new GargishLeatherArmsType2() : new GargishLeatherArmsType1()); + EquipItem(m, m.Female ? new GargishLeatherKiltType2() : new GargishLeatherKiltType1()); + EquipItem(m, m.Female ? new GargishLeatherLegsType2() : new GargishLeatherLegsType1()); } else { - EquipItem(new Tekagi()); - EquipItem(new TattsukeHakama(hues.RandomElement())); - EquipItem(new HakamaShita(0x2C3)); - EquipItem(new NinjaTabi(0x2C3)); - EquipItem(new Kasa()); + EquipItem(m, new Tekagi()); + EquipItem(m, new TattsukeHakama(hues.RandomElement())); + EquipItem(m, new HakamaShita(0x2C3)); + EquipItem(m, new NinjaTabi(0x2C3)); + EquipItem(m, new Kasa()); } - PackItem(new SmokeBomb()); - PackItem(new SmokeBomb()); - PackItem(new SmokeBomb()); - PackItem(new SmokeBomb()); - PackItem(new SmokeBomb()); - - Spellbook book = new BookOfNinjitsu(); - PackItem(book); - + m.PackItem(new SmokeBomb()); + m.PackItem(new SmokeBomb()); + m.PackItem(new SmokeBomb()); + m.PackItem(new SmokeBomb()); + m.PackItem(new SmokeBomb()); + m.PackItem(new BookOfNinjitsu()); + break; + } + case "swordsman": + case "fencer": + case "warrior": + case "mace fighter": + { + if (elf) + { + EquipItem(m, new Circlet()); + EquipItem(m, new HideGorget()); + EquipItem(m, new HideChest()); + EquipItem(m, new HidePauldrons()); + EquipItem(m, new HideGloves()); + EquipItem(m, new HidePants()); + EquipItem(m, new ElvenBoots()); + } + else if (gargoyle) + { + EquipItem(m, m.Female ? new GargishLeatherChestType2() : new GargishLeatherChestType1()); + EquipItem(m, m.Female ? new GargishLeatherArmsType2() : new GargishLeatherArmsType1()); + EquipItem(m, m.Female ? new GargishLeatherKiltType2() : new GargishLeatherKiltType1()); + EquipItem(m, m.Female ? new GargishLeatherLegsType2() : new GargishLeatherLegsType1()); + } + else + { + EquipItem(m, new Bascinet()); + EquipItem(m, new StuddedGorget()); + EquipItem(m, new StuddedChest()); + EquipItem(m, new StuddedArms()); + EquipItem(m, new StuddedGloves()); + EquipItem(m, new StuddedLegs()); + EquipItem(m, new ThighBoots()); + } break; } } + if (addSkillItems) + { + m.AddShirt(shirtHue); + m.AddPants(pantsHue); + m.AddShoes(); + + // All elves get a wild staff + if (elf) + { + EquipItem(m, new WildStaff()); + } + } + for (var i = 0; i < skills.Length; ++i) { - var snv = skills[i]; - - if (snv.Value > 0 && (snv.Name != SkillName.Stealth || prof == 7) && snv.Name != SkillName.RemoveTrap && - snv.Name != SkillName.Spellweaving) + var (name, value) = skills[i]; + if (value <= 0) { - var skill = m.Skills[snv.Name]; + continue; + } - if (skill != null) - { - skill.BaseFixedPoint = snv.Value * 10; + var skill = m.Skills[name]; - if (addSkillItems) - { - AddSkillItems(snv.Name, m); - } - } + if (skill != null) + { + skill.BaseFixedPoint = value * 10; + m.AddSkillItems(name); } } } - private static void EquipItem(Item item, bool mustEquip = false) + private static void EquipItem(Mobile m, Item item, bool mustEquip = false) { + if (item == null) + { + return; + } + if (!Core.AOS) { item.LootType = LootType.Newbied; } - if (m_Mobile?.EquipItem(item) == true) + if (m?.EquipItem(item) == true) { return; } - var pack = m_Mobile?.Backpack; + var pack = m?.Backpack; if (!mustEquip && pack != null) { @@ -1264,14 +668,14 @@ namespace Server.Misc } } - private static void PackItem(Item item) + private static void PackItem(this Mobile m, Item item) { if (!Core.AOS) { item.LootType = LootType.Newbied; } - var pack = m_Mobile.Backpack; + var pack = m.Backpack; if (pack != null) { @@ -1283,108 +687,123 @@ namespace Server.Misc } } - private static void PackInstrument() + private static void AddShirt(this Mobile m, int shirtHue) { - switch (Utility.Random(6)) + var hue = Utility.ClipDyedHue(shirtHue & 0x3FFF); + var raceFlag = m.Race.RaceFlag; + + var shirt = raceFlag switch { - case 0: - PackItem(new Drums()); - break; - case 1: - PackItem(new Harp()); - break; - case 2: - PackItem(new LapHarp()); - break; - case 3: - PackItem(new Lute()); - break; - case 4: - PackItem(new Tambourine()); - break; - case 5: - PackItem(new TambourineTassel()); - break; + Race.AllowElvesOnly => new ElvenShirt(hue), + Race.AllowGargoylesOnly when m.Female => new GargishClothChestType2 { Hue = hue }, + Race.AllowGargoylesOnly => new GargishClothChestType1 { Hue = hue }, + // Humans + _ => (Item)(Utility.Random(3) switch + { + 0 => new Shirt(hue), + 1 => new FancyShirt(hue), + _ => new Doublet(hue) + }) + }; + + EquipItem(m, shirt); + } + + private static void AddPants(this Mobile m, int pantsHue) + { + var hue = Utility.ClipDyedHue(pantsHue & 0x3FFF); + var raceFlag = m.Race.RaceFlag; + var female = m.Female; + + var pants = raceFlag switch + { + Race.AllowElvesOnly => new ElvenPants(hue), + Race.AllowGargoylesOnly when female => new GargishClothLegsType2 { Hue = hue }, + Race.AllowGargoylesOnly => new GargishClothLegsType1 { Hue = hue }, + // Humans + _ => (Item)(Utility.RandomBool() switch + { + true when female => new Skirt(hue), + true => new LongPants(hue), + false when female => new Kilt(hue), + false => new ShortPants(hue) + }) + }; + + EquipItem(m, pants); + } + + private static void AddShoes(this Mobile m) + { + if (m.Race == Race.Elf) + { + EquipItem(m, new ElvenBoots()); + } + else if (m.Race == Race.Human) + { + EquipItem(m, new Shoes(Utility.RandomYellowHue())); } } - private static void PackScroll(int circle) + private static void PackInstrument(this Mobile m) { - switch (Utility.Random(8) * (circle + 1)) + Item instrument = Utility.Random(6) switch { - case 0: - PackItem(new ClumsyScroll()); - break; - case 1: - PackItem(new CreateFoodScroll()); - break; - case 2: - PackItem(new FeeblemindScroll()); - break; - case 3: - PackItem(new HealScroll()); - break; - case 4: - PackItem(new MagicArrowScroll()); - break; - case 5: - PackItem(new NightSightScroll()); - break; - case 6: - PackItem(new ReactiveArmorScroll()); - break; - case 7: - PackItem(new WeakenScroll()); - break; - case 8: - PackItem(new AgilityScroll()); - break; - case 9: - PackItem(new CunningScroll()); - break; - case 10: - PackItem(new CureScroll()); - break; - case 11: - PackItem(new HarmScroll()); - break; - case 12: - PackItem(new MagicTrapScroll()); - break; - case 13: - PackItem(new MagicUnTrapScroll()); - break; - case 14: - PackItem(new ProtectionScroll()); - break; - case 15: - PackItem(new StrengthScroll()); - break; - case 16: - PackItem(new BlessScroll()); - break; - case 17: - PackItem(new FireballScroll()); - break; - case 18: - PackItem(new MagicLockScroll()); - break; - case 19: - PackItem(new PoisonScroll()); - break; - case 20: - PackItem(new TelekinesisScroll()); - break; - case 21: - PackItem(new TeleportScroll()); - break; - case 22: - PackItem(new UnlockScroll()); - break; - case 23: - PackItem(new WallOfStoneScroll()); - break; - } + 0 => new Drums(), + 1 => new Harp(), + 2 => new LapHarp(), + 3 => new Lute(), + 4 => new Tambourine(), + _ => new TambourineTassel() + }; + + m.PackItem(instrument); + } + + private static void PackScroll(this Mobile m, int circle) + { + Item item = (Utility.Random(8) * (circle + 1)) switch + { + 0 => new ClumsyScroll(), + 1 => new CreateFoodScroll(), + 2 => new FeeblemindScroll(), + 3 => new HealScroll(), + 4 => new MagicArrowScroll(), + 5 => new NightSightScroll(), + 6 => new ReactiveArmorScroll(), + 7 => new WeakenScroll(), + 8 => new AgilityScroll(), + 9 => new CunningScroll(), + 10 => new CureScroll(), + 11 => new HarmScroll(), + 12 => new MagicTrapScroll(), + 13 => new MagicUnTrapScroll(), + 14 => new ProtectionScroll(), + 15 => new StrengthScroll(), + 16 => new BlessScroll(), + 17 => new FireballScroll(), + 18 => new MagicLockScroll(), + 19 => new PoisonScroll(), + 20 => new TelekinesisScroll(), + 21 => new TeleportScroll(), + 22 => new UnlockScroll(), + _ => new WallOfStoneScroll() + }; + + m.PackItem(item); + } + + private static void PackTinkerPart(this Mobile m) + { + Item item = Utility.Random(4) switch + { + 0 => new Axle(), + 1 => new Gears(), + 2 => new Hinge(), + 3 => new Springs() + }; + + m.PackItem(item); } private static Item NecroHue(Item item) @@ -1394,324 +813,296 @@ namespace Server.Misc return item; } - private static void AddSkillItems(SkillName skill, Mobile m) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Item Robe(int raceFlag, bool female, int hue) => + raceFlag switch + { + Race.AllowElvesOnly when female => new FemaleElvenRobe(hue), + Race.AllowElvesOnly => new MaleElvenRobe(hue), + _ => new Robe(hue) + }; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Item SwordsWeapon(int raceFlag) => + raceFlag switch + { + Race.AllowElvesOnly => new RuneBlade(), + Race.AllowGargoylesOnly => new DreadSword(), + _ => new Katana() + }; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Item MacingWeapon(int raceFlag) => + raceFlag switch + { + Race.AllowElvesOnly => new DiamondMace(), + Race.AllowGargoylesOnly => new DiscMace(), + _ => new Club() + }; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Item FencingWeapon(int raceFlag) => + raceFlag switch + { + Race.AllowElvesOnly => new Leafblade(), + Race.AllowGargoylesOnly => new BloodBlade(), + _ => new Kryss() + }; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Item RangedWeapon(int raceFlag) => + raceFlag switch + { + Race.AllowElvesOnly => new ElvenCompositeLongbow(), + Race.AllowGargoylesOnly => new SerpentstoneStaff(), + _ => new GnarledStaff() + }; + + private static void AddSkillItems(this Mobile m, SkillName skill) { + var raceFlag = m.Race.RaceFlag; var elf = m.Race == Race.Elf; + var human = m.Race == Race.Human; + var gargoyle = m.Race == Race.Gargoyle; + var elfOrHuman = Race.IsAllowedRace(m.Race, Race.AllowHumanOrElves); + var female = m.Female; switch (skill) { case SkillName.Alchemy: { - PackItem(new Bottle(4)); - PackItem(new MortarPestle()); - - var hue = Utility.RandomPinkHue(); - - if (elf) - { - if (m.Female) - { - EquipItem(new FemaleElvenRobe(hue)); - } - else - { - EquipItem(new MaleElvenRobe(hue)); - } - } - else - { - EquipItem(new Robe(Utility.RandomPinkHue())); - } + m.PackItem(new Bottle(4)); + m.PackItem(new MortarPestle()); + EquipItem(m, Robe(raceFlag, female, Utility.RandomPinkHue())); break; } case SkillName.Anatomy: { - PackItem(new Bandage(3)); - - var hue = Utility.RandomYellowHue(); - - if (elf) - { - if (m.Female) - { - EquipItem(new FemaleElvenRobe(hue)); - } - else - { - EquipItem(new MaleElvenRobe(hue)); - } - } - else - { - EquipItem(new Robe(hue)); - } + m.PackItem(new Bandage(3)); + EquipItem(m, Robe(raceFlag, female, Utility.RandomYellowHue())); break; } case SkillName.AnimalLore: { - var hue = Utility.RandomBlueHue(); - if (elf) { - EquipItem(new WildStaff()); - - if (m.Female) - { - EquipItem(new FemaleElvenRobe(hue)); - } - else - { - EquipItem(new MaleElvenRobe(hue)); - } + EquipItem(m, new WildStaff()); } else { - EquipItem(new ShepherdsCrook()); - EquipItem(new Robe(hue)); + EquipItem(m, new ShepherdsCrook()); + } + + EquipItem(m, Robe(raceFlag, female, Utility.RandomGreenHue())); + + break; + } + case SkillName.AnimalTaming: + { + if (human) + { + EquipItem(m, new ShepherdsCrook()); } break; } case SkillName.Archery: { - PackItem(new Arrow(25)); + m.PackItem(new Arrow(25)); - if (elf) - { - EquipItem(new ElvenCompositeLongbow()); - } - else - { - EquipItem(new Bow()); - } + EquipItem(m, RangedWeapon(raceFlag)); break; } case SkillName.ArmsLore: { - if (elf) + Item item = Utility.Random(3) switch { - switch (Utility.Random(3)) - { - case 0: - EquipItem(new Leafblade()); - break; - case 1: - EquipItem(new RuneBlade()); - break; - case 2: - EquipItem(new DiamondMace()); - break; - } - } - else - { - switch (Utility.Random(3)) - { - case 0: - EquipItem(new Kryss()); - break; - case 1: - EquipItem(new Katana()); - break; - case 2: - EquipItem(new Club()); - break; - } - } + 0 => FencingWeapon(raceFlag), + 1 => MacingWeapon(raceFlag), + _ => SwordsWeapon(raceFlag) + }; + EquipItem(m, item); break; } case SkillName.Begging: { - if (elf) + Item staff = raceFlag switch { - EquipItem(new WildStaff()); - } - else - { - EquipItem(new GnarledStaff()); - } + Race.AllowElvesOnly => new WildStaff(), + Race.AllowGargoylesOnly => new GlassStaff(), + _ => new GnarledStaff() + }; + EquipItem(m, staff); break; } case SkillName.Blacksmith: { - PackItem(new Tongs()); - PackItem(new Pickaxe()); - PackItem(new Pickaxe()); - PackItem(new IronIngot(50)); - EquipItem(new HalfApron(Utility.RandomYellowHue())); + m.PackItem(new Tongs()); + m.PackItem(new Pickaxe()); + m.PackItem(new Pickaxe()); + m.PackItem(new IronIngot(50)); + EquipItem(m, new HalfApron(Utility.RandomYellowHue())); break; } case SkillName.Bushido: { - EquipItem(new Hakama()); - EquipItem(new Kasa()); - EquipItem(new BookOfBushido()); + if (elfOrHuman) + { + // Delete pants + m?.FindItemOnLayer(Layer.OuterLegs)?.Delete(); + + EquipItem(m, new Hakama()); + EquipItem(m, new Kasa()); + } + + EquipItem(m, new BookOfBushido()); break; } case SkillName.Fletching: { - PackItem(new Board(14)); - PackItem(new Feather(5)); - PackItem(new Shaft(5)); + m.PackItem(new Board(14)); + m.PackItem(new Feather(5)); + m.PackItem(new Shaft(5)); break; } case SkillName.Camping: { - PackItem(new Bedroll()); - PackItem(new Kindling(5)); + m.PackItem(new Bedroll()); + m.PackItem(new Kindling(5)); break; } case SkillName.Carpentry: { - PackItem(new Board(10)); - PackItem(new Saw()); - EquipItem(new HalfApron(Utility.RandomYellowHue())); + m.PackItem(new Board(10)); + m.PackItem(new Saw()); + + if (elfOrHuman) + { + EquipItem(m, new HalfApron(Utility.RandomYellowHue())); + } + break; } case SkillName.Cartography: { - PackItem(new BlankMap()); - PackItem(new BlankMap()); - PackItem(new BlankMap()); - PackItem(new BlankMap()); - PackItem(new Sextant()); + m.PackItem(new BlankMap()); + m.PackItem(new BlankMap()); + m.PackItem(new BlankMap()); + m.PackItem(new BlankMap()); + m.PackItem(new Sextant()); break; } case SkillName.Cooking: { - PackItem(new Kindling(2)); - PackItem(new RawLambLeg()); - PackItem(new RawChickenLeg()); - PackItem(new RawFishSteak()); - PackItem(new SackFlour()); - PackItem(new Pitcher(BeverageType.Water)); + m.PackItem(new Kindling(2)); + m.PackItem(new RawLambLeg()); + m.PackItem(new RawChickenLeg()); + m.PackItem(new RawFishSteak()); + m.PackItem(new SackFlour()); + m.PackItem(new Pitcher(BeverageType.Water)); break; } case SkillName.Chivalry: { - if (Core.ML) - { - PackItem(new BookOfChivalry()); - } - + m.PackItem(new BookOfChivalry()); break; } case SkillName.DetectHidden: { - EquipItem(new Cloak(0x455)); + if (elfOrHuman) + { + EquipItem(m, new Cloak(0x455)); + } + break; } case SkillName.Discordance: { - PackInstrument(); + m.PackInstrument(); break; } case SkillName.Fencing: { - if (elf) - { - EquipItem(new Leafblade()); - } - else - { - EquipItem(new Kryss()); - } - + EquipItem(m, FencingWeapon(raceFlag)); break; } case SkillName.Fishing: { - EquipItem(new FishingPole()); + EquipItem(m, new FishingPole()); var hue = Utility.RandomYellowHue(); - if (elf) { - Item i = new Circlet(); - i.Hue = hue; - EquipItem(i); + EquipItem(m, new Circlet { Hue = hue }); } - else + else if (human) { - EquipItem(new FloppyHat(hue)); + EquipItem(m, new FloppyHat(hue)); } break; } case SkillName.Healing: { - PackItem(new Bandage(50)); - PackItem(new Scissors()); + m.PackItem(new Bandage(50)); + m.PackItem(new Scissors()); break; } case SkillName.Herding: { - if (elf) - { - EquipItem(new WildStaff()); - } - else - { - EquipItem(new ShepherdsCrook()); - } - + EquipItem(m, new ShepherdsCrook()); break; } case SkillName.Hiding: { - EquipItem(new Cloak(0x455)); + if (elfOrHuman) + { + EquipItem(m, new Cloak(0x455)); + } + break; } case SkillName.Inscribe: { - PackItem(new BlankScroll(2)); - PackItem(new BlueBook()); + m.PackItem(new BlankScroll(2)); + m.PackItem(new BlueBook()); break; } case SkillName.ItemID: { - if (elf) + Item staff = raceFlag switch { - EquipItem(new WildStaff()); - } - else - { - EquipItem(new GnarledStaff()); - } + Race.AllowElvesOnly => new WildStaff(), + Race.AllowGargoylesOnly => new SerpentstoneStaff(), + _ => new GnarledStaff() + }; + EquipItem(m, staff); break; } case SkillName.Lockpicking: { - PackItem(new Lockpick(20)); + m.PackItem(new Lockpick(20)); break; } case SkillName.Lumberjacking: { - EquipItem(new Hatchet()); + EquipItem(m, elfOrHuman ? new Hatchet() : new DualShortAxes()); break; } case SkillName.Macing: { - if (elf) - { - EquipItem(new DiamondMace()); - } - else - { - EquipItem(new Club()); - } - + EquipItem(m, MacingWeapon(raceFlag)); break; } case SkillName.Magery: { - var regs = new BagOfReagents(30); + var regs = new BagOfReagents(30) { LootType = LootType.Regular }; if (!Core.AOS) { @@ -1721,180 +1112,164 @@ namespace Server.Misc } } - PackItem(regs); + m.PackItem(regs); + m.PackScroll(0); + m.PackScroll(1); + m.PackScroll(2); - regs.LootType = LootType.Regular; - - PackScroll(0); - PackScroll(1); - PackScroll(2); - - var book = new Spellbook((ulong)0x382A8C38); - - EquipItem(book); - - book.LootType = LootType.Blessed; + EquipItem(m, new Spellbook(0x382A8C38ul) { LootType = LootType.Blessed }); + EquipItem(m, Robe(raceFlag, female, Utility.RandomBlueHue())); if (elf) { - EquipItem(new Circlet()); - - if (m.Female) - { - EquipItem(new FemaleElvenRobe(Utility.RandomBlueHue())); - } - else - { - EquipItem(new MaleElvenRobe(Utility.RandomBlueHue())); - } + EquipItem(m, new Circlet()); } - else + else if (human) { - EquipItem(new WizardsHat()); - EquipItem(new Robe(Utility.RandomBlueHue())); + EquipItem(m, new WizardsHat()); } break; } case SkillName.Mining: { - PackItem(new Pickaxe()); + m.PackItem(new Pickaxe()); break; } case SkillName.Musicianship: { - PackInstrument(); + m.PackInstrument(); break; } case SkillName.Necromancy: { if (Core.ML) { - Container regs = new BagOfNecroReagents(); - - PackItem(regs); - - regs.LootType = LootType.Regular; + m.PackItem(new BagOfNecroReagents { LootType = LootType.Regular }); } break; } case SkillName.Ninjitsu: { - EquipItem(new Hakama(0x2C3)); // Only ninjas get the hued one. - EquipItem(new Kasa()); - EquipItem(new BookOfNinjitsu()); + if (elfOrHuman) + { + // Delete pants + m?.FindItemOnLayer(Layer.OuterLegs)?.Delete(); + + EquipItem(m, new Hakama(0x2C3)); // Only ninjas get the hued one. + EquipItem(m, new Kasa()); + } + + EquipItem(m, new BookOfNinjitsu()); break; } case SkillName.Parry: { - EquipItem(new WoodenShield()); + Item shield = raceFlag switch + { + Race.AllowGargoylesOnly => new GargishWoodenShield(), + _ => new WoodenShield() + }; + EquipItem(m, shield); + break; } case SkillName.Peacemaking: { - PackInstrument(); + m.PackInstrument(); break; } case SkillName.Poisoning: { - PackItem(new LesserPoisonPotion()); - PackItem(new LesserPoisonPotion()); + m.PackItem(new LesserPoisonPotion()); + m.PackItem(new LesserPoisonPotion()); break; } case SkillName.Provocation: { - PackInstrument(); + m.PackInstrument(); break; } + case SkillName.Stealing: case SkillName.Snooping: { - PackItem(new Lockpick(20)); + m.PackItem(new Lockpick(20)); break; } case SkillName.SpiritSpeak: { - EquipItem(new Cloak(0x455)); - break; - } - case SkillName.Stealing: - { - PackItem(new Lockpick(20)); - break; - } - case SkillName.Swords: - { - if (elf) - { - EquipItem(new RuneBlade()); - } - //else if (gargoyle) - //{ - //EquipItem(new DreadSword()); IMPLEMENTION NEEDED - //} - else - { - EquipItem(new Katana()); - } - + EquipItem(m, new Cloak(0x455)); break; } case SkillName.Tactics: + case SkillName.Swords: { - if (elf) - { - EquipItem(new RuneBlade()); - } - else - { - EquipItem(new Katana()); - } + EquipItem(m, SwordsWeapon(raceFlag)); break; } case SkillName.Tailoring: { - PackItem(new BoltOfCloth()); - PackItem(new SewingKit()); + m.PackItem(new BoltOfCloth()); + m.PackItem(new SewingKit()); + break; + } + case SkillName.Tinkering: + { + if (!Core.AOS) + { + m.PackTinkerPart(); + m.PackTinkerPart(); + m.PackTinkerPart(); + } + m.PackItem(new TinkerTools()); break; } case SkillName.Tracking: { - var shoes = m_Mobile?.FindItemOnLayer(Layer.Shoes); - - shoes?.Delete(); - - var hue = Utility.RandomYellowHue(); - - if (elf) + if (elfOrHuman) { - EquipItem(new ElvenBoots(hue)); - } - else - { - EquipItem(new Boots(hue)); + // Delete shoes + m?.FindItemOnLayer(Layer.Shoes)?.Delete(); + + var hue = Utility.RandomYellowHue(); + EquipItem(m, elf ? new ElvenBoots(hue) : new Boots(hue)); } - EquipItem(new SkinningKnife()); + EquipItem(m, new SkinningKnife()); break; } case SkillName.Veterinary: { - PackItem(new Bandage(5)); - PackItem(new Scissors()); + m.PackItem(new Bandage(5)); + m.PackItem(new Scissors()); break; } case SkillName.Wrestling: { - if (elf) + Item item = raceFlag switch { - EquipItem(new LeafGloves()); - } - else + Race.AllowElvesOnly => new LeafGloves(), + Race.AllowGargoylesOnly when m.Female => new GargishLeatherArmsType2(), + Race.AllowGargoylesOnly => new GargishLeatherArmsType1(), + _ => new LeatherGloves() + }; + EquipItem(m, item); + break; + } + case SkillName.Throwing: + { + if (gargoyle) { - EquipItem(new LeatherGloves()); + // EquipItem(m, new Boomerang()); } + break; + } + case SkillName.Mysticism: + { + // PackItem(new MysticBook(0xAB)); break; } } diff --git a/Projects/UOContent/Misc/ProfessionInfo.cs b/Projects/UOContent/Misc/ProfessionInfo.cs new file mode 100644 index 000000000..9eda06bd9 --- /dev/null +++ b/Projects/UOContent/Misc/ProfessionInfo.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Server +{ + public class ProfessionInfo + { + public static ProfessionInfo[] Professions { get; } + + private static bool TryGetSkillName(string name, out SkillName skillName) + { + if (Enum.TryParse(name, out skillName)) + { + return true; + } + + var lowerName = name.ToLowerInvariant().Replace(" ", ""); + + foreach (var so in SkillInfo.Table) + { + if (lowerName == so.ProfessionSkillName.ToLowerInvariant()) + { + skillName = (SkillName)so.SkillID; + return true; + } + } + + return false; + + } + + static ProfessionInfo() + { + var profs = new List + { + new() + { + ID = 0, // Custom + Name = "Advanced", + TopLevel = false, + GumpID = 5571 + } + }; + + var file = Core.FindDataFile("prof.txt"); + if (!File.Exists(file)) + { + var parent = Path.Combine(Core.BaseDirectory, "Data/Professions"); + file = Path.Combine(ExpansionInfo.GetEraFolder(parent), "prof.txt"); + } + + var maxProf = 0; + + if (File.Exists(file)) + { + using var s = File.OpenText(file); + + while (!s.EndOfStream) + { + var line = s.ReadLine(); + + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + line = line.Trim(); + + if (!line.InsensitiveStartsWith("Begin")) + { + continue; + } + + var prof = new ProfessionInfo(); + + int stats; + int valid; + var skills = stats = valid = 0; + + while (!s.EndOfStream) + { + line = s.ReadLine(); + + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + line = line.Trim(); + + if (line.InsensitiveStartsWith("End")) + { + if (valid >= 4) + { + profs.Add(prof); + } + + break; + } + + var cols = line.Split('\t', StringSplitOptions.RemoveEmptyEntries); + var key = cols[0].ToLowerInvariant(); + var value = cols[1].Trim('"'); + + if (key == "type" && value != "profession") + { + break; + } + + switch (key) + { + case "truename": + { + prof.Name = value; + ++valid; + } + break; + case "nameid": + prof.NameID = Utility.ToInt32(value); + break; + case "descid": + prof.DescID = Utility.ToInt32(value); + break; + case "desc": + { + prof.ID = Utility.ToInt32(value); + if (prof.ID > maxProf) + { + maxProf = prof.ID; + } + + ++valid; + } + break; + case "toplevel": + prof.TopLevel = Utility.ToBoolean(value); + break; + case "gump": + prof.GumpID = Utility.ToInt32(value); + break; + case "skill": + { + if (!TryGetSkillName(value, out var skillName)) + { + break; + } + + prof.Skills[skills++] = new SkillNameValue(skillName, Utility.ToInt32(cols[2])); + + if (skills == prof.Skills.Length) + { + ++valid; + } + } + break; + case "stat": + { + if (!Enum.TryParse(value, out StatType stat)) + { + break; + } + + prof.Stats[stats++] = new StatNameValue(stat, Utility.ToInt32(cols[2])); + + if (stats == prof.Stats.Length) + { + ++valid; + } + } + break; + } + } + } + } + + Professions = new ProfessionInfo[1 + maxProf]; + + foreach (var p in profs) + { + Professions[p.ID] = p; + } + + profs.Clear(); + profs.TrimExcess(); + } + + private ProfessionInfo() + { + Name = string.Empty; + + Skills = new SkillNameValue[4]; + Stats = new StatNameValue[3]; + } + + public int ID { get; private set; } + public string Name { get; private set; } + public int NameID { get; private set; } + public int DescID { get; private set; } + public bool TopLevel { get; private set; } + public int GumpID { get; private set; } + public SkillNameValue[] Skills { get; } + public StatNameValue[] Stats { get; } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/InterredGrizzle .cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/InterredGrizzle .cs index b0059787e..4b6df14d4 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/InterredGrizzle .cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/InterredGrizzle .cs @@ -119,7 +119,8 @@ namespace Server.Mobiles p = GetSpawnPosition(2); var eable = Map.GetItemsInRange(p, 0); - bool atLocation = eable.GetEnumerator().MoveNext(); + using var enumerator = eable.GetEnumerator(); + bool atLocation = enumerator.MoveNext(); eable.Free(); if (!atLocation) { diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Special/Ilhenir.cs b/Projects/UOContent/Mobiles/Monsters/ML/Special/Ilhenir.cs index 801c03733..073c4729c 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Special/Ilhenir.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Special/Ilhenir.cs @@ -252,7 +252,8 @@ namespace Server.Mobiles p = GetSpawnPosition(2); var eable = Map.GetItemsInRange(p, 0); - bool atLocation = eable.GetEnumerator().MoveNext(); + using var enumerator = eable.GetEnumerator(); + bool atLocation = enumerator.MoveNext(); eable.Free(); if (!atLocation) { diff --git a/Projects/UOContent/Mobiles/PlayerMobile.cs b/Projects/UOContent/Mobiles/PlayerMobile.cs index c3b925e64..17e7da183 100644 --- a/Projects/UOContent/Mobiles/PlayerMobile.cs +++ b/Projects/UOContent/Mobiles/PlayerMobile.cs @@ -803,14 +803,21 @@ namespace Server.Mobiles switch (type) { case BlockMountType.Dazed: - SendLocalizedMessage(1112457); - break; // You are still too dazed to fly. + { + SendLocalizedMessage(1112457); // You are still too dazed to fly. + break; + } case BlockMountType.BolaRecovery: - SendLocalizedMessage(1112455); - break; // You cannot fly while recovering from a bola throw. + { + SendLocalizedMessage(1112455); // You cannot fly while recovering from a bola throw. + break; + } case BlockMountType.DismountRecovery: - SendLocalizedMessage(1112456); - break; // You cannot fly while recovering from a dismount maneuver. + { + // You cannot fly while recovering from a dismount maneuver. + SendLocalizedMessage(1112456); + break; + } } } else if (Hits < 25) // TODO confirm @@ -3204,7 +3211,6 @@ namespace Server.Mobiles RecentlyReported ??= new List(); - // Professions weren't verified on 1.0 RC0 if (!CharacterCreation.VerifyProfession(Profession)) { Profession = 0; diff --git a/Projects/UOContent/Special Systems/Engines/TestCenter.cs b/Projects/UOContent/Special Systems/Engines/TestCenter.cs index 706045e35..2c84bc177 100644 --- a/Projects/UOContent/Special Systems/Engines/TestCenter.cs +++ b/Projects/UOContent/Special Systems/Engines/TestCenter.cs @@ -2,7 +2,10 @@ using System; using System.Text; using Microsoft.Toolkit.HighPerformance; using Server.Commands; +using Server.Factions; using Server.Gumps; +using Server.Items; +using Server.Mobiles; using Server.Network; namespace Server.Misc @@ -84,7 +87,7 @@ namespace Server.Misc private static void ChangeStrength(Mobile from, int value) { - if (value < 10 || value > 125) + if (value is < 10 or > 125) { from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. } @@ -106,7 +109,7 @@ namespace Server.Misc private static void ChangeDexterity(Mobile from, int value) { - if (value < 10 || value > 125) + if (value is < 10 or > 125) { from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. } @@ -128,7 +131,7 @@ namespace Server.Misc private static void ChangeIntelligence(Mobile from, int value) { - if (value < 10 || value > 125) + if (value is < 10 or > 125) { from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. } @@ -186,6 +189,485 @@ namespace Server.Misc } } + private static Item MakeNewbie(Item item) + { + if (!Core.AOS) + { + item.LootType = LootType.Newbied; + } + + return item; + } + + private static void PlaceItemIn(Container parent, int x, int y, Item item) + { + parent.AddItem(item); + item.Location = new Point3D(x, y, 0); + } + + private static Item MakePotionKeg(PotionEffect type, int hue) + { + var keg = new PotionKeg + { + Held = 100, + Type = type, + Hue = hue + }; + + return MakeNewbie(keg); + } + + private static void FillBankAOS(Mobile m) + { + var bank = m.BankBox; + + // The new AOS bankboxes don't have powerscrolls, they are automatically 'applied': + + for (var i = 0; i < PowerScroll.Skills.Count; ++i) + { + m.Skills[PowerScroll.Skills[i]].Cap = 120.0; + } + + m.StatCap = 250; + + Container cont; + + // Begin box of money + cont = new WoodenBox { ItemID = 0xE7D, Hue = 0x489 }; + + PlaceItemIn(cont, 16, 51, new BankCheck(500000)); + PlaceItemIn(cont, 28, 51, new BankCheck(250000)); + PlaceItemIn(cont, 40, 51, new BankCheck(100000)); + PlaceItemIn(cont, 52, 51, new BankCheck(100000)); + PlaceItemIn(cont, 64, 51, new BankCheck(50000)); + + PlaceItemIn(cont, 16, 115, new Silver(9000)); + PlaceItemIn(cont, 34, 115, new Gold(60000)); + + PlaceItemIn(bank, 18, 169, cont); + // End box of money + + // Begin bag of potion kegs + cont = new Backpack { Name = "Various Potion Kegs" }; + + PlaceItemIn(cont, 45, 149, MakePotionKeg(PotionEffect.CureGreater, 0x2D)); + PlaceItemIn(cont, 69, 149, MakePotionKeg(PotionEffect.HealGreater, 0x499)); + PlaceItemIn(cont, 93, 149, MakePotionKeg(PotionEffect.PoisonDeadly, 0x46)); + PlaceItemIn(cont, 117, 149, MakePotionKeg(PotionEffect.RefreshTotal, 0x21)); + PlaceItemIn(cont, 141, 149, MakePotionKeg(PotionEffect.ExplosionGreater, 0x74)); + + PlaceItemIn(cont, 93, 82, new Bottle(1000)); + + PlaceItemIn(bank, 53, 169, cont); + // End bag of potion kegs + + // Begin bag of tools + cont = new Bag { Name = "Tool Bag" }; + + PlaceItemIn(cont, 30, 35, new TinkerTools(1000)); + PlaceItemIn(cont, 60, 35, new HousePlacementTool()); + PlaceItemIn(cont, 90, 35, new DovetailSaw(1000)); + PlaceItemIn(cont, 30, 68, new Scissors()); + PlaceItemIn(cont, 45, 68, new MortarPestle(1000)); + PlaceItemIn(cont, 75, 68, new ScribesPen(1000)); + PlaceItemIn(cont, 90, 68, new SmithHammer(1000)); + PlaceItemIn(cont, 30, 118, new TwoHandedAxe()); + PlaceItemIn(cont, 60, 118, new FletcherTools(1000)); + PlaceItemIn(cont, 90, 118, new SewingKit(1000)); + + PlaceItemIn(cont, 36, 51, new RunicHammer(CraftResource.DullCopper, 1000)); + PlaceItemIn(cont, 42, 51, new RunicHammer(CraftResource.ShadowIron, 1000)); + PlaceItemIn(cont, 48, 51, new RunicHammer(CraftResource.Copper, 1000)); + PlaceItemIn(cont, 54, 51, new RunicHammer(CraftResource.Bronze, 1000)); + PlaceItemIn(cont, 61, 51, new RunicHammer(CraftResource.Gold, 1000)); + PlaceItemIn(cont, 67, 51, new RunicHammer(CraftResource.Agapite, 1000)); + PlaceItemIn(cont, 73, 51, new RunicHammer(CraftResource.Verite, 1000)); + PlaceItemIn(cont, 79, 51, new RunicHammer(CraftResource.Valorite, 1000)); + + PlaceItemIn(cont, 36, 55, new RunicSewingKit(CraftResource.SpinedLeather, 1000)); + PlaceItemIn(cont, 42, 55, new RunicSewingKit(CraftResource.HornedLeather, 1000)); + PlaceItemIn(cont, 48, 55, new RunicSewingKit(CraftResource.BarbedLeather, 1000)); + + PlaceItemIn(bank, 118, 169, cont); + // End bag of tools + + // Begin bag of archery ammo + cont = new Bag { Name = "Bag Of Archery Ammo" }; + + PlaceItemIn(cont, 48, 76, new Arrow(5000)); + PlaceItemIn(cont, 72, 76, new Bolt(5000)); + + PlaceItemIn(bank, 118, 124, cont); + // End bag of archery ammo + + // Begin bag of treasure maps + cont = new Bag { Name = "Bag Of Treasure Maps" }; + + PlaceItemIn(cont, 30, 35, new TreasureMap(1, Map.Trammel)); + PlaceItemIn(cont, 45, 35, new TreasureMap(2, Map.Trammel)); + PlaceItemIn(cont, 60, 35, new TreasureMap(3, Map.Trammel)); + PlaceItemIn(cont, 75, 35, new TreasureMap(4, Map.Trammel)); + PlaceItemIn(cont, 90, 35, new TreasureMap(5, Map.Trammel)); + PlaceItemIn(cont, 90, 35, new TreasureMap(6, Map.Trammel)); + + PlaceItemIn(cont, 30, 50, new TreasureMap(1, Map.Trammel)); + PlaceItemIn(cont, 45, 50, new TreasureMap(2, Map.Trammel)); + PlaceItemIn(cont, 60, 50, new TreasureMap(3, Map.Trammel)); + PlaceItemIn(cont, 75, 50, new TreasureMap(4, Map.Trammel)); + PlaceItemIn(cont, 90, 50, new TreasureMap(5, Map.Trammel)); + PlaceItemIn(cont, 90, 50, new TreasureMap(6, Map.Trammel)); + + PlaceItemIn(cont, 55, 100, new Lockpick(30)); + PlaceItemIn(cont, 60, 100, new Pickaxe()); + + PlaceItemIn(bank, 98, 124, cont); + // End bag of treasure maps + + // Begin bag of raw materials + cont = new Bag { Hue = 0x835, Name = "Raw Materials Bag" }; + + PlaceItemIn(cont, 92, 60, new BarbedLeather(5000)); + PlaceItemIn(cont, 92, 68, new HornedLeather(5000)); + PlaceItemIn(cont, 92, 76, new SpinedLeather(5000)); + PlaceItemIn(cont, 92, 84, new Leather(5000)); + + PlaceItemIn(cont, 30, 118, new Cloth(5000)); + PlaceItemIn(cont, 30, 84, new Board(5000)); + PlaceItemIn(cont, 57, 80, new BlankScroll(500)); + + PlaceItemIn(cont, 30, 35, new DullCopperIngot(5000)); + PlaceItemIn(cont, 37, 35, new ShadowIronIngot(5000)); + PlaceItemIn(cont, 44, 35, new CopperIngot(5000)); + PlaceItemIn(cont, 51, 35, new BronzeIngot(5000)); + PlaceItemIn(cont, 58, 35, new GoldIngot(5000)); + PlaceItemIn(cont, 65, 35, new AgapiteIngot(5000)); + PlaceItemIn(cont, 72, 35, new VeriteIngot(5000)); + PlaceItemIn(cont, 79, 35, new ValoriteIngot(5000)); + PlaceItemIn(cont, 86, 35, new IronIngot(5000)); + + PlaceItemIn(cont, 30, 59, new RedScales(5000)); + PlaceItemIn(cont, 36, 59, new YellowScales(5000)); + PlaceItemIn(cont, 42, 59, new BlackScales(5000)); + PlaceItemIn(cont, 48, 59, new GreenScales(5000)); + PlaceItemIn(cont, 54, 59, new WhiteScales(5000)); + PlaceItemIn(cont, 60, 59, new BlueScales(5000)); + + PlaceItemIn(bank, 98, 169, cont); + // End bag of raw materials + + // Begin bag of spell casting stuff + cont = new Backpack { Hue = 0x480, Name = "Spell Casting Stuff" }; + + PlaceItemIn(cont, 45, 105, new Spellbook(ulong.MaxValue)); + PlaceItemIn(cont, 65, 105, new NecromancerSpellbook(0xFFFFUL)); + PlaceItemIn(cont, 85, 105, new BookOfChivalry()); + PlaceItemIn(cont, 105, 105, new BookOfBushido()); // Default ctor = full + PlaceItemIn(cont, 125, 105, new BookOfNinjitsu()); // Default ctor = full + + var runebook = new Runebook(10); + runebook.CurCharges = runebook.MaxCharges; + PlaceItemIn(cont, 145, 105, runebook); + + Item toHue = new BagOfReagents(150) { Hue = 0x2D }; + PlaceItemIn(cont, 45, 150, toHue); + + toHue = new BagOfNecroReagents(150) { Hue = 0x488 }; + PlaceItemIn(cont, 65, 150, toHue); + + PlaceItemIn(cont, 140, 150, new BagOfAllReagents(500)); + + for (var i = 0; i < 9; ++i) + { + PlaceItemIn(cont, 45 + i * 10, 75, new RecallRune()); + } + + PlaceItemIn(cont, 141, 74, new FireHorn()); + + PlaceItemIn(bank, 78, 169, cont); + // End bag of spell casting stuff + + // Begin bag of ethereals + cont = new Backpack { Hue = 0x490, Name = "Bag Of Ethy's!" }; + + PlaceItemIn(cont, 45, 66, new EtherealHorse()); + PlaceItemIn(cont, 69, 82, new EtherealOstard()); + PlaceItemIn(cont, 93, 99, new EtherealLlama()); + PlaceItemIn(cont, 117, 115, new EtherealKirin()); + PlaceItemIn(cont, 45, 132, new EtherealUnicorn()); + PlaceItemIn(cont, 69, 66, new EtherealRidgeback()); + PlaceItemIn(cont, 93, 82, new EtherealSwampDragon()); + PlaceItemIn(cont, 117, 99, new EtherealBeetle()); + + PlaceItemIn(bank, 38, 124, cont); + // End bag of ethereals + + // Begin first bag of artifacts + cont = new Backpack { Hue = 0x48F, Name = "Bag of Artifacts" }; + + PlaceItemIn(cont, 45, 66, new TitansHammer()); + PlaceItemIn(cont, 69, 82, new InquisitorsResolution()); + PlaceItemIn(cont, 93, 99, new BladeOfTheRighteous()); + PlaceItemIn(cont, 117, 115, new ZyronicClaw()); + + PlaceItemIn(bank, 58, 124, cont); + // End first bag of artifacts + + // Begin second bag of artifacts + cont = new Backpack { Hue = 0x48F, Name = "Bag of Artifacts" }; + + PlaceItemIn(cont, 45, 66, new GauntletsOfNobility()); + PlaceItemIn(cont, 69, 82, new MidnightBracers()); + PlaceItemIn(cont, 93, 99, new VoiceOfTheFallenKing()); + PlaceItemIn(cont, 117, 115, new OrnateCrownOfTheHarrower()); + PlaceItemIn(cont, 45, 132, new HelmOfInsight()); + PlaceItemIn(cont, 69, 66, new HolyKnightsBreastplate()); + PlaceItemIn(cont, 93, 82, new ArmorOfFortune()); + PlaceItemIn(cont, 117, 99, new TunicOfFire()); + PlaceItemIn(cont, 45, 115, new LeggingsOfBane()); + PlaceItemIn(cont, 69, 132, new ArcaneShield()); + PlaceItemIn(cont, 93, 66, new Aegis()); + PlaceItemIn(cont, 117, 82, new RingOfTheVile()); + PlaceItemIn(cont, 45, 99, new BraceletOfHealth()); + PlaceItemIn(cont, 69, 115, new RingOfTheElements()); + PlaceItemIn(cont, 93, 132, new OrnamentOfTheMagician()); + PlaceItemIn(cont, 117, 66, new DivineCountenance()); + PlaceItemIn(cont, 45, 82, new JackalsCollar()); + PlaceItemIn(cont, 69, 99, new HuntersHeaddress()); + PlaceItemIn(cont, 93, 115, new HatOfTheMagi()); + PlaceItemIn(cont, 117, 132, new ShadowDancerLeggings()); + PlaceItemIn(cont, 45, 66, new SpiritOfTheTotem()); + PlaceItemIn(cont, 69, 82, new BladeOfInsanity()); + PlaceItemIn(cont, 93, 99, new AxeOfTheHeavens()); + PlaceItemIn(cont, 117, 115, new TheBeserkersMaul()); + PlaceItemIn(cont, 45, 132, new Frostbringer()); + PlaceItemIn(cont, 69, 66, new BreathOfTheDead()); + PlaceItemIn(cont, 93, 82, new TheDragonSlayer()); + PlaceItemIn(cont, 117, 99, new BoneCrusher()); + PlaceItemIn(cont, 45, 115, new StaffOfTheMagi()); + PlaceItemIn(cont, 69, 132, new SerpentsFang()); + PlaceItemIn(cont, 93, 66, new LegacyOfTheDreadLord()); + PlaceItemIn(cont, 117, 82, new TheTaskmaster()); + PlaceItemIn(cont, 45, 99, new TheDryadBow()); + + PlaceItemIn(bank, 78, 124, cont); + // End second bag of artifacts + + // Begin bag of minor artifacts + cont = new Backpack { Hue = 0x48F, Name = "Bag of Minor Artifacts" }; + + PlaceItemIn(cont, 45, 66, new LunaLance()); + PlaceItemIn(cont, 69, 82, new VioletCourage()); + PlaceItemIn(cont, 93, 99, new CavortingClub()); + PlaceItemIn(cont, 117, 115, new CaptainQuacklebushsCutlass()); + PlaceItemIn(cont, 45, 132, new NightsKiss()); + PlaceItemIn(cont, 69, 66, new ShipModelOfTheHMSCape()); + PlaceItemIn(cont, 93, 82, new AdmiralsHeartyRum()); + PlaceItemIn(cont, 117, 99, new CandelabraOfSouls()); + PlaceItemIn(cont, 45, 115, new IolosLute()); + PlaceItemIn(cont, 69, 132, new GwennosHarp()); + PlaceItemIn(cont, 93, 66, new ArcticDeathDealer()); + PlaceItemIn(cont, 117, 82, new EnchantedTitanLegBone()); + PlaceItemIn(cont, 45, 99, new NoxRangersHeavyCrossbow()); + PlaceItemIn(cont, 69, 115, new BlazeOfDeath()); + PlaceItemIn(cont, 93, 132, new DreadPirateHat()); + PlaceItemIn(cont, 117, 66, new BurglarsBandana()); + PlaceItemIn(cont, 45, 82, new GoldBricks()); + PlaceItemIn(cont, 69, 99, new AlchemistsBauble()); + PlaceItemIn(cont, 93, 115, new PhillipsWoodenSteed()); + PlaceItemIn(cont, 117, 132, new PolarBearMask()); + PlaceItemIn(cont, 45, 66, new BowOfTheJukaKing()); + PlaceItemIn(cont, 69, 82, new GlovesOfThePugilist()); + PlaceItemIn(cont, 93, 99, new OrcishVisage()); + PlaceItemIn(cont, 117, 115, new StaffOfPower()); + PlaceItemIn(cont, 45, 132, new ShieldOfInvulnerability()); + PlaceItemIn(cont, 69, 66, new HeartOfTheLion()); + PlaceItemIn(cont, 93, 82, new ColdBlood()); + PlaceItemIn(cont, 117, 99, new GhostShipAnchor()); + PlaceItemIn(cont, 45, 115, new SeahorseStatuette()); + PlaceItemIn(cont, 69, 132, new WrathOfTheDryad()); + PlaceItemIn(cont, 93, 66, new PixieSwatter()); + + for (var i = 0; i < 10; i++) + { + PlaceItemIn(cont, 117, 128, new MessageInABottle(Utility.RandomBool() ? Map.Trammel : Map.Felucca, 4)); + } + + PlaceItemIn(bank, 18, 124, cont); + + if (Core.SE) + { + cont = new Bag { Hue = 0x501, Name = "Tokuno Minor Artifacts" }; + + PlaceItemIn(cont, 42, 70, new Exiler()); + PlaceItemIn(cont, 38, 53, new HanzosBow()); + PlaceItemIn(cont, 45, 40, new TheDestroyer()); + PlaceItemIn(cont, 92, 80, new DragonNunchaku()); + PlaceItemIn(cont, 42, 56, new PeasantsBokuto()); + PlaceItemIn(cont, 44, 71, new TomeOfEnlightenment()); + PlaceItemIn(cont, 35, 35, new ChestOfHeirlooms()); + PlaceItemIn(cont, 29, 0, new HonorableSwords()); + PlaceItemIn(cont, 49, 85, new AncientUrn()); + PlaceItemIn(cont, 51, 58, new FluteOfRenewal()); + PlaceItemIn(cont, 70, 51, new PigmentsOfTokuno()); + PlaceItemIn(cont, 40, 79, new AncientSamuraiDo()); + PlaceItemIn(cont, 51, 61, new LegsOfStability()); + PlaceItemIn(cont, 88, 78, new GlovesOfTheSun()); + PlaceItemIn(cont, 55, 62, new AncientFarmersKasa()); + PlaceItemIn(cont, 55, 83, new ArmsOfTacticalExcellence()); + PlaceItemIn(cont, 50, 85, new DaimyosHelm()); + PlaceItemIn(cont, 52, 78, new BlackLotusHood()); + PlaceItemIn(cont, 52, 79, new DemonForks()); + PlaceItemIn(cont, 33, 49, new PilferedDancerFans()); + + PlaceItemIn(bank, 58, 124, cont); + } + + if (Core.SE) // This bag came only after SE. + { + cont = new Bag { Name = "Bag of Bows" }; + + PlaceItemIn(cont, 31, 84, new Bow()); + PlaceItemIn(cont, 78, 74, new CompositeBow()); + PlaceItemIn(cont, 53, 71, new Crossbow()); + PlaceItemIn(cont, 56, 39, new HeavyCrossbow()); + PlaceItemIn(cont, 82, 72, new RepeatingCrossbow()); + PlaceItemIn(cont, 49, 45, new Yumi()); + + for (var i = 0; i < cont.Items.Count; i++) + { + if (cont.Items[i] is BaseRanged bow) + { + bow.Attributes.WeaponSpeed = 35; + bow.Attributes.WeaponDamage = 35; + } + } + + PlaceItemIn(bank, 108, 135, cont); + } + } + + public static void FillBankbox(Mobile m) + { + if (Core.AOS) + { + FillBankAOS(m); + return; + } + + var bank = m.BankBox; + + bank.DropItem(new BankCheck(1000000)); + + // Full spellbook + var book = new Spellbook { Content = ulong.MaxValue }; + + bank.DropItem(book); + + var bag = new Bag(); + + for (var i = 0; i < 5; ++i) + { + bag.DropItem(new Moonstone(MoonstoneType.Felucca)); + } + + // Felucca moonstones + bank.DropItem(bag); + + bag = new Bag(); + + for (var i = 0; i < 5; ++i) + { + bag.DropItem(new Moonstone(MoonstoneType.Trammel)); + } + + // Trammel moonstones + bank.DropItem(bag); + + // Treasure maps + bank.DropItem(new TreasureMap(1, Map.Trammel)); + bank.DropItem(new TreasureMap(2, Map.Trammel)); + bank.DropItem(new TreasureMap(3, Map.Trammel)); + bank.DropItem(new TreasureMap(4, Map.Trammel)); + bank.DropItem(new TreasureMap(5, Map.Trammel)); + + // Bag containing 50 of each reagent + bank.DropItem(new BagOfReagents()); + + // Craft tools + bank.DropItem(MakeNewbie(new Scissors())); + bank.DropItem(MakeNewbie(new SewingKit(1000))); + bank.DropItem(MakeNewbie(new SmithHammer(1000))); + bank.DropItem(MakeNewbie(new FletcherTools(1000))); + bank.DropItem(MakeNewbie(new DovetailSaw(1000))); + bank.DropItem(MakeNewbie(new MortarPestle(1000))); + bank.DropItem(MakeNewbie(new ScribesPen(1000))); + bank.DropItem(MakeNewbie(new TinkerTools(1000))); + + // A few dye tubs + bank.DropItem(new Dyes()); + bank.DropItem(new DyeTub()); + bank.DropItem(new DyeTub()); + bank.DropItem(new BlackDyeTub()); + bank.DropItem(new DyeTub { DyedHue = 0x485, Redyable = false }); + + // Some food + bank.DropItem(MakeNewbie(new Apple(1000))); + + // Resources + bank.DropItem(MakeNewbie(new Feather(1000))); + bank.DropItem(MakeNewbie(new BoltOfCloth(1000))); + bank.DropItem(MakeNewbie(new BlankScroll(1000))); + bank.DropItem(MakeNewbie(new Hides(1000))); + bank.DropItem(MakeNewbie(new Bandage(1000))); + bank.DropItem(MakeNewbie(new Bottle(1000))); + bank.DropItem(MakeNewbie(new Log(1000))); + + bank.DropItem(MakeNewbie(new IronIngot(5000))); + bank.DropItem(MakeNewbie(new DullCopperIngot(5000))); + bank.DropItem(MakeNewbie(new ShadowIronIngot(5000))); + bank.DropItem(MakeNewbie(new CopperIngot(5000))); + bank.DropItem(MakeNewbie(new BronzeIngot(5000))); + bank.DropItem(MakeNewbie(new GoldIngot(5000))); + bank.DropItem(MakeNewbie(new AgapiteIngot(5000))); + bank.DropItem(MakeNewbie(new VeriteIngot(5000))); + bank.DropItem(MakeNewbie(new ValoriteIngot(5000))); + + // Reagents + bank.DropItem(MakeNewbie(new BlackPearl(1000))); + bank.DropItem(MakeNewbie(new Bloodmoss(1000))); + bank.DropItem(MakeNewbie(new Garlic(1000))); + bank.DropItem(MakeNewbie(new Ginseng(1000))); + bank.DropItem(MakeNewbie(new MandrakeRoot(1000))); + bank.DropItem(MakeNewbie(new Nightshade(1000))); + bank.DropItem(MakeNewbie(new SulfurousAsh(1000))); + bank.DropItem(MakeNewbie(new SpidersSilk(1000))); + + // Some extra starting gold + bank.DropItem(MakeNewbie(new Gold(9000))); + + // 5 blank recall runes + for (var i = 0; i < 5; ++i) + { + bank.DropItem(MakeNewbie(new RecallRune())); + } + + AddPowerScrolls(bank); + } + + private static void AddPowerScrolls(BankBox bank) + { + var bag = new Bag(); + + for (var i = 0; i < PowerScroll.Skills.Count; ++i) + { + bag.DropItem(new PowerScroll(PowerScroll.Skills[i], 120.0)); + } + + bag.DropItem(new StatCapScroll(250)); + + bank.DropItem(bag); + } + public class TCHelpGump : Gump { public TCHelpGump() : base(40, 40) diff --git a/Projects/UOContent/UOContent.csproj b/Projects/UOContent/UOContent.csproj index 00117bb55..aab3a5561 100755 --- a/Projects/UOContent/UOContent.csproj +++ b/Projects/UOContent/UOContent.csproj @@ -40,7 +40,7 @@ - +