Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

I figured out the backup files folder pretty early on; it's saved me from a recurring crash-on-load error, when I was able to just pull files from the backup and replace the entire directory, phew!

What I do now is, I copy all the files fresh from the backup folder into my own folder somewhere else, go through that personal folder and delete any files that look like they aren't going to be something I'm interested in and/or capable of editing, and then I split the files I do want to edit into different folders as separate "Mods" (since that seems likely to be less error-prone than my previous attempt to Do Everything All At Once).  E.g. one mod just to update the gendered language in that little exchanges-dictionary (all the $sir and $master and $brother stuff).  Once I've edited the files there, I go copy them into the Mods folder in my AppData/Roaming/Strive/Mods folder, so I'm not editing any of the backup files directly at any step (unless I seriously screw up my process and accidently save the wrong file, which I've done at least once but did recover from).  I could reload the entire game at some point if need be, make sure it's all fresh.  In fact that might be advisable.  Hmm.

I've never had any problems with Notepad++ -- aside from occasionally winding up forgetting which version of a file I've opened and thus editing the wrong one, but I've gotten better at being careful with that.  The code is definitely getting to the right StatsTab file (or it wouldn't come up with the extra button in the first place), and I'll check later to make sure that the other file is likewise properly updating.

On your advice, I went ahead and got that Godot engine editor (two copies -- the last stable full build (not the current dev/alpha build) and the highest final number on the one you recommended for this game particularly.  That's (checks) 4.3 and 3.3.4.  Being able to load up the game and look at the behind-the-scenes details was five or ten minutes of pure excitement-joy as I went through seeing all the screens.  It did kinda spoil a later plot point because that's the text on one screen, but eh, I knew I was gonna get spoilers due to messing with the code to begin with.

At this point, this feels like a "this step is beyond my skills" roadblock, which at least confirms I'm not missing something that would be obvious to veteran Godot coders.  When I first went to college (some 25 years ago), I signed up for Visual Basic because I couldn't make anything work, despite self-teaching myself from GW-BASIC through QBasic.  Turns out I'd missed the dot-operator (the object.property thing), and once I learned that, I could make everything work and basically didn't get all that much from the rest of the class (which was aimed at newbies, while I'd been coding since like 14).  Knowing that the block isn't something that basic is a relief.

I think what I'll do is step back slightly, content myself with figuring out how to mod the code that has been working, continue exploring as I go, and probably change the "call me Master" button to a slave name change button, since in fact I was able to make that much work (losing a function I don't really care to make use of anyway).  Or maybe I'll see if I can replace the "Release" button that I'm always afraid of pressing, since I don't really intend to use it.

I appreciate you taking the time to work through the troubleshooting with me; that has reduced my frustration back to a much more manageable level.  And hey, getting me over the hump to actually downloading the editor might wind up with me getting back into hobbyist game design, who knows?  Maybe that'll go somewhere interesting.

Using the mod system to apply your changes introduces a whole new set of potential problems, but also likely explains the gap between what is shown and the results you get. Here's a mod that correctly though crudely implements your changes, plus 1 line to update the GUI after changing the name.

https://mega.nz/file/aFpSGKyD#Kt8X026t4Bo8QkecY3hL1ierERvHrwNW2DW-C9JySVo

Oooh, thanks!  Downloading.

And yeah, I noticed that the name didn't update directly after changing (I had to switch screens to get that to work), but that was a minor inconvenience I could figure out later if it bugged me.

(1 edit)

It's working fine!  The only thing I noticed is that the immediate update changes the name in the left (personal) panel, but not in the slave list (until I change screens).  I presume there's a "rebuild slave list" call or something that'd do that, just like your last line there.

I went ahead and updated the logic to include the effect on the slave:

func _on_namechangeconfirm_pressed():
get_node("namechange").visible = false
var text = "Yes, $master."
 
if person.obed >= 70:  ## Highly obedient
    if person.loyal >= 50:
        text = "— Of course, $master.  It's my pleasure to mold myself to your desire."
        person.loyal += 10  ## They're pleased with the personal attention and "gift" of a new name
        person.stress -= 5
    else:  ## They're not yet broken in, but have been forced to high obedience
        text = "— Of course, $master.  Your will is all that matters."
        person.loyal += 5  ## They have mixed feelings about the personal attention
        person.stress += 5
elif person.obed < 35:  ## Not yet broken
    if person.conf > 30:
        text = "— You can't just take my name away!"
    else:
        text = "— Are you really going to take away even my name??"
    person.stress += 15  ## Highly stressed at having their individuality taken from them
else:  ## Moderate, compelled obedience
    if person.conf > 60:
        text = "— I guess I don't have much choice, do I?"
    else:
        text = "— Yes... $master."
    person.stress += 5  ## Kinda used to it by this point, but it's still a negative
 
person.name = get_node("namechange/LineEdit").get_text()
get_tree().get_current_scene().close_dialogue()
get_tree().get_current_scene().popup(person.dictionary(text))
get_parent().slavetabopen() # Ankmairdor - add this to update GUI and show new name immediately

So basically, if you name them right away it helps to break them; if you've already done some work before naming them it's a little stressful; if you wait until they're well trained then it's still a little stressful but bonds them more to you; and if you hold off until you're sure of their loyalty then it's a wonderful gift.

I mean you could totally abuse the function to just repeatedly stress them out (or increase their loyalty a bunch), but I don't intend to use it that way and thus don't care to code around it.

P.S. Forgot to include support for Mute characters, but now have a similar section with reactions ranging from outrage to resignation to joy.  There's so much that can be done with body language, even without access to words!

Yes, "get_tree().get_current_scene().rebuild_slave_list()" will do exactly as you expect.

To prevent spamming the name change, I'd probably add a member variable to person.gd to track which day the name was changed and then essentially put the stat effects on cooldown. Though the simpler method might be to simply subtract some energy from the player as a minor cost and require sufficient energy to enable the button, which doesn't fit quite as well intuitively but works okay as a game mechanic.

"Mute" gets attention because it's obvious, but there's always room for slaves to be more expressive in terms of their traits.

Sweet.  So now the only other major roadblock I've hit (that hasn't cleared up with some troubleshooting) is how to add an extra .gd file of my own, because I couldn't make that work at all.  I presume that has to do with something outside the basic scripts folder?

