init 1 python: # Another Chance (henceforth usually "AC") has some strange code that seems # to be, at least in part, an initial attempt at deniably easing # implementation of a patch like this one: there are some functions clearly # intended to be part of a mechanism whereby the substituted name of a # character will be different depending on who's talking about them. (One # can imagine many other situations in which such a feature would be # useful.) # # However, it doesn't currently work: it's incomplete, and there's no way # to invoke it. # # Worse, the part that's currently there is, as far as I can tell, just a # duplication of functionality that Ren'Py already provides (see, e.g., the # Ren'Py documentation for the .dynamic flag on characters), and it gets in # the way of implementing the desired functionality here. # # (I'm not entirely sure whether that functionality is actually possible # without support from the Ren'Py engine, but I _am_ sure that one could # make a better approximation to it than this.) #### # Virtually all uses of "[jo]" are in contexts associated with either the # main character or Flora. (They're not all speech; many, perhaps most, are # narration -- but fortunately, as in most VNs, the narrator is the MC.) # Thus, the following line provides 99.9% of the functionality of this # patch. Character_jo.default_name = u"Mom" # As always, the remaining 0.1% requires 99.9% of the work. # # As of AC v1.14, there are only two or three places in the entire game # where another character names Jo directly: once in one of Kate's scenes # (and in its replay), and once conditionally from Lindsey (depending on # the status of various characters' love-points). Those could be handled in # many ways; I've chosen a way that I can at least fool myself into # thinking could be generalized beyond those two occurrences. # def apply_contextual_name_patch(): # You'd think Ren'Py would have some function like this (or, # preferably, would provide this information as an argument to # callbacks). Instead we rely on undocumented internals. # # This can fail! If a character's speech is triggered from an inline # Python statement, rather than a standard Ren'Py say-statement, this # will incorrectly return None. That doesn't actually seem to occur in # AC, so I haven't attempted to address it here. # # (If it turns out to be necessary, we may be able to rely partly on # AC's own related mechanism: the variable `game._speaker` will be the # last character to have a say-command given for them. This is wrong in # the other direction, however -- it's always right during a Say, but # still holds the previous speaker during a Menu.) def get_current_speaker(): current = renpy.game.context().current node = renpy.game.script.lookup(current) if type(node) is renpy.ast.Say: who = node.who else: who = None if who == u'extend': who = _last_say_who # undocumented Ren'Py-internal variable if who is None: return None # In Ren'Py, the speaking character doesn't have to be a character- # object; a plain string works just as well. In that case there's # nothing matching that name in the store, and we'll just have to # send the string on. # # There are multiple such uses in AC v1.26.1a; in particular there # is the recurring(?) character "???", but apparently there is also # a character by the name of "Chad" somewhere. # # We assume that all speakers identified as "???" are the same # character, or at least that they'd all refer to [jo] the same # way. As of v1.26.1a, it appears that none ever actually do. return getattr(renpy.store, who, who) def smtf(s): speaker = get_current_speaker() # These characters (including None, which represents the MC # when speaking in menu text or narration) use the new default # name, and need no further processing. if speaker in {None, narrator, mc, flora}: return s # I assume these characters would most likely call her 'Jo'. (As of # v1.14, though, there are no examples of this occurring.) if speaker in {jo, mrsl, nurse, spinach, "???"}: return s.replace('[jo]', 'Jo') # This bit is incredibly niche; it's intended to fix a very minor # bug introduced into the `quest_maxine_eggs_bathroom_encounter` # conversation. # # If the per-character name functionality were present, this would # still be bugged, but it'd be easy to fix at the call site: # # $ not_best_girl = max([jo, kate, ...], lambda c: c.love) # if speaker is lindsey: if getattr(renpy.store, 'not_best_girl', None) == "Mom": renpy.store.not_best_girl = "your mom" # All other characters will refer to Jo as "your mom". # # No attempt is made to automatically capitalize this in contexts # where that would be expected. That's technically not possible to # do automatically in the general case, and happens not to be # necessary in the particular case of AC v1.14. # # I did consider using "Jo" instead... but (as of v1.14), if # someone installs this patch before they start, they'll probably # be left wondering who the hell 'Jo' was when Kate or Lindsey # eventually namedropped her. # # If she had a canon surname and/or proper intro sequence, # something like "Ms. X" would probably be the best option; but I'm # neither willing to fanwank the former nor write the latter. return s.replace('[jo]', u"your mom") renpy.config.say_menu_text_filter = smtf apply_contextual_name_patch() del apply_contextual_name_patch