From 6abda701a499348cb43ca48c47f69e4311ab091f Mon Sep 17 00:00:00 2001 From: kozhilya Date: Tue, 6 May 2025 19:25:11 +0400 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B8=D1=82=D1=83=D0=B0=D0=BB=D1=8B!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Pf2eDataScrapper/Importers/DatabaseHelper.cs | 14 +- .../Aonprd/DataBuilder/AonprdDataBuilder.cs | 2 + .../Helpers/AonprdBuilderGlobals.cs | 2 +- .../DataBuilder/Helpers/StringHelper.cs | 34 +- .../Processors/AbstractEntityProcessor.cs | 5 +- .../Subclasses/ApparitionProcessor.cs | 9 +- .../Processors/Types/AncestryProcessor.cs | 2 +- .../Processors/Types/ClassProcessor.cs | 8 +- .../Processors/Types/RitualProcessor.cs | 629 ++++++++++++++++++ .../Processors/Types/SpellProcessor.cs | 8 +- ...signer.cs => 20250506124313_1.Designer.cs} | 305 +++++++-- ...0250505211157_1.cs => 20250506124313_1.cs} | 140 +++- .../Migrations/Pf2eDbContextModelSnapshot.cs | 303 +++++++-- Pf2eModel/Model/Enum/ElementEnum.cs | 27 + Pf2eModel/Model/Enum/EntityType.cs | 3 + Pf2eModel/Model/Enum/TrainingRank.cs | 24 + Pf2eModel/Model/Enum/TrainingStage.cs | 14 - .../BackgroundRelation/BackgroundTraining.cs | 2 +- .../Structure/ClassRelation/ClassTraining.cs | 2 +- .../ClassRelation/SubclassTrainings.cs | 2 +- Pf2eModel/Model/Structure/Ritual.cs | 67 ++ .../Structure/RitualRelation/RitualArea.cs | 23 + .../Structure/RitualRelation/RitualCheck.cs | 34 + Pf2eModel/Model/Structure/Spell.cs | 31 +- .../Structure/SpellRelation/SpellRitual.cs | 25 - Pf2eModel/Pf2eDbContext.cs | 15 +- Pf2eModel/Pf2eDbContextModel.cs | 53 +- Pf2eViewer/EntityView.cs | 4 + 28 files changed, 1543 insertions(+), 244 deletions(-) create mode 100644 Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/RitualProcessor.cs rename Pf2eModel/Migrations/{20250505211157_1.Designer.cs => 20250506124313_1.Designer.cs} (91%) rename Pf2eModel/Migrations/{20250505211157_1.cs => 20250506124313_1.cs} (92%) create mode 100644 Pf2eModel/Model/Enum/ElementEnum.cs create mode 100644 Pf2eModel/Model/Enum/TrainingRank.cs delete mode 100644 Pf2eModel/Model/Enum/TrainingStage.cs create mode 100644 Pf2eModel/Model/Structure/Ritual.cs create mode 100644 Pf2eModel/Model/Structure/RitualRelation/RitualArea.cs create mode 100644 Pf2eModel/Model/Structure/RitualRelation/RitualCheck.cs delete mode 100644 Pf2eModel/Model/Structure/SpellRelation/SpellRitual.cs diff --git a/Pf2eDataScrapper/Importers/DatabaseHelper.cs b/Pf2eDataScrapper/Importers/DatabaseHelper.cs index 14f5366..718aed3 100644 --- a/Pf2eDataScrapper/Importers/DatabaseHelper.cs +++ b/Pf2eDataScrapper/Importers/DatabaseHelper.cs @@ -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(); + } } diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdDataBuilder.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdDataBuilder.cs index 031ebd8..aa26ef8 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdDataBuilder.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdDataBuilder.cs @@ -101,6 +101,8 @@ internal class AonprdDataBuilder(AonprdLoader loader) } SubProcessProgressBar.Next("Ready"); + + DatabaseHelper.ResetContext(); } ProcessProgressBar.Next("Done!"); diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/AonprdBuilderGlobals.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/AonprdBuilderGlobals.cs index d5b35a9..c6a4191 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/AonprdBuilderGlobals.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/AonprdBuilderGlobals.cs @@ -8,5 +8,5 @@ internal class AonprdBuilderGlobals private AonprdBuilderGlobals() { } - public static AonprdBuilderGlobals Instance = new AonprdBuilderGlobals(); + public static AonprdBuilderGlobals Instance = new(); } diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/StringHelper.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/StringHelper.cs index 134fbf2..5a21e1f 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/StringHelper.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/StringHelper.cs @@ -6,13 +6,25 @@ internal partial class StringHelper { private StringHelper() { } - public List ParseMarkdown(string input) + public List RowSplit(string value) { - List 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 Links = []; + + public string Suffix = ""; } internal class MarkdownLink diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AbstractEntityProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AbstractEntityProcessor.cs index 94a9dea..e742685 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AbstractEntityProcessor.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AbstractEntityProcessor.cs @@ -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(path) ?? ""}"; protected string AddedDescription(string[] paths) => string.Join("", paths.Select(AddedDescription)); - protected virtual string GetDescription() => Input.GetRequired("markdown"); + protected virtual string GetDescription() => + Input.GetRequired("markdown") + AddedDescription(AddedDescriptionPaths()); protected virtual void AddEntity() { diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Subclasses/ApparitionProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Subclasses/ApparitionProcessor.cs index 7b15874..08d2eb2 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Subclasses/ApparitionProcessor.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Subclasses/ApparitionProcessor.cs @@ -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("spells_markdown"); - List spellUrls = StringHelper.ParseMarkdown(spellMd).Select(l => l.Url).ToList(); + List spellUrls = StringHelper + .ParseMarkdownLinks(spellMd) + .Links.Select(l => l.Url) + .ToList(); List 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, } ); } diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/AncestryProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/AncestryProcessor.cs index 4571eef..8ae626a 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/AncestryProcessor.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/AncestryProcessor.cs @@ -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; diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/ClassProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/ClassProcessor.cs index bff7d17..7c60ec7 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/ClassProcessor.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/ClassProcessor.cs @@ -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(m[0].Groups[1].Value); + TrainingRank rank = Input.Enum(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($"{pair.Key.ToLower()}_proficiency"), + Rank = Input.EnumRequired($"{pair.Key.ToLower()}_proficiency"), }; return classTraining; diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/RitualProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/RitualProcessor.cs new file mode 100644 index 0000000..cd2383a --- /dev/null +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/RitualProcessor.cs @@ -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("level"); + Object.Duration = Input.GetOptional("duration", -1); + + Object.Range = Input.GetOptional("range", -1); + Object.RangeString = Input.GetOptionalLocale("range_raw", LocaleType.English); + + Object.CastTime = CalculateCastTime(Input.GetRequired("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("element") ?? []) + .Select(token => Input.Enum(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("area_raw"); + + if (string.IsNullOrEmpty(areaRaw)) + { + return; + } + + string areaType = Input.GetRequired("area_type")[0]; + RitualArea ritualArea = new() + { + Ritual = Object, + Type = Input.Enum(areaType), + Details = new() { [LocaleType.English] = areaRaw }, + }; + + Object.Area = ritualArea; + Context.RitualAreas.Add(ritualArea); + } + + private void ProcessPrimaryCheck() + { + string? check = Input.GetOptional("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 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 ritualChecks = parts.Select(part => ResolveCheck(part, false)).ToList(); + + // TODO + // 1. Проверить ritualChecks, если в каких-то Untrained, а в каком-то есть ранг - все к этому рангу + // 2. Поставить primarySuffix + // 3. Добавить в коллекцию + } + + private List ResolveChecks(string input, bool isSecondary) + { + List result = []; + List> 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 checkOptions = checkStrings.SelectMany(a => a).ToList(); + List skills = Context + .Trainings.Where(t => Pf2eDbContext.LocaleSearchArray(t.Name, checkOptions)) + .ToList(); + + foreach (List 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> regexDictionary = new() + { + // General match + // [name](url) ? ? + [PrimaryRegex1()] = match => + { + skillName = match.Groups[1].Value; + result.Rank = Input.Enum(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 + [PrimaryRegex3()] = match => + { + skillName = match.Groups[1].Value; + result.Rank = Input.Enum(match.Groups[2].Value.ToLower()); + }, + }; + + foreach (KeyValuePair> 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) + +[Religion](/Skills.aspx?ID=13) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Occultism](/Skills.aspx?ID=11) + +[Arcana](/Skills.aspx?ID=2) +[Nature](/Skills.aspx?ID=10) +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Nature](/Skills.aspx?ID=10) +[Religion](/Skills.aspx?ID=13) +[Occultism](/Skills.aspx?ID=11) + +[Religion](/Skills.aspx?ID=13) + +[Nature](/Skills.aspx?ID=10) +[Religion](/Skills.aspx?ID=13) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) + +[Occultism](/Skills.aspx?ID=11) + +[Religion](/Skills.aspx?ID=13) + +[Occultism](/Skills.aspx?ID=11) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) + +[Nature](/Skills.aspx?ID=10) + +[Crafting](/Skills.aspx?ID=4) + +[Occultism](/Skills.aspx?ID=11) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) + +[Occultism](/Skills.aspx?ID=11) + +[Occultism](/Skills.aspx?ID=11) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) + +[Nature](/Skills.aspx?ID=10) + +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Occultism](/Skills.aspx?ID=11) + +[Occultism](/Skills.aspx?ID=11) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) + +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Occultism](/Skills.aspx?ID=11) + +[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 + +[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 + +[Religion](/Skills.aspx?ID=13) + +[Performance](/Skills.aspx?ID=12) + +[Occultism](/Skills.aspx?ID=11) + [Religion](/Skills.aspx?ID=13) + +DC 40 [Arcana](/Skills.aspx?ID=2) +[Nature](/Skills.aspx?ID=10) + +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Nature](/Skills.aspx?ID=10) + +[Religion](/Skills.aspx?ID=13) + +[Nature](/Skills.aspx?ID=10) + +[Nature](/Skills.aspx?ID=10) + +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) + +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) + +[Religion](/Skills.aspx?ID=13) + +[Crafting](/Skills.aspx?ID=4) +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Arcana](/Skills.aspx?ID=2) + +[Nature](/Skills.aspx?ID=10) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) + +[Occultism](/Skills.aspx?ID=11) + +[Fortune-Telling Lore](/Skills.aspx?ID=8) +[Occultism](/Skills.aspx?ID=11) + +[Performance](/Skills.aspx?ID=12) + +[Nature](/Skills.aspx?ID=10) + +[Nature](/Skills.aspx?ID=10) + +[Arcana](/Skills.aspx?ID=2) +[Nature](/Skills.aspx?ID=10) + +Occultism +Religion + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) + +[Arcana](/Skills.aspx?ID=2) + + [Nature](/Skills.aspx?ID=10) +[Religion](/Skills.aspx?ID=13) + +[Nature](/Skills.aspx?ID=10) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) + +[Nature](/Skills.aspx?ID=10) + +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Occultism](/Skills.aspx?ID=11) + +[Nature](/Skills.aspx?ID=10) +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Religion](/Skills.aspx?ID=13) + +[Nature](/Skills.aspx?ID=10) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Arcana](/Skills.aspx?ID=2) +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Arcana](/Skills.aspx?ID=2) +[Nature](/Skills.aspx?ID=10) +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Religion](/Skills.aspx?ID=13) + +[Nature](/Skills.aspx?ID=10) + +[Nature](/Skills.aspx?ID=10) + + [Religion](/Skills.aspx?ID=13) + +[Arcana](/Skills.aspx?ID=2) +[Nature](/Skills.aspx?ID=10) +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) as determined by the tradition of spell cast in the ritual + +[Arcana](/Skills.aspx?ID=2) +[Nature](/Skills.aspx?ID=10) +[Occultism](/Skills.aspx?ID=11) +[Religion](/Skills.aspx?ID=13) + +[Diplomacy ](/Skills.aspx?ID=39) + +[Occultism ](/Skills.aspx?ID=44) +[Survival](/Skills.aspx?ID=49) + +[Occultism ](/Skills.aspx?ID=44) +[Religion ](/Skills.aspx?ID=46) + +[Religion](/Skills.aspx?ID=46) + +[Performance ](/Skills.aspx?ID=45) + +[Cooking Lore](/Skills.aspx?ID=41) + +[Cooking Lore](/Skills.aspx?ID=41) +[Tea Lore ](/Skills.aspx?ID=41) + +[Crafting](/Skills.aspx?ID=37) + +[Athletics](/Skills.aspx?ID=36) + +[Medicine](/Skills.aspx?ID=42) + +[Perception](/Rules.aspx?ID=2298) + +[Diplomacy](/Skills.aspx?ID=39) + +[Religion](/Skills.aspx?ID=46) + +[Religion](/Skills.aspx?ID=46) + +[Religion](/Skills.aspx?ID=46) + +[Arcana](/Skills.aspx?ID=35) +[Occultism](/Skills.aspx?ID=44) + +[Crafting](/Skills.aspx?ID=37) + +[Arcana](/Skills.aspx?ID=35) +[Occultism](/Skills.aspx?ID=44) + +[Crafting](/Skills.aspx?ID=37) +[Nature](/Skills.aspx?ID=43) +[Society](/Skills.aspx?ID=47) + +[Arcana](/Skills.aspx?ID=35) +[Occultism](/Skills.aspx?ID=44) + +[Nature](/Skills.aspx?ID=43) +[Religion](/Skills.aspx?ID=46) + +[Arcana](/Skills.aspx?ID=35) +[Occultism](/Skills.aspx?ID=44) +[Religion](/Skills.aspx?ID=46) + +[Arcana](/Skills.aspx?ID=35) +[Occultism](/Skills.aspx?ID=44) + +[Nature](/Skills.aspx?ID=43) + +[Religion](/Skills.aspx?ID=46) + +[Arcana](/Skills.aspx?ID=35) +[Occultism](/Skills.aspx?ID=44) + +[Arcana](/Skills.aspx?ID=35) +[Occultism](/Skills.aspx?ID=44) + +[Arcana](/Skills.aspx?ID=35) +[Nature](/Skills.aspx?ID=43) +[Occultism](/Skills.aspx?ID=44) + +[Cooking Lore](/Skills.aspx?ID=41) +[Crafting](/Skills.aspx?ID=37) +[Performance](/Skills.aspx?ID=45) +[Survival](/Skills.aspx?ID=49) + +[Medicine](/Skills.aspx?ID=42) + +[Cooking Lore](/Skills.aspx?ID=41) +[Crafting](/Skills.aspx?ID=37) +[Performance](/Skills.aspx?ID=45) +[Survival](/Skills.aspx?ID=49) + +skill corresponding to the target’s casting tradition + +[Arcana](/Skills.aspx?ID=35) +[Occultism](/Skills.aspx?ID=44) + +[Diplomacy](/Skills.aspx?ID=39) +[Society](/Skills.aspx?ID=47) + +[Diplomacy](/Skills.aspx?ID=39) +[Society](/Skills.aspx?ID=47) + +[Arcana](/Skills.aspx?ID=35) +[Nature](/Skills.aspx?ID=43) +[Occultism](/Skills.aspx?ID=44) +[Religion](/Skills.aspx?ID=46) + +[Occultism](/Skills.aspx?ID=44) + +[Arcana](/Skills.aspx?ID=35) +[Occultism](/Skills.aspx?ID=44) + +[Arcana](/Skills.aspx?ID=35) +[Occultism](/Skills.aspx?ID=44) + +[Crafting](/Skills.aspx?ID=37) + +[Nature](/Skills.aspx?ID=43) + +[Performance](/Skills.aspx?ID=45) + +[Religion](/Skills.aspx?ID=46) + +[Nature](/Skills.aspx?ID=43) + +[Arcana](/Skills.aspx?ID=35) +[Nature](/Skills.aspx?ID=43) +[Occultism](/Skills.aspx?ID=44) +[Religion](/Skills.aspx?ID=46) + +[Nature](/Skills.aspx?ID=43) +[Occultism](/Skills.aspx?ID=44) +*/ diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/SpellProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/SpellProcessor.cs index 617f861..81e5b6b 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/SpellProcessor.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/SpellProcessor.cs @@ -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("duration", -1); Object.Range = Input.GetOptional("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("tradition") ?? []) .Select(token => Input.Enum(token.ToString())) .ToArray(); + Object.Elements = (Input.GetOptional("element") ?? []) + .Select(token => Input.Enum(token.ToString())) + .ToArray(); + switch (Input.GetRequired("spell_type")) { case "Focus": diff --git a/Pf2eModel/Migrations/20250505211157_1.Designer.cs b/Pf2eModel/Migrations/20250506124313_1.Designer.cs similarity index 91% rename from Pf2eModel/Migrations/20250505211157_1.Designer.cs rename to Pf2eModel/Migrations/20250506124313_1.Designer.cs index ee58128..8164062 100644 --- a/Pf2eModel/Migrations/20250505211157_1.Designer.cs +++ b/Pf2eModel/Migrations/20250506124313_1.Designer.cs @@ -13,7 +13,7 @@ using Pf2eModel.Model.Enum; namespace Pf2eModel.Migrations { [DbContext(typeof(Pf2eDbContext))] - [Migration("20250505211157_1")] + [Migration("20250506124313_1")] partial class _1 { /// @@ -34,7 +34,7 @@ namespace Pf2eModel.Migrations NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "deity_fonts", new[] { "none", "heal", "harm", "any" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "deity_sanctification", new[] { "holy", "unholy", "any" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_rarity", new[] { "common", "uncommon", "rare", "unique" }); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_type", new[] { "unknown", "trait", "action", "ancestry", "archetype", "background", "backpack", "campaign_feature", "class", "subclass_group", "subclass", "condition", "deity", "feat", "heritage", "spell", "language" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_type", new[] { "unknown", "trait", "action", "ancestry", "archetype", "background", "backpack", "campaign_feature", "class", "subclass_group", "subclass", "condition", "deity", "feat", "heritage", "spell", "ritual", "language" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "feat_action_type", new[] { "passive", "action", "reaction", "free" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "feat_category", new[] { "uncategorized", "ancestry-feature", "class-feature", "calling", "class", "skill", "general", "ancestry", "bonus", "deityboon", "curse", "pfsboon", "campaign-feature" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "locale_type", new[] { "english", "legacy_english", "russian", "legacy", "hobby", "other" }); @@ -44,7 +44,7 @@ namespace Pf2eModel.Migrations NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "spell_damage_category", new[] { "persistent", "splash" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "spell_damage_kinds", new[] { "damage", "healing", "any" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "spell_tradition", new[] { "none", "divine", "occult", "arcane", "primal", "elemental", "all" }); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "training_stage", new[] { "untrained", "trained", "expert", "master", "legendary" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "training_rank", new[] { "untrained", "trained", "expert", "master", "legendary", "mythic" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "trait_type", new[] { "regular", "class", "tradition" }); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -708,9 +708,9 @@ namespace Pf2eModel.Migrations .HasColumnName("background_id") .HasColumnOrder(2); - b.Property("Level") - .HasColumnType("training_stage") - .HasColumnName("level") + b.Property("Rank") + .HasColumnType("training_rank") + .HasColumnName("rank") .HasColumnOrder(4); b.Property("TrainingId") @@ -854,9 +854,9 @@ namespace Pf2eModel.Migrations .HasColumnName("class_id") .HasColumnOrder(2); - b.Property("Stage") - .HasColumnType("training_stage") - .HasColumnName("stage") + b.Property("Rank") + .HasColumnType("training_rank") + .HasColumnName("rank") .HasColumnOrder(4); b.Property("TrainingId") @@ -905,9 +905,9 @@ namespace Pf2eModel.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("Stage") - .HasColumnType("training_stage") - .HasColumnName("stage") + b.Property("Rank") + .HasColumnType("training_rank") + .HasColumnName("rank") .HasColumnOrder(4); b.Property("SubclassId") @@ -1238,6 +1238,163 @@ namespace Pf2eModel.Migrations b.ToTable("languages", (string)null); }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Ritual", b => + { + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("id") + .HasColumnOrder(1); + + b.Property("CastTime") + .HasColumnType("integer") + .HasColumnName("cast_time") + .HasColumnOrder(3) + .HasComment("Продолжительность ритуала в секундах"); + + b.Property("Cost") + .HasColumnType("jsonb") + .HasColumnName("cost") + .HasColumnOrder(14); + + b.Property("Duration") + .HasColumnType("integer") + .HasColumnName("duration") + .HasColumnOrder(4) + .HasComment("Время действия эффекта ритуала в секундах"); + + b.PrimitiveCollection("Elements") + .IsRequired() + .HasColumnType("integer[]") + .HasColumnName("elements") + .HasColumnOrder(5); + + b.Property("Level") + .HasColumnType("integer") + .HasColumnName("level") + .HasColumnOrder(2); + + b.Property("PrimaryCheckRank") + .HasColumnType("training_rank") + .HasColumnName("primary_check_rank") + .HasColumnOrder(7); + + b.Property("PrimaryCheckSuffix") + .HasColumnType("jsonb") + .HasColumnName("primary_check_suffix") + .HasColumnOrder(8); + + b.Property("Range") + .HasColumnType("integer") + .HasColumnName("range") + .HasColumnOrder(6); + + b.Property("RangeString") + .HasColumnType("jsonb") + .HasColumnName("range_string") + .HasColumnOrder(12); + + b.Property("Requirement") + .HasColumnType("jsonb") + .HasColumnName("requirement") + .HasColumnOrder(15); + + b.Property("SecondaryCasters") + .HasColumnType("integer") + .HasColumnName("secondary_casters") + .HasColumnOrder(9); + + b.Property("SecondaryCastersMax") + .HasColumnType("integer") + .HasColumnName("secondary_casters_max") + .HasColumnOrder(10); + + b.Property("SecondaryCastersSuffix") + .HasColumnType("jsonb") + .HasColumnName("secondary_casters_suffix") + .HasColumnOrder(11); + + b.Property("Target") + .HasColumnType("jsonb") + .HasColumnName("target") + .HasColumnOrder(13); + + b.HasKey("Id") + .HasName("pk_rituals"); + + b.ToTable("rituals", (string)null); + }); + + modelBuilder.Entity("Pf2eModel.Model.Structure.RitualRelation.RitualArea", b => + { + b.Property("RitualId") + .HasColumnType("integer") + .HasColumnName("ritual_id") + .HasColumnOrder(1); + + b.Property("Details") + .HasMaxLength(255) + .HasColumnType("jsonb") + .HasColumnName("details") + .HasColumnOrder(2); + + b.Property("Type") + .HasColumnType("spell_area_type") + .HasColumnName("type") + .HasColumnOrder(3); + + b.HasKey("RitualId") + .HasName("pk_ritual_areas"); + + b.ToTable("ritual_areas", (string)null); + }); + + modelBuilder.Entity("Pf2eModel.Model.Structure.RitualRelation.RitualCheck", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id") + .HasColumnOrder(1); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("IsSecondary") + .HasColumnType("boolean") + .HasColumnName("is_secondary") + .HasColumnOrder(6); + + b.Property("Rank") + .HasColumnType("training_rank") + .HasColumnName("rank") + .HasColumnOrder(5); + + b.Property("RitualId") + .HasColumnType("integer") + .HasColumnName("ritual_id") + .HasColumnOrder(2); + + b.Property("TrainingId") + .HasColumnType("integer") + .HasColumnName("training_id") + .HasColumnOrder(3); + + b.Property("TrainingString") + .HasColumnType("jsonb") + .HasColumnName("training_string") + .HasColumnOrder(4); + + b.HasKey("Id") + .HasName("pk_ritual_checks"); + + b.HasIndex("RitualId") + .HasDatabaseName("ix_ritual_checks_ritual_id"); + + b.HasIndex("TrainingId") + .HasDatabaseName("ix_ritual_checks_training_id"); + + b.ToTable("ritual_checks", (string)null); + }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Spell", b => { b.Property("Id") @@ -1248,18 +1405,29 @@ namespace Pf2eModel.Migrations b.Property("Actions") .HasColumnType("action_enum") .HasColumnName("actions") - .HasColumnOrder(3); + .HasColumnOrder(4); + + b.Property("Cost") + .HasColumnType("jsonb") + .HasColumnName("cost") + .HasColumnOrder(11); b.Property("Duration") .HasMaxLength(255) .HasColumnType("integer") .HasColumnName("duration") - .HasColumnOrder(4); + .HasColumnOrder(5); + + b.PrimitiveCollection("Elements") + .IsRequired() + .HasColumnType("integer[]") + .HasColumnName("elements") + .HasColumnOrder(8); b.Property("IsFocus") .HasColumnType("boolean") .HasColumnName("is_focus") - .HasColumnOrder(5); + .HasColumnOrder(3); b.Property("Level") .HasColumnType("integer") @@ -1271,21 +1439,26 @@ namespace Pf2eModel.Migrations .HasColumnName("range") .HasColumnOrder(6); + b.Property("Requirement") + .HasColumnType("jsonb") + .HasColumnName("requirement") + .HasColumnOrder(12); + b.Property("Target") .HasColumnType("jsonb") .HasColumnName("target") - .HasColumnOrder(8); + .HasColumnOrder(10); b.PrimitiveCollection("Traditions") .IsRequired() .HasColumnType("spell_tradition[]") .HasColumnName("traditions") - .HasColumnOrder(6); + .HasColumnOrder(7); b.Property("Trigger") .HasColumnType("jsonb") .HasColumnName("trigger") - .HasColumnOrder(7); + .HasColumnOrder(9); b.HasKey("Id") .HasName("pk_spells"); @@ -1435,38 +1608,6 @@ namespace Pf2eModel.Migrations b.ToTable("spell_defenses", (string)null); }); - modelBuilder.Entity("Pf2eModel.Model.Structure.SpellRelation.SpellRitual", b => - { - b.Property("SpellId") - .HasColumnType("integer") - .HasColumnName("spell_id") - .HasColumnOrder(1); - - b.Property("PrimaryCheck") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("primary_check") - .HasColumnOrder(2); - - b.Property("SecondaryCasters") - .HasColumnType("integer") - .HasColumnName("secondary_casters") - .HasColumnOrder(3); - - b.Property("SecondaryChecks") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("secondary_checks") - .HasColumnOrder(4); - - b.HasKey("SpellId") - .HasName("pk_spell_rituals"); - - b.ToTable("spell_rituals", (string)null); - }); - modelBuilder.Entity("Pf2eModel.Model.Structure.Subclass", b => { b.Property("Id") @@ -2064,6 +2205,50 @@ namespace Pf2eModel.Migrations b.Navigation("Entity"); }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Ritual", b => + { + b.HasOne("Pf2eModel.Model.Base.Entity", "Entity") + .WithOne() + .HasForeignKey("Pf2eModel.Model.Structure.Ritual", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_rituals_entities_id"); + + b.Navigation("Entity"); + }); + + modelBuilder.Entity("Pf2eModel.Model.Structure.RitualRelation.RitualArea", b => + { + b.HasOne("Pf2eModel.Model.Structure.Ritual", "Ritual") + .WithOne("Area") + .HasForeignKey("Pf2eModel.Model.Structure.RitualRelation.RitualArea", "RitualId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_ritual_areas_rituals_ritual_id"); + + b.Navigation("Ritual"); + }); + + modelBuilder.Entity("Pf2eModel.Model.Structure.RitualRelation.RitualCheck", b => + { + b.HasOne("Pf2eModel.Model.Structure.Ritual", "Ritual") + .WithMany("Checks") + .HasForeignKey("RitualId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_ritual_checks_rituals_ritual_id"); + + b.HasOne("Pf2eModel.Model.Common.Training", "Training") + .WithMany() + .HasForeignKey("TrainingId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_ritual_checks_trainings_training_id"); + + b.Navigation("Ritual"); + + b.Navigation("Training"); + }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Spell", b => { b.HasOne("Pf2eModel.Model.Base.Entity", "Entity") @@ -2112,17 +2297,6 @@ namespace Pf2eModel.Migrations b.Navigation("Spell"); }); - modelBuilder.Entity("Pf2eModel.Model.Structure.SpellRelation.SpellRitual", b => - { - b.HasOne("Pf2eModel.Model.Structure.Spell", "Spell") - .WithOne("SpellRitual") - .HasForeignKey("Pf2eModel.Model.Structure.SpellRelation.SpellRitual", "SpellId") - .OnDelete(DeleteBehavior.Cascade) - .HasConstraintName("fk_spell_rituals_spells_spell_id"); - - b.Navigation("Spell"); - }); - modelBuilder.Entity("Pf2eModel.Model.Structure.Subclass", b => { b.HasOne("Pf2eModel.Model.Structure.SubclassGroup", "Group") @@ -2245,13 +2419,18 @@ namespace Pf2eModel.Migrations b.Navigation("FeatPrerequisites"); }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Ritual", b => + { + b.Navigation("Area"); + + b.Navigation("Checks"); + }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Spell", b => { b.Navigation("SpellAreas"); b.Navigation("SpellDefenses"); - - b.Navigation("SpellRitual"); }); modelBuilder.Entity("Pf2eModel.Model.Structure.Subclass", b => diff --git a/Pf2eModel/Migrations/20250505211157_1.cs b/Pf2eModel/Migrations/20250506124313_1.cs similarity index 92% rename from Pf2eModel/Migrations/20250505211157_1.cs rename to Pf2eModel/Migrations/20250506124313_1.cs index 5a380f6..e6384d3 100644 --- a/Pf2eModel/Migrations/20250505211157_1.cs +++ b/Pf2eModel/Migrations/20250506124313_1.cs @@ -24,7 +24,7 @@ namespace Pf2eModel.Migrations .Annotation("Npgsql:Enum:deity_fonts", "none,heal,harm,any") .Annotation("Npgsql:Enum:deity_sanctification", "holy,unholy,any") .Annotation("Npgsql:Enum:entity_rarity", "common,uncommon,rare,unique") - .Annotation("Npgsql:Enum:entity_type", "unknown,trait,action,ancestry,archetype,background,backpack,campaign_feature,class,subclass_group,subclass,condition,deity,feat,heritage,spell,language") + .Annotation("Npgsql:Enum:entity_type", "unknown,trait,action,ancestry,archetype,background,backpack,campaign_feature,class,subclass_group,subclass,condition,deity,feat,heritage,spell,ritual,language") .Annotation("Npgsql:Enum:feat_action_type", "passive,action,reaction,free") .Annotation("Npgsql:Enum:feat_category", "uncategorized,ancestry-feature,class-feature,calling,class,skill,general,ancestry,bonus,deityboon,curse,pfsboon,campaign-feature") .Annotation("Npgsql:Enum:locale_type", "english,legacy_english,russian,legacy,hobby,other") @@ -34,7 +34,7 @@ namespace Pf2eModel.Migrations .Annotation("Npgsql:Enum:spell_damage_category", "persistent,splash") .Annotation("Npgsql:Enum:spell_damage_kinds", "damage,healing,any") .Annotation("Npgsql:Enum:spell_tradition", "none,divine,occult,arcane,primal,elemental,all") - .Annotation("Npgsql:Enum:training_stage", "untrained,trained,expert,master,legendary") + .Annotation("Npgsql:Enum:training_rank", "untrained,trained,expert,master,legendary,mythic") .Annotation("Npgsql:Enum:trait_type", "regular,class,tradition"); migrationBuilder.CreateTable( @@ -293,19 +293,53 @@ namespace Pf2eModel.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "rituals", + columns: table => new + { + id = table.Column(type: "integer", nullable: false), + level = table.Column(type: "integer", nullable: false), + cast_time = table.Column(type: "integer", nullable: false, comment: "Продолжительность ритуала в секундах"), + duration = table.Column(type: "integer", nullable: false, comment: "Время действия эффекта ритуала в секундах"), + elements = table.Column(type: "integer[]", nullable: false), + range = table.Column(type: "integer", nullable: false), + primary_check_rank = table.Column(type: "training_rank", nullable: false), + primary_check_suffix = table.Column(type: "jsonb", nullable: true), + secondary_casters = table.Column(type: "integer", nullable: false), + secondary_casters_max = table.Column(type: "integer", nullable: false), + secondary_casters_suffix = table.Column(type: "jsonb", nullable: true), + range_string = table.Column(type: "jsonb", nullable: true), + target = table.Column(type: "jsonb", nullable: true), + cost = table.Column(type: "jsonb", nullable: true), + requirement = table.Column(type: "jsonb", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_rituals", x => x.id); + table.ForeignKey( + name: "fk_rituals_entities_id", + column: x => x.id, + principalTable: "entities", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "spells", columns: table => new { id = table.Column(type: "integer", nullable: false), level = table.Column(type: "integer", nullable: false), + is_focus = table.Column(type: "boolean", nullable: false), actions = table.Column(type: "action_enum", nullable: false), duration = table.Column(type: "integer", maxLength: 255, nullable: true), - is_focus = table.Column(type: "boolean", nullable: false), - traditions = table.Column(type: "spell_tradition[]", nullable: false), range = table.Column(type: "integer", nullable: false), + traditions = table.Column(type: "spell_tradition[]", nullable: false), + elements = table.Column(type: "integer[]", nullable: false), trigger = table.Column(type: "jsonb", nullable: true), - target = table.Column(type: "jsonb", nullable: true) + target = table.Column(type: "jsonb", nullable: true), + cost = table.Column(type: "jsonb", nullable: true), + requirement = table.Column(type: "jsonb", nullable: true) }, constraints: table => { @@ -554,7 +588,7 @@ namespace Pf2eModel.Migrations id = table.Column(type: "integer", nullable: false), background_id = table.Column(type: "integer", nullable: false), training_id = table.Column(type: "integer", nullable: false), - level = table.Column(type: "training_stage", nullable: false) + rank = table.Column(type: "training_rank", nullable: false) }, constraints: table => { @@ -629,7 +663,7 @@ namespace Pf2eModel.Migrations .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), class_id = table.Column(type: "integer", nullable: false), training_id = table.Column(type: "integer", nullable: true), - stage = table.Column(type: "training_stage", nullable: false) + rank = table.Column(type: "training_rank", nullable: false) }, constraints: table => { @@ -826,6 +860,54 @@ namespace Pf2eModel.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "ritual_areas", + columns: table => new + { + ritual_id = table.Column(type: "integer", nullable: false), + details = table.Column(type: "jsonb", maxLength: 255, nullable: true), + type = table.Column(type: "spell_area_type", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_ritual_areas", x => x.ritual_id); + table.ForeignKey( + name: "fk_ritual_areas_rituals_ritual_id", + column: x => x.ritual_id, + principalTable: "rituals", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ritual_checks", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + ritual_id = table.Column(type: "integer", nullable: false), + training_id = table.Column(type: "integer", nullable: true), + training_string = table.Column(type: "jsonb", nullable: true), + rank = table.Column(type: "training_rank", nullable: false), + is_secondary = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_ritual_checks", x => x.id); + table.ForeignKey( + name: "fk_ritual_checks_rituals_ritual_id", + column: x => x.ritual_id, + principalTable: "rituals", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_ritual_checks_trainings_training_id", + column: x => x.training_id, + principalTable: "trainings", + principalColumn: "id", + onDelete: ReferentialAction.SetNull); + }); + migrationBuilder.CreateTable( name: "deity_spells", columns: table => new @@ -922,26 +1004,6 @@ namespace Pf2eModel.Migrations onDelete: ReferentialAction.Cascade); }); - migrationBuilder.CreateTable( - name: "spell_rituals", - columns: table => new - { - spell_id = table.Column(type: "integer", nullable: false), - primary_check = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), - secondary_casters = table.Column(type: "integer", nullable: false), - secondary_checks = table.Column(type: "character varying(255)", maxLength: 255, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_spell_rituals", x => x.spell_id); - table.ForeignKey( - name: "fk_spell_rituals_spells_spell_id", - column: x => x.spell_id, - principalTable: "spells", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - migrationBuilder.CreateTable( name: "entity_trait", columns: table => new @@ -1048,7 +1110,7 @@ namespace Pf2eModel.Migrations .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), subclass_id = table.Column(type: "integer", nullable: false), training_id = table.Column(type: "integer", nullable: false), - stage = table.Column(type: "training_stage", nullable: false) + rank = table.Column(type: "training_rank", nullable: false) }, constraints: table => { @@ -1203,6 +1265,16 @@ namespace Pf2eModel.Migrations table: "languages", column: "entity_id"); + migrationBuilder.CreateIndex( + name: "ix_ritual_checks_ritual_id", + table: "ritual_checks", + column: "ritual_id"); + + migrationBuilder.CreateIndex( + name: "ix_ritual_checks_training_id", + table: "ritual_checks", + column: "training_id"); + migrationBuilder.CreateIndex( name: "ix_spell_areas_spell_id", table: "spell_areas", @@ -1322,6 +1394,12 @@ namespace Pf2eModel.Migrations migrationBuilder.DropTable( name: "keyword_aliases"); + migrationBuilder.DropTable( + name: "ritual_areas"); + + migrationBuilder.DropTable( + name: "ritual_checks"); + migrationBuilder.DropTable( name: "spell_areas"); @@ -1331,9 +1409,6 @@ namespace Pf2eModel.Migrations migrationBuilder.DropTable( name: "spell_defenses"); - migrationBuilder.DropTable( - name: "spell_rituals"); - migrationBuilder.DropTable( name: "subclass_provided_entities"); @@ -1367,6 +1442,9 @@ namespace Pf2eModel.Migrations migrationBuilder.DropTable( name: "keywords"); + migrationBuilder.DropTable( + name: "rituals"); + migrationBuilder.DropTable( name: "spells"); diff --git a/Pf2eModel/Migrations/Pf2eDbContextModelSnapshot.cs b/Pf2eModel/Migrations/Pf2eDbContextModelSnapshot.cs index a0dd2fc..2b14fa3 100644 --- a/Pf2eModel/Migrations/Pf2eDbContextModelSnapshot.cs +++ b/Pf2eModel/Migrations/Pf2eDbContextModelSnapshot.cs @@ -31,7 +31,7 @@ namespace Pf2eModel.Migrations NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "deity_fonts", new[] { "none", "heal", "harm", "any" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "deity_sanctification", new[] { "holy", "unholy", "any" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_rarity", new[] { "common", "uncommon", "rare", "unique" }); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_type", new[] { "unknown", "trait", "action", "ancestry", "archetype", "background", "backpack", "campaign_feature", "class", "subclass_group", "subclass", "condition", "deity", "feat", "heritage", "spell", "language" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_type", new[] { "unknown", "trait", "action", "ancestry", "archetype", "background", "backpack", "campaign_feature", "class", "subclass_group", "subclass", "condition", "deity", "feat", "heritage", "spell", "ritual", "language" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "feat_action_type", new[] { "passive", "action", "reaction", "free" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "feat_category", new[] { "uncategorized", "ancestry-feature", "class-feature", "calling", "class", "skill", "general", "ancestry", "bonus", "deityboon", "curse", "pfsboon", "campaign-feature" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "locale_type", new[] { "english", "legacy_english", "russian", "legacy", "hobby", "other" }); @@ -41,7 +41,7 @@ namespace Pf2eModel.Migrations NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "spell_damage_category", new[] { "persistent", "splash" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "spell_damage_kinds", new[] { "damage", "healing", "any" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "spell_tradition", new[] { "none", "divine", "occult", "arcane", "primal", "elemental", "all" }); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "training_stage", new[] { "untrained", "trained", "expert", "master", "legendary" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "training_rank", new[] { "untrained", "trained", "expert", "master", "legendary", "mythic" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "trait_type", new[] { "regular", "class", "tradition" }); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -705,9 +705,9 @@ namespace Pf2eModel.Migrations .HasColumnName("background_id") .HasColumnOrder(2); - b.Property("Level") - .HasColumnType("training_stage") - .HasColumnName("level") + b.Property("Rank") + .HasColumnType("training_rank") + .HasColumnName("rank") .HasColumnOrder(4); b.Property("TrainingId") @@ -851,9 +851,9 @@ namespace Pf2eModel.Migrations .HasColumnName("class_id") .HasColumnOrder(2); - b.Property("Stage") - .HasColumnType("training_stage") - .HasColumnName("stage") + b.Property("Rank") + .HasColumnType("training_rank") + .HasColumnName("rank") .HasColumnOrder(4); b.Property("TrainingId") @@ -902,9 +902,9 @@ namespace Pf2eModel.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("Stage") - .HasColumnType("training_stage") - .HasColumnName("stage") + b.Property("Rank") + .HasColumnType("training_rank") + .HasColumnName("rank") .HasColumnOrder(4); b.Property("SubclassId") @@ -1235,6 +1235,163 @@ namespace Pf2eModel.Migrations b.ToTable("languages", (string)null); }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Ritual", b => + { + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("id") + .HasColumnOrder(1); + + b.Property("CastTime") + .HasColumnType("integer") + .HasColumnName("cast_time") + .HasColumnOrder(3) + .HasComment("Продолжительность ритуала в секундах"); + + b.Property("Cost") + .HasColumnType("jsonb") + .HasColumnName("cost") + .HasColumnOrder(14); + + b.Property("Duration") + .HasColumnType("integer") + .HasColumnName("duration") + .HasColumnOrder(4) + .HasComment("Время действия эффекта ритуала в секундах"); + + b.PrimitiveCollection("Elements") + .IsRequired() + .HasColumnType("integer[]") + .HasColumnName("elements") + .HasColumnOrder(5); + + b.Property("Level") + .HasColumnType("integer") + .HasColumnName("level") + .HasColumnOrder(2); + + b.Property("PrimaryCheckRank") + .HasColumnType("training_rank") + .HasColumnName("primary_check_rank") + .HasColumnOrder(7); + + b.Property("PrimaryCheckSuffix") + .HasColumnType("jsonb") + .HasColumnName("primary_check_suffix") + .HasColumnOrder(8); + + b.Property("Range") + .HasColumnType("integer") + .HasColumnName("range") + .HasColumnOrder(6); + + b.Property("RangeString") + .HasColumnType("jsonb") + .HasColumnName("range_string") + .HasColumnOrder(12); + + b.Property("Requirement") + .HasColumnType("jsonb") + .HasColumnName("requirement") + .HasColumnOrder(15); + + b.Property("SecondaryCasters") + .HasColumnType("integer") + .HasColumnName("secondary_casters") + .HasColumnOrder(9); + + b.Property("SecondaryCastersMax") + .HasColumnType("integer") + .HasColumnName("secondary_casters_max") + .HasColumnOrder(10); + + b.Property("SecondaryCastersSuffix") + .HasColumnType("jsonb") + .HasColumnName("secondary_casters_suffix") + .HasColumnOrder(11); + + b.Property("Target") + .HasColumnType("jsonb") + .HasColumnName("target") + .HasColumnOrder(13); + + b.HasKey("Id") + .HasName("pk_rituals"); + + b.ToTable("rituals", (string)null); + }); + + modelBuilder.Entity("Pf2eModel.Model.Structure.RitualRelation.RitualArea", b => + { + b.Property("RitualId") + .HasColumnType("integer") + .HasColumnName("ritual_id") + .HasColumnOrder(1); + + b.Property("Details") + .HasMaxLength(255) + .HasColumnType("jsonb") + .HasColumnName("details") + .HasColumnOrder(2); + + b.Property("Type") + .HasColumnType("spell_area_type") + .HasColumnName("type") + .HasColumnOrder(3); + + b.HasKey("RitualId") + .HasName("pk_ritual_areas"); + + b.ToTable("ritual_areas", (string)null); + }); + + modelBuilder.Entity("Pf2eModel.Model.Structure.RitualRelation.RitualCheck", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id") + .HasColumnOrder(1); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("IsSecondary") + .HasColumnType("boolean") + .HasColumnName("is_secondary") + .HasColumnOrder(6); + + b.Property("Rank") + .HasColumnType("training_rank") + .HasColumnName("rank") + .HasColumnOrder(5); + + b.Property("RitualId") + .HasColumnType("integer") + .HasColumnName("ritual_id") + .HasColumnOrder(2); + + b.Property("TrainingId") + .HasColumnType("integer") + .HasColumnName("training_id") + .HasColumnOrder(3); + + b.Property("TrainingString") + .HasColumnType("jsonb") + .HasColumnName("training_string") + .HasColumnOrder(4); + + b.HasKey("Id") + .HasName("pk_ritual_checks"); + + b.HasIndex("RitualId") + .HasDatabaseName("ix_ritual_checks_ritual_id"); + + b.HasIndex("TrainingId") + .HasDatabaseName("ix_ritual_checks_training_id"); + + b.ToTable("ritual_checks", (string)null); + }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Spell", b => { b.Property("Id") @@ -1245,18 +1402,29 @@ namespace Pf2eModel.Migrations b.Property("Actions") .HasColumnType("action_enum") .HasColumnName("actions") - .HasColumnOrder(3); + .HasColumnOrder(4); + + b.Property("Cost") + .HasColumnType("jsonb") + .HasColumnName("cost") + .HasColumnOrder(11); b.Property("Duration") .HasMaxLength(255) .HasColumnType("integer") .HasColumnName("duration") - .HasColumnOrder(4); + .HasColumnOrder(5); + + b.PrimitiveCollection("Elements") + .IsRequired() + .HasColumnType("integer[]") + .HasColumnName("elements") + .HasColumnOrder(8); b.Property("IsFocus") .HasColumnType("boolean") .HasColumnName("is_focus") - .HasColumnOrder(5); + .HasColumnOrder(3); b.Property("Level") .HasColumnType("integer") @@ -1268,21 +1436,26 @@ namespace Pf2eModel.Migrations .HasColumnName("range") .HasColumnOrder(6); + b.Property("Requirement") + .HasColumnType("jsonb") + .HasColumnName("requirement") + .HasColumnOrder(12); + b.Property("Target") .HasColumnType("jsonb") .HasColumnName("target") - .HasColumnOrder(8); + .HasColumnOrder(10); b.PrimitiveCollection("Traditions") .IsRequired() .HasColumnType("spell_tradition[]") .HasColumnName("traditions") - .HasColumnOrder(6); + .HasColumnOrder(7); b.Property("Trigger") .HasColumnType("jsonb") .HasColumnName("trigger") - .HasColumnOrder(7); + .HasColumnOrder(9); b.HasKey("Id") .HasName("pk_spells"); @@ -1432,38 +1605,6 @@ namespace Pf2eModel.Migrations b.ToTable("spell_defenses", (string)null); }); - modelBuilder.Entity("Pf2eModel.Model.Structure.SpellRelation.SpellRitual", b => - { - b.Property("SpellId") - .HasColumnType("integer") - .HasColumnName("spell_id") - .HasColumnOrder(1); - - b.Property("PrimaryCheck") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("primary_check") - .HasColumnOrder(2); - - b.Property("SecondaryCasters") - .HasColumnType("integer") - .HasColumnName("secondary_casters") - .HasColumnOrder(3); - - b.Property("SecondaryChecks") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("secondary_checks") - .HasColumnOrder(4); - - b.HasKey("SpellId") - .HasName("pk_spell_rituals"); - - b.ToTable("spell_rituals", (string)null); - }); - modelBuilder.Entity("Pf2eModel.Model.Structure.Subclass", b => { b.Property("Id") @@ -2061,6 +2202,50 @@ namespace Pf2eModel.Migrations b.Navigation("Entity"); }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Ritual", b => + { + b.HasOne("Pf2eModel.Model.Base.Entity", "Entity") + .WithOne() + .HasForeignKey("Pf2eModel.Model.Structure.Ritual", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_rituals_entities_id"); + + b.Navigation("Entity"); + }); + + modelBuilder.Entity("Pf2eModel.Model.Structure.RitualRelation.RitualArea", b => + { + b.HasOne("Pf2eModel.Model.Structure.Ritual", "Ritual") + .WithOne("Area") + .HasForeignKey("Pf2eModel.Model.Structure.RitualRelation.RitualArea", "RitualId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_ritual_areas_rituals_ritual_id"); + + b.Navigation("Ritual"); + }); + + modelBuilder.Entity("Pf2eModel.Model.Structure.RitualRelation.RitualCheck", b => + { + b.HasOne("Pf2eModel.Model.Structure.Ritual", "Ritual") + .WithMany("Checks") + .HasForeignKey("RitualId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_ritual_checks_rituals_ritual_id"); + + b.HasOne("Pf2eModel.Model.Common.Training", "Training") + .WithMany() + .HasForeignKey("TrainingId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_ritual_checks_trainings_training_id"); + + b.Navigation("Ritual"); + + b.Navigation("Training"); + }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Spell", b => { b.HasOne("Pf2eModel.Model.Base.Entity", "Entity") @@ -2109,17 +2294,6 @@ namespace Pf2eModel.Migrations b.Navigation("Spell"); }); - modelBuilder.Entity("Pf2eModel.Model.Structure.SpellRelation.SpellRitual", b => - { - b.HasOne("Pf2eModel.Model.Structure.Spell", "Spell") - .WithOne("SpellRitual") - .HasForeignKey("Pf2eModel.Model.Structure.SpellRelation.SpellRitual", "SpellId") - .OnDelete(DeleteBehavior.Cascade) - .HasConstraintName("fk_spell_rituals_spells_spell_id"); - - b.Navigation("Spell"); - }); - modelBuilder.Entity("Pf2eModel.Model.Structure.Subclass", b => { b.HasOne("Pf2eModel.Model.Structure.SubclassGroup", "Group") @@ -2242,13 +2416,18 @@ namespace Pf2eModel.Migrations b.Navigation("FeatPrerequisites"); }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Ritual", b => + { + b.Navigation("Area"); + + b.Navigation("Checks"); + }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Spell", b => { b.Navigation("SpellAreas"); b.Navigation("SpellDefenses"); - - b.Navigation("SpellRitual"); }); modelBuilder.Entity("Pf2eModel.Model.Structure.Subclass", b => diff --git a/Pf2eModel/Model/Enum/ElementEnum.cs b/Pf2eModel/Model/Enum/ElementEnum.cs new file mode 100644 index 0000000..c512355 --- /dev/null +++ b/Pf2eModel/Model/Enum/ElementEnum.cs @@ -0,0 +1,27 @@ +using NpgsqlTypes; + +namespace Pf2eModel.Model.Enum; + +public enum ElementEnum +{ + [PgName("universal")] + Universal, + + [PgName("air")] + Air, + + [PgName("water")] + Water, + + [PgName("earth")] + Earth, + + [PgName("fire")] + Fire, + + [PgName("wood")] + Wood, + + [PgName("metal")] + Metal, +} diff --git a/Pf2eModel/Model/Enum/EntityType.cs b/Pf2eModel/Model/Enum/EntityType.cs index 7cfd3cf..c01d9b2 100644 --- a/Pf2eModel/Model/Enum/EntityType.cs +++ b/Pf2eModel/Model/Enum/EntityType.cs @@ -52,6 +52,9 @@ public enum EntityType [PgName("spell")] Spell, + [PgName("ritual")] + Ritual, + [PgName("language")] Language, } diff --git a/Pf2eModel/Model/Enum/TrainingRank.cs b/Pf2eModel/Model/Enum/TrainingRank.cs new file mode 100644 index 0000000..7fae960 --- /dev/null +++ b/Pf2eModel/Model/Enum/TrainingRank.cs @@ -0,0 +1,24 @@ +using NpgsqlTypes; + +namespace Pf2eModel.Model.Enum; + +public enum TrainingRank +{ + [PgName("untrained")] + Untrained, + + [PgName("trained")] + Trained, + + [PgName("expert")] + Expert, + + [PgName("master")] + Master, + + [PgName("legendary")] + Legendary, + + [PgName("mythic")] + Mythic, +} diff --git a/Pf2eModel/Model/Enum/TrainingStage.cs b/Pf2eModel/Model/Enum/TrainingStage.cs deleted file mode 100644 index 4af94bf..0000000 --- a/Pf2eModel/Model/Enum/TrainingStage.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Pf2eModel.Model.Enum; - -public enum TrainingStage -{ - Untrained = 0, - - Trained = 1, - - Expert = 2, - - Master = 3, - - Legendary = 4, -} diff --git a/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundTraining.cs b/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundTraining.cs index d4d6e24..80fccc8 100644 --- a/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundTraining.cs +++ b/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundTraining.cs @@ -20,7 +20,7 @@ public class BackgroundTraining public int TrainingId { get; set; } [Column(Order = 4)] - public TrainingStage Level { get; set; } + public TrainingRank Rank { get; set; } [JsonIgnore] public Background Background { get; set; } = null!; diff --git a/Pf2eModel/Model/Structure/ClassRelation/ClassTraining.cs b/Pf2eModel/Model/Structure/ClassRelation/ClassTraining.cs index d7e66ac..ae0d8bb 100644 --- a/Pf2eModel/Model/Structure/ClassRelation/ClassTraining.cs +++ b/Pf2eModel/Model/Structure/ClassRelation/ClassTraining.cs @@ -20,7 +20,7 @@ public class ClassTraining public int? TrainingId { get; set; } [Column(Order = 4)] - public TrainingStage Stage { get; set; } + public TrainingRank Rank { get; set; } [JsonIgnore] public Class Class { get; set; } = null!; diff --git a/Pf2eModel/Model/Structure/ClassRelation/SubclassTrainings.cs b/Pf2eModel/Model/Structure/ClassRelation/SubclassTrainings.cs index 75ac908..389b7e5 100644 --- a/Pf2eModel/Model/Structure/ClassRelation/SubclassTrainings.cs +++ b/Pf2eModel/Model/Structure/ClassRelation/SubclassTrainings.cs @@ -19,7 +19,7 @@ public class SubclassTrainings public int TrainingId { get; set; } [Column(Order = 4)] - public TrainingStage Stage { get; set; } = TrainingStage.Trained; + public TrainingRank Rank { get; set; } = TrainingRank.Trained; public Subclass Subclass { get; set; } = null!; diff --git a/Pf2eModel/Model/Structure/Ritual.cs b/Pf2eModel/Model/Structure/Ritual.cs new file mode 100644 index 0000000..0b72f97 --- /dev/null +++ b/Pf2eModel/Model/Structure/Ritual.cs @@ -0,0 +1,67 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; +using Pf2eModel.Model.Base; +using Pf2eModel.Model.Common.I18n; +using Pf2eModel.Model.Enum; +using Pf2eModel.Model.Structure.RitualRelation; + +namespace Pf2eModel.Model.Structure; + +[EntityOfType(EntityType.Ritual)] +public class Ritual : IEntity +{ + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + [Column(Order = 1)] + public int Id { get; set; } + public Entity Entity { get; set; } = null!; + + [Column(Order = 2)] + public int Level { get; set; } + + [Column(Order = 3)] + [Comment("Продолжительность ритуала в секундах")] + public int CastTime { get; set; } + + [Column(Order = 4)] + [Comment("Время действия эффекта ритуала в секундах")] + public int Duration { get; set; } + + [Column(Order = 5)] + public ElementEnum[] Elements { get; set; } = []; + + [Column(Order = 6)] + public int Range { get; set; } + + [Column(Order = 7)] + public TrainingRank PrimaryCheckRank { get; set; } = TrainingRank.Trained; + + [Column(Order = 8)] + public LocaleString? PrimaryCheckSuffix { get; set; } = null; + + [Column(Order = 9)] + public int SecondaryCasters { get; set; } = 0; + + [Column(Order = 10)] + public int SecondaryCastersMax { get; set; } = 0; + + [Column(Order = 11)] + public LocaleString? SecondaryCastersSuffix { get; set; } = null; + + [Column(Order = 12)] + public LocaleString? RangeString { get; set; } = null; + + [Column(Order = 13)] + public LocaleString? Target { get; set; } = null; + + [Column(Order = 14)] + public LocaleString? Cost { get; set; } = null; + + [Column(Order = 15)] + public LocaleString? Requirement { get; set; } = null; + + public virtual RitualArea? Area { get; set; } = null; + + public virtual ICollection Checks { get; set; } = []; +} diff --git a/Pf2eModel/Model/Structure/RitualRelation/RitualArea.cs b/Pf2eModel/Model/Structure/RitualRelation/RitualArea.cs new file mode 100644 index 0000000..cac4118 --- /dev/null +++ b/Pf2eModel/Model/Structure/RitualRelation/RitualArea.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Pf2eModel.Model.Common.I18n; +using Pf2eModel.Model.Enum; + +namespace Pf2eModel.Model.Structure.RitualRelation; + +public class RitualArea +{ + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + [Column(Order = 1)] + public int RitualId { get; set; } + + [Column(Order = 2)] + [MaxLength(255)] + public LocaleString? Details { get; set; } + + [Column(Order = 3)] + public SpellAreaType Type { get; set; } + + public virtual Ritual Ritual { get; set; } = null!; +} diff --git a/Pf2eModel/Model/Structure/RitualRelation/RitualCheck.cs b/Pf2eModel/Model/Structure/RitualRelation/RitualCheck.cs new file mode 100644 index 0000000..76e7de5 --- /dev/null +++ b/Pf2eModel/Model/Structure/RitualRelation/RitualCheck.cs @@ -0,0 +1,34 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Pf2eModel.Model.Common; +using Pf2eModel.Model.Common.I18n; +using Pf2eModel.Model.Enum; + +namespace Pf2eModel.Model.Structure.RitualRelation; + +public class RitualCheck +{ + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [Column(Order = 1)] + public int Id { get; set; } + + [Column(Order = 2)] + public int RitualId { get; set; } + + public Ritual Ritual { get; set; } = null!; + + [Column(Order = 3)] + public int? TrainingId { get; set; } + + public Training? Training { get; set; } = null!; + + [Column(Order = 4)] + public LocaleString? TrainingString { get; set; } = null; + + [Column(Order = 5)] + public TrainingRank Rank { get; set; } + + [Column(Order = 6)] + public bool IsSecondary { get; set; } +} diff --git a/Pf2eModel/Model/Structure/Spell.cs b/Pf2eModel/Model/Structure/Spell.cs index 598ed01..d92949e 100644 --- a/Pf2eModel/Model/Structure/Spell.cs +++ b/Pf2eModel/Model/Structure/Spell.cs @@ -21,27 +21,36 @@ public class Spell : IEntity public int Level { get; set; } [Column(Order = 3)] - public ActionEnum Actions { get; set; } = ActionEnum.Other; - - [Column(Order = 4)] - [MaxLength(255)] - public int? Duration { get; set; } = null; - - [Column(Order = 5)] public bool IsFocus { get; set; } - [Column(Order = 6)] - public SpellTradition[] Traditions { get; set; } = []; + [Column(Order = 4)] + public ActionEnum Actions { get; set; } = ActionEnum.Other; + + [Column(Order = 5)] + [MaxLength(255)] + public int? Duration { get; set; } = null; [Column(Order = 6)] public int Range { get; set; } [Column(Order = 7)] - public LocaleString? Trigger { get; set; } = null; + public SpellTradition[] Traditions { get; set; } = []; [Column(Order = 8)] + public ElementEnum[] Elements { get; set; } = []; + + [Column(Order = 9)] + public LocaleString? Trigger { get; set; } = null; + + [Column(Order = 10)] public LocaleString? Target { get; set; } = null; + [Column(Order = 11)] + public LocaleString? Cost { get; set; } = null; + + [Column(Order = 12)] + public LocaleString? Requirement { get; set; } = null; + /* [Column(Order = 4)] public bool Counteraction { get; set; } @@ -71,7 +80,5 @@ public class Spell : IEntity public virtual ICollection SpellAreas { get; set; } = []; - public virtual SpellRitual? SpellRitual { get; set; } - public virtual ICollection SpellDefenses { get; set; } = new List(); } diff --git a/Pf2eModel/Model/Structure/SpellRelation/SpellRitual.cs b/Pf2eModel/Model/Structure/SpellRelation/SpellRitual.cs deleted file mode 100644 index 133ff9c..0000000 --- a/Pf2eModel/Model/Structure/SpellRelation/SpellRitual.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace Pf2eModel.Model.Structure.SpellRelation; - -public class SpellRitual -{ - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.None)] - [Column(Order = 1)] - public int SpellId { get; set; } - - [Column(Order = 2)] - [MaxLength(255)] - public string PrimaryCheck { get; set; } = null!; - - [Column(Order = 3)] - public int SecondaryCasters { get; set; } - - [Column(Order = 4)] - [MaxLength(255)] - public string SecondaryChecks { get; set; } = null!; - - public virtual Spell Spell { get; set; } = null!; -} diff --git a/Pf2eModel/Pf2eDbContext.cs b/Pf2eModel/Pf2eDbContext.cs index 820f45b..065cc8c 100644 --- a/Pf2eModel/Pf2eDbContext.cs +++ b/Pf2eModel/Pf2eDbContext.cs @@ -14,6 +14,7 @@ using Pf2eModel.Model.Structure.BackgroundRelation; using Pf2eModel.Model.Structure.ClassRelation; using Pf2eModel.Model.Structure.DeityRelation; using Pf2eModel.Model.Structure.FeatRelation; +using Pf2eModel.Model.Structure.RitualRelation; using Pf2eModel.Model.Structure.SpellRelation; namespace Pf2eModel; @@ -93,6 +94,12 @@ public partial class Pf2eDbContext : DbContext public virtual DbSet Languages { get; set; } + public virtual DbSet Rituals { get; set; } + + public virtual DbSet RitualAreas { get; set; } + + public virtual DbSet RitualChecks { get; set; } + public virtual DbSet Sources { get; set; } public virtual DbSet Spells { get; set; } @@ -103,8 +110,6 @@ public partial class Pf2eDbContext : DbContext public virtual DbSet SpellDefenses { get; set; } - public virtual DbSet SpellRituals { get; set; } - public virtual DbSet Trainings { get; set; } public virtual DbSet Traits { get; set; } @@ -114,12 +119,12 @@ public partial class Pf2eDbContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { DotEnv.Load(options: new DotEnvOptions(probeForEnv: true, probeLevelsToSearch: 2)); - string databaseCnnection = EnvReader.GetStringValue("DATABASE_CONNECTION"); + string databaseConnection = EnvReader.GetStringValue("DATABASE_CONNECTION"); // optionsBuilder.LogTo(Console.WriteLine); optionsBuilder.UseSnakeCaseNamingConvention(); optionsBuilder.UseNpgsql( - databaseCnnection, + databaseConnection, builder => { builder @@ -143,7 +148,7 @@ public partial class Pf2eDbContext : DbContext .MapEnum() .MapEnum() .MapEnum() - .MapEnum() + .MapEnum() .MapEnum(); } ); diff --git a/Pf2eModel/Pf2eDbContextModel.cs b/Pf2eModel/Pf2eDbContextModel.cs index 2ff16f5..7ebf1dc 100644 --- a/Pf2eModel/Pf2eDbContextModel.cs +++ b/Pf2eModel/Pf2eDbContextModel.cs @@ -18,6 +18,7 @@ using Pf2eModel.Model.Structure.BackgroundRelation; using Pf2eModel.Model.Structure.ClassRelation; using Pf2eModel.Model.Structure.DeityRelation; using Pf2eModel.Model.Structure.FeatRelation; +using Pf2eModel.Model.Structure.RitualRelation; using Pf2eModel.Model.Structure.SpellRelation; namespace Pf2eModel; @@ -81,7 +82,7 @@ public partial class Pf2eDbContext .HasPostgresEnum() .HasPostgresEnum() .HasPostgresEnum() - .HasPostgresEnum() + .HasPostgresEnum() .HasPostgresEnum(); } @@ -436,6 +437,8 @@ public partial class Pf2eDbContext BindLocaleString(entity, s => s.Trigger, false); BindLocaleString(entity, s => s.Target, false); + BindLocaleString(entity, s => s.Cost, false); + BindLocaleString(entity, s => s.Requirement, false); entity .HasMany(e => e.SpellAreas) @@ -443,13 +446,6 @@ public partial class Pf2eDbContext .HasForeignKey(e => e.SpellId) .OnDelete(DeleteBehavior.Cascade); - entity - .HasOne(e => e.SpellRitual) - .WithOne(e => e.Spell) - .HasForeignKey(e => e.SpellId) - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(false); - entity .HasMany(e => e.SpellDefenses) .WithOne(e => e.Spell) @@ -461,7 +457,46 @@ public partial class Pf2eDbContext BindLocaleString(entity, a => a.Details, false); }); modelBuilder.Entity(entity => { }); - modelBuilder.Entity(entity => { }); + + // Ritual + modelBuilder.Entity(entity => + { + BindEntity(entity); + + BindLocaleString(entity, s => s.RangeString, false); + BindLocaleString(entity, s => s.Target, false); + BindLocaleString(entity, s => s.Cost, false); + BindLocaleString(entity, s => s.Requirement, false); + BindLocaleString(entity, s => s.PrimaryCheckSuffix, false); + BindLocaleString(entity, s => s.SecondaryCastersSuffix, false); + + entity + .HasOne(r => r.Area) + .WithOne(a => a.Ritual) + .HasForeignKey(a => a.RitualId) + .OnDelete(DeleteBehavior.Cascade); + + entity + .HasMany(r => r.Checks) + .WithOne(c => c.Ritual) + .HasForeignKey(c => c.RitualId) + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity(entity => + { + BindLocaleString(entity, a => a.Details, false); + }); + + modelBuilder.Entity(entity => + { + BindLocaleString(entity, a => a.TrainingString, false); + + entity + .HasOne(c => c.Training) + .WithMany() + .HasForeignKey(c => c.TrainingId) + .OnDelete(DeleteBehavior.SetNull); + }); // Trait modelBuilder.Entity(entity => diff --git a/Pf2eViewer/EntityView.cs b/Pf2eViewer/EntityView.cs index 20f619b..3455a70 100644 --- a/Pf2eViewer/EntityView.cs +++ b/Pf2eViewer/EntityView.cs @@ -79,6 +79,10 @@ public class EntityView EntityType.Spell, context => context.Spells.Include(s => s.SpellAreas).Include(s => s.SpellDefenses) ), + new Getter( + EntityType.Ritual, + context => context.Rituals.Include(r => r.Area).Include(r => r.Checks) + ), ]; private abstract class Getter(EntityType type)