Ok, not entirely sure of the best to organise this so I'm just gonna go ahead ramble.
Training apply per APFirst of all training now applies its stat/trait/effect/whatever changes according to the "doNum" property. It defaults to 0. doNum works like so:
if amount == 0: amount = self.girl.AP
while amount > self.course.AP:
# do stuff
amount -= self.course.AP
Where amount is set to doNum. This allows for the course to either apply its changes a set number of times, or to keep doing so until the girl is out of AP.
One-off-event TrainingLessons can now be one-off-events. These are lessons that have a "labels" dict. The dict contains "state"->"label" pairs. The labels are normal renpy labels and the states are the flags returned from the check_success() function in TrainingJob that specify how the training went.
The default flags are:
- "normal" = No special state, training went as planned.
- "obey" = The girl was very obedient, gained an obedient point.
- "disobey" = The girl was very disobedient, gained a disobedient point.
- "stop" = The girl refused to be trained and the lesson was unassigned, gained a disobedient point. Used for schooling, notably free girls given XXX courses.
- "runaway" = The girl managed to runaway.
- 0 (girl_ap) = The girl had no AP.
- 1 (hero_ap) = The trainer had no AP.
- 2 (no_gold) = The player couldn't afford the training.
- 3 (bad_trainer) = The girl refused to be trained by the trainer.
Currently only for girls that don't have the Broken trait and have disposition < 500 who have a slave as a trainer.
The 4 flags with numbers aren't 'normal' success states, as they apply before success is checked. They can still however have labels assigned to them. The labels dict requires a "normal" label, all others are optional and will use the default labels if not specified.
"obey" doesn't have a default label, as the labels in renpy must be defined as:
label my_training_event(girl, trainer, job, obeys):
# blah blah
Where "girl" is the girl being trained, "trainer" the trainer, "job" a OneOffTrainingJob instance and "obeys" a boolean that flags whether the girl got the "obey" state. This allows the normal training label to cover both normal and obedient states with optional extra content if the author doesn't want to write an entirely different / cloned label.
The labels are accessed through renpy.call() and so should end with a return statement.
The OneOffTrainingJob class is a special subclass of TrainingJob that is used for these training events as they occur outside of normal next_day logic and still need to be reported. They are used to calculate the check_success state and create the event for the next day screen as normal. To actually apply the training changes you need to put the following somewhere in the label:
$ job()
One-off-event training forces a doNum of 1, as it is used like an interaction and only takes up the AP of the girl and trainer when used.
TrainersCurrently all girls can work as trainers. They are assigned just like other jobs and become available to set to training girls in the training assignment screen. Girls can refused to be trained, but only as specified above under the "bad_trainer" state. Non-player trainers can be used for one-off-event training and so the labels should be written using the "trainer" argument instead of "hero".
ItemsSome items and traits were added to test using equipment to affect the chance to obey/disobey/runaway.
The traits and items are:
- Restrained = Decreases chance to runaway. Slave Collar (amulet), Wrist/Ankle Manacles (wrist/feet).
- Easy to Reward = Increases chance to obey. Pleasurable Vibrator (misc).
- Easy to Punish = Decreases chance to disobey. Shocking Vibrator (misc).
The items add the traits, and the traits contain a new property called "trEffMax". trEffMax is used to calculate the maximum that the trait can add to the chances to form a multiplier. Eg: Restrained has a trEffMax of 5. Each item adds 1. If the girl has 3 equipped the multiplier would be 1 - 0.6 = 0.4.
Girls List and Girl ProfileSome slight changes here. As well as "Train" being added as a valid action under TrainingDungeon, "Take Course" has as well. Instead of assigning the action "Take Course" sends you directly to the training assignment screen.
City JailI gave the jail a location on both variants of the map so it can be accessed. Fell free to change these whenever.
The jail now has a background and standard look_around action.
The jail has a "Browse Cells" action which triggers "browse_jail_cells" events. Currently no events in, but I figured this would be needed at some point.
The add/remove prisoner functions and list in the CityJail class are currently unused. I decided I wanted to keep the logic for escaped girls separate from the normal jail code so it could be easily managed under 1 class.
Slave MarketI decided to use the current slave market interface for the browsing and release of your escaped slaves for convenience. To this end I recoded the pyt_slave_shopping screen. It not accepts arguments of the following:
screen pyt_slave_shopping(store, tt_text, buy_button, buy_tt):
# blah blah
- store = The SlaveMarket instance to pull the slaves from.
- tt_text = The default tooltip text.
- buy_button = The text to show on the buy button.
- buy_tt = The tooltip text to show for the buy button.
As such the pytfall.world_actions.slave_market() function now requires you to pass the following arguments:
slave_market(store, tt_text, button="Go Shopping", null_button="No Slaves Available", buy_button="Purchase", buy_tt="You can buy this great girl for a measly sum of %s Gold!")
There was 1 or 2 slight changes to the SlaveMarket class to facilitate this change, but most importantly a new property was added called "girlfin". This returns the Finances class for the girl. This was added to the store instance passed to the screen can override this behaviour. In particular this was used so that retrieving escaped slaves from the jail costs their base_price * (0.75 - (0.125 - time)), where time is how long they left in the jail. This imitates the 'bail' of the girl being lower then their normal costs, and allows it to increases the long they are in jail.
Running AwayMost importantly, this release includes the RunawayManager class. The class that handles all the logic for escaped girls.
The RunawayManager instance can be found at pytfall.ra, and is included in normal pytfall.next_day behaviour.
Currently only slave girls can run away. I thought about making it so that free girls would simple leave your service immediately, but don't know if you want them gone for good, placed back into the girls meet code, whatever.
If a slave manages to successfully get a runaway state during training their training stops and are added to the RunawayManager.girls list. This sets their location to "Unknown", action to "Hiding" and prevents you from interacting with them in the girls list and girl profile screen apart from viewing their gallery. You can filter escaped girls in the girls list screen using the "Run Away" filter on the right.
If the RunawayManager contains girls it will push an event during the next_day screen in the training section telling you which of your girls have escaped. It also contains debug info on their status if developer mode is on.
There is debug code in the class which adds the first 2 slaves in the players girls list to the manager on day 1 to help testing.
The manager calculates the girls "status" which is currently an average of their vitality, intelligence and agility stats over their maxes. This figure is passed to the dice function to calculate the chances for the following next_day behaviour:
- All look_around events are cleared.
- Any girls that should be released from jail are.
- Any girls that are in jail have their jail timers decreased.
- Any girls that aren't in jail have their escaped timers increased.
- Any girls that have been free for over 20 days have a chance to escape. These girls are removed from the players list.
if dice(status) and dice(escape_time) - Any girls that have been free for over 10 days have a chance to be jailed. These girls are added to the managers jail_cache.
if dice(status) and len(jail_cache) < 10 - Any girls that have been free for over 5 days have a chance to generate a look_around event.
if dice(status) and len(look_cache) < 5
The look_cache events will use the label contained in the new Girl property "runaway_look_event". This is "escaped_girl_recapture" by default which is a generic recapture label which guarantees capture. These events must call "pytfall.ra.retrieve(girl)" to have the girl returned to the player if desired.
Currently the chances generated using the girls status gives a decent amount of chances to find the girls in look_around events and in the jail. The limits on the amounts though would decrease this is too many escape, a valid outcome of trying to find so many people at once. 20 days seems like a decent amount of time to try and recapture a girl, and the girls are only in jail for 5 days.
End~Everything should be working. I might have introduced a bug where the events manager removes the wrong events in the kill_event function, but I'm gonna have to do more testing to find out.
How do we want to handle free girls in relation to escaping?
Do we want to change the numbers in the runaway manager?
Should I integrate the unused CityJail code into the slave market interface so characters can be added to the jail without needed to use the RunawayManager?
As the knowledge and skill scores for the trainer during training can be calculated independently for different lessons (dancing classes can use different stats to sex classes for instance) I felt that allowing all girls to teach others was a good idea. It removes the need for a specific skill, although one can be added to provide bonuses for if they do teach. Maybe add a new occupation?
I'll post more here later if I forget anything.