Anyway.

Yeah, if I were thinking to make a mod for more than just my own private use, I'd probably try to work out a nice integrated restriction like those you mentioned.  Or if it turns out that I wind up using it too much, I guess, but I doubt that'll be an issue.

For the traits, I'm definitely putting a lot of work into expanding the dialogue based on various traits and trait combinations.  First step is just working on the basic Talk Mode thing -- just trying to make sure I grasp the flow enough to make things work without breaking things (the first major step! spent way too long troubleshooting just to realize I'd forgotten a colon and a quote somewhere).  I've been having way too much fun making up randomized dialogue options for Foul Mouth (and I don't usually like things with swearing! but it feels weird to have slave characters with such a pronounced trait who talk just the same as everyone else even when being outraged at their captor).

Next step will be to change the character descriptions again (I did this in a previous attempt, but I want to start from scratch), making them more condensed and flowy and less gamified.  Bits I've thought of include, let's see... logic for when the sizes for two things are equal, nearly equal, or very unequal, then making the sentence combine them ("small X and Y"), use a basic "and" ("small X and average Y"), or contrast ("small X but huge Y" or "huge X but small Y").  Combining longer hair with description of chest ("her long hair flows down and around her large breasts", "his long hair contrasts his muscular chest"), depending on hairstyle.  Describing the clothing they're wearing, once I figure out how to reference items/gear (butler suit, geisha outfit, but also handcuffs or slave collar, etc.).

My first attempt was mostly to get rid of the genital description because I'm not the kind of "master" who wants to see penises every time I enter a room (I initially changed them to how far apart they spread their legs).  And even the way they stand or the way they look at me could be switched up based on traits and/or stats.

