Creating Mods
I don't know what this article looked like on the original wiki, but it didn't survive the transfer very well. The XML file was an absolute mess. I've cleaned it up as well as I can, but it's still a very difficult page to read - hopefully someone that actually understands modding can improve it further. -Pocket
This explanation written by julzor.
First of all, I suggest getting a copy of Girl Life from GitHub, since that gets the files and utilities that you will need to use. https://git.catrenelle.com/Kevin_Smarts/glife
You can open another mod (or any .qsp file) with QGen 5. QGen 5 is in the main repository of Girl Life. For instance, I cloned the Girl life repository in the folder "~/GitHub/glife". QGen 5 is "~/GitHub/glife/QSP/QGen5/QGen.exe".
Since I'm using MacOS, I start it with wine, which works just fine.
wine "~/GitHub/glife/QSP/QGen5/QGen.exe"
(Junjulaug75 note: I couldn't check this line because I don't have wine. Please check this KeyMAsterOfGozer)
To understand how a mod is set up: Open up an existing mod and look at the locations. Illume made two examples mods easy to install and understand, they should be in the forum, in the mod thread; they add a couple of basic actions to the game, but it''s better to not rush things.
Open the mod you prefer and look for the three locations (assuming the modder didn't change the locations order, they will work anyway...)
Every mod should have these:
mod_modname_setup
mod_modname_readme
mod_modname
Remember that the "modname" part in these is substituted with the actual mod's name. So in the case of the iwhore mod, these locations are:
mod_iwhore_setup
mod_iwhore_readme
mod_iwhore
1) mod_modname_setup
This location sets up basic info to be displayed in the mods admin page in the main app. Should look something like this:
!input basic mod information here.
!this location must be the first one
$mod_info[0] = 'pornster'
!0=mod name, saved to $mod_name[i] array
$mod_info[1] = '00100'
!1=mod version
!this will be displayed as version 1.2, fix3.
!if you input 40500, will be showen as version 4.5
$mod_info[2] = 'KeyMasterOfGozer'
!2=mod author
$mod_info[3] = 'Micro-manage porn schedule.'
!3=mod description, input a short brief here.
Illume worked his magic here: $mod_info[0] will be the name of your mod, but not the location that will be checked for. Pay attention to what's added before and after
mod_info[0]
In that case "mod_" and "_setup". So the location that it will be checked is "mod_modname_setup"
if curloc = 'mod_<<$mod_info[0]
usehtml = 1
!this will be only showed if you exec mod file. This location should be only called by gs, so this line will not trigger on normal mod playing
'<center><h1><font color=red>ACCESS DENIED</font></h1></center>
$mod_info[0] is a mod for Girl Life - English Community Version and can not be played individually.'
'You can find the main game in Tfgames site (external link)
'Our forum: Tfgames site (external link)'
2) mod_modname_readme
This location is just to give a detailed description for the main app's modpage. Should look something like this:
if curloc = 'mod_<<$mod_info[0]>>_readme':
'Mod <center><b>< font color=red> Pornster </font></b></center>'
'Mod is to allow fine-grained tweaking of the porn schedule. This is mostly just for me to get my feet wet making a mod.'
end
And the "core" of your mod will be checked it the same way. It's not displayed here but in the main game mod location... Anyway, once in game you read the detailed description written by the mod author you just installed the mod...
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3) mod_modname
This location gets run in every location in the game. So for this reason, it's probably best practice to make whatever you put here be a light as possible. It should probably only be a set of if statement checks that see if the current location that is actualy running is one that your mod is interested in. For instance, if you mod does something in your appartment in the city, you should check to see if the current location is the appartment in the city, and then do stuff. Probably a good idea to do a "gs" or "gt".
Example:
if curloc = 'mod_<<mod_info[0]>>_readme':
!input mod entry point here. this will be checked on every location, please keep it clean and brief to avoid game lag
!pornstudio
if $curloc = 'pornstudio': act "Hack the Schedule": gs 'mod_pornster_hack'
end
Notice, all this example does is add an additional action if the player is currently in the Porn Studio location.
The action then points them off to a safer location that acts more normally and is not run for all locations.
!!!!!PAY ATTENTION!!!!!!!
4) ALL INCLUDED LOCATIONS MUST BE NAMED IN THE FORMAT "mod_modname_locationname"
The "core" location of the mod not only will be checked by Illume's magic everytime... . The check that allow the mod to be used do not accept locations that have not the prefix "mod_" and the name of the mod itself. EVERY LOCATIONS.
So if you are used to create a location to store names variable code part number values and what do you want, and you are used to call it for example "notes"... doing that you will make a great mess. Instead call the storing location "mod_modname_notes" and everything will be fine.
A single location that have not the format "mod_modname_xxxxxx" will break the mod and it won''t load or will give error; be sure to double check the location format and the "_" break line symbol (put the correct name here)
Here is another sample from @julzor:
location: mod_testmod
if $loc = 'korrPar' and hour > 0 and hour < 6: gt 'mod_testmod_korrParAddition', 'night_event'
location mod_testmod_korrParAddition
if $ARGS[0] = 'night_event':
> add event
end
or if we also want to add a new action to korrPar, that is always there,
for example to go to the new balcony (we use a gs and not a gt):
location: mod_testmod
if $loc = 'korrPar' and hour > 0 and hour < 6: gt 'mod_testmod_korrParAddition', 'night_event'
if $loc = 'korrPar': gs 'mod_testmod_korrParAddition', 'new_action'
location mod_testmod_korrParAddition
if $ARGS[0] = 'night_event':
> add event
end
if $ARGS[0] = 'new_action':
act 'Go to the balcony: gt 'mod_testmod_balcony'
end
Some other words and examples from Junjulaug75...(absolutely in a terrible english)
$loc is a named stored variable (remember that "$" allow to store variable as name...) that Girl Life use sometimes to adress locations as long as $metka; they probably comes from the russian authors...
If the location you want to check is addressed that way, when you enter there you will have no problems; also Girl Life use in most of its location this address so you should go smooth most of the times...
IF NOT USE INSTEAD:
"$curloc"
"$curloc" is something that is part of the qgen/qsp: it stores the locations you visit independantly by the action you made: it will be always been checked...
Let summarize for the moment... .
Mod name conventions:
"mod_" will be the prefix for every location so if your mod will be called "wonderwoman", your core location will be "mod_wonderwoman".
The first two location have to be called "mod_wonderwoman_setup" "mod_wonderwoman_readme".
Then if you want to create a new location called "planet" it cannot be called simply "planet" but "mod_wonderwoman_planet".
Do not make a mess with names:
"notes" location: will make a mess
"mod_wonderwoman_notes" location: you can go smooth
What happen when you wrote "if $loc = 'school': act'stuff': gt 'school', 'lesson'" in your "core" mod location (mod_modname)?
If the location "school" address itself in that way $loc = 'school'
location: school
$loc = 'school'
$metka = 'something'
if $args[0]='lesson':
act 'study': stuff.................
end
...then when you will go to school you will go straight to the location "school" $args[0] = 'lesson'...
If not
location: school
$loc = 'something_blue'
$metka = 'something_green'
if $args[0]='lesson':
act 'study': stuff.................
end
that's because the check failed due to the lack of "$loc = 'school'" in the location school; in that case you should use "if $curloc" because it will be stored always.
We'll return to that later
Couple of examples:
If you want to add an action when you spray milk from your boobs at school...then you should do something like that in your mod:
First you should start, so you should create the three location in the right way. Copy/past the three locations Illume created. Rename them with the right format, adjust them according to your mod description and names or the setup will go wrong; you could use search/replace with qgen, but my advice is to have a look in them and do that manually; it will help you in a better coding understanding...
You should have the right named locations and setted
"mod_wonderwoman_setup"
"mod_wonderwoman_readme"
"mod_wonderwoman".
Now create a new location and name it
"mod_wonderwoman_milk"
Write in "mod_wonderwoman_milk" these lines
if $args[0] = 'wave':
msg 'why having boobs if i cannot shoot with them?...'
act 'SHOOT!': gt 'mod_wonderwoman_milk','no_wave'
end
if $args[0] = 'drink':
hydra += 20
act 'I think i have no more...': gt 'school_ground', 'start'
end
if $args[0] = 'no_wave':
msg 'Crap...i did not wrote how to wave...'
act 'return': gt 'school_ground', 'start'
end
Write in your "core" location ("mod_wonderwoman") these lines
#Location:"mod_wonderwoman"
if $curloc = 'school_ground' and $args[0] = 'start':
act 'spray milk': gt 'mod_wonderwoman_milk','wave'
act 'nahhh....i''m thirsty': gt 'mod_wonderwoman_milk','drink'
end</nowiki></code>
TIPS
From the new location you created you return back with gt 'school_ground', 'start' (...assuming the school_ground is a location i may be wrong and it could be gschool_ground....just look for it in the main game...)That will happen if the location has inside an $args[0] = 'start'.
Location can be entered even if they have no $args[0]; in that case you will go there simply with gt 'school_ground'. That is valid even when searching locations: if the location school_ground (or gschool_ground) has inside an $arg[0]='start' that is probably the entry point:
'school_ground'
and you will look for it that way.
if $curloc = 'school_ground' and $args[0] = 'start':
otherwise the entry point it's simply
'school_ground', 'start'
and you will look for it that way
if $curloc = 'school_ground':
The entry point is usually what have the main pic of the location of course; that is not valid if the location you are looking for is not a "physical" one.
DELETING ACTIONS
If you want to delete an action that is in game you should use "delact" and rewrite the act you just deleted as you wish (i'm not a master about it...) but it will be in the form:
#Location:"mod_wonderwoman"
if $curloc = 'school_ground' and $args[0] = 'start':
delact 'Go school'
act 'Go school': gt 'mod_wonderwoman_milk','milk_school'
end</code>
Of course the location 'school_ground' have to have the action "go school" (...i don't remember actually....) Do not commit mispell: if you are deleting the action "go school" you are deleting the action "go school" and not "go school naked"
...to delete "go school naked" use
delact "go school naked"
(...this for sure is not in the game....)
AVOID TO USE DYNAMICS
From what i know dynamics stores something that can be used easily by the game...anyway Illume said to not use them, you should recreate what the dynamics do and use what you created...that's a pain....
Let made it simple: shower is one of the things that is called with "dynamic" in that way:
dynamic $showerdin
So if you want to call the use of shower in your mod you should recreate what dynamic does inside your mod and call them in another way: i do that with
gs 'mod_modname_alocationthatstoresallthedynamicsiused'
(not called that way obviously)
This is the dynamic form for the shower:
$showerdin = {
menu_off = 1
if hypnoAddict = 0:
cumspclnt = 1
else
cumspclnt = 18
end
gs 'cum_cleanup'
pcs_hairbsh = 0
pcs_makeup = 1
if pcs_sweat > 10: pcs_sweat = 10 + rand(0,4)
if false_lashes >= 1:
if rand(0,4) <= 2:
'You''re careful enough that your false lashes make it through relatively unscathed.'
else
'Unfortunately, your false lashes don''t make it through the shower.'
false_lashes = 0
pcs_lashes = pcs_naturallashes
gs 'body_shape', 'basebeautycalc', 1
end
end
}
That's what i do:
I create 'mod_modname_alocationthatstoresallthedynamicsiused' location ...then i put in there
if $args[0] = 'showerdin':
menu_off = 1
if hypnoAddict = 0:
cumspclnt = 1
else
cumspclnt = 18
end
gs 'cum_cleanup'
pcs_hairbsh = 0
pcs_makeup = 1
if pcs_sweat > 10: pcs_sweat = 10 + rand(0,4)
if false_lashes >= 1:
if rand(0,4) <= 2:
'You''re careful enough that your false lashes make it through relatively unscathed.'
else
'Unfortunately, your false lashes don''t make it through the shower.'
false_lashes = 0
pcs_lashes = pcs_naturallashes
gs 'body_shape', 'basebeautycalc', 1
end
end
end
and i call that dynamic as a state:
'mod_modname_alocationthatstoresallthedynamicsiused', 'showerdin'
AGAIN: DYNAMICS CAN CALL FOR OTHER DYNAMICS INSIDE THEMSELF(...and the pain rise...and rise ...and rise...)
Another hint: pay attention to the main game changes.
Sometimes authors change the entry to a location; the entry in the park of pavlovsk, for example, time ago was simply gt 'gskver', because the entry were outside an $args[0].
It can happen that you wrote that correctly at the beginning but then things changed... .