For the basics of modding, refer to the Modding Guide. If you have any questions or need help, use this topic.
Fantasy Slave Management/RPG Erotic Game · By
For the basics of modding, refer to the Modding Guide. If you have any questions or need help, use this topic.
Anyone have any clue why this doesn't work? I've got this in "mods/modname/scripts/characters/races.gd", but it doesn't seem to be doing anything.
https://pastebin.com/1swUp609
What do you mean by "doesn't seem to be doing anything." Have you looked at races.gd after applying?
If that's all the mod does, i don't see it actually having any impact on the game whatsoever. Nothing iterates over all races. Even if you added those 2 races here, currently you'd need to also modify a bunch of other code for them to actually be used anywhere.
Particularly all the races arrays in globals.gd, like say adding them to:
var starting_pc_races = ['Human', 'Elf', 'Dark Elf', 'Orc', 'Demon', 'Beastkin Cat', 'Beastkin Wolf', 'Beastkin Fox', 'Halfkin Cat', 'Halfkin Wolf', 'Halfkin Fox', 'Taurus']
Noticed the problem, I had same issue on new files i made. Tabs vs. spaces, the game uses tabs for indentation and the mod code all expects tabs. You need to convert all those spaces to tabs, then it should work.
Edit: It's more than that, testing out more. The mod code expects all following lines to begin with a tab too, so the "Race One" and "Race two" need to be indented. However, even with that, using a regex tester it doesn't match the regex the game is using for variables.
Edit2: The game's regex for variables does not support this far as I can tell,
(var.*=)\s([{]([^\{\}]*[\r\n]*)*[}])?([^\{\}\s]*)
That won't match anything with nested {}'s which are required for adding a race. You could work around this by defining your own races, and then appending them to the official ones during startup of the game? Otherwise, we'll need a new version that supports this. Basically that chunk of code needs to be amended to also accept a form where it's "var blah = {" followed by a series of lines starting with tab, and then ending with a }, similar to what it does for functions.
To work around this, instead of modifying races.gd, add your own file that defines those 2 races, then do something like this for scripts/globals.gd
It's possible to mod the mod system, to change that regular expression to something that would work better.
I wasn't very familiar with Godot syntax when I wrote that regular expression. I had to look up multi-line variables, and was not aware at the time that a dictionary with multiple values could be declared on a single line, and I couldn't even find an example of a static multi-dimensional array/dictionary and its declaration.
Regular expressions are... difficult to get right.
Having said that,
what is a regex tester and where can I find one?
Haha yeah... I tried to tweak the regex to get it working right, but bit burned out on coding from work to finish. I typically use a site like www.regex101.com so I can visually see how it's matching to a set of text. Can then stick in a variety of test cases and see how it responds. I was able to tweak it to accept:
var blah = {
<tab indented text>
}
But the solution wouldn't have worked for single lines. Likely could have made it work with some more groupings and or operators. I used that site earlier to figure out why some of my code wasn't working, as in my own mod,it also fails on:
var randomportraits = load(globals.modfolder + "/randomportraits/randomportraits.gd").new()
Because it only matches on
var randomportraits = load(globals.modfolder
and inserts that into the file, breaking the game. Thus, i did var blah = null, and then conditionally load it first time i need it.
The mod can't add a "races" variable, because that variable already exists in the script, so either they conflict (and the mod is not applied) or the one from the mod is overwritten.
Btw, can you define a variable before the "extends Node" statement?
I suggest to remove line 2 and 19 from the mod and insert the code after line 359 of races.gd, so that the new two races are pushed at the end of the existing list (the mod should start with <AddTo 358> or something like that, the number may be slightly wrong)
Also what Kyler2 said.
http://strive4power.wikia.com/wiki/Modding_Guide
I know about the conflict, but my understanding is that the <AddTo -1> tag should resolve it by modifying the object alone. I already sent this off to Maverik, and he didn't seem to find a problem with my reasoning but recommended that I post here to see if anyone could find something he missed.
<AddTo ...> is based off insertion point, not total line number.
<AddTo 2>
func testfunc: ....
....
Will add to line 2 of testfunc, not line 2 of the file.
For base files, you cannot define anything before the "extends Node" statement. Godot requires all files to begin with that. (Or begin with extending a subclass of Node)
Did you read the mod guide at the top? There is no mods folder in the game, and the mods folder the game does use, does not exist by default. Per the guide:
> Download and put the mods in the mod folder (%APPDATA%\Strive\mods)
That means you need to make that folder yourself, and extract the mod(s) there. Similar for bodies and portraits folders.
This picture might help explain the folders part a bit. Hope this helps...
https://mega.nz/#!qRpBAARb!5emCMX28BOqGTFpxqUlos1pNkf4Ww0xZJRkC84weBWc
(Link will expire in about 2 weeks to save space on my account >_<)
To re-iterate, NO it does NOT go in the same place the .exe is for strive.
Hit the windows key plus R to open the run dialog, paste in this:
%APPDATA%\Strive
That opens the game's data folder, it's in a completely separate place from where the Strive.exe file is. It's where your saves are stored. You should see a saves sub folder, as well as progressdata and settings.ini files.
This is where you make a mods folder and place mods. and what fusiontech45's image is a screenshot of. It is also where the Portraits and Bodies folders go.
There is no %appdata%/strive because im downloading a zip file, and the zip file is on my desktop, theres nothing in that appdata folder related to strive, the only thing in my %appdata% folder is a Local file and in that Local file it goes to a Microsoft folder and theres nothing in the Microsoft folder. :/
Or, a nice simple .bat file. Double click this file and it will create and open the Strive for Power mod directory.
http://www.mediafire.com/file/n6nk6uep54624ja/Create_And_Open_Strive_Mods.bat/fi...
For the properly paranoid, you can type the following two lines in the command prompt.
mkdir %APPDATA%\Strive\mods start %APPDATA%\Strive\mods
I'm not sure if it works with Mac, but it's just Bash.
Probably needs quotes, otherwise it'll break if the user has spaces in their name. Also "start" on my computer, starts another command prompt. Maybe it works better elsewhere, but if I replace start with explorer, then an explorer window opens.
mkdir "%APPDATA%\Strive\mods" explorer "%APPDATA%\Strive\mods"
http://www.mediafire.com/file/qig2s3fpmawnqrg/Strive%20Mods%20Folder.bat
This newly revised .bat file will open (and create, if necessary) the mods folder for Strive.
We're really trying here.
Wondering if next version of game, the "open mod folder" button could be updated to create the folder if it's missing?
Edit: I also found that the button doesn't even work, as it tries to run OS.shell_open with the user:// path, and that function doesn't auto-resolve the user:// part, it wants an absolute path on the system, did the following:
func _on_openmodfolder_pressed():
var dir = Directory.new()
dir.open("user://")
dir.make_dir("mods")
OS.shell_open(modfolder.replace("user:/", OS.get_user_data_dir()))
I some how got it to run the bat file, now what do I do? the .exe is still on my desktop so its not going to see this file thats 1000 folders away, cus I already put the portrait mods and what not in it and the game couldnt find it :/
Edit: Im trying too, I really just want to enjoy this game but this is just so frustrating for me
Screenshots of what you're seeing/doing would help immensely. One of yo ulooking at the "%appdata%\Strive" folder, and maybe the contents of the mods folder. Plus maybe one of the game with the mods panel open.
The game can trivially find this folder, it asks windows where the user's app data folder is, windows tells it, it then looks in the Strive sub folder. Doesn't matter where the game's exe is. You might have modified the folder it uses for the mod or portraits. In which case it might be looking somewhere else. We've been working off what the default folders are, but they can be changed.
All I did was download the file onto my desktop, then extracted it into a folder also on my desktop called strive. From there theres so much in the folder I have no clue whats what except the .exe I use to run the game.
Edit: I ran the .bat and im now waiting for more instructions because this is honestly so confusing and convoluted, the way it was put made it seem much MUCH simpler than this "Put the mods in the mods folder then run the game and activate the mods" But the zip file doesnt have a mods folder so... ugh. I dont know how you expect me to get to this hidden folder so often to mod the game, its so out of the way and inconvenient. It takes me literally 4 minutes to find my way to the mods folder the bat file made
If your OS is Windows 10, the user folder is C:\Users\USERNAME\AppData\Roaming. The bolded word USERNAME is whatever user name you chose when you set up your device. In the Roaming folder is a folder named Strive. You need to create a folder named mods in the Strive folder. I created a shortcut on my desktop for the AppData folder as several applications put saves and configuration files there.
If your OS is different than Windows 10 I can't help you.
I'm sorry, but this is not confusing or convoluted. It's fairly basic. It should take seconds to find the way to the mods folder the bat file made, open explorer, then paste this in the address bar and hit enter: %APPDATA%\Strive . I can't comprehend how that takes 4 minutes to find, unless it takes you 1 minute to move and click your mouse or press buttons on the keyboard for each action. We've been repeating this same thing over and over here. This %APPDATA% folder is also where a bunch of other game's data often end up, including save files. You'll want to get used to finding it, or understanding how to enter in paths like this in windows explorer.
At this point I'm not sure it makes sense to explain further, you don't seem to be capable of following directions, considering we've explained what goes in this folder before, but here I go:
It has a mods folder, then in that folder you extract the mod, the mod should have it's own folder, containing an info.txt file. Full path you end up with is:
%APPDATA%\Strive\mods\randomportraits\
and in there you'd see an info.txt file.
Then for portrait packs , their zip file usually contains the Bodies and Portraits folders. You want to copy those into the Strive folder, so you end up with:
%APPDATA%\Strive\Portraits\
%APPDATA%\Strive\Bodies\
One thing to note, itch's forums kinda suck for copy and pasting text. It often inserts random unicode characters. If those end up getting copied, then things might not work quite right. Did my best to try and avoid that with these. However if any of these don't behave right, try to delete characters before the % or after the \ that may be there, but hidden.
I'd hate to come back to this a literal month afterwards but I dont think the problem Im having can be explained on this platform easily. Is there another way I can contact one of you to help me, im sure it would only take 2 mins for me to figure it out, dumping text doesnt leave much back and forth to be had, since I cant convey my problem directly.
You should try joining the discord server https://itch.io/t/284398/discord
I was able to apply my mod, randomportraits, fine.
However, modification of var is still broken. Better regex i recommend is in there, but the code for AddTo is still broken, it's got .replacen("{", "").replacen("}", "") still so it breaks any nested {}'s by stripping them. This was broken in other versions in various ways though so i don't know anything new that is broken?
Hey all,
I've decided to give a shot at making a mod. I want to make a mod that adds a custom race to strive. Also, I could generalize it, so people can easily add their own races.
What I have so far:
A file which defines the new race. Located in …/roaming/strive/mods/ponyrace/newraces.gd
An edited version of globals.gd which calls my races.gd mod and includes the new race in the race list. Located in /mods/ponyrace/globals.gd
(Note: these hyperlinks sometimes go to the wrong file. For correct the file, ensure the text above matches the actual URL you land on. Edit 3: these pastebin links are kinda out of date. Use the project link in the next post).
Edit: just noticed the # comment mark in globals.gd. I therefore added the desired races inside \mods\ponyrace\scripts\variables.gd.
It doesn't work as intended:
After removing and adding all mods (including my mod, ponyrace), the pony race doesn't show up in game. Clearly, I'm not even close yet.
If anyone could point out what I'm doing wrong, that would be awesome. It someone who knows what they are doing can confirm that my code theoretically ought to work, that would also be helpful, because then I can go and look for missing comas or similar.
Thanks!
Edit 1:
Attempting to add the new race data inside will give a console error and crash the game.
script error: parse error: unexpected assign.
at: newraces.gd:2
where line 2 is the first like where I start defining the new race.
edit 2:
When I try to generate a new person, I see the new races available. However, when I click that option, a console error occurs.
at /scripts/characters/constructor.gd:89
invalid get index 'beastkin pony' (on base: dictionary)
This error code makes me think 'beastkin pony' is not get registered everywhere correctly. But Three things I notice.
Therefore, my edits have correctly updated variables.gd and globals.gd, but not races.gd or global.races.
newraces.gd
var races = { "Beastkin Pony" : { ...
globals.gd
# newrace mod <AddTo 0> func _init(): var newRaces = load(setfolders.mods + "/ponyRace/newraces.gd").new() for cur_race in newRaces.races: races[cur_race] = newRaces.races[cur_race] var longtails = ['cat','fox','wolf','demon','dragon','scruffy','snake tail','racoon', 'horse'] var alltails = ['cat','fox','wolf','bunny','bird','demon','dragon','scruffy','snake tail','racoon', 'horse']
- global newRaces not necessary
- <AddTo -1> dont work
- newRaces is the file, races is the dictionary
- AddTo on vars also does not seem to work (but if it does: should be before each var and have only the additional content)
- penistypearray is the same as in original file
Hey, uh, I don't know where else I'd ask this, so... does anyone know if it's possible to have a futanari option for the player character in character creation, since you can have futanari characters in random encounters? Or maybe like, unlocked character customization, so one could play as, say, a dragonkin character with fur and equine parts? I imagine such features wouldn't suit everyone's playstyle, but I for one really enjoy it when a game lets you choose to "ignore the rules" and mess around. I have very little modding experience, though I'd be willing to learn; I want to be able to do that stuff eventually, but it can be pretty intimidating. What I mean by this is: I'm mostly curious as to whether it would be possible, and what it would entail. Please tell me if I'm doing anything wrong, socially; I'm awkward and don't know how to do stuff. Thanks in advance, and great game; I'm really enjoying it so far!
Unlocked character customization would be a Big undertaking, almost too bothersome, you have something like that with the laboratory already, letting you add some mods and what not, so maybe an overhaul of the laboratory system would actually be easier to implement, but from the get go you would need to sink into the depths of coding in GDScript and trust me, takes time and patience. I myself am not even sure how I would even begin tackling that lol.
Follow up: I downloaded the Windows version of the game and see a lot of scripts aren't as packed up there, so I think I have more of a general idea of structure. However I'm still curious about some things. For example the "Faster pregnancies & growup" mod I have installed looks like it should work fine, but apparently doesn't. Have there been some changes in recent versions that might break things like var reassignment in scripts/variables.gd?
Mods currently do not work for MacOS as the mod system currently uses a crude text file parsing system(scripts/mods/modpanel.gd) to edit the files with matching relative paths. It will not report any failures during the application of mods, nor warn of conflicts between mods. Due to the fact that all the game's script files are stored in a .pck file for MacOS, the relative paths do not match and the appropriate changes are not made.
There have not been any recent changes that would break var reassignment. The "Faster pregnancies & growup" mod works fine for me (Windows 7 x64); the changes to variables.gd match the mod. If you managed to overcome of the .pck file issue, then verify that the mod folder is located correctly(Strive/mods/Faster pregnancies & growup/info.txt), as the mod system will only check the immediate sub-directory.
The community currently does not have any active MacOS modders, so we have not been able to overcome issues related to the OS. There is a Discord(https://itch.io/t/284398/discord) where we modders and players discuss stuff. I would appreciate any help you can give towards compatibility with MacOS. If you can find a method of modding the game on MacOS, then I can create a mod system for it.
The inventory system currently uses load() for item icons. Thus only images that use Godot's resource system can be used for items. Don't know how well this works, but someone made a tutorial for adding such images: https://f95zone.to/threads/strive-for-power-v0-5-25-maverik.1136/page-100#post-1...
Otherwise, your other option would be to change load() for image icons to globals.loadimage(), thus enabling the usage of normal image files for items.
you can put your textures inside folder with mod and use something likes this:
var customImage = Image.new()
customImage.load(globals.modfolder + location of your custom textures
createcustomtexture.create_from_image (customImage)
i wasnt able to test it in practice because i only have ideas for custom potions, but whole potion system annoys me a little and i dont wanna mod without ideas i could consider as "good"
The red dots are TextureRects in the map.scn file. The tooltip text and which points connect are stored in explorationregions.gd. map.gd uses those2 files to determine where to draw the lines when you hover over a red dot.
.scn files are not text files and are best edited using the Godot Engine. A new project can be created and Strive can be copied into the project folder to allow basic access. Beyond that it gets rather complex.
Alternatively, once map.scn has been loaded by the game, any script file can be used to create new red dots by duplicating an existing TextureRect.
explorationregions.gd should be fairly straight forward as it is a simple text file . I'd recommend starting from a copy an existing region.
explorationregions.gd only defines the pairs of dots connected by lines on the map.
In map.gd, the function "showtooltip(node)" creates the lines for each exit listed for the zone. The dots are Images displayed by TextureRect GUI controls(https://docs.godotengine.org/en/3.1/classes/class_texturerect.html). The position of those controls is what determines where the dot is. The name of those controls needs to match the name of a zone. The only way to get a zone to appear on the map is to add a new control node to the map.scn scene tree.
The following can be added to the beginning of _ready() in map.gd, as a minimal setup for adding a new red dot node:
var newNode = find_node("sea").duplicate()
newNode.rect_position = Vector2(100,100)
newNode.name = "newZone"
find_node("roads").add_child(newNode)
It seems like adding code to map.gd anywhere lead to freeze of the map. Here is my code to the end of _ready()
extends Control
#warning-ignore:unused_class_variable
var mouse_in = false
#warning-
ignore:unused_class_variable
var dragging = false
onready var size = $TextureRect.get_size()
var
offset = Vector2()
var status = 'none'
var timer = 0
var currentloc = null
var newNode = find_node("sea").duplicate()
newNode.rect_position = Vector2(100,100)
newNode.name = "newZone"
find_node("roads").add_child(newNode)
func _ready():
for i in get_node("TextureRect/roads").get_children() +
get_node("TextureRect/towns").get_children():
i.connect
("mouse_entered",self,'showtooltip',[i])
i.connect
("mouse_exited",self,'hidetooltip')
func _input(event):
if self.is_visible_in_tree() == false:
return
if event.is_action_pressed("LMB"):
var eventpos =
event.global_position
var barpos = $TextureRect.get_global_position()
size =
$TextureRect.get_size()
var target_rect = Rect2(barpos.x, barpos.y, size.x, size.y)
if target_rect.has_point(eventpos):
status = 'clicked'
offset = barpos - eventpos
if event.is_action_released("LMB"):
status
= 'none'
if status == 'clicked' and event.is_class("InputEventMouseMotion"):
status = 'dragging'
#centermap('frostford')
if status == 'dragging':
$TextureRect.set_global_position(event.global_position+offset)
So I said "The following can be added to the beginning of _ready() in map.gd."
You have: "The following code added before the beginning of _ready() in map.gd."
Spot the difference? It freezes cause you put local-scope code in the file-scoped portion of the code, which is completely undefined behavior. I tried to be quite precise with my description, because there are very few locations you can put this code in the file to get the expected behavior. Perhaps I was too concise, but I am going to sleep now. The code I gave you only works inside a function and not inside a for loop.
My bugfix is a patch and not a mod, which means that the patch cannot be applied through the mod system.
Make sure that your Strive has no mods currently active. Copy the contents of the patch (minus the change log) into the "files" folder of your Strive program folder. The OS should prompt you to replace the files and merge the folders. If there is a "backup" folder in the Strive program folder, then delete it so that a new one will be made including the patch when Strive starts.
Afterwards you can try to add other mods, though some may conflict with the patch due to the many changes, including to the mod system.
Edit: small mistake
Your question is not entirely clear, but I recommend using Leo's mod(https://itch.io/t/667993/leos-mod) as an example of how to add new items, especially with custom images as icons. The key to that is applying my bugfix patch first, as it fixes many problems related to custom icons. For more detailed help with modding I recommend the Discord (https://itch.io/t/284398/discord), as that is where the most active modders tend to gather.
Unfortunately, some of these effects are scattered throughout the code. For example, the beastkin cat dodge bonus is handled in the combat code that calculates hit and miss.
I've done a quick search and the Tauran milk production seems to be set in mansion.gd during the milking process at end of day. You can change this value for your own version but the endofday() function is so big it is a bad function to start modding.
So I made my own mod with about 25 or so different purposes, but it was all done via overwrite. Now that I have decided I want to post the mods, I need to edit them so they modify the functions instead of replacing them. Also splitting that big mod into a dozen or so smaller ones.
Everything was going well until I reached my Beastkin Mouse & Rat mod...
So what I want to do is append my races to the end of the array, but after some testing, it doesn't seem to work that way. Perhaps I'm doing something wrong, so I thought I'd pop into the Discord and ask for help, but after waiting a few minutes I figured it wouldn't hurt to post here as well.
My mod works fine, and just by adding to the list of races, they show up in the character creation menu, as intended. So everything works fine. (I've also run into some wild halfkin rats, so I'm happy about that as well)
The problem occurs when trying to convert the mod over to be additive instead of replacing the entire variable array.
Has anyone here successfully added a race to the game without replacing the var races array in races.gd?
Side note: I also have custom 'body parts' for the mice and rats, since round ears weren't a thing in vanilla for some reason... And of course, I had to add the tail descriptions lol.
EDIT: Apparently I needed to take a short break. Syntax error stopped me in my tracks. Fixed now, and working as intended... now to figure out how to deal with descriptions.gd which has dozens of changes and additions lol... This is gonna be fun. Special thanks to Ankmairdor for the help on Discord. Sorry I wasted your time lol.
List of all my mods (currently unreleased):
Alchemy For Dummies - Replaces all alchemy recipes with a recipe requiring one Basic Solution (Breaks game balance, I'll make another mod later to fulfill the purpose behind this mod - avoiding the grind of fighting hundreds of monsters with limited stamina [read as: stress] forcing multiple breaks and cutting into valuable gaming time; this mod was just a quick & dirty one intended to make me smile and get me used to the modding environment while also granting me the satisfaction of never having to farm underground monsters again lol. Why are they so far from town?)
Beastkin Mouse & Rat - Adds the named races to the game via a simple method, and adds custom descriptions for them. Because of how the game is coded, this automatically creates the halfkin variants of each (for those of you that don't know - all Beastkin have a halfkin variant and it's handled automatically by the code)
Combat Preview Fix (Not working, need to figure things out for this one; it's intended to show the exact number of enemies [working] and the highest level of all enemies present [not working at all])
Combat Stress Reduction - Reduces stress gained per turn in combat, as it says on the tin.
Gender Equality - Adjusts character creation for gender equality by allowing almost all options regardless of gender. (minor tweaks required before it's release ready)
I'll be working on a few other things here or there, like rebalance patches and such. I'd love to have a look at the quest log and make a backlog of completed quests, and also rewrite a bunch of questlog entries because coming back to an old save and trying to figure out what's needed is kind of annoying. It's far easier to start over, and that means walking away from whatever amount of effort your put in the previous save.
One other thing I'd like to tackle at some point is changing that intro text that pops up during character creation. I want to move the button and reduce the size of the text window... it really doesn't need to be that big... but those are on the editor side, and I can't be bothered to open Godot right now lol.
The game does not have permission from the OS to create folders/files in the Strive program folder so it didn't create or fill the "backup" folder which is the backbone of the mod system. You should move the Strive program folder to a new location that has more open permissions. Generally the desktop works, otherwise documents folders tend to work. If neither of those work then you can add it to ".../AppData/Roaming/" next to the Strive user data folder.
It seems you resolved your other issue but I will add this for others.
In the bottom right of your mods menu is the path "user://mods/Leo/", this should be "user://mods/". You need to press the button for the path and use the black arrow at the top of the folder dialogue to go up a folder.
As a result of this bad path, a duplicate of the Constants mod was created inside the Leo's mod folder. It's best to delete that duplicate after changing the path in game, though it should usually be harmless.
The method of the Expanded Sex mod is rather old fashioned and clunky. Aric's Expansion GitHub version uses the modern method. I recommend using the patching section of the modding guide to put the new sex action files directly into the game folder ".../files/scripts/actions". The path in your mod would simply be "...YOUR_MOD/patch/files/scripts/actions/YOUR_FILE.gd".
The simple answer is that after the mod system resets the game files to the backup state the mods are applied from top to bottom with each successive mod applying changes to the resulting state of the files.
There are some nuances to how the order affects the conflicts of mods as there are multiple ways to mod scripts. Line edits (tagged changes) to add or remove lines from existing definitions are tracked by the mod system in order to attempt to maintain correct line targeting for later mods. However, if multiple mods attempt to edit the same lines, then the mod system will likely not resolve the conflict. Due to the line targeting corrections lines added by mods are not indexed, and thus cannot be directly line edited.
For file patching and definition replacements (untagged changes) the mod system overwrites the relevant code regardless of prior changes and resets the tracking of line edits. However, this means that successive mods may incorrectly target lines if they were expecting a vanilla definition.
There are a lot of potential nuances to what you are asking and without elaboration on your part I will have to do so.
Importing an image is different than loading an image when working with Godot, Strive's game engine. Images are imported only by the Godot Editor and stored as multiple files; the critical ones being the text file(.import) that tells how to load the image and the slightly altered image file(.stex). Unless you are adding the image to a scene file(.tscn or .scn), loading images during the initialization of the game, or wish to obfuscate it from other users, there is no need for importing as Strive has a "loadimage" function in globals.gd that will load any valid image file.
The process of importing is fairly simple. Place the image in the Strive program folder in the exact location(relative to the program's root folder) where you plan to use it from. Start the Godot Editor and scan the Strive program folder to find the project file. Load the program folder as your project and the editor should automatically import the image.
Including the imported image in a mod is as simple as including all the files for the imported image except the image file itself (unless you want to, but it will double the size) in the "patch" folder of the mod. Use the same folder structure in the "patch" folder as program folder to get the files to the right locations.
Okay, I give. It's possible I'm not even messing with the right part of the code (I recently did a giant overhaul of the game's text just for fun before realizing that the text I was working with was obsolete/nonfunctional and just a few lines had been lifted to an entirely different part of the code, which was the part that actually mattered, sigh). It's possible that I'm overlooking something basic, or that the part of the code I'd actually need to mess with isn't even editable in the user-accessible text-style files, so here I am hoping for answers/guidance.
(Note: I'm a longtime hobbyist coder/game designer, and new to Godot/GDScript, but it's similar to many languages I've used over the years, and most of the basics are easy enough to grasp. So I expect I might be failing at some core distinctions or underlying foundational details.)
Anyway, so, in StatsTab.gd I found the section where some buttons pop up and you can order them to call you by a new name. So I figured I'd try to add a button that lets you change their name. Mostly I'm just copying what seems like a reasonable section of code and changing a few tidbits that seem like they won't break anything. (I do feel a bit like the classmates I tutored back in college, when I was already skilled in Visual Basic while they were randomly copy-pasting code with no grasp of the underlying structure and then getting confused why it broke.) It easily created a button, but of course the button doesn't do anything.
So I hunted through a few files, making some educated guesses, and happened across Mansion.tscn (I've only recently dug into files that aren't .gd), which does have the right variable names (callorder, callconfirm). So I copied some code there, changed names to match the other file, and gave it a shot. No dice. Button appears, but does not do anything.
I double-checked that I hadn't misspelled anything, and that all the references match the pattern of the original code ("callorder" becomes "namechange", "callconfirm" becomes "namechangeconfirm"). Nothing looks like it needs a particular uncopyable code (e.g. a unique numerical ID). It appears that having identical names (like "Label") is fine so long as they're under distinct Nodes. I finally got smart enough to open all the files collectively in Notepad++ and search for the variable name, and it appears that these are the only two files that reference it, out of the Scripts folder and the Files folder.
And just to test, I went through the original functions and changed the internal parts (not referencing the variable name) and got a functional change-name button. But changing all the references to "callorder" and "callconfirm" to "blahcallorder" and "blahcallconfirm" breaks the button entirely, so clearly there's something else going on here.
So now I'm stumped.
Here's the original code. To keep the code here shorter, I've omitted the Anchors and Margins, as I can't imagine they're part of the problem here (and I haven't messed with them, just copied them wholesale hoping the button would show up in the same place). Again, all I did was change "callorder" to "namechange" and "callconfirm" to "namechangeconfirm" in copied code in the same file:
Part 1 (in Mansion.tscn): [connection signal="pressed" from="MainScreen/slave_tab/stats/callorder/callconfirm" to="MainScreen/slave_tab/stats" method="_on_callconfirm_pressed"] Part 2 (in Mansion.tscn): [node name="callorder" type="Popup" parent="MainScreen/slave_tab/stats"] size_flags_vertical = 2 [node name="TextureRect" type="TextureRect" parent="MainScreen/slave_tab/stats/callorder"] texture = ExtResource( 44 ) expand = true [node name="Label" type="Label" parent="MainScreen/slave_tab/stats/callorder"] size_flags_horizontal = 2 size_flags_vertical = 0 text = "How should $name address you?" align = 1 [node name="callconfirm" type="Button" parent="MainScreen/slave_tab/stats/callorder"] size_flags_horizontal = 2 size_flags_vertical = 2 text = "Confirm" [node name="LineEdit" type="LineEdit" parent="MainScreen/slave_tab/stats/callorder"] size_flags_horizontal = 2 size_flags_vertical = 2 caret_blink = true Part 3 (in StatsTab.gd): func callorder(): get_node("callorder").popup() ## Improved phrasing get_node("callorder/Label").set_text(person.dictionary("How should $name address you?")) get_node("callorder/LineEdit").set_text(person.masternoun) get_node("callorder/LineEdit").set_placeholder(person.getMasterNoun()) func _on_callconfirm_pressed(): get_node("callorder").visible = false var text = "" ## Improved phrasing plus support for characters who don't speak with their mouths if !person.traits.has("Mute"): text = "You have ordered $name to call you '$master' from now on. " else: text = "Since $name cannot speak, you teach $him a way to sign '$master'." person.masternoun = get_node("callorder/LineEdit").get_text() get_tree().get_current_scene().close_dialogue() get_tree().get_current_scene().popup(person.dictionary(text)) Part 4 (in StatsTab.gd): buttons.append({text = person.dictionary("Order to call you ..."), function = 'callorder'}) SAMPLES OF MY VERSION: ## Testing to see if I can add a button buttons.append({text = person.dictionary("Change Name"), function = 'namechange'}) #That part worked fine, but the rest doesn't: [node name="namechange" type="Popup" parent="MainScreen/slave_tab/stats"] [connection signal="pressed" from="MainScreen/slave_tab/stats/namechange/namechangeconfirm" to="MainScreen/slave_tab/stats" method="_on_namechangeconfirm_pressed"] func _on_namechangeconfirm_pressed():
Note: I'm not adding interior line breaks or tabs in the actual code unless they're there in the code I'm working from. The copy is identical except for the variable name changes, the obvious strings (like "Order to call you..." to "Change Name", which works fine), and a bit of If/Else code (which I'm not having any trouble with elsewhere and doesn't seem to be related to the problem).
Any clue what I'm missing?
Hello, I basically became the leader of the modding community here after I spent a couple years debugging this game, though I haven't been as active lately. Usually the fastest way to get help is to ask on the Discord (https://itch.io/t/284398/discord), but I try to keep an eye on this site as well.
Godot Script is mostly Python with a little LUA mixed in so the basics should be intuitive to anyone that has messed around with other scripts, but it does a few things in eccentric ways. Most of the files can be edit in text editors, though I recommend using the Debug mod (https://itch.io/t/1137280/debugmod-v10d) for dealing with errors. For general editing of the GUI (scene files .scn and text scene files .tscn) I strongly recommend using the editor provided for the Godot Engine. The game's program folder is mostly the same as the project folder and it uses a version between 3.2 and 3.3 (the latter is likely the closest match).
Strive for Power was created by a beginner programmer so the code can be straightforward to read but messy in design. Large sections of code and even entire files are no longer used, with no clear indications most of the time. This problem was rather low on the priorities list so I haven't gotten around to it.
Scene files are generally used to create GUI that is not expected to dynamically change form or order during run time. Godot provides multiple ways to connect functions to actions such button presses. For buttons created in scene files the standard approach is the stuff you found at the bottom of the file:
[connection signal="pressed" from="MainScreen/slave_tab/stats/callorder/callconfirm" to="MainScreen/slave_tab/stats" method="_on_callconfirm_pressed"]
However, Strive has multiple systems for dynamically creating buttons during runtime and the system relevant to what you are working on is "func dialogue" found in ".../scripts/Mansion.gd". In another function it uses the following code to bind functions to the button presses.
newbutton.connect("pressed", destination, array.function, array.args)
However, this all works pretty well and there's not really anything to worry about besides making certain that you spelled things consistently.
You have excluded some details of your version, so it's not possible for me to determine the exact causes of your problems. My first guess would be that you have not named your name change function exactly 'namechange', put something in the wrong file, or missed renaming something not shown. I would expect it to be in statstab.gd and look something like this:
func namechange(): get_node("namechange").popup()
You didn't specify the location and said it works, but I assume your dynamic button data looks similar to this:
buttons.append({text = person.dictionary("Order to call you ..."), function = 'callorder'}) buttons.append({text = person.dictionary("Change Name"), function = 'namechange'})
For clarity, the name of the function should be as you specified in your dynamic button data. The node names and paths for get_node() in your function should be as you specified in mansion.tscn.
Also, while it doesn't appear to cause any errors and you mentioned not adding line breaks, the signal connection lines contain breaks that are not originally present in the file. A bigger problem would be using spaces instead of tabs within your code.
Yeah, I specified that I didn't change spaces in the actual code because I did add line breaks here (to prevent it going off the side of my screen when I switched it to Code Mode there). I'm aware that spaces can be functional; they aren't in most of the languages I've used, but since Godot/GDScript uses indentations functionally I presume that all whitespace is potentially functional and I'm careful about not messing with it (my brain is pretty well specced to grasp open/close mechanics such as parentheses and nesting -- that's the very thing that those classmates in college were messing up all the time, pasting code into random spots and breaking the nested logic of the original code).
ETA: And yes, I am very careful about the distinction between tabs and spaces. I'm using tabs in the code for all the indentations -- they don't just look similar, they are equivalent even in the whitespace.
Here's my code (again omitting Anchors and Margins, for brevity). Again, these are in the exact same files, matching the original code exactly, including the white space (the line breaks have been added here purely for readability, and are not used in the code); the only thing I have changed is the variable names (carefully matched in logic to the original set of names), obvious Strings, and some If/Then logic that shouldn't impact the buttons themselves, just the text displayed (I even commented it out with a test string instead, to be sure it wasn't screwing things up).
############################################## #### Testing to see if I can add a button #### ############################################## [node name="namechange" type="Popup" parent="MainScreen/slave_tab/stats"] size_flags_horizontal = 2 size_flags_vertical = 2 [node name="TextureRect" type="TextureRect" parent="MainScreen/slave_tab/stats/namechange"] texture = ExtResource( 44 ) expand = true [node name="Label" type="Label" parent="MainScreen/slave_tab/stats/namechange"] size_flags_horizontal = 2 size_flags_vertical = 0 text = "What name should $name respond to?" align = 1 [node name="namechangeconfirm" type="Button" parent="MainScreen/slave_tab/stats/namechange"] size_flags_horizontal = 2 size_flags_vertical = 2 text = "Change Their Name" [node name="LineEdit" type="LineEdit" parent="MainScreen/slave_tab/stats/namechange"] size_flags_horizontal = 2 size_flags_vertical = 2 caret_blink = true ################## #### END TEST #### ################## ############################################## #### Testing to see if I can add a button #### ############################################## [connection signal="pressed" from="MainScreen/slave_tab/stats/namechange/namechangeconfirm" to="MainScreen/slave_tab/stats" method="_on_namechangeconfirm_pressed"] ############################################## #### Testing to see if I can add a button #### ############################################## #### Function called when new button gets pressed: func namechange(): get_node("namechange").popup() get_node("namechange/Label").set_text(person.dictionary("What name should $name respond to?")) get_node("namechange/LineEdit").set_text(person.name) get_node("namechange/LineEdit").set_placeholder(person.name) #### When new button gets pressed: func _on_namechangeconfirm_pressed(): get_node("namechange").visible = false var text = "" text = "Yes, $master." #if 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 even my name away??" #elif person.obed > 70: ## Highly obedient # text = "— Of course, $master. Every part of me exists to serve your will." #else: ## Moderate, compelled obedience # if person.conf > 60: # text = "— I guess I don't have much choice." # else: # text = "— Yes... $master." person.name = get_node("namechange/LineEdit").get_text() get_tree().get_current_scene().close_dialogue() get_tree().get_current_scene().popup(person.dictionary(text)) ## Testing to see if I can add a button buttons.append({text = person.dictionary("Change Name"), function = 'namechange'})
So yeah, I don't think I missed something as simple as using the wrong name. And since changing the original names (in both files) to blahCallOrder and blahCallOrderConfirm completely broke the original sections that were working, and since none of the other files in either directory reference these variables, it definitely feels like I'm missing a piece that needs to get accounted for elsewhere.
Also, I included the buttons.append line exactly as you quoted, in my "samples of my code" at the end of my first post there. Just added it to here for completion. Really wish the code formatting let me include line breaks, this wall of text stuff is killing me.
I don't see any problems with the code as presented, including the commented out code. Probably due to itch.io formatting you are missing leading whitespace in the functions so I'll have to take your word that it is not an issue. You haven't specified if you are using the Debug mod or the editor, so I can't rule out the possibility of a tangentially related error somehow sabotaging you.
Itch.io code can be formatted but it doesn't play nice with copy and paste. Edit: seems extra lines really don't work, though adding a space to them works.
code code after extra line break code after tab code after extra line break with space
If we assume that there are no errors, then we will have to get creative in looking for the source of the problem. Please verify that you are not editing the files in the "backup" folder for Strive as those files are 100% copies but are not used except to replace the game's files whenever the mod system applies or resets mods. Note that any changes you have made to the non-backup files will be erased if you use the mod system, and the Debug mod doesn't actually use the mod system. Additionally if you have made your own copies of the files, make sure that the game is using files with your latest changes. Finally, I've had people report in some cases that editors like Notepad++ were somehow editing something like copies of files rather than the actual files so their edits had no effect, though I've never had this happen to me.
Using the Debug mod or editor it is possible to use print() to get direct feedback as to the state of the program in functions, which can be more useful than relying on the Game's GUI to behave as expected. The game also has a system designed for file based trace statements in globals.gd, but those are more helpful for dealing with crashes.
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
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?
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'
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.
Yes, it is possible to move slaves between progresses, but there are a few data points to be careful of duplicates. Newly generated persons are simply assigned an ID number from a the counter "globals.state.slavecounter", which then increments. Some functions search for slaves by ID, which would only be capable of finding the first slave in the list with that ID. There is also the 'unique' data which identifies starting slaves and quest slaves, which could have similar problems. Finally, any relations data or data involving interactions with other slaves would be incorrect.
Hmm, interesting.
So the fact that the ID is so high is because I caught and sold a bunch of slaves in between finding ones I liked.
Does the unique ID stay with sold slaves (until they presumably vanish from the market), or are they given a new ID when you buy them back? I've been using a sell-and-buyback strategy to get Mansion Upgrade points and a brand.
If selling slaves gets them out of the pool but maintains a higher slave counter, would it be possible to change my preferred slaves to the IDs e.g. 12, 13, 14, 15? I could either ignore the relations/interactions data, or figure out how to swap a few numbers around.
I wouldn't be messing with the unique/quest slaves, yeah. I pretty much always use the same starting slave specs anyway (I found a nice setup that works with my overall story concept, and gives me a neat pun, so it'll be a while before I tire of that specific character).
The ID increments any time a person is generated, so every step of your exploration that generates an encounter with persons in it increases the counter even if you choose to ignore or evade the encounter. The ID and 'unique' data stay the same for a person for their entire existence until they are deleted. This means that even if you sell and re-buy someone they maintain all their relations and relatives data with other persons. I mention the 'unique' data entry because some people like the idea of having multiple custom starting slaves.
A safe approach is to change a transferring slave's ID to be the current value of "globals.state.slavecounter" and then increment that value manually. It may also be safe to change IDs to be negative for transfers, though I haven't checked this thoroughly. However, if you are moving multiple slaves and want them to maintain a friendship, rivalry, or family status, then the corresponding ID values have to be changed to match the new IDs. The rest of that data should be deleted or not transferred to the new progress otherwise a transferring slave may have some preconceptions about slaves they have never met before.
Hmmm. Sounds like suboptimal code, the idea that characters get created before the game knows whether they even matter (whether the player will in any way get to see the details). It would make more sense to say "There's two bandits over there, do you want to engage?" and then, if you engage, generating characters. This problem would be even worse for those giant packs of bandits I've seen (but not yet engaged with).
Actually, optimal code would likely generate a full character only upon capture, and generate a partial (necessary stats only) character for combat, then generate the next partial bit at the end of combat (when you get to see a few new stats), and finally transferring the partial character into a fresh full character if you capture them.
It's good to know that the uniqueness sticks around even if you sell them, though. That does avoid some issues.