1# Copyright 2004-2021 Tom Rothamel <pytom@bishoujo.us> 2# 3# Permission is hereby granted, free of charge, to any person 4# obtaining a copy of this software and associated documentation files 5# (the "Software"), to deal in the Software without restriction, 6# including without limitation the rights to use, copy, modify, merge, 7# publish, distribute, sublicense, and/or sell copies of the Software, 8# and to permit persons to whom the Software is furnished to do so, 9# subject to the following conditions: 10# 11# The above copyright notice and this permission notice shall be 12# included in all copies or substantial portions of the Software. 13# 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22init python: 23 class PackageToggle(Action): 24 def __init__(self, name): 25 self.name = name 26 27 def get_selected(self): 28 return self.name in project.current.data['packages'] 29 30 def __call__(self): 31 packages = project.current.data['packages'] 32 33 if self.name in packages: 34 packages.remove(self.name) 35 else: 36 packages.append(self.name) 37 38 project.current.save_data() 39 renpy.restart_interaction() 40 41 class DataToggle(Action): 42 def __init__(self, field): 43 self.field = field 44 45 def get_selected(self): 46 return project.current.data[self.field] 47 48 def __call__(self): 49 project.current.data[self.field] = not project.current.data[self.field] 50 51 project.current.save_data() 52 renpy.restart_interaction() 53 54 55 DEFAULT_BUILD_INFO = """ 56 57## This section contains information about how to build your project into 58## distribution files. 59init python: 60 61 ## The name that's used for directories and archive files. For example, if 62 ## this is 'mygame-1.0', the windows distribution will be in the 63 ## directory 'mygame-1.0-win', in the 'mygame-1.0-win.zip' file. 64 build.directory_name = "PROJECTNAME-1.0" 65 66 ## The name that's uses for executables - the program that users will run 67 ## to start the game. For example, if this is 'mygame', then on Windows, 68 ## users can click 'mygame.exe' to start the game. 69 build.executable_name = "PROJECTNAME" 70 71 ## If True, Ren'Py will include update information into packages. This 72 ## allows the updater to run. 73 build.include_update = False 74 75 ## File patterns: 76 ## 77 ## The following functions take file patterns. File patterns are case- 78 ## insensitive, and matched against the path relative to the base 79 ## directory, with and without a leading /. If multiple patterns match, 80 ## the first is used. 81 ## 82 ## 83 ## In a pattern: 84 ## 85 ## / 86 ## Is the directory separator. 87 ## * 88 ## Matches all characters, except the directory separator. 89 ## ** 90 ## Matches all characters, including the directory separator. 91 ## 92 ## For example: 93 ## 94 ## *.txt 95 ## Matches txt files in the base directory. 96 ## game/**.ogg 97 ## Matches ogg files in the game directory or any of its subdirectories. 98 ## **.psd 99 ## Matches psd files anywhere in the project. 100 101 ## Classify files as None to exclude them from the built distributions. 102 103 build.classify('**~', None) 104 build.classify('**.bak', None) 105 build.classify('**/.**', None) 106 build.classify('**/#**', None) 107 build.classify('**/thumbs.db', None) 108 109 ## To archive files, classify them as 'archive'. 110 111 # build.classify('game/**.png', 'archive') 112 # build.classify('game/**.jpg', 'archive') 113 114 ## Files matching documentation patterns are duplicated in a mac app 115 ## build, so they appear in both the app and the zip file. 116 117 build.documentation('*.html') 118 build.documentation('*.txt') 119 """ 120 121# A screen that displays a file or directory name, and 122# lets the user change it, 123# 124# title 125# The title of the link. 126# value 127# The value of the field. 128screen distribute_name: 129 130 add SEPARATOR2 131 132 frame: 133 style "l_indent" 134 has vbox 135 136 text title 137 138 add HALF_SPACER 139 140 frame: 141 style "l_indent" 142 text "[value!q]" 143 144 add SPACER 145 146 147screen build_distributions: 148 149 frame: 150 style_group "l" 151 style "l_root" 152 153 window: 154 155 has vbox 156 157 label _("Build Distributions: [project.current.display_name!q]") 158 159 add HALF_SPACER 160 161 hbox: 162 163 # Left side. 164 frame: 165 style "l_indent" 166 xmaximum ONEHALF 167 xfill True 168 169 has vbox 170 171 use distribute_name( 172 title=_("Directory Name:"), 173 value=project.current.dump["build"]["directory_name"]) 174 175 use distribute_name( 176 title=_("Executable Name:"), 177 value=project.current.dump["build"]["executable_name"]) 178 179 add SEPARATOR2 180 181 frame: 182 style "l_indent" 183 has vbox 184 185 text _("Actions:") 186 187 add HALF_SPACER 188 189 frame style "l_indent": 190 191 has vbox 192 193 textbutton _("Edit options.rpy") action editor.Edit("game/options.rpy", check=True) 194 textbutton _("Add from clauses to calls, once") action Jump("add_from") 195 textbutton _("Refresh") action Jump("build_distributions") 196 197 add HALF_SPACER 198 199 textbutton _("Upload to itch.io") action Jump("itch") 200 201 # Right side. 202 frame: 203 style "l_indent" 204 xmaximum ONEHALF 205 xfill True 206 207 has vbox 208 209 add SEPARATOR2 210 211 frame: 212 style "l_indent" 213 has vbox 214 215 text _("Build Packages:") 216 217 add HALF_SPACER 218 219 $ packages = project.current.dump["build"]["packages"] 220 221 for pkg in packages: 222 if not pkg["hidden"]: 223 $ description = pkg["description"] 224 textbutton "[description!q]" action PackageToggle(pkg["name"]) style "l_checkbox" 225 226 add SPACER 227 add HALF_SPACER 228 add SEPARATOR2 229 230 frame: 231 style "l_indent" 232 has vbox 233 234 text _("Options:") 235 236 add HALF_SPACER 237 238 if project.current.dump["build"]["include_update"]: 239 textbutton _("Build Updates") action DataToggle("build_update") style "l_checkbox" 240 241 textbutton _("Add from clauses to calls") action DataToggle("add_from") style "l_checkbox" 242 textbutton _("Force Recompile") action DataToggle("force_recompile") style "l_checkbox" 243 244 245 textbutton _("Return") action Jump("front_page") style "l_left_button" 246 textbutton _("Build") action Jump("start_distribute") style "l_right_button" 247 248label add_from_common: 249 python: 250 interface.processing(_("Adding from clauses to call statements that do not have them.")) 251 project.current.launch([ "add_from" ], wait=True) 252 253 return 254 255label add_from: 256 call add_from_common 257 jump build_distributions 258 259 260label start_distribute: 261 if project.current.data["add_from"]: 262 call add_from_common 263 264 jump distribute 265 266label build_update_dump: 267 python: 268 project.current.update_dump(True) 269 270 if project.current.dump.get("error", False): 271 interface.error(_("Errors were detected when running the project. Please ensure the project runs without errors before building distributions.")) 272 273 return 274 275label build_distributions: 276 277 call build_update_dump 278 279label post_build: 280 281 if not project.current.dump["build"]["directory_name"]: 282 jump build_missing 283 284 call screen build_distributions 285 286label build_missing: 287 288 python hide: 289 290 interface.yesno(_("Your project does not contain build information. Would you like to add build information to the end of options.rpy?"), yes=Return(True), no=Jump("front_page")) 291 292 project_name = project.current.name 293 project_name = project_name.replace(" ", "_") 294 project_name = project_name.replace(":", "") 295 project_name = project_name.replace(";", "") 296 297 build_info = DEFAULT_BUILD_INFO.replace("PROJECTNAME", project_name) 298 299 with open(os.path.join(project.current.path, "game", "options.rpy"), "a") as f: 300 f.write(build_info) 301 302 jump build_distributions 303