init -1: define ladies_light_color = "#c7c0e2" define ladies_dark_color = "#917ecf" define ladies_insensitive_color = "#555555" define ALL_LADIES = {} default all_ladies = {} default persistent.all_ladies = {} init python: # Always show the "ladies" button in the top right corner config.overlay_screens.append("ladies_button") # Function used to translate text def trans(str, scope = None): return renpy.substitute(str, scope = scope) class UpdateStyle(Action): def __call__(self): style.rebuild() class LadyCore: def __init__(self, tag, name, age, height, weight, max_outfits=0): self.tag = tag self.name = name self.age = age self._height = height self._weight = weight self.max_outfits = max_outfits ALL_LADIES[self.tag] = self def known(self, origin): if origin == "ingame": if self.tag in all_ladies: return all_ladies[self.tag].known else: if self.tag in persistent.all_ladies: return persistent.all_ladies[self.tag]["known"] return False def max_outfit_unlocked(self, origin): if origin == "ingame": if self.tag in all_ladies: return max(all_ladies[self.tag].outfits) else: if self.tag in persistent.all_ladies: return max(persistent.all_ladies[self.tag]["outfits"]) return 1 def previous_outfit(self, origin, current_outfit): if origin == "ingame": otf = [ o for o in all_ladies[self.tag].outfits if o < current_outfit ] else: otf = [ o for o in persistent.all_ladies[self.tag]["outfits"] if o < current_outfit ] if otf: return max(otf) else: return current_outfit def next_outfit(self, origin, current_outfit): if origin == "ingame": otf = [ o for o in all_ladies[self.tag].outfits if o > current_outfit ] else: otf = [ o for o in persistent.all_ladies[self.tag]["outfits"] if o > current_outfit ] if otf: return min(otf) else: return current_outfit def job(self): if self.tag in all_ladies: return all_ladies[self.tag].job else: return "" @property def height(self): return trans(_("[lady_height_cm]{size=-10}cm{/size} [lady_height_foot]\""), scope={"lady_height_cm" : self._height[0], "lady_height_foot" : self._height[1]}) @property def weight(self): return trans(_("[lady_weight_kg]{size=-10}kg{/size} [lady_weight_lbs]{size=-10}lbs{/size}"), scope={"lady_weight_kg" : self._weight[0], "lady_weight_lbs" : self._weight[1]}) def get_stat(self, stat_tag, origin): if origin == "ingame": if stat_tag in all_ladies[self.tag].stats: return str(all_ladies[self.tag].stats[stat_tag]) else: if stat_tag in persistent.all_ladies[self.tag]["stats"]: return str(persistent.all_ladies[self.tag]["stats"][stat_tag]) return str(DEFAULT_STATS[stat_tag].default_value) def outfit_format(self): if self.max_outfits < 10: return "{}" elif self.max_outfits < 100: return "{:02d}" else: return "{:003d}" class Lady: def __init__(self, tag, job): # IS the MC already met this character? self.known = False self.tag = tag self.job = job # Max outfit unlocked (first outfit automatically unlocked) self.outfits = {1} self.stats = {} all_ladies[self.tag] = self # Method used to indicates that this lady was met def met(self): if not _in_replay: renpy.notify(renpy.substitute(_("New Character: [lady_name]"), scope={"lady_name" : ALL_LADIES[self.tag].name})) renpy.sound.play(audio.notification_unlock) self.known = True persistent.all_ladies[self.tag]["known"] = True # Method used to unlock an outfit def outfit(self, outfit_number): if not _in_replay: renpy.notify(renpy.substitute(_("[lady_name]: New Outfit"), scope={"lady_name" : ALL_LADIES[self.tag].name})) renpy.sound.play(audio.notification_unlock) self.outfits.add(outfit_number) persistent.all_ladies[self.tag]["outfits"].add(outfit_number) # Method used to increase or decrease a stat def stat(self, stat_tag, stat_value=1): if not _in_replay: if stat_tag not in STATS: renpy.error("(Lady.stat): Stat tag <{}> doesn't exist in STATS list.".format(stat_tag)) dft = DEFAULT_STATS[stat_tag] if dft.authorized_values is not None and stat_value not in dft.authorized_values: renpy.error("(Lady.stat): Value <{}> isn't authorized for the stat <{}>.".format(stat_value, stat_tag)) if stat_tag not in self.stats: # Initialize the stat if it's the first time it is updated self.stats[stat_tag] = dft.default_value if stat_tag not in persistent.all_ladies[self.tag]["stats"]: # Initialize the stat if it's the first time it is updated in persistent persistent.all_ladies[self.tag]["stats"][stat_tag] = dft.default_value if isinstance(stat_value, str): self.stats[stat_tag] = stat_value if persistent.all_ladies[self.tag]["stats"][stat_tag] != stat_value: persistent.all_ladies[self.tag]["stats"][stat_tag] = stat_value else: self.stats[stat_tag] += stat_value if persistent.all_ladies[self.tag]["stats"][stat_tag] < self.stats[stat_tag]: persistent.all_ladies[self.tag]["stats"][stat_tag] = self.stats[stat_tag] define ADRIANNA_CORE = LadyCore( tag="adrianna", name="[Mom]", age=39, height=(171, 5.6), weight=(60, 132), max_outfits=40 ) default adrianna = Lady( tag="adrianna", job=_("Model") ) init python: if "adrianna" not in persistent.all_ladies: persistent.all_ladies["adrianna"] = { "known" : False, "outfits" : {1}, "stats" : {} } define JENNA_CORE = LadyCore( tag="jenna", name="[Aunty]", age=34, height=(169, 5.5), weight=(57, 125), max_outfits=15 ) default jenna = Lady( tag="jenna", job=_("Secretary") ) init python: if "jenna" not in persistent.all_ladies: persistent.all_ladies["jenna"] = { "known" : False, "outfits" : {1}, "stats" : {} } define LINDA_CORE = LadyCore( tag="linda", name="[Linda]", age=43, height=(169, 5.5), weight=(68, 150), max_outfits=15 ) default linda = Lady( tag="linda", job=_("Housewife") ) init python: if "linda" not in persistent.all_ladies: persistent.all_ladies["linda"] = { "known" : False, "outfits" : {1}, "stats" : {} } define EMMA_CORE = LadyCore( tag="emma", name="[Emma]", age=38, height=(166, 5.4), weight=(53, 116), max_outfits=13 ) default emma = Lady( tag="emma", job=_("Receptionist") ) init python: if "emma" not in persistent.all_ladies: persistent.all_ladies["emma"] = { "known" : False, "outfits" : {1}, "stats" : {} } define MADISON_CORE = LadyCore( tag="madison", name="[Madison]", age=30, height=(167, 5.4), weight=(51, 112), max_outfits=7 ) default madison = Lady( tag="madison", job=_("Inspector") ) init python: if "madison" not in persistent.all_ladies: persistent.all_ladies["madison"] = { "known" : False, "outfits" : {1}, "stats" : {} } define SCARLETT_CORE = LadyCore( tag="scarlett", name="[Scarlett]", age=46, height=(162, 5.3), weight=(64, 141), max_outfits=7 ) default scarlett = Lady( tag="scarlett", job=_("Assistant") ) init python: if "scarlett" not in persistent.all_ladies: persistent.all_ladies["scarlett"] = { "known" : False, "outfits" : {1}, "stats" : {} } define KATE_CORE = LadyCore( tag="kate", name="[Kate]", age=32, height=(161, 5.3), weight=(59, 130), max_outfits=7 ) default kate = Lady( tag="kate", job=_("Receptionist") ) init python: if "kate" not in persistent.all_ladies: persistent.all_ladies["kate"] = { "known" : False, "outfits" : {1}, "stats" : {} } define REBECCA_CORE = LadyCore( tag="rebecca", name="[Rebecca]", age=18, height=(163, 5.3), weight=(53, 117), max_outfits=11 ) default rebecca = Lady( tag="rebecca", job=_("College Student") ) init python: if "rebecca" not in persistent.all_ladies: persistent.all_ladies["rebecca"] = { "known" : False, "outfits" : {1}, "stats" : {} } define CAROLINE_CORE = LadyCore( tag="caroline", name="[Caroline]", age=35, height=(165, 5.4), weight=(60, 132), max_outfits=1 ) default caroline = Lady( tag="caroline", job=_("Cafe Owner") ) init python: if "caroline" not in persistent.all_ladies: persistent.all_ladies["caroline"] = { "known" : False, "outfits" : {1}, "stats" : {} } define SANDRA_CORE = LadyCore( tag="sandra", name="[Sandra]", age=51, height=(166, 5.4), weight=(66, 145), max_outfits=1 ) default sandra = Lady( tag="sandra", job=_("Restaurant Owner") ) init python: if "sandra" not in persistent.all_ladies: persistent.all_ladies["sandra"] = { "known" : False, "outfits" : {1}, "stats" : {} } define AVA_CORE = LadyCore( tag="ava", name="[Ava]", age=41, height=(170, 5.5), weight=(58, 128), max_outfits=2 ) default ava = Lady( tag="ava", job=_("Stripper") ) init python: if "ava" not in persistent.all_ladies: persistent.all_ladies["ava"] = { "known" : False, "outfits" : {1}, "stats" : {} } define SOPHIA_CORE = LadyCore( tag="sophia", name="[Sophia]", age=24, height=(168, 5.5), weight=(59, 130), max_outfits=2 ) default sophia = Lady( tag="sophia", job=_("Waitress") ) init python: if "sophia" not in persistent.all_ladies: persistent.all_ladies["sophia"] = { "known" : False, "outfits" : {1}, "stats" : {} } define ELENA_CORE = LadyCore( tag="elena", name="[Elena]", age=36, height=(171, 5.6), weight=(59, 130), max_outfits=2 ) default elena = Lady( tag="elena", job=_("Stripper") ) init python: if "elena" not in persistent.all_ladies: persistent.all_ladies["elena"] = { "known" : False, "outfits" : {1}, "stats" : {} } define JASMINE_CORE = LadyCore( tag="jasmine", name="[Jasmine]", age=39, height=(170, 5.6), weight=(65, 143), max_outfits=1 ) default jasmine = Lady( tag="jasmine", job=_("Stripper") ) init python: if "jasmine" not in persistent.all_ladies: persistent.all_ladies["jasmine"] = { "known" : False, "outfits" : {1}, "stats" : {} } define LADIES_ORDER = [ "adrianna", "jenna", "linda", "emma", "madison", "scarlett", "kate", "rebecca", "caroline", "sandra", "ava", "sophia", "elena", "jasmine" ] init python: class Stat: def __init__(self, name, default_value, authorized_values=None): self.name = name self.default_value = default_value self.authorized_values = authorized_values define STATS = [ "handjob", "facefuck", "spank", "blowjob", "vaginal", "swallow", "titjob", "anal", "facial", "footjob", "pregnant", "creampie", ] define DEFAULT_STATS = { "handjob" : Stat(_("Handjob"), 0), "facefuck" : Stat(_("Facefuck"), 0), "spank" : Stat(_("Ass Spanked"), 0), "blowjob" : Stat(_("Blowjob"), 0), "vaginal" : Stat(_("Vaginal Sex"), 0), "swallow" : Stat(_("Loads Swallowed"), 0), "titjob" : Stat(_("Titjob"), 0), "anal" : Stat(_("Anal Sex"), 0), "facial" : Stat(_("Facials"), 0), "footjob" : Stat(_("Footjob"), 0), "pregnant" : Stat(_("Impregnated"), "no", {_("no"), _("yes")}), "creampie" : Stat(_("Creampies"), 0) } # # "LADIES" button displayed in the top right corner anytime # default persistent.ladies_button_opacity = 1.0 default show_ladies_button = True transform ladies_button_alpha(): on idle: alpha persistent.ladies_button_opacity on hover: alpha 1.0 screen ladies_button(): if show_ladies_button and not _in_replay: imagebutton: at ladies_button_alpha anchor (0.5,0.5) pos (0.98, 0.04) idle "heart_button" hover Transform("heart_button", zoom=1.2) #activate_sound audio.beat hover_sound audio.button_hover action Show("ladies_selection") screen ladies_selection_menu: tag menu if main_menu: use ladies_selection("persistent", frommenu=True) else: use ladies_selection(frommenu=True) # Bar background image ladies_idle_bar = Solid("#302a4d", xysize=(18,1050)) image ladies_hover_bar = Solid("#3F385B", xysize=(18,1050)) # Bar thumb image ladies_idle_thumb = Solid("#c6c0e3", xysize=(18,1050)) image ladies_hover_thumb = Solid("#e8e2ff", xysize=(18,1050)) screen ladies_selection(origin="ingame", frommenu=False): modal True style_prefix "ladies" if origin == "ingame": default dico = all_ladies else: default dico = all_ladies # Background add "ladies_selection_background" # Title text _("Ladies"): xalign 0.5 ypos 70 size 90 vpgrid: cols 4 xspacing 20 yspacing 60 draggable True mousewheel True # 285 = ysize of one thumbnail # 60 = yspacing above ymaximum 285*2 + 60 xpos 90 ypos 300 scrollbars "vertical" # Since we have scrollbars, we have to position the side, rather than the vpgrid proper. # side_xalign 0.9 side_spacing 20 vscrollbar_xsize 15 vscrollbar_base_bar Frame("ladies_[prefix_]bar", gui.vscrollbar_borders, tile=gui.scrollbar_tile) vscrollbar_thumb Frame("ladies_[prefix_]thumb", gui.vscrollbar_borders, tile=gui.scrollbar_tile) for tag, l in [ (tag, ALL_LADIES[tag]) for tag in LADIES_ORDER ]: button: padding (0, 0) vbox: spacing 5 if l.known(origin): text l.name xalign 0.5 else: text _("???") xalign 0.5 frame: style "empty" xysize (417, 235) idle_background tag + "_selection_idle" hover_background tag + "_selection_hover" insensitive_background Transform(tag + "_selection_idle", matrixcolor=SaturationMatrix(0), blur=20.0) foreground Frame("ladies_thumbnail_foreground", 30, 30) sensitive l.known(origin) action Show("lady", lady_tag=tag, origin=origin) textbutton _("Close"): style "ladiesui_button" keysym "game_menu" align (0.5, 0.93) if frommenu: if origin == "ingame": action ShowMenu("save") else: action Return() else: action Hide("ladies_selection") screen lady(lady_tag, origin="ingame"): modal True style_prefix "ladies" default LADY = ALL_LADIES[lady_tag] default current_outfit = LADY.max_outfit_unlocked(origin) # Background add "lady_selected_background" add lady_tag + "_outfit_" + str(current_outfit) # Infos vbox: anchor (1.0, 0.0) pos (0.99, 0.01) text LADY.name: xalign 1.0 size 70 outlines [ (1, "#000000", -1, -1) ] text trans(_("[lady_age] years old"), scope={"lady_age" : LADY.age}): xalign 1.0 size 28 color ladies_dark_color outlines [ (1, "#000000", -1, -1) ] text _(LADY.job()): xalign 1.0 color "#ffffff" size 28 outlines [ (1, "#000000", -1, -1) ] text LADY.height: xalign 1.0 size 25 outlines [ (1, "#000000", -1, -1) ] text LADY.weight: xalign 1.0 size 25 color ladies_dark_color outlines [ (1, "#000000", -1, -1) ] # Stats vpgrid: cols 3 rows 4 xspacing 30 yspacing 80 xpos 500 ypos 300 for s in STATS: hbox: spacing 10 #add "stat_" + s + "_icon" xysize (100, 100) vbox: spacing 10 yalign 0.5 label DEFAULT_STATS[s].name size_group "ladies_stats_size" label LADY.get_stat(s, origin) size_group "ladies_stats_size" text_color ladies_light_color vbox: anchor (0.5, 0.0) pos (200, 970) spacing 10 text trans(_("Outfit [lady_current_outfit]/[lady_max_outfit]"), scope={"lady_current_outfit" : LADY.outfit_format().format(current_outfit), "lady_max_outfit": LADY.outfit_format().format(LADY.max_outfits)}): xalign 0.5 hbox: spacing 20 xalign 0.5 textbutton _("Previous"): style "ladiesui_button" size_group "lady_ui_button" sensitive current_outfit > 1 action SetScreenVariable("current_outfit", LADY.previous_outfit(origin, current_outfit)) textbutton _("Next"): style "ladiesui_button" size_group "lady_ui_button" sensitive current_outfit < LADY.max_outfit_unlocked(origin) action SetScreenVariable("current_outfit", LADY.next_outfit(origin, current_outfit)) textbutton _("Return"): style "ladiesui_button" keysym "game_menu" anchor (1.0, 1.0) pos (1900, 1060) action Hide("lady") style ladies_text: font gui.ft_lemon_milk color ladies_light_color style ladies_label_text: xalign 0.5 font gui.ft_lemon_milk size 27 color "#ffffff" style ladiesui_button is button: padding (30, 6) idle_background Frame(Transform("button_frame_white", matrixcolor=TintMatrix(ladies_light_color)), 2, 2) hover_background Frame(Transform("button_frame_white", matrixcolor=TintMatrix(ladies_dark_color)), 2, 2) insensitive_background Frame(Transform("button_frame_white", matrixcolor=TintMatrix(ladies_insensitive_color)), 2, 2) hover_sound audio.button_hover style ladiesui_button_text is button_text: font gui.ft_lemon_milk size 17 idle_color ladies_light_color hover_color ladies_dark_color insensitive_color ladies_insensitive_color xalign 0.5