(Technical, Code architecture) How are large sandbox games with lots of customizability designed? (Strive4Power, COC)

fassass

Newbie
Nov 12, 2017
19
9
I've got over 5 years making games & doing software, and for my next project, I want to make a porn sandbox with a lot of character customization. I have the combat, character stats, and some basic UI done, however I struggle a lot with the procedural elements/sandbox elements.

This game will be very similar to TITS, COC and Liliths throne with its character customizaiblity. It will have a lot of menuing, and be fully 2d with lots of text.

I'm making this game in Godot, although I'm open to general advice on this topic. My questions are as follows:

1. How is the architecture of sandbox interactivity -> custom event scenes -> back to sandbox interactivity usually handled? As in, if I have a character exploring, then I have them do something, how do we go back to the exploring section? Is it like a separate layer that's overlaid on top of the overworld logic? Or is it more like there's an overworld loop, and we break out of it for a scene, then go back to the loop? If this question sounds stupid, then I understand. Im not really explaining it that well.

2. How is saving state between scenes & save files usually handled? Is it all serialized in a huge JSON, or is there a more elegant solution?

3. Does anyone actually care about the performance of text-based games (liliths throne, No Haven)? Both these games are quite laggy, but I don't see many references to that fact during discussion.

4. How are things like appearance/race actually handled in code? TITS has over 20 values with unique identifiers ( ) - and making a dedicated class for this aint to difficult for someone of my skill. Still, I was wondering if theres a blogpost/devlog on this or something similar.

5. How are procedural sex events usually scripted (like in liliths throne and strive4power). Do these games have source code I can analyze?

That's most of the questions I can think of currently. I'll ask more later.

Overall, the hardest part is DEFINETLY the procedural generation in these games.
 

Satori6

Game Developer
Aug 29, 2023
448
852
I've got over 5 years making games & doing software, and for my next project, I want to make a porn sandbox with a lot of character customization. I have the combat, character stats, and some basic UI done, however I struggle a lot with the procedural elements/sandbox elements.

This game will be very similar to TITS, COC and Liliths throne with its character customizaiblity. It will have a lot of menuing, and be fully 2d with lots of text.

I'm making this game in Godot, although I'm open to general advice on this topic. My questions are as follows:

1. How is the architecture of sandbox interactivity -> custom event scenes -> back to sandbox interactivity usually handled? As in, if I have a character exploring, then I have them do something, how do we go back to the exploring section? Is it like a separate layer that's overlaid on top of the overworld logic? Or is it more like there's an overworld loop, and we break out of it for a scene, then go back to the loop? If this question sounds stupid, then I understand. Im not really explaining it that well.

2. How is saving state between scenes & save files usually handled? Is it all serialized in a huge JSON, or is there a more elegant solution?

3. Does anyone actually care about the performance of text-based games (liliths throne, No Haven)? Both these games are quite laggy, but I don't see many references to that fact during discussion.

4. How are things like appearance/race actually handled in code? TITS has over 20 values with unique identifiers ( ) - and making a dedicated class for this aint to difficult for someone of my skill. Still, I was wondering if theres a blogpost/devlog on this or something similar.

5. How are procedural sex events usually scripted (like in liliths throne and strive4power). Do these games have source code I can analyze?

That's most of the questions I can think of currently. I'll ask more later.

Overall, the hardest part is DEFINETLY the procedural generation in these games.
1: Overworld
> Visit Area
> Check flags & variables for pre scripted scenes (plot) and trigger the special scene instead of loading the area (or redirect before rendering the area).
> If that didn't trigger, check for random events and trigger them if the conditions are met, instead of loading the area (or redirect).
> If no special/random events were triggered, load the area as usual.
> Otherwise save the area and when appropriate (ie; the event doesn't move you to a different place) load it once the current plot or random scene is over.
> Add flags as needed to avoid random events from chaining or repeating right after they're over.

2: Most sandbox games use Twine with SugarCube, which automatically handles saves. For other cases, JSON seems like the simplest approach. Just make sure not to save any images on b64 or other stuff that bloats the size of a save file.

3: Lilith's Throne had awful performance. It wasn't the only reason why I stopped playing it (I disliked the game in general), but it was one of them. There's no reason for a text-based game to be laggy on 2024 hardware.

4: Not sure, but maybe the could be used to get an idea.

5: You can analyze DoL's code, which is probably the best modern example of a sandbox with random event/sex generation.
 

fassass

Newbie
Nov 12, 2017
19
9
Holy shit, thank you so much.

I considered using Twine (and honestly I might make a simple game to get my name out there), but for a more complex game like the one I want to make, Godot is the best choice for me. I'll post something soon...
 

papel

Member
Game Developer
Sep 2, 2018
345
462
3 - People may not complain in the "proper" channels, but a text game that is slow/laggy speaks volumes about the (lack of) skill of the developer.

4 - My best guess here is that it uses a similar approach to databases: you have a "table" with number of "rows", with unique identifiers, that bring the rest of the desired information. For instance:

Python:
head_stuff = [0, human, "your face looks human"],
[1, canine, "your face looks canine, with a big snout"],
[2, equine, "your face is long like a horse's"]
# Effectively, you have an array of arrays
# Repeat for each body part that can transform, like arms, torso, legs

# And the player only needs to carry/point to that id, like so:
Player.class
   arms == 0
   head == 2
   legs == 0
   torso == 1

function describe_player():
  print(head_stuff[player.head][2]) # With player.head being 2, it will print the Equine description
Also, in Godot, you can use , so that you can use words as key identifiers instead of position in the array. The above would then look like this
Python:
head_stuff = {"equine":"your face is long like a horse's",
"human": "your face looks human"}

Player.class
  arms == "human"
  head == "equine"

function describe_player():
  print(head_stuff[player.head]) # As head is "equine", it will print the value of the "equine" key.
I think saving and loading dicts as JSON objects shouldn't be too hard. You can also create an external file to be read once the game starts, to fill the descriptions' arrays or dicts, this will make it much easier to edit said text and even work on translations.

These Dict objects can also be super useful as means of adding, checking and saving gameplay flags, as Satori mentioned, because you only ever need to save them when they're TRUE, so a check of "does dict with the key BLAH exist?" will return false unless it was triggered. An example, very close to actual godot code:

Python:
# Make sure to define this inside a GLOBAL script.
var game_flags:Dict = {} #Creates an empty dictionary

# Whenever you attribute a value to a key, if said key doesn't exist, it is created and added to the Dict object
game_flags["event_bob_talked1"] = true

# Keep in mind that trying the get the value of a key that doesn't exist will crash the game with an error
func get_flag_value(key):
  if game_flags.has(key):
    return game_flags[key]
  else: #it does not have the key, so it's automatically false
    return false

func first_talk(): #Script of bob's first talk
  if get_flag_value("event_bob_talked1"):
    print("Bob has already talked here")
  else: #If the key doesn't exist, it'll enter here
    print("Bob arrives to talk for the first time")
You can also save answers and decisions as their own keys as well, if you want to create branches caused by dialogue choices. As an example: Bob can encounter a fairy (1st_encounter flag) and, depending on what he answers, he may or may not find the fairy again (1st_encounter_answer flag)

Python:
if get_flag_value("1st_encounter_fairy"): #If true, Bob has triggered the scene the first time
  if get_flag_value("1st_encounter_answer") == 2:
    print("The fairy finds Bob before he can even think about looking for her")
  else:
    print("Bob tries to find the fairy, but he fails")
else:
  print("Bob finds a fairy for the first time")