WTS/game/scripts/utility/editor.rpy
2022-05-17 00:48:22 +01:00

556 lines
26 KiB
Plaintext

# init python:
# def catch_character_call(label, called):
# if called:
# if label.startswith(("her_main", "cho_main", "ast_main", "ton_main", "sus_main", "lun_main", "hoo_main")):
# editor.catch(label)
# def lookup(what):
# if isinstance(what, (int, str, float, bool)):
# return None
# for k, v in store.__dict__.iteritems():
# if k.startswith("_"):
# continue
# if v == what:
# return k
# return None
# class ExpressionEditor(NoRollback):
# transforms = ("move_fade", "sprite_fly_idle")
# char = {"her_main": "hermione",
# "ton_main": "tonks",
# "ast_main": "astoria",
# "cho_main": "cho",
# "sus_main": "susan",
# "lun_main": "luna",
# "hoo_main": "hooch",
# }
# def __init__(self):
# self.label = None
# self.line = None
# self.line_contents = None
# self.args = None
# self._file = None
# self._file_contents = None
# self.define_expressions()
# self.changes = _dict()
# def launch_editor(self, file=None, line=None):
# """Launches external text editor."""
# if renpy.in_rollback() or renpy.in_fixed_rollback():
# return
# renpy.launch_editor([file], line)
# return
# def overwrite_statement(self):
# # Backup file contents
# with open(self._file, "r") as f:
# self._file_contents = f.readlines()
# found = False
# try:
# new = self.get_new_statement()
# old = self.line_contents
# # Overwrite the file contents
# with open(self._file, "w") as f:
# for n, l in enumerate(self._file_contents, 1):
# if n == self.line and l.partition("#")[0].strip() == old:
# found = True
# f.writelines(l.replace(old, new))
# # Is it a new line, or have we already edited it?
# if n not in self.changes.get(self._file, _list()):
# self.changes.setdefault(self._file, _dict()).setdefault(n, [old, new, self.args, self.char[self.label], None])
# else:
# self.changes[self._file][n] = [old, new, self.args, self.char[self.label], None]
# self.line_contents = new
# else:
# f.writelines(l)
# if not found:
# renpy.notify("Line {} contents changed unexpectedly, no changes were made.".format(self.line))
# return
# except:
# # Restore backup
# with open(self._file, "w") as f:
# for l in self._file_contents:
# f.writelines(l)
# renpy.notify("An error occurred, no changes were made.")
# return
# renpy.notify("Saved.")
# return
# def get_new_statement(self):
# text = "\"\", " if not self.args["text"] else "\"{}\", ".format(self.args["text"].replace("\"", "\\\""))
# mouth = "" if self.args["mouth"] == False else "\"{}\", ".format(self.args["mouth"])
# eyes = "" if self.args["eyes"] == False else "\"{}\", ".format(self.args["eyes"])
# eyebrows = "" if self.args["eyebrows"] == False else "\"{}\", ".format(self.args["eyebrows"])
# pupils = "" if self.args["pupils"] == False else "\"{}\", ".format(self.args["pupils"])
# hair = "" if self.label != "ton_main" or self.args["hair"] in (None, "(No change)") else "hair=\"{}\", ".format(self.args["hair"])
# cheeks = "" if self.args["cheeks"] in (None, "(No change)") else "cheeks=\"{}\", ".format(self.args["cheeks"])
# tears = "" if self.args["tears"] in (None, "(No change)") else "tears=\"{}\", ".format(self.args["tears"])
# emote = "" if self.args["emote"] == None else "emote=\"{}\", ".format(self.args["emote"])
# face = "" if self.args["face"] == None else "face=\"{}\", ".format(self.args["face"])
# xpos = self.args["xpos"]
# if xpos == None:
# xpos = ""
# else:
# xpos = "xpos={}, ".format(xpos) if is_integer(xpos) else "xpos=\"{}\", ".format(xpos)
# ypos = self.args["ypos"]
# if ypos == None:
# ypos = ""
# else:
# ypos = "ypos={}, ".format(ypos) if is_integer(ypos) else "ypos=\"{}\", ".format(ypos)
# flip = "" if self.args["flip"] == None else "flip={}, ".format(self.args["flip"])
# trans = "" if self.args["trans"] == None else "trans={}, ".format(self.args["trans"])
# animation = "" if self.args["animation"] == False else "animation={}".format(self.args["animation"])
# new = "call {}({}{}{}{}{}{}{}{}{}{}{}{}{}{}{})".format(self.label, text, mouth, eyes, eyebrows, pupils, hair, cheeks, tears, emote, face, xpos, ypos, flip, trans, animation)
# new = new.replace(", )", ")")
# return new
# def catch(self, label):
# # Get file and line number
# stack = renpy.get_return_stack()[-1]
# node = renpy.game.script.namemap.get(stack, None)
# # Console call fallback
# if node.filename == "<string>":
# return
# self._file = config.basedir+"/"+node.filename
# self.line = node.linenumber
# self.label = label
# if self.changes.get(self._file, _dict()).get(self.line, None):
# # Get arguments from cache
# self.args = self.changes[self._file][self.line][2]
# else:
# # Get arguments from node
# node = renpy.game.script.lookup_or_none(self.label)
# self.args = _dict([(k, getattr(store, k)) for k in node.parameters.apply(None, None).iterkeys()])
# if self.args["cheeks"] == None:
# self.args["cheeks"] = "(No change)"
# if self.args["tears"] == None:
# self.args["tears"] = "(No change)"
# if self.label == "ton_main":
# if self.args["hair"] == None:
# self.args["hair"] = "(No change)"
# # Lookup transition name (Reverse lookup)
# trans_arg = self.args["trans"]
# if trans_arg:
# self.args["trans"] = lookup(trans_arg)
# #_transitions = _dict([(obj.callable, name) for (name, obj) in store.__dict__.iteritems() if name in self.transitions])
# #self.args["trans"] = _transitions[self.args["trans"].callable]
# # Lookup transform name
# anim_arg = self.args["animation"]
# if not anim_arg in (False, None):
# #self.args["animation"] = lookup(anim_arg)
# _transforms = _dict([(obj, name) for (name, obj) in store.__dict__.iteritems() if isinstance(obj, renpy.atl.ATLTransformBase)])
# self.args["animation"] = _transforms[anim_arg]
# # Check for already made changes and hijack the line.
# if self.changes.get(self._file, _dict()).get(self.line, None):
# self.line_contents = self.changes[self._file][self.line][1]
# else:
# # Read file and find the line in question
# with open(self._file, "U") as f:
# for n, l in enumerate(f, 1):
# if n == self.line:
# l = l.partition("#")[0].strip() # Ignore comments and strip spaces
# if l.startswith("call {}".format(self.label)):
# self.line_contents = l
# break
# return
# def set_data(self, arg, val):
# if not isinstance(val, basestring):
# return
# if self.args[arg] != val:
# self.args[arg] = val
# self.overwrite_statement()
# def get_tooltip(self, file, line):
# if self.changes[file][line][4] == None:
# imagepath = config.basedir.replace("\\", "/")
# args = self.changes[file][line][2]
# char = self.changes[file][line][3]
# if char == "hermione":
# hair = her_hair_base
# box = (450, 275, 320, 240)
# elif char == "tonks":
# hair = ton_hair_base_new
# box = (450, 275, 320, 240)
# elif char == "astoria":
# hair = ast_hair_base
# box = (450, 320, 280, 240)
# elif char == "cho":
# hair = cho_hair_ponytail1
# box = (450, 310, 280, 240)
# elif char == "susan":
# hair = sus_hair_base
# box = (450, 310, 280, 240)
# elif char == "luna":
# hair = lun_hair_base
# box = (450, 310, 280, 240)
# elif char == "hooch":
# hair = hoo_hair_base
# box = (370, 240, 280, 240)
# sprites = [imagepath+"/game/characters/"+char+"/body/base/front.webp"]
# if not "No change" in args["cheeks"]:
# sprites.append(imagepath+"/game/characters/"+char+"/face/cheeks/"+args["cheeks"]+".webp")
# sprites.append(imagepath+"/game/characters/"+char+"/face/eyes/"+args["eyes"]+".webp")
# if not any(x in args["eyes"] for x in ("closed", "happyCl")):
# m = imagepath+"/game/characters/"+char+"/face/eyes/"+args["eyes"]+"_mask.webp"
# sprites.append(AlphaMask(imagepath+"/game/characters/"+char+"/face/pupils/"+args["pupils"]+".webp", m))
# sprites.append(imagepath+"/game/characters/"+char+"/face/eyebrows/"+args["eyebrows"]+".webp")
# if not "No change" in args["tears"]:
# sprites.append(imagepath+"/game/characters/"+char+"/face/tears/"+args["tears"]+".webp")
# sprites.append(imagepath+"/game/characters/"+char+"/face/mouth/"+args["mouth"]+".webp")
# # Hair
# sprites.append(hair.get_back()[0])
# if hair.back_outline:
# sprites.append(hair.back_outline)
# sprites.append(hair.get_image())
# sprites = tuple(itertools.chain.from_iterable(((0,0), x) for x in sprites))
# self.changes[file][line][4] = At(Crop(box, Composite((1010, 1200), *sprites)), Transform(zoom=0.5))
# return self.changes[file][line][4]
# def set_expressions(self):
# if not self.char or not self.label:
# return
# c = getattr(renpy.store, self.char[self.label])
# cheeks = None if self.args["cheeks"] in (None, "(No change)") else self.args["cheeks"]
# tears = None if self.args["tears"] in (None, "(No change)") else self.args["tears"]
# if self.label == "ton_main":
# hair = None if self.args["hair"] in (None, "(No change)") else self.args["hair"]
# # Hardcoded for tonks
# if hair:
# if hair in ("neutral", "basic", "reset"):
# target_color = tonks_haircolor
# elif hair in ("red", "angry", "furious"):
# target_color = [[164, 34, 34, 255], [219, 83, 83, 255]]
# elif hair in ("orange", "upset", "annoyed"):
# target_color = [[228, 93, 34, 255], [246, 193, 170, 255]]
# elif hair in ("yellow", "happy", "cheerful"):
# target_color = [[255, 213, 23, 255], [255, 239, 167, 255]]
# elif hair in ("green", "disgusted"):
# target_color = [[111, 205, 75, 255], [200, 237, 186, 255]]
# elif hair in ("blue", "sad"):
# target_color = [[64, 75, 205, 255], [182, 186, 237, 255]]
# elif hair == "purple":
# target_color = [[205, 75, 205, 255], [237, 186, 237, 255]]
# elif hair in ("white", "scared"):
# target_color = [[238, 238, 241, 255], [249, 249, 250, 255]]
# elif hair in ("pink", "horny"):
# target_color = [[255, 105, 180, 255], [251, 205, 222, 255]]
# tonks.get_equipped("hair").set_color(target_color)
# c.set_face(mouth=self.args["mouth"], eyes=self.args["eyes"], eyebrows=self.args["eyebrows"], pupils=self.args["pupils"], cheeks=cheeks, tears=tears)
# def get_expressions(self, type):
# return sorted(self.expressions[self.char[self.label]][type])
# def define_expressions(self):
# def scan_files(char):
# dirs = {
# "mouth": None,
# "eyes": None,
# "eyebrows": None,
# "pupils": None,
# "cheeks": None,
# "tears": None,
# "hair": ["(No change)", "neutral", "angry", "upset", "happy", "disgusted", "sad", "purple", "scared", "horny"],
# }
# for k, v in dirs.iteritems():
# if k == "hair":
# continue
# path = "{}/game/characters/{}/face/{}/".format(config.basedir, char, k)
# if not os.path.exists(path):
# os.makedirs(path)
# dirs[k] = list(x.rsplit(".webp")[0] for x in os.listdir(path) if x.endswith(".webp") and not "_mask" in x and not "_skin" in x)
# dirs["cheeks"] += ["(No change)"]
# dirs["tears"] += ["(No change)"]
# return _dict(dirs)
# self.expressions = _dict([(x, scan_files(x)) for x in self.char.itervalues()])
# def editor_reset():
# editor.changes = _dict()
# if config.developer and not renpy.mobile:
# editor = ExpressionEditor()
# config.label_callback = catch_character_call
# config.after_load_callbacks.append(editor_reset)
# config.interact_callbacks.append(editor.set_expressions)
# screen editor():
# layer "interface"
# tag editor
# zorder 0
# style_prefix "editor"
# default minimised = False
# default minimised_history = False
# default minimised_cg = False
# default frame_size = (250, 500)
# default expressions = ("mouth", "eyes", "eyebrows", "pupils", "cheeks", "tears", "hair")
# if config.developer and not _menu:
# # Editor
# drag:
# drag_name "editor"
# draggable True
# drag_offscreen False
# drag_handle (0, 0, 1.0, 26)
# pos (50, 50)
# window:
# background "#00000080"
# xysize (frame_size if not minimised else (250, 28))
# button action NullAction() style "empty" ypos 18
# text "Expression Editor {size=-2}ver 0.2{/size}" size 10 color "#FFF" outlines [(1, "#00000080", 1, 0)]
# textbutton "_" ysize 28 offset (-32, -7) text_size 15 text_yalign 0.5 xalign 1.0 action [ToggleScreenVariable("minimised", True, False), SelectedIf(None)] tooltip ("Maximise" if minimised else "Minimise")
# textbutton "x" ysize 28 offset (6, -7) text_size 15 text_yalign 0.5 xalign 1.0 action Hide("editor") tooltip "Close editor"
# frame:
# style "empty"
# xysize (236, 2)
# pos (0, 18)
# background "#FFFFFF80"
# if not minimised:
# if editor.label:
# $ f = editor._file.split("/")[-1]
# $ l = editor.line
# vbox:
# ypos 24
# for i in expressions:
# if i == "hair" and not editor.label == "ton_main":
# pass
# else:
# text i size 14 color "#fff" outlines [(1, "#00000080", 1, 0)]
# hbox:
# xpos 12
# box_wrap True
# for j in editor.get_expressions(i):
# textbutton j:
# selected (j == editor.args[i])
# action Function(editor.set_data, i, j)
# text_size 8
# text_selected_color "#009900"
# text_xalign 0.5
# xminimum 32
# # History
# drag:
# drag_name "editor_history"
# draggable True
# drag_offscreen False
# drag_handle (0, 0, 1.0, 26)
# pos (300, 50)
# frame:
# background "#00000080"
# xysize (frame_size if not minimised_history else (250, 28))
# button action NullAction() style "empty" xysize (frame_size if not minimised_history else (250, 28)) ypos 18
# text "History" size 10 color "#FFF" outlines [(1, "#00000080", 1, 0)]
# textbutton "_" ysize 28 offset (-32, -7) text_size 15 text_yalign 0.5 xalign 1.0 action [ToggleScreenVariable("minimised_history", True, False), SelectedIf(None)] tooltip ("Maximise" if minimised_history else "Minimise")
# textbutton "x" ysize 28 offset (6, -7) text_size 15 text_yalign 0.5 xalign 1.0 action Hide("editor") tooltip "Close editor"
# frame:
# style "empty"
# xysize (236, 2)
# pos (0, 18)
# background "#FFFFFF80"
# if not minimised_history:
# if editor.changes:
# $ n = 0
# $ nn = 0
# for k, v in editor.changes.iteritems():
# $ n += 1
# $ nn += len(v)
# text "[nn] changes in [n] files" size 10 color "#FFF" xalign 0.5 ypos 26 outlines [(1, "#00000080", 1, 0)]
# frame:
# style "empty"
# xsize 236
# ymaximum 400
# yfill True
# ypos 42
# side "c r":
# area (0, 0, 236, 400)
# viewport id "editor_history":
# draggable False
# mousewheel True
# vbox:
# for fn in editor.changes.iterkeys():
# text (fn.split("/")[-1]) size 10 color "#FFF" xalign 0.5 outlines [(1, "#00000080", 1, 0)]
# frame style "empty" xysize (236, 2) background "#FFFFFF80"
# for l in editor.changes[fn].iterkeys():
# textbutton "Line [l]":
# text_size 10
# text_color "#FFF"
# text_outlines [(1, "#00000080", 1, 0)]
# if editor.line == l:
# background "#FFFFFF80"
# tooltip editor.get_tooltip(fn, l)
# action Function(editor.launch_editor, file=fn, line=l)
# vbar value YScrollValue("editor_history") xsize 10
# else:
# text "No history." size 15 color "#FFF" align (0.5, 0.5) outlines [(1, "#00000080", 1, 0)]
# # CG poser
# if renpy.get_screen("animatedCG"):
# drag:
# drag_name "editor_cg"
# draggable True
# drag_offscreen False
# drag_handle (0, 0, 1.0, 26)
# pos (550, 50)
# frame:
# background "#00000080"
# xysize (frame_size if not minimised_cg else (250, 28))
# button action NullAction() style "empty" xysize (frame_size if not minimised_cg else (250, 28)) ypos 18
# text "CG Poser" size 10 color "#FFF" outlines [(1, "#00000080", 1, 0)]
# textbutton "_" ysize 28 offset (-32, -7) text_size 15 text_yalign 0.5 xalign 1.0 action [ToggleScreenVariable("minimised_cg", True, False), SelectedIf(None)] tooltip ("Maximise" if minimised_history else "Minimise")
# textbutton "x" ysize 28 offset (6, -7) text_size 15 text_yalign 0.5 xalign 1.0 action Hide("editor") tooltip "Close editor"
# frame:
# style "empty"
# xysize (236, 2)
# pos (0, 18)
# background "#FFFFFF80"
# if not minimised_cg:
# $ x, y = camera.pos
# $ zoom = camera.zoom
# $ rotate = camera.rotate
# default pos_step = 5
# default zoom_step = 0.05
# default rotate_step = 5
# vbox:
# text "Pos Step ({})".format(pos_step) color "#fff"
# hbox:
# textbutton "-":
# action SetScreenVariable("pos_step", max(pos_step-5, 5))
# textbutton "+":
# action SetScreenVariable("pos_step", min(pos_step+5, 100))
# text "Pos (x={}, y={})".format(x, y) color "#fff"
# hbox:
# textbutton "X-":
# action [SetVariable("camera.pos", (x-pos_step, y)), Function(camera.redraw, 0)]
# textbutton "X+":
# action [SetVariable("camera.pos", (x+pos_step, y)), Function(camera.redraw, 0)]
# hbox:
# textbutton "Y-":
# action [SetVariable("camera.pos", (x, y-pos_step)), Function(camera.redraw, 0)]
# textbutton "Y+":
# action [SetVariable("camera.pos", (x, y+pos_step)), Function(camera.redraw, 0)]
# null height 20
# text "Zoom Step ({})".format(zoom_step) color "#fff"
# hbox:
# textbutton "-":
# action SetScreenVariable("zoom_step", max(zoom_step-0.01, 0.01))
# textbutton "+":
# action SetScreenVariable("zoom_step", min(zoom_step+0.01, 0.25))
# text "Zoom (zoom={})".format(zoom) color "#fff"
# hbox:
# textbutton "-":
# action [SetVariable("camera.zoom", zoom-zoom_step), Function(camera.redraw, 0)]
# textbutton "+":
# action [SetVariable("camera.zoom", zoom+zoom_step), Function(camera.redraw, 0)]
# null height 20
# text "Rotate Step ({})".format(rotate_step) color "#fff"
# hbox:
# textbutton "-":
# action SetScreenVariable("rotate_step", max(rotate_step-1, 1))
# textbutton "+":
# action SetScreenVariable("rotate_step", min(rotate_step+1, 1))
# text "Rotate ({})".format(rotate) color "#fff"
# hbox:
# textbutton "-":
# action [SetVariable("camera.rotate", rotate-rotate_step), Function(camera.redraw, 0)]
# textbutton "+":
# action [SetVariable("camera.rotate", rotate+rotate_step), Function(camera.redraw, 0)]
# null height 50
# textbutton "Copy to Clipboard" action [Function(set_clipboard, "$ camera.set(zoom={}, pos=({}, {}), rotate={}, t=1.0)".format(zoom, x, y, rotate)), Notify("Copied!")]
# style editor_button is empty:
# margin (3, 3)
# style editor_button_text:
# color "#cccccc"
# hover_color "#ffffff"
# outlines [(1, "#00000080", 1, 0)]