From d3d2f6c8aa82d3c5f52285b1c739e9f70163997a Mon Sep 17 00:00:00 2001 From: LoafyLemon Date: Tue, 11 Apr 2023 20:36:22 +0100 Subject: [PATCH] Modding support * Resolved CHARACTERS constant to allow adding custom characters without having to rely on monkey patching. --- game/scripts/characters.rpy | 2 +- game/scripts/constants.rpy | 2 - game/scripts/doll/init.rpy | 2 +- game/scripts/doll/main.rpy | 8 +++- game/scripts/gui/say.rpy | 2 +- game/scripts/interface/cheats.rpy | 4 +- game/scripts/inventory/gifts.rpy | 44 +++++++++---------- .../rooms/main_room/objects/poster.rpy | 2 +- game/scripts/script.rpy | 2 +- game/scripts/utility/editor.rpy | 7 +-- game/scripts/utility/lint.rpy | 4 +- game/scripts/wardrobe/functions.rpy | 30 ++++++------- game/scripts/wardrobe/studio.rpy | 7 ++- 13 files changed, 60 insertions(+), 56 deletions(-) diff --git a/game/scripts/characters.rpy b/game/scripts/characters.rpy index 416d605c..f495b3f7 100644 --- a/game/scripts/characters.rpy +++ b/game/scripts/characters.rpy @@ -10,7 +10,7 @@ init -999 python: def narrator_fade(ev, interact=True, **kwargs): if ev == "begin": - behind = [f"{i}_main" for i in CHARACTERS] + ["snape_main", "genie_main", "cg"] + behind = [f"{i}_main" for i in states.dolls] + ["snape_main", "genie_main", "cg"] renpy.show("fade", zorder=15, behind=behind) elif ev == "end": renpy.hide("fade") diff --git a/game/scripts/constants.rpy b/game/scripts/constants.rpy index 63dd59fc..f85a3275 100644 --- a/game/scripts/constants.rpy +++ b/game/scripts/constants.rpy @@ -1,4 +1,2 @@ -define CHARACTERS = {"hermione", "tonks", "astoria", "cho", "luna", "susan", "hooch"} -define SAYERS = {i[:3]:i for i in CHARACTERS} define ALLOWED_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz " diff --git a/game/scripts/doll/init.rpy b/game/scripts/doll/init.rpy index 0045a337..9b0b40a3 100644 --- a/game/scripts/doll/init.rpy +++ b/game/scripts/doll/init.rpy @@ -2,7 +2,7 @@ init offset = 2 init python: def wardrobe_init(): - for c in CHARACTERS: + for c in states.dolls: char = get_character_object(c) body_default = get_character_body(c, type="default") diff --git a/game/scripts/doll/main.rpy b/game/scripts/doll/main.rpy index 369f110a..8512f483 100644 --- a/game/scripts/doll/main.rpy +++ b/game/scripts/doll/main.rpy @@ -62,7 +62,7 @@ init python: self.zorder = 15 self.layer = "screens" self.animation = None - self.tag = get_character_tag(name) + self.tag = f"{name}_main" # Transform properties self.pos = (0, 0) @@ -72,6 +72,12 @@ init python: self.modpath = "mods/" + posixpath.normpath(modpath) if modpath else "" + # Add doll name to global doll states store + try: + renpy.store.states.dolls.add(name) + except AttributeError: + renpy.store.states.dolls = {name} + def generate_hash(self): clothes_hash = str([x[0]._hash for x in self.states.values() if istype(x[0], (DollCloth, DollClothDynamic, DollMakeup)) and x[2]]) salt = str( [self.name, self.pose, str(self.body._hash), str(self.face._hash), str(self.cum._hash), clothes_hash] ) diff --git a/game/scripts/gui/say.rpy b/game/scripts/gui/say.rpy index 86ddaf8a..e4ad46bd 100644 --- a/game/scripts/gui/say.rpy +++ b/game/scripts/gui/say.rpy @@ -130,7 +130,7 @@ screen choice(items): style_prefix gui.theme("menu") default blacklist_screens = {"say", "letter", "bld1"} # Combine sets - default blacklist_tags = set(get_character_tag(x) for x in CHARACTERS) + default blacklist_tags = set(get_character_tag(x) for x in states.dolls) # Dont add the fade if character or saybox is present (They have their own triggers for fading) if not any(renpy.get_screen(x) for x in blacklist_screens) and not any(renpy.showing(x, layer="screens") for x in blacklist_tags): diff --git a/game/scripts/interface/cheats.rpy b/game/scripts/interface/cheats.rpy index 246cfe0f..a0c2a1e8 100644 --- a/game/scripts/interface/cheats.rpy +++ b/game/scripts/interface/cheats.rpy @@ -70,7 +70,7 @@ label cheats: jump cheats.general python: - for i in CHARACTERS: + for i in states.dolls: for x in getattr(renpy.store, i).outfits: if not x.hidden: x.unlock() @@ -326,7 +326,7 @@ label cheats: "-Unequip all clothes-": python: - for i in CHARACTERS: + for i in states.dolls: getattr(renpy.store, i).unequip("clothes") nar "All characters are now naked." diff --git a/game/scripts/inventory/gifts.rpy b/game/scripts/inventory/gifts.rpy index 6d6e354a..a40948bd 100644 --- a/game/scripts/inventory/gifts.rpy +++ b/game/scripts/inventory/gifts.rpy @@ -1,24 +1,24 @@ -default lollipop_ITEM = Item("lollipop", "gift", "Lollipop Candy", 20, "A lollipop candy. An adult candy for kids or kids candy for adults?", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default chocolate_ITEM = Item("chocolate", "gift", "Chocolate", 40, "The recipe for this delicious milk chocolate is kept a secret. (Rumoured to contain dried faeries).", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default plush_owl_ITEM = Item("plush_owl", "gift", "Plush owl", 35, "A Toy owl stuffed with feathers of an actual owl. It's so cuddly!", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default butterbeer_ITEM = Item("butterbeer", "gift", "Butterbeer", 50, "Girls can't resist this beverage's buttery texture. Therefore it's always in high demand among the boys.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default science_mag_ITEM = Item("science_mag", "gift", "Educational Magazines", 30, "Educational magazines.\nthe Trusty companions of every social outcast.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default girls_mag_ITEM = Item("girls_mag", "gift", "Girly Magazines", 45, "Girly magazines.\nAll cool girls are reading these.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default adult_mag_ITEM = Item("adult_mag", "gift", "Adult magazines", 60, "Your boyfriend is turning into a nice guy?\nYour husband won't abuse you anymore?\nAll you wanted to know about relationships, love and sex. Mostly about sex.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default porn_mag_ITEM = Item("porn_mag", "gift", "Porn magazines", 80, "Give these to your girlfriend to test her, to your wife to shame her and to your daughter to avoid \"the talk\".", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default krum_poster_ITEM = Item("krum_poster", "gift", "Viktor Krum Poster", 25, "A skilled Quidditch Seeker, Viktor has been selected to play for the Bulgarian National Quidditch team despite still going to school, and is widely regarded as one of the best players in the world.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default sexy_lingerie_ITEM = Item("sexy_lingerie", "gift", "Sexy Lingerie", 75, "Sexy lingerie \"Fairy Godmother\". Charm your wizard in bed or empress your sisters at a Sabbath.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default sexy_stockings_ITEM = Item("sexy_stockings", "gift", "Sexy Stockings", 50, "Somewhere between now and the dark-ages came the invention of stockings, when you want to show some skin but not too much.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default pink_condoms_ITEM = Item("condoms", "gift", "A Pack Of Condoms", 50, "Unleash the one-horned beast!\n{size=-4}May contain traces of actual unicorn saliva.{/size}", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default vibrator_ITEM = Item("vibrator", "gift", "Vibrator", 55, "A magnificent, magically enhanced vibrator made of vine wood, with a dragon heartstring core.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default anal_lube_ITEM = Item("lube", "gift", "Jar of lubricant", 60, "A Jar full of lube, Buy this for your loved one - show that you care.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default ballgag_and_cuffs_ITEM = Item("ballgag_and_cuffs", "gift", "Ball gag and cuffs", 70, "Ball gag and cuffs, Turn your soulmate into your cellmate.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default anal_plugs_ITEM = Item("buttplugs", "gift", "Anal plugs", 85, "Anal plugs decorated with actual tails. Sizes vary to satisfy expert practitioners and beginner alike.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default testral_strapon_ITEM = Item("strapon", "gift", "Thestral Strap-on", 200, "Thestral strap-on.\nWhen you see it, you'll shit bricks.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default broom_2000_ITEM = Item("broom", "gift", "Lady Speed Stick-2000", 500, "{size=-2}The \"Lady Speed Stick-2000\", an elegant way of transportation for passionate witches. The trademarked saddle guarantees full satisfaction. Get one for your witch and she won't use her boring old broom ever again!{/size}", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default sexdoll_ITEM = Item("sexdoll", "gift", "Sex doll \"Joanne\"", 350, "It's so realistic. Almost looks like a real human under the influence of a spell of some sort.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default anal_beads_ITEM = Item("beads", "gift", "Anal beads", 65, "Anal beads engraved with a strange inscription \"Property of L.C.\".", givable=True, caption="Give", usable_on=list(CHARACTERS)) +default lollipop_ITEM = Item("lollipop", "gift", "Lollipop Candy", 20, "A lollipop candy. An adult candy for kids or kids candy for adults?", givable=True, caption="Give", usable_on=list(states.dolls)) +default chocolate_ITEM = Item("chocolate", "gift", "Chocolate", 40, "The recipe for this delicious milk chocolate is kept a secret. (Rumoured to contain dried faeries).", givable=True, caption="Give", usable_on=list(states.dolls)) +default plush_owl_ITEM = Item("plush_owl", "gift", "Plush owl", 35, "A Toy owl stuffed with feathers of an actual owl. It's so cuddly!", givable=True, caption="Give", usable_on=list(states.dolls)) +default butterbeer_ITEM = Item("butterbeer", "gift", "Butterbeer", 50, "Girls can't resist this beverage's buttery texture. Therefore it's always in high demand among the boys.", givable=True, caption="Give", usable_on=list(states.dolls)) +default science_mag_ITEM = Item("science_mag", "gift", "Educational Magazines", 30, "Educational magazines.\nthe Trusty companions of every social outcast.", givable=True, caption="Give", usable_on=list(states.dolls)) +default girls_mag_ITEM = Item("girls_mag", "gift", "Girly Magazines", 45, "Girly magazines.\nAll cool girls are reading these.", givable=True, caption="Give", usable_on=list(states.dolls)) +default adult_mag_ITEM = Item("adult_mag", "gift", "Adult magazines", 60, "Your boyfriend is turning into a nice guy?\nYour husband won't abuse you anymore?\nAll you wanted to know about relationships, love and sex. Mostly about sex.", givable=True, caption="Give", usable_on=list(states.dolls)) +default porn_mag_ITEM = Item("porn_mag", "gift", "Porn magazines", 80, "Give these to your girlfriend to test her, to your wife to shame her and to your daughter to avoid \"the talk\".", givable=True, caption="Give", usable_on=list(states.dolls)) +default krum_poster_ITEM = Item("krum_poster", "gift", "Viktor Krum Poster", 25, "A skilled Quidditch Seeker, Viktor has been selected to play for the Bulgarian National Quidditch team despite still going to school, and is widely regarded as one of the best players in the world.", givable=True, caption="Give", usable_on=list(states.dolls)) +default sexy_lingerie_ITEM = Item("sexy_lingerie", "gift", "Sexy Lingerie", 75, "Sexy lingerie \"Fairy Godmother\". Charm your wizard in bed or empress your sisters at a Sabbath.", givable=True, caption="Give", usable_on=list(states.dolls)) +default sexy_stockings_ITEM = Item("sexy_stockings", "gift", "Sexy Stockings", 50, "Somewhere between now and the dark-ages came the invention of stockings, when you want to show some skin but not too much.", givable=True, caption="Give", usable_on=list(states.dolls)) +default pink_condoms_ITEM = Item("condoms", "gift", "A Pack Of Condoms", 50, "Unleash the one-horned beast!\n{size=-4}May contain traces of actual unicorn saliva.{/size}", givable=True, caption="Give", usable_on=list(states.dolls)) +default vibrator_ITEM = Item("vibrator", "gift", "Vibrator", 55, "A magnificent, magically enhanced vibrator made of vine wood, with a dragon heartstring core.", givable=True, caption="Give", usable_on=list(states.dolls)) +default anal_lube_ITEM = Item("lube", "gift", "Jar of lubricant", 60, "A Jar full of lube, Buy this for your loved one - show that you care.", givable=True, caption="Give", usable_on=list(states.dolls)) +default ballgag_and_cuffs_ITEM = Item("ballgag_and_cuffs", "gift", "Ball gag and cuffs", 70, "Ball gag and cuffs, Turn your soulmate into your cellmate.", givable=True, caption="Give", usable_on=list(states.dolls)) +default anal_plugs_ITEM = Item("buttplugs", "gift", "Anal plugs", 85, "Anal plugs decorated with actual tails. Sizes vary to satisfy expert practitioners and beginner alike.", givable=True, caption="Give", usable_on=list(states.dolls)) +default testral_strapon_ITEM = Item("strapon", "gift", "Thestral Strap-on", 200, "Thestral strap-on.\nWhen you see it, you'll shit bricks.", givable=True, caption="Give", usable_on=list(states.dolls)) +default broom_2000_ITEM = Item("broom", "gift", "Lady Speed Stick-2000", 500, "{size=-2}The \"Lady Speed Stick-2000\", an elegant way of transportation for passionate witches. The trademarked saddle guarantees full satisfaction. Get one for your witch and she won't use her boring old broom ever again!{/size}", givable=True, caption="Give", usable_on=list(states.dolls)) +default sexdoll_ITEM = Item("sexdoll", "gift", "Sex doll \"Joanne\"", 350, "It's so realistic. Almost looks like a real human under the influence of a spell of some sort.", givable=True, caption="Give", usable_on=list(states.dolls)) +default anal_beads_ITEM = Item("beads", "gift", "Anal beads", 65, "Anal beads engraved with a strange inscription \"Property of L.C.\".", givable=True, caption="Give", usable_on=list(states.dolls)) -default wine_ITEM = Item("wine", "gift", "Wine", 60, "For the more refined palate.", givable=True, caption="Give", usable_on=list(CHARACTERS)) -default firewhisky_ITEM = Item("firewhisky", "gift", "Firewhisky", 80, "Great taste with a fiery burn.", givable=True, caption="Give", unlocked=False, usable_on=list(CHARACTERS)) +default wine_ITEM = Item("wine", "gift", "Wine", 60, "For the more refined palate.", givable=True, caption="Give", usable_on=list(states.dolls)) +default firewhisky_ITEM = Item("firewhisky", "gift", "Firewhisky", 80, "Great taste with a fiery burn.", givable=True, caption="Give", unlocked=False, usable_on=list(states.dolls)) diff --git a/game/scripts/rooms/main_room/objects/poster.rpy b/game/scripts/rooms/main_room/objects/poster.rpy index 84095488..c8ffe2fe 100644 --- a/game/scripts/rooms/main_room/objects/poster.rpy +++ b/game/scripts/rooms/main_room/objects/poster.rpy @@ -20,7 +20,7 @@ label naughty_list: # This code retrieves user name and displays it on a leaderboard-like # list for funsies, the variable is discarded afterwards. _username = None - _d = [(i, get_character_progression(i)) for i in CHARACTERS if get_character_unlock(i)] + _d = [(i, get_character_progression(i)) for i in states.dolls if get_character_unlock(i)] _d.append(["Snape", states.sna.level]) try: diff --git a/game/scripts/script.rpy b/game/scripts/script.rpy index 557df84c..fe581935 100644 --- a/game/scripts/script.rpy +++ b/game/scripts/script.rpy @@ -78,7 +78,7 @@ label start_dev: for i in inventory.items: i.owned = i.limit - for i in CHARACTERS: + for i in states.dolls: for x in getattr(renpy.store, i).outfits: if not x.hidden: x.unlock() diff --git a/game/scripts/utility/editor.rpy b/game/scripts/utility/editor.rpy index a534eb37..e072d16a 100644 --- a/game/scripts/utility/editor.rpy +++ b/game/scripts/utility/editor.rpy @@ -14,6 +14,7 @@ init python: self.persistent_expressions = _dict() self.last_expressions = _dict() self.active = False + self.sayers = {i[:3]:i for i in states.dolls} def catch(self, *args, **kwargs): if not self.active or renpy.is_init_phase(): @@ -258,7 +259,7 @@ init python: all_files = renpy.list_files() d = _dict() - for charname in CHARACTERS: + for charname in states.dolls: charobj = get_character_object(charname) extensions = charobj.extensions @@ -306,7 +307,7 @@ init python: who = node.who args = node.arguments - if who in SAYERS: + if who in self.sayers: keywords = ["mouth", "eyes", "eyebrows", "pupils", "cheeks", "tears", "emote", "face", "xpos", "ypos", "pos", "flip", "trans", "animation", "hair"] else: @@ -465,7 +466,7 @@ screen editor(): action [CaptureFocus(expr_type), SetScreenVariable("focused", expr_type)] selected GetFocusRect(expr_type) - if e.node.who in SAYERS: + if e.node.who in e.sayers: textbutton "😊": action Function(e.toggle_expressions_persistent_type, e.node.who, "cheeks") selected (e.get_expressions_persistent_type(e.node.who, "cheeks")) diff --git a/game/scripts/utility/lint.rpy b/game/scripts/utility/lint.rpy index 7e8fe63e..b8908495 100644 --- a/game/scripts/utility/lint.rpy +++ b/game/scripts/utility/lint.rpy @@ -19,7 +19,7 @@ init -1 python: renpy.execute_default_statement(False) # Add images to linting list to avoid undefined errors - for i in CHARACTERS: + for i in states.dolls: prefix = "{}_main".format(i) renpy.lint.image_prefixes[prefix] = True @@ -34,7 +34,7 @@ init -1 python: OTHER = ["flip", "trans", "animation", "hair", "emote"] KEYS = EXPRESSIONS + POSITIONS + OTHER INTERPUNCT = (".", "!", "?", "--", "*", ")", "}") - + SAYERS = {i[:3]:i for i in states.dolls} RE_SPACES = re.compile(r"\s[^\S\r\n]") RE_COMMA = re.compile(r"\w+, \w+, \w+ and") RE_BRACKET = re.compile(r"\([^)]*$") diff --git a/game/scripts/wardrobe/functions.rpy b/game/scripts/wardrobe/functions.rpy index de6131e3..5fecad35 100644 --- a/game/scripts/wardrobe/functions.rpy +++ b/game/scripts/wardrobe/functions.rpy @@ -1,41 +1,41 @@ init -1 python: def get_character_progression(key): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return getattr(states, f"{key[:3]}").level def get_character_scheduling(key): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return getattr(states, f"{key[:3]}").wardrobe_scheduling def get_character_requirement(key, type): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return getattr(renpy.store, key[:3]+"_requirements").get(type, 0) def get_character_response(key, type): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return getattr(renpy.store, key[:3]+"_responses").get(type) def get_character_object(key): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return getattr(store, key) def get_character_outfit(key, type="default"): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return getattr(store, "{}_outfit_{}".format(key[:3], type)) def get_character_body(key, type="default"): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return getattr(store, "{}_body_{}".format(key[:3], type)) def get_character_outfit_req(key, item): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) if not isinstance(item, DollOutfit): @@ -53,37 +53,37 @@ init -1 python: print("\n".join(req)) def get_character_tag(key): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return "{}_main".format(key) def get_character_sayer(key): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return getattr(store, key[:3]) def get_character_gift_label(key): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return "give_{}_gift".format(key[:3]) def get_character_potion_check_label(key): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return "{}_potion_check".format(key[:3]) def get_character_potion_check(key): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return getattr(store, "{}_potion_check".format(key[:3])) def get_character_unlock(key): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return getattr(store, "{}_unlocked".format(key)) def get_character_mood(key): - if not key in CHARACTERS: + if not key in states.dolls: raise KeyError("'{}' character is undefined.".format(key)) return getattr(store, "{}_mood".format(key[:3])) diff --git a/game/scripts/wardrobe/studio.rpy b/game/scripts/wardrobe/studio.rpy index a7327b17..0cac3eba 100644 --- a/game/scripts/wardrobe/studio.rpy +++ b/game/scripts/wardrobe/studio.rpy @@ -12,14 +12,13 @@ init python in studio: Transform = renpy.store.Transform Flatten = renpy.store.Flatten Drag = renpy.store.Drag - CHARACTERS = renpy.store.CHARACTERS get_character_object = renpy.store.get_character_object @functools.cache def get_faces(): d = _dict() - for charname in CHARACTERS: + for charname in renpy.store.states.dolls: charobj = get_character_object(charname) extensions = charobj.extensions @@ -43,7 +42,7 @@ init python in studio: def get_choices(): d = {} - for i in CHARACTERS: + for i in renpy.store.states.dolls: d[i] = {} d[i]["eyebrows"] = faces[i].get("eyebrows", [None]).index("base") d[i]["eyes"] = faces[i].get("eyes", [None]).index("base") @@ -80,7 +79,7 @@ init python in studio: active_girl = renpy.store.states.active_girl d = {} - for i in CHARACTERS: + for i in renpy.store.states.dolls: d[i] = [drag_init(getattr(renpy.store, i)), (i == active_girl)] return d