OVERVIEW A Transformable is a structure representing a statistic that can change during the course of play. They are generally implemented on People, but there is no reason that they can't be implemented on other sorts of objects as well. The general idea is that a parent object contains a number of Transformables, and looks at these Transformables when it generates descriptive text. The parent object might also implement methods that examine several Transformables, along with worn apparel and other information, to determine something (Person.isFemale or Person.isMale, for example). The story can also examine the current value of a Transformable and respond appropriately, or modify the value of the Transformable during play. Note: Transformables and Apparel need to be able to interact. For example, breast forms or a chest wrap ought to temporarily modify the chest transformable, for all intents and purposes. A GenericTransformable implementation is provided, from which other Transformables can be derived. IMPLEMENTATION GenericTransformable provides a structure for a statistic that ranges along a single axis. It provides the following internal values, accessable through methods: - an integer "value" (default: defaultValue) The current actual value of the transformable, that the game code reacts to (see below). - an integer "newValue" (default: value) The value that the current value will be change to when the transformation is applied (see below). - an integer "defaultValue" (default: 50) The value that the transformable is initialized to if no value is given in the defaults table. - an integer "maxValue" (default: 100) The highest value that this Transformable can reach. - an integer "minValue" (default: 0) The lowest value that this Transformable can reach. - an integer "hardMaxValue" (default: undefined) The highest value that this Transformable can reach even with apparel modifications etc. - an integer "hardMinValue" (default: undefined) The lowest value that this Transformable can reach even with apparel modifications etc. In almost all cases, the accessor methods below should be used in lieu of direct access of the fields. The fields are only exposed so that values can be included in object defaults tables. The exception to this is when the game wants to look at the raw transformable value before it is modified by apparel and such. When a Transformable is instantiated, its fields are initialized to those listed default values. Subclasses should override the access methods or fields to change these defaults. The following methods are provided: getValue() returns value, modified by any apparel worn by the parent object etc (ie 6" heels will increase height by 6"), capped between hardMinValue (if defined) and hardMaxValue (if defined) inclusive. getNewValue() returns newValue, modified by any apparel worn by the parent object etc, capped between hardMinValue (if defined) and hardMaxValue (if defined) inclusive. setValue( int v ) newValue = v; // But capped between minValue and maxValue inclusive. // If SmutBook.Config.immediateTransformations is true, then applyTransformation(); increase( int amount ) setValue( newValue + amount ); decrease( int amount ) setValue( newValue - amount ); getDescription( bool thirdPerson = false ) The default implementation throws an error. applyTransformation() value = newValue; // See below. Note: The single-axis scale structure is appropriate for most things: height, hair length, body shape, genital and chest size, etc. But it is not appropriate for things like hair color, for example, which are picked from a collection of possible values that don't have any particular scaled relationship. In this case, it would be best to define some constants on the subclass (ie. HairColor.BLACK) that the Transformable's value field can be explicitly set to, and the increase() and decrease() methods overridden to disable them. MINIMUMS AND MAXIMUMS minValue and maxValue can be used to prevent tranformations from going too far into undefined or ridiculous territory. For example, capping height between 4.5-6.5 ft, capping breast size >0, etc. hardMinValue and hardMaxValue should generally be left undefined. These set a cap even after modifiers from apparel and other effects. An exception might be putting a hard cap on breast size >0 (a chest wrap just hides your tits, it doesn't cave your chest in lol). IMMEDIATE AND DELAYED TRANSFORMATIONS There appear to be two different ways that transformations are generally handled within a game's narrative. One way is immediate transformation, where an action by the player results in an immediate change to the player character. You drink a potion, and your hair grows. The other way is delayed transformation. The player character goes through their day (or a number of scenes until a transformative event, or whatever). The actions that the player chooses for the player character throughout the day don't result in a transformation until the player character sleeps, visits the witch, etc. SmutBook provides a configuration field, SmutBook.Config.immediateTransformations, to switch between these two paradigms. THe default is delayed transformation. Setting SmutBook.Config.immediateTransformations to true changes the library to do immediate transformations. In the delayed transformations mode, all changes to a Transformable are applied to its newValue, and the newValue only replaces the current real value when applyTransformation() is called. Immediate transformation mode acts the same way, except that applyTransformation() is automatically called before setValue() returns. INTERACTION WITH APPAREL FIXME TODO WornApparel has implements the method getTransformableMod( String transformableName ). This method goes through all of the contents of the WornApparel, looking at each item's .transformableMod[transformableName] field, and totaling them up. getValue() and getNewValue() call this method on the parent object's apparel object, if it has one, and modifies the returned value accordingly. This functionality can be used to implement things like high heeled shoes that increase the wearer's height, breast forms that increase the wearer's bust size, chest wraps which decrease it, strapon dildos, etc. FIXME TODO Likewise, a Transformable can be given a ClothingSlot that it occupies. This way, worn apparel descriptions can include body parts that they partially conceal. For example, "She is wearing a sheer negligee, revealing her C-cup breasts, her 8" cock, and her heavy balls." TRANSFORMABLES TO IMPLEMENT Bust Flat Chest Puffy Nipples AAA AA A B C D DD DDD DDDD H Penis/Clitoris Scrotum/Vagina BodyShape (Butt/Hips/Waist/Shoulders ratio) HairColor HairLength Face EyeColor Feet Voice BodyFat (figures into BodyShape desc as well) Height Note: How to implement shaven/unshaven body parts? Note: Need a function that, given two prototype Persons, a list of transformable keys (or nil for all), and a percentage, returns a set of transformables that is that percentage in-between the two prototype Persons. This is for games where a character is slowly transforming into another specific person. Might also fix it so you can pass a list of transformable keys to exclude, as well.