Ритуалы!
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
using Pf2eModel;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Pf2eModel;
|
||||
using Slugify;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers;
|
||||
|
||||
public class DatabaseHelper
|
||||
{
|
||||
public readonly Pf2eDbContext Context = new();
|
||||
public Pf2eDbContext Context = new();
|
||||
|
||||
public readonly SlugHelper Slugger = new();
|
||||
|
||||
@@ -25,5 +26,12 @@ public class DatabaseHelper
|
||||
|
||||
public static readonly DatabaseHelper Instance = new();
|
||||
|
||||
public static readonly Pf2eDbContext DbContext = Instance.Context;
|
||||
public static Pf2eDbContext DbContext => Instance.Context;
|
||||
|
||||
public static void ResetContext()
|
||||
{
|
||||
Instance.Context.SaveChanges();
|
||||
// Instance.Context.Dispose();
|
||||
// Instance.Context = new();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +101,8 @@ internal class AonprdDataBuilder(AonprdLoader loader)
|
||||
}
|
||||
|
||||
SubProcessProgressBar.Next("Ready");
|
||||
|
||||
DatabaseHelper.ResetContext();
|
||||
}
|
||||
|
||||
ProcessProgressBar.Next("Done!");
|
||||
|
||||
+1
-1
@@ -8,5 +8,5 @@ internal class AonprdBuilderGlobals
|
||||
|
||||
private AonprdBuilderGlobals() { }
|
||||
|
||||
public static AonprdBuilderGlobals Instance = new AonprdBuilderGlobals();
|
||||
public static AonprdBuilderGlobals Instance = new();
|
||||
}
|
||||
|
||||
+28
-6
@@ -6,13 +6,25 @@ internal partial class StringHelper
|
||||
{
|
||||
private StringHelper() { }
|
||||
|
||||
public List<MarkdownLink> ParseMarkdown(string input)
|
||||
public List<string> RowSplit(string value)
|
||||
{
|
||||
List<MarkdownLink> links = [];
|
||||
return value
|
||||
.Replace(", or", ",")
|
||||
.Replace(" or ", ", ")
|
||||
.Replace(";", ",")
|
||||
.Split(", ")
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public MarkdownLinkSplit ParseMarkdownLinks(string input)
|
||||
{
|
||||
MarkdownLinkSplit result = new();
|
||||
|
||||
Match match = MarkdownRegex().Match(input);
|
||||
if (match.Captures.Count > 0)
|
||||
{
|
||||
links.Add(
|
||||
result.Links.Add(
|
||||
new()
|
||||
{
|
||||
Prefix = match.Groups[1].Value.Trim(),
|
||||
@@ -21,7 +33,10 @@ internal partial class StringHelper
|
||||
}
|
||||
);
|
||||
}
|
||||
return links;
|
||||
|
||||
result.Suffix = MarkdownRegex().Replace(input, "");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string ResolveSource(string input)
|
||||
@@ -33,10 +48,17 @@ internal partial class StringHelper
|
||||
public static StringHelper Instance { get; } = new();
|
||||
|
||||
[GeneratedRegex(@"^\[.*?\]\(.*?\)\s+(.*)$")]
|
||||
private static partial Regex SourceSuffixRegex();
|
||||
public static partial Regex SourceSuffixRegex();
|
||||
|
||||
[GeneratedRegex(@"(.*?)\[(.*?)\]\((.*?)\)")]
|
||||
private static partial Regex MarkdownRegex();
|
||||
public static partial Regex MarkdownRegex();
|
||||
}
|
||||
|
||||
internal class MarkdownLinkSplit
|
||||
{
|
||||
public List<MarkdownLink> Links = [];
|
||||
|
||||
public string Suffix = "";
|
||||
}
|
||||
|
||||
internal class MarkdownLink
|
||||
|
||||
+4
-1
@@ -49,13 +49,16 @@ internal abstract class AbstractEntityProcessor(AonprdProcessorInput input)
|
||||
Context.SaveChanges();
|
||||
}
|
||||
|
||||
protected virtual string[] AddedDescriptionPaths() => [];
|
||||
|
||||
protected string AddedDescription(string path) =>
|
||||
$"\r\n\r\n========== [{path}] ==========\r\n\r\n{Input.GetOptional<string>(path) ?? ""}";
|
||||
|
||||
protected string AddedDescription(string[] paths) =>
|
||||
string.Join("", paths.Select(AddedDescription));
|
||||
|
||||
protected virtual string GetDescription() => Input.GetRequired<string>("markdown");
|
||||
protected virtual string GetDescription() =>
|
||||
Input.GetRequired<string>("markdown") + AddedDescription(AddedDescriptionPaths());
|
||||
|
||||
protected virtual void AddEntity()
|
||||
{
|
||||
|
||||
+6
-3
@@ -9,7 +9,7 @@ using Pf2eModel.Model.Structure;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Subclasses;
|
||||
|
||||
[AonprdProcessor("apparition", ["class", "spell", "skill"])]
|
||||
// [AonprdProcessor("apparition", ["class", "spell", "skill"])]
|
||||
internal class ApparitionProcessor(AonprdProcessorInput input) : AbstractSubclassProcessor(input)
|
||||
{
|
||||
public override Subclass Object { get; } = new();
|
||||
@@ -22,7 +22,10 @@ internal class ApparitionProcessor(AonprdProcessorInput input) : AbstractSubclas
|
||||
{
|
||||
// Spells
|
||||
string spellMd = Input.GetRequired<string>("spells_markdown");
|
||||
List<string> spellUrls = StringHelper.ParseMarkdown(spellMd).Select(l => l.Url).ToList();
|
||||
List<string> spellUrls = StringHelper
|
||||
.ParseMarkdownLinks(spellMd)
|
||||
.Links.Select(l => l.Url)
|
||||
.ToList();
|
||||
|
||||
List<int> spellIds = Context
|
||||
.EntityExternals.Where(x => spellUrls.Contains(x.Suffix))
|
||||
@@ -61,7 +64,7 @@ internal class ApparitionProcessor(AonprdProcessorInput input) : AbstractSubclas
|
||||
{
|
||||
Subclass = Object,
|
||||
Training = training,
|
||||
Stage = TrainingStage.Trained,
|
||||
Rank = TrainingRank.Trained,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ using Pf2eModel.Model.Structure;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Types;
|
||||
|
||||
[AonprdProcessor("ancestry", ["trait", "language"])]
|
||||
[AonprdProcessor("ancestry", ["trait", "source", "language"])]
|
||||
internal class AncestryProcessor(AonprdProcessorInput input) : AbstractEntityProcessor(input)
|
||||
{
|
||||
public override EntityType Type => EntityType.Ancestry;
|
||||
|
||||
+4
-4
@@ -98,7 +98,7 @@ internal class ClassProcessor(AonprdProcessorInput input) : AbstractEntityProces
|
||||
{
|
||||
Class = Object,
|
||||
Training = skill,
|
||||
Stage = TrainingStage.Trained,
|
||||
Rank = TrainingRank.Trained,
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
@@ -117,7 +117,7 @@ internal class ClassProcessor(AonprdProcessorInput input) : AbstractEntityProces
|
||||
throw new Exception($"Can't parse training string '{value}'");
|
||||
}
|
||||
|
||||
TrainingStage stage = Input.Enum<TrainingStage>(m[0].Groups[1].Value);
|
||||
TrainingRank rank = Input.Enum<TrainingRank>(m[0].Groups[1].Value);
|
||||
|
||||
string[] parts = GetTrainingString(m[0].Groups[2].Value);
|
||||
|
||||
@@ -142,7 +142,7 @@ internal class ClassProcessor(AonprdProcessorInput input) : AbstractEntityProces
|
||||
{
|
||||
Class = Object,
|
||||
Training = training,
|
||||
Stage = stage,
|
||||
Rank = rank,
|
||||
};
|
||||
|
||||
trainings.Add(classTraining);
|
||||
@@ -193,7 +193,7 @@ internal class ClassProcessor(AonprdProcessorInput input) : AbstractEntityProces
|
||||
{
|
||||
Class = Object,
|
||||
Training = pair.Value,
|
||||
Stage = Input.EnumRequired<TrainingStage>($"{pair.Key.ToLower()}_proficiency"),
|
||||
Rank = Input.EnumRequired<TrainingRank>($"{pair.Key.ToLower()}_proficiency"),
|
||||
};
|
||||
|
||||
return classTraining;
|
||||
|
||||
+629
@@ -0,0 +1,629 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Helpers;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Common;
|
||||
using Pf2eModel.Model.Common.I18n;
|
||||
using Pf2eModel.Model.Enum;
|
||||
using Pf2eModel.Model.Structure;
|
||||
using Pf2eModel.Model.Structure.RitualRelation;
|
||||
using Pf2eModel.Model.Structure.SpellRelation;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Types;
|
||||
|
||||
[AonprdProcessor("ritual", ["trait", "source", "skill"])]
|
||||
internal partial class RitualProcessor(AonprdProcessorInput input) : AbstractEntityProcessor(input)
|
||||
{
|
||||
public override EntityType Type => EntityType.Ritual;
|
||||
|
||||
public override Ritual Object { get; } = new();
|
||||
|
||||
public override void Add() => Context.Rituals.Add(Object);
|
||||
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
Object.Level = Input.GetRequired<int>("level");
|
||||
Object.Duration = Input.GetOptional<int>("duration", -1);
|
||||
|
||||
Object.Range = Input.GetOptional<int>("range", -1);
|
||||
Object.RangeString = Input.GetOptionalLocale("range_raw", LocaleType.English);
|
||||
|
||||
Object.CastTime = CalculateCastTime(Input.GetRequired<string>("actions"));
|
||||
|
||||
Object.Cost = Input.GetOptionalLocale("cost_markdown", LocaleType.English);
|
||||
|
||||
Object.Target = Input.GetOptionalLocale("target_markdown", LocaleType.English);
|
||||
Object.Requirement = Input.GetOptionalLocale("requirement_markdown", LocaleType.English);
|
||||
|
||||
Object.Elements = (Input.GetOptional<JArray>("element") ?? [])
|
||||
.Select(token => Input.Enum<ElementEnum>(token.ToString()))
|
||||
.ToArray();
|
||||
|
||||
ProcessArea();
|
||||
|
||||
Object.PrimaryCheckSuffix = Input.GetOptionalLocale(
|
||||
"primary_check_markdown",
|
||||
LocaleType.English
|
||||
);
|
||||
// ProcessPrimaryCheck();
|
||||
}
|
||||
|
||||
private int CalculateCastTime(string value)
|
||||
{
|
||||
string[] parts = value.Trim().ToLower().Split(" ");
|
||||
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
throw new($"Can't determine cast time of \"{value}\"");
|
||||
}
|
||||
|
||||
int number = int.Parse(parts[0]);
|
||||
|
||||
string unit = parts[1].ToLower();
|
||||
int unitSeconds = unit switch
|
||||
{
|
||||
"hour" => 3600,
|
||||
"hours" => 3600,
|
||||
"day" => 86400,
|
||||
"days" => 86400,
|
||||
"week" => 7 * 86400,
|
||||
"weeks" => 7 * 86400,
|
||||
_ => throw new($"Can't determine cast time of \"{value}\""),
|
||||
};
|
||||
|
||||
return number * unitSeconds;
|
||||
}
|
||||
|
||||
private void ProcessArea()
|
||||
{
|
||||
string? areaRaw = Input.GetOptional<string>("area_raw");
|
||||
|
||||
if (string.IsNullOrEmpty(areaRaw))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string areaType = Input.GetRequired<string[]>("area_type")[0];
|
||||
RitualArea ritualArea = new()
|
||||
{
|
||||
Ritual = Object,
|
||||
Type = Input.Enum<SpellAreaType>(areaType),
|
||||
Details = new() { [LocaleType.English] = areaRaw },
|
||||
};
|
||||
|
||||
Object.Area = ritualArea;
|
||||
Context.RitualAreas.Add(ritualArea);
|
||||
}
|
||||
|
||||
private void ProcessPrimaryCheck()
|
||||
{
|
||||
string? check = Input.GetOptional<string>("primary_check_markdown");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(check))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Замена символа ссылок
|
||||
check = StringHelper.MarkdownRegex().Replace(check, "$1[$2]{$3}");
|
||||
check = check.Replace("(", "<").Replace(")", ">").Replace("{", "(").Replace("}", ")");
|
||||
|
||||
// Временная замена скобок ранга и дополнения
|
||||
#pragma warning disable SYSLIB1045
|
||||
MatchCollection rankMatches = new Regex(@"<(.*?)>").Matches(check);
|
||||
#pragma warning restore SYSLIB1045
|
||||
for (int i = 0; i < rankMatches.Count; i++)
|
||||
{
|
||||
check = check.Replace(rankMatches[i].Value, $"{{rank-{i}}}");
|
||||
}
|
||||
|
||||
// Разбиваем строку на части
|
||||
List<string> parts = StringHelper.RowSplit(check);
|
||||
|
||||
// Возвращаем скобки ранга и дополнения
|
||||
for (int i = 0; i < rankMatches.Count; i++)
|
||||
{
|
||||
for (int j = 0; j < parts.Count; j++)
|
||||
{
|
||||
parts[j] = parts[j].Replace($"{{rank-{i}}}", rankMatches[i].Value);
|
||||
}
|
||||
}
|
||||
|
||||
// Обработка частей
|
||||
List<RitualCheck> ritualChecks = parts.Select(part => ResolveCheck(part, false)).ToList();
|
||||
|
||||
// TODO
|
||||
// 1. Проверить ritualChecks, если в каких-то Untrained, а в каком-то есть ранг - все к этому рангу
|
||||
// 2. Поставить primarySuffix
|
||||
// 3. Добавить в коллекцию
|
||||
}
|
||||
|
||||
private List<RitualCheck> ResolveChecks(string input, bool isSecondary)
|
||||
{
|
||||
List<RitualCheck> result = [];
|
||||
List<List<string>> checkStrings = [];
|
||||
|
||||
foreach (string part in StringHelper.RowSplit(input))
|
||||
{
|
||||
Match match = StringHelper.MarkdownRegex().Match(part);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
string prefix = match.Groups[1].Value.Trim();
|
||||
string text = match.Groups[2].Value.Trim();
|
||||
|
||||
checkStrings.Add([prefix + " " + text, text]);
|
||||
}
|
||||
else
|
||||
{
|
||||
checkStrings.Add([part.Trim()]);
|
||||
}
|
||||
}
|
||||
|
||||
List<string> checkOptions = checkStrings.SelectMany(a => a).ToList();
|
||||
List<Training> skills = Context
|
||||
.Trainings.Where(t => Pf2eDbContext.LocaleSearchArray(t.Name, checkOptions))
|
||||
.ToList();
|
||||
|
||||
foreach (List<string> checks in checkStrings)
|
||||
{
|
||||
Training? skill = skills.FirstOrDefault(t =>
|
||||
checks.Any(check => t.Name!.Contains(check))
|
||||
);
|
||||
|
||||
LocaleString? trainingString =
|
||||
(skill is null) ? null : new() { [LocaleType.English] = checks[0] };
|
||||
|
||||
result.Add(
|
||||
new()
|
||||
{
|
||||
Ritual = Object,
|
||||
Training = skill,
|
||||
IsSecondary = isSecondary,
|
||||
TrainingString = trainingString,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private string primarySuffix = "";
|
||||
|
||||
private RitualCheck ResolveCheck(string input, bool isSecondary)
|
||||
{
|
||||
RitualCheck result = new() { Ritual = Object, IsSecondary = isSecondary };
|
||||
string? skillName = null;
|
||||
|
||||
Dictionary<Regex, Action<Match>> regexDictionary = new()
|
||||
{
|
||||
// General match
|
||||
// [name](url) ? <rank?> ?
|
||||
[PrimaryRegex1()] = match =>
|
||||
{
|
||||
skillName = match.Groups[1].Value;
|
||||
result.Rank = Input.Enum<TrainingRank>(match.Groups[4].Value.ToLower());
|
||||
primarySuffix +=
|
||||
match.Groups[3].Value + match.Groups[5].Value + match.Groups[6].Value;
|
||||
},
|
||||
|
||||
// ? [name](url)
|
||||
[PrimaryRegex2()] = match =>
|
||||
{
|
||||
skillName = match.Groups[2].Value;
|
||||
result.Rank = TrainingRank.Untrained;
|
||||
primarySuffix += match.Groups[1].Value;
|
||||
},
|
||||
|
||||
// name <rank>
|
||||
[PrimaryRegex3()] = match =>
|
||||
{
|
||||
skillName = match.Groups[1].Value;
|
||||
result.Rank = Input.Enum<TrainingRank>(match.Groups[2].Value.ToLower());
|
||||
},
|
||||
};
|
||||
|
||||
foreach (KeyValuePair<Regex, Action<Match>> pair in regexDictionary)
|
||||
{
|
||||
Match match = pair.Key.Match(input);
|
||||
|
||||
if (!match.Success)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pair.Value.Invoke(match);
|
||||
}
|
||||
|
||||
if (skillName is null)
|
||||
{
|
||||
throw new($"Can't resolve skill name from \"{input}\"");
|
||||
}
|
||||
|
||||
result.Training = Context.Trainings.FirstOrDefault(t =>
|
||||
Pf2eDbContext.LocaleSearch(t.Name, skillName)
|
||||
);
|
||||
|
||||
result.TrainingString =
|
||||
(result.Training is null) ? null : new() { [LocaleType.English] = skillName };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override string[] AddedDescriptionPaths() =>
|
||||
[
|
||||
"summary_markdown",
|
||||
"primary_check_markdown",
|
||||
"secondary_casters_raw",
|
||||
"secondary_check_markdown",
|
||||
];
|
||||
|
||||
[GeneratedRegex(@"\((\/.*?)\)")]
|
||||
private static partial Regex LinkRemoveRegex();
|
||||
|
||||
[GeneratedRegex(@"\((\w*)[;, ]?(.*?)\)")]
|
||||
private static partial Regex PrimaryCheckSuffixRegex();
|
||||
|
||||
[GeneratedRegex(
|
||||
@"^ *\[\s*(.*?)\s*\]\((.*?)\)\s*([a-z' ]*?)<(.*?)(?:[;,]\s*(.*?))?>([a-z' ]*?)$",
|
||||
RegexOptions.Multiline
|
||||
)]
|
||||
private static partial Regex PrimaryRegex1();
|
||||
|
||||
[GeneratedRegex(@"^ *(.*?) *\[\s*(.*?)\s*\]\((.*?)\) *$", RegexOptions.Multiline)]
|
||||
private static partial Regex PrimaryRegex2();
|
||||
|
||||
[GeneratedRegex(@"^ *(.*?)\s*<(.*?)> *$", RegexOptions.Multiline)]
|
||||
private static partial Regex PrimaryRegex3();
|
||||
}
|
||||
|
||||
/*
|
||||
TEST DATA FOR PRIMARY RANK
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2) <expert>
|
||||
|
||||
[Religion](/Skills.aspx?ID=13) <expert; you must be a [daemon](/MonsterFamilies.aspx?ID=26), an [urdefhan](/MonsterFamilies.aspx?ID=158)>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2) <master>
|
||||
[Occultism](/Skills.aspx?ID=11) <master>
|
||||
[Religion](/Skills.aspx?ID=13) <master>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <master>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
[Nature](/Skills.aspx?ID=10)
|
||||
[Occultism](/Skills.aspx?ID=11)
|
||||
[Religion](/Skills.aspx?ID=13) <legendary>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10)
|
||||
[Religion](/Skills.aspx?ID=13)
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Religion](/Skills.aspx?ID=13) <expert>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10)
|
||||
[Religion](/Skills.aspx?ID=13) <master, the check has the [secret](/Traits.aspx?ID=142) trait>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
[Occultism](/Skills.aspx?ID=11) <trained>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Religion](/Skills.aspx?ID=13) <expert; you must be a [div](/MonsterFamilies.aspx?ID=225)>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <trained>
|
||||
|
||||
[Crafting](/Skills.aspx?ID=4) <expert>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2) <expert>
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11)
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2) <expert>
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <expert>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11)
|
||||
[Religion](/Skills.aspx?ID=13)
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2) <Expert>
|
||||
[Occultism](/Skills.aspx?ID=11) <Expert>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11)
|
||||
[Religion](/Skills.aspx?ID=13) <master>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
[Nature](/Skills.aspx?ID=10)
|
||||
[Occultism](/Skills.aspx?ID=11)
|
||||
[Religion](/Skills.aspx?ID=13) matching the ley line's tradition <legendary>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
[Nature](/Skills.aspx?ID=10)
|
||||
[Occultism](/Skills.aspx?ID=11)
|
||||
[Religion](/Skills.aspx?ID=13) based on the ley line <master>
|
||||
|
||||
[Religion](/Skills.aspx?ID=13) <trained>
|
||||
|
||||
[Performance](/Skills.aspx?ID=12) <expert>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11)
|
||||
[Religion](/Skills.aspx?ID=13) <legendary>
|
||||
|
||||
DC 40 [Arcana](/Skills.aspx?ID=2)
|
||||
[Nature](/Skills.aspx?ID=10) <master>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11)
|
||||
[Religion](/Skills.aspx?ID=13) <legendary>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <expert; you must be the [Mosquito Witch](/Monsters.aspx?ID=1735)>
|
||||
|
||||
[Religion](/Skills.aspx?ID=13) <master>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <expert>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <master>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11)
|
||||
[Religion](/Skills.aspx?ID=13)
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <master>
|
||||
[Religion](/Skills.aspx?ID=13) <master>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <master>
|
||||
[Religion](/Skills.aspx?ID=13) <master>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <master>
|
||||
[Religion](/Skills.aspx?ID=13) <master>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11)
|
||||
[Religion](/Skills.aspx?ID=13) <legendary>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
[Occultism](/Skills.aspx?ID=11) <master>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Religion](/Skills.aspx?ID=13) <trained>
|
||||
|
||||
[Crafting](/Skills.aspx?ID=4) <master>
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
[Religion](/Skills.aspx?ID=13) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
[Occultism](/Skills.aspx?ID=11) <master, the check has the [secret](/Traits.aspx?ID=142) trait>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Fortune-Telling Lore](/Skills.aspx?ID=8) <trained>
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Performance](/Skills.aspx?ID=12) <expert>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <master>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
[Nature](/Skills.aspx?ID=10) <expert>
|
||||
|
||||
Occultism <Trained>
|
||||
Religion <trained>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2)
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2) <expert>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10)
|
||||
[Religion](/Skills.aspx?ID=13) <expert>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <master>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2) <master>
|
||||
[Occultism](/Skills.aspx?ID=11) <master>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <expert>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
[Religion](/Skills.aspx?ID=13) <expert>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=11) <master>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <master>
|
||||
[Occultism](/Skills.aspx?ID=11) <master>
|
||||
[Religion](/Skills.aspx?ID=13) <master>
|
||||
|
||||
[Religion](/Skills.aspx?ID=13)
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <master>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2) <expert>
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
[Religion](/Skills.aspx?ID=13) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2) <expert>
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
[Religion](/Skills.aspx?ID=13) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2) <master>
|
||||
[Nature](/Skills.aspx?ID=10) <master>
|
||||
[Occultism](/Skills.aspx?ID=11) <master>
|
||||
[Religion](/Skills.aspx?ID=13) <master>
|
||||
|
||||
[Religion](/Skills.aspx?ID=13) <expert>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <expert>
|
||||
|
||||
[Nature](/Skills.aspx?ID=10) <master>
|
||||
|
||||
[Religion](/Skills.aspx?ID=13) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2) <expert>
|
||||
[Nature](/Skills.aspx?ID=10) <expert>
|
||||
[Occultism](/Skills.aspx?ID=11) <expert>
|
||||
[Religion](/Skills.aspx?ID=13) <expert> as determined by the tradition of spell cast in the ritual
|
||||
|
||||
[Arcana](/Skills.aspx?ID=2) <legendary>
|
||||
[Nature](/Skills.aspx?ID=10) <legendary>
|
||||
[Occultism](/Skills.aspx?ID=11) <legendary>
|
||||
[Religion](/Skills.aspx?ID=13) <legendary>
|
||||
|
||||
[Diplomacy ](/Skills.aspx?ID=39)<expert>
|
||||
|
||||
[Occultism ](/Skills.aspx?ID=44)<trained>
|
||||
[Survival](/Skills.aspx?ID=49) <expert>
|
||||
|
||||
[Occultism ](/Skills.aspx?ID=44)
|
||||
[Religion ](/Skills.aspx?ID=46) <expert>
|
||||
|
||||
[Religion](/Skills.aspx?ID=46) <expert>
|
||||
|
||||
[Performance ](/Skills.aspx?ID=45)<expert>
|
||||
|
||||
[Cooking Lore](/Skills.aspx?ID=41) <expert>
|
||||
|
||||
[Cooking Lore](/Skills.aspx?ID=41)
|
||||
[Tea Lore ](/Skills.aspx?ID=41) <expert>
|
||||
|
||||
[Crafting](/Skills.aspx?ID=37) <expert>
|
||||
|
||||
[Athletics](/Skills.aspx?ID=36) <expert>
|
||||
|
||||
[Medicine](/Skills.aspx?ID=42) <expert>
|
||||
|
||||
[Perception](/Rules.aspx?ID=2298) <master>
|
||||
|
||||
[Diplomacy](/Skills.aspx?ID=39) <expert>
|
||||
|
||||
[Religion](/Skills.aspx?ID=46) <expert; you must be an [angel](/Traits.aspx?ID=530)>
|
||||
|
||||
[Religion](/Skills.aspx?ID=46) <expert; you must be a [demon](/Traits.aspx?ID=573)>
|
||||
|
||||
[Religion](/Skills.aspx?ID=46) <expert; you must be a [devil](/Traits.aspx?ID=575)>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35)
|
||||
[Occultism](/Skills.aspx?ID=44) <master>
|
||||
|
||||
[Crafting](/Skills.aspx?ID=37) <legendary>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35)
|
||||
[Occultism](/Skills.aspx?ID=44) <legendary>
|
||||
|
||||
[Crafting](/Skills.aspx?ID=37)
|
||||
[Nature](/Skills.aspx?ID=43)
|
||||
[Society](/Skills.aspx?ID=47) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35)
|
||||
[Occultism](/Skills.aspx?ID=44) <expert, the check has the [secret](/Traits.aspx?ID=690) trait>
|
||||
|
||||
[Nature](/Skills.aspx?ID=43)
|
||||
[Religion](/Skills.aspx?ID=46) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35) <expert>
|
||||
[Occultism](/Skills.aspx?ID=44) <expert>
|
||||
[Religion](/Skills.aspx?ID=46) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35)
|
||||
[Occultism](/Skills.aspx?ID=44) <expert>
|
||||
|
||||
[Nature](/Skills.aspx?ID=43) <expert>
|
||||
|
||||
[Religion](/Skills.aspx?ID=46) <expert>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35)
|
||||
[Occultism](/Skills.aspx?ID=44) <master, the check has the [secret](/Traits.aspx?ID=690) trait>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35)
|
||||
[Occultism](/Skills.aspx?ID=44) <master>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35)
|
||||
[Nature](/Skills.aspx?ID=43)
|
||||
[Occultism](/Skills.aspx?ID=44) <master>
|
||||
|
||||
[Cooking Lore](/Skills.aspx?ID=41)
|
||||
[Crafting](/Skills.aspx?ID=37)
|
||||
[Performance](/Skills.aspx?ID=45)
|
||||
[Survival](/Skills.aspx?ID=49) <trained>
|
||||
|
||||
[Medicine](/Skills.aspx?ID=42) <trained>
|
||||
|
||||
[Cooking Lore](/Skills.aspx?ID=41)
|
||||
[Crafting](/Skills.aspx?ID=37)
|
||||
[Performance](/Skills.aspx?ID=45)
|
||||
[Survival](/Skills.aspx?ID=49) <expert>
|
||||
|
||||
skill corresponding to the target’s casting tradition <trained>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35) <mythic>
|
||||
[Occultism](/Skills.aspx?ID=44) <mythic>
|
||||
|
||||
[Diplomacy](/Skills.aspx?ID=39) <mythic>
|
||||
[Society](/Skills.aspx?ID=47) <mythic>
|
||||
|
||||
[Diplomacy](/Skills.aspx?ID=39) <mythic>
|
||||
[Society](/Skills.aspx?ID=47) <mythic>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35) <mythic>
|
||||
[Nature](/Skills.aspx?ID=43) <mythic>
|
||||
[Occultism](/Skills.aspx?ID=44) <mythic>
|
||||
[Religion](/Skills.aspx?ID=46) <mythic>
|
||||
|
||||
[Occultism](/Skills.aspx?ID=44) <mythic>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35) <mythic>
|
||||
[Occultism](/Skills.aspx?ID=44) <mythic>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35) <mythic>
|
||||
[Occultism](/Skills.aspx?ID=44) <mythic>
|
||||
|
||||
[Crafting](/Skills.aspx?ID=37) <mythic>
|
||||
|
||||
[Nature](/Skills.aspx?ID=43) <mythic>
|
||||
|
||||
[Performance](/Skills.aspx?ID=45) <mythic>
|
||||
|
||||
[Religion](/Skills.aspx?ID=46) <mythic>
|
||||
|
||||
[Nature](/Skills.aspx?ID=43) <mythic>
|
||||
|
||||
[Arcana](/Skills.aspx?ID=35) <mythic>
|
||||
[Nature](/Skills.aspx?ID=43) <mythic>
|
||||
[Occultism](/Skills.aspx?ID=44) <mythic>
|
||||
[Religion](/Skills.aspx?ID=46) <mythic>
|
||||
|
||||
[Nature](/Skills.aspx?ID=43) <master>
|
||||
[Occultism](/Skills.aspx?ID=44) <master>
|
||||
*/
|
||||
+7
-1
@@ -6,7 +6,7 @@ using Pf2eModel.Model.Structure.SpellRelation;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Types;
|
||||
|
||||
[AonprdProcessor("spell")]
|
||||
// [AonprdProcessor("spell")]
|
||||
internal class SpellProcessor(AonprdProcessorInput input) : AbstractEntityProcessor(input)
|
||||
{
|
||||
public override EntityType Type => EntityType.Spell;
|
||||
@@ -25,13 +25,19 @@ internal class SpellProcessor(AonprdProcessorInput input) : AbstractEntityProces
|
||||
Object.Duration = Input.GetOptional<int>("duration", -1);
|
||||
Object.Range = Input.GetOptional<int>("range", -1);
|
||||
|
||||
Object.Cost = Input.GetOptionalLocale("cost_markdown", LocaleType.English);
|
||||
Object.Trigger = Input.GetOptionalLocale("trigger_markdown", LocaleType.English);
|
||||
Object.Target = Input.GetOptionalLocale("target_markdown", LocaleType.English);
|
||||
Object.Requirement = Input.GetOptionalLocale("requirement_markdown", LocaleType.English);
|
||||
|
||||
Object.Traditions = (Input.GetOptional<JArray>("tradition") ?? [])
|
||||
.Select(token => Input.Enum<SpellTradition>(token.ToString()))
|
||||
.ToArray();
|
||||
|
||||
Object.Elements = (Input.GetOptional<JArray>("element") ?? [])
|
||||
.Select(token => Input.Enum<ElementEnum>(token.ToString()))
|
||||
.ToArray();
|
||||
|
||||
switch (Input.GetRequired<string>("spell_type"))
|
||||
{
|
||||
case "Focus":
|
||||
|
||||
Reference in New Issue
Block a user