There aren't many games that have you build relationships with infinite NPCs.
"infinite" NPCs would have to be coded differently to avoid performance issues.
If you move and modify every NPC on each time step it's simply a lot of processing, see for example HHS+ or Strive for Power: Conquest
A workaround would be semi-randomly populating the cell the player is in and then only updating those NPCs, but that would need a complete rewrite of the code.
Infinite isn't even a possibility thousands even a million can be done rather easily.
It depends though on the language you are using and what libraries you choose to use.
If you use renpy with the basic cpython 3.* your limitation is set by pygame for the most part.
Pygame:
If you have a 3ghz cpu you can update about 3000 items every 1/60th of a second if the update is done correctly and not to excessive. In short you won't be able to do it if you are using large nested if else methods.
Renpy:
It has a Rollback system that causes even greater limitation.
SDL isn't the issue. Using C/C++ on the same system you can update around 40,000 in the same 1/60th of a second.
If you use a well designed ECS(Entity Component System) system with C/C++ you can get a fairly decent boost in performance because of reducing upper cache and memory calls. You can move that into the hundreds of thousands even millions. If you don't have to render each and everyone of them you can save a good bit of performance as well.
Of course you could create update groups for real time systems. Objects/ AI's that are visible or with in eye sight are update instantly, the rest can be updated every other or even 3rd call. All the main calculations are time based anyways. Those that aren't it won't matter.
Back to renpy:
The biggest problem you have with large numbers of characters when it comes to renpy is he rollback system. Every time it updates and stores those variables takes time and the more you add the more it takes.
If you want to use a large number of characters getting rid of the rollback system is a good place to start. Fully disable it.
It might also be more preferable to use a database like SQLite to store all the characters in. You could then update them as needed through out game play and not have to do all of them at a single time.
Given games using renpy are generally not in Real time you don't have to finish in 1/60th of a second 200ms is fast enough in most cases to feel responsive. That means if you write your update system properly and don't uses stupid nested if else methods you could handle about 3000 x 12 Characters = 36,000.
Those numbers don't take into any account of other stuff Renpy may be doing that uses performance up.
It assumes the two primary and most costly factors are the use of pygame and the rollback system.
If they remake menus each time rather than work from a saved copy of the menu then that would also be something that causes significant performance hits. That's just one example.
Profiling it would probably give you better ideas on what else is a performance sink and bottleneck