As some of you are already aware, h.coder released the source code for potential future releases of Fetish Master; while the official version is still 0.985e, the Git source is versioned at 0.99. Over the last couple of years, I’ve been adding my own tweaks and changes, testing how I can bend the engine some without breaking it. None of these have been submitted for consideration to the main branch, as a lot of it is either subjective or hastily coded.
While I haven’t added new events, and only implemented a couple event tweaks and items to test some changes, it should be compatible with most mods. I’ve implemented a new digestion system, but a lot of the stomach content is based on Dohavocom’s code (with some tweaks) and should be compatible with his mod. The main branch also implements most of Maternal-Reads’ organ changes, so the only* issue at hand is Nost’s old mod, which may or may not be getting the clean-up and expansion it deserves soon enough.
*While Maternal-Reads’ mod is largely compatible, the way it’s distributed will be a bit of an issue. I might make a compatibility release, as a lot of things will likely go wrong if installed as-is. If you wish to install it, delete its dist folder first, and note that some of its changes might interfere with some of the changes in either the base 0.99 or this branch of it.
Unfortunately I’ve been a bit lax in terms of taking notes; I made most of my edits on whims and the old forum was the only source of documentation for most of it; neither Google’s cache nor the Wayback Machine captured the old threads in any useful capacity. Still, I’ll try to outline the major changes and caveats below:
Layered Images and Paper Doll support
Previously, the game supported two image layers - one for the background (DisplayBG()), and one for a character or object in the foreground (DisplayChar()). For modders that wanted a detailed paperdoll system - something where parts of the character image changed based on parameters like clothing, hair color, bust/belly size, etc. - this was pretty limiting.I’ve added a new method for use in events and templates: DisplayChars({})
.
Note the curly braces - while the other image methods take a single string as input (pointing to the matching image), DisplayChars acts on an array, which can be defined on the fly as a series of comma-separated strings inside a set of curly braces. The first image in the list will be the first rendered, making it the bottom layer, while the last image will become the topmost layer.
There are no limitations on the number of images that can be called, beyond memory limits, and otherwise as far as the user is concerned it functions similarly to the other display methods. The largest caveat as of now is that the process is fairly slow (it can cause the game to hang for upwards of a second), and I haven’t really worked on making it efficient.
Simplified flag operations, and EventExists
I was getting tired of how messy it was to get and change a flag's value just for simple increments, so I simplified the process withIncFlag/DecFlag(string)
As the method names suggest, these simply take the flag given as input, get its value, and increment or decrement the value by one respectively.
To further simplify matters, there's also AddFlag/SubFlag(string, int)
- similar to the above, it calls Inc/DecFlag on a given flag int number of times. There are also matching methods for personal flags - Per*Flag or *PerFlag, given your personal preference.
I also added a much less generally useful boolean method - EventExists(string). The given string should be the path to an event file, as generally as it would be for adding an event choice. If the file exists, it returns true, otherwise it returns false. This is primarily useful for modders who want their events to extend other mods - in my case I was using it to avoid triggering a certain dialogue path if the game couldn’t find that Dohavocom’s mod was installed, as there was no flag necessarily related to what I wanted to do.
New Digestion and Stomach Capacity code
Before the old forum crashed, there were some discussions about the inadequacies of the older digestion code. People with massive stomachs could take upwards of a week to digest their loads partially or fully, and the math didn't do a great job of handling low-calorie meals, to the point of some spectacular failures.As it was written then, the body would digest a set amount of calories per hour, and subtract an amount of food matching the calories digested to total calories ratio, with some quirks for low numbers. I rewrote it to be a little closer to reality - now the body digests a set amount of food per hour based on your maximum stomach size, so that a full (but not stretched) stomach would digest fully over the course of 40 hours or so, with overstuffed stomachs taking longer to process.
Additionally, stomach capacities and stretch capabilities were largely rewritten based on Dohavocom’s code. There are some changes; I don’t factor in things like the desireforfat skill, and some tweaking allows for the absolute maximum capacity to increase naturally, if very slowly, but as far as I’ve found nothing breaks compatibility with his mod. However, the amount of testing I’ve been able to do by myself is limited, and adapting for the old Digest-Up effects is still a bit of a trial-and-error process.
Changes to Body Fat Calculations
This is where things start getting a little dicey, as there's been limited testing here. Essentially, while the old code calculated an average weight based on the size, it made the assumption that body fat was zero percent, meaning everybody started at a perfect weight, and creating skinny characters was essentially impossible. Instead, I changed the calculations so that a portion of each (adult) character's starting weight is stored as fat, making estimates as to how much added weight would be 'excess' fat and changing some of the body fat level descriptions to be a bit closer to reality. Other changes include metabolism slowing down for underweight/starving characters and additional points of certain physical traits adding to your lean weight to simulate added muscle weight, and changes to the way lactating burns calories to balance things out.The big issue with this so far is that NPCs don’t eat without being forced to by an event; people who burn calories regularly via activities like milking won’t make up the deficit, eventually draining away their body fat and leaving them skeletal. At the moment I’ve implemented two separate quick-fixes - one specific to Belanika and one for NPCs with the npc_rest effect applied - that should prevent that from being an issue, if it ever really was one in the first place.
Support for limited-stock items in shops
Essentially, using addItemToShop(string, int), you can add an item to a shop in a quantity defined by int; after buying that many, the item disappears from the shop. However, the stock value is currently stored in the store inventory, and gets reset any time the shop is reloaded; you'll want to use this in conjunction with LoadShop below. Limited stock in a shop is denoted by text in parentheses after the item name describing the quantity still available, and you will get a warning if you attempt to buy more than what the shop has on hand.You may want to use this with a conditional method such as a flag check, as the specified amount of the item will be added to the store each time the AddItemToShop call is made.
'Parallel' organs and multiple sets of breasts
This is a mess of my own creation, owing to looking back at old versions of the SDK and noticing things that could've been implemented but weren't. The idea of a parallel organ was that you could have a second version of an organ under a different name, that still responded to the same action calls and acted on stats featuring its own name rather than a set of stats defined explicitly.As an example, I rewrote the breasts organ to support this sort of parallelism, with an example item added to the item shop designed to give characters a second set of breasts and a few events and descriptions changed. I haven’t explicitly rewritten most of the events, so I can’t guarantee things that affect the breasts organ would actually affect any other organs typed as breasts under different names.
The basic way of adding a parallelized organ is largely the same as activating any other. The game looks at .exists stats, and if they’re active, it tries loading the organ of that name. However, since something like breasts2 isn’t a defined organ, we have to make it look somewhere else. Instead, we tell the engine to look at the text value defined for the exists stat if doesn’t exist. if it finds something - say, if the text value of breasts2.exists is breasts - we create a new breasts organ, redefine its name as breasts2, and add it to the character. This requires the organ to be written in a way that the stats associated with it don’t have a defined organ name; for example, while the original breasts organ defined the volume of milk held with “breasts.milk_volume”, we need it to be something like this.name+“milk_volume”. If the stat name were the same for both organs, we’d be updating the stat for the original organ twice without even defining a unique stat for the original organ.
Naturally, this isn’t a perfect solution, and it might cause more headaches than it would’ve to just copy and paste the original organ a few times and changing the names. But there might be instances where it’s genuinely useful, complicated as it is. I’d love if I could get some feedback on this.
Permanent shops and LoadShop method
One of the big issues with the idea of adding limited-stock items to shop inventories was that shops were essentially temporary constructs; every time you open a shop with NewShop(), it creates a new shop. This makes it a pain in the ass if you want to add a limited-stock item but don't want it added every time the shop is opened, or want to keep track of stock between visits.I’ve added a new method LoadShop(String title)
that simplifies this through the magic of hashmaps. By using it instead of NewShop, it will create a storefront with the specified title if it doesn’t exist, or load the one stored in the world if it’s been created. This also means that AddItemToShop only ever needs to be called once, but again with the magic of hashmaps, if you try to add an item to a shop when it already exists, you won’t get duplicate shop entries (though calling AddItemToShop with a limited stock amount will add that amount of the limited item each time). And of course, if this all seems needlessly complicated, the old method works just fine.
For example implementation, look at the updated event file for the item shop near the outskirts.
Months, Years, Seasons and More
I've added a whole new calendar system that currently has no use whatsoever! Above the string of text in the bottom-left part of the screen telling you the day and time, you'll find another string with the day of the week, current month and day, and even the year and season. Click the image below for an example as the site probably cuts off the bottom.The game starts arbitrarily on Monday, April 7; assuming the Dimension Shift that defines the setting would’ve been big enough to define a new epoch, the year is now 52 After Shift, roughly in line with the timeframe defined by the history book in the library. The seasons should shift within a day or two of accuracy to a ‘real’ calendar, and while nothing actually uses the months or seasons yet, spring was chosen as the starting date as warmer months seem like they’d be better for tentacle beasts to thrive, which are integral to some of the early-game quests.
Modders looking to adapt events for specific seasons or months have a number of tools available to do so, and the DisplaySeasonalBG(String)
command can automatically display the right background for an event depending on the season, provided the proper files exist.
Modding commands for new calendar stuff
GameClock functions - prepend with "clock." in scripts:boolean:
isSeason(String season) //case-insensitive, accepts Fall or Autumn
isWinter()/isFall()/isAutumn()/isSpring()/isSummer() //simplification of the above
isMonth(int month) //compares by int; use 4 instead of April, etc.
isWeekday(string weekday) //checks day of week, including weekends
String:
getSeason() //returns season
getMonth() //returns current month as String
getWeekday() //returns day of week as string, including weekends
int:
getMonthNum() //returns month as number - 1 for January, 2 for February, etc.
Scripting functions:
DisplaySeasonalBG(String file)
//Loads files based on season
DisplaySeasonalBG(file.png) looks for Summer_file.png in summer, Autumn_file.png in the fall, etc.
If there is no seasonal image, no image will be loaded.
All files must have the same extension (the renderer doesn't care if it's the wrong one)
Autumn must be used in place of Fall.
I think that about covers the important stuff. There’ve also been a few tweaks to fix what broke when Maternal-Reads’ organs were implemented, as well as updated splash text and hopefully some fixes for the game to run smoothly on non-Oracle versions of Java.
You can find the source code for my branch at GitGud. I’ve uploaded a precompiled build to Mediafire (password: fmaster); as it lacks images, you’ll need the image pack linked below.
If possible I’d appreciate feedback - what works, what’s horribly broken, what could be improved and what’s too confusing. Most of this stuff was thrown together with little or no actual planning, so there’s a lot that needs cleaning up, but I’d like to know what people find useful and what can get moved to the back burner.
For anyone looking to try it out, make sure you’re using a clean install and fresh saves. The basic 0.99 image pack is available here, and if you’re installing other mods, please don’t copy over the dist folder if they include one.