import * as _ from "lodash" ; import { Appendage , AppendageType } from "./body/appendage" ; import { Balls } from "./body/balls" ; import { BodyPart } from "./body/bodypart" ; import { Color } from "./body/color" ; import { Genitalia } from "./body/genitalia" ; import { RaceDesc } from "./body/race" ; import { Entity } from "./entity" ; import { GAME } from "./GAME" ; import { Item , ItemType } from "./item" ; import { IParse , Text } from "./text" ; export namespace TF { export enum Effect { Unchanged = 0 , Changed = 1 , Added = 2 , Removed = 3 } export interface ISetTFRet { bodypart ? : BodyPart ; } export function SetRaceOne ( bodypart , race , ret ? ) { ret = ret || { } ; let changed = Effect . Unchanged ; if ( _ . isArray ( bodypart ) ) { const list = [ ] ; for ( const bp of bodypart ) { if ( bp . race !== race ) { list . push ( bp ) ; } } if ( list . length > 0 ) { changed = Effect . Changed ; const bp = _ . sample ( list ) ; bp . race = race ; ret . bodypart = bp ; } } else { changed = ( bodypart . race !== race ) ? Effect . Changed : Effect . Unchanged ; bodypart . race = race ; ret . bodypart = bodypart ; } return changed ; } export function SetRaceAll ( bodypart , race ) { let changed = Effect . Unchanged ; if ( _ . isArray ( bodypart ) ) { const list = [ ] ; for ( const bp of bodypart ) { if ( bp . race !== race ) { list . push ( bp ) ; } } for ( const bp of list ) { changed = true ; bp . race = race ; } } else { changed = ( bodypart . race !== race ) ? Effect . Changed : Effect . Unchanged ; bodypart . race = race ; } return changed ; } export function SetAppendage ( slots , type , race , color , count ? ) { if ( ! _ . isNumber ( count ) ) { count = 1 ; } for ( const app of slots ) { if ( app . type === type ) { const changed = ( ( app . race !== race ) || ( app . count !== count ) || ( app . color !== color ) ) ? Effect . Changed : Effect . Unchanged ; app . race = race ; app . color = color ; app . count = count ; return changed ; } } slots . push ( new Appendage ( type , race , color , count ) ) ; return Effect . Added ; } export function RemoveAppendage ( slots , type , count ) { let all = false ; if ( count < 0 ) { all = true ; } else if ( ! _ . isNumber ( count ) ) { count = 1 ; } for ( let i = 0 ; i < slots . length ; i ++ ) { const app = slots [ i ] ; if ( app . type === type ) { if ( all ) { app . count = 0 ; } else { app . count -= count ; } if ( app . count > 0 ) { return Effect . Changed ; } else { slots . splice ( i , 1 ) ; return Effect . Removed ; } } } return Effect . Unchanged ; } export function SetBalls ( balls , ideal ? , count ? ) { count = count || 2 ; ideal = ideal || 2 ; const orig = balls . count . Get ( ) ; const res = balls . count . IncreaseStat ( ideal , count ) ; if ( res > 0 ) { if ( orig === 0 ) { return Effect . Added ; } else { return Effect . Changed ; } } else { return Effect . Unchanged ; } } export function RemBalls ( balls , ideal ? , count ? ) { count = count || 2 ; ideal = ideal || 0 ; const res = balls . count . DecreaseStat ( ideal , count ) ; if ( res !== 0 ) { if ( balls . count . Get ( ) === 0 ) { return Effect . Removed ; } else { return Effect . Changed ; } } else { return Effect . Unchanged ; } } export function UseItem ( target , suppressUse ? ) { let changed = Effect . Unchanged ; if ( ! suppressUse && this . useStr ) { this . useStr ( target ) ; } for ( const effect of this . effects ) { if ( effect . func ) { const ret = effect . func ( target , effect . opts ) ; if ( ret !== Effect . Unchanged ) { changed = ret ; } } } return { consume : true , changed } ; } export function UseItemDesc ( target ) { const parse = { name : target . NameDesc ( ) , s : target === GAME ( ) . player ? "" : "s" , item : this . name } ; Text . Add ( "[name] chug[s] down a bottle of [item]." , parse ) ; Text . NL ( ) ; Text . Flush ( ) ; } interface IItemEffectsOpts { odds : number ; race : RaceDesc ; str : string ; count : number ; } interface IItemEffectsModStat { odds : number ; ideal : number ; max : number ; } interface IItemEffectsModStatMulti extends IItemEffectsModStat { multi : number ; } interface IItemEffectsIdealStat { odds : number ; rangeMin : number ; rangeMax : number ; max : number ; } export namespace ItemEffects { export function SetBody ( target , opts ) { let changed = Effect . Unchanged ; const parse = { Poss : target . Possessive ( ) , str : opts . str } ; const odds = opts . odds || 1 ; const body = target . body . torso ; if ( Math . random ( ) < odds ) { changed = TF . SetRaceOne ( body , opts . race ) ; if ( changed !== Effect . Unchanged ) { Text . Add ( "[Poss] body turns into [str]!" , parse ) ; Text . NL ( ) ; } } Text . Flush ( ) ; return changed ; } export function SetFace ( target , opts ) { let changed = Effect . Unchanged ; const parse = { Poss : target . Possessive ( ) , str : opts . str } ; const odds = opts . odds || 1 ; const head = target . body . head ; if ( Math . random ( ) < odds ) { changed = TF . SetRaceOne ( head , opts . race ) ; if ( changed !== Effect . Unchanged ) { Text . Add ( "[Poss] face turns into [str]!" , parse ) ; Text . NL ( ) ; } } Text . Flush ( ) ; return changed ; } export function SetTongue ( target , opts ) { let changed = Effect . Unchanged ; const parse = { Poss : target . Possessive ( ) , str : opts . str } ; const odds = opts . odds || 1 ; const head = target . body . head ; if ( Math . random ( ) < odds ) { changed = TF . SetRaceOne ( head . mouth . tongue , opts . race ) ; if ( changed !== Effect . Unchanged ) { Text . Add ( "[Poss] tongue turns into [str]!" , parse ) ; Text . NL ( ) ; } } Text . Flush ( ) ; return changed ; } export function SetArms ( target , opts ) { let changed = Effect . Unchanged ; const parse = { Poss : target . Possessive ( ) , str : opts . str } ; const odds = opts . odds || 1 ; const body = target . body . arms ; if ( Math . random ( ) < odds ) { changed = TF . SetRaceOne ( body , opts . race ) ; if ( changed !== Effect . Unchanged ) { Text . Add ( "[Poss] arms turns into [str]!" , parse ) ; Text . NL ( ) ; } } Text . Flush ( ) ; return changed ; } export function SetLegs ( target , opts ) { let changed = Effect . Unchanged ; const parse = { Poss : target . Possessive ( ) , str : opts . str } ; const odds = opts . odds || 1 ; const count = opts . count || 2 ; const legs = target . body . legs ; if ( legs . count >= 2 && Math . random ( ) < odds ) { changed = TF . SetRaceOne ( legs , opts . race ) ; if ( changed !== Effect . Unchanged ) { Text . Add ( "[Poss] legs turns into [str]!" , parse ) ; Text . NL ( ) ; } } Text . Flush ( ) ; return changed ; } export function SetCock ( target , opts ) { let changed = Effect . Unchanged ; const parse = { poss : target . possessive ( ) , Poss : target . Possessive ( ) , str : opts . str } ; const odds = opts . odds || 1 ; const cocks = target . AllCocks ( ) ; if ( Math . random ( ) < odds ) { changed = TF . SetRaceOne ( cocks , opts . race ) ; if ( changed !== Effect . Unchanged ) { if ( cocks . length > 1 ) { Text . Add ( "One of [poss] cocks turns into [str]!" , parse ) ; } else { Text . Add ( "[Poss] cock turns into [str]!" , parse ) ; } Text . NL ( ) ; } } Text . Flush ( ) ; return changed ; } export function SetEars ( target , opts ) { let changed = Effect . Unchanged ; const parse = { Poss : target . Possessive ( ) , str : opts . str } ; const odds = opts . odds || 1 ; const ears = target . Ears ( ) ; if ( Math . random ( ) < odds ) { changed = TF . SetRaceOne ( ears , opts . race ) ; if ( changed !== Effect . Unchanged ) { Text . Add ( "[Poss] ears turn into [str]!" , parse ) ; Text . NL ( ) ; } } Text . Flush ( ) ; return changed ; } export function SetKnot ( target , opts ) { const parse = { Poss : target . Possessive ( ) , poss : target . possessive ( ) } ; const odds = opts . odds || 1 ; let num = opts . num || 1 ; for ( const cock of target . AllCocks ( ) ) { if ( Math . random ( ) < odds ) { parse . cockDesc = cock . Short ( ) ; if ( opts . value ) { if ( cock . knot === 0 ) { cock . knot = 1 ; Text . Add ( "[Poss] [cockDesc] grows a knot!" , parse ) ; Text . NL ( ) ; num -- ; } } else { if ( cock . knot === 1 ) { cock . knot = 0 ; Text . Add ( "The knot on [poss] [cockDesc] disappears!" , parse ) ; Text . NL ( ) ; num -- ; } } if ( num <= 0 ) { break ; } } } Text . Flush ( ) ; } export function SetCover ( target , opts ) { const odds = opts . odds || 1 ; const value = opts . value || Genitalia . Cover . NoCover ; if ( ! target . FirstCock ( ) ) { return Effect . Unchanged ; } const gen = target . Genitalia ( ) ; if ( Math . random ( ) < odds ) { if ( gen . cover !== value ) { const parse = { Poss : target . Possessive ( ) , poss : target . possessive ( ) , cocks : target . MultiCockDesc ( ) , notS : target . NumCocks ( ) > 1 ? "" : "s" , is : target . NumCocks ( ) > 1 ? "are" : "is" , } ; if ( value === Genitalia . Cover . NoCover ) { if ( gen . cover === Genitalia . Cover . Sheath ) { Text . Add ( "The sheath protecting [poss] [cocks] disappears!" , parse ) ; } else if ( gen . cover === Genitalia . Cover . Slit ) { Text . Add ( "[Poss] genital slit slowly closes up, pushing [poss] [cocks] into the open!" , parse ) ; } } else if ( value === Genitalia . Cover . Sheath ) { if ( gen . cover === Genitalia . Cover . NoCover ) { Text . Add ( "[Poss] [cocks] grow[notS] a sheath!" , parse ) ; } else if ( gen . cover === Genitalia . Cover . Slit ) { Text . Add ( "[Poss] genital slit coarsens into a sheath, covering [poss] [cocks]!" , parse ) ; } } else if ( value === Genitalia . Cover . Slit ) { if ( gen . cover === Genitalia . Cover . NoCover ) { Text . Add ( "[Poss] [cocks] [is] enveloped in a protective genital slit!" , parse ) ; } else if ( gen . cover === Genitalia . Cover . Sheath ) { Text . Add ( "[Poss] sheath morphs into a protective genital slit, covering [poss] [cocks]!" , parse ) ; } } gen . SetCover ( value ) ; Text . NL ( ) ; Text . Flush ( ) ; return Effect . Changed ; } } return Effect . Unchanged ; } export function SetTail ( target , opts ) { let changed = Effect . Unchanged ; const parse = { name : target . NameDesc ( ) , Poss : target . Possessive ( ) , s : target === GAME ( ) . player ? "" : "s" , str : opts . str } ; const odds = opts . odds || 1 ; if ( Math . random ( ) < odds ) { changed = SetAppendage ( target . Back ( ) , AppendageType . tail , opts . race , opts . color ) ; switch ( changed ) { case Effect . Changed : Text . Add ( "[Poss] tail changes, turning into [str]!" , parse ) ; Text . NL ( ) ; break ; case Effect . Added : Text . Add ( "[name] suddenly grow[s] [str]!" , parse ) ; Text . NL ( ) ; break ; } } Text . Flush ( ) ; return changed ; } export function RemTail ( target , opts ) { let changed = Effect . Unchanged ; const tail = target . HasTail ( ) ; const parse = { name : target . NameDesc ( ) , Poss : target . Possessive ( ) , count : Text . NumToText ( opts . count ) , hisher : target . hisher ( ) } ; parse . s = tail && tail . count > 1 ? "s" : "" ; const odds = opts . odds || 1 ; if ( Math . random ( ) < odds ) { changed = TF . RemoveAppendage ( target . Back ( ) , AppendageType . tail , opts . count ) ; switch ( changed ) { case Effect . Changed : Text . Add ( "[name] lose [count] of [hisher] tails!" , parse ) ; Text . NL ( ) ; break ; case Effect . Removed : Text . Add ( "[name] lose all trace of [hisher] tail[s]!" , parse ) ; Text . NL ( ) ; break ; } } Text . Flush ( ) ; return changed ; } export function SetHorn ( target , opts ) { let changed = Effect . Unchanged ; const parse = { name : target . NameDesc ( ) , Poss : target . Possessive ( ) , s : target === GAME ( ) . player ? "" : "s" , str : opts . str } ; const odds = opts . odds || 1 ; if ( Math . random ( ) < odds ) { changed = TF . SetAppendage ( target . Appendages ( ) , AppendageType . horn , opts . race , opts . color , opts . count ) ; switch ( changed ) { case Effect . Changed : Text . Add ( "[Poss] horns change, turning into [str]!" , parse ) ; Text . NL ( ) ; break ; case Effect . Added : Text . Add ( "[name] suddenly grow[s] [str]!" , parse ) ; Text . NL ( ) ; break ; } } Text . Flush ( ) ; return changed ; } export function RemHorn ( target , opts ) { let changed = Effect . Unchanged ; const parse = { name : target . NameDesc ( ) , Poss : target . Possessive ( ) , count : Text . NumToText ( opts . count ) , hisher : target . hisher ( ) } ; const odds = opts . odds || 1 ; if ( Math . random ( ) < odds ) { changed = TF . RemoveAppendage ( target . Appendages ( ) , AppendageType . horn , opts . count ) ; switch ( changed ) { case Effect . Changed : Text . Add ( "[name] lose [count] of [hisher] horns!" , parse ) ; Text . NL ( ) ; break ; case Effect . Removed : Text . Add ( "[name] lose all trace of [hisher] horns!" , parse ) ; Text . NL ( ) ; break ; } } Text . Flush ( ) ; return changed ; } export function SetAntenna ( target , opts ) { let changed = Effect . Unchanged ; const parse = { name : target . NameDesc ( ) , Poss : target . Possessive ( ) , s : target === GAME ( ) . player ? "" : "s" , str : opts . str } ; const odds = opts . odds || 1 ; const count = opts . count || 2 ; if ( Math . random ( ) < odds ) { changed = TF . SetAppendage ( target . Appendages ( ) , AppendageType . antenna , opts . race , opts . color , count ) ; switch ( changed ) { case Effect . Changed : Text . Add ( "[Poss] antenna change, turning into [str]!" , parse ) ; Text . NL ( ) ; break ; case Effect . Added : Text . Add ( "[name] suddenly grow[s] [str]!" , parse ) ; Text . NL ( ) ; break ; } } Text . Flush ( ) ; return changed ; } export function RemAntenna ( target , opts ) { let changed = Effect . Unchanged ; const parse = { name : target . NameDesc ( ) , Poss : target . Possessive ( ) , count : Text . NumToText ( opts . count ) , hisher : target . hisher ( ) } ; const odds = opts . odds || 1 ; if ( Math . random ( ) < odds ) { changed = TF . RemoveAppendage ( target . Appendages ( ) , AppendageType . antenna , opts . count ) ; switch ( changed ) { case Effect . Changed : Text . Add ( "[name] lose [count] of [hisher] antenna!" , parse ) ; Text . NL ( ) ; break ; case Effect . Removed : Text . Add ( "[name] lose all trace of [hisher] antenna!" , parse ) ; Text . NL ( ) ; break ; } } Text . Flush ( ) ; return changed ; } export function SetWings ( target , opts ) { let changed = Effect . Unchanged ; const parse = { name : target . NameDesc ( ) , Poss : target . Possessive ( ) , s : target === GAME ( ) . player ? "" : "s" , str : opts . str } ; const odds = opts . odds || 1 ; const count = opts . count || 2 ; if ( Math . random ( ) < odds ) { changed = TF . SetAppendage ( target . Back ( ) , AppendageType . wing , opts . race , opts . color , count ) ; switch ( changed ) { case Effect . Changed : Text . Add ( "[Poss] wings change, turning into [str]!" , parse ) ; Text . NL ( ) ; break ; case Effect . Added : Text . Add ( "[name] suddenly grow[s] [str]!" , parse ) ; Text . NL ( ) ; break ; } } Text . Flush ( ) ; return changed ; } export function RemWings ( target , opts ) { let changed = Effect . Unchanged ; const parse = { name : target . NameDesc ( ) , Poss : target . Possessive ( ) , count : Text . NumToText ( opts . count ) , hisher : target . hisher ( ) } ; const odds = opts . odds || 1 ; if ( Math . random ( ) < odds ) { changed = TF . RemoveAppendage ( target . Back ( ) , AppendageType . wing , opts . count ) ; switch ( changed ) { case Effect . Changed : Text . Add ( "[name] lose [count] of [hisher] wings!" , parse ) ; Text . NL ( ) ; break ; case Effect . Removed : Text . Add ( "[name] lose all trace of [hisher] wings!" , parse ) ; Text . NL ( ) ; break ; } } Text . Flush ( ) ; return changed ; } export function SetAbdomen ( target , opts ) { let changed = Effect . Unchanged ; const parse = { name : target . NameDesc ( ) , Poss : target . Possessive ( ) , s : target === GAME ( ) . player ? "" : "s" , str : opts . str } ; const odds = opts . odds || 1 ; const count = opts . count || 2 ; if ( Math . random ( ) < odds ) { changed = TF . SetAppendage ( target . Back ( ) , AppendageType . abdomen , opts . race , opts . color , count ) ; switch ( changed ) { case Effect . Changed : Text . Add ( "[Poss] abdomen changes, turning into [str]!" , parse ) ; Text . NL ( ) ; break ; case Effect . Added : Text . Add ( "[name] suddenly grow[s] [str]!" , parse ) ; Text . NL ( ) ; break ; } } Text . Flush ( ) ; return changed ; } export function RemAbdomen ( target , opts ) { let changed = Effect . Unchanged ; const parse = { name : target . NameDesc ( ) , Poss : target . Possessive ( ) , count : Text . NumToText ( opts . count ) , hisher : target . hisher ( ) } ; const odds = opts . odds || 1 ; if ( Math . random ( ) < odds ) { changed = TF . RemoveAppendage ( target . Back ( ) , AppendageType . abdomen , opts . count ) ; switch ( changed ) { case Effect . Changed : Text . Add ( "[name] lose [count] of [hisher] abdomen!" , parse ) ; Text . NL ( ) ; break ; case Effect . Removed : Text . Add ( "[name] lose all trace of [hisher] abdomen!" , parse ) ; Text . NL ( ) ; break ; } } Text . Flush ( ) ; return changed ; } export function SetBalls ( target , opts ) { let changed = Effect . Unchanged ; const parse = { name : target . NameDesc ( ) , s : target === GAME ( ) . player ? "" : "s" , count : Text . NumToText ( opts . count ) , ballsDesc ( ) { return target . BallsDesc ( ) ; } } ; const odds = opts . odds || 1 ; const count = opts . count || 2 ; const ideal = opts . ideal || 2 ; if ( Math . random ( ) < odds ) { changed = TF . SetBalls ( target . body . balls , ideal , count ) ; switch ( changed ) { case Effect . Changed : Text . Add ( "[name] grow[s] an extra [count] testicles!" , parse ) ; Text . NL ( ) ; break ; case Effect . Added : Text . Add ( "[name] suddenly grow[s] a [ballsDesc]!" , parse ) ; Text . NL ( ) ; break ; } } Text . Flush ( ) ; return changed ; } export function RemBalls ( target , opts ) { let changed = Effect . Unchanged ; const parse = { name : target . NameDesc ( ) , count : Text . NumToText ( opts . count ) , hisher : target . hisher ( ) , ballsDesc : target . BallsDesc ( ) } ; const odds = opts . odds || 1 ; const count = opts . count || 2 ; const ideal = opts . ideal ; if ( Math . random ( ) < odds ) { changed = TF . RemBalls ( target . body . balls , ideal , count ) ; switch ( changed ) { case Effect . Changed : Text . Add ( "[name] lose [count] of [hisher] testicles!" , parse ) ; Text . NL ( ) ; break ; case Effect . Removed : Text . Add ( "[name] lose all trace of [hisher] [ballsDesc]!" , parse ) ; Text . NL ( ) ; break ; } } Text . Flush ( ) ; return changed ; } export function IncBallSize ( target , opts ) { const odds = opts . odds || 1 ; const parse = { Poss : target . Possessive ( ) } ; if ( Math . random ( ) < odds && target . Balls ( ) . size . IncreaseStat ( opts . ideal , opts . max ) ) { if ( ! target . HasBalls ( ) ) { return ; } Text . Add ( "[Poss] balls have grown in size!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function DecBallSize ( target , opts ) { const odds = opts . odds || 1 ; const parse = { Poss : target . Possessive ( ) } ; if ( Math . random ( ) < odds && target . Balls ( ) . size . DecreaseStat ( opts . ideal , opts . max ) ) { if ( ! target . HasBalls ( ) ) { return ; } Text . Add ( "[Poss] balls have shrunk in size!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function IdealBallSize ( target , opts ) { const odds = opts . odds || 1 ; const parse = { Poss : target . Possessive ( ) } ; if ( Math . random ( ) < odds ) { const ideal = _ . random ( opts . rangeMin || 0 , opts . rangeMax || 0 , true ) ; const diff = target . Balls ( ) . size . IdealStat ( ideal , opts . max ) ; if ( ! target . HasBalls ( ) ) { return ; } if ( diff > 0 ) { Text . Add ( "[Poss] balls have grown in size!" , parse ) ; Text . NL ( ) ; } else if ( diff < 0 ) { Text . Add ( "[Poss] balls have shrunk in size!" , parse ) ; Text . NL ( ) ; } } Text . Flush ( ) ; } export function IncBreastSize ( target , opts ) { const parse = { Poss : target . Possessive ( ) } ; const odds = opts . odds || 1 ; const multi = opts . multi ; if ( opts . female ) { if ( ! target . FirstVag ( ) ) { return ; } } _ . each ( target . AllBreastRows ( ) , ( breasts ) => { if ( Math . random ( ) < odds ) { const diff = breasts . size . IncreaseStat ( opts . ideal , opts . max ) ; if ( diff ) { Text . Add ( "[Poss] breasts grows bigger!" , parse ) ; Text . NL ( ) ; if ( ! multi ) { return false ; } } } } ) ; Text . Flush ( ) ; } export function DecBreastSize ( target , opts ) { const parse = { Poss : target . Possessive ( ) } ; const odds = opts . odds || 1 ; const multi = opts . multi ; _ . each ( target . AllBreastRows ( ) , ( breasts ) => { if ( Math . random ( ) < odds ) { const diff = breasts . size . DecreaseStat ( opts . ideal , opts . max ) ; if ( diff ) { Text . Add ( "[Poss] breasts become smaller!" , parse ) ; Text . NL ( ) ; if ( ! multi ) { return false ; } } } } ) ; Text . Flush ( ) ; } export function SetIdealBreastSize ( target , opts ) { const parse = { Poss : target . Possessive ( ) } ; const odds = opts . odds || 1 ; const multi = opts . multi ; if ( opts . female ) { if ( ! target . FirstVag ( ) ) { return ; } } _ . each ( target . AllBreastRows ( ) , ( breasts ) => { if ( Math . random ( ) < odds ) { const diff = breasts . size . IdealStat ( opts . ideal , opts . max ) ; if ( diff > 0 ) { Text . Add ( "[Poss] breasts grows bigger!" , parse ) ; Text . NL ( ) ; if ( ! multi ) { return false ; } } else if ( diff < 0 ) { Text . Add ( "[Poss] breasts become smaller!" , parse ) ; Text . NL ( ) ; if ( ! multi ) { return false ; } } } } ) ; Text . Flush ( ) ; } export function IncCockLen ( target , opts ) { const parse = { Poss : target . Possessive ( ) } ; const odds = opts . odds || 1 ; const multi = opts . multi ; _ . each ( target . AllCocks ( ) , ( cock ) => { if ( Math . random ( ) < odds ) { const diff = cock . length . IncreaseStat ( opts . ideal , opts . max ) ; if ( diff ) { Text . Add ( "[Poss] cock grows longer!" , parse ) ; Text . NL ( ) ; if ( ! multi ) { return false ; } } } } ) ; Text . Flush ( ) ; } export function DecCockLen ( target , opts ) { const parse = { Poss : target . Possessive ( ) } ; const odds = opts . odds || 1 ; const multi = opts . multi ; _ . each ( target . AllCocks ( ) , ( cock ) => { if ( Math . random ( ) < odds ) { const diff = cock . length . DecreaseStat ( opts . ideal , opts . max ) ; if ( diff ) { Text . Add ( "[Poss] cock becomes shorter!" , parse ) ; Text . NL ( ) ; if ( ! multi ) { return false ; } } } } ) ; Text . Flush ( ) ; } export function SetIdealCockLen ( target , opts ) { const parse = { Poss : target . Possessive ( ) } ; const odds = opts . odds || 1 ; const multi = opts . multi ; _ . each ( target . AllCocks ( ) , ( cock ) => { if ( Math . random ( ) < odds ) { const diff = cock . length . IdealStat ( opts . ideal , opts . max ) ; if ( diff > 0 ) { Text . Add ( "[Poss] cock grows longer!" , parse ) ; Text . NL ( ) ; if ( ! multi ) { return false ; } } else if ( diff < 0 ) { Text . Add ( "[Poss] cock becomes shorter!" , parse ) ; Text . NL ( ) ; if ( ! multi ) { return false ; } } } } ) ; Text . Flush ( ) ; } export function IncCockThk ( target , opts ) { const parse = { Poss : target . Possessive ( ) } ; const odds = opts . odds || 1 ; const multi = opts . multi ; _ . each ( target . AllCocks ( ) , ( cock ) => { if ( Math . random ( ) < odds ) { const diff = cock . thickness . IncreaseStat ( opts . ideal , opts . max ) ; if ( diff ) { Text . Add ( "[Poss] cock grows thicker!" , parse ) ; Text . NL ( ) ; if ( ! multi ) { return false ; } } } } ) ; Text . Flush ( ) ; } export function DecCockThk ( target , opts ) { const parse = { Poss : target . Possessive ( ) } ; const odds = opts . odds || 1 ; const multi = opts . multi ; _ . each ( target . AllCocks ( ) , ( cock ) => { if ( Math . random ( ) < odds ) { const diff = cock . thickness . DecreaseStat ( opts . ideal , opts . max ) ; if ( diff ) { Text . Add ( "[Poss] cock grows thinner!" , parse ) ; Text . NL ( ) ; if ( ! multi ) { return false ; } } } } ) ; Text . Flush ( ) ; } export function SetIdealCockThk ( target , opts ) { const parse = { Poss : target . Possessive ( ) } ; const odds = opts . odds || 1 ; const multi = opts . multi ; _ . each ( target . AllCocks ( ) , ( cock ) => { if ( Math . random ( ) < odds ) { const diff = cock . thickness . IdealStat ( opts . ideal , opts . max ) ; if ( diff > 0 ) { Text . Add ( "[Poss] cock grows thicker!" , parse ) ; Text . NL ( ) ; if ( ! multi ) { return false ; } } else if ( diff < 0 ) { Text . Add ( "[Poss] cock grows thinner!" , parse ) ; Text . NL ( ) ; if ( ! multi ) { return false ; } } } } ) ; Text . Flush ( ) ; } export function IncFem ( target , opts ) { const odds = opts . odds || 1 ; const female = target . FirstVag ( ) ; if ( opts . female && ! female ) { return ; } const parse = { name : target . NameDesc ( ) , notS : target . plural ( ) ? "" : "s" } ; if ( Math . random ( ) < odds && target . body . femininity . IncreaseStat ( opts . ideal , opts . max , true ) ) { Text . Add ( "[name] become[notS] more feminine!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function DecFem ( target , opts ) { const odds = opts . odds || 1 ; const female = target . FirstVag ( ) ; if ( opts . male && female ) { return ; } const parse = { name : target . NameDesc ( ) , notS : target . plural ( ) ? "" : "s" } ; if ( Math . random ( ) < odds && target . body . femininity . DecreaseStat ( opts . ideal , opts . max , true ) ) { Text . Add ( "[name] become[notS] more masculine!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function IdealFem ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , notS : target . plural ( ) ? "" : "s" } ; if ( Math . random ( ) < odds ) { const ideal = _ . random ( opts . rangeMin || 0 , opts . rangeMax || 0 , true ) ; const diff = target . body . femininity . IdealStat ( ideal , opts . max , true ) ; if ( diff > 0 ) { Text . Add ( "[name] become[notS] more feminine!" , parse ) ; Text . NL ( ) ; } else if ( diff < 0 ) { Text . Add ( "[name] become[notS] more masculine!" , parse ) ; Text . NL ( ) ; } } Text . Flush ( ) ; } export function IncTone ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , notS : target . plural ( ) ? "" : "s" } ; if ( Math . random ( ) < odds && target . body . muscleTone . IncreaseStat ( opts . ideal , opts . max , true ) ) { Text . Add ( "[name] become[notS] more muscular!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function DecTone ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , notS : target . plural ( ) ? "" : "s" } ; if ( Math . random ( ) < odds && target . body . muscleTone . DecreaseStat ( opts . ideal , opts . max , true ) ) { Text . Add ( "[name] become[notS] less muscular!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function IdealTone ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , notS : target . plural ( ) ? "" : "s" } ; if ( Math . random ( ) < odds ) { const ideal = _ . random ( opts . rangeMin || 0 , opts . rangeMax || 0 , true ) ; const diff = target . body . muscleTone . IdealStat ( ideal , opts . max , true ) ; if ( diff > 0 ) { Text . Add ( "[name] become[notS] more muscular!" , parse ) ; Text . NL ( ) ; } else if ( diff < 0 ) { Text . Add ( "[name] become[notS] less muscular!" , parse ) ; Text . NL ( ) ; } } Text . Flush ( ) ; } export function IncHips ( target , opts ) { const odds = opts . odds || 1 ; const parse = { Poss : target . Possessive ( ) } ; if ( Math . random ( ) < odds && target . body . torso . hipSize . IncreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[Poss] hips widen!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function DecHips ( target , opts ) { const odds = opts . odds || 1 ; const parse = { Poss : target . Possessive ( ) } ; if ( Math . random ( ) < odds && target . body . torso . hipSize . DecreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[Poss] hips narrow!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function IdealHips ( target , opts ) { const odds = opts . odds || 1 ; const parse = { Poss : target . Possessive ( ) } ; if ( Math . random ( ) < odds ) { const ideal = _ . random ( opts . rangeMin || 0 , opts . rangeMax || 0 , true ) ; const diff = target . body . torso . hipSize . IdealStat ( ideal , opts . max ) ; if ( diff > 0 ) { Text . Add ( "[Poss] hips widen!" , parse ) ; Text . NL ( ) ; } else if ( diff < 0 ) { Text . Add ( "[Poss] hips narrow!" , parse ) ; Text . NL ( ) ; } } Text . Flush ( ) ; } export function IncStr ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . strength . IncreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit stronger!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function IncSta ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . stamina . IncreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit tougher!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function IncDex ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . dexterity . IncreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit swifter!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function IncInt ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . intelligence . IncreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit smarter!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function IncSpi ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . spirit . IncreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit more stoic!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function IncLib ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . libido . IncreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit hornier!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function IncCha ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . charisma . IncreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit more charming!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function DecStr ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . strength . DecreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit weaker!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function DecSta ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . stamina . DecreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit less tough!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function DecDex ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . dexterity . DecreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit clumsier!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function DecInt ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . intelligence . DecreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit dumber!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function DecSpi ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . spirit . DecreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit less stoic!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function DecLib ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . libido . DecreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit more composed!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } export function DecCha ( target , opts ) { const odds = opts . odds || 1 ; const parse = { name : target . NameDesc ( ) , is : target . is ( ) } ; if ( Math . random ( ) < odds && target . charisma . DecreaseStat ( opts . ideal , opts . max ) ) { Text . Add ( "[name] [is] suddenly a bit less charming!" , parse ) ; Text . NL ( ) ; } Text . Flush ( ) ; } } } export class TFItem extends Item { public useStr : any ; public effects : any [ ] ; constructor ( id , name ) { super ( id , name , ItemType . Potion ) ; this . Use = TF . UseItem ; this . useStr = TF . UseItemDesc ; this . effects = [ ] ; this . isTF = true ; } public PushEffect ( func , opts ? ) { this . effects . push ( { func , opts } ) ; } }