From e2db412186e020504f1186220635bcd7662a9059 Mon Sep 17 00:00:00 2001 From: librarianmage Date: Tue, 27 Jun 2023 03:12:53 +0000 Subject: [PATCH 01/10] Update icon FossilOrigin-Name: 102e4c458fb4a257ae1641662ee2dceee7ab365d053dc4f1a5f2d38b1c4fba35 --- icon-small.png => Assets/favicon.png | Bin 288 -> 288 bytes Assets/icon.aseprite | Bin 0 -> 575 bytes icon.png => Assets/icon.png | Bin 2001 -> 2001 bytes icon.aseprite | Bin 536 -> 0 bytes workshop.json | 2 +- 5 files changed, 1 insertion(+), 1 deletion(-) rename icon-small.png => Assets/favicon.png (55%) create mode 100644 Assets/icon.aseprite rename icon.png => Assets/icon.png (90%) delete mode 100644 icon.aseprite diff --git a/icon-small.png b/Assets/favicon.png similarity index 55% rename from icon-small.png rename to Assets/favicon.png index 03c9cf1b2116d5db6307304b22fb00accd522fcd..b39beadb09512d8e4345764767f78d99b2ada1c6 100644 GIT binary patch delta 32 mcmZ3$w18>Ca>mk$D^f(1^>lQlqaL?10D-5gpUXO@geCy3mkJyJ delta 32 mcmZ3$w18>Ca>lZWD^f%*J8O6TPPEcw00K`}KbLh*2~7aQhzlP8 diff --git a/Assets/icon.aseprite b/Assets/icon.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..98b011eb2e2f1cb7b34fb0420d546b0fbd62823c GIT binary patch literal 575 zcmcC#Vqkc%l#xLJ2ss!S85kH+fEWRU85lu=3<5w%3$Pz(`mc}dU|ZRN7Ki~cy8_rs zBHgDHAnafMogp^FY#J$xa~2Fb!lTgU4PVc`N!FklYw@{=YL& zhy@fK@dp7 z0LUIz2DhTb+*BDLlLhWqkOGh-3xiuuV!APq#i{@#fZ#tc<{$tRcNKFUKU*g9;Q`~~ zPawEu>T(_i21hP^!8o8AR$zd#0U<(*2!jYvOX~$gJ_Z90r@+|M*MIq=r7ydreCW?- xHcoM4RDT^)BxU~7CgrrTsCt=Ks)0-_XaT6|9vreBctNv39M=`ym>LB6r0G^9KESbY*n8afWXt$&t;uc GLK6U_Jrwr< delta 57 zcmcb}f02K}9>)C>_XaTA|9vreBctNv39M=`ym>LB6r0Giq^`CerS;|vK;Y@>=d#Wz Gp$Pz}_Z3S3 diff --git a/icon.aseprite b/icon.aseprite deleted file mode 100644 index f5ddd21249cb6b2fcae59301bf11fa116fb15133..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 536 zcmb1OVqkc%l#xLJ2ss!S85kH+fEWRU85lu=3<5w%3orv{`mc|yU|U&%7Ki~cy8_rs zBHgDHAnafMogp^FY#J$xa~2Fb!lTgU4PVc`N!FklYw@{=YL& zhy@fff-1` z0LUIz2A{;r)S@;JQvo9J9~e6j0E(ZAIcFz1avd<>VELG3`}BYRTC>P(M{XgFxu@CE zPrAC6S;qZ1_uSXVwM|HS#(5cqFTwWO*Yl^c+xmOG<=mm_^>{>=iD>`; diff --git a/workshop.json b/workshop.json index 9dab11b..4f6e5b8 100644 --- a/workshop.json +++ b/workshop.json @@ -5,4 +5,4 @@ "Tags": "Stable,Beta,Script,Gender,Pronouns", "Visibility": "2", "ImagePath": "icon.png" -} +} \ No newline at end of file From 6b679518203701a71b9c29b01c4d54dae7ed6060 Mon Sep 17 00:00:00 2001 From: librarianmage Date: Mon, 14 Aug 2023 22:58:45 +0000 Subject: [PATCH 02/10] Update icon metadata FossilOrigin-Name: fac48b0d23111cd9eef2c0edf4541c755211aafd7d195d90c6d90855afceed46 --- meme.png => Assets/meme.png | Bin manifest.json | 2 +- workshop.json | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename meme.png => Assets/meme.png (100%) diff --git a/meme.png b/Assets/meme.png similarity index 100% rename from meme.png rename to Assets/meme.png diff --git a/manifest.json b/manifest.json index e903043..11783ec 100644 --- a/manifest.json +++ b/manifest.json @@ -4,5 +4,5 @@ "description": "Adds gendeers and pronounce", "version": "1.4", "author": "librarianmage", - "previewImage": "icon.png" + "previewImage": "Assets/icon.png" } diff --git a/workshop.json b/workshop.json index 4f6e5b8..da4d102 100644 --- a/workshop.json +++ b/workshop.json @@ -4,5 +4,5 @@ "Description": "A mod that works in conjunction with the [url=https://steamcommunity.com/sharedfiles/filedetails/?id=1735379738]Gender and Pronoun Sets[/url] mod to allow your delver to wreathe themselves in the gender identity and pronouns they feel most comfortable in.\n\nSpecifically, this mod allows you to pick from all personal genders and pronouns defined in game (including pseudo-plural ones), with a number of additions.\n\nAdditionally, the \"choose pronoun\" prompt in game has been modified to use the modern UI. This will facilitate picking from the extended list this mod provides.\n\n[i]`=name=` pronoun sets:[/i] Starting with version 1.1, `=name=` in a pronoun set will be dynamically replaced with the player character's name (`=name's=` with the possessive version). To demonstrate this, a pronoun set consisting completely of `=name=` and `=name's=` has been added.\n\nTested to work on game version 203.54 and the Moon Stair alpha.\n\n[url=https://github.com/librarianmage/QudGendersUnleashed]Github Page[/url]", "Tags": "Stable,Beta,Script,Gender,Pronouns", "Visibility": "2", - "ImagePath": "icon.png" + "ImagePath": "Assets/icon.png" } \ No newline at end of file From 4b5bd56683ab3e0cae591c8fd52690f1b5788843 Mon Sep 17 00:00:00 2001 From: librarianmage Date: Mon, 14 Aug 2023 23:12:39 +0000 Subject: [PATCH 03/10] Add CHANGELOG.md FossilOrigin-Name: be506432b41f89b53678c4d3784bfa46034579f4c3b0d5f242755c793ad0e0ea --- CHANGELOG.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..20626c9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,32 @@ +# Changelog + +## Unreleased + +Meta: + +* Add `CHANGELOG.md` +* Update icon + +## v1.4 — 2022-10-15 +Tested to work on game version 203.54 and the Moon Stair alpha + +* Update mod to work with Moon Stair alpha + +## v1.3 — 2022-07-26 +Tested to work on game version 203.54 + +* Update documentation + +## v1.2 — 2022-07-26 + +* Update name only pronoun to use player's name in all third-person pronoun positions + +## v1.1 — 2022-07-06 + +* Add pronoun set that uses only the name of the thing being referred to +* Update playtime pronoun selector (seen on the character stat screen) to use the modern UI +* Update icon + +## v1.0 — 2022-05-31 + +* Initial release From 01c59841a5a39ab42adc96f6b3ae36f1035835dd Mon Sep 17 00:00:00 2001 From: librarianmage Date: Mon, 14 Aug 2023 23:31:42 +0000 Subject: [PATCH 04/10] Fix error preventing loading FossilOrigin-Name: aab031e7b4bd1d12a776fb6ebd4c31bdc4417752856b03cfa16e6b8c91344581 --- CHANGELOG.md | 3 +++ selectors.cs | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20626c9..2e061a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog ## Unreleased +Tested to work on game versions 204.100 / 205.54 (beta) + +* Fix error preventing loading Meta: diff --git a/selectors.cs b/selectors.cs index 3c3c037..63b0c6f 100644 --- a/selectors.cs +++ b/selectors.cs @@ -101,11 +101,11 @@ public static async Task OnChoosePronounSetAsync(GameObject Player) options.AddRange(pronounNames); options.Add(""); - int index = await Popup.AsyncShowOptionsList( + int index = await Popup.ShowOptionListAsync( Title: "Change Pronoun Set", Options: options.ToArray(), AllowEscape: true, - defaultSelected: indexCurrentPronounSet + 1); + DefaultSelected: indexCurrentPronounSet + 1); if (index > -1) { @@ -123,7 +123,7 @@ public static async Task OnChoosePronounSetAsync(GameObject Player) } } - int basePronounIndex = await Popup.AsyncShowOptionsList( + int basePronounIndex = await Popup.ShowOptionListAsync( Title: "Select Base Set", Options: pronounNames.ToArray(), RespectOptionNewlines: false, From 0a139da43cf820509d400381fc3ca66d769870f2 Mon Sep 17 00:00:00 2001 From: librarianmage Date: Tue, 15 Aug 2023 02:25:23 +0000 Subject: [PATCH 05/10] Reduce Wrapping FossilOrigin-Name: e023c3e62025d6454964388fff25c988a4d0331c8eb822ed8814f4631ae4472c --- namepronoun.cs | 69 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/namepronoun.cs b/namepronoun.cs index c10cbc9..cbf5598 100644 --- a/namepronoun.cs +++ b/namepronoun.cs @@ -5,35 +5,87 @@ namespace QudGendersUnleashed.NamePronoun { + /// + /// Wraps the returned by with a . + /// [HarmonyPatch(typeof(GameObject))] [HarmonyPatch(nameof(GameObject.GetPronounProvider))] public static class NameOnlyPronounPatch { static IPronounProvider Postfix(IPronounProvider PronounSet, GameObject __instance) { - return new NamePronounWrapper(PronounSet, __instance); + return NamePronounWrapper.Wrap(PronounSet, __instance); } } - // Wraps a IPronounProvider to replace =name=/=name's= with the holder's name + /// + /// Wraps a , replacing =name=/=name's= with the name of the pronouns' referent. + /// public class NamePronounWrapper : IPronounProvider { private IPronounProvider BasePronouns; - private GameObject Referrant; + private GameObject Referent; + + private static bool CouldHaveName(string S) => S.Contains("=name"); + + public static bool CouldBeNamePronouns(IPronounProvider Pronouns) => + CouldHaveName(Pronouns.Name) + || CouldHaveName(Pronouns.CapitalizedName) + || CouldHaveName(Pronouns.Subjective) + || CouldHaveName(Pronouns.CapitalizedSubjective) + || CouldHaveName(Pronouns.Objective) + || CouldHaveName(Pronouns.CapitalizedObjective) + || CouldHaveName(Pronouns.PossessiveAdjective) + || CouldHaveName(Pronouns.CapitalizedPossessiveAdjective) + || CouldHaveName(Pronouns.SubstantivePossessive) + || CouldHaveName(Pronouns.CapitalizedSubstantivePossessive) + || CouldHaveName(Pronouns.Reflexive) + || CouldHaveName(Pronouns.CapitalizedReflexive) + || CouldHaveName(Pronouns.PersonTerm) + || CouldHaveName(Pronouns.CapitalizedPersonTerm) + || CouldHaveName(Pronouns.ImmaturePersonTerm) + || CouldHaveName(Pronouns.CapitalizedImmaturePersonTerm) + || CouldHaveName(Pronouns.FormalAddressTerm) + || CouldHaveName(Pronouns.CapitalizedFormalAddressTerm) + || CouldHaveName(Pronouns.OffspringTerm) + || CouldHaveName(Pronouns.CapitalizedOffspringTerm) + || CouldHaveName(Pronouns.SiblingTerm) + || CouldHaveName(Pronouns.CapitalizedSiblingTerm) + || CouldHaveName(Pronouns.ParentTerm) + || CouldHaveName(Pronouns.CapitalizedParentTerm) + || CouldHaveName(Pronouns.IndicativeProximal) + || CouldHaveName(Pronouns.CapitalizedIndicativeProximal) + || CouldHaveName(Pronouns.IndicativeDistal) + || CouldHaveName(Pronouns.CapitalizedIndicativeDistal); + + public static IPronounProvider Wrap(IPronounProvider BasePronouns, GameObject Referent) + { + if (BasePronouns is NamePronounWrapper p && p.Referent != Referent) + { + p.Referent = Referent; + } + else if (CouldBeNamePronouns(BasePronouns)) + { + return new NamePronounWrapper(BasePronouns, Referent); + } + + return BasePronouns; + } public NamePronounWrapper(IPronounProvider BasePronouns, GameObject Referrant) { this.BasePronouns = BasePronouns; - this.Referrant = Referrant; - // Consider: caching if replacing is needed + this.Referent = Referrant; } - string ReplaceWithName(string Pronoun, bool capitalize = false) + public string ReplaceWithName(string Pronoun, bool capitalize = false) { if (Pronoun.Contains("=name")) { - string DisplayName = Referrant.BaseDisplayNameStripped; - if (capitalize) { DisplayName = ColorUtility.CapitalizeExceptFormatting(DisplayName); } + string DisplayName = Referent.BaseDisplayNameStripped; + if (capitalize) { + DisplayName = ColorUtility.CapitalizeExceptFormatting(DisplayName); + } string DisplayNamePosessive = Grammar.MakePossessive(DisplayName); return Pronoun.Replace("=name=", DisplayName) .Replace("=name's=", DisplayNamePosessive); @@ -76,7 +128,6 @@ string ReplaceWithName(string Pronoun, bool capitalize = false) public string CapitalizedReflexive => ReplaceWithName(BasePronouns.CapitalizedReflexive, true); - // Consider: The methods below here are unlikely to contain =name=/=name's=, remove wrap? public string PersonTerm => ReplaceWithName(BasePronouns.PersonTerm); public string CapitalizedPersonTerm => ReplaceWithName(BasePronouns.CapitalizedPersonTerm, true); From 4eeb7aadb182c934bb238a90b7f606ae73213890 Mon Sep 17 00:00:00 2001 From: librarianmage Date: Tue, 15 Aug 2023 03:01:44 +0000 Subject: [PATCH 06/10] Update README, LICENSE FossilOrigin-Name: dc4886880f6fac38cc09140314bb8d73c3a2900dba59291e5aea937f731432af --- CHANGELOG.md | 3 ++ LICENSE | 122 ++------------------------------------------------ README.md | 24 ++++++++-- manifest.json | 13 +++--- workshop.json | 4 +- 5 files changed, 35 insertions(+), 131 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e061a2..d0a21bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,14 @@ Tested to work on game versions 204.100 / 205.54 (beta) * Fix error preventing loading +* Reduce `NamePronounWrapper` wrapping Meta: * Add `CHANGELOG.md` * Update icon +* Update mod description +* Update `LICENSE` ## v1.4 — 2022-10-15 Tested to work on game version 203.54 and the Moon Stair alpha 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/README.md b/README.md index 82b5072..33d026f 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,29 @@ # Qud: Genders Unleashed -A mod that works in conjunction with the [Gender and Pronoun Sets](https://steamcommunity.com/sharedfiles/filedetails/?id=1735379738) mod to allow your delver to wreathe themselves in the gender identity and pronouns they feel most comfortable in. +A mod that works in conjunction with the [Gender and Pronoun Sets](https://steamcommunity.com/sharedfiles/filedetails/?id=1735379738) mod to provide a plethora of genders and pronouns for your game character. Specifically, this mod allows you to pick from all personal genders and pronouns defined in game (including pseudo-plural ones), with a number of additions. Additionally, the "choose pronoun" prompt in game has been modified to use the modern UI. This will facilitate picking from the extended list this mod provides. -*`=name=` pronoun sets:* Starting with version 1.1, `=name=` in a pronoun set will be dynamically replaced with the player character's name (`=name's=` with the possessive version). To demonstrate this, a pronoun set consisting completely of `=name=` and `=name's=` has been added. +Tested to work on game versions 204.100 / 205.54 (beta). -Tested to work on game version 203.54 +[Source Code (GitHub)](https://github.com/librarianmage/QudGendersUnleashed) \| [Workshop Page](https://steamcommunity.com/sharedfiles/filedetails/?id=2815078000) \| [My Caves of Qud Mods (Steam Workshop)](https://steamcommunity.com/profiles/76561198836298826/myworkshopfiles/?appid=333640) -[Github Page](https://github.com/librarianmage/QudGendersUnleashed) \| [Workshop Page](https://steamcommunity.com/sharedfiles/filedetails/?id=2815078000) \| [My Caves of Qud Mods (Steam Workshop)](https://steamcommunity.com/profiles/76561198836298826/myworkshopfiles/?appid=333640) +Also check out the [Pride Naming Colors](https://steamcommunity.com/sharedfiles/filedetails/?id=2951409991) Workshop mod by Steam user Flaborized! + +## `=name=` Pronoun Sets + +Starting with version 1.1, `=name=` in a pronoun set will be dynamically replaced with the player character's name (`=name's=` with the possessive version). To demonstrate this, a pronoun set consisting completely of `=name=` and `=name's=` has been added. + +## 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/manifest.json b/manifest.json index 11783ec..72aa679 100644 --- a/manifest.json +++ b/manifest.json @@ -1,8 +1,9 @@ { - "id": "QudGendersUnleashed", - "title": "{{m-Y-g alternation|Qud: Genders Unleashed}}", - "description": "Adds gendeers and pronounce", - "version": "1.4", - "author": "librarianmage", - "previewImage": "Assets/icon.png" + "id": "QudGendersUnleashed", + "title": "{{m-Y-g alternation|Qud: Genders Unleashed}}", + "description": "Adds gendeers and pronounce", + "tags": "Gender,Pronouns", + "version": "1.4", + "author": "{{R|librarianmage}}", + "previewImage": "Assets/icon.png" } diff --git a/workshop.json b/workshop.json index da4d102..aed6f2a 100644 --- a/workshop.json +++ b/workshop.json @@ -1,8 +1,8 @@ { "WorkshopId": 2815078000, "Title": "Qud: Genders Unleashed", - "Description": "A mod that works in conjunction with the [url=https://steamcommunity.com/sharedfiles/filedetails/?id=1735379738]Gender and Pronoun Sets[/url] mod to allow your delver to wreathe themselves in the gender identity and pronouns they feel most comfortable in.\n\nSpecifically, this mod allows you to pick from all personal genders and pronouns defined in game (including pseudo-plural ones), with a number of additions.\n\nAdditionally, the \"choose pronoun\" prompt in game has been modified to use the modern UI. This will facilitate picking from the extended list this mod provides.\n\n[i]`=name=` pronoun sets:[/i] Starting with version 1.1, `=name=` in a pronoun set will be dynamically replaced with the player character's name (`=name's=` with the possessive version). To demonstrate this, a pronoun set consisting completely of `=name=` and `=name's=` has been added.\n\nTested to work on game version 203.54 and the Moon Stair alpha.\n\n[url=https://github.com/librarianmage/QudGendersUnleashed]Github Page[/url]", + "Description": "A mod that works in conjunction with the [url=https://steamcommunity.com/sharedfiles/filedetails/?id=1735379738]Gender and Pronoun Sets[/url] mod to to provide a plethora of genders and pronouns for your game character.\n\nSpecifically, this mod allows you to pick from all personal genders and pronouns defined in game (including pseudo-plural ones), with a number of additions.\n\nAdditionally, the \"choose pronoun\" prompt in game has been modified to use the modern UI. This will facilitate picking from the extended list this mod provides.\n\nTested to work on game versions 204.100 / 205.54 (beta).\n\n[url=https://github.com/librarianmage/QudGendersUnleashed]Source Code (GitHub)[/url]\n\n[h1]`=name=` Pronoun Sets[/h1]Starting with version 1.1, `=name=` in a pronoun set will be dynamically replaced with the player character's name (`=name's=` with the possessive version). To demonstrate this, a pronoun set consisting completely of `=name=` and `=name's=` has been added.", "Tags": "Stable,Beta,Script,Gender,Pronouns", "Visibility": "2", "ImagePath": "Assets/icon.png" -} \ No newline at end of file +} From 2a2295ae23a50b4158bd5265f89539a1a1bfb3fc Mon Sep 17 00:00:00 2001 From: librarianmage Date: Tue, 15 Aug 2023 03:11:13 +0000 Subject: [PATCH 07/10] Reorganize FossilOrigin-Name: 5d02519db523eeb02be728991bf04a4bd3360f8b221c7ba35bb3beab2df62965 --- egg.cs => Egg.cs | 0 namepronoun.cs => NamePronoun.cs | 0 selectors.cs => SelectorPatches.cs | 0 workshop.json | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) rename egg.cs => Egg.cs (100%) rename namepronoun.cs => NamePronoun.cs (100%) rename selectors.cs => SelectorPatches.cs (100%) diff --git a/egg.cs b/Egg.cs similarity index 100% rename from egg.cs rename to Egg.cs diff --git a/namepronoun.cs b/NamePronoun.cs similarity index 100% rename from namepronoun.cs rename to NamePronoun.cs diff --git a/selectors.cs b/SelectorPatches.cs similarity index 100% rename from selectors.cs rename to SelectorPatches.cs diff --git a/workshop.json b/workshop.json index aed6f2a..ba6025c 100644 --- a/workshop.json +++ b/workshop.json @@ -1,7 +1,7 @@ { "WorkshopId": 2815078000, "Title": "Qud: Genders Unleashed", - "Description": "A mod that works in conjunction with the [url=https://steamcommunity.com/sharedfiles/filedetails/?id=1735379738]Gender and Pronoun Sets[/url] mod to to provide a plethora of genders and pronouns for your game character.\n\nSpecifically, this mod allows you to pick from all personal genders and pronouns defined in game (including pseudo-plural ones), with a number of additions.\n\nAdditionally, the \"choose pronoun\" prompt in game has been modified to use the modern UI. This will facilitate picking from the extended list this mod provides.\n\nTested to work on game versions 204.100 / 205.54 (beta).\n\n[url=https://github.com/librarianmage/QudGendersUnleashed]Source Code (GitHub)[/url]\n\n[h1]`=name=` Pronoun Sets[/h1]Starting with version 1.1, `=name=` in a pronoun set will be dynamically replaced with the player character's name (`=name's=` with the possessive version). To demonstrate this, a pronoun set consisting completely of `=name=` and `=name's=` has been added.", + "Description": "A mod that works in conjunction with the [url=https://steamcommunity.com/sharedfiles/filedetails/?id=1735379738]Gender and Pronoun Sets[/url] mod to to provide a plethora of genders and pronouns for your game character.\n\nSpecifically, this mod allows you to pick from all personal genders and pronouns defined in game (including pseudo-plural ones), with a number of additions.\n\nAdditionally, the \"choose pronoun\" prompt in game has been modified to use the modern UI. This will facilitate picking from the extended list this mod provides.\n\nTested to work on game versions 204.100 / 205.54 (beta).\n\n[url=https://github.com/librarianmage/QudGendersUnleashed]Source Code (GitHub)[/url]\n\nAlso check out the [url=https://steamcommunity.com/sharedfiles/filedetails/?id=2951409991]Pride Naming Colors[/url] Workshop mod by Steam user Flaborized!\n\n[h1]`=name=` Pronoun Sets[/h1]Starting with version 1.1, `=name=` in a pronoun set will be dynamically replaced with the player character's name (`=name's=` with the possessive version). To demonstrate this, a pronoun set consisting completely of `=name=` and `=name's=` has been added.", "Tags": "Stable,Beta,Script,Gender,Pronouns", "Visibility": "2", "ImagePath": "Assets/icon.png" From ac1d54340741908894edd12b1d85a6d8ff19f12b Mon Sep 17 00:00:00 2001 From: librarianmage Date: Tue, 15 Aug 2023 11:04:20 +0000 Subject: [PATCH 08/10] Rehaul selector UI FossilOrigin-Name: ddb7d7508d865cf990edaba4f1200ec6cd742fe772ab4930b15c2bfb460b3122 --- CHANGELOG.md | 1 + Egg.cs | 23 ++++-- SelectorPatches.cs | 138 ++++---------------------------- Selectors.cs | 193 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 224 insertions(+), 131 deletions(-) create mode 100644 Selectors.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index d0a21bc..c8937f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased Tested to work on game versions 204.100 / 205.54 (beta) +* Add new selector UI * Fix error preventing loading * Reduce `NamePronounWrapper` wrapping diff --git a/Egg.cs b/Egg.cs index 446a43d..b0124f2 100644 --- a/Egg.cs +++ b/Egg.cs @@ -1,14 +1,23 @@ using XRL.UI; using XRL.Wish; -[HasWishCommand] -public class GenderUploadForm +namespace QudGendersUnleashed.Wishes { - [WishCommand(Command = "gendermeme")] - static public bool GenderMeme() + /// Useless wish used to generate the header image. + [HasWishCommand] + public class GenderUploadForm { - string[] opts = {"Male", "Female", "Custom [Upload custom gender (max 10MB)]"}; - Popup.ShowOptionList("Gender", opts); - return true; + [WishCommand(Command = "gendermeme")] + static public bool GenderMeme() + { + string[] opts = { + "Male", + "Female", + "Custom [Upload custom gender (max 10MB)]" + }; + + Popup.ShowOptionList("Gender", opts); + return true; + } } } diff --git a/SelectorPatches.cs b/SelectorPatches.cs index 63b0c6f..c6ce9f8 100644 --- a/SelectorPatches.cs +++ b/SelectorPatches.cs @@ -1,145 +1,35 @@ using HarmonyLib; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; using XRL; using XRL.World; using XRL.CharacterBuilds.Qud.UI; -using XRL.UI; using System.Threading.Tasks; -namespace QudGendersUnleashed.PronounAndGenderSelectorPatches +namespace QudGendersUnleashed.Selectors.Patches { - [HarmonyPatch] - public static class CharacterCreationGenderPatch + [HarmonyPatch(typeof(QudCustomizeCharacterModuleWindow))] + [HarmonyPatch(nameof(QudCustomizeCharacterModuleWindow.OnChooseGenderAsync))] + public static class GenderPatch { - public static MethodInfo TargetMethod() - { - return AccessTools.DeclaredMethod(AccessTools.Inner(typeof(QudCustomizeCharacterModuleWindow), "d__5"), "MoveNext"); - } - public static IEnumerable Transpiler(IEnumerable instructions) - { - MethodInfo oldPReefMethod = AccessTools.Method(typeof(Gender), nameof(Gender.GetAllGenericPersonalSingular)); - MethodInfo oldMStairMethod = AccessTools.Method(typeof(Gender), nameof(Gender.GetAllGenericPersonal)); - MethodInfo newMethod = AccessTools.Method(typeof(Gender), nameof(Gender.GetAllPersonal)); + static bool Prefix() => false; - IEnumerable replacePReef = HarmonyLib.Transpilers.MethodReplacer(instructions, oldPReefMethod, newMethod); - IEnumerable replaceMStair = HarmonyLib.Transpilers.MethodReplacer(replacePReef, oldMStairMethod, newMethod); - - return replaceMStair; - } + static Task Postfix(Task _, QudCustomizeCharacterModuleWindow __instance) => Selectors.OnChooseGenderAsync(__instance); } - [HarmonyPatch] - public static class CharacterCreationPronounPatch + [HarmonyPatch(typeof(QudCustomizeCharacterModuleWindow))] + [HarmonyPatch(nameof(QudCustomizeCharacterModuleWindow.OnChoosePronounSetAsync))] + public static class PronounPatch { - public static MethodBase TargetMethod() - { - return AccessTools.DeclaredMethod(AccessTools.Inner(typeof(QudCustomizeCharacterModuleWindow), "d__7"), "MoveNext"); - } - public static IEnumerable Transpiler(IEnumerable instructions) - { - - MethodInfo oldPReefMethod = AccessTools.Method(typeof(PronounSet), nameof(PronounSet.GetAllGenericPersonalSingular)); - MethodInfo oldMStairMethod = AccessTools.Method(typeof(PronounSet), nameof(PronounSet.GetAllGenericPersonal)); - MethodInfo newMethod = AccessTools.Method(typeof(PronounSet), nameof(PronounSet.GetAllPersonal)); + static bool Prefix() => false; - IEnumerable replacePReef = HarmonyLib.Transpilers.MethodReplacer(instructions, oldPReefMethod, newMethod); - IEnumerable replaceMStair = HarmonyLib.Transpilers.MethodReplacer(replacePReef, oldMStairMethod, newMethod); - - return replaceMStair; - } + static Task Postfix(Task _, PronounSet ___fromGenderPlaceholder, QudCustomizeCharacterModuleWindow __instance) + => Selectors.OnChoosePronounSetAsync(__instance, ___fromGenderPlaceholder); } - // Technically unused [HarmonyPatch(typeof(PronounAndGenderSets))] [HarmonyPatch(nameof(PronounAndGenderSets.ShowChangePronounSet))] public static class PlaytimePronounPatch { - public static IEnumerable Transpiler(IEnumerable instructions) - { - MethodInfo oldMethod = AccessTools.Method(typeof(PronounSet), nameof(PronounSet.GetAllGenericPersonal)); - MethodInfo newMethod = AccessTools.Method(typeof(PronounSet), nameof(PronounSet.GetAllPersonal)); - return HarmonyLib.Transpilers.MethodReplacer(instructions, oldMethod, newMethod); - } - } - - - [HarmonyPatch(typeof(StatusScreen))] - [HarmonyPatch(nameof(StatusScreen.Show))] - public static class StatusScreenPatch - { - public static IEnumerable Transpiler(IEnumerable instructions) - { - MethodInfo oldMethod = AccessTools.Method(typeof(PronounAndGenderSets), nameof(PronounAndGenderSets.ShowChangePronounSet)); - MethodInfo newMethod = AccessTools.Method(typeof(StatusScreenPatch), nameof(StatusScreenPatch.ChangePronounSet)); - return HarmonyLib.Transpilers.MethodReplacer(instructions, oldMethod, newMethod); - } - - public static void ChangePronounSet(GameObject Player) - { - Task newPronounTask = OnChoosePronounSetAsync(Player); - newPronounTask.Wait(); - PronounSet newPronoun = newPronounTask.Result; - - if (newPronoun != null) - { - Player.SetPronounSet(newPronoun.Register()); - } - } - - public static async Task OnChoosePronounSetAsync(GameObject Player) - { - List availablePronounSets = PronounSet.GetAllPersonal(); - IEnumerable pronounNames = availablePronounSets.Select((PronounSet pronounSet) => pronounSet.Name); - - PronounSet currentPronounSet = Player.GetPronounSet(); - int indexCurrentPronounSet = availablePronounSets.FindIndex(p => p == currentPronounSet); - - List options = new List(); - options.Add(""); - options.AddRange(pronounNames); - options.Add(""); - - int index = await Popup.ShowOptionListAsync( - Title: "Change Pronoun Set", - Options: options.ToArray(), - AllowEscape: true, - DefaultSelected: indexCurrentPronounSet + 1); - - if (index > -1) - { - if (options[index] != "") - { - if (index == 0) - { - // Selected - Gender playerGender = Player.GetGender(); - return new PronounSet(playerGender); - } - else - { - return availablePronounSets[index - 1]; - } - } - - int basePronounIndex = await Popup.ShowOptionListAsync( - Title: "Select Base Set", - Options: pronounNames.ToArray(), - RespectOptionNewlines: false, - AllowEscape: true); - - if (basePronounIndex > -1) - { - PronounSet original = availablePronounSets[basePronounIndex]; - PronounSet newPronounSet = new PronounSet(original); - if (await newPronounSet.CustomizeAsync()) - { - return newPronounSet; - } - } - } - return null; - } + static bool Prefix() => false; + static void Postfix() => Selectors.ChoosePronounSet(); } } diff --git a/Selectors.cs b/Selectors.cs new file mode 100644 index 0000000..ab65550 --- /dev/null +++ b/Selectors.cs @@ -0,0 +1,193 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using ConsoleLib.Console; +using XRL; +using XRL.CharacterBuilds.Qud.UI; +using XRL.UI; +using XRL.World; + +namespace QudGendersUnleashed.Selectors +{ + [HasModSensitiveStaticCache] + public static class Selectors + { + private static string FromGenderText = Markup.Color("W", ""); + private static string CreateNewText = Markup.Color("W", ""); + + [ModSensitiveStaticCache] + private static Dictionary _PronounGenderMapping; + + public static Dictionary PronounGenderMapping { + get { + if (_PronounGenderMapping == null) + { + _PronounGenderMapping = new Dictionary(); + + var suspects = Gender.Find(g => !g.DoNotReplicateAsPronounSet); + foreach (Gender g in suspects) + { + var setName = new PronounSet(g).Name; + var pronounSet = PronounSet.GetIfExists(setName); + if (pronounSet != null) _PronounGenderMapping.Add(pronounSet, g); + } + + } + + return _PronounGenderMapping; + } + } + + private static string FormatName(string name, string color = "M") + { + if (ColorUtility.HasFormatting(name)) + { + return Markup.Color("y", name); + } + else + { + return Markup.Color(color, name); + } + } + + private static string FormatGender(Gender g) + { + string name = FormatName(g.Name); + string summary = Markup.Color("c", g.GetBasicSummary()); + + return $"{name}\n{summary}"; + } + + private static string FormatPronounSet(PronounSet p) + { + string name = FormatName(p.GetShortName()); + + string extra = ""; + + Gender g; + if (PronounGenderMapping.TryGetValue(p, out g)) + { + extra = Markup.Color("m", $" (from {FormatName(g.Name, "m")})"); + } + + string summary = Markup.Color("c", p.GetBasicSummary()); + + return $"{name}{extra}\n{summary}"; + } + + private static string FormatFromGenderPronounOption(Gender g1) + { + Gender g = g1 ?? Gender.Get("nonspecific"); + if (g == null) return FromGenderText; + + string gName = FormatName(g.Name, "m"); + + string extra = Markup.Color("m", $"({gName})"); + + string summary = Markup.Color("c", g.GetBasicSummary()); + + return $"{FromGenderText} {extra}\n{summary}"; + } + + public static async Task ChooseGenderAsync(Gender current) + { + var availableGenders = Gender.GetAllPersonal(); + var options = availableGenders.Select(gender=>FormatGender(gender)).ToList(); + options.Add(CreateNewText); + + var initial = availableGenders.IndexOf(current); + if (initial < 0) initial = 0; + + int n = await Popup.ShowOptionListAsync("Choose Gender", options.ToArray(), AllowEscape: true, DefaultSelected: initial); + + if (n <= -1) return null; + else if (n == options.Count - 1) + { + int b = await Popup.ShowOptionListAsync("Select Base Gender", availableGenders.Select(PronounSet => PronounSet.Name).ToArray(), AllowEscape: true, DefaultSelected: initial); + if( b > -1 ) + { + var baseGender = availableGenders[b]; + var newGender = new Gender(baseGender); + bool ok = await newGender.CustomizeAsync(); + if( ok ) return newGender; + } + } + else return availableGenders[n]; + + return null; + } + + public static async Task OnChooseGenderAsync(QudCustomizeCharacterModuleWindow window) + { + return await ChooseGenderAsync(window?.module?.data?.gender); + } + + public static void ChooseGender() + { + var newGender = ChooseGenderAsync(The.Player.GetGender()).Result; + + The.Player.SetGender(newGender.Register()); + } + + public static async Task ChoosePronounSetAsync(Gender currentGender, PronounSet currentPronounSet, PronounSet placeholder) + { + var availablePronounSets = PronounSet.GetAllPersonal(); + + var options = new List(); + options.Add(FormatFromGenderPronounOption(currentGender)); + options.AddRange( availablePronounSets.Select(pronounSet => FormatPronounSet(pronounSet))); + + options.Add(CreateNewText); + + var PSpos = availablePronounSets.IndexOf(currentPronounSet); + var initialPos = PSpos + 1; + var newPos = PSpos; + if (newPos < 0) newPos = 0; + + int n = await Popup.ShowOptionListAsync("Choose Pronoun Set", options.ToArray(), AllowEscape: true, DefaultSelected: initialPos); + + if( n > -1 ) + { + if( n == options.Count-1 ) + { + int b = await Popup.ShowOptionListAsync("Select Base Set", availablePronounSets.Select(PronounSet => PronounSet.Name).ToArray(), AllowEscape: true, DefaultSelected: newPos); + if( b > -1 ) + { + var basePronounSet = availablePronounSets[b]; + var newPronounSet = new PronounSet(basePronounSet); + bool ok = await newPronounSet.CustomizeAsync(); + if( ok ) return newPronounSet; + } + } + else + { + if( n == 0 ) return placeholder; + return availablePronounSets[n-1]; + } + } + + return null; + } + + public static async Task OnChoosePronounSetAsync(QudCustomizeCharacterModuleWindow window, PronounSet fromGenderPlaceholder) + { + var data = window?.module?.data; + return await ChoosePronounSetAsync(data?.gender, data?.pronounSet, fromGenderPlaceholder); + } + + public static void ChoosePronounSet() + { + var sentinel = new PronounSet(); + var newPronounSet = ChoosePronounSetAsync(The.Player.GetGender(), The.Player.GetPronounSet(), sentinel).Result; + if (newPronounSet == sentinel) + { + var n = new PronounSet(The.Player.GetGender()); + The.Player.SetPronounSet(n); + } + else if (newPronounSet != null) + { + The.Player.SetPronounSet(newPronounSet.Register()); + } + } + } +} From 46cff4f1d4823360e7275b13940d5570ff75ab3e Mon Sep 17 00:00:00 2001 From: librarianmage Date: Tue, 15 Aug 2023 12:21:52 +0000 Subject: [PATCH 09/10] Refactor code FossilOrigin-Name: 2a555e9d5bc38aea312f4d13d216837eefe02fe0346b82d128e3844b117697b1 --- Egg.cs | 23 --------- NamePronoun.cs | 104 ++++++++++++++++++++--------------------- SelectorPatches.cs | 5 +- Selectors.cs | 113 ++++++++++++++++++++++++++------------------- Wishes.cs | 32 +++++++++++++ 5 files changed, 152 insertions(+), 125 deletions(-) delete mode 100644 Egg.cs create mode 100644 Wishes.cs diff --git a/Egg.cs b/Egg.cs deleted file mode 100644 index b0124f2..0000000 --- a/Egg.cs +++ /dev/null @@ -1,23 +0,0 @@ -using XRL.UI; -using XRL.Wish; - -namespace QudGendersUnleashed.Wishes -{ - /// Useless wish used to generate the header image. - [HasWishCommand] - public class GenderUploadForm - { - [WishCommand(Command = "gendermeme")] - static public bool GenderMeme() - { - string[] opts = { - "Male", - "Female", - "Custom [Upload custom gender (max 10MB)]" - }; - - Popup.ShowOptionList("Gender", opts); - return true; - } - } -} diff --git a/NamePronoun.cs b/NamePronoun.cs index cbf5598..efc03f8 100644 --- a/NamePronoun.cs +++ b/NamePronoun.cs @@ -12,10 +12,8 @@ namespace QudGendersUnleashed.NamePronoun [HarmonyPatch(nameof(GameObject.GetPronounProvider))] public static class NameOnlyPronounPatch { - static IPronounProvider Postfix(IPronounProvider PronounSet, GameObject __instance) - { - return NamePronounWrapper.Wrap(PronounSet, __instance); - } + static IPronounProvider Postfix(IPronounProvider pronouns, GameObject __instance) + => NamePronounWrapper.Wrap(pronouns, __instance); } /// @@ -26,73 +24,73 @@ public class NamePronounWrapper : IPronounProvider private IPronounProvider BasePronouns; private GameObject Referent; - private static bool CouldHaveName(string S) => S.Contains("=name"); - - public static bool CouldBeNamePronouns(IPronounProvider Pronouns) => - CouldHaveName(Pronouns.Name) - || CouldHaveName(Pronouns.CapitalizedName) - || CouldHaveName(Pronouns.Subjective) - || CouldHaveName(Pronouns.CapitalizedSubjective) - || CouldHaveName(Pronouns.Objective) - || CouldHaveName(Pronouns.CapitalizedObjective) - || CouldHaveName(Pronouns.PossessiveAdjective) - || CouldHaveName(Pronouns.CapitalizedPossessiveAdjective) - || CouldHaveName(Pronouns.SubstantivePossessive) - || CouldHaveName(Pronouns.CapitalizedSubstantivePossessive) - || CouldHaveName(Pronouns.Reflexive) - || CouldHaveName(Pronouns.CapitalizedReflexive) - || CouldHaveName(Pronouns.PersonTerm) - || CouldHaveName(Pronouns.CapitalizedPersonTerm) - || CouldHaveName(Pronouns.ImmaturePersonTerm) - || CouldHaveName(Pronouns.CapitalizedImmaturePersonTerm) - || CouldHaveName(Pronouns.FormalAddressTerm) - || CouldHaveName(Pronouns.CapitalizedFormalAddressTerm) - || CouldHaveName(Pronouns.OffspringTerm) - || CouldHaveName(Pronouns.CapitalizedOffspringTerm) - || CouldHaveName(Pronouns.SiblingTerm) - || CouldHaveName(Pronouns.CapitalizedSiblingTerm) - || CouldHaveName(Pronouns.ParentTerm) - || CouldHaveName(Pronouns.CapitalizedParentTerm) - || CouldHaveName(Pronouns.IndicativeProximal) - || CouldHaveName(Pronouns.CapitalizedIndicativeProximal) - || CouldHaveName(Pronouns.IndicativeDistal) - || CouldHaveName(Pronouns.CapitalizedIndicativeDistal); - - public static IPronounProvider Wrap(IPronounProvider BasePronouns, GameObject Referent) + private static bool CouldHaveName(string s) => s.Contains("=name"); + + public static bool CouldBeNamePronouns(IPronounProvider pronouns) => + CouldHaveName(pronouns.Name) + || CouldHaveName(pronouns.CapitalizedName) + || CouldHaveName(pronouns.Subjective) + || CouldHaveName(pronouns.CapitalizedSubjective) + || CouldHaveName(pronouns.Objective) + || CouldHaveName(pronouns.CapitalizedObjective) + || CouldHaveName(pronouns.PossessiveAdjective) + || CouldHaveName(pronouns.CapitalizedPossessiveAdjective) + || CouldHaveName(pronouns.SubstantivePossessive) + || CouldHaveName(pronouns.CapitalizedSubstantivePossessive) + || CouldHaveName(pronouns.Reflexive) + || CouldHaveName(pronouns.CapitalizedReflexive) + || CouldHaveName(pronouns.PersonTerm) + || CouldHaveName(pronouns.CapitalizedPersonTerm) + || CouldHaveName(pronouns.ImmaturePersonTerm) + || CouldHaveName(pronouns.CapitalizedImmaturePersonTerm) + || CouldHaveName(pronouns.FormalAddressTerm) + || CouldHaveName(pronouns.CapitalizedFormalAddressTerm) + || CouldHaveName(pronouns.OffspringTerm) + || CouldHaveName(pronouns.CapitalizedOffspringTerm) + || CouldHaveName(pronouns.SiblingTerm) + || CouldHaveName(pronouns.CapitalizedSiblingTerm) + || CouldHaveName(pronouns.ParentTerm) + || CouldHaveName(pronouns.CapitalizedParentTerm) + || CouldHaveName(pronouns.IndicativeProximal) + || CouldHaveName(pronouns.CapitalizedIndicativeProximal) + || CouldHaveName(pronouns.IndicativeDistal) + || CouldHaveName(pronouns.CapitalizedIndicativeDistal); + + public static IPronounProvider Wrap(IPronounProvider basePronouns, GameObject referent) { - if (BasePronouns is NamePronounWrapper p && p.Referent != Referent) + if (basePronouns is NamePronounWrapper p && p.Referent != referent) { - p.Referent = Referent; + p.Referent = referent; } - else if (CouldBeNamePronouns(BasePronouns)) + else if (CouldBeNamePronouns(basePronouns)) { - return new NamePronounWrapper(BasePronouns, Referent); + return new NamePronounWrapper(basePronouns, referent); } - return BasePronouns; + return basePronouns; } - public NamePronounWrapper(IPronounProvider BasePronouns, GameObject Referrant) + public NamePronounWrapper(IPronounProvider basePronouns, GameObject referent) { - this.BasePronouns = BasePronouns; - this.Referent = Referrant; + this.BasePronouns = basePronouns; + this.Referent = referent; } - public string ReplaceWithName(string Pronoun, bool capitalize = false) + public string ReplaceWithName(string pronoun, bool capitalize = false) { - if (Pronoun.Contains("=name")) + if (pronoun.Contains("=name")) { - string DisplayName = Referent.BaseDisplayNameStripped; + string displayName = Referent.BaseDisplayNameStripped; if (capitalize) { - DisplayName = ColorUtility.CapitalizeExceptFormatting(DisplayName); + displayName = ColorUtility.CapitalizeExceptFormatting(displayName); } - string DisplayNamePosessive = Grammar.MakePossessive(DisplayName); - return Pronoun.Replace("=name=", DisplayName) - .Replace("=name's=", DisplayNamePosessive); + string displayNamePossessive = Grammar.MakePossessive(displayName); + return pronoun.Replace("=name=", displayName) + .Replace("=name's=", displayNamePossessive); } else { - return Pronoun; + return pronoun; } } diff --git a/SelectorPatches.cs b/SelectorPatches.cs index c6ce9f8..98fa293 100644 --- a/SelectorPatches.cs +++ b/SelectorPatches.cs @@ -4,8 +4,9 @@ using XRL.CharacterBuilds.Qud.UI; using System.Threading.Tasks; -namespace QudGendersUnleashed.Selectors.Patches +namespace QudGendersUnleashed.Patches { + /// Patch the gender selector during character creation. [HarmonyPatch(typeof(QudCustomizeCharacterModuleWindow))] [HarmonyPatch(nameof(QudCustomizeCharacterModuleWindow.OnChooseGenderAsync))] public static class GenderPatch @@ -15,6 +16,7 @@ public static class GenderPatch static Task Postfix(Task _, QudCustomizeCharacterModuleWindow __instance) => Selectors.OnChooseGenderAsync(__instance); } + /// Patch the pronoun set selector during character creation. [HarmonyPatch(typeof(QudCustomizeCharacterModuleWindow))] [HarmonyPatch(nameof(QudCustomizeCharacterModuleWindow.OnChoosePronounSetAsync))] public static class PronounPatch @@ -25,6 +27,7 @@ static Task Postfix(Task _, PronounSet ___fromGenderPlac => Selectors.OnChoosePronounSetAsync(__instance, ___fromGenderPlaceholder); } + /// Patch the pronoun set selector from the character sheet. [HarmonyPatch(typeof(PronounAndGenderSets))] [HarmonyPatch(nameof(PronounAndGenderSets.ShowChangePronounSet))] public static class PlaytimePronounPatch diff --git a/Selectors.cs b/Selectors.cs index ab65550..ea51751 100644 --- a/Selectors.cs +++ b/Selectors.cs @@ -7,8 +7,11 @@ using XRL.UI; using XRL.World; -namespace QudGendersUnleashed.Selectors +// TODO: refactor + +namespace QudGendersUnleashed { + /// Selectors for gender and pronoun sets. [HasModSensitiveStaticCache] public static class Selectors { @@ -28,8 +31,8 @@ public static Dictionary PronounGenderMapping { foreach (Gender g in suspects) { var setName = new PronounSet(g).Name; - var pronounSet = PronounSet.GetIfExists(setName); - if (pronounSet != null) _PronounGenderMapping.Add(pronounSet, g); + var set = PronounSet.GetIfExists(setName); + if (set != null) _PronounGenderMapping.Add(set, g); } } @@ -98,75 +101,89 @@ public static async Task ChooseGenderAsync(Gender current) var initial = availableGenders.IndexOf(current); if (initial < 0) initial = 0; - int n = await Popup.ShowOptionListAsync("Choose Gender", options.ToArray(), AllowEscape: true, DefaultSelected: initial); - - if (n <= -1) return null; - else if (n == options.Count - 1) + int index = await Popup.ShowOptionListAsync( + Title: "Choose Gender", + Options: options.ToArray(), + AllowEscape: true, + DefaultSelected: initial + ); + + if (index <= -1) + return null; + else if (0 <= index && index < options.Count - 1) + return availableGenders[index]; + else { - int b = await Popup.ShowOptionListAsync("Select Base Gender", availableGenders.Select(PronounSet => PronounSet.Name).ToArray(), AllowEscape: true, DefaultSelected: initial); - if( b > -1 ) - { - var baseGender = availableGenders[b]; - var newGender = new Gender(baseGender); - bool ok = await newGender.CustomizeAsync(); - if( ok ) return newGender; - } - } - else return availableGenders[n]; + int baseIndex = await Popup.ShowOptionListAsync( + Title: "Select Base Gender", + Options: availableGenders.Select(gender => gender.Name).ToArray(), + AllowEscape: true, + DefaultSelected: initial + ); + + if (baseIndex <= -1) return null; + + var baseGender = availableGenders[baseIndex]; + var newGender = new Gender(baseGender); - return null; + if(await newGender.CustomizeAsync()) + return newGender; + else + return null; + } } public static async Task OnChooseGenderAsync(QudCustomizeCharacterModuleWindow window) - { - return await ChooseGenderAsync(window?.module?.data?.gender); - } + => await ChooseGenderAsync(window?.module?.data?.gender); public static void ChooseGender() { var newGender = ChooseGenderAsync(The.Player.GetGender()).Result; - The.Player.SetGender(newGender.Register()); } public static async Task ChoosePronounSetAsync(Gender currentGender, PronounSet currentPronounSet, PronounSet placeholder) { var availablePronounSets = PronounSet.GetAllPersonal(); - var options = new List(); options.Add(FormatFromGenderPronounOption(currentGender)); - options.AddRange( availablePronounSets.Select(pronounSet => FormatPronounSet(pronounSet))); - + options.AddRange(availablePronounSets.Select(pronounSet => FormatPronounSet(pronounSet))); options.Add(CreateNewText); - var PSpos = availablePronounSets.IndexOf(currentPronounSet); - var initialPos = PSpos + 1; - var newPos = PSpos; - if (newPos < 0) newPos = 0; + int initialPos, newPos; + if (currentPronounSet == null) + { + initialPos = 0; + newPos = 0; + } + else + { + int setIndex = availablePronounSets.IndexOf(currentPronounSet); + + initialPos = setIndex + 1; + newPos = setIndex; + if (newPos < 0) newPos = 0; + } int n = await Popup.ShowOptionListAsync("Choose Pronoun Set", options.ToArray(), AllowEscape: true, DefaultSelected: initialPos); - if( n > -1 ) + if (n <= -1) + return null; + else if (n == 0) + return placeholder; + else if (1 <= n && n < options.Count - 1) + return availablePronounSets[n]; + else { - if( n == options.Count-1 ) - { - int b = await Popup.ShowOptionListAsync("Select Base Set", availablePronounSets.Select(PronounSet => PronounSet.Name).ToArray(), AllowEscape: true, DefaultSelected: newPos); - if( b > -1 ) - { - var basePronounSet = availablePronounSets[b]; - var newPronounSet = new PronounSet(basePronounSet); - bool ok = await newPronounSet.CustomizeAsync(); - if( ok ) return newPronounSet; - } - } - else - { - if( n == 0 ) return placeholder; - return availablePronounSets[n-1]; - } - } + int b = await Popup.ShowOptionListAsync("Select Base Set", availablePronounSets.Select(PronounSet => PronounSet.Name).ToArray(), AllowEscape: true, DefaultSelected: newPos); + if (b <= -1) return null; - return null; + var basePronounSet = availablePronounSets[b]; + var newPronounSet = new PronounSet(basePronounSet); + + if( await newPronounSet.CustomizeAsync() ) return newPronounSet; + else return null; + } } public static async Task OnChoosePronounSetAsync(QudCustomizeCharacterModuleWindow window, PronounSet fromGenderPlaceholder) diff --git a/Wishes.cs b/Wishes.cs new file mode 100644 index 0000000..731d1b1 --- /dev/null +++ b/Wishes.cs @@ -0,0 +1,32 @@ +using XRL.UI; +using XRL.Wish; + +namespace QudGendersUnleashed +{ + /// Various wishes of varying utility. + [HasWishCommand] + public static class Wishes + { + /// Changes the user's gender. + /// Will not change the user's pronouns. + [WishCommand(Command = "changegender")] + static public void ChangeGender() => Selectors.ChooseGender(); + + /// Changes the user's pronouns. + [WishCommand(Command = "changepronouns")] + static public void ChangePronounSet() => Selectors.ChoosePronounSet(); + + /// Useless wish used to generate the header image. + [WishCommand(Command = "gendermeme")] + static public void GenderUploadForm() + { + string[] opts = { + "Male", + "Female", + "Custom [Upload custom gender (max 10MB)]" + }; + + Popup.ShowOptionList("Gender", opts); + } + } +} From 927059cde4c2a4e3ac092182a10efe7be1bf932c Mon Sep 17 00:00:00 2001 From: librarianmage Date: Tue, 15 Aug 2023 12:31:51 +0000 Subject: [PATCH 10/10] Update metadata FossilOrigin-Name: 3df66962ee57fcd521e551ee82294ed9150e101162d3cf9260c870ac021c92f7 --- README.md | 6 ++++-- workshop.json | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 33d026f..9133be1 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,15 @@ A mod that works in conjunction with the [Gender and Pronoun Sets](https://steam Specifically, this mod allows you to pick from all personal genders and pronouns defined in game (including pseudo-plural ones), with a number of additions. -Additionally, the "choose pronoun" prompt in game has been modified to use the modern UI. This will facilitate picking from the extended list this mod provides. +Additionally, all gender and pronoun prompts have been redesigned with inspirations from kernelmethod's [Better Pet Selector](https://steamcommunity.com/sharedfiles/filedetails/?id=3006503292) mod. Tested to work on game versions 204.100 / 205.54 (beta). [Source Code (GitHub)](https://github.com/librarianmage/QudGendersUnleashed) \| [Workshop Page](https://steamcommunity.com/sharedfiles/filedetails/?id=2815078000) \| [My Caves of Qud Mods (Steam Workshop)](https://steamcommunity.com/profiles/76561198836298826/myworkshopfiles/?appid=333640) -Also check out the [Pride Naming Colors](https://steamcommunity.com/sharedfiles/filedetails/?id=2951409991) Workshop mod by Steam user Flaborized! +## Wishes + +The wishes `changegender` and `changepronouns` have been added for quick access while playing. ## `=name=` Pronoun Sets diff --git a/workshop.json b/workshop.json index ba6025c..847418d 100644 --- a/workshop.json +++ b/workshop.json @@ -1,7 +1,7 @@ { "WorkshopId": 2815078000, "Title": "Qud: Genders Unleashed", - "Description": "A mod that works in conjunction with the [url=https://steamcommunity.com/sharedfiles/filedetails/?id=1735379738]Gender and Pronoun Sets[/url] mod to to provide a plethora of genders and pronouns for your game character.\n\nSpecifically, this mod allows you to pick from all personal genders and pronouns defined in game (including pseudo-plural ones), with a number of additions.\n\nAdditionally, the \"choose pronoun\" prompt in game has been modified to use the modern UI. This will facilitate picking from the extended list this mod provides.\n\nTested to work on game versions 204.100 / 205.54 (beta).\n\n[url=https://github.com/librarianmage/QudGendersUnleashed]Source Code (GitHub)[/url]\n\nAlso check out the [url=https://steamcommunity.com/sharedfiles/filedetails/?id=2951409991]Pride Naming Colors[/url] Workshop mod by Steam user Flaborized!\n\n[h1]`=name=` Pronoun Sets[/h1]Starting with version 1.1, `=name=` in a pronoun set will be dynamically replaced with the player character's name (`=name's=` with the possessive version). To demonstrate this, a pronoun set consisting completely of `=name=` and `=name's=` has been added.", + "Description": "A mod that works in conjunction with the [url=https://steamcommunity.com/sharedfiles/filedetails/?id=1735379738]Gender and Pronoun Sets[/url] mod to to provide a plethora of genders and pronouns for your game character.\n\nSpecifically, this mod allows you to pick from all personal genders and pronouns defined in game (including pseudo-plural ones), with a number of additions.\n\nAdditionally, all gender and pronoun prompts have been redesigned with inspirations from kernelmethod's [url=https://steamcommunity.com/sharedfiles/filedetails/?id=3006503292]Better Pet Selector[/url] mod.\n\nTested to work on game versions 204.100 / 205.54 (beta).\n\n[url=https://github.com/librarianmage/QudGendersUnleashed]Source Code (GitHub)[/url]\n\n[h1]Wishes[/h1]The wishes `changegender` and `changepronouns` have been added for quick access while playing.[h1]`=name=` Pronoun Sets[/h1]Starting with version 1.1, `=name=` in a pronoun set will be dynamically replaced with the player character's name (`=name's=` with the possessive version). To demonstrate this, a pronoun set consisting completely of `=name=` and `=name's=` has been added.", "Tags": "Stable,Beta,Script,Gender,Pronouns", "Visibility": "2", "ImagePath": "Assets/icon.png"