├── README.md └── game └── Submods └── All Scrollable Menus ├── CHANGELOG.md └── all_menus_are_gen_scrollable.rpy /README.md: -------------------------------------------------------------------------------- 1 | # All Scrollable Menus 2 | ### Oops! All Scrollables! 3 | 4 | This submod replaces the standard Ren'Py menus with your choice of the following menus: 5 | #### The `mas_gen_scrollable_menu`: 6 | - The same screen used for large menus (Like the `Goodbye`, `I'm feeling`, `I want to tell you something` menus) 7 | - Slides Monika over to the left 8 | - Displays in the top right corner of the window 9 | 10 | ##### Sample: 11 | ![image](https://cdn.discordapp.com/attachments/609579661847953430/734161840271130684/screenshot0215.png) 12 | 13 | #### The `talk_choice` menu: 14 | - The same screen used for the main 'Talk' screen 15 | - Slides Monika over to the left 16 | - Displays on the right-middle of the window 17 | 18 | ##### Sample: 19 | ![image](https://cdn.discordapp.com/attachments/609579661847953430/734161839587459143/screenshot0214.png) 20 | 21 | #### The `unobstructed_choice` menu: 22 | - Custom screen which is essentially a medium between the above two menus 23 | - Monika doesn't need to slide over anymore 24 | - Displays in the right middle of the window 25 | 26 | ##### Sample: 27 | ![image](https://cdn.discordapp.com/attachments/609579661847953430/734161834810277948/screenshot0213.png) 28 | 29 | This submod is compatible with the [Submod Updater Plugin](https://github.com/Booplicate/MAS-Submods-SubmodUpdaterPlugin/releases/latest)! Give it an install to make updating this submod easier. 30 | 31 | ### Please report any and all problems in the `issues` tab. 32 | ###### Thank you 33 | -------------------------------------------------------------------------------- /game/Submods/All Scrollable Menus/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## September 12, 2020 (1.0.4): 2 | - Allow overrides of user choice for specific labels 3 | - This is done to deal with issues where Monika should not move in some labels 4 | 5 | ## August 03, 2020 (1.0.3): 6 | - Fix for changed constants as of the current unstable (build 126), will be carried through MAS 0.11.4 7 | 8 | ## July 18, 2020 (1.0.2): 9 | - Crash fix for opendoor greetings 10 | - Added another menu type, the `unobstructed_choice` menu, which is a medium between the `mas_gen_scrollable` and `talk_choice` menus 11 | - Optimizations 12 | 13 | ## July 16, 2020 (1.0.1): 14 | - Added settings pane and option to use the `talk_choice` screen instead of the `mas_gen_scrollable` menu 15 | 16 | ## July 13, 2020 (1.0.0): 17 | - Initial Release 18 | -------------------------------------------------------------------------------- /game/Submods/All Scrollable Menus/all_menus_are_gen_scrollable.rpy: -------------------------------------------------------------------------------- 1 | default persistent._gsm_menu_style = gsm_utils.TYPE_SCROLLABLE 2 | 3 | init -990 python in mas_submod_utils: 4 | gsm_submod = Submod( 5 | author="multimokia", 6 | name="All Gen Scrollable Menus", 7 | description="A submod which converts all menus to gen-scrollable-menus so Monika's face is never hidden.", 8 | version="1.0.4", 9 | settings_pane="gsm_settings", 10 | version_updates={ 11 | "multimokia_all_gen_scrollable_menus_v1_0_0": "multimokia_all_gen_scrollable_menus_v1_0_2", 12 | "multimokia_all_gen_scrollable_menus_v1_0_1": "multimokia_all_gen_scrollable_menus_v1_0_2", 13 | "multimokia_all_gen_scrollable_menus_v1_0_2": "multimokia_all_gen_scrollable_menus_v1_0_3" 14 | } 15 | ) 16 | 17 | init -989 python in gsm_utils: 18 | import store 19 | 20 | #Register the updater if needed 21 | if store.mas_submod_utils.isSubmodInstalled("Submod Updater Plugin"): 22 | store.sup_utils.SubmodUpdater( 23 | submod=store.mas_submod_utils.gsm_submod, 24 | user_name="multimokia", 25 | repository_name="MAS-Submod-Consistent-Menus", 26 | tag_formatter=lambda x: x[x.index('_') + 1:], 27 | update_dir="", 28 | attachment_id=None, 29 | ) 30 | 31 | #START: Update scripts 32 | label multimokia_all_gen_scrollable_menus_v1_0_0(version="v1_0_0"): 33 | return 34 | 35 | label multimokia_all_gen_scrollable_menus_v1_0_1(version="v1_0_1"): 36 | return 37 | 38 | label multimokia_all_gen_scrollable_menus_v1_0_2(version="v1_0_2"): 39 | python: 40 | safeDel("_gsm_use_talk_choice") 41 | safeDel("_gsm_unobstructed_choice") 42 | return 43 | 44 | label multimokia_all_gen_scrollable_menus_v1_0_3(version="v1_0_3"): 45 | return 46 | 47 | #START: Settings Pane 48 | screen gsm_settings(): 49 | vbox: 50 | box_wrap False 51 | xfill True 52 | xmaximum 1000 53 | 54 | hbox: 55 | style_prefix "check" 56 | box_wrap False 57 | 58 | textbutton "Use Gen Scrollable Menu": 59 | action SetField(persistent, "_gsm_menu_style", gsm_utils.TYPE_SCROLLABLE) 60 | selected persistent._gsm_menu_style == gsm_utils.TYPE_SCROLLABLE 61 | 62 | textbutton "Use Talk Choice Screen": 63 | action SetField(persistent, "_gsm_menu_style", gsm_utils.TYPE_CHOICE_MENU) 64 | selected persistent._gsm_menu_style == gsm_utils.TYPE_CHOICE_MENU 65 | 66 | textbutton "Use Unobstructed Choice Screen": 67 | action SetField(persistent, "_gsm_menu_style", gsm_utils.TYPE_UNOBSTRUCTED_CHOICE_MENU) 68 | selected persistent._gsm_menu_style == gsm_utils.TYPE_UNOBSTRUCTED_CHOICE_MENU 69 | 70 | init -1 python in gsm_utils: 71 | TYPE_SCROLLABLE = "mas_gen_scrollable_menu" 72 | TYPE_CHOICE_MENU = "talk_choice" 73 | TYPE_UNOBSTRUCTED_CHOICE_MENU = "unobstructed_choice" 74 | 75 | def parse_to_gen_scrollable(items): 76 | """ 77 | Converts the list of items to a 4 part tuple used for the mas_gen_scrollable_menu 78 | 79 | IN: 80 | items - a tuple of (label, value) representing menuitems 81 | 82 | OUT: 83 | tuple - (label, value, False, False) representing menuitems in mas_gen_scrollable_menu format 84 | """ 85 | #Convert items to the 4 part tuple 86 | return [ 87 | (x[0], x[1], False, False) 88 | for x in items 89 | ] 90 | 91 | def parse_to_standard_renpy_menu(items): 92 | """ 93 | Converts the list of items to the standard list of MenuEntry objects renpy uses for menus 94 | 95 | IN: 96 | items - a tuple of (label, value) representing menuitems 97 | 98 | OUT: 99 | list of MenuEntry objects representing menuitems in standard renpy format 100 | """ 101 | menu_items = list() 102 | 103 | #Get the location of the menu as MenuEntries need it 104 | location = renpy.game.context().current 105 | 106 | #And now make a formatted list of menu_items 107 | for (label, value) in items: 108 | if value is not None: 109 | action = renpy.ui.ChoiceReturn(label, value, location) 110 | chosen = action.get_chosen() 111 | 112 | else: 113 | action = None 114 | chosen = False 115 | 116 | if renpy.config.choice_screen_chosen: 117 | me = renpy.MenuEntry((label, action, chosen)) 118 | else: 119 | me = renpy.MenuEntry((label, action)) 120 | 121 | me.caption = label 122 | me.action = action 123 | me.chosen = chosen 124 | menu_items.append(me) 125 | 126 | return menu_items 127 | 128 | #Now build maps for these 129 | TYPE_PARSE_MAP = { 130 | TYPE_SCROLLABLE: parse_to_gen_scrollable, 131 | TYPE_CHOICE_MENU: parse_to_standard_renpy_menu, 132 | TYPE_UNOBSTRUCTED_CHOICE_MENU: parse_to_standard_renpy_menu, 133 | } 134 | 135 | TYPE_KWARGS_MAP = { 136 | TYPE_SCROLLABLE: { 137 | "display_area": store.mas_ui.SCROLLABLE_MENU_TXT_TALL_AREA, 138 | "scroll_align": store.mas_ui.SCROLLABLE_MENU_XALIGN 139 | } 140 | } 141 | 142 | #This dict holds all the labels which need to force a custom menu type 143 | LABEL_MENU_OVERRIDE_MAP = { 144 | "mas_bday_surprise_party_reacton_cake": TYPE_UNOBSTRUCTED_CHOICE_MENU 145 | } 146 | 147 | init 900 python: 148 | def menu_override(items, set_expr): 149 | """ 150 | For the docstring DM Tom: 152088707963289600 151 | 152 | :pcrowSip: 153 | """ 154 | global _history_list 155 | global _window_auto 156 | 157 | if renpy.config.old_substitutions: 158 | def substitute(s): 159 | return s % renpy.exports.tag_quoting_dict 160 | else: 161 | def substitute(s): 162 | return s 163 | 164 | #Filter the list of items to only include ones for which the condition is True. 165 | items = [ 166 | (substitute(label), value) 167 | for label, condition, value in items 168 | if renpy.python.py_eval(condition) 169 | ] 170 | 171 | #Check to see if there's at least one choice in set of items: 172 | if not items: 173 | return None 174 | 175 | #Filter the list of items on the set_expr: 176 | if set_expr: 177 | set = renpy.python.py_eval(set_expr) 178 | items = [ 179 | (label, value) 180 | for label, value in items 181 | if label not in set 182 | ] 183 | 184 | else: 185 | set = None 186 | 187 | #Get the menu style to use in case we need an override 188 | menu_type = gsm_utils.LABEL_MENU_OVERRIDE_MAP.get(mas_submod_utils.current_label) 189 | 190 | #If there's no menu override, then we'll fallback to the chosen style 191 | if menu_type is None: 192 | menu_type = persistent._gsm_menu_style 193 | 194 | #Prep before showing the menu 195 | if ( 196 | renpy.showing("monika") 197 | and menu_type != gsm_utils.TYPE_UNOBSTRUCTED_CHOICE_MENU 198 | ): 199 | renpy.show("monika", at_list=[t21]) 200 | 201 | 202 | #Get last line if it exists 203 | last_line = _history_list[-1].what if _history_list else "" 204 | 205 | #Local var for use later 206 | window_hidden = False 207 | 208 | #Handle the textbox show to keep the question up during the menu 209 | if last_line.endswith("{nw}"): 210 | renpy.say(m, last_line.replace("{nw}", "{fast}"), interact=False) 211 | 212 | elif last_line.endswith("{fast}"): 213 | renpy.say(m, last_line, interact=False) 214 | 215 | #Otherwise no text, and we should hide the textbox instead 216 | else: 217 | _window_hide() 218 | #Since we set window to hide, we'll need to reset the window to auto after 219 | window_hidden = True 220 | 221 | #Parse menu items 222 | formatted_items = gsm_utils.TYPE_PARSE_MAP[menu_type](items) 223 | 224 | #If the screen takes kwargs, we'll handle that here 225 | picked = renpy.call_screen( 226 | menu_type, 227 | items=formatted_items, 228 | **gsm_utils.TYPE_KWARGS_MAP.get(menu_type, dict()) 229 | ) 230 | 231 | #Reset Monika's position 232 | if renpy.showing("monika"): 233 | renpy.show("monika", at_list=[t11]) 234 | 235 | #Set window to auto again if we hid it 236 | if window_hidden: 237 | _window_auto = True 238 | 239 | #And pop from hist 240 | if last_line.endswith("{fast}"): 241 | _history_list.pop() 242 | 243 | #If we have a set, fill it in with the label of the chosen item. 244 | if set is not None and picked is not None: 245 | for label, value in items: 246 | if value == picked: 247 | try: 248 | set.append(label) 249 | except AttributeError: 250 | set.add(label) 251 | 252 | return picked 253 | 254 | renpy.exports.menu = menu_override 255 | 256 | #Unobstructed menu screen and styles 257 | screen unobstructed_choice(items): 258 | style_prefix "unobstructedchoice" 259 | 260 | vbox: 261 | for i in items: 262 | textbutton i.caption action i.action 263 | 264 | 265 | style unobstructedchoice_vbox is choice_vbox: 266 | xcenter 1050 267 | 268 | style unobstructedchoice_button is choice_button 269 | 270 | style unobstructedchoice_button_dark is choice_button_dark 271 | 272 | style unobstructedchoice_button_text is choice_button_text 273 | 274 | style unobstructedchoice_button_text_dark is choice_button_text_dark 275 | --------------------------------------------------------------------------------