diff --git a/Assets/cover.png b/Assets/cover.png new file mode 100644 index 0000000..a3b6ad6 Binary files /dev/null and b/Assets/cover.png differ diff --git a/Assets/favicon.png b/Assets/favicon.png new file mode 100644 index 0000000..53d05ab Binary files /dev/null and b/Assets/favicon.png differ diff --git a/Assets/icon.aseprite b/Assets/icon.aseprite new file mode 100644 index 0000000..5a77f7b Binary files /dev/null and b/Assets/icon.aseprite differ diff --git a/Assets/icon.png b/Assets/icon.png new file mode 100644 index 0000000..ca411f9 Binary files /dev/null and b/Assets/icon.png differ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..3691246 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,29 @@ +# Changelog + +## v1.3 — 2024-06-16 +Tested to work on game version 207.71 + +* Reorganizes options + +Meta: + +* Add `CHANGELOG.md` +* Update icon +* Update cover photo +* Update `LICENSE` + +## v1.2 — 2022-07-24 +Tested to work on game version 203.54 + +* Expands customization options (range of coloring highlight) + +## v1.1 — 2022-07-24 +Tested to work on game version 203.54 + +* Adds customization options regarding hint display + * coloring (on or off) + * capitalization (key words, whole clue, and none) + +## v1.0 — 2022-05-25 + +* Initial release diff --git a/LICENSE b/LICENSE index 0e259d4..f852d42 100644 --- a/LICENSE +++ b/LICENSE @@ -1,121 +1,5 @@ -Creative Commons Legal Code +Copyright (C) 2022–2023 by librarianmage -CC0 1.0 Universal +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Options.xml b/Options.xml index 6c02471..1976c25 100644 --- a/Options.xml +++ b/Options.xml @@ -1,6 +1,46 @@ - + + + + + + + + diff --git a/README.md b/README.md index f068d1e..7f34aa8 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,20 @@ # Finder of Ruin A mod that aids in the finding of the Ruin of House Isner by making the clues a bit more obvious. -The mod offers two aids: coloring or capitalizing the hint text (key words or the entire clue). +The mod offers two aids: coloring or uppercasing the hint text (key words or the entire clue). -Tested to work on game version 203.54 +Tested to work on game version 207.71 [Github Page](https://github.com/librarianmage/FinderOfRuin) \| [Workshop Page](https://steamcommunity.com/sharedfiles/filedetails/?id=2812261314) \| [My Caves of Qud Mods (Steam Workshop)](https://steamcommunity.com/profiles/76561198836298826/myworkshopfiles/?appid=333640) + +## Installation + +Please refer to the Caves of Qud Wiki for [mod installation instructions](https://wiki.cavesofqud.com/wiki/Modding:Installing_a_mod). + +## Development + +In order for type-checking and auto-completion to work, place the game-generated `Mods.csproj` into the parent directory of this folder. + +## License + +I share the source of my mods with the intent that they can be useful for others. To this end, the code of this mod has been released with the Zero-Clause BSD (0BSD) license and the assets of this mod (namely, files in the `Assets/` folder) have been released with the Creative Commons Zero v1.0 Universal (CC0-1.0) license. diff --git a/Scripts/ClueFormatter.cs b/Scripts/ClueFormatter.cs new file mode 100644 index 0000000..89621ab --- /dev/null +++ b/Scripts/ClueFormatter.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text.RegularExpressions; +using ConsoleLib.Console; +using static FinderOfRuin.Options.Formatting; + +namespace FinderOfRuin +{ + /// + /// Utilities for formatting Isner clues. + /// + public static class LoreFormatter + { + /// + /// Inspired by Scott Rippey's StackOverflow answer. + /// + private const string MatchingCurlyBraces = + @"(?:[^\{\}]|(?\{)|(?<-open>\}))+(?(open)(?!))"; + + /// + /// Made public for . + /// + public static readonly string CluePattern = $@"\{{({MatchingCurlyBraces})\}}"; + + /// + /// Matches the entire clue fragment. The first group is the inner clue text. + /// + public static readonly Regex ClueRegex = new(CluePattern); + + private static readonly string ClueInnerPattern = $@"(?<=\{{){MatchingCurlyBraces}(?=\}})"; + + /// + /// Matches the inner clue text, without the braces. + /// + public static readonly Regex ClueInnerRegex = new(ClueInnerPattern); + + /// + /// Formats the entire clue based on . + /// + /// + /// This function gets used as a . + /// + /// + /// The formatted match. + /// + /// + /// A of the inside of a clue. + /// + public static string FormatClueInner(Match ClueMatch) + { + var clue = ClueMatch.Value; + + if (!WantEntireClue) + { + return clue; + } + + if (Highlight.WantEntireClue) + { + clue = Highlight.Style switch + { + Highlight.HighlightStyle.OnlyWhite => Markup.Color("Y", clue), + Highlight.HighlightStyle.ColoredKeyWords => Markup.Color("Y", clue), + _ + => throw new ArgumentOutOfRangeException( + nameof(Highlight.HighlightStyle), + $"Finder of Ruin: Unexpected highlight style: {Highlight.Style}" + ) + }; + } + + if (Uppercasing.WantEntireClue) + { + clue = ColorUtility.ToUpperExceptFormatting(clue); + } + + return clue; + } + + private const string KeyWordPattern = @"(?:masterwork)|(?:Ruin)|(?:House Isner)"; + + /// + /// Matches the notable key words. + /// + public static readonly Regex KeyWordRegex = new(KeyWordPattern); + + /// + /// Map of key word to color format. + /// + public static readonly ReadOnlyDictionary KeyWordColors = + new( + new Dictionary + { + { "masterwork", "c" }, + { "Ruin", "r" }, + { "House Isner", "M" } + } + ); + + /// + /// Formats the key word matches based on . + /// + /// + /// This function gets used as a . + /// + /// + /// The formatted match. + /// + /// + /// A of a key word. + /// + public static string FormatKeyWords(Match KeyWordMatch) + { + var keyWord = KeyWordMatch.Value; + + if (!WantKeyWords) + { + return keyWord; + } + + if (Highlight.WantKeyWords) + { + keyWord = Highlight.Style switch + { + Highlight.HighlightStyle.OnlyWhite => Markup.Color("Y", keyWord), + Highlight.HighlightStyle.ColoredKeyWords + => KeyWordColors.TryGetValue(keyWord, out var color) + ? Markup.Color(color, keyWord) + : keyWord, + _ + => throw new ArgumentOutOfRangeException( + nameof(Highlight.HighlightStyle), + $"Finder of Ruin: Unexpected highlight style: {Highlight.Style}" + ) + }; + } + + if (Uppercasing.WantKeyWords) + { + keyWord = ColorUtility.ToUpperExceptFormatting(keyWord); + } + + return keyWord; + } + + ///Formats an Isner clue. + ///For use in . + public static string FormatLore(string Lore) + { + if (!Wanted) + { + return Lore; + } + + if (WantKeyWords) + { + var keyWordMatcher = new MatchEvaluator(FormatKeyWords); + Lore = KeyWordRegex.Replace(Lore, keyWordMatcher); + } + + if (WantEntireClue) + { + var clueMatcher = new MatchEvaluator(FormatClueInner); + Lore = ClueInnerRegex.Replace(Lore, clueMatcher); + } + + return Lore; + } + } +} diff --git a/Scripts/Options.cs b/Scripts/Options.cs new file mode 100644 index 0000000..4d53d54 --- /dev/null +++ b/Scripts/Options.cs @@ -0,0 +1,80 @@ +using static XRL.UI.Options; + +namespace FinderOfRuin +{ + public static class Options + { + private static string Option(string Name) => $"Books_FinderOfRuin_{Name}"; + + public static class Formatting + { + public static bool Enabled => + GetOption(Option("EnableFormatting"), "Yes").EqualsNoCase("Yes"); + + public static bool Wanted => Enabled && (Highlight.Enabled || Uppercasing.Enabled); + + public static bool WantKeyWords => + Enabled && (Highlight.WantKeyWords || Uppercasing.WantKeyWords); + + public static bool WantEntireClue => + Enabled && (Highlight.WantEntireClue || Uppercasing.WantEntireClue); + + public enum Span + { + KeyWords, + EntireClue + }; + + public static class Highlight + { + public static bool Enabled => + GetOption(Option("EnableHighlight"), "Yes").EqualsNoCase("Yes"); + + public static Span Span => + GetOption(Option("HighlightSpan")) switch + { + "Key Words" => Span.KeyWords, + "Entire Clue" => Span.EntireClue, + _ => Span.KeyWords + }; + + public enum HighlightStyle + { + OnlyWhite, + ColoredKeyWords + }; + + public static HighlightStyle Style => + GetOption(Option("HighlightStyle")) switch + { + "Only White" => HighlightStyle.OnlyWhite, + "Colored Key Words" => HighlightStyle.ColoredKeyWords, + _ => HighlightStyle.ColoredKeyWords + }; + + public static bool WantKeyWords => + Enabled && (Span == Span.KeyWords || Style == HighlightStyle.ColoredKeyWords); + + public static bool WantEntireClue => Enabled && Span == Span.EntireClue; + } + + public static class Uppercasing + { + public static bool Enabled => + GetOption(Option("EnableUppercasing"), "Yes").EqualsNoCase("Yes"); + + public static Span Span => + GetOption(Option("UppercasingSpan")) switch + { + "Key Words" => Span.KeyWords, + "Entire Clue" => Span.EntireClue, + _ => Span.KeyWords + }; + + public static bool WantKeyWords => Enabled && Span == Span.KeyWords; + + public static bool WantEntireClue => Enabled && Span == Span.EntireClue; + } + } + } +} diff --git a/Scripts/OptionsMigrator.cs b/Scripts/OptionsMigrator.cs new file mode 100644 index 0000000..d0e0005 --- /dev/null +++ b/Scripts/OptionsMigrator.cs @@ -0,0 +1,89 @@ +using XRL; +using static XRL.UI.Options; + +namespace FinderOfRuin +{ + [HasModSensitiveStaticCache] + public static class OptionsMigrator + { + [ModSensitiveCacheInit] + public static void AttemptMigration() + { + UnityEngine.Debug.Log("Finder of Ruin: Checking if migration needed…"); + if ( + !( + int.TryParse( + GetOption("Books_FinderOfRuin_OptionsVersion", "0"), + out var version + ) + && version == 1 + ) + ) + { + UnityEngine.Debug.Log("Finder of Ruin: Migration not done, migrating…"); + + if (HasOption("Books_FinderOfRuin_Highlight")) + { + var highlight = GetOption("Books_FinderOfRuin_Highlight"); + + switch (highlight) + { + case "None": + SetOption("Books_FinderOfRuin_EnableHighlight", "No"); + break; + case "Key Words": + SetOption("Books_FinderOfRuin_EnableHighlight", "Yes"); + SetOption("Books_FinderOfRuin_HighlightSpan", "Key Words"); + break; + case "Entire Clue": + SetOption("Books_FinderOfRuin_EnableHighlight", "Yes"); + SetOption("Books_FinderOfRuin_HighlightSpan", "Entire Clue"); + break; + default: + break; + } + } + + if (HasOption("Books_FinderOfRuin_HighlightStyle")) + { + var highlightStyle = GetOption("Books_FinderOfRuin_HighlightStyle"); + + if (highlightStyle == "White") + { + SetOption("Books_FinderOfRuin_HighlightStyle", "Only White"); + } + } + + if (HasOption("Books_FinderOfRuin_Capitalization")) + { + var capitalization = GetOption("Books_FinderOfRuin_Capitalization"); + + switch (capitalization) + { + case "Default": + SetOption("Books_FinderOfRuin_EnableUppercasing", "No"); + break; + case "Key Words": + SetOption("Books_FinderOfRuin_EnableUppercasing", "Yes"); + SetOption("Books_FinderOfRuin_UppercasingSpan", "Key Words"); + break; + case "Entire Clue": + SetOption("Books_FinderOfRuin_EnableUppercasing", "Yes"); + SetOption("Books_FinderOfRuin_UppercasingSpan", "Entire Clue"); + break; + default: + break; + } + } + + SetOption("Books_FinderOfRuin_OptionsVersion", "1"); + + UnityEngine.Debug.Log("Finder of Ruin: Migration done."); + } + else + { + UnityEngine.Debug.Log("Finder of Ruin: Migration already done"); + } + } + } +} diff --git a/Scripts/RuinPatches.cs b/Scripts/RuinPatches.cs new file mode 100644 index 0000000..8f01d60 --- /dev/null +++ b/Scripts/RuinPatches.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Reflection.Emit; +using System.Text.RegularExpressions; +using HarmonyLib; +using XRL; + +namespace FinderOfRuin.Patches +{ + [HarmonyPatch(typeof(MarkovChain))] + [HarmonyPatch(nameof(MarkovChain.AppendSecret))] + internal static class FormattingPatcher + { + private static IEnumerable Transpiler( + IEnumerable Instructions + ) + { + var codeMatcher = new CodeMatcher(Instructions); + + // replace regex to only accept balanced {}s and match the outermost pair + + codeMatcher.MatchStartForward(new CodeMatch(OpCodes.Ldstr, "{.*?}")); + + if (codeMatcher.IsInvalid) + { + UnityEngine.Debug.LogError("FinderOfRuin: Cannot find regex pattern"); + return Instructions; + } + + codeMatcher.SetOperandAndAdvance(LoreFormatter.CluePattern); + + // remove outer {}s from secretNugget (getting + + codeMatcher + .MatchEndForward(new CodeMatch(Instruction => Instruction.IsStarg())) + .Advance(1); + + if (codeMatcher.IsInvalid) + { + UnityEngine.Debug.LogError("FinderOfRuin: Cannot find starg anchor"); + return Instructions; + } + + // secretNugget = HeaderMatches.Groups[1].Value; + codeMatcher.InsertAndAdvance( + new CodeInstruction[] + { + new CodeInstruction(OpCodes.Ldloc_1), + new CodeInstruction( + OpCodes.Callvirt, + AccessTools.PropertyGetter(typeof(Match), nameof(Match.Groups)) + ), + new CodeInstruction(OpCodes.Ldc_I4_1), + new CodeInstruction( + OpCodes.Callvirt, + AccessTools.Method( + typeof(GroupCollection), + "get_Item", + new[] { typeof(int) } + ) + ), + new CodeInstruction( + OpCodes.Callvirt, + AccessTools.PropertyGetter(typeof(Capture), nameof(Capture.Value)) + ), + new CodeInstruction(OpCodes.Stloc_0) + } + ); + + // prevent stripping of formatting brackets + + codeMatcher + .MatchStartForward( + new CodeMatch( + Instruction => + Instruction.Is(OpCodes.Ldstr, "{") || Instruction.Is(OpCodes.Ldstr, "}") + ), + new CodeMatch(OpCodes.Ldstr, ""), + new CodeMatch( + Instruction => + Instruction.Calls( + AccessTools.Method( + typeof(string), + nameof(String.Replace), + new[] { typeof(string), typeof(string) } + ) + ) + ) + ) + .Repeat(CodeMatcher => CodeMatcher.RemoveInstructions(3)); + + return codeMatcher.InstructionEnumeration(); + } + } + + [HarmonyPatch(typeof(MarkovChain))] + [HarmonyPatch(nameof(MarkovChain.AppendSecret))] + internal static class LoreFormatterPatch + { + private static void Prefix(ref string Secret) => Secret = LoreFormatter.FormatLore(Secret); + } +} diff --git a/icon-small.png b/icon-small.png deleted file mode 100644 index 2c6fe71..0000000 Binary files a/icon-small.png and /dev/null differ diff --git a/icon.aseprite b/icon.aseprite deleted file mode 100644 index 04ec302..0000000 Binary files a/icon.aseprite and /dev/null differ diff --git a/icon.png b/icon.png deleted file mode 100644 index 78089cb..0000000 Binary files a/icon.png and /dev/null differ diff --git a/manifest.json b/manifest.json index 58910cf..5e11154 100644 --- a/manifest.json +++ b/manifest.json @@ -1,8 +1,8 @@ { - "id": "FinderOfRuin", - "title": "Finder of {{r|Ruin}}", - "description": "Makes it easier to find the {{c|masterwork}} pistol {{r|Ruin}} of {{M|House Isner}}. See Options > Finder of Ruin for customization.", - "version": "1.1", - "author": "librarianmage", - "previewImage": "icon.png" + "id": "FinderOfRuin", + "title": "{{M|Finder}} {{c|of}} {{r|Ruin}}", + "description": "Makes it easier to find the {{c|masterwork}} pistol {{r|Ruin}} of {{M|House Isner}}. See {{W|Options}} {{y|>}} {{c|Finder of Ruin}} for customization.", + "version": "1.3", + "author": "{{R|librarianmage}}", + "previewImage": "Assets/icon.png" } diff --git a/project.csproj b/project.csproj index 9823b73..35e1d19 100644 --- a/project.csproj +++ b/project.csproj @@ -1,7 +1,9 @@ - netstandard2.0 - false + FinderOfRuin + FinderOfRuin + librarianmage + true diff --git a/ruin.cs b/ruin.cs deleted file mode 100644 index 56ba8a8..0000000 --- a/ruin.cs +++ /dev/null @@ -1,79 +0,0 @@ -using HarmonyLib; -using System; -using System.Text.RegularExpressions; -using XRL; -using XRL.UI; - -namespace FinderOfRuin.HarmonyPatches -{ - [HarmonyPatch(typeof(LoreGenerator))] - [HarmonyPatch(nameof(LoreGenerator.RuinOfHouseIsnerLore))] - class LorePatcher - { - static void Postfix(ref string __result) - { - String Highlight = Options.GetOption("Books_FinderOfRuin_Highlight", "Key Words"); - String HighlightStyle = Options.GetOption("Books_FinderOfRuin_HighlightStyle", "Colored Key Words"); - String Capitalization = Options.GetOption("Books_FinderOfRuin_Capitalization", "Default"); - - if (Highlight == "Entire Clue" || Capitalization == "Entire Clue") - { - Regex rx = new Regex(@"\{(.*)\}"); - - Func match = (Match m) => - { - String hint = m.Captures[0].Value; - if (Capitalization == "Entire Clue") { hint = hint.ToUpper(); }; - if (Highlight == "Entire Clue") { hint = "&Y" + hint + "&y"; } - return hint; - }; - - MatchEvaluator evaluator = new MatchEvaluator(match); - __result = rx.Replace(__result, evaluator); - } - - if (Highlight == "Key Words" || Capitalization == "Key Words" || (Highlight == "Entire Clue" && HighlightStyle == "Colored Key Words")) - { - Regex rx = new Regex(@"(masterwork|ruin|house isner)", RegexOptions.IgnoreCase); - - Func match = (Match m) => - { - String hint = m.Captures[0].Value; - if (Capitalization == "Key Words") { hint = hint.ToUpper(); }; - if (Highlight != "Default" && HighlightStyle == "Colored Key Words") - { - String restColor = (Highlight == "Entire Clue") ? "&Y" : "&y"; - String startColor; - - if (hint.ToLower() == "masterwork") - { - startColor = "&c"; - } - else if (hint.ToLower() == "ruin") - { - startColor = "&r"; - } - else if (hint.ToLower() == "house isner") - { - startColor = "&M"; - } - else - { - startColor = restColor; - } - - hint = startColor + hint + restColor; - } - else if (Highlight == "Key Words" && HighlightStyle == "White") - { - hint = "&Y" + hint + "&y"; - } - return hint; - }; - - MatchEvaluator evaluator = new MatchEvaluator(match); - __result = rx.Replace(__result, evaluator); - } - } - } -} diff --git a/screenshot.png b/screenshot.png deleted file mode 100644 index e9fb5ed..0000000 Binary files a/screenshot.png and /dev/null differ diff --git a/workshop.json b/workshop.json index 53732c9..c6b122f 100644 --- a/workshop.json +++ b/workshop.json @@ -1,8 +1,8 @@ { "WorkshopId": 2812261314, "Title": "Finder of Ruin", - "Description": "A mod that aids in the finding of the Ruin of House Isner by making the clues a bit more obvious.\n\nThe mod offers two aids: coloring or capitalizing the hint text (key words or the entire clue).\n\nTested to work on game version 203.54\n\n[url=https://github.com/librarianmage/FinderOfRuin]Github Page[/url]", + "Description": "A mod that aids in the finding of the Ruin of House Isner by making the clues a bit more obvious.\n\nThe mod offers two aids: coloring or uppercasing the hint text (key words or the entire clue).\n\nTested to work on game version 207.71\n\n[url=https://github.com/librarianmage/FinderOfRuin]Source Code (GitHub)[/url]", "Tags": "Stable,Beta,Artifact,Script", "Visibility": "2", - "ImagePath": "icon.png" -} + "ImagePath": "Assets/icon.png" +} \ No newline at end of file