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

5.00 star(s) 1 Vote

Camrin91

Newbie
Mar 23, 2019
35
8
216
It is no longer visible, but there was a police notice warning that the site was blocked because it was under investigation for child pornography
 

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
It is no longer visible, but there was a police notice warning that the site was blocked because it was under investigation for child pornography
I'm wondering if that's just what they said on their side. The post on pixel drain just says:
Not only are they blocking access to the site (which is bad enough), they are also spreading a terrifying and misleading image of what pixeldrain is being used for
So, if that's the explicit case, they've yet to tell the owner of pixeldrain that.
 

Tommy7358

Member
Jul 25, 2022
384
672
208
Hi sleepingkirby, first of all I want to thank you for your work on the cheat injector and for reporting code errors you find in the game to Boots. I just wanted to ask a quick question to sate my curiosity. I've also asked freddygonzo and pepplez the same question in their thread as well.

Boots has repeatedly said that the dev team are reworking the codebase with ease of modding in mind so disregarding any previous problems or that not all systems are currently in place yet, how actually mod friendly is The Null Hypothesis now in your own opinion?
 
Last edited:

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
Hi sleepingkirby, first of all I want to thank you for your work on the cheat injector and for reporting code errors you find in the game to Boots. I just wanted to ask a quick question to sate my curiosity. I've also asked freddygonzo and pepplez the same question in their thread as well.

Boots has repeatedly said that the dev team are reworking the codebase with ease of modding in mind so disregarding any previous problems or that not all systems are currently in place yet, how actually mod friendly is The Null Hypothesis now in your own opinion?
Let me first say that when someone tells me (at work) that a server, service or algorithm is too slow or too fast, the first thing I ask is "how fast is fast?" or "how slow is slow?" Relative quantifiers are exactly that, relative. I once worked a job where someone complained that 400ms (or some number like that) response time from a server is too slow. But when my coworker calculated the time it takes for the speed of light to travel the curve of the earth from the server's location to his location, it was close to said number, something like 367ms.

All that is to say how easy/friendly is relative. What's easy/friendly to me may not be easy/friendly to someone else. So bear that in mind.

With that said, It is and it's not at the same time. It is in that RonChon did the right thing in building a framework. You define instantiate characters, events, conditions, etc. and then hook them up via conditions and register them. That's the right way to do things. In programming, we call that the (among other things. Long story). It's open for extension but closed for modification. Meaning it's easy(open) to extend functionality of the original code but doesn't require you to modify the original code (closed to modification). But as with anything that has this much functionality, there's a significant learning curve. Which adds (unavoidable) difficulty to how easily someone can mod the game. On top of all of that (something that is avoidable, in my opinion.) is how intuitive some of the placement of the files are. Like, let's look at the directories for this game
Code:
sleepingkirby@AnimalKirby:~/Games/TheNullHypothesis-0.8c-pc/game$ ls -la
total 431320
drwxr-xr-x 16 sleepingkirby sleepingkirby      4096 Oct 11 13:46  .
drwxr-xr-x  5 sleepingkirby sleepingkirby      4096 Oct 13 18:20  ..
-rw-r--r--  1 sleepingkirby sleepingkirby     60656 Oct 10 21:54  agency_fb_bold.ttf
-rw-r--r--  1 sleepingkirby sleepingkirby     57280 Oct 10 21:54  agency_fb.ttf
-rw-r--r--  1 sleepingkirby sleepingkirby 441361846 Oct  6 23:57  archive.rpa
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct  6 19:53  cache
drwxr-xr-x 25 sleepingkirby sleepingkirby      4096 Oct  8 19:41  characters
drwxr-xr-x  9 sleepingkirby sleepingkirby      4096 Oct  8 19:41  core
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct 19 11:24  definitions
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct  8 19:41  displayables
drwxr-xr-x  7 sleepingkirby sleepingkirby      4096 Oct  8 19:41  events
drwxr-xr-x  6 sleepingkirby sleepingkirby      4096 Oct  8 19:41  images
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct 15 18:36  interfaces
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct 14 20:03  inventory
drwxr-xr-x 22 sleepingkirby sleepingkirby      4096 Oct  8 19:41  locations
-rw-r--r--  1 sleepingkirby sleepingkirby     65284 Oct 10 21:55  magneto_bold.ttf
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct 12 00:55  mechanics
-rw-r--r--  1 sleepingkirby sleepingkirby     20744 Oct 10 21:55  raydis.otf
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct 15 21:11  saves
-rw-r--r--  1 sleepingkirby sleepingkirby         9 Oct  6 23:57  script_version.txt
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct  8 19:41  seasons
drwxr-xr-x  7 sleepingkirby sleepingkirby      4096 Oct  8 19:41  sounds
sleepingkirby@AnimalKirby:~/Games/TheNullHypothesis-0.8c-pc/game$ ls -la core
total 36
drwxr-xr-x  9 sleepingkirby sleepingkirby 4096 Oct  8 19:41 .
drwxr-xr-x 16 sleepingkirby sleepingkirby 4096 Oct 11 13:46 ..
drwxr-xr-x  2 sleepingkirby sleepingkirby 4096 Oct 15 19:55 base
drwxr-xr-x  2 sleepingkirby sleepingkirby 4096 Oct 14 16:34 definitions
drwxr-xr-x  2 sleepingkirby sleepingkirby 4096 Oct  8 19:41 displayables
drwxr-xr-x  3 sleepingkirby sleepingkirby 4096 Oct  8 19:41 events
drwxr-xr-x  2 sleepingkirby sleepingkirby 4096 Oct  8 19:41 live2d
drwxr-xr-x  4 sleepingkirby sleepingkirby 4096 Oct 15 21:07 mechanics
drwxr-xr-x  2 sleepingkirby sleepingkirby 4096 Oct  8 19:41 sampling
So there's a "core" directory at the base game directory. But there's also a "base" folder inside it. What's the difference between a base and a core? But also, there's core mechanics (the mechanics folder inside core) but also a mechanics folder in the base game directory. What's the difference between those? And while I'm sure there's a reason for these directories and you can learn and remember pretty easily, they're also forgotten really easily as well. And you'd think all you'd need to do to create a new character is to create the files in the character directory or, at the very most, add the character as part of the definitions (folder), right? Nope, you'd need to add the character into games/seasons/database.rpy into the "Characters" array. And there lies a violation of the open-close principle. You'd have to modify or override the database file (i.e. modify something that should be closed) to add a new character. All this can be dealt with with a little more care and a little organization. But, honestly, for someone whose job isn't a programmer or doesn't have a degree in programming, this is all very good work. Is it perfect? No. But to get this far is very good.

