public static void ParseLevels(string html, Spell spell, ILog log) { List<SpellListLevel> levels = new List<SpellListLevel>(); ParseClassLevel(html, levels, SpellList.Ids.Bard, string.Format(ClassPattern, "barde", "Bard")); if (!ParseClassLevel(html, levels, SpellList.Ids.SorcererWizard, EnsWizPattern1)) { // Version alternative if (!ParseClassLevel(html, levels, SpellList.Ids.SorcererWizard, string.Format(ClassPattern, "magicien", "Mag"))) { ParseClassLevel(html, levels, SpellList.Ids.SorcererWizard, EnsWizPattern2); } } ParseClassLevel(html, levels, SpellList.Ids.Ranger, string.Format(ClassPattern, "rôdeur", "Rôd")); ParseClassLevel(html, levels, SpellList.Ids.Paladin, string.Format(ClassPattern, "paladin", "Pal")); ParseClassLevel(html, levels, SpellList.Ids.Druid, string.Format(ClassPattern, "druide", "Dru")); ParseClassLevel(html, levels, SpellList.Ids.Cleric, string.Format(ClassPattern, "prêtre", "Prê")); ParseClassLevel(html, levels, SpellList.Ids.Inquisitor, string.Format(ClassPattern, "inquisiteur", "Inq")); ParseClassLevel(html, levels, SpellList.Ids.Summoner, string.Format(ClassPattern, "invocateur|conjurateur", "Inv")); ParseClassLevel(html, levels, SpellList.Ids.Witch, string.Format(ClassPattern, "sorcière", "Sor")); ParseClassLevel(html, levels, SpellList.Ids.Alchemist, string.Format(ClassPattern, "alchimiste", "Alch")); ParseClassLevel(html, levels, SpellList.Ids.Oracle, string.Format(ClassPattern, "oracle", "Ora")); ParseClassLevel(html, levels, SpellList.Ids.Oracle, string.Format(ClassPattern, "prêtre", "Prê")); ParseClassLevel(html, levels, SpellList.Ids.Magus, string.Format(ClassPattern, "magus", "magus")); ParseClassLevel(html, levels, SpellList.Ids.AntiPaladin, string.Format(ClassPattern, "antipaladin", "antipaladin")); if (levels.Count == 0) { throw new ParseException("Impossible de détecter les niveaux de classe"); } spell.Levels = levels.ToArray(); }
public static void ParseCastingTime(string html, Spell spell, ILog log) { var match = Regex.Match(html, Pattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); if (!match.Success) { throw new ParseException("Impossible de détecter le temps d'incantation"); } var castingTime = spell.CastingTime = new SpellCastingTime(); var value = match.Groups["Value"].Value.Trim(); match = Regex.Match(value, ValuePattern, RegexOptions.CultureInvariant); if (match.Success) { castingTime.Value = int.Parse(match.Groups["Quantity"].Value); var unit = match.Groups["Unit"].Value.ToLowerInvariant(); if (unit.IndexOf("voir description") != -1) castingTime.Unit = TimeUnit.Special; else castingTime.Unit = ParseTimeUnit(unit); } if (!match.Success || castingTime.Unit == TimeUnit.Special) { castingTime.Value = 0; castingTime.Unit = TimeUnit.Special; castingTime.Text = MarkupUtil.RemoveMarkup(value); } }
public static void ParseTarget(string html, Spell spell, ILog log) { var match = Regex.Match(html, Pattern, RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); if (!match.Success) { if (!noTargetSpells.Contains(spell.Id)) { log.Warning($"{spell.Name} : cible introuvable. Si le sort n'a pas de cible, il doit être ajouté dans le fichier contenant les sorts sans cible"); } return; } var type = match.Groups["Type"].Value; int count; typeCount.TryGetValue(type, out count); count++; typeCount[type] = count; var value = MarkupUtil.RemoveMarkup(match.Groups["Value"].Value.Trim()); spell.Target = new SpellTarget { Value = value }; }
public static bool TryParse(WikiPage page, out Spell spell, ILog log = null) { spell = null; try { spell = Parse(page, log); return true; } catch (ParseException e) { log.Error("{0}: {1}", page.Title, e.Message); return false; } }
public static void ParseDescriptor(string html, Spell spell, ILog log) { var match = Regex.Match(html, DescriptorPattern, RegexOptions.CultureInvariant); if (!match.Success) { match = Regex.Match(html, DescriptorPattern2, RegexOptions.CultureInvariant); } if (match.Success) { foreach (var descriptor in match.Groups["Title"].Value.Split(',').Select(d => d.Trim().ToLowerInvariant())) { spell.Descriptor |= ParseDescriptorValue(descriptor); } } }
public static void ParseSchool(string html, Spell spell, ILog log) { var schoolMatch = Regex.Match(html, SchoolPattern, RegexOptions.CultureInvariant); if (schoolMatch.Success) { spell.School = ParseSpellSchoolTitle(schoolMatch.Groups["Title"].Value); } else if (html.IndexOf(UniversalSchoolPattern, StringComparison.OrdinalIgnoreCase) != -1) { spell.School = SpellSchool.Universal; } else { throw new ParseException("Impossible de lire l'école de magie"); } // TODO lire les branches }
private static Spell Parse(WikiPage page, ILog log = null) { var spell = new Spell(); spell.Name = page.Title; spell.Id = page.Id; // Ajout source wiki spell.Source.References.Add(References.FromFrWiki(page.Url)); // Ajout source drp spell.Source.References.Add(References.FromFrDrp(page.Id)); var wiki = page.Raw; if (wiki.IndexOf("'''École'''", StringComparison.Ordinal) == -1 && wiki.IndexOf("'''Ecole'''", StringComparison.Ordinal) == -1) { throw new ParseException("École de magie introuvable"); } SpellParser parser = new SpellParser(spell, wiki); parser.Execute(log); return spell; }
public SpellParser(Spell spell, string html) { this.spell = spell; this.html = html; }
public static void ParseSavingThrow(string html, Spell spell, ILog log) { if (spell.Name == "Transmutation de potion en poison") { // Cas particulier : ce sort décrit plusieurs sorts return; } var match = Regex.Match(html, Pattern, RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); if (!match.Success) { return; throw new ParseException("Jet de sauvegarde introuvable"); } var value = MarkupUtil.RemoveMarkup(match.Groups["Value"].Value.Trim()); var compareValue = value.ToLowerInvariant(); var savingThrow = new SpellSavingThrow(); var copyValue = false; if (compareValue.IndexOf(" ou ", StringComparison.Ordinal) != -1 || compareValue.IndexOf(" et ", StringComparison.Ordinal) != -1 || compareValue.IndexOf(" puis ", StringComparison.Ordinal) != -1) { copyValue = true; savingThrow.Target = SpellSavingThrowTarget.Special; savingThrow.Effect = SpellSavingThrowEffect.Special; } else if ((match = Regex.Match(compareValue, EffectPattern, RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture)).Success) { switch (match.Groups["Type"].Value) { case "volonté": savingThrow.Target = SpellSavingThrowTarget.Will; break; case "réflexes": savingThrow.Target = SpellSavingThrowTarget.Reflex; break; case "vigueur": savingThrow.Target = SpellSavingThrowTarget.Fortitude; break; case "oui": savingThrow.Target = SpellSavingThrowTarget.Special; copyValue = true; break; case "non": savingThrow.Target = SpellSavingThrowTarget.None; copyValue = true; break; } var effect = match.Groups["Value"].Value.Trim(); if (effect.EndsWith(", voir texte")) { copyValue = true; effect = effect.Substring(0, effect.Length - ", voir texte".Length); } else if (effect.EndsWith(", voir description")) { copyValue = true; effect = effect.Substring(0, effect.Length - ", voir description".Length); } else if (effect.EndsWith(", voir plus bas")) { copyValue = true; effect = effect.Substring(0, effect.Length - ", voir plus bas".Length); } match = Regex.Match(effect, BonusPattern, RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); if (match.Success) { effect = match.Groups["Effect"].Value.Trim(); foreach (Capture bonusCapture in match.Groups["Parenthesis"].Captures) { var bonus = bonusCapture.Value.Trim().ToLowerInvariant(); switch (bonus) { case "inoffensif": savingThrow.Harmless = true; break; case "objet": savingThrow.Objects = true; break; case "inoffensif, objet": case "objet, inoffensif": savingThrow.Harmless = true; savingThrow.Objects = true; break; case "spécial, voir texte": case "voir texte": case "voir plus bas": case "voir description": case "en cas d’interaction": case "en cas d'interaction": case "spécial, voir plus bas": copyValue = true; break; case "": break; default: throw new ParseException(string.Format("Détail du jet de sauvegarde non reconnu : \"{0}\" dans le texte \"{1}\"", bonus, value)); } } } switch (effect) { case "annuler": case "annule": savingThrow.Effect = SpellSavingThrowEffect.Negates; break; case "1/2 dégâts": case "réduit de moitié": case "réduire de moitié": savingThrow.Effect = SpellSavingThrowEffect.Half; break; case "partiel": case "partielle": savingThrow.Effect = SpellSavingThrowEffect.Partial; break; case "dévoile": case "dévoiler": case "dévoiler l'illusion": savingThrow.Effect = SpellSavingThrowEffect.Disbelief; break; case "": break; default: if (copyValue) { // On a déjà détecté un sort spécial, on arrête là } else { throw new ParseException(string.Format("Impossible de décoder l'effet du jet de sauvegarde \"{0}\"", effect)); } break; } } else if (compareValue.EqualsOrdinal("aucun") || compareValue.EqualsOrdinal("non")) { savingThrow = null; } else if (compareValue.StartsWithOrdinal("aucun")) { savingThrow.SpecificValue = value; } else if (compareValue.EqualsOrdinal("voir description") || compareValue.EqualsOrdinal("voir texte")) { savingThrow.Effect = SpellSavingThrowEffect.Special; savingThrow.SpecificValue = value; } else if (compareValue.EqualsOrdinal("spécial, voir plus bas")) { savingThrow.Effect = SpellSavingThrowEffect.Special; savingThrow.SpecificValue = value; } else if (compareValue.EqualsOrdinal("spécial, voir texte")) { savingThrow.Effect = SpellSavingThrowEffect.Special; savingThrow.SpecificValue = value; } else { throw new ParseException(string.Format("Impossible de décoder le type de jet de sauvegarde dans \"{0}\"", value)); } if (copyValue) { savingThrow.SpecificValue = value; } spell.SavingThrow = savingThrow; }
public SpellWrapper(Spell spell) { this.spell = spell; }
public static void ParseRange(string html, Spell spell, ILog log) { var match = Regex.Match(html, RangePattern, RegexOptions.CultureInvariant); if (!match.Success) { if (!noRangeSpells.Contains(spell.Id)) { throw new ParseException($"Portée introuvable pour l'id {spell.Id}"); } // portée ignorée return; } var rangeValue = match.Groups["Value"].Value.Trim(); switch (rangeValue.ToLowerInvariant()) { case "[[personnelle]]": case "personnelle": case "[[présentation des sorts#portee|personnelle]]": spell.Range = new SpellRange {Unit = SpellRangeUnit.Personal}; break; case "[[contact]]": case "contact": case "[[présentation des sorts#portee|contact]]": case "[[présentation des sorts#contact|contact]]": spell.Range = new SpellRange {Unit = SpellRangeUnit.Touch}; break; case "[[illimitée]]": case "illimitée": spell.Range = new SpellRange {Unit = SpellRangeUnit.Unlimited}; break; case "courte (7,50 m + 1,50 m/2 [[niveau|niveaux]])": case "courte (7,50 m + 1,50 m/2 [[niveau|niveaux]]) (5 cases + 1 case/2 [[niveau|niveaux]])": // Format sans snippet case "courte (7,50 m + 1,50 m/2 [[niveau|niveaux]]) (5 {s:c} + 1 {s:c}/2 [[niveau|niveaux]])": // Format APG case "courte (7,50 m + 1,50 m/2 [[niveau|niveaux]])/(5 {s:c} + 1 {s:c}/2 [[niveau|niveaux]])": // Format UM case "courte (7,50 m + 1,50 m/2 [[niveau|niveaux]]) / (5 {s:c} + 1 {s:c}/2 [[niveau|niveaux]])": // Format UM 2 case "courte (7,50 m + 1,50 m/2 [niveau|niveaux]])/(5 {s:c} + 1 {s:c}/2 [[niveau|niveaux]])": // Format UM (buggé!) case "courte (7,5 m + 1,5 m/2 [[niveau|niveaux]]) (5 {s:c} + 1 {s:c}/2 [[niveau|niveaux]])": // Format court (pas de décimale non significative) case "courte (7,50 m + 1,50 m/2 niveaux) (5 cases + 1 case/2 niveaux)": case "ccourte (7,50 m + 1,50 m/2 [[niveau|niveaux]]) (5 {s:c} + 1 {s:c}/2 [[niveau|niveaux]])": // Transmutation du sang en acide (BUG) //case "courte (7,50 m + 1,50 m/2 ([niveau|niveaux]])": // Détection faussée //case "courte (7,50 mètres + 1,50 mètre/2 [[niveau|niveaux]])": // Convocation de monstres I //case "proche (7,50 m + 1,50 m/2 [[niveau|niveaux]])": // Délivrance de la paralysie //case "courte (7,50 m/5 cases + 1,50 m/1 case par 2 [[niveau|niveaux]])": // Illumination //case "courte (7,50 m + 1,50 m/2 [[niveau|niveaux]])/(5 cases + 1 case/2 [[niveau|niveaux]])": // Lenteur //case "courte (7,50 m + 1,50 m/2 niveaux) / (5 cases + 1 case/2 [[niveau|niveaux]])": // Lien télépathique //case "courte (7,50 m + 1,50 m/2 [[niveau|niveaux]]) / (5 cases + 1 case/2 [[niveau|niveaux]])": // Manipulation à distance //case "courte (7,50 m + 1,50 m/2 [[niveau|niveaux]]) / (5 cases + 1 cases/2 [[niveau|niveaux]])": // Mauvais oeil //case "courte (7,50 + 1,50 m/2 [[niveau|niveaux]])": // Profanation //case "courte (7,50 m + 1,50 m/2 [[niveau|niveaux]]) (5 {s:c} + 1 ({s:c}))": // Vermine géante //case "courte (7,50 m + 1,50 m/2 [[niveau|niveaux]] - 5 cases + 1 case/2 [[niveau|niveaux]])": // Zone de vérité //case "courte (7,50 m + 1,50 m/2 niveaux) (5 {s:c} + 1 {s:c}/2 niveaux)": // Appel cacophonique //case "courte (7,50 m + 1,50 m/2 [[niveau|niveaux]) (5 {s:c} + 1 {s:c}/2 [[niveau|niveaux])": // Bouclier involontaire //case "courte (7,5 m + 1,5 m/2 [[niveau|niveaux]]) (5 {s:c} + 1 {s:c}/2 [[niveau|niveaux]])": // Dangereux final //case "courte (7,50 m + 1,50 m/2 niveaux)": // Négation de l'arôme //case "courte (7,50 m + 1,50 m/2 niveaux) (5 cases + 1 case/2 niveaux)": // Vérole spell.Range = new SpellRange {Unit = SpellRangeUnit.Close}; break; // Format standard case "moyenne (30 m + 3 m/[[niveau]])": case "moyenne (30 m + 3 m/[[niveau]]) (20 {s:c} + 2 {s:c}/[[niveau]])": case "moyenne (30 m + 3 m/[[niveau|niveaux]])/(20 {s:c} + 2 {s:c}/[[niveau|niveaux]])": case "moyenne (30 m + 3 m/[[niveau]]) / (20 {s:c} + 2 {s:c}/[[niveau]])": //case "moyenne (20 cases + 2 cases/[[niveau]]) (30 m + 3 m/[[niveau]])": // Extinction des feux //case "moyenne (30 m/20 cases + 3 m/2 cases par [[niveau]])": // Immobilisation de morts-vivants //case "moyenne (30 m + 3 m/[[niveau]]) / (20 cases + 2 cases/[[niveau]])": // Lueur d'arc-en-ciel //case "moyenne (30 m + 3 m/[[niveau]])/(20 cases + 2 cases/[[niveau]])": // Main spectrale //case "moyenne (30 m + 3 m/[[niveau]]) / (20 cases + 2 case/[[niveau]])": // Mur de feu //case "moyenne (30 m + 3 m/niveau) / (20 cases + 2 cases/[[niveau]])": // Mur de glace //case "moyenne (30 m + 3 m/niveau)": // Pétrification // Format APG case "intermédiaire (30 m + 3 m/[[niveau]]) (20 {s:c} + 2 {s:c}/[[niveau]])": //case "intermédiaire (30 m + 3 m/niveau)": // Appel des pierres spell.Range = new SpellRange {Unit = SpellRangeUnit.Medium}; break; case "longue (120 m + 12 m/[[niveau]])": // Format standard case "longue (120 m + 12 m/[[niveau]]) (80 {s:c} + 8 {s:c}/[[niveau]])": // Format APG case "longue (120 m + 12 m/[[niveau]]) / (80 {s:c} + 8 {s:c}/[[niveau]])": // Format UM //case "longue (120 m/80 cases + 12 m/8 cases par [[niveau]])": // Image silencieuse //case "longue (120 m + 12 m/[[niveau]])/(80 cases + 8 cases/[[niveau]])": // Localisation d'objets //case "longue (120 m + 12 m/[[niveau]]) / (80 cases + 8 cases/[[niveau]])": // Lueur féerique //case "longue (120 m + 12 m/niveau)": // Sphère glaciale //case "longue (120 m + 12 m/niveau) (80 cases + 8 cases/niveau)": // Tsunami //case "longue (120 m + 12 m/niveau) (80 cases) + 8 cases par niveau)": // Vortex spell.Range = new SpellRange {Unit = SpellRangeUnit.Long}; break; case "0 m": case "0 m (0 {s:c})": spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "0"}; break; case "1,50 m": // Charmant cadeau case "1,50 m (1 {s:c})": // Manteau de rêves spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "1"}; break; case "3 m": //case "3 m - 2 cases": // Zone d'antimagie case "3 m (2 {s:c})": // Interdiction du fou spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "2"}; break; case "4,50 m": case "4,50 m (3 {s:c})": //case "4,50 m/3 cases": // Mains brûlantes spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "3"}; break; case "6 m": //case "6 m (4 cases)": // Manteau du chaos case "6 m (4 {s:c})": // Final revigorant spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "4"}; break; case "9 m": case "9 m (6 {s:c})": // Cri strident spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "6"}; break; case "12 m": case "12 m (8 {s:c})": // Recherche de pensées spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "8"}; break; case "15 m/10 cases": case "15 m/10 {s:c}": // Imprécation case "15 m (10 {s:c})": // Bénédiction spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "10"}; break; case "18 mètres": case "18 m": case "18 m/12 cases": case "18 m (12 {s:c})": case "18 mètres (12 {s:c})": // Extase case "18 m/12 {s:c}": // Identification spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "12"}; break; case "30 m (20 {s:c})": // Joueur de flûte spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "20"}; break; case "36 m": // Sillage de lumière case "36 m (24 {s:c})": // Éclair spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "24"}; break; case "jusqu’à 3 m (2 {s:c})/[[niveau]]": // Champ de force spell.Range = new SpellRange {SpecificValue = "jusqu'à 2 cases/niveau"}; break; case "12 m (8 {s:c})/[[niveau]]": // Contrôle des vents spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "8/level"}; break; case "15 m (10 {s:c})/[[niveau]]": // Entrer dans une image spell.Range = new SpellRange {Unit = SpellRangeUnit.Squares, SpecificValue = "10/level"}; break; case "1,5 km/[[niveau]]": // Vent des murmures spell.Range = new SpellRange {SpecificValue = "1,5 km/niveau"}; break; case "3 ou 9 m (2 ou 6 {s:c})": // Détonation discordante spell.Range = new SpellRange {SpecificValue = "3 ou 9 m (2 ou 6 cases)"}; break; case "9 ou 18 m (6 ou 12 {s:c})": // Souffle de dragon spell.Range = new SpellRange {SpecificValue = "9 ou 18 m (6 ou 12 cases)"}; break; case "voir description": // Coffre secret case "courte (7,50 m + 1,50 m/2 [[niveau|niveaux]]) (5 {s:c} + 1 {s:c}/2 [[niveau|niveaux]]) (voir description)": case "[[présentation des sorts#portee|contact]] (voir description)": // Passage dans l'éther case "0 m (voir description)": // Symbole de mort case "3 m (voir description)": // Communication avec les apparitions case "spéciale (voir description)": // Enchevetrement flamboyant & Flammes de la vengeance //case "contact ; voir texte": // Lien sacré //case "voir texte": // Vague mondiale case "[[présentation des sorts#portee|contact]] et [[présentation des sorts#portee|illimitée]] (voir description)": // Vengeance fantasmagorique case "[[personnelle]] ou 1,50 m (1 {s:c}) (voir description)": // Voile d'énergie positive & Voile du paradis case "3 km": // Contrôle du climat case "7,5 km": // Main du berger case "1,5 km": // Oeil indiscret case "n’importe où dans la zone défendue": // Défense magique case "[[présentation des sorts#portee|personnelle]] ou [[présentation des sorts#portee|contact]]": // Invisibilité, Prémonition et Sphère d'invisibilité case "[[personnelle]] ou [[contact]]": case "[[personnelle]] ou courte (7,50 m + 1,50 m/2 [[niveau|niveaux]]) (5 {s:c} + 1 {s:c}/2 [[niveau|niveaux]])": // Lévitation case "[[personnelle]] et [[contact]]": // Téléportation et Téléportation interplanétaire case "[[personnelle]] et [[présentation des sorts#portee|contact]]": case "[[personnelle]] ou [[présentation des sorts#portee|contact]]": // Liberté de mouvement, orientation case "9 ou 18 m": // Souffle de dragon case "[[contact]] (voir description)": // * case "[[présentation des sorts#portee|contact]] ou 1,50 m (1 {s:c}) (voir description)": // Manteau de colère case "[[contact]] ou 1,50 m (1 {s:c}) (voir description)": // Manteau de colère case "[[personnelle]] et courte (7,50 m + 1,50 m/2 [[niveau|niveaux]]) (5 {s:c} + 1 {s:c}/2 [[niveau|niveaux]])": // Lien des esprits combatifs case "[[émanation]] de 9 m (6 {s:c}) de rayon centrée sur le lanceur de sorts": // Note pétrifiante spell.Range = new SpellRange { SpecificValue = rangeValue .Replace("[[niveau|niveaux]]", "niveaux") .Replace("[[", string.Empty) .Replace("]]", string.Empty) .Replace("{s:c}", "case(s)") }; break; default: log.Warning("{0}: Portée non reconnue \"{1}\"", spell.Name, rangeValue); spell.Range = new SpellRange { SpecificValue = MarkupUtil.RemoveMarkup(rangeValue) }; break; } if (spell.Range != null) { return; } const string meterRange = "^(\\d+) m$"; match = Regex.Match(rangeValue, meterRange, RegexOptions.CultureInvariant); if (match.Success) { } }
private string AsSourceLabel(Spell spell) { switch (spell.Source.Id) { case Source.Ids.PathfinderRpg: return "PHB"; case Source.Ids.AdvancedPlayerGuide: return "APG"; case Source.Ids.UltimateMagic: return "UM"; case Source.Ids.UltimateCombat: return "UC"; default: return string.Empty; } }
private static string GetSpellListLevel(Spell spell, string spellListId) { var level = spell.Levels.FirstOrDefault(l => l.List == spellListId); return level != null ? level.Level.ToString() : string.Empty; }
private static string GetLocalizedEntry(Spell spell, string language, string href, string defaultValue = null) { if (spell.Localization == null) return defaultValue; return spell.Localization.GetLocalizedEntry(language, href, defaultValue); }
public static void ParseComponents(string html, Spell spell, ILog log) { var match = Regex.Match(html, Pattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); if (!match.Success) { if (!noComponentSpells.Contains(spell.Id)) { throw new ParseException($"Composantes introuvables pour l'id {spell.Id}"); } // composantes ignorée return; } spell.Components = new SpellComponents(); var components = match.Groups["Value"].Value.Split(',').Select(s => s.Trim().ToLowerInvariant()); foreach (var c in components) { switch (c) { case "m": spell.Components.Kinds |= SpellComponentKinds.Material; break; case "v": spell.Components.Kinds |= SpellComponentKinds.Verbal; break; case "g": case "s": // Désactiver pour trouver tous les sorts de l'APG avec le bug spell.Components.Kinds |= SpellComponentKinds.Somatic; break; case "fd": spell.Components.Kinds |= SpellComponentKinds.DivineFocus; break; case "f": spell.Components.Kinds |= SpellComponentKinds.Focus; break; case "m/fd": case "fd/m": spell.Components.Kinds |= SpellComponentKinds.MaterialOrDivineFocus; break; case "f/fd": case "fd/f": spell.Components.Kinds |= SpellComponentKinds.FocusOrDivineFocus; break; default: throw new ParseException("Formule de composantes inconnue"); } } var comment = match.Groups["Comment"].Value.Trim(); if (comment.Length > 1) { if (comment[0] == '(' && comment[comment.Length - 1] == ')') { comment = comment.Substring(1, comment.Length - 2); } } spell.Components.Description = MarkupUtil.RemoveMarkup(comment); }
public static void ParseMagicResistance(string html, Spell spell, ILog log) { const string pattern = "'''Résistance à la magie''' "; var i = html.IndexOf(pattern, StringComparison.Ordinal); var spellResist = spell.SpellResistance = new SpellResistance(); if (i == -1) { //throw new ParseException("Résistance à la magie introuvable"); spellResist.Resist = SpecialBoolean.No; return; } var eol = html.IndexOf('\n', i); if (eol == -1) { throw new ParseException("Résistance à la magie mal formée"); } i += pattern.Length; // La valeur de résistance à la magie est la fin de la phrase var value = html.Substring(i, eol - i); // On conserve la valeur originale (si la détection échoue, c'est elle que l'on indiquera) var originalValue = value; // On supprime les éventuels liens indiqués en fin de RM value = Regex.Replace(value.ToLowerInvariant(), RemoveMarkupPattern, "$2").Trim(); switch (value) { case No: // Il ne reste plus que le texte "non" comme valeur, on le renvoie spellResist.Resist = SpecialBoolean.No; return; case Yes: // Il ne reste plus que le texte "oui" comme valeur, on le renvoie spellResist.Resist = SpecialBoolean.Yes; return; } // On va tenter de déchiffrer la valeur spécifique de RM indiquée var match = Regex.Match(value, RMPattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); if (!match.Success) { // On a pas pu détecter le type de RM, on renvoie spécial spellResist.Resist = SpecialBoolean.Special; spellResist.Text = MarkupUtil.RemoveMarkup(originalValue).Trim(); return; } switch (match.Groups["val"].Value.ToLowerInvariant()) { case Yes: spellResist.Resist = SpecialBoolean.Yes; break; case No: spellResist.Resist = SpecialBoolean.No; break; } foreach (var capture in match.Groups["word"].Captures.Cast<Capture>()) { switch (capture.Value.ToLowerInvariant()) { case "voir description": case "voir texte": case "spécial": spellResist.Text = value; break; case "inoffensif": spellResist.Harmless = true; break; case "objet": case "[[présentation des sorts#jetsdesauvegarde|objet]]": spellResist.Objects = true; break; default: // ?? throw new ParseException(string.Format("Détail de RM non reconnu : {0}", capture.Value)); } } }