Ритуалы готовы
This commit is contained in:
+200
-439
@@ -1,7 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Helpers;
|
using Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Helpers;
|
||||||
using Pf2eModel;
|
using Pf2eModel;
|
||||||
@@ -46,11 +48,10 @@ internal partial class RitualProcessor(AonprdProcessorInput input) : AbstractEnt
|
|||||||
|
|
||||||
ProcessArea();
|
ProcessArea();
|
||||||
|
|
||||||
Object.PrimaryCheckSuffix = Input.GetOptionalLocale(
|
ProcessPrimaryChecks();
|
||||||
"primary_check_markdown",
|
ProcessSecondaryChecks();
|
||||||
LocaleType.English
|
|
||||||
);
|
ProcessSecondaryCasters();
|
||||||
// ProcessPrimaryCheck();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CalculateCastTime(string value)
|
private int CalculateCastTime(string value)
|
||||||
@@ -100,7 +101,50 @@ internal partial class RitualProcessor(AonprdProcessorInput input) : AbstractEnt
|
|||||||
Context.RitualAreas.Add(ritualArea);
|
Context.RitualAreas.Add(ritualArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessPrimaryCheck()
|
private readonly Dictionary<string, string> _castersCleanup = new()
|
||||||
|
{
|
||||||
|
[", up to a maximum of "] = "-",
|
||||||
|
[" or more"] = "-999",
|
||||||
|
[" (or more)"] = "-999",
|
||||||
|
["up to "] = "0-",
|
||||||
|
[" to "] = "-",
|
||||||
|
["at least 1"] = "1-999",
|
||||||
|
};
|
||||||
|
|
||||||
|
private void ProcessSecondaryCasters()
|
||||||
|
{
|
||||||
|
string? input = Input.GetOptional<string>("secondary_casters_raw");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(input))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, string> pair in _castersCleanup)
|
||||||
|
{
|
||||||
|
input = input.Replace(pair.Key, pair.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Match match = CasterRegex().Match(input);
|
||||||
|
|
||||||
|
if (!match.Success)
|
||||||
|
{
|
||||||
|
throw new($"Can't parse secondary casters: \"{input}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.SecondaryCasters = int.Parse(M(1));
|
||||||
|
Object.SecondaryCastersMax = (M(2) != "") ? int.Parse(M(2)) : Object.SecondaryCasters;
|
||||||
|
|
||||||
|
if (M(3) != "")
|
||||||
|
{
|
||||||
|
Object.SecondaryCastersSuffix = new() { [LocaleType.English] = M(3) };
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
string M(int i) => match.Groups[i].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessPrimaryChecks()
|
||||||
{
|
{
|
||||||
string? check = Input.GetOptional<string>("primary_check_markdown");
|
string? check = Input.GetOptional<string>("primary_check_markdown");
|
||||||
|
|
||||||
@@ -109,21 +153,129 @@ internal partial class RitualProcessor(AonprdProcessorInput input) : AbstractEnt
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<string> parts = CheckStringPrepare(check);
|
||||||
|
|
||||||
|
string suffix = "";
|
||||||
|
|
||||||
|
// Обработка частей
|
||||||
|
List<RitualCheck> ritualChecks = parts
|
||||||
|
.Select(part => ResolveCheck(part.Trim(), true, out suffix))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (
|
||||||
|
ritualChecks.Any(c => c.Rank == TrainingRank.Untrained)
|
||||||
|
&& ritualChecks.Any(c => c.Rank != TrainingRank.Untrained)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Смешанные ранги
|
||||||
|
TrainingRank[] ranks = ritualChecks
|
||||||
|
.Select(c => c.Rank)
|
||||||
|
.Distinct()
|
||||||
|
.Where(r => r != TrainingRank.Untrained)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (ranks.Length > 1)
|
||||||
|
{
|
||||||
|
throw new($"Can't resolve mixed ranks: {string.Join(", ", ranks)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (
|
||||||
|
RitualCheck ritualCheck in ritualChecks.Where(r => r.Rank == TrainingRank.Untrained)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ritualCheck.Rank = ranks[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suffix != "")
|
||||||
|
{
|
||||||
|
Object.PrimaryCheckSuffix = new() { [LocaleType.English] = suffix };
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (RitualCheck ritualCheck in ritualChecks)
|
||||||
|
{
|
||||||
|
Object.Checks.Add(ritualCheck);
|
||||||
|
Context.RitualChecks.Add(ritualCheck);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessSecondaryChecks()
|
||||||
|
{
|
||||||
|
string? check = Input.GetOptional<string>("secondary_check_markdown");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(check))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> parts = CheckStringPrepare(check);
|
||||||
|
|
||||||
|
foreach (string part in parts)
|
||||||
|
{
|
||||||
|
RitualCheck ritualCheck = ResolveCheck(part.Trim(), false, out string suffix);
|
||||||
|
|
||||||
|
if (suffix != "")
|
||||||
|
{
|
||||||
|
if (ritualCheck.TrainingString is not null)
|
||||||
|
{
|
||||||
|
ritualCheck.TrainingString[LocaleType.English] += $" ({suffix})";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ritualCheck.TrainingString = new() { [LocaleType.English] = suffix };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.Checks.Add(ritualCheck);
|
||||||
|
Context.RitualChecks.Add(ritualCheck);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<string, string> _checksCleanupReplaces = new()
|
||||||
|
{
|
||||||
|
["DC 35 Arcana"] = "Arcana <DC 35>",
|
||||||
|
[")or"] = ") or",
|
||||||
|
["[Lore](/Skills.aspx?ID=41) (any)"] = "[Any Lore](/Skills.aspx?ID=41)",
|
||||||
|
["[Lore](/Skills.aspx?ID=8) (any)"] = "[Any Lore](/Skills.aspx?ID=8)",
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly Dictionary<Regex, string> _checksCleanupRegexes = new()
|
||||||
|
{
|
||||||
|
[new(@"(\w+) \[Lore\]", RegexOptions.Compiled | RegexOptions.Multiline)] = "[$1 Lore]",
|
||||||
|
};
|
||||||
|
|
||||||
|
private List<string> CheckStringPrepare(string input)
|
||||||
|
{
|
||||||
|
// Отчистка проблемных частей
|
||||||
|
foreach (KeyValuePair<string, string> pair in _checksCleanupReplaces)
|
||||||
|
{
|
||||||
|
input = input.Replace(pair.Key, pair.Value);
|
||||||
|
}
|
||||||
|
foreach (KeyValuePair<Regex, string> pair in _checksCleanupRegexes)
|
||||||
|
{
|
||||||
|
input = pair.Key.Replace(input, pair.Value);
|
||||||
|
}
|
||||||
|
|
||||||
// Замена символа ссылок
|
// Замена символа ссылок
|
||||||
check = StringHelper.MarkdownRegex().Replace(check, "$1[$2]{$3}");
|
input = StringHelper.MarkdownRegex().Replace(input, "$1[$2]{$3}");
|
||||||
check = check.Replace("(", "<").Replace(")", ">").Replace("{", "(").Replace("}", ")");
|
input = input.Replace("(", "<").Replace(")", ">").Replace("{", "(").Replace("}", ")");
|
||||||
|
|
||||||
|
if (input.EndsWith(';') || input.EndsWith(','))
|
||||||
|
{
|
||||||
|
input = input[..^1].Trim();
|
||||||
|
}
|
||||||
|
|
||||||
// Временная замена скобок ранга и дополнения
|
// Временная замена скобок ранга и дополнения
|
||||||
#pragma warning disable SYSLIB1045
|
#pragma warning disable SYSLIB1045
|
||||||
MatchCollection rankMatches = new Regex(@"<(.*?)>").Matches(check);
|
MatchCollection rankMatches = new Regex(@"<(.*?)>").Matches(input);
|
||||||
#pragma warning restore SYSLIB1045
|
#pragma warning restore SYSLIB1045
|
||||||
for (int i = 0; i < rankMatches.Count; i++)
|
for (int i = 0; i < rankMatches.Count; i++)
|
||||||
{
|
{
|
||||||
check = check.Replace(rankMatches[i].Value, $"{{rank-{i}}}");
|
input = input.Replace(rankMatches[i].Value, $"{{rank-{i}}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Разбиваем строку на части
|
// Разбиваем строку на части
|
||||||
List<string> parts = StringHelper.RowSplit(check);
|
List<string> parts = StringHelper.RowSplit(input);
|
||||||
|
|
||||||
// Возвращаем скобки ранга и дополнения
|
// Возвращаем скобки ранга и дополнения
|
||||||
for (int i = 0; i < rankMatches.Count; i++)
|
for (int i = 0; i < rankMatches.Count; i++)
|
||||||
@@ -134,71 +286,14 @@ internal partial class RitualProcessor(AonprdProcessorInput input) : AbstractEnt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обработка частей
|
return parts;
|
||||||
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)
|
private RitualCheck ResolveCheck(string input, bool isPrimary, out string suffix)
|
||||||
{
|
{
|
||||||
List<RitualCheck> result = [];
|
RitualCheck result = new() { Ritual = Object, IsPrimary = isPrimary };
|
||||||
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;
|
string? skillName = null;
|
||||||
|
string s = "";
|
||||||
|
|
||||||
Dictionary<Regex, Action<Match>> regexDictionary = new()
|
Dictionary<Regex, Action<Match>> regexDictionary = new()
|
||||||
{
|
{
|
||||||
@@ -207,9 +302,19 @@ internal partial class RitualProcessor(AonprdProcessorInput input) : AbstractEnt
|
|||||||
[PrimaryRegex1()] = match =>
|
[PrimaryRegex1()] = match =>
|
||||||
{
|
{
|
||||||
skillName = match.Groups[1].Value;
|
skillName = match.Groups[1].Value;
|
||||||
result.Rank = Input.Enum<TrainingRank>(match.Groups[4].Value.ToLower());
|
try
|
||||||
primarySuffix +=
|
{
|
||||||
match.Groups[3].Value + match.Groups[5].Value + match.Groups[6].Value;
|
result.Rank = Input.Enum<TrainingRank>(match.Groups[4].Value.ToLower());
|
||||||
|
s += match.Groups[3].Value + match.Groups[5].Value + match.Groups[6].Value;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
s +=
|
||||||
|
match.Groups[3].Value
|
||||||
|
+ match.Groups[4].Value
|
||||||
|
+ match.Groups[5].Value
|
||||||
|
+ match.Groups[6].Value;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// ? [name](url)
|
// ? [name](url)
|
||||||
@@ -217,14 +322,21 @@ internal partial class RitualProcessor(AonprdProcessorInput input) : AbstractEnt
|
|||||||
{
|
{
|
||||||
skillName = match.Groups[2].Value;
|
skillName = match.Groups[2].Value;
|
||||||
result.Rank = TrainingRank.Untrained;
|
result.Rank = TrainingRank.Untrained;
|
||||||
primarySuffix += match.Groups[1].Value;
|
s += match.Groups[1].Value;
|
||||||
},
|
},
|
||||||
|
|
||||||
// name <rank>
|
// name <rank>
|
||||||
[PrimaryRegex3()] = match =>
|
[PrimaryRegex3()] = match =>
|
||||||
{
|
{
|
||||||
skillName = match.Groups[1].Value;
|
skillName = match.Groups[1].Value;
|
||||||
result.Rank = Input.Enum<TrainingRank>(match.Groups[2].Value.ToLower());
|
try
|
||||||
|
{
|
||||||
|
result.Rank = Input.Enum<TrainingRank>(match.Groups[2].Value.ToLower());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
s += match.Groups[2].Value;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -232,25 +344,23 @@ internal partial class RitualProcessor(AonprdProcessorInput input) : AbstractEnt
|
|||||||
{
|
{
|
||||||
Match match = pair.Key.Match(input);
|
Match match = pair.Key.Match(input);
|
||||||
|
|
||||||
if (!match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
continue;
|
pair.Value.Invoke(match);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pair.Value.Invoke(match);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skillName is null)
|
suffix = s;
|
||||||
{
|
|
||||||
throw new($"Can't resolve skill name from \"{input}\"");
|
skillName ??= input;
|
||||||
}
|
|
||||||
|
|
||||||
result.Training = Context.Trainings.FirstOrDefault(t =>
|
result.Training = Context.Trainings.FirstOrDefault(t =>
|
||||||
Pf2eDbContext.LocaleSearch(t.Name, skillName)
|
Pf2eDbContext.LocaleSearch(t.Name, skillName)
|
||||||
);
|
);
|
||||||
|
|
||||||
result.TrainingString =
|
result.TrainingString =
|
||||||
(result.Training is null) ? null : new() { [LocaleType.English] = skillName };
|
(result.Training is not null) ? null : new() { [LocaleType.English] = skillName };
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -263,14 +373,8 @@ internal partial class RitualProcessor(AonprdProcessorInput input) : AbstractEnt
|
|||||||
"secondary_check_markdown",
|
"secondary_check_markdown",
|
||||||
];
|
];
|
||||||
|
|
||||||
[GeneratedRegex(@"\((\/.*?)\)")]
|
|
||||||
private static partial Regex LinkRemoveRegex();
|
|
||||||
|
|
||||||
[GeneratedRegex(@"\((\w*)[;, ]?(.*?)\)")]
|
|
||||||
private static partial Regex PrimaryCheckSuffixRegex();
|
|
||||||
|
|
||||||
[GeneratedRegex(
|
[GeneratedRegex(
|
||||||
@"^ *\[\s*(.*?)\s*\]\((.*?)\)\s*([a-z' ]*?)<(.*?)(?:[;,]\s*(.*?))?>([a-z' ]*?)$",
|
@"^ *\[\s*(.*?)\s*\]\((.*?)\)\s*([a-z' ]*?)<(.*?)(?:[;,]?\s*(.*?))?>([a-z' ]*?)$",
|
||||||
RegexOptions.Multiline
|
RegexOptions.Multiline
|
||||||
)]
|
)]
|
||||||
private static partial Regex PrimaryRegex1();
|
private static partial Regex PrimaryRegex1();
|
||||||
@@ -280,350 +384,7 @@ internal partial class RitualProcessor(AonprdProcessorInput input) : AbstractEnt
|
|||||||
|
|
||||||
[GeneratedRegex(@"^ *(.*?)\s*<(.*?)> *$", RegexOptions.Multiline)]
|
[GeneratedRegex(@"^ *(.*?)\s*<(.*?)> *$", RegexOptions.Multiline)]
|
||||||
private static partial Regex PrimaryRegex3();
|
private static partial Regex PrimaryRegex3();
|
||||||
|
|
||||||
|
[GeneratedRegex(@"^(\d+)(?:\-(\d+))?,? *\(?(.*?)\)?$", RegexOptions.Multiline)]
|
||||||
|
private static partial Regex CasterRegex();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
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>
|
|
||||||
*/
|
|
||||||
|
|||||||
+3
-3
@@ -13,7 +13,7 @@ using Pf2eModel.Model.Enum;
|
|||||||
namespace Pf2eModel.Migrations
|
namespace Pf2eModel.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(Pf2eDbContext))]
|
[DbContext(typeof(Pf2eDbContext))]
|
||||||
[Migration("20250506124313_1")]
|
[Migration("20250506175505_1")]
|
||||||
partial class _1
|
partial class _1
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -1358,9 +1358,9 @@ namespace Pf2eModel.Migrations
|
|||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
b.Property<bool>("IsSecondary")
|
b.Property<bool>("IsPrimary")
|
||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("is_secondary")
|
.HasColumnName("is_primary")
|
||||||
.HasColumnOrder(6);
|
.HasColumnOrder(6);
|
||||||
|
|
||||||
b.Property<TrainingRank>("Rank")
|
b.Property<TrainingRank>("Rank")
|
||||||
@@ -889,7 +889,7 @@ namespace Pf2eModel.Migrations
|
|||||||
training_id = table.Column<int>(type: "integer", nullable: true),
|
training_id = table.Column<int>(type: "integer", nullable: true),
|
||||||
training_string = table.Column<string>(type: "jsonb", nullable: true),
|
training_string = table.Column<string>(type: "jsonb", nullable: true),
|
||||||
rank = table.Column<TrainingRank>(type: "training_rank", nullable: false),
|
rank = table.Column<TrainingRank>(type: "training_rank", nullable: false),
|
||||||
is_secondary = table.Column<bool>(type: "boolean", nullable: false)
|
is_primary = table.Column<bool>(type: "boolean", nullable: false)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
@@ -1355,9 +1355,9 @@ namespace Pf2eModel.Migrations
|
|||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
b.Property<bool>("IsSecondary")
|
b.Property<bool>("IsPrimary")
|
||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("is_secondary")
|
.HasColumnName("is_primary")
|
||||||
.HasColumnOrder(6);
|
.HasColumnOrder(6);
|
||||||
|
|
||||||
b.Property<TrainingRank>("Rank")
|
b.Property<TrainingRank>("Rank")
|
||||||
|
|||||||
@@ -30,5 +30,5 @@ public class RitualCheck
|
|||||||
public TrainingRank Rank { get; set; }
|
public TrainingRank Rank { get; set; }
|
||||||
|
|
||||||
[Column(Order = 6)]
|
[Column(Order = 6)]
|
||||||
public bool IsSecondary { get; set; }
|
public bool IsPrimary { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,12 @@ public class EntityView
|
|||||||
),
|
),
|
||||||
new Getter<Ritual>(
|
new Getter<Ritual>(
|
||||||
EntityType.Ritual,
|
EntityType.Ritual,
|
||||||
context => context.Rituals.Include(r => r.Area).Include(r => r.Checks)
|
context =>
|
||||||
|
context
|
||||||
|
.Rituals.Include(r => r.Area)
|
||||||
|
.Include(r => r.Checks)
|
||||||
|
.ThenInclude(c => c.Training)
|
||||||
|
.AsQueryable()
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user