ModernUO/Projects/UOContent/Misc/CharacterCreation.cs
Kamron Batman 6e69d25e33
fix: Fixes structured logging (#1043)
- [X] Fixes various bugs in logging.
2022-06-05 01:00:22 -07:00

1278 lines
46 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Server.Accounting;
using Server.Items;
using Server.Logging;
using Server.Mobiles;
using Server.Network;
namespace Server.Misc
{
public static class CharacterCreation
{
private static readonly ILogger logger = LogFactory.GetLogger(typeof(CharacterCreation));
// Allowed skills that are not race or era specific
private static readonly HashSet<SkillName> _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 _newHavenInfo =
new("New Haven", "The Bountiful Harvest Inn", 3503, 2574, 14, Map.Trammel);
public static void Initialize()
{
// Register our event handler
EventSink.CharacterCreated += EventSink_CharacterCreated;
}
private static void AddBackpack(this Mobile m)
{
var pack = m.Backpack;
if (pack == null)
{
pack = new Backpack();
pack.Movable = false;
m.AddItem(pack);
}
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)
{
if (a.Count >= a.Limit)
{
return null;
}
for (var i = 0; i < a.Length; ++i)
{
if (a[i] == null)
{
return a[i] = new PlayerMobile();
}
}
return null;
}
private static void EventSink_CharacterCreated(CharacterCreatedEventArgs args)
{
if (!VerifyProfession(args.Profession))
{
args.Profession = 0;
}
var state = args.State;
if (state == null)
{
return;
}
var newChar = CreateMobile(args.Account as Account);
if (newChar == null)
{
logger.Information("Login: {NetState}: Character creation failed, account full", state);
return;
}
args.Mobile = newChar;
newChar.Player = true;
newChar.AccessLevel = args.Account.AccessLevel;
newChar.Female = args.Female;
newChar.Race = Core.Expansion >= args.Race.RequiredExpansion ? args.Race : Race.DefaultRace;
newChar.Hue = newChar.Race.ClipSkinHue(args.Hue & 0x3FFF) | 0x8000;
newChar.Hunger = 20;
var young = false;
if (newChar is PlayerMobile pm)
{
pm.Profession = args.Profession;
if (pm.AccessLevel == AccessLevel.Player && ((Account)pm.Account).Young)
{
young = pm.Young = true;
}
}
SetName(newChar, args.Name);
newChar.AddBackpack();
SetStats(newChar, state, args.Stats, args.Profession);
SetSkills(newChar, args.Skills, args.Profession, args.ShirtHue, args.PantsHue);
var race = newChar.Race;
if (race.ValidateHair(newChar, args.HairID))
{
newChar.HairItemID = args.HairID;
newChar.HairHue = race.ClipHairHue(args.HairHue & 0x3FFF);
}
if (race.ValidateFacialHair(newChar, args.BeardID))
{
newChar.FacialHairItemID = args.BeardID;
newChar.FacialHairHue = race.ClipHairHue(args.BeardHue & 0x3FFF);
}
if (TestCenter.Enabled)
{
TestCenter.FillBankbox(newChar);
}
if (young)
{
var ticket = new NewPlayerTicket();
ticket.Owner = newChar;
newChar.BankBox.DropItem(ticket);
}
var city = GetStartLocation(args, young);
newChar.MoveToWorld(city.Location, city.Map);
logger.Information(
"Login: {0}: New character being created (account={1}, character={2}, serial={3}, started.city={4}, started.location={5}, started.map={6})",
state,
args.Account.Username,
newChar.Name,
newChar.Serial,
city.City,
city.Location,
city.Map);
new WelcomeTimer(newChar).Start();
}
public static bool VerifyProfession(int profession) =>
profession >= 0 && profession < ProfessionInfo.Professions.Length;
private static CityInfo GetStartLocation(CharacterCreatedEventArgs args, bool isYoung)
{
if (Core.ML)
{
return _newHavenInfo; // We don't get the client Version until AFTER Character creation
}
var useHaven = isYoung;
var flags = args.State?.Flags ?? ClientFlags.None;
var m = args.Mobile;
var profession = ProfessionInfo.Professions[args.Profession];
switch (profession?.Name.ToLowerInvariant())
{
case "necromancer":
{
if ((flags & ClientFlags.Malas) != 0)
{
return new CityInfo("Umbra", "Mardoth's Tower", 2114, 1301, -50, Map.Malas);
}
useHaven = true;
/*
* Unfortunately you are playing on a *NON-Age-Of-Shadows* game
* installation and cannot be transported to Malas.
* You will not be able to take your new player quest in Malas
* without an AOS client. You are now being taken to the city of
* Haven on the Trammel facet.
*/
Timer.StartTimer(BadStartMessageDelay, () => m.SendLocalizedMessage(1062205));
break;
}
case "paladin":
{
return _newHavenInfo;
}
case "samurai":
{
if ((flags & ClientFlags.Tokuno) != 0)
{
return new CityInfo("Samurai DE", "Haoti's Grounds", 368, 780, -1, Map.Malas);
}
useHaven = true;
/*
* Unfortunately you are playing on a *NON-Samurai-Empire* game
* installation and cannot be transported to Tokuno.
* You will not be able to take your new player quest in Tokuno
* without an SE client. You are now being taken to the city of
* Haven on the Trammel facet.
*/
Timer.StartTimer(BadStartMessageDelay, () => m.SendLocalizedMessage(1063487));
break;
}
case "ninja":
{
if ((flags & ClientFlags.Tokuno) != 0)
{
return new CityInfo("Ninja DE", "Enimo's Residence", 414, 823, -1, Map.Malas);
}
useHaven = true;
/*
* Unfortunately you are playing on a *NON-Samurai-Empire* game
* installation and cannot be transported to Tokuno.
* You will not be able to take your new player quest in Tokuno
* without an SE client. You are now being taken to the city of
* Haven on the Trammel facet.
*/
Timer.StartTimer(BadStartMessageDelay, () => m.SendLocalizedMessage(1063487));
break;
}
}
return useHaven ? _newHavenInfo : args.City;
}
private static void SetStats(Mobile m, NetState state, StatNameValue[] stats, int prof)
{
var maxStats = state.NewCharacterCreation ? 90 : 80;
var str = 0;
var dex = 0;
var intel = 0;
if (prof > 0)
{
stats = ProfessionInfo.Professions[prof]?.Stats ?? stats;
}
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;
}
}
if (str is < 10 or > 60 || dex is < 10 or > 60 || intel is < 10 or > 60 || str + dex + intel != maxStats)
{
str = 10;
dex = 10;
intel = 10;
}
m.InitStats(str, dex, intel);
}
private static void SetName(Mobile m, string name)
{
name = name.Trim();
if (!NameVerification.Validate(name, 2, 16, true, false, true, 1, NameVerification.SpaceDashPeriodQuote))
{
name = "Generic Player";
}
m.Name = name;
}
private static bool ValidateSkills(int raceFlag, SkillNameValue[] skills)
{
var total = 0;
for (var i = 0; i < skills.Length; ++i)
{
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)
{
skills[i] = default;
continue;
}
total += value;
for (var j = i + 1; j < skills.Length; ++j)
{
var (nameCheck, valueCheck) = skills[j];
if (valueCheck > 0 && nameCheck == name)
{
return false;
}
}
}
return total is 100 or 120;
}
private static void SetSkills(Mobile m, SkillNameValue[] skills, int prof, int shirtHue, int pantsHue)
{
ProfessionInfo profession = null;
if (prof > 0)
{
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 (profession?.Name.ToLowerInvariant())
{
case "necromancer":
{
Container regs = new BagOfNecroReagents { LootType = LootType.Regular };
if (!Core.AOS)
{
foreach (var item in regs.Items)
{
item.LootType = LootType.Newbied;
}
}
m.PackItem(regs);
EquipItem(m, new BoneHelm());
if (elf)
{
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(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(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));
}
// animate dead, evil omen, pain spike, summon familiar, wraith form
m.PackItem(new NecromancerSpellbook(0x8981ul) { LootType = LootType.Blessed });
addSkillItems = false;
break;
}
case "paladin":
{
if (elf)
{
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(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(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));
}
m.PackItem(new BookOfChivalry { LootType = LootType.Blessed });
addSkillItems = false;
break;
}
case "samurai":
{
addSkillItems = false;
if (elf)
{
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(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(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());
}
m.PackItem(new Scissors());
m.PackItem(new Bandage(50));
m.PackItem(new BookOfBushido());
break;
}
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(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(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(m, new Tekagi());
EquipItem(m, new TattsukeHakama(hues.RandomElement()));
EquipItem(m, new HakamaShita(0x2C3));
EquipItem(m, new NinjaTabi(0x2C3));
EquipItem(m, new Kasa());
}
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 (name, value) = skills[i];
if (value <= 0)
{
continue;
}
var skill = m.Skills[name];
if (skill != null)
{
skill.BaseFixedPoint = value * 10;
m.AddSkillItems(name);
}
}
}
private static void EquipItem(Mobile m, Item item, bool mustEquip = false)
{
if (item == null)
{
return;
}
if (!Core.AOS)
{
item.LootType = LootType.Newbied;
}
if (m?.EquipItem(item) == true)
{
return;
}
var pack = m?.Backpack;
if (!mustEquip && pack != null)
{
pack.DropItem(item);
}
else
{
item.Delete();
}
}
private static void PackItem(this Mobile m, Item item)
{
if (!Core.AOS)
{
item.LootType = LootType.Newbied;
}
var pack = m.Backpack;
if (pack != null)
{
pack.DropItem(item);
}
else
{
item.Delete();
}
}
private static void AddShirt(this Mobile m, int shirtHue)
{
var hue = Utility.ClipDyedHue(shirtHue & 0x3FFF);
var raceFlag = m.Race.RaceFlag;
var shirt = raceFlag switch
{
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 PackInstrument(this Mobile m)
{
Item instrument = Utility.Random(6) switch
{
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)
{
item.Hue = 0x2C3;
return item;
}
[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 Bow()
};
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:
{
m.PackItem(new Bottle(4));
m.PackItem(new MortarPestle());
EquipItem(m, Robe(raceFlag, female, Utility.RandomPinkHue()));
break;
}
case SkillName.Anatomy:
{
m.PackItem(new Bandage(3));
EquipItem(m, Robe(raceFlag, female, Utility.RandomYellowHue()));
break;
}
case SkillName.AnimalLore:
{
if (elf)
{
EquipItem(m, new WildStaff());
}
else
{
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:
{
m.PackItem(new Arrow(25));
EquipItem(m, RangedWeapon(raceFlag));
break;
}
case SkillName.ArmsLore:
{
Item item = Utility.Random(3) switch
{
0 => FencingWeapon(raceFlag),
1 => MacingWeapon(raceFlag),
_ => SwordsWeapon(raceFlag)
};
EquipItem(m, item);
break;
}
case SkillName.Begging:
{
Item staff = raceFlag switch
{
Race.AllowElvesOnly => new WildStaff(),
Race.AllowGargoylesOnly => new GlassStaff(),
_ => new GnarledStaff()
};
EquipItem(m, staff);
break;
}
case SkillName.Blacksmith:
{
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:
{
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:
{
m.PackItem(new Board(14));
m.PackItem(new Feather(5));
m.PackItem(new Shaft(5));
break;
}
case SkillName.Camping:
{
m.PackItem(new Bedroll());
m.PackItem(new Kindling(5));
break;
}
case SkillName.Carpentry:
{
m.PackItem(new Board(10));
m.PackItem(new Saw());
if (elfOrHuman)
{
EquipItem(m, new HalfApron(Utility.RandomYellowHue()));
}
break;
}
case SkillName.Cartography:
{
m.PackItem(new BlankMap());
m.PackItem(new BlankMap());
m.PackItem(new BlankMap());
m.PackItem(new BlankMap());
m.PackItem(new Sextant());
break;
}
case SkillName.Cooking:
{
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:
{
m.PackItem(new BookOfChivalry());
break;
}
case SkillName.DetectHidden:
{
if (elfOrHuman)
{
EquipItem(m, new Cloak(0x455));
}
break;
}
case SkillName.Discordance:
{
m.PackInstrument();
break;
}
case SkillName.Fencing:
{
EquipItem(m, FencingWeapon(raceFlag));
break;
}
case SkillName.Fishing:
{
EquipItem(m, new FishingPole());
var hue = Utility.RandomYellowHue();
if (elf)
{
EquipItem(m, new Circlet { Hue = hue });
}
else if (human)
{
EquipItem(m, new FloppyHat(hue));
}
break;
}
case SkillName.Healing:
{
m.PackItem(new Bandage(50));
m.PackItem(new Scissors());
break;
}
case SkillName.Herding:
{
EquipItem(m, new ShepherdsCrook());
break;
}
case SkillName.Hiding:
{
if (elfOrHuman)
{
EquipItem(m, new Cloak(0x455));
}
break;
}
case SkillName.Inscribe:
{
m.PackItem(new BlankScroll(2));
m.PackItem(new BlueBook());
break;
}
case SkillName.ItemID:
{
Item staff = raceFlag switch
{
Race.AllowElvesOnly => new WildStaff(),
Race.AllowGargoylesOnly => new SerpentstoneStaff(),
_ => new GnarledStaff()
};
EquipItem(m, staff);
break;
}
case SkillName.Lockpicking:
{
m.PackItem(new Lockpick(20));
break;
}
case SkillName.Lumberjacking:
{
EquipItem(m, elfOrHuman ? new Hatchet() : new DualShortAxes());
break;
}
case SkillName.Macing:
{
EquipItem(m, MacingWeapon(raceFlag));
break;
}
case SkillName.Magery:
{
var regs = new BagOfReagents(30) { LootType = LootType.Regular };
if (!Core.AOS)
{
foreach (var item in regs.Items)
{
item.LootType = LootType.Newbied;
}
}
m.PackItem(regs);
m.PackScroll(0);
m.PackScroll(1);
m.PackScroll(2);
EquipItem(m, new Spellbook(0x382A8C38ul) { LootType = LootType.Blessed });
EquipItem(m, Robe(raceFlag, female, Utility.RandomBlueHue()));
if (elf)
{
EquipItem(m, new Circlet());
}
else if (human)
{
EquipItem(m, new WizardsHat());
}
break;
}
case SkillName.Mining:
{
m.PackItem(new Pickaxe());
break;
}
case SkillName.Musicianship:
{
m.PackInstrument();
break;
}
case SkillName.Necromancy:
{
if (Core.ML)
{
m.PackItem(new BagOfNecroReagents { LootType = LootType.Regular });
}
break;
}
case SkillName.Ninjitsu:
{
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:
{
Item shield = raceFlag switch
{
Race.AllowGargoylesOnly => new GargishWoodenShield(),
_ => new WoodenShield()
};
EquipItem(m, shield);
break;
}
case SkillName.Peacemaking:
{
m.PackInstrument();
break;
}
case SkillName.Poisoning:
{
m.PackItem(new LesserPoisonPotion());
m.PackItem(new LesserPoisonPotion());
break;
}
case SkillName.Provocation:
{
m.PackInstrument();
break;
}
case SkillName.Stealing:
case SkillName.Snooping:
{
m.PackItem(new Lockpick(20));
break;
}
case SkillName.SpiritSpeak:
{
EquipItem(m, new Cloak(0x455));
break;
}
case SkillName.Tactics:
case SkillName.Swords:
{
EquipItem(m, SwordsWeapon(raceFlag));
break;
}
case SkillName.Tailoring:
{
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:
{
if (elfOrHuman)
{
// Delete shoes
m?.FindItemOnLayer(Layer.Shoes)?.Delete();
var hue = Utility.RandomYellowHue();
EquipItem(m, elf ? new ElvenBoots(hue) : new Boots(hue));
}
EquipItem(m, new SkinningKnife());
break;
}
case SkillName.Veterinary:
{
m.PackItem(new Bandage(5));
m.PackItem(new Scissors());
break;
}
case SkillName.Wrestling:
{
Item item = raceFlag switch
{
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(m, new Boomerang());
}
break;
}
case SkillName.Mysticism:
{
// PackItem(new MysticBook(0xAB));
break;
}
}
}
}
}