Later on I'll be trying to revamp the sex scenes a bit, see what I can do without breaking everything.  I definitely want the Dominant/Submissive stuff to work more like Omegaverse, and the non-human cocks to actually matter.  And the thing that actually got me into modding was being halfway through a scene when the term "rectum" was used, and then "shit hole", and I'm like "......well, someone doesn't have a firm grasp on reasonable sex-scene terminology" (or possibly just English registers -- the idea that certain terminology works in doctor's offices and not in the bedroom) and then I went "hmm, wonder how hard it would be to change this stuff..." and down the rabbit hole I went.

The core of the modding system uses .gd files in the mod as though the mod folder was the "files" folder to apply changes to matching .gd files in the game folder. To do anything outside of that core you need to use either the "patch" folder or the dynamic mod folder functions, both of which are explained in the modding guild found in-game in the Mod menu's "Help". Note that you need to use the BugFix mod if you want to use the patch system to add new folders for the new files.

English is not Mav's first language, so he missed some of the subtle parts of the language.

Yeah, I'd guessed as much.  In the moment, I was irritated, but afterwards I was just amused -- I'm a language buff, and it's always interesting to run across signs that someone isn't a native speaker (though I do have to wonder about "shit hole" since most of the languages I've studied have "shit" as a base obvious swear with roughly equivalent meaning).  It also explained a lot of odd phrasings in the rest of the program (another detail I'm focused on while modding, just to increase immersion).

As far as the modding, guess for now I'll stick to the existing files and see how far I can go with just that.

Latest roadblock: What is the distinction between these two formats?

## First Format:
var rules = {'silence':false, 'pet':false, 'contraception':false}
## Second Format:
var gear = {costume = null, underwear = null, accessory = null}
var itemlist = {clothmiko = {code = "clothmiko", type = "gear", subtype = "costume"}}
## List of possible costumes:
#costume: clothmaid, clothkimono, clothmiko, clothbutler...
 
## This line works:
if person.rules["nudity"] != true:  ## Nope!
    text += "Not naked!"
## This line doesn't:
if person.gear[costume] != null:
    text += "In costume!"
 
## But the code gets REALLY SUPER WEIRD for that second format???
## These are things I found that seem to reference it:
for i in globals.itemdict.values():
    if !i.type in ['gear','dummy']:
        i.amount += 10
 
var handcuffs = false
for i in person.gear.values():
    if i != null && globals.state.unstackables.has(i):
        var tempitem = globals.state.unstackables[i]
        if tempitem.code in ['acchandcuffs']:
            handcuffs = true
for i in ['clothkimono','underwearlacy','accamuletemerald']:
    var tmpitem = globals.items.createunstackable(i)
    globals.state.unstackables[str(tmpitem.id)] = tmpitem
    globals.items.enchantrand(tmpitem)

What the heck is going on here?  It seems like the first format (dictionary?) allows for a super easy reference to keyed codes ("Does he have this specific rule? Y/N"), while the second format -- which I think I tried to look up soon after dipping into this language, and could not find -- seems to either require several more steps, or require you to manually hunt through every entry to locate the thing in question.

What I want is to be able to see if a person is wearing a specific costume, underwear, or accessory, and then give description based on that.  How to reference these values?

(2 edits)

Something to note is that the game randomly switches between American English and British English for spelling and grammar, which likely reflects the fact that the game was proofread by players from around the world. With all the inconsistencies in how the language is handled there are some places where if it sort of fits and it isn't clearly wrong then it gets a pass.

Documentation: https://docs.godotengine.org/en/3.3/classes/class_dictionary.html?highlight=dict...

The first format is a Python styled dictionary creation, the advantages being that it is more obvious that the keys are string values and the keys aren't as limited, for instance including a space between words.

The second format is a Lua styled dictionary creation, the advantage is it's simplicity with less quotation marks to type and read. The downsides are that it can sometimes be confusing to read and it's limited in terms of functionality.

var gold = 5
var formatPython1 = { gold : gold }  # creates { 5 : 5}
var formatPython2 = { 'gold' : gold }  # creates { 'gold' : 5}
var formatLua = { gold = gold }  # creates { 'gold' : 5}
var emptyDict = {}
emptyDict[gold] = gold  # creates { 5 : 5}

Both formats are only relevant when creating the dictionaries, afterwards they have no impact on how the data behaves. This seems to be the source of most of your confusion as you seem to have assumed that the formats used to create the dictionaries impact how they look up keys. Therefore the weirdness you are experiencing is the result of you not properly attributing the data types used as keys and comparisons. For reference, GDScript has the function typeof() that can be used to return the integer that corresponds to https://docs.godotengine.org/en/stable/classes/class_@globalscope.html#enum-glob...

You can use a simple line such as this to learn more about what a referenced value currently contains:

print("value: ", value, "  type: ", typeof(value) )

This line probably doesn't work because there is no variable within the context named "costume":

if person.gear[costume] != null:

This should be quite obvious if you were to read the error messages from the Debug mod. The editor will also show the error message, but it can sometimes get lost among the other things it likes to complain about.

Finally, the "gear" data for persons is a simple dictionary with string keys and the values are either null or string typed item IDs. The string values need to be used in the dictionary "globals.state.unstackables" to find the dictionary typed item data for that specific item. The process for checking for items is usually over-complicated by programmers that don't fully understand the gear system nor power of GDScript.

var temp = globals.state.unstackables.get( person.gear.accessory )
var handcuffs = temp && temp.code == 'acchandcuffs'
(1 edit)

I knew my code was definitely not right, I just had absolutely no clue what the next step would be or how to look it up (as I had tried, some time ago, to find any example in the Godot/GDScript documentation that matched what I was seeing there, and came up blank).

var gold = 5
var formatPython1 = { gold : gold }  # creates { 5 : 5}
var formatPython2 = { 'gold' : gold }  # creates { 'gold' : 5}
var formatLua = { gold = gold }  # creates { 'gold' : 5}
var emptyDict = {}
emptyDict[gold] = gold  # creates { 5 : 5}

*tearing my hair out*

okay so

let me get this straight:

the Lua format lets you make a string without using quotes, that becomes a string in the code and gets referenced as a string???

never in a million years would I have made that leap on my own

this is my "dot operator" moment for this language

(actually it's more like... this language has broken one of the Core Concepts of every language I have studied thus far (aside from perhaps HTML), which is that strings go inside quotes and non-strings stay outside quotes and never the twain shall meet)


Thank you so much for laying it out so succinctly so I can compare the formats.  That helps a hell of a lot, and I much appreciate it.

Okay I think I got to the right stuff where I can easily check what I want

but en route I ran across a weird output formatting?  I'm gonna scrap this code, it was just to pin down the right details, but I am baffled as to how this produces the output.  This isn't even a question really, just a "wtf??"

(NOTE: the line break in the one text line is for readability here and not in the actual code)

CODE:
text += "Not naked!  "
var clothes = globals.state.unstackables.get(person.gear.costume)
var accessory = globals.state.unstackables.get(person.gear.accessory)
 
text += "clothes: " + clothes + ", type: " + typeof(clothes)
    + "; accessory: " + accessory + ", type: " + typeof(accessory)
text += "\nClothes Code: " + clothes.code + "\n Accessory Code: " + accessory.code
 
RESULTS:
1393, type: ; accessory:, type: 1393, type: ; accessory:, type:
Accessory Code: acchandcuffs

So it did spit out the right details, so now I know how to get it.  And I need some error-catching to make sure I'm handling actual variables and not making messy code when they're not wearing anything.  And the actual variables there translate to numbers hence the need for a thing to look them up and all (and 1393 appears to be the null entry? I guess?).

but... why did "clothes: " disappear? why did "Clothes Code: " disappear?  Do mishandled null entries actually erase part of existing strings???

The string values need to be used in the dictionary "globals.state.unstackables" to find the dictionary typed item data for that specific item.
GDScript does not allow you to add/concatenate non-string values to strings. The only reason you are getting anything at all is because in non-debug mode minor errors will be effectively omitted from execution, which is causing data corruption in your "text" variable. I recommended the print() function because it will automatically convert each argument into a string and then concatenate those strings. If you want to create your own string, then you must convert the dictionary to a string using str( clothes ) before you concatenate it.