There are more things I can go into detail, but I'm pretty sure you didn't ask the question expecting to get a mini-class on programming. So I'll just summarize what I've said and add a few more things:
  1. Allowing easy code and class usability is a plus for modding
  2. Non-intuitive organization and naming scheme is a minus for modding
  3. The learning curve to understand what's where and what does what, is a minus for modding. But this is unavoidable.
  4. Some functions can be written with more openness in mind. But, really you can't predict everything so I can excuse that.
  5. The range/amount of QOL functions for programmers is a plus modding.

Now, is it more moddable than most renpy games? By leaps and bounds. But, at the same time, renpy itself kind of already encourages that so it's hard to measure how improved this all is compared to base renpy.

So, looking at all of that, yeah, it's a mixed bag. It is "friendly", but "friendly" can range from a neighbor you've only spoken to twice but will run into a burning house to save your life, to a coworker you've known for decades but will easily leave you behind for a promotion/raise. Who's to say decades worth of advice and connections is or isn't worth someone running into a burning house to save your life? I personally think it does its job adequately in being mod friendly. But then, that also depends on how future proof the code is. And no one knows where that will go except for RonChon himself. And, if I'm being brutually honest, this problem of future proofing is EXACTLY the problem with RLE. Spaghetti code is fine if does its job right and doesn't need to be touched. The problem came (for modders) when Oni needed to expand the game's capabilities and change the code existing code. RonChon's code is less susceptible to needing the code to change for future things. But, as you can see, it didn't guarantee that it didn't need to. Which, from a pure modder's perspective, makes little practical difference between the two.

All that is to say, I think it does it's job and intent fine for modding. Who knows what the future will hold. The design that's there now isn't bad, but it isn't perfect either. And it's too much an ask, especially from a non-programmer, to expect it to be perfect.

One last thing. I think most people forget that computers, while near infinitely adaptable, can't be everything to everyone all at once. Law of conservation of mass and energy and all that. And, sometime, the expectation for something to be as such, is itself folly. This is a game. A game built on a bulky framework (renpy) built on a slow and, arguably, dumb language. There's only so much you can do with something like that. We can't, shouldn't expect it to fulfill all of our needs and desire.
 

Tommy7358

Member
Jul 25, 2022
384
672
208
Let me first say that when someone tells me (at work) that a server, service or algorithm is too slow or too fast, the first thing I ask is "how fast is fast?" or "how slow is slow?" Relative quantifiers are exactly that, relative. I once worked a job where someone complained that 400ms (or some number like that) response time from a server is too slow. But when my coworker calculated the time it takes for the speed of light to travel the curve of the earth from the server's location to his location, it was close to said number, something like 367ms.

All that is to say how easy/friendly is relative. What's easy/friendly to me may not be easy/friendly to someone else. So bear that in mind.

With that said, It is and it's not at the same time. It is in that RonChon did the right thing in building a framework. You define instantiate characters, events, conditions, etc. and then hook them up via conditions and register them. That's the right way to do things. In programming, we call that the (among other things. Long story). It's open for extension but closed for modification. Meaning it's easy(open) to extend functionality of the original code but doesn't require you to modify the original code (closed to modification). But as with anything that has this much functionality, there's a significant learning curve. Which adds (unavoidable) difficulty to how easily someone can mod the game. On top of all of that (something that is avoidable, in my opinion.) is how intuitive some of the placement of the files are. Like, let's look at the directories for this game
Code:
sleepingkirby@AnimalKirby:~/Games/TheNullHypothesis-0.8c-pc/game$ ls -la
total 431320
drwxr-xr-x 16 sleepingkirby sleepingkirby      4096 Oct 11 13:46  .
drwxr-xr-x  5 sleepingkirby sleepingkirby      4096 Oct 13 18:20  ..
-rw-r--r--  1 sleepingkirby sleepingkirby     60656 Oct 10 21:54  agency_fb_bold.ttf
-rw-r--r--  1 sleepingkirby sleepingkirby     57280 Oct 10 21:54  agency_fb.ttf
-rw-r--r--  1 sleepingkirby sleepingkirby 441361846 Oct  6 23:57  archive.rpa
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct  6 19:53  cache
drwxr-xr-x 25 sleepingkirby sleepingkirby      4096 Oct  8 19:41  characters
drwxr-xr-x  9 sleepingkirby sleepingkirby      4096 Oct  8 19:41  core
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct 19 11:24  definitions
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct  8 19:41  displayables
drwxr-xr-x  7 sleepingkirby sleepingkirby      4096 Oct  8 19:41  events
drwxr-xr-x  6 sleepingkirby sleepingkirby      4096 Oct  8 19:41  images
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct 15 18:36  interfaces
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct 14 20:03  inventory
drwxr-xr-x 22 sleepingkirby sleepingkirby      4096 Oct  8 19:41  locations
-rw-r--r--  1 sleepingkirby sleepingkirby     65284 Oct 10 21:55  magneto_bold.ttf
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct 12 00:55  mechanics
-rw-r--r--  1 sleepingkirby sleepingkirby     20744 Oct 10 21:55  raydis.otf
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct 15 21:11  saves
-rw-r--r--  1 sleepingkirby sleepingkirby         9 Oct  6 23:57  script_version.txt
drwxr-xr-x  2 sleepingkirby sleepingkirby      4096 Oct  8 19:41  seasons
drwxr-xr-x  7 sleepingkirby sleepingkirby      4096 Oct  8 19:41  sounds
sleepingkirby@AnimalKirby:~/Games/TheNullHypothesis-0.8c-pc/game$ ls -la core
total 36
drwxr-xr-x  9 sleepingkirby sleepingkirby 4096 Oct  8 19:41 .
drwxr-xr-x 16 sleepingkirby sleepingkirby 4096 Oct 11 13:46 ..
drwxr-xr-x  2 sleepingkirby sleepingkirby 4096 Oct 15 19:55 base
drwxr-xr-x  2 sleepingkirby sleepingkirby 4096 Oct 14 16:34 definitions
drwxr-xr-x  2 sleepingkirby sleepingkirby 4096 Oct  8 19:41 displayables
drwxr-xr-x  3 sleepingkirby sleepingkirby 4096 Oct  8 19:41 events
drwxr-xr-x  2 sleepingkirby sleepingkirby 4096 Oct  8 19:41 live2d
drwxr-xr-x  4 sleepingkirby sleepingkirby 4096 Oct 15 21:07 mechanics
drwxr-xr-x  2 sleepingkirby sleepingkirby 4096 Oct  8 19:41 sampling
So there's a "core" directory at the base game directory. But there's also a "base" folder inside it. What's the difference between a base and a core? But also, there's core mechanics (the mechanics folder inside core) but also a mechanics folder in the base game directory. What's the difference between those? And while I'm sure there's a reason for these directories and you can learn and remember pretty easily, they're also forgotten really easily as well. And you'd think all you'd need to do to create a new character is to create the files in the character directory or, at the very most, add the character as part of the definitions (folder), right? Nope, you'd need to add the character into games/seasons/database.rpy into the "Characters" array. And there lies a violation of the open-close principle. You'd have to modify or override the database file (i.e. modify something that should be closed) to add a new character. All this can be dealt with with a little more care and a little organization. But, honestly, for someone whose job isn't a programmer or doesn't have a degree in programming, this is all very good work. Is it perfect? No. But to get this far is very good.

There are more things I can go into detail, but I'm pretty sure you didn't ask the question expecting to get a mini-class on programming. So I'll just summarize what I've said and add a few more things:
  1. Allowing easy code and class usability is a plus for modding
  2. Non-intuitive organization and naming scheme is a minus for modding
  3. The learning curve to understand what's where and what does what, is a minus for modding. But this is unavoidable.
  4. Some functions can be written with more openness in mind. But, really you can't predict everything so I can excuse that.
  5. The range/amount of QOL functions for programmers is a plus modding.

Now, is it more moddable than most renpy games? By leaps and bounds. But, at the same time, renpy itself kind of already encourages that so it's hard to measure how improved this all is compared to base renpy.

So, looking at all of that, yeah, it's a mixed bag. It is "friendly", but "friendly" can range from a neighbor you've only spoken to twice but will run into a burning house to save your life, to a coworker you've known for decades but will easily leave you behind for a promotion/raise. Who's to say decades worth of advice and connections is or isn't worth someone running into a burning house to save your life? I personally think it does its job adequately in being mod friendly. But then, that also depends on how future proof the code is. And no one knows where that will go except for RonChon himself. And, if I'm being brutually honest, this problem of future proofing is EXACTLY the problem with RLE. Spaghetti code is fine if does its job right and doesn't need to be touched. The problem came (for modders) when Oni needed to expand the game's capabilities and change the code existing code. RonChon's code is less susceptible to needing the code to change for future things. But, as you can see, it didn't guarantee that it didn't need to. Which, from a pure modder's perspective, makes little practical difference between the two.

All that is to say, I think it does it's job and intent fine for modding. Who knows what the future will hold. The design that's there now isn't bad, but it isn't perfect either. And it's too much an ask, especially from a non-programmer, to expect it to be perfect.

One last thing. I think most people forget that computers, while near infinitely adaptable, can't be everything to everyone all at once. Law of conservation of mass and energy and all that. And, sometime, the expectation for something to be as such, is itself folly. This is a game. A game built on a bulky framework (renpy) built on a slow and, arguably, dumb language. There's only so much you can do with something like that. We can't, shouldn't expect it to fulfill all of our needs and desire.
Thanks for the detailed reponse. I actually appreciate you going through the trouble of breaking it down to a non-programmer like me and believe it or not I have read through all of your recent posts even if I don't completely understand all of it. Who'd thought I'd be intently reading about a programmer's thoughts on a porn game forum?

Just a couple of more questions and then I'll stop bothering you for now. So if I'm reading this correctly essentially what you're saying is that TNH's better than most Ren'Py games and gets more correct than not in terms of moddability but Ren'Py itself is based on an older and more cumbersome language right? And possibly it could get messy very quickly if in the future more features need to be added like with RLE?

Would the TNH be more resilient to such a scenario as I understand you saying and would you say whether or not the remaining systems yet to be added in v0.9 and v1.0 affect your current answer in anyway?

Thanks in advance. Heh, I'll probably bug you with this same question again when v1.0/v1.1 eventually arrives.
 

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
Thanks for the detailed reponse. I actually appreciate you going through the trouble of breaking it down to a non-programmer like me and believe it or not I have read through all of your recent posts even if I don't completely understand all of it. Who'd thought I'd be intently reading about a programmer's thoughts on a porn game forum?

Just a couple of more questions and then I'll stop bothering you for now. So if I'm reading this correctly essentially what you're saying is that TNH's better than most Ren'Py games and gets more correct than not in terms of moddability but Ren'Py itself is based on an older and more cumbersome language right? And possibly it could get messy very quickly if in the future more features need to be added like with RLE?

Would the TNH be more resilient to such a scenario as I understand you saying and would you say whether or not the remaining systems yet to be added in v0.9 and v1.0 affect your current answer in anyway?

Thanks in advance. Heh, I'll probably bug you with this same question again when v1.0/v1.1 eventually arrives.
Don't worry about whether or not you're bugging me with questions like these. I got my degree by choice. I enjoy talking about this. If my wife isn't forcing me to rest today, I'd be programming right now. Hell, consider this. I got my degree in the US. No college loans, no scholarships, no family help. I paid, out of my own pocket, for my degree. That should show how much I actually like the subject.

Who'd thought I'd be intently reading about a programmer's thoughts on a porn game forum?
I'll pass on to you what was passed on to me before I got into programing by a CS Harvard graduate. Computers are just a tool. No different than a hammer or a pencil. As such, anything from building the Eiffel tower to making porn, all requires tools.

So if I'm reading this correctly essentially what you're saying is that TNH's better than most Ren'Py games and gets more correct than not in terms of moddability
Correct. But keep in mind that most games were not built with the idea of moddability in mind. So it's a little unfair to say that game A is better than game B for moddability when game A is built as such and game B was built just to be a game. It'd be like comparing a car to an airplane and say "The airplane can fly and the car can't." Is it a good that a game can do both? Yes. But again, not everything can be everything for everyone. Which, in our example of cars vs airplanes, is why the flying car are such an intisive idea.

Ren'Py itself is based on an older and more cumbersome language right?
Python is actually one of the younger languages. But, in my opinion, it's one of the worse ones. But it is one of the slower ones (a language being newer doesn't mean it's faster and a language being slower doesn't mean it's older. I know it feels like it should, but it doesn't). In fact, you can see here (note that this source is not the end all be all of programming speed tests. But for our purposes, it's a good enough source):
1760869306082.png

It's cramped, but you can see that python 3.11 is actually near the bottom of the list. Slower than even Java, and that's saying a lot (I've had a professor that once had her team convert a Java program into C++ for performance reasons. They got a 20x performance boost. Not 20%, 20 times). But also, yes, python is a cumbersome language. As with most interpreted languages (i.e. programming languages that don't need to be compiled down to a binary. These languages include Perl, Ruby, Python, Javascript and PHP. The opposite of this are languages like C, C++, C#, Java, Rust and GO), due to the convenience of not needing to be compiled to rule, they will always be more cumbersome (and slower) than languages that need to be compiled. But even for compiled languages, Python is one of the slower and dumber ones (in my opinion. Which I can back up, but there are die-hard python users out there that swear python's the best language. But usually, those views come out to more zealotry than statistical proof). I can get into that more if you want, but, for now, just take my word for it.

And possibly it could get messy very quickly if in the future more features need to be added like with RLE?
Possibly, but not likely. As I mentioned before, RonChon did a good job in allowing people the ability to expand/extend the game from its base. But if, in the future, RonChon discovers that the base of the game isn't enough and needs to be re-written, then, yeah, it'd be no different than with RLE. But, most likely, it will not be as bad as RLE. This ties back to the "how fast is fast?" point. Both have the possibility of things being rewritten to the point where any mods for the game need to be rewritten. But there's a higher likelihood with RLE than with TNH.

Would the TNH be more resilient to such a scenario as I understand you saying and would you say whether or not the remaining systems yet to be added in v0.9 and v1.0 affect your current answer in anyway?
I don't foresee it affecting my answer, but it all depends on implementation. To be frank, I don't think the rewrite between 0.8b and 0.8c was really needed. Is it better? Yes. To what degree? That's debatable. So, basically, with this recent rewrite, there shouldn't* (terms and conditions may apply) be a need for another rewrite. But you never know. Unless I know the full scope of the game, I can't say for sure.

Heh, I'll probably bug you with this same question again when v1.0/v1.1 eventually arrives.
Unless there's another massive rewrite of the game's core (which, there shouldn't be), I doubt anything will change.


I feel like I should also explain somethings about mods versus the game itself. Judging by your questions, I think you might have a (common) misconception as to mods for games, in particular, this game.

So when people talk about mods for video games, like say, N64 Ocarina of Time randomizer, the mod is actually a modification of the game binary itself. Mods for this game is closer to a DLC. This game, first and foremost, identifies and instantiates pieces, characters, items, events, schedulers, triggers etc., then reads different definitions and logic to form the game. One may think, "How is this different from the OoT randomizer?" The difference is, you can add your own file to append or supersede other files, definitions, events, etc. to do things like, add new characters or events or clothing. And that's the mod. Remember when I linked this conversation? This is a good example of 2 different type of mods. I call mine a "cheat injector" because (among other things) I'm modifying the base code of the game. The TNHUXMod is the other type. That mod is a .rpy file that utilizes, adds to and supercedes existing game code to make something new. And this is exactly why the TNHUXMod crashed with my cheat injector. TNHUXMod was using a core game function for its own purposes. Which, it's allowed, and encouraged, to do as that was RonChon's intent. This cheat injector, however, had modified one of the functions that TNHUXMod was using, thus, making the code generate an error.
You know what, this might be better explained with a practical example.

TNHUXMod was using this function:
Code:
screen relationships_status(status, **properties)
to make its own GUI. It would make a call like
Code:
use relationships_status('Happy')
To show a GUI element. By the way, this function makes the "Happy" or "Horny" or "Mad" icon in the "Mood" in the menu for Rogue and other LI's.

But my injector redefined that function to this:
Code:
screen relationships_status(status, c, **properties)
So, all the sudden, TNHUXMod is trying to run this:
Code:
use relationships_status('Happy')
When my injector redefined it to be called like this:
Code:
use relationships_status('Happy', Rogue)
where the additional 'c' is for a character.

So yeah, you can see why the game crashed when the two were used together since it was defined to require the code to pass in a character as part of its call.

Now, why is knowing the difference between the 2 important? Well, a mod in the latter aspect, the one that uses the game's own code and functions, etc. to extend or change the game, depends on said functions and code. The two have to, in essence, speak the same language. As with the example above, if mod tells the game "Say apple", but the game doesn't know what the word "Say" means, and, instead, knows the command "Speak", the mod is going to have problems telling the game what to do. When RonChon rewrite the core of the game, a lot of these "verbages" changed. Like, literally, the function called "check_approval" was renamed to "approval_check". What is and isn't a base part of the game and what is the core part of the game got moved and/or renamed.
Now, why would someone need to redefine "the language", you might ask? I mean, we're speaking English and it's working just fine. Except it doesn't always. If you need to describe, say, Chinese idioms, you're in trouble. Or, there are some words in Chinese that just aren't translatable because the English language doesn't have the same idea. Like the word 養. You can translate that as adopt. Or raise. Or to nuture. Or to make healthy. Or support. Or give birth. But the truth is, none of those, by themselves is the right definition. That word's meaning is an intersection of all the words I just listed. So, if you want the word 養, in it's most accurate, purest form in English, you need an entirely new word that doesn't exist. Which means, those wanting to use that word will need to change what/how they're saying things. But this also means that any older literature might need annotations for modern readers that didn't know the old ways of expressing that and/or corrections if the old authors really meant 養 when they wrote "adopt" or "foster" but didn't have the vocabulary for it. So, in just adding one new word, a lot of things needed to be changed. This is why you never know if future features will require a rewrite of the code. If the feature does not and cannot exist with the current design of the game, and the feature NEEDS to exist, the game will have to change for to accomodate it. Which changes functions (the verbage) which will require any mods to change how it talks to the main game.
Of course, if you've designed a solution with enough foresight that said feature can be included without a problem, no change is needed. Which loops back to my original answer of it depends on the solution and design, but also, you can't predict everything.
 

Tommy7358

Member
Jul 25, 2022
384
672
208
Don't worry about whether or not you're bugging me with questions like these. I got my degree by choice. I enjoy talking about this. If my wife isn't forcing me to rest today, I'd be programming right now. Hell, consider this. I got my degree in the US. No college loans, no scholarships, no family help. I paid, out of my own pocket, for my degree. That should show how much I actually like the subject.


I'll pass on to you what was passed on to me before I got into programing by a CS Harvard graduate. Computers are just a tool. No different than a hammer or a pencil. As such, anything from building the Eiffel tower to making porn, all requires tools.


Correct. But keep in mind that most games were not built with the idea of moddability in mind. So it's a little unfair to say that game A is better than game B for moddability when game A is built as such and game B was built just to be a game. It'd be like comparing a car to an airplane and say "The airplane can fly and the car can't." Is it a good that a game can do both? Yes. But again, not everything can be everything for everyone. Which, in our example of cars vs airplanes, is why the flying car are such an intisive idea.


Python is actually one of the younger languages. But, in my opinion, it's one of the worse ones. But it is one of the slower ones (a language being newer doesn't mean it's faster and a language being slower doesn't mean it's older. I know it feels like it should, but it doesn't). In fact, you can see here (note that this source is not the end all be all of programming speed tests. But for our purposes, it's a good enough source):
View attachment 5356582

It's cramped, but you can see that python 3.11 is actually near the bottom of the list. Slower than even Java, and that's saying a lot (I've had a professor that once had her team convert a Java program into C++ for performance reasons. They got a 20x performance boost. Not 20%, 20 times). But also, yes, python is a cumbersome language. As with most interpreted languages (i.e. programming languages that don't need to be compiled down to a binary. These languages include Perl, Ruby, Python, Javascript and PHP. The opposite of this are languages like C, C++, C#, Java, Rust and GO), due to the convenience of not needing to be compiled to rule, they will always be more cumbersome (and slower) than languages that need to be compiled. But even for compiled languages, Python is one of the slower and dumber ones (in my opinion. Which I can back up, but there are die-hard python users out there that swear python's the best language. But usually, those views come out to more zealotry than statistical proof). I can get into that more if you want, but, for now, just take my word for it.


Possibly, but not likely. As I mentioned before, RonChon did a good job in allowing people the ability to expand/extend the game from its base. But if, in the future, RonChon discovers that the base of the game isn't enough and needs to be re-written, then, yeah, it'd be no different than with RLE. But, most likely, it will not be as bad as RLE. This ties back to the "how fast is fast?" point. Both have the possibility of things being rewritten to the point where any mods for the game need to be rewritten. But there's a higher likelihood with RLE than with TNH.


I don't foresee it affecting my answer, but it all depends on implementation. To be frank, I don't think the rewrite between 0.8b and 0.8c was really needed. Is it better? Yes. To what degree? That's debatable. So, basically, with this recent rewrite, there shouldn't* (terms and conditions may apply) be a need for another rewrite. But you never know. Unless I know the full scope of the game, I can't say for sure.


Unless there's another massive rewrite of the game's core (which, there shouldn't be), I doubt anything will change.


I feel like I should also explain somethings about mods versus the game itself. Judging by your questions, I think you might have a (common) misconception as to mods for games, in particular, this game.

So when people talk about mods for video games, like say, N64 Ocarina of Time randomizer, the mod is actually a modification of the game binary itself. Mods for this game is closer to a DLC. This game, first and foremost, identifies and instantiates pieces, characters, items, events, schedulers, triggers etc., then reads different definitions and logic to form the game. One may think, "How is this different from the OoT randomizer?" The difference is, you can add your own file to append or supersede other files, definitions, events, etc. to do things like, add new characters or events or clothing. And that's the mod. Remember when I linked this conversation? This is a good example of 2 different type of mods. I call mine a "cheat injector" because (among other things) I'm modifying the base code of the game. The TNHUXMod is the other type. That mod is a .rpy file that utilizes, adds to and supercedes existing game code to make something new. And this is exactly why the TNHUXMod crashed with my cheat injector. TNHUXMod was using a core game function for its own purposes. Which, it's allowed, and encouraged, to do as that was RonChon's intent. This cheat injector, however, had modified one of the functions that TNHUXMod was using, thus, making the code generate an error.
You know what, this might be better explained with a practical example.

TNHUXMod was using this function:
Code:
screen relationships_status(status, **properties)
to make its own GUI. It would make a call like
Code:
use relationships_status('Happy')
To show a GUI element. By the way, this function makes the "Happy" or "Horny" or "Mad" icon in the "Mood" in the menu for Rogue and other LI's.

But my injector redefined that function to this:
Code:
screen relationships_status(status, c, **properties)
So, all the sudden, TNHUXMod is trying to run this:
Code:
use relationships_status('Happy')
When my injector redefined it to be called like this:
Code:
use relationships_status('Happy', Rogue)
where the additional 'c' is for a character.

So yeah, you can see why the game crashed when the two were used together since it was defined to require the code to pass in a character as part of its call.

Now, why is knowing the difference between the 2 important? Well, a mod in the latter aspect, the one that uses the game's own code and functions, etc. to extend or change the game, depends on said functions and code. The two have to, in essence, speak the same language. As with the example above, if mod tells the game "Say apple", but the game doesn't know what the word "Say" means, and, instead, knows the command "Speak", the mod is going to have problems telling the game what to do. When RonChon rewrite the core of the game, a lot of these "verbages" changed. Like, literally, the function called "check_approval" was renamed to "approval_check". What is and isn't a base part of the game and what is the core part of the game got moved and/or renamed.
Now, why would someone need to redefine "the language", you might ask? I mean, we're speaking English and it's working just fine. Except it doesn't always. If you need to describe, say, Chinese idioms, you're in trouble. Or, there are some words in Chinese that just aren't translatable because the English language doesn't have the same idea. Like the word 養. You can translate that as adopt. Or raise. Or to nuture. Or to make healthy. Or support. Or give birth. But the truth is, none of those, by themselves is the right definition. That word's meaning is an intersection of all the words I just listed. So, if you want the word 養, in it's most accurate, purest form in English, you need an entirely new word that doesn't exist. Which means, those wanting to use that word will need to change what/how they're saying things. But this also means that any older literature might need annotations for modern readers that didn't know the old ways of expressing that and/or corrections if the old authors really meant 養 when they wrote "adopt" or "foster" but didn't have the vocabulary for it. So, in just adding one new word, a lot of things needed to be changed. This is why you never know if future features will require a rewrite of the code. If the feature does not and cannot exist with the current design of the game, and the feature NEEDS to exist, the game will have to change for to accomodate it. Which changes functions (the verbage) which will require any mods to change how it talks to the main game.
Of course, if you've designed a solution with enough foresight that said feature can be included without a problem, no change is needed. Which loops back to my original answer of it depends on the solution and design, but also, you can't predict everything.
Phew... I can feel my brain actively working reading through your post. So most mods are likely to be based on using the game's base mod superceding them with the the game's code being more accomodating to this type of mod; while the rare few mods like yours straight up modify and replace the base code. From there I think it doesn't take a genius to figure out that mods that rely on base game code won't be running well with mods that literally replace said base code to function.
 

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
The first few times I tried that it didn't work, but shortly before I saw this reply it did. Weird. Maybe I was too early into chapter 1 for it?
Yeah, you're right. It looks like RonChon split the XP bar at level one and the rest of the levels.
Code:
    if Player.XP >= Player.XP_goal:
        add "images/interfaces/[interface_resolution]/Player_menu/skills_xp_bar.webp" anchor (1.0, 0.5) pos (0.921, 0.285) zoom interface_adjustment
    elif Player.level == 1:
        bar value Player.XP range Player.XP_goal anchor (1.0, 0.5) pos (0.921, 0.285) xysize (int(277 * game_resolution), int(24 * game_resolution)):
            left_bar At(f"images/interfaces/{interface_resolution}/Player_menu/skills_xp_bar.webp", interface_zoom)
            right_bar At(f"images/interfaces/{interface_resolution}/Player_menu/skills_xp_empty_bar.webp", interface_zoom)

            thumb None
            thumb_offset 0
    else:
        bar value FieldValue(Player, "XP", Player.XP_goal) range (Player.XP_goal) anchor (1.0, 0.5) pos (0.921, 0.285) xysize (int(277 * game_resolution), int(24 * game_resolution)):
            left_bar At(f"images/interfaces/{interface_resolution}/Player_menu/skills_xp_bar.webp", interface_zoom)
            right_bar At(f"images/interfaces/{interface_resolution}/Player_menu/skills_xp_empty_bar.webp", interface_zoom)

            thumb None
            thumb_offset 0
I think I initially let it go because I thought that, just by getting through the dialogue stuff, you should gain a level. Maybe I'm wrong. I'll take a look at it tomorrow.
 

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
Cheat injector updated to v2.8. As always, please apply to a fresh copy of the game. A bug was found where the exp bar for the first level wasn't made into a slider. That's been fixed.
 

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
I have made all what say the instructions... but... nothing! I dont know what more I can add about that
And you've also given me nothing so I don't know what I can reply to besides "It does work". Because "it doesn't work" ranges from "The script had an error" to "A button doesn't work." to "I don't know what I'm looking for." Hell, I've had people that tell me "It didn't work. I installed it." when what they did to "install" was download the .bat file into the game directory. Like, I've literally posted screenshots on the OP showing that it does work. I've even added a new screenshot as of this latest version so it does work. All I have is your word that "it doesn't work" versus me seeing, making and using the cheat that it does.
 

swiftstack

New Member
Nov 3, 2021
6
2
61
sleepingkirby, thank you very much for all your hard work on this!

Unfortunately, the mod isn't activating for me either, with a fresh copy of the game and the latest patch. There are no clickable buttons, no XP slider, no "cheat enabled" message. Only the console log works, which is the only sign that the patch worked at all.

Here's the patch install log, for reference. Are there any other logs I can help provide?

Bash:
$ ./TNH\ Inject.sh

#####################################################################################################################################################################################################################################################


The Null Hypothesis Cheat Injector

   Vesrion: 2.8
   by Sleepingkirby
   Inspired/based on RL Cheat Injector by SLDR @ F95zone.com
#####################################################################################################################################################################################################################################################


 Checking if modification has already been done...
 No backup's found. Safe to progress.

 Checking to make sure requirements are met.




Files to be editted not found. Is it still in the archive.rpa?


 Rpatool missing. Downloading
--2025-10-26 00:07:53--  https://raw.githubusercontent.com/Shizmob/rpatool/master/rpatool
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 18594 (18K) [text/plain]
Saving to: ‘rpatool’

rpatool                                                       100%[==============================================================================================================================================>]  18.16K  --.-KB/s    in 0.001s

2025-10-26 00:07:53 (14.0 MB/s) - ‘rpatool’ saved [18594/18594]

 Extracting archive.rpa...
../renpy/common/00console.rpy patched
./core/mechanics/utilities.rpy patched
./interfaces/Player_menu.rpy patched
./interfaces/sex.rpy patched
./core/mechanics/approval.rpy patched
./core/mechanics/sex/request.rpy patched
./interfaces/interactions.rpy patched
./core/mechanics/clothing.rpy patched
./core/mechanics/behavior.rpy patched
./definitions/player.rpy patched
./interfaces/phone.rpy patched
./interfaces/base.rpy patched
./interfaces/main_menu.rpy patched
DONE!
 

sleepingkirby

Well-Known Member
Aug 8, 2017
1,321
1,955
262
sleepingkirby, thank you very much for all your hard work on this!

Unfortunately, the mod isn't activating for me either, with a fresh copy of the game and the latest patch. There are no clickable buttons, no XP slider, no "cheat enabled" message. Only the console log works, which is the only sign that the patch worked at all.

Here's the patch install log, for reference. Are there any other logs I can help provide?

Bash:
$ ./TNH\ Inject.sh

#####################################################################################################################################################################################################################################################


The Null Hypothesis Cheat Injector

   Vesrion: 2.8
   by Sleepingkirby
   Inspired/based on RL Cheat Injector by SLDR @ F95zone.com
#####################################################################################################################################################################################################################################################


Checking if modification has already been done...
No backup's found. Safe to progress.

Checking to make sure requirements are met.




Files to be editted not found. Is it still in the archive.rpa?


Rpatool missing. Downloading
--2025-10-26 00:07:53--  https://raw.githubusercontent.com/Shizmob/rpatool/master/rpatool
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 18594 (18K) [text/plain]
Saving to: ‘rpatool’

rpatool                                                       100%[==============================================================================================================================================>]  18.16K  --.-KB/s    in 0.001s

2025-10-26 00:07:53 (14.0 MB/s) - ‘rpatool’ saved [18594/18594]

Extracting archive.rpa...
../renpy/common/00console.rpy patched
./core/mechanics/utilities.rpy patched
./interfaces/Player_menu.rpy patched
./interfaces/sex.rpy patched
./core/mechanics/approval.rpy patched
./core/mechanics/sex/request.rpy patched
./interfaces/interactions.rpy patched
./core/mechanics/clothing.rpy patched
./core/mechanics/behavior.rpy patched
./definitions/player.rpy patched
./interfaces/phone.rpy patched
./interfaces/base.rpy patched
./interfaces/main_menu.rpy patched
DONE!
Honestly, just providing that tells me a lot. RPAtool was downloaded fine. The files that needs to be modified are there. It ran correctly with no errors. Even just telling me that there's no GUI elements, no messages, etc. says a lot.

Can you please run this command in the game directory:
Code:
diff interfaces/Player_menu.rpy interfaces/Player_menu.rpy.orig
And give me the output?

Oh, and what OS (name and version. i.e. MacOS 15, Ubuntu 22.04, etc.) and game version are you on?


ETA: If I had to take a blind guess as to what's going on, I'd guess you're applying the cheat injector to game version v0.8b or earlier. But definitely please provide the above info asked.
 
Last edited:

swiftstack

New Member
Nov 3, 2021
6
2
61
I figured it out!

This mod and freddygonzo's TNHUXMod gamplay experience mod are not compatible. They both modify the interface, and
`TNHUXMod.rpy` was overriding this mod's interface patches.

Just for your reference, I'm running macOS 15.6.1 and I've attached a diff file as requested. But uninstalling TNHUXMod solved all my issues.

Thank you for your help!

Bash:
% grep version ./definitions/config.rpy

define config.version = "0.8c"
Bash:
% diff -u interfaces/Player_menu.rpy.orig interfaces/Player_menu.rpy

--- interfaces/Player_menu.rpy.orig    2025-10-26 00:07:54
+++ interfaces/Player_menu.rpy    2025-10-26 00:07:54
@@ -764,8 +764,8 @@
     text "Name" anchor (0.5, 0.5) pos (0.114, 0.306):
         size 26

-    text "Points" anchor (0.5, 0.5) pos (0.226, 0.306):
-        size 26
+    textbutton "{size=26}" + "Points" anchor (0.5, 0.5) pos (0.226, 0.306):
+        action Function(Player.History.update, "trained" if skills_leaderboard_type == "combat" else "studied")

     vbox anchor (0.0, 0.0) pos (0.0585, 0.328) xysize (int(729 * game_resolution), 0.557):
         spacing 2
@@ -901,10 +901,8 @@

         size 30

-    text "[Player.skill_points]" anchor (0.5, 0.5) pos (0.9, 0.239):
-        font "agency_fb.ttf"
-
-        size 30
+    textbutton "{size=30}{font=agency_fb.ttf}" + "[Player.skill_points]" anchor (0.5, 0.5) pos (0.9, 0.239):
+        action Function(Player.History.update, "bought_skill_point")

     add "images/interfaces/[interface_resolution]/Player_menu/skills.webp" anchor (0.5, 0.5) pos (0.9145, 0.239) zoom 0.3 * interface_adjustment

@@ -916,14 +914,14 @@
     if Player.XP >= Player.XP_goal:
         add "images/interfaces/[interface_resolution]/Player_menu/skills_xp_bar.webp" anchor (1.0, 0.5) pos (0.921, 0.285) zoom interface_adjustment
     elif Player.level == 1:
-        bar value Player.XP range Player.XP_goal anchor (1.0, 0.5) pos (0.921, 0.285) xysize (int(277 * game_resolution), int(24 * game_resolution)):
+        bar value FieldValue(Player, "XP", Player.XP_goal) range(Player.XP_goal) anchor (1.0, 0.5) pos (0.921, 0.285) xysize (int(277 * game_resolution), int(24 * game_resolution)):
             left_bar At(f"images/interfaces/{interface_resolution}/Player_menu/skills_xp_bar.webp", interface_zoom)
             right_bar At(f"images/interfaces/{interface_resolution}/Player_menu/skills_xp_empty_bar.webp", interface_zoom)

             thumb None
             thumb_offset 0
     else:
-        bar value (Player.XP - Player.XP_goal / 1.75) range (Player.XP_goal - Player.XP_goal / 1.75) anchor (1.0, 0.5) pos (0.921, 0.285) xysize (int(277 * game_resolution), int(24 * game_resolution)):
+        bar value FieldValue(Player, "XP", Player.XP_goal) range (Player.XP_goal) anchor (1.0, 0.5) pos (0.921, 0.285) xysize (int(277 * game_resolution), int(24 * game_resolution)):
             left_bar At(f"images/interfaces/{interface_resolution}/Player_menu/skills_xp_bar.webp", interface_zoom)
             right_bar At(f"images/interfaces/{interface_resolution}/Player_menu/skills_xp_empty_bar.webp", interface_zoom)

@@ -1347,8 +1345,8 @@
     text "CASH{alpha=0.0}_{/alpha}" anchor (0.0, 0.5) pos (0.673, 0.905):
         size 45

-    text "$[Player.cash]" anchor (1.0, 0.5) pos (0.9265, 0.905):
-        size 45
+    textbutton "{size=45}" + "$[Player.cash]" anchor (1.0, 0.5) pos (0.9265, 0.905):
+        action SetVariable("Player.cash", int(Player.cash) + int(50000))

 screen cannot_gift_screen(Character, Item, message = "Cannot give [Character.name] the [Item.name]."):
     modal True
@@ -2188,10 +2186,8 @@

         add "images/interfaces/[interface_resolution]/Player_menu/relationships_[status].webp" anchor (0.5, 0.5) pos (0.5, 0.35) zoom high_resolution_interface_adjustment

-        text "[status.upper()]" anchor (0.5, 0.5) pos (0.5, 0.85):
-            size properties.get("text_size", 16)
-
-            color properties.get("text_color", "#000000")
+        textbutton "{size=[properties.get(\"text_size\", 16)]}{color=[properties.get(\"text_color\", \"#000000\")]}" + "[status.upper()]" anchor (0.5, 0.5) pos (0.5, 0.85):
+            action SetDict(properties.get("char")._status, status, 0)

 screen relationships_tab(action, button_text, **properties):
     button anchor properties.get("anchor", (0.0, 0.0)) pos properties.get("pos", (0.0, 0.0)) xysize properties.get("xysize", (None, None)):
@@ -2316,22 +2312,14 @@

         add "images/interfaces/[interface_resolution]/Player_menu/relationships_love.webp" zoom interface_adjustment

-        text "[relationships_Entry.love]" anchor (0.5, 0.5) pos (0.435, 0.4655):
-            font "agency_fb.ttf"
-
-            size 30
+        textbutton "{size=30}{font=agency_fb.ttf}" + "[relationships_Entry.love]" anchor (0.5, 0.5) pos (0.435, 0.4655):
+            action SetField(relationships_Entry, "love", relationships_Entry.love + 100)

-            color "#000000"
-
         add "images/interfaces/[interface_resolution]/Player_menu/relationships_trust.webp" zoom interface_adjustment

-        text "[relationships_Entry.trust]" anchor (0.5, 0.5) pos (0.435, 0.5065):
-            font "agency_fb.ttf"
+        textbutton "{size=30}{font=agency_fb.ttf}" + "[relationships_Entry.trust]" anchor (0.5, 0.5) pos (0.435, 0.5065):
+            action SetField(relationships_Entry, "trust", relationships_Entry.trust + 100)

-            size 30
-
-            color "#000000"
-
         text "PUBLIC NAME" anchor (0.0, 0.5) pos (0.495, 0.242):
             font "agency_fb.ttf"

@@ -2342,11 +2330,9 @@

             size 28

-        text "RELATIONSHIP STATUS" anchor (0.0, 0.5) pos (0.495, 0.297):
-            font "agency_fb.ttf"
+        textbutton "{size=28}{font=agency_fb.ttf} RELATIONSHIP STATUS" anchor (0.0, 0.5) pos (0.495, 0.297):
+            action Function(removeCheating, relationships_Entry)

-            size 28
-
         if relationships_Entry not in Partners:
             text "Single" anchor (1.0, 0.5) pos (0.713, 0.297):
                 font "agency_fb.ttf"
@@ -2400,18 +2386,21 @@
             if relationships_Entry.is_in_normal_mood():
                 use relationships_status(
                     "happy",
+                    char = relationships_Entry,
                     text_color = "#00ff06",
                 )

             if relationships_Entry.get_status() == "mad":
                 use relationships_status(
                     "mad",
+                    char = relationships_Entry,
                     text_color = "#f00d48",
                 )

             if relationships_Entry.status["horny"] or relationships_Entry.status["nympho"]:
                 use relationships_status(
                     "horny",
+                    char = relationships_Entry,
                     text_color = "#dd64e8",
                 )

@@ -2419,6 +2408,7 @@
                 if relationships_Entry.status.get(status, False):
                     use relationships_status(
                         status,
+                        char = relationships_Entry,
                         text_color = color,
                     )

@@ -2470,7 +2460,10 @@
                     $ friendship = relationships_Entry.get_friendship(getattr(store, C))

                     fixed xysize (int(135 * game_resolution), int(195 * game_resolution)):
-                        add "images/interfaces/full/photos/[C].webp" align (0.5, 0.5) zoom 0.13
+                        imagebutton idle f"images/interfaces/full/photos/{C}.webp" align (0.5, 0.5):
+                            at transform:
+                                zoom 0.13
+                            action SetDict(relationships_Entry.friendship, f"{C}", relationships_Entry.friendship[C] + 50)

                         add "images/interfaces/[interface_resolution]/Player_menu/relationships_[friendship].webp" align (0.5, 0.5) zoom interface_adjustment
 
  • Like
Reactions: sleepingkirby
5.00 star(s) 1 Vote