Cheat Mod Ren'Py The Null Hypothesis Cheat Injector [v2.8] [Sleepingkirby]

5.00 star(s) 1 Vote

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
And how would one modify history?
Wow, uh... you really want to know. Most people just tune out when they hear something this complicated. I mean kudos to you but, in this case, it might be easier to just have them deepthroat you multiple times. But I've never been one to deny someone knowledge that can improve themselves so... *cracks knuckles*. With that said, feel free to ask any further questions about my explanation if I'm getting too much into jargon because I'm about to teach you a small lesson in computer programming . This is usually a day or two's lesson in CS 101 or 102 class.

The history object is an instantiation of the history class. Meaning that it's an custom object that RonChon wrote with a lot of properties (data holders) and methods (functions that manipulate data within it or allows you to interface with data within it) within it on how to use it. It's a long read but you'll find the class definition in games/scripts/base/history.rpy within the game's file if you want to read the whole thing. With that said, the history class has some pretty complex properties. In particular, it has properties that RonChon made that tracks events he calls trackers (rightfully so). They look like this:
Code:
    class HistoryClass(object):
        TRACKER_NAMES: Tuple = (
            "immediate",
            "event",
            "recent",
            "last",
            "yesterday",
            "daily",
            "weekly",
            "season",
            "chapter",
            "persistent",
            "permanent")
So, as you can see, events can fall into one of these many trackers. Like if you've just gotten blow job, an event might be made under recent or daily. How do trackers like persistent and permanent differ from each other? I don't quite remember. But for your purpose, you'll want to modify the persistent tracker. We know this because the definition of the check method looks like this:
Code:
        def check(self, Item: str, tracker: str = "persistent", after: Union[int, Tuple[int, int]] = 0) -> int:
            history_Item = self.trackers[tracker].get(Item, None)

            if not history_Item:
                return 0

            cutoff_day, cutoff_time = (after, 0) if isinstance(after, int) else after

            return sum(1 for day_, time_ in history_Item.completed if day_ > cutoff_day or (day_ == cutoff_day and time_ > cutoff_time))
And the function that calls for the check for deep throat looks like this:
Code:
        @property
        def throat_training(self):
            return min(4, math.floor(self.History.check("deepthroat")/8))
The call to self.History.check doesn't specify a tracker to use, but the definition says that the default value for which tracker to use, if none is provided is persistent as by this:
Code:
def check(self, Item: str, tracker: str = "persistent", after: Union[int, Tuple[int, int]] = 0) -> int:
So now you know that you need to update the persistent tracker within history. Good. Now it's important to know that history isn't a value. As the tracker definition I printed about the trackers above say:

Code:
        TRACKER_NAMES: Tuple = (
            "immediate",
            "event",
The trackers themselves are of the type "tuple". I'm going to refer to tuples as "arrays" from now on because that's how it's called in almost every other programming language. And array, like the name implies, is a list of values that are stored in order. i.e. if you were to add to an array the values 1, 7 and 5, it will store it in that order. You can also call the value in an array by its index. So if you've added it into the variable "myArray", you can get the second value you've put into that array with myArray[1] (array's start from 0, not 1. So the second item has the index of 1 and third item has the index of 2, etc.).

So, now you know you're looking to push things into the persistent tracker array. The History.check method is a summation of how many items within the array of items that make up the persistent tracker that has the value "deepthroat" (if you're like, "What? It's summation?!? Where did that come from?" In the post I posted earlier with the full explanation, it actually says that. Also, you can see it within the definition of the History.check method that it's returning a sum).

Now the question is, what is the value you want to store into the tracker. We know it's not just a number because the check function is looking for an item string. In the file game/scripts/sex/utilities.rpy, you'll see in start_Action, that it says:
Code:
        if Action.type == "deepthroat":
            $ Player.give_trait("saliva")
<snip>
        python:
            for C in (Actor, Target):
                if not C.History.check(Action.type, tracker = "recent"):
                    C.History.update(Action.type)
So, now you know that, it only adds to a character's history's persistent tracker with a certain action type if it isn't in the "recent" tracker. But, luckily, you don't really care about that. All you want to do is add more deepthroat items into the persistent tracker. So the final command is:

<name of character>.History.update("deepthroat")

Now, why did I say it might be easier to just have them deepthroat you multiple times? Well, as you can see here:

Code:
return min(4, math.floor(self.History.check("deepthroat")/8))
We now know that self.History.check("deepthroat") just returns a number, a sum of all objects named "deepthroat". It then takes that number and divides it by 8 (rounding down in case of decimals). It then compares it to the number 4 and returns which ever is smaller. So, the max to training is 32 no matter what. So, to get max training, you need to spam the command 32 times. Which, most people will actually get there pretty naturally but can pretty tedious if you were to spam that command. Or, you can write a for-loop to do it for you, but I'm not sure if you want to learn more programming at this point.
 
Last edited:

randomguy75

New Member
Oct 11, 2021
4
2
103
So, now you know that, it only adds to a character's history's persistent tracker with a certain action type if it isn't in the "recent" tracker. But, luckily, you don't really care about that. All you want to do is add more deepthroat items into the persistent tracker. So the final command is:

<name of character>.History.update("deepthroat")

Now, why did I say it might be easier to just have them deepthroat you multiple times? Well, as you can see here:

Code:
return min(4, math.floor(self.History.check("deepthroat")/8))
We now know that self.History.check("deepthroat") just returns a number, a sum of all objects named "deepthroat". It then takes that number and divides it by 8 (rounding down in case of decimals). It then compares it to the number 4 and returns which ever is smaller. So, the max to training is 32 no matter what. So, to get max training, you need to spam the command 32 times. Which, most people will actually get there pretty naturally but can pretty tedious if you were to spam that command. Or, you can write a for-loop to do it for you, but I'm not sure if you want to learn more programming at this point.
Thanks for telling me, it took me ages to find the right variables to locate and it eventually led me to the update function
 
  • Like
Reactions: sleepingkirby

mrbombadil

Member
Jul 25, 2024
133
362
82
I just installed this mod and unfortunately got the following error when in the Journal I clicked on a relationship (Rogue).

I first installed the TNHUXMod and that worked with no issues. Then I installed the cheat mod (the bat file said everything was installed). At this point is when the error started.

Code:
I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/scripts/locations/bedrooms/bedrooms.rpy", line 89, in script
    menu(menu_location = Player.home):
  File "game/scripts/interfaces/Player_menu.rpy", line 118, in execute
    screen Player_menu(page, giving_gift = False):
  File "game/scripts/interfaces/Player_menu.rpy", line 118, in execute
    screen Player_menu(page, giving_gift = False):
  File "game/scripts/interfaces/Player_menu.rpy", line 138, in execute
    if black_screen[0]:
  File "game/scripts/interfaces/Player_menu.rpy", line 221, in execute
    if menu_page == "database":
  File "game/scripts/interfaces/Player_menu.rpy", line 232, in execute
    use relationships_screen()
  File "game/TNHUXMod.rpy", line 1500, in execute
    screen relationships_screen():
  File "game/TNHUXMod.rpy", line 1500, in execute
    screen relationships_screen():
  File "game/TNHUXMod.rpy", line 1596, in execute
    if relationships_Entry:
  File "game/TNHUXMod.rpy", line 1677, in execute
    hbox anchor (0.0, 0.5) pos (0.736, 0.286) ysize int(107*game_resolution):
  File "game/TNHUXMod.rpy", line 1678, in execute
    if relationships_Entry.is_in_normal_mood():
  File "game/TNHUXMod.rpy", line 1679, in execute
    use relationships_status(
TypeError: missing a required argument: 'c'

-- Full Traceback ------------------------------------------------------------

Traceback (most recent call last):
  File "game/scripts/locations/bedrooms/bedrooms.rpy", line 89, in script
    menu(menu_location = Player.home):
  File "renpy/ast.py", line 1890, in execute
    choice = renpy.exports.menu(choices, self.set, args, kwargs, item_arguments)
             ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/exports/menuexports.py", line 134, in menu
    rv = renpy.store.menu(new_items)
         ~~~~~~~~~~~~~~~~^^^^^^^^^^^
  File "renpy/exports/menuexports.py", line 424, in display_menu
    rv = renpy.ui.interact(mouse='menu', type=type, roll_forward=roll_forward)
         ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/ui.py", line 301, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/display/core.py", line 2220, in interact
    repeat, rv = self.interact_core(preloads=preloads, trans_pause=trans_pause, pause=pause, pause_start=pause_start, pause_modal=pause_modal, **kwargs) # type: ignore
                 ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^               
  File "renpy/display/core.py", line 2753, in interact_core
    root_widget.visit_all(lambda d : d.per_interact())
    ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/display/displayable.py", line 434, in visit_all
    d.visit_all(callback, seen)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "renpy/display/displayable.py", line 434, in visit_all
    d.visit_all(callback, seen)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "renpy/display/displayable.py", line 434, in visit_all
    d.visit_all(callback, seen)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "renpy/display/screen.py", line 503, in visit_all
    callback(self)
    ~~~~~~~~^^^^^^
  File "renpy/display/core.py", line 2753, in <lambda>
    root_widget.visit_all(lambda d : d.per_interact())
                                     ~~~~~~~~~~~~~~^^ 
  File "renpy/display/screen.py", line 514, in per_interact
    self.update()
    ~~~~~~~~~~~^^
  File "renpy/display/screen.py", line 723, in update
    self.screen.function(**self.scope)
    ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
  File "game/scripts/interfaces/Player_menu.rpy", line 118, in execute
    screen Player_menu(page, giving_gift = False):
  File "game/scripts/interfaces/Player_menu.rpy", line 118, in execute
    screen Player_menu(page, giving_gift = False):
  File "game/scripts/interfaces/Player_menu.rpy", line 138, in execute
    if black_screen[0]:
  File "game/scripts/interfaces/Player_menu.rpy", line 221, in execute
    if menu_page == "database":
  File "game/scripts/interfaces/Player_menu.rpy", line 232, in execute
    use relationships_screen()
  File "game/TNHUXMod.rpy", line 1500, in execute
    screen relationships_screen():
  File "game/TNHUXMod.rpy", line 1500, in execute
    screen relationships_screen():
  File "game/TNHUXMod.rpy", line 1596, in execute
    if relationships_Entry:
  File "game/TNHUXMod.rpy", line 1677, in execute
    hbox anchor (0.0, 0.5) pos (0.736, 0.286) ysize int(107*game_resolution):
  File "game/TNHUXMod.rpy", line 1678, in execute
    if relationships_Entry.is_in_normal_mood():
  File "game/TNHUXMod.rpy", line 1679, in execute
    use relationships_status(
  File "renpy/parameter.py", line 301, in apply
    raise TypeError(msg) from None
TypeError: missing a required argument: 'c'

Windows-11-10.0.26100-SP0 AMD64
Ren'Py 8.4.0.25050403+unofficial
The Null Hypothesis 0.8b1
Wed Aug 13 14:50:47 2025
Btw, I also don't see any way of actually using this cheat mod. There's no button or anything obvious. The original post also doesn't explain how to use it, as far as I can tell. Maybe I missed this?
 

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
I just installed this mod and unfortunately got the following error when in the Journal I clicked on a relationship (Rogue).

I first installed the TNHUXMod and that worked with no issues. Then I installed the cheat mod (the bat file said everything was installed). At this point is when the error started.

Code:
I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/scripts/locations/bedrooms/bedrooms.rpy", line 89, in script
    menu(menu_location = Player.home):
  File "game/scripts/interfaces/Player_menu.rpy", line 118, in execute
    screen Player_menu(page, giving_gift = False):
  File "game/scripts/interfaces/Player_menu.rpy", line 118, in execute
    screen Player_menu(page, giving_gift = False):
  File "game/scripts/interfaces/Player_menu.rpy", line 138, in execute
    if black_screen[0]:
  File "game/scripts/interfaces/Player_menu.rpy", line 221, in execute
    if menu_page == "database":
  File "game/scripts/interfaces/Player_menu.rpy", line 232, in execute
    use relationships_screen()
  File "game/TNHUXMod.rpy", line 1500, in execute
    screen relationships_screen():
  File "game/TNHUXMod.rpy", line 1500, in execute
    screen relationships_screen():
  File "game/TNHUXMod.rpy", line 1596, in execute
    if relationships_Entry:
  File "game/TNHUXMod.rpy", line 1677, in execute
    hbox anchor (0.0, 0.5) pos (0.736, 0.286) ysize int(107*game_resolution):
  File "game/TNHUXMod.rpy", line 1678, in execute
    if relationships_Entry.is_in_normal_mood():
  File "game/TNHUXMod.rpy", line 1679, in execute
    use relationships_status(
TypeError: missing a required argument: 'c'

-- Full Traceback ------------------------------------------------------------

Traceback (most recent call last):
  File "game/scripts/locations/bedrooms/bedrooms.rpy", line 89, in script
    menu(menu_location = Player.home):
  File "renpy/ast.py", line 1890, in execute
    choice = renpy.exports.menu(choices, self.set, args, kwargs, item_arguments)
             ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/exports/menuexports.py", line 134, in menu
    rv = renpy.store.menu(new_items)
         ~~~~~~~~~~~~~~~~^^^^^^^^^^^
  File "renpy/exports/menuexports.py", line 424, in display_menu
    rv = renpy.ui.interact(mouse='menu', type=type, roll_forward=roll_forward)
         ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/ui.py", line 301, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/display/core.py", line 2220, in interact
    repeat, rv = self.interact_core(preloads=preloads, trans_pause=trans_pause, pause=pause, pause_start=pause_start, pause_modal=pause_modal, **kwargs) # type: ignore
                 ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^             
  File "renpy/display/core.py", line 2753, in interact_core
    root_widget.visit_all(lambda d : d.per_interact())
    ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/display/displayable.py", line 434, in visit_all
    d.visit_all(callback, seen)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "renpy/display/displayable.py", line 434, in visit_all
    d.visit_all(callback, seen)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "renpy/display/displayable.py", line 434, in visit_all
    d.visit_all(callback, seen)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "renpy/display/screen.py", line 503, in visit_all
    callback(self)
    ~~~~~~~~^^^^^^
  File "renpy/display/core.py", line 2753, in <lambda>
    root_widget.visit_all(lambda d : d.per_interact())
                                     ~~~~~~~~~~~~~~^^
  File "renpy/display/screen.py", line 514, in per_interact
    self.update()
    ~~~~~~~~~~~^^
  File "renpy/display/screen.py", line 723, in update
    self.screen.function(**self.scope)
    ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
  File "game/scripts/interfaces/Player_menu.rpy", line 118, in execute
    screen Player_menu(page, giving_gift = False):
  File "game/scripts/interfaces/Player_menu.rpy", line 118, in execute
    screen Player_menu(page, giving_gift = False):
  File "game/scripts/interfaces/Player_menu.rpy", line 138, in execute
    if black_screen[0]:
  File "game/scripts/interfaces/Player_menu.rpy", line 221, in execute
    if menu_page == "database":
  File "game/scripts/interfaces/Player_menu.rpy", line 232, in execute
    use relationships_screen()
  File "game/TNHUXMod.rpy", line 1500, in execute
    screen relationships_screen():
  File "game/TNHUXMod.rpy", line 1500, in execute
    screen relationships_screen():
  File "game/TNHUXMod.rpy", line 1596, in execute
    if relationships_Entry:
  File "game/TNHUXMod.rpy", line 1677, in execute
    hbox anchor (0.0, 0.5) pos (0.736, 0.286) ysize int(107*game_resolution):
  File "game/TNHUXMod.rpy", line 1678, in execute
    if relationships_Entry.is_in_normal_mood():
  File "game/TNHUXMod.rpy", line 1679, in execute
    use relationships_status(
  File "renpy/parameter.py", line 301, in apply
    raise TypeError(msg) from None
TypeError: missing a required argument: 'c'

Windows-11-10.0.26100-SP0 AMD64
Ren'Py 8.4.0.25050403+unofficial
The Null Hypothesis 0.8b1
Wed Aug 13 14:50:47 2025
Btw, I also don't see any way of actually using this cheat mod. There's no button or anything obvious. The original post also doesn't explain how to use it, as far as I can tell. Maybe I missed this?
This cheat injector should not be ran with other mods. Even if it applies and runs, that's by sheer luck and cannot be trusted.

As to how to use it, this cheat injector modifies the game's own GUI so that certain UI elements are interact-able. Like where it shows the money, you can click on it to increase the amount of money you have. See the screenshots in the OP for what elements are interact-able as the screenshot circles which elements are interactable. There are a few more features that are in the features sections.
 

mrbombadil

Member
Jul 25, 2024
133
362
82
This cheat injector should not be ran with other mods. Even if it applies and runs, that's by sheer luck and cannot be trusted.

As to how to use it, this cheat injector modifies the game's own GUI so that certain UI elements are interact-able. Like where it shows the money, you can click on it to increase the amount of money you have. See the screenshots in the OP for what elements are interact-able as the screenshot circles which elements are interactable. There are a few more features that are in the features sections.
OK, good to know. I reinstalled the game. Then installed only this cheat mod. Despite a bunch of syntax error messages during the installation the mod does indeed now work.

Thanks!

Of course it would be awesome if in the future there would be compatibility between the cheat mod and the multi-mod since they cover different types of improvement and are both nice.
 

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
OK, good to know. I reinstalled the game. Then installed only this cheat mod. Despite a bunch of syntax error messages during the installation the mod does indeed now work.
There shouldn't be any syntax errors. Syntax errors means the code couldn't be interpreted properly by the interpreter and, hence, cannot be understood or ran. Please post those syntax errors so I can see what's going on.

Of course it would be awesome if in the future there would be compatibility between the cheat mod and the multi-mod since they cover different types of improvement and are both nice.
That's technically impossible. Basically, imagine if there's a book of instructions. I wrote that for step 5, look at page 15. And at page 15, I wrote specialized instructions. Now imagine if a second person said half of page 15 should have their specialized instructions that references page 46. Neither of our instructions would work properly and the person trying to follow the instructions wouldn't know what's going on. That's what's going on here. Unless I work with said mod creators and make sure we don't step on each other's toes and they and/or I run custom checks for each other's code (which is a big pain and error proned), cross compatibility will be not be possible.
 

mrbombadil

Member
Jul 25, 2024
133
362
82
Here's my explanation of how to cheat the anal and deepthroat training.

Open the console (cheat mod) by pressing Shift+o. For each girl use the following commands 32 times. To repeat a command simply press the up key and then enter.

Rogue.History.update("deepthroat")
Rogue.History.update("anal")

Do the same for Jean and Laura.

After this the girls assholes will have loosened so much they can take the largest butt plug with ease (and they say how comfortable it is now). Nice.
 
Last edited:

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
Here's my explanation of how to cheat the anal and deepthroat training.

Open the console (cheat mod) by pressing Shift+o. For each girl use the following commands 32 times. To repeat a command simply press the up key and then enter.

Rogue.History.update("deepthroat")
Rogue.History.update("anal")

Do the same for Jane and Laura.

After this the girls assholes will have loosened so much they can take the largest butt plug with ease (and they say how comfortable it is now). Nice.
I went into that long explanation was for several reasons.
  1. Show people why you can't just to a straight number and that, by doing so, you're literally wiping out code (which is why the game crashes).
  2. Show that there might be other things that are affected if you directly add the event into the history. (Like, as a possible example, the "recent" tracker might be used for something. So you might be missing events or dialogue if the recent tracker wasn't updated.)
  3. Explain that there's a limit as well as why just adding one history event won't change anything that's visible.
  4. Each event update has timestamp attached. Theoretically, RonChon can check to see if someone has cheated or trigger a bad event depending on how many deep throat or anal training there was during a single day. I don't think that's being done now, but it is possible.
If someone is okay with all these risks (because these are persistent changes), go for it. If not, might just want to do it regularly.

If you can just add that might be some risk involved with cheating that like to the post in the game thread, I'd appreciate it. Just a basic "This might cause problems later. Do at your own risk." would be enough.
 

Walkaway

Newbie
Feb 16, 2019
28
12
88
Those just increase the friendship between the two characters. If they're already maxed, it doesn't do anything that you can see. Please note that, so far, only Rogue and Laura can be best friends. It's hard coded into the game.
Thx for the reply, but I tested it with a new save and the character icons for the girls' friendship between eachother isn't interactable for me
 
  • Like
Reactions: mrbombadil

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
Thx for the reply, but I tested it with a new save and the character icons for the girls' friendship between eachother isn't interactable for me
You are correct. It looks like they changed the path of the pictures, which messes with the pattern matching. I'll fix it later today after work.
 

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
You are correct. It looks like they changed the path of the pictures, which messes with the pattern matching. I'll fix it later today after work.
Cheat injector has been updated to V2.2. Fixed to match changes in code that disabled the friendship button. Please remember that any re-application needs to go on a fresh install.
 

mrbombadil

Member
Jul 25, 2024
133
362
82
Thank you sleepingkirby !

I'm not sure if you thought about it already, but do you think in the future you could please make a cheat for the leader board points? I don't know if that's difficult.
 

DatMan

New Member
Jun 27, 2023
4
3
89
I can only imagine how excited sleepingkirby is at the announcement of changes to the code for 8c and beyond :D

Good luck when that comes out though.
 

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
I can only imagine how excited sleepingkirby is at the announcement of changes to the code for 8c and beyond :D

Good luck when that comes out though.
To be honest, I don't think the code base change will be that exciting. RonChon is solidifying the code base. So, probably from my perspective, probably not much will be changed short of a few variables. But that's the thing with code. You never know until you look at it. I've seen some great code come from absolute newbs and I've seen shit code from seasoned professionals and everything in between. The proof is in the pudding.

Thank you sleepingkirby !

I'm not sure if you thought about it already, but do you think in the future you could please make a cheat for the leader board points? I don't know if that's difficult.
I have thought about it and looked into it a while back. But it's similar to deep throat and anal training. It's not a straight number but an aggregate of history/events. So it's semi difficult. Let me take a look after my errands tonight and see if any of that has changed (I think I looked at it back in 0.6).


ETA: Yeah, so I remembered correctly. There's a "leaderboard_score" variable under every character object. But that is evaluated by this function:
Code:
        @property
        def leaderboard_score(self) -> Dict[str, float]:
            score = {"combat": 0.0, "cognitive": 0.0}

            combat_modifier = 3.0*(2.0 if self.check_traits("combat_expert") else 0.5 if self.check_traits("combat_loser") else 1.0)

            score["combat"] = combat_modifier*self.History.check("trained", after = day - (day % 14))

            study_modifier = 1.5*(2.0 if self.check_traits("academically_gifted") else 0.5 if self.check_traits("academically_challenged") else 1.0)
            class_modifier = 3.0*(2.0 if self.check_traits("academically_gifted") else 0.5 if self.check_traits("academically_challenged") else 1.0)

            score["cognitive"] = study_modifier*self.History.check("studied", after = day - (day % 14)) + class_modifier*self.History.check("attended_class", after = day - (day % 14))

            return score
Of all of that, the 2 most important lines are:
Code:
            score["combat"] = combat_modifier*self.History.check("trained", after = day - (day % 14))
            score["cognitive"] = study_modifier*self.History.check("studied", after = day - (day % 14)) + class_modifier*self.History.check("attended_class", after = day - (day % 14))
Which reads "The combat store is the combat modifier times how many items in history that's labelled 'trained' between today and around the start of the week 2 weeks ago". The cognitive is the same, but also adds class attended.

So, the way to increase the score is to just add more items that you've studied or trained. Which, I can add a button somewhere to do that. But:
  1. Is it worth while to add a button that pretty much does the same thing as just training or studying in game?
  2. Where should the button me?
 
Last edited:
  • Like
Reactions: mrbombadil

pepplez

Well-Known Member
Jun 7, 2020
1,049
1,417
307
Of course it would be awesome if in the future there would be compatibility between the cheat mod and the multi-mod since they cover different types of improvement and are both nice.
Then freddygonzo would have to make an extra version, since the screens have been changed. Whether he is willing to do so is another question. The correct installation order would also have to be considered, which could overwhelm some people.


  1. Is it worth while to add a button that pretty much does the same thing as just training or studying in game?
Imho it's not worth the effort but that's your decision in the end.
By the way: If I click on the field "Relationship Status" it raises an error:
click_there.jpg
You don't have permission to view the spoiler content. Log in or register now.
Everything else is working fine.

p.s. I've tested it with the Summoner mod and it seems to run fine with the cheat mod installed.
 
Last edited:

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
Imho it's not worth the effort but that's your decision in the end.
It is, but just because not everyone plays the same way or for the same reason, so I wanted to field some opinions. But also, the same effect can, essentially, be done with resetting time. Study, reset time to morning, study again.

By the way: If I click on the field "Relationship Status" it raises an error:
You don't have permission to view the spoiler content. Log in or register now.
Everything else is working fine.
Huh... Thought I clicked on that last time update. I'll take a look.
 

pepplez

Well-Known Member
Jun 7, 2020
1,049
1,417
307
Huh... Thought I clicked on that last time update. I'll take a look.
Maybe there is no permanent attribute because there is no relationship at the moment at all, just started a new game.
edit: Scratch that, it also crashes later in game.
 
Last edited:

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
Maybe there is no permanent attribute because there is no relationship at the moment at all, just started a new game.
Nope, permanent is part of the base definition:
Code:
    class HistoryClass(object):
        TRACKER_NAMES: Tuple = (
            "immediate",
            "event",
            "recent",
            "last",
            "yesterday",
            "daily",
            "weekly",
            "season",
            "chapter",
            "persistent",
            "permanent")
It's statically defined. I'm not seeing the error on my side. Now, I'm not saying I don't believe this happened because, on my testing, at one point it worked and at one point, it crashed with a different error. Saying that other_c doesn't have a .tag attribute.
Code:
  File "game/scripts/mechanics/utilities.rpy", line 18, in removeCheating
    Player.History.remove(f"cheated_on_{C.tag}_with_{other_C.tag}_flirting_in_public")
                                                     ^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'tag'
But that block of code? Here's how it's written:
Code:
        for other_C in all_Companions:
            if hasattr(other_C, "tag"):
                Player.History.remove(f"cheated_on_{C.tag}_with_{other_C.tag}_flirting_in_public")
                Player.History.remove(f"cheated_on_{C.tag}_with_{other_C.tag}_date")
                Player.History.remove(f"cheated_on_{C.tag}_with_{other_C.tag}_relationship")
                if Player.History.permanent.get(f"cheated_on_{C.tag}_with_{other_C.tag}_flirting_in_public"):
                   del Player.History.permanent[f"cheated_on_{C.tag}_with_{other_C.tag}_flirting_in_public"]
It explicitly says, if other_C DOES have.tag, run the offending line of code. It also says line 18, which that line is not.

Needless to say, 1) that doesn't make any sense. 2) it's something going on with the game itself if it's missing its own static definitions.

Can you extract a fresh copy, reapply the cheat and see if you still get the error? I think python and/or renpy is badly caching code (probably in the pickle file/save) and that's causing all of this.
 
  • Like
Reactions: pepplez

mrbombadil

Member
Jul 25, 2024
133
362
82
So, the way to increase the score is to just add more items that you've studied or trained. Which, I can add a button somewhere to do that. But:
  1. Is it worth while to add a button that pretty much does the same thing as just training or studying in game?
  2. Where should the button me?
Thank you for looking into this and for the explanation. It makes sense, I understand the code now.

1. I do think it would be a cool little feature. Nothing major, but it's helpful to those who don't want to grind through so many study and combat sessions. Instead we could simply click the button once to set the score to e.g. 500 points. That would save a lot of time and grinding. Still, I do understand it might not be a major help if people don't care about the leader board.

So whether or not "it's worth the effort" depends mostly on the degree of coding effort.

One simplistic solution could be to have a button that sets the score to e.g. 500. So something crude like this:

Code:
@property
        def leaderboard_score(self) -> Dict[str, float]:
            score = {"combat": 500, "cognitive": 500}   
            return score
2. There's space for a button in the canvas/frame used for the "Name" table header. I don't know how UIs work with Renpy, so I don't know how easy it is to add a button there. This might be a rough idea:

1755772604642.png
 

pepplez

Well-Known Member
Jun 7, 2020
1,049
1,417
307
Can you extract a fresh copy, reapply the cheat and see if you still get the error? I think python and/or renpy is badly caching code (probably in the pickle file/save) and that's causing all of this.
Sure. Got a file not found error, didn't notice this while patching it the first time, though.
Code:
 Searching for RPA packages
   + Unpacking "archive.rpa" - 452466189 bytes
Could not extract file  from archive: [Errno 2] the requested file . does not exist in the given Ren'Py archive

  Cleaning up temporary files...

  Creating cheat...
./scripts/interfaces/main_menu.rpy patched
./scripts/interfaces/base.rpy patched
./scripts/base/config.rpy patched
./scripts/mechanics/utilities.rpy patched
./scripts/base/player.rpy patched
./scripts/interfaces/Player_menu.rpy patched
./scripts/interfaces/sex.rpy patched
./scripts/mechanics/approval.rpy patched
./scripts/sex/request.rpy patched
./scripts/interfaces/interactions.rpy patched
./scripts/mechanics/movement.rpy patched
    Success! Cheats are now enabled!

  Cleaning up temporary files...

----------------------------------------------------

   Finished!
Started a new game, played until day4, clicked relationship status and got the same error i posted before.
edit: Will make Rogue my girlfriend and cheat on her, we'll see what happens then, will update this post then.

Edit: Done.
lol.jpg here_we_go.jpg
Same error as before.
You don't have permission to view the spoiler content. Log in or register now.
Maybe its on my end and renpy engine is messing with the appdata folder and saves?
 
Last edited:
5.00 star(s) 1 Vote