import * as _ from "lodash" ; import { GetDEBUG } from "../app" ; import { Abilities } from "./abilities" ; import { Ability , AbilityCollection } from "./ability" ; import { GetAggroEntry } from "./ability/default" ; import { AppendageType } from "./body/appendage" ; import { LowerBodyType } from "./body/body" ; import { Body } from "./body/body" ; import { BodyPartType } from "./body/bodypart" ; import { NippleType } from "./body/breasts" ; import { Butt } from "./body/butt" ; import { Cock } from "./body/cock" ; import { Color , ColorDesc } from "./body/color" ; import { Gender } from "./body/gender" ; import { IMouth } from "./body/head" ; import { Orifice } from "./body/orifice" ; import { Race , RaceDesc , RaceScore } from "./body/race" ; import { Vagina } from "./body/vagina" ; import { CurEncounter } from "./combat-data" ; import { DamageType , Element } from "./damagetype" ; import { EntityDict } from "./entity-dict" ; import { EntityMenu } from "./entity-menu" ; import { GAME } from "./GAME" ; import { Gui } from "./gui" ; import { IStorage } from "./istorage" ; import { Item , ItemIds } from "./item" ; import { ItemToy } from "./items/toy-item" ; import { Jobs } from "./job" ; import { LactationHandler } from "./lactation" ; import { ILocation } from "./location" ; import { Perk , PerkIds } from "./perks" ; import { PregnancyHandler , Womb } from "./pregnancy" ; import { Stat } from "./stat" ; import { StatusEffect } from "./statuseffect" ; import { StatusList } from "./statuslist" ; import { IParse , Text } from "./text" ; import { ITime , Time } from "./time" ; import { Unit } from "./utility" ; export enum DrunkLevel { Sober = 0.25 , Tipsy = 0.50 , Sloshed = 0.75 , Drunk = 1.00 } export enum TargetStrategy { None = 0 , NearDeath = 1 , LowHp = 2 , LowAbsHp = 4 , HighHp = 8 , HighAbsHp = 16 , Leader = 32 , SPHunt = 64 , LPHunt = 128 } export interface ICastingEntry { ability : Ability ; target : Entity | any ; retarget : CallableFunction ; } export interface IAggroEntry { entity : Entity ; aggro : number ; } export interface ICombatOrder { entity : Entity ; isEnemy ? : boolean ; aggro ? : IAggroEntry [ ] ; aggroAllies ? : IAggroEntry [ ] ; initiative : number ; cooldown ? : any [ ] ; casting ? : ICastingEntry ; spellstack ? : any [ ] ; } export interface ICombatEncounter { combatOrder : ICombatOrder [ ] ; enemy : any ; GetLivePartyArray : ( ) => any ; GetLiveEnemyArray : ( ) => any ; CombatTick : ( ) => void ; GenerateUniqueName : ( entity : Entity ) => void ; canRun : boolean ; onRun : ( ) => void ; RunLevel : ( ) => number ; } class EntityParser { private ent : Entity ; constructor ( entity ) { this . ent = entity ; } public get name ( ) { return this . ent . name ; } public get mname ( ) { return this . ent . nameDesc ( ) ; } public get mName ( ) { return this . ent . NameDesc ( ) ; } public get heshe ( ) { return this . ent . heshe ( ) ; } public get HeShe ( ) { return this . ent . HeShe ( ) ; } public get hisher ( ) { return this . ent . hisher ( ) ; } public get HisHer ( ) { return this . ent . HisHer ( ) ; } public get himher ( ) { return this . ent . himher ( ) ; } public get HimHer ( ) { return this . ent . HimHer ( ) ; } public get hishers ( ) { return this . ent . hishers ( ) ; } public get poss ( ) { return this . ent . possessive ( ) ; } public get Poss ( ) { return this . ent . Possessive ( ) ; } public get poss2 ( ) { return this . ent . possessivePlural ( ) ; } public get Poss2 ( ) { return this . ent . PossessivePlural ( ) ; } public get has ( ) { return this . ent . has ( ) ; } public get is ( ) { return this . ent . is ( ) ; } public mfFem ( male , female ) { return this . ent . mfFem ( male , female ) ; } public mfTrue ( male , female ) { return this . ent . mfTrue ( male , female ) ; } public haslegs ( iflegs , nolegs = `` ) { return this . ent . HasLegs ( ) ? iflegs : nolegs ; } public taur ( iftaur , nottaur = `` ) { return this . ent . IsTaur ( ) ? iftaur : nottaur ; } public naga ( ifnaga , notnaga = `` ) { return this . ent . IsNaga ( ) ? ifnaga : notnaga ; } public goo ( ifgoo , notgoo = `` ) { return this . ent . IsGoo ( ) ? ifgoo : notgoo ; } public flexible ( ifflexible , notflexible = `` ) { return this . ent . IsFlexible ( ) ? ifflexible : notflexible ; } public hashair ( ifhashair , nothashair = `` ) { return this . ent . HasHair ( ) ? ifhashair : nothashair ; } public longhair ( iflonghair , notlonghair = `` ) { return this . ent . HasLongHair ( ) ? iflonghair : notlonghair ; } public longtongue ( iflongtongue , notlongtongue = `` ) { return this . ent . LongTongue ( ) ? iflongtongue : notlongtongue ; } public hascock ( cock , nocock = `` ) { return this . ent . FirstCock ( ) !== undefined ? cock : nocock ; } public get cocks ( ) { return this . ent . MultiCockDesc ( ) ; } public get cocksandballs ( ) { return `${ this . cocks }${ this . ent . HasBalls ( ) ? ` and ${ this . balls }` : "" }` ; } public get cock ( ) { const cock = this . ent . GetPreferredCock ( ) || this . ent . FirstCock ( ) ; return cock . Short ( ) ; } public get cockTip ( ) { const cock = this . ent . GetPreferredCock ( ) || this . ent . FirstCock ( ) ; return cock . TipShort ( ) ; } public get knot ( ) { const cock = this . ent . GetPreferredCock ( ) || this . ent . FirstCock ( ) ; return cock . KnotShort ( ) ; } public get balls ( ) { return this . ent . BallsDesc ( ) ; } public get butt ( ) { return this . ent . Butt ( ) . Short ( ) ; } public get anus ( ) { return this . ent . Butt ( ) . AnalShort ( ) ; } public get vag ( ) { return this . ent . FirstVag ( ) . Short ( ) ; } public hasvag ( vag , novag = `` ) { return this . ent . FirstVag ( ) !== undefined ? vag : novag ; } public get vagoranus ( ) { return this . ent . FirstVag ( ) ? this . vag : this . anus ; } public get clit ( ) { return this . ent . FirstVag ( ) . ClitShort ( ) ; } public get gen ( ) { let ret = "" ; const c = this . ent . FirstCock ( ) ; const v = this . ent . FirstVag ( ) ; if ( c === undefined && v === undefined ) { return "featureless crotch" ; } if ( c !== undefined ) { ret += this . cocks ; } if ( c !== undefined && v !== undefined ) { ret += " and " ; } if ( v !== undefined ) { ret += this . vag ; } return ret ; } public get breasts ( ) { return this . ent . FirstBreastRow ( ) . Short ( ) ; } public get nip ( ) { return this . ent . FirstBreastRow ( ) . NipShort ( ) ; } public get nips ( ) { return this . ent . FirstBreastRow ( ) . NipsShort ( ) ; } public get tongue ( ) { return this . ent . TongueDesc ( ) ; } public get tongueTip ( ) { return this . ent . TongueTipDesc ( ) ; } public get skin ( ) { return this . ent . SkinDesc ( ) ; } public hasfur ( fur , nofur = `` ) { return this . ent . HasFur ( ) ? fur : nofur ; } public hasscales ( scales , noscales = `` ) { return this . ent . HasScales ( ) ? scales : noscales ; } public hasskin ( skin , noskin = `` ) { return this . ent . HasSkin ( ) ? skin : noskin ; } public get hair ( ) { return this . ent . Hair ( ) . Short ( ) ; } public get lips ( ) { return this . ent . LipsDesc ( ) ; } public get face ( ) { return this . ent . FaceDesc ( ) ; } public get faceLong ( ) { return this . ent . body . FaceDescLong ( ) ; } public get ear ( ) { return this . ent . EarDesc ( ) ; } public get ears ( ) { return this . ent . EarDesc ( true ) ; } public get eye ( ) { return this . ent . EyeDesc ( ) ; } public get eyes ( ) { return this . ent . EyesDesc ( ) ; } public get hand ( ) { return this . ent . HandDesc ( ) ; } public get palm ( ) { return this . ent . PalmDesc ( ) ; } public get hip ( ) { return this . ent . HipDesc ( ) ; } public get hips ( ) { return this . ent . HipsDesc ( ) ; } public get thigh ( ) { return this . ent . ThighDesc ( ) ; } public get thighs ( ) { return this . ent . ThighsDesc ( ) ; } public get leg ( ) { return this . ent . LegDesc ( ) ; } public get legs ( ) { return this . ent . LegsDesc ( ) ; } public get knee ( ) { return this . ent . KneeDesc ( ) ; } public get knees ( ) { return this . ent . KneesDesc ( ) ; } public get foot ( ) { return this . ent . FootDesc ( ) ; } public get feet ( ) { return this . ent . FeetDesc ( ) ; } public get belly ( ) { return this . ent . StomachDesc ( ) ; } public get tail ( ) { const tail = this . ent . HasTail ( ) ; return tail ? tail . Short ( ) : "" ; } public hastail ( tail , notail = `` ) { return this . ent . HasTail ( ) ? tail : notail ; } public get wing ( ) { const wing = this . ent . HasWings ( ) ; return wing ? wing . Short ( ) : "" ; } public haswings ( wing , nowing = `` ) { return this . ent . HasWings ( ) ? wing : nowing ; } public get horns ( ) { const horns = this . ent . HasHorns ( ) ; return horns ? horns . Short ( ) : "" ; } public hashorns ( horns , nohorns = `` ) { return this . ent . HasHorns ( ) ? horns : nohorns ; } public get weapon ( ) { return this . ent . WeaponDesc ( ) ; } public get armor ( ) { return this . ent . ArmorDesc ( ) ; } public get botarmor ( ) { return this . ent . LowerArmorDesc ( ) ; } public humanity ( conds , ... str ) { if ( conds . length !== str . length - 1 ) { return Text . ApplyStyle ( `Parse error [humanity(conds, ...str)], number of strs must equal conds - 1!` , "error" ) ; } const humanity = this . ent . Humanity ( ) ; for ( const [ i , cond ] of conds . entries ( ) ) { if ( humanity >= cond ) { return str [ i ] ; } } return _ . last ( str ) ; } } export class Entity { public static IdToEntity = EntityDict . IdToEntity ; public name : string ; public monsterName : string ; public MonsterName : string ; public groupName : string ; public GroupName : string ; public uniqueName : string ; public ID : string ; public title : string [ ] ; public avatar : any ; public combatExp : number ; public coinDrop : number ; public abilities : any ; public recipes : Item [ ] ; public alchemyLevel : number ; public jobs : any ; public currentJob : any ; public experience : number ; public level : number ; public pendingStatPoints : number ; public expToLevel : number ; public sexperience : number ; public sexlevel : number ; public sexpToLevel : number ; public ExpToLevel = 15 ; public SexpToLevel = 30 ; public curHp : number ; public maxHp : Stat ; public curSp : number ; public maxSp : Stat ; public curLust : number ; public maxLust : Stat ; public strength : Stat ; public stamina : Stat ; public dexterity : Stat ; public intelligence : Stat ; public spirit : Stat ; public libido : Stat ; public charisma : Stat ; public weaponSlot : Item ; public topArmorSlot : Item ; public botArmorSlot : Item ; public acc1Slot : Item ; public acc2Slot : Item ; public strapOn : ItemToy ; public prefCock : Cock ; public elementAtk : DamageType ; public elementDef : DamageType ; public atkMod : number ; public defMod : number ; public combatStatus : StatusList ; public statusDef : any [ ] ; public statusDefGear : any [ ] ; public statusWear : any [ ] ; public body : Body ; public drunkLevel : number ; public pregHandler : PregnancyHandler ; public lactHandler : LactationHandler ; public flags : any ; public sex : any ; public perks : Perk [ ] ; public aggro : any [ ] ; public subDom : Stat ; public slut : Stat ; public relation : Stat ; public location : ILocation ; public InteractDefault = EntityMenu . InteractDefault ; public LevelUpPrompt = EntityMenu . LevelUpPrompt ; public EquipPrompt = EntityMenu . EquipPrompt ; public JobPrompt = EntityMenu . JobPrompt ; public UniqueId = EntityDict . UniqueId ; public get Parser ( ) { return this . parser ; } private parser : EntityParser ; constructor ( ) { this . parser = new EntityParser ( this ) ; this . name = "ENTITY" ; this . monsterName = undefined ; this . MonsterName = undefined ; this . groupName = undefined ; this . GroupName = undefined ; this . ID = undefined ; this . title = new Array ( ) ; this . avatar = { } ; this . combatExp = 0 ; this . coinDrop = 0 ; this . abilities = { } ; this . abilities . Skills = new AbilityCollection ( "Skills" ) ; this . abilities . Spells = new AbilityCollection ( "Spells" ) ; this . abilities . Support = new AbilityCollection ( "Support" ) ; this . abilities . Seduce = new AbilityCollection ( "Seduce" ) ; this . abilities . Special = new AbilityCollection ( "SPECIAL" ) ; this . recipes = [ ] ; this . alchemyLevel = 0 ; this . jobs = { } ; this . experience = 0 ; this . level = 1 ; this . pendingStatPoints = 0 ; this . expToLevel = this . ExpToLevel ; this . sexperience = 0 ; this . sexlevel = 1 ; this . sexpToLevel = this . SexpToLevel ; const that = this ; this . curHp = 0 ; this . maxHp = new Stat ( 10 , 10 , 5 ) ; this . maxHp . debug = ( ) => that . name + ".maxHp" ; this . curSp = 0 ; this . maxSp = new Stat ( 10 , 5 , 5 ) ; this . maxSp . debug = ( ) => that . name + ".maxSp" ; this . curLust = 0 ; this . maxLust = new Stat ( 10 , 5 , 5 ) ; this . maxLust . debug = ( ) => that . name + ".maxLust" ; this . strength = new Stat ( 0 , 1 , 0.1 ) ; this . strength . debug = ( ) => that . name + ".strength" ; this . stamina = new Stat ( 0 , 1 , 0.1 ) ; this . stamina . debug = ( ) => that . name + ".stamina" ; this . dexterity = new Stat ( 0 , 1 , 0.1 ) ; this . dexterity . debug = ( ) => that . name + ".dexterity" ; this . intelligence = new Stat ( 0 , 1 , 0.1 ) ; this . intelligence . debug = ( ) => that . name + ".intelligence" ; this . spirit = new Stat ( 0 , 1 , 0.1 ) ; this . spirit . debug = ( ) => that . name + ".spirit" ; this . libido = new Stat ( 0 , 1 , 0.1 ) ; this . libido . debug = ( ) => that . name + ".libido" ; this . charisma = new Stat ( 0 , 1 , 0.1 ) ; this . charisma . debug = ( ) => that . name + ".charisma" ; this . elementAtk = new DamageType ( ) ; this . elementDef = new DamageType ( ) ; this . combatStatus = new StatusList ( ) ; this . statusDef = [ ] ; this . statusDefGear = [ ] ; this . statusWear = [ ] ; this . body = new Body ( this ) ; this . drunkLevel = 0.0 ; this . pregHandler = new PregnancyHandler ( this ) ; this . lactHandler = new LactationHandler ( this ) ; this . Equip ( ) ; this . SetLevelBonus ( ) ; this . RestFull ( ) ; this . flags = { } ; this . sex = { rBlow : 0 , gBlow : 0 , rCunn : 0 , gCunn : 0 , rAnal : 0 , gAnal : 0 , rVag : 0 , gVag : 0 , sired : 0 , birth : 0 , } ; this . perks = [ ] ; this . aggro = [ ] ; this . subDom = new Stat ( 0 ) ; this . subDom . debug = ( ) => that . name + ".subDom" ; this . slut = new Stat ( 0 ) ; this . slut . debug = ( ) => that . name + ".slut" ; this . relation = new Stat ( 0 ) ; this . relation . debug = ( ) => that . name + ".relation" ; } public Interact ( switchSpot ) { } public SetLevelBonus ( ) { this . maxHp . level = this . level * this . maxHp . growth ; this . maxSp . level = this . level * this . maxSp . growth ; this . maxLust . level = this . level * this . maxLust . growth ; this . strength . level = this . level * this . strength . growth ; this . stamina . level = this . level * this . stamina . growth ; this . dexterity . level = this . level * this . dexterity . growth ; this . intelligence . level = this . level * this . intelligence . growth ; this . spirit . level = this . level * this . spirit . growth ; this . libido . level = this . level * this . libido . growth ; this . charisma . level = this . level * this . charisma . growth ; } public HasPerk ( perk ) { for ( const p of this . perks ) { if ( p === perk ) { return true ; } } return false ; } public AddPerk ( perk ) { for ( const p of this . perks ) { if ( p === perk ) { return ; } } this . perks . push ( perk ) ; } public KnowsRecipe ( item ) { const idx = this . recipes . indexOf ( item ) ; return ( idx !== - 1 ) ; } public AddAlchemy ( item ) { const idx = this . recipes . indexOf ( item ) ; if ( idx === - 1 ) { this . recipes . push ( item ) ; } } public Equip ( ) { this . maxHp . bonus = 0 ; this . maxSp . bonus = 0 ; this . maxLust . bonus = 0 ; this . strength . bonus = 0 ; this . stamina . bonus = 0 ; this . dexterity . bonus = 0 ; this . intelligence . bonus = 0 ; this . spirit . bonus = 0 ; this . libido . bonus = 0 ; this . charisma . bonus = 0 ; this . atkMod = 1 ; this . defMod = 1 ; this . elementAtk = new DamageType ( ) ; if ( ! this . weaponSlot ) { this . elementAtk . dmg [ Element . pBlunt ] = 1 ; } this . elementDef = new DamageType ( ) ; this . statusDefGear = [ ] ; if ( this . weaponSlot ) { this . weaponSlot . Equip ( this ) ; } if ( this . topArmorSlot ) { this . topArmorSlot . Equip ( this ) ; } if ( this . botArmorSlot ) { this . botArmorSlot . Equip ( this ) ; } if ( this . acc1Slot ) { this . acc1Slot . Equip ( this ) ; } if ( this . acc2Slot ) { this . acc2Slot . Equip ( this ) ; } this . BalanceStats ( ) ; } public Strip ( ) { this . weaponSlot = undefined ; this . topArmorSlot = undefined ; this . botArmorSlot = undefined ; this . acc1Slot = undefined ; this . acc2Slot = undefined ; this . strapOn = undefined ; } public ItemUsable ( item ) { if ( item . isTF ) { return false ; } return true ; } public ItemUse ( item , backPrompt ) { return { grab : false , consume : true } ; } public Strapon ( ) { return this . strapOn ; } public AddExp ( exp , reserve ? ) { const buff = this . combatStatus . stats [ StatusEffect . Full ] ; if ( buff && buff . exp ) { exp = Math . ceil ( buff . exp * exp ) ; } const r = reserve ? "RESERVE: " : "" ; if ( GetDEBUG ( ) ) { Text . NL ( ) ; Text . Add ( `${ r }${ this . name } gains ${ exp } xp.` , undefined , "bold" ) ; Text . NL ( ) ; Text . Flush ( ) ; } this . experience += exp ; if ( this . currentJob ) { this . currentJob . AddExp ( this , exp , reserve ) ; } while ( this . experience >= this . expToLevel ) { this . experience -= this . expToLevel ; this . expToLevel = Math . floor ( this . expToLevel * 1.2 ) ; this . level ++ ; this . pendingStatPoints += Stat . growthPointsPerLevel ; this . SetLevelBonus ( ) ; if ( GetDEBUG ( ) ) { Text . NL ( ) ; Text . Add ( `${ r }${ this . name } gains a level! Now at ${ this . level }.` , undefined , "bold" ) ; Text . NL ( ) ; Text . Flush ( ) ; } } } public AddSexExp ( sexp ) { if ( GetDEBUG ( ) ) { Text . NL ( ) ; Text . Add ( `${ this . name } gains ${ sexp } sex exp.` , undefined , "bold" ) ; Text . NL ( ) ; Text . Flush ( ) ; } this . sexperience += sexp ; while ( this . sexperience >= this . sexpToLevel ) { this . sexperience -= this . sexpToLevel ; this . sexpToLevel = Math . floor ( this . sexpToLevel * 2 ) ; this . sexlevel ++ ; if ( GetDEBUG ( ) ) { Text . NL ( ) ; Text . Add ( `${ this . name } gains a sex level! Now at ${ this . sexlevel }.` , undefined , "bold" ) ; Text . NL ( ) ; Text . Flush ( ) ; } } } public SetExpToLevel ( ) { this . sexpToLevel = this . SexpToLevel ; this . expToLevel = this . ExpToLevel ; for ( let i = 1 ; i < this . level ; i ++ ) { this . expToLevel = Math . floor ( this . expToLevel * 1.2 ) ; } for ( let i = 1 ; i < this . sexlevel ; i ++ ) { this . sexpToLevel = Math . floor ( this . sexpToLevel * 2 ) ; } } public IsAtLocation ( location ) { return ( this . location === location ) ; } public DropTable ( ) { return [ ] ; } public Update ( step ? ) { if ( step ) { const time = new Time ( ) ; time . Inc ( step ) ; const hours = time . ToHours ( ) ; this . AddLustOverTime ( hours ) ; this . AccumulateCumOverTime ( hours ) ; this . LactationOverTime ( hours ) ; this . PregnancyOverTime ( hours ) ; this . HandleDrunknessOverTime ( hours ) ; this . HandleStretchOverTime ( hours ) ; this . combatStatus . Update ( this , hours ) ; } } public HandleStretchOverTime ( hours ) { this . body . HandleStretchOverTime ( hours ) ; } public AccumulateCumOverTime ( hours ) { const balls = this . Balls ( ) ; const inc = balls . cumProduction . Get ( ) * hours ; balls . cum . IncreaseStat ( balls . CumCap ( ) , inc ) ; } public MilkDrained ( ) { this . lactHandler . MilkDrained ( ) ; } public MilkFull ( ) { this . lactHandler . MilkFull ( ) ; } public MilkDrain ( drain ) { return this . LactHandler ( ) . MilkDrain ( drain ) ; } public MilkDrainFraction ( fraction ) { return this . LactHandler ( ) . MilkDrainFraction ( fraction ) ; } public LactHandler ( ) { return this . lactHandler ; } public LactationOverTime ( hours ) { this . lactHandler . Update ( hours ) ; } public PregHandler ( ) { return this . pregHandler ; } public PregnancyOverTime ( hours ) { this . pregHandler . Update ( hours ) ; } public PregnancyProgess ( womb , slot , oldProgress , progress ) { } public PregnancyTrigger ( womb , slot ) { const that = this ; Gui . Callstack . unshift ( ( ) => { womb . pregnant = false ; if ( GetDEBUG ( ) ) { const parse = { name : that . name , } ; Text . Clear ( ) ; Text . Add ( "PLACEHOLDER: [name] gave birth." , parse ) ; Text . NL ( ) ; Text . Flush ( ) ; Gui . NextPrompt ( ) ; } } ) ; } public CanGiveBirth ( ) { return true ; } public DrunkRecoveryRate ( ) { let sta = this . Sta ( ) ; if ( sta < Math . E ) { sta = Math . E ; } return Math . log ( sta ) / 25 ; } public HandleDrunknessOverTime ( hours , suppressText ? ) { const oldLevel = this . drunkLevel ; this . drunkLevel -= this . DrunkRecoveryRate ( ) * hours ; if ( this . drunkLevel < 0 ) { this . drunkLevel = 0 ; } } public Drunk ( ) { return this . drunkLevel ; } public DrunkStr ( ) { const parse = { name : this . NameDesc ( ) , isAre : this . is ( ) , } ; if ( this . drunkLevel > DrunkLevel . Drunk ) { return Text . Parse ( "[name] [isAre] passed out, dead drunk." , parse ) ; } if ( this . drunkLevel > DrunkLevel . Sloshed ) { return Text . Parse ( "[name] [isAre] reeling, quite drunk." , parse ) ; } if ( this . drunkLevel > DrunkLevel . Tipsy ) { return Text . Parse ( "[name] [isAre] tipsy, wobbling slighty." , parse ) ; } if ( this . drunkLevel > DrunkLevel . Sober ) { return Text . Parse ( "[name] [isAre] feeling a bit tipsy." , parse ) ; } return false ; } public Drink ( drink , suppressText ) { let sta = this . Sta ( ) ; if ( sta < Math . E ) { sta = Math . E ; } const oldLevel = this . drunkLevel ; this . drunkLevel += drink / Math . log ( sta ) ; } public InnPrompt ( ) { Text . Clear ( ) ; Text . Add ( "[PLACEHOLDER]" ) ; Text . NL ( ) ; Text . Flush ( ) ; Gui . NextPrompt ( ) ; } public SetEyeColor ( color ) { this . body . head . eyes . color = color ; } public SetHairColor ( color ) { this . body . head . hair . color = color ; } public SetSkinColor ( color ) { this . body . torso . color = color ; } public DebugMode ( debug ) { const value = debug ? 50 : 0 ; this . maxHp . cheat = value * 10 ; this . maxSp . cheat = value * 10 ; this . maxLust . cheat = value * 10 ; this . strength . cheat = value ; this . stamina . cheat = value ; this . dexterity . cheat = value ; this . intelligence . cheat = value ; this . spirit . cheat = value ; this . libido . cheat = value ; this . charisma . cheat = value ; this . Equip ( ) ; if ( debug ) { this . RestFull ( ) ; } } public Act ( encounter , activeChar ) { Text . Add ( this . name + " acts! Rawr!" ) ; Text . NL ( ) ; Text . Flush ( ) ; const t = this . GetSingleTarget ( encounter , activeChar ) ; Abilities . Attack . Use ( encounter , this , t ) ; } public FinishCastInternal ( ability , encounter , caster , targets ) { Text . Flush ( ) ; if ( encounter ) { encounter . CombatTick ( ) ; } else { Gui . PrintDefaultOptions ( ) ; } } public CanBeInterrupted ( ability , encounter , caster , result ) { return true ; } public GetCombatEntry ( encounter ) { const ent = this ; let found ; _ . each ( encounter . combatOrder , ( it ) => { if ( it . entity === ent ) { found = it ; return false ; } } ) ; return found ; } public GetPartyTarget ( encounter , activeChar , ally ? ) { let isEnemy = activeChar . isEnemy ; const confuse = activeChar . entity . combatStatus . stats [ StatusEffect . Confuse ] ; if ( confuse ) { isEnemy = ! isEnemy ; } if ( ally ) { isEnemy = ! isEnemy ; } if ( isEnemy ) { return GAME ( ) . party ; } else { return encounter . enemy ; } } public GetSingleTarget ( encounter , activeChar , strategy ? , ally ? ) { let isEnemy = activeChar . isEnemy ; const confuse = activeChar . entity . combatStatus . stats [ StatusEffect . Confuse ] ; if ( confuse ) { isEnemy = ! isEnemy ; } if ( ally ) { isEnemy = ! isEnemy ; } let targets ; if ( isEnemy ) { targets = encounter . GetLivePartyArray ( ) ; } else { targets = encounter . GetLiveEnemyArray ( ) ; } strategy = strategy || TargetStrategy . None ; let aggro ; if ( ally ) { activeChar . aggroAllies = _ . reject ( activeChar . aggroAllies , ( it ) => { return it . entity . Incapacitated ( ) ; } ) ; _ . each ( targets , ( t ) => { if ( ! GetAggroEntry ( activeChar , t ) ) { activeChar . aggroAllies . push ( { entity : t , aggro : 1 } ) ; } } ) ; aggro = _ . clone ( activeChar . aggroAllies ) ; } else { activeChar . aggro = _ . reject ( activeChar . aggro , ( it ) => { return it . entity . Incapacitated ( ) ; } ) ; _ . each ( targets , ( t ) => { if ( ! GetAggroEntry ( activeChar , t ) ) { activeChar . aggro . push ( { entity : t , aggro : 1 } ) ; } } ) ; aggro = _ . clone ( activeChar . aggro ) ; } if ( strategy & TargetStrategy . NearDeath ) { _ . each ( aggro , ( a ) => { let hp = 1 - a . entity . HPLevel ( ) ; hp *= hp ; a . aggro *= hp ; } ) ; } if ( strategy & TargetStrategy . LowHp ) { _ . each ( aggro , ( a ) => { const hp = 1 - a . entity . HPLevel ( ) ; a . aggro *= hp ; } ) ; } if ( strategy & TargetStrategy . HighHp ) { _ . each ( aggro , ( a ) => { const hp = a . entity . HPLevel ( ) ; a . aggro *= hp ; } ) ; } const min = _ . minBy ( aggro , ( a ) => { return a . entity . curHp ; } ) . entity . curHp ; const max = _ . maxBy ( aggro , ( a ) => { return a . entity . curHp ; } ) . entity . curHp ; const span = max - min ; if ( strategy & TargetStrategy . LowAbsHp ) { _ . each ( aggro , ( a ) => { let hp = ( a . entity . curHp - min ) / span ; hp = 1 - hp ; a . aggro *= hp ; } ) ; } if ( strategy & TargetStrategy . HighAbsHp ) { _ . each ( aggro , ( a ) => { const hp = ( a . entity . curHp - min ) / span ; a . aggro *= hp ; } ) ; } if ( strategy & TargetStrategy . Leader ) { if ( aggro . length > 0 ) { aggro [ 0 ] . aggro *= 5 ; } } if ( strategy & TargetStrategy . SPHunt ) { for ( const agg of aggro ) { const sp = Math . log ( agg . entity . SP ( ) ) ; agg . aggro *= sp ; } } if ( strategy & TargetStrategy . LPHunt ) { for ( const agg of aggro ) { const lp = Math . log ( agg . entity . Lust ( ) ) ; agg . aggro *= lp ; } } const sum = _ . sumBy ( aggro , ( a ) => { return a . aggro ; } ) ; let step = Math . random ( ) * sum ; for ( const agg of aggro ) { step -= agg . aggro ; if ( step <= 0.0 ) { return agg . entity ; } } return _ . sample ( aggro ) . entity ; } public HP ( ) { const buff = this . combatStatus . stats [ StatusEffect . Buff ] ; const mod = ( buff && buff . HP ) ? buff . HP : 1 ; return Math . ceil ( ( this . maxHp . Get ( ) + Math . pow ( ( this . strength . Get ( ) + this . stamina . Get ( ) ) / 2 , 1.3 ) ) * mod ) ; } public SP ( ) { const buff = this . combatStatus . stats [ StatusEffect . Buff ] ; const mod = ( buff && buff . SP ) ? buff . SP : 1 ; return Math . ceil ( ( this . maxSp . Get ( ) + Math . pow ( ( this . spirit . Get ( ) + this . intelligence . Get ( ) + this . stamina . Get ( ) ) / 3 , 1.3 ) ) * mod ) ; } public Lust ( ) { const buff = this . combatStatus . stats [ StatusEffect . Buff ] ; const mod = ( buff && buff . LP ) ? buff . LP : 1 ; return Math . ceil ( ( this . maxLust . Get ( ) + Math . pow ( this . libido . Get ( ) , 1.3 ) ) * mod ) ; } public MinLust ( ) { return 0 ; } public Str ( ) { const buff = this . combatStatus . stats [ StatusEffect . Buff ] ; if ( buff && buff . Str ) { return this . strength . Get ( ) * buff . Str ; } else { return this . strength . Get ( ) ; } } public Sta ( ) { const buff = this . combatStatus . stats [ StatusEffect . Buff ] ; if ( buff && buff . Sta ) { return this . stamina . Get ( ) * buff . Sta ; } else { return this . stamina . Get ( ) ; } } public Dex ( ) { const buff = this . combatStatus . stats [ StatusEffect . Buff ] ; if ( buff && buff . Dex ) { return this . dexterity . Get ( ) * buff . Dex ; } else { return this . dexterity . Get ( ) ; } } public Int ( ) { const buff = this . combatStatus . stats [ StatusEffect . Buff ] ; if ( buff && buff . Int ) { return this . intelligence . Get ( ) * buff . Int ; } else { return this . intelligence . Get ( ) ; } } public Spi ( ) { const buff = this . combatStatus . stats [ StatusEffect . Buff ] ; if ( buff && buff . Spi ) { return this . spirit . Get ( ) * buff . Spi ; } else { return this . spirit . Get ( ) ; } } public Lib ( ) { const buff = this . combatStatus . stats [ StatusEffect . Buff ] ; if ( buff && buff . Lib ) { return this . libido . Get ( ) * buff . Lib ; } else { return this . libido . Get ( ) ; } } public Cha ( ) { const buff = this . combatStatus . stats [ StatusEffect . Buff ] ; if ( buff && buff . Cha ) { return this . charisma . Get ( ) * buff . Cha ; } else { return this . charisma . Get ( ) ; } } public Incapacitated ( ) { return this . curHp <= 0 ; } public Inhibited ( ) { if ( this . combatStatus . stats [ StatusEffect . Freeze ] !== undefined ) { return true ; } if ( this . combatStatus . stats [ StatusEffect . Numb ] !== undefined ) { return true ; } if ( this . combatStatus . stats [ StatusEffect . Petrify ] !== undefined ) { return true ; } if ( this . combatStatus . stats [ StatusEffect . Blind ] !== undefined ) { return true ; } if ( this . combatStatus . stats [ StatusEffect . Sleep ] !== undefined ) { return true ; } if ( this . combatStatus . stats [ StatusEffect . Enrage ] !== undefined ) { return true ; } if ( this . combatStatus . stats [ StatusEffect . Fatigue ] !== undefined ) { return true ; } if ( this . combatStatus . stats [ StatusEffect . Limp ] !== undefined ) { return true ; } return false ; } public AddHPFraction ( fraction ) { fraction = fraction || 0 ; const old = this . curHp ; this . curHp += fraction * this . HP ( ) ; if ( this . curHp > this . HP ( ) ) { this . curHp = this . HP ( ) ; } if ( this . curHp < 0 ) { this . curHp = 0 ; if ( CurEncounter ( ) ) { CurEncounter ( ) . OnIncapacitate ( this ) ; } } if ( fraction > 0 && this . combatStatus . stats [ StatusEffect . Bleed ] ) { this . combatStatus . stats [ StatusEffect . Bleed ] = undefined ; } return this . curHp - old ; } public AddSPFraction ( fraction ) { fraction = fraction || 0 ; const old = this . curSp ; this . curSp += fraction * this . SP ( ) ; if ( this . curSp > this . SP ( ) ) { this . curSp = this . SP ( ) ; } if ( this . curSp < 0 ) { this . curSp = 0 ; } return this . curSp - old ; } public AddLustFraction ( fraction ) { fraction = fraction || 0 ; const old = this . curLust ; this . curLust += fraction * this . Lust ( ) ; if ( this . curLust > this . Lust ( ) ) { this . curLust = this . Lust ( ) ; } if ( this . curLust < 0 ) { this . curLust = 0 ; } return this . curLust - old ; } public PhysDmgHP ( encounter , caster , val ) { const parse = { possessive : this . possessive ( ) , } ; const ent = this ; if ( val >= 0 ) { return true ; } if ( this . combatStatus . stats [ StatusEffect . Sleep ] !== undefined ) { this . combatStatus . stats [ StatusEffect . Sleep ] = undefined ; } if ( this . combatStatus . stats [ StatusEffect . Confuse ] !== undefined ) { this . combatStatus . stats [ StatusEffect . Confuse ] . OnFade ( encounter , this ) ; } if ( this . combatStatus . stats [ StatusEffect . Counter ] !== undefined ) { const onhit = this . combatStatus . stats [ StatusEffect . Counter ] . OnHit ; this . combatStatus . stats [ StatusEffect . Counter ] . hits -- ; if ( this . combatStatus . stats [ StatusEffect . Counter ] . hits <= 0 ) { this . combatStatus . stats [ StatusEffect . Counter ] = undefined ; } let ret ; if ( onhit ) { ret = onhit ( encounter , this , caster , val ) ; } return ret ; } const decoy = this . combatStatus . stats [ StatusEffect . Decoy ] ; if ( decoy !== undefined ) { const num = decoy . copies ; const toHit = 1 / ( num + 1 ) ; if ( Math . random ( ) < toHit ) { return true ; } const defFunc = ( ) => { parse . oneof = num > 1 ? " one of" : "" ; parse . copy = num > 1 ? "copies" : "copy" ; Text . Add ( "The attack is absorbed by[oneof] [possessive] [copy]!" , parse ) ; Text . NL ( ) ; ent . combatStatus . stats [ StatusEffect . Decoy ] . copies -- ; if ( ent . combatStatus . stats [ StatusEffect . Decoy ] . copies <= 0 ) { ent . combatStatus . stats [ StatusEffect . Decoy ] = undefined ; } Text . Flush ( ) ; return false ; } ; const func = decoy . func || defFunc ; return func ( caster , val ) ; } return true ; } public AddHPAbs ( val ) { val = val || 0 ; const old = this . curHp ; this . curHp += val ; if ( this . curHp > this . HP ( ) ) { this . curHp = this . HP ( ) ; } if ( this . curHp < 0 ) { this . curHp = 0 ; if ( CurEncounter ( ) ) { CurEncounter ( ) . OnIncapacitate ( this ) ; } } if ( val > 0 && this . combatStatus . stats [ StatusEffect . Bleed ] ) { this . combatStatus . stats [ StatusEffect . Bleed ] = undefined ; } return this . curHp - old ; } public AddSPAbs ( val ) { val = val || 0 ; const old = this . curSp ; this . curSp += val ; if ( this . curSp > this . SP ( ) ) { this . curSp = this . SP ( ) ; } if ( this . curSp < 0 ) { this . curSp = 0 ; } return this . curSp - old ; } public AddLustAbs ( val ) { val = val || 0 ; const old = this . curLust ; this . curLust += val ; if ( this . curLust > this . Lust ( ) ) { this . curLust = this . Lust ( ) ; } if ( this . curLust < 0 ) { this . curLust = 0 ; } return this . curLust - old ; } public RestFull ( ) { this . curHp = this . HP ( ) ; this . curSp = this . SP ( ) ; this . curLust = this . MinLust ( ) ; } public Sleep ( ) { this . curHp = this . HP ( ) ; this . curSp = this . SP ( ) ; } public HPLevel ( ) { return this . curHp / this . HP ( ) ; } public SPLevel ( ) { return this . curSp / this . SP ( ) ; } public LustLevel ( ) { return this . curLust / this . Lust ( ) ; } public ClearCombatBonuses ( ) { this . maxHp . temp = 0 ; this . maxSp . temp = 0 ; this . maxLust . temp = 0 ; this . strength . temp = 0 ; this . stamina . temp = 0 ; this . dexterity . temp = 0 ; this . intelligence . temp = 0 ; this . spirit . temp = 0 ; this . libido . temp = 0 ; this . charisma . temp = 0 ; this . BalanceStats ( ) ; this . statusWear = [ ] ; } public BalanceStats ( ) { if ( this . curHp < 0 ) { this . curHp = 0 ; } else if ( this . curHp > this . HP ( ) ) { this . curHp = this . HP ( ) ; } if ( this . curSp < 0 ) { this . curSp = 0 ; } else if ( this . curSp > this . SP ( ) ) { this . curSp = this . SP ( ) ; } if ( this . curLust < 0 ) { this . curLust = 0 ; } else if ( this . curLust > this . Lust ( ) ) { this . curLust = this . Lust ( ) ; } } public AddLustOverTime ( hours ) { let lustRate = this . libido . Get ( ) / this . spirit . Get ( ) ; lustRate /= 48 ; const slutFactor = ( ( this . slut . Get ( ) / 100 ) + 1 ) ; this . AddLustFraction ( hours * lustRate * slutFactor ) ; } public LustCombatEfficiencyLevel ( ) { let lustFactor = ( this . LustLevel ( ) - 0.5 ) * 2 ; if ( lustFactor < 0 ) { lustFactor = 0 ; } return 1.0 - 0.25 * lustFactor ; } public LustCombatTurnLossChance ( ) { let lustFactor = this . LustLevel ( ) - 0.5 ; if ( lustFactor < 0 ) { lustFactor = 0 ; } return lustFactor ; } public Initiative ( ) { let ini = Math . sqrt ( 2 * this . Dex ( ) + this . Int ( ) ) ; const haste = this . combatStatus . stats [ StatusEffect . Haste ] ; if ( haste ) { ini *= haste . factor ; } const slow = this . combatStatus . stats [ StatusEffect . Slow ] ; if ( slow ) { ini /= slow . factor ; } return ini ; } public PAttack ( ) { const atkStat = ( this . Str ( ) * 3 + this . Sta ( ) + this . Dex ( ) ) / 2 ; const atkWep = this . atkMod ; const atkRand = _ . random ( 0.9 , 1.1 ) ; return atkStat * atkWep * atkRand ; } public PDefense ( ) { let defStat = this . Sta ( ) * 3 + this . Spi ( ) ; if ( defStat < 0 ) { defStat = 0 ; } const defArmor = this . defMod ; const defRand = _ . random ( 0.9 , 1.1 ) ; return defStat * defArmor * defRand ; } public PHit ( ) { let hitStat = 3 * this . Dex ( ) + this . Int ( ) + this . Cha ( ) ; const blind = this . combatStatus . stats [ StatusEffect . Blind ] ; if ( blind ) { hitStat *= ( 1 - blind . str ) ; } return hitStat ; } public PEvade ( attack ? ) { const evadeStat = 3 * this . Dex ( ) + this . Int ( ) + this . Cha ( ) ; return evadeStat ; } public MAttack ( ) { const magStat = ( 3 * this . Int ( ) + this . Spi ( ) + this . Cha ( ) ) / 2 ; const magRand = _ . random ( 0.9 , 1.1 ) ; return magStat * magRand ; } public MDefense ( ) { let magDef = this . Sta ( ) + 3 * this . Spi ( ) ; if ( magDef < 0 ) { magDef = 0 ; } const magRand = _ . random ( 0.9 , 1.1 ) ; return magDef * magRand ; } public MHit ( ) { const hitStat = 3 * this . Int ( ) + this . Spi ( ) + this . Cha ( ) ; return hitStat ; } public MEvade ( attack ? ) { const evadeStat = 3 * this . Spi ( ) + this . Int ( ) + this . Dex ( ) ; return evadeStat ; } public LAttack ( ) { const sedStat = ( this . Dex ( ) + 2 * this . Lib ( ) + 2 * this . Cha ( ) ) / 2 ; const sedArmor = 1 ; const sedRand = _ . random ( 0.9 , 1.1 ) ; return sedStat * sedArmor * sedRand ; } public LDefense ( ) { let comStat = 2 * this . Sta ( ) + this . Spi ( ) + this . Cha ( ) ; if ( comStat < 0 ) { comStat = 0 ; } const comRand = _ . random ( 0.9 , 1.1 ) ; return comStat * comRand ; } public LHit ( ) { const hitStat = 3 * this . Lib ( ) + 2 * this . Cha ( ) ; return hitStat ; } public LEvade ( attack ? ) { let evadeStat = 3 * this . Spi ( ) + this . Sta ( ) + this . Int ( ) ; const blind = this . combatStatus . stats [ StatusEffect . Blind ] ; if ( blind ) { evadeStat *= ( 1 + blind . str ) ; } return evadeStat ; } public Resistance ( type ) { const res = this . statusDef [ type ] || 0 ; const gear = this . statusDefGear [ type ] || 0 ; const wear = this . statusWear [ type ] || 0 ; const curse = this . combatStatus . stats [ StatusEffect . Curse ] ; let total = res + gear - wear ; if ( curse ) { total -= curse . str ; } return total ; } public AddResistanceWear ( type , wear ? ) { wear = wear || 0 ; if ( this . statusWear [ type ] ) { this . statusWear [ type ] += wear ; } else { this . statusWear [ type ] = wear ; } } public SaveSexFlags ( storage ) { const sex = { } ; if ( this . sex . rBlow !== 0 ) { sex . rBlow = this . sex . rBlow ; } if ( this . sex . gBlow !== 0 ) { sex . gBlow = this . sex . gBlow ; } if ( this . sex . rCunn !== 0 ) { sex . rCunn = this . sex . rCunn ; } if ( this . sex . gCunn !== 0 ) { sex . gCunn = this . sex . gCunn ; } if ( this . sex . rAnal !== 0 ) { sex . rAnal = this . sex . rAnal ; } if ( this . sex . gAnal !== 0 ) { sex . gAnal = this . sex . gAnal ; } if ( this . sex . rVag !== 0 ) { sex . rVag = this . sex . rVag ; } if ( this . sex . gVag !== 0 ) { sex . gVag = this . sex . gVag ; } if ( this . sex . sired !== 0 ) { sex . sired = this . sex . sired ; } if ( this . sex . birth !== 0 ) { sex . birth = this . sex . birth ; } storage . sex = sex ; } public SaveCombatStats ( storage ) { storage . name = this . name ; storage . exp = this . experience . toFixed ( ) ; storage . points = this . pendingStatPoints . toFixed ( ) ; storage . exp2lvl = this . expToLevel . toFixed ( ) ; storage . lvl = this . level . toFixed ( ) ; storage . sexp = this . sexperience . toFixed ( ) ; storage . sxp2lvl = this . sexpToLevel . toFixed ( ) ; storage . slvl = this . sexlevel . toFixed ( ) ; storage . alvl = this . alchemyLevel . toFixed ( ) ; storage . curHp = this . curHp . toFixed ( 1 ) ; storage . maxHp = this . maxHp . base . toFixed ( 1 ) ; storage . curSp = this . curSp . toFixed ( 1 ) ; storage . maxSp = this . maxSp . base . toFixed ( 1 ) ; storage . curLust = this . curLust . toFixed ( 1 ) ; storage . maxLust = this . maxLust . base . toFixed ( 1 ) ; storage . str = this . strength . base . toFixed ( 1 ) ; storage . sta = this . stamina . base . toFixed ( 1 ) ; storage . dex = this . dexterity . base . toFixed ( 1 ) ; storage . inte = this . intelligence . base . toFixed ( 1 ) ; storage . spi = this . spirit . base . toFixed ( 1 ) ; storage . lib = this . libido . base . toFixed ( 1 ) ; storage . cha = this . charisma . base . toFixed ( 1 ) ; storage . maxHpG = this . maxHp . growth . toFixed ( 1 ) ; storage . maxSpG = this . maxSp . growth . toFixed ( 1 ) ; storage . maxLustG = this . maxLust . growth . toFixed ( 1 ) ; storage . strG = this . strength . growth . toFixed ( 1 ) ; storage . staG = this . stamina . growth . toFixed ( 1 ) ; storage . dexG = this . dexterity . growth . toFixed ( 1 ) ; storage . inteG = this . intelligence . growth . toFixed ( 1 ) ; storage . spiG = this . spirit . growth . toFixed ( 1 ) ; storage . libG = this . libido . growth . toFixed ( 1 ) ; storage . chaG = this . charisma . growth . toFixed ( 1 ) ; if ( this . monsterName ) { storage . mName = this . monsterName ; } if ( this . MonsterName ) { storage . MName = this . MonsterName ; } this . SaveStatusEffects ( storage ) ; } public SaveStatusEffects ( storage ) { const s = this . combatStatus . ToStorage ( ) ; if ( s ) { storage . stat = s ; } } public SavePersonalityStats ( storage ) { if ( this . subDom . base !== 0 ) { storage . subDom = this . subDom . base . toFixed ( ) ; } if ( this . slut . base !== 0 ) { storage . slut = this . slut . base . toFixed ( ) ; } if ( this . relation . base !== 0 ) { storage . rel = this . relation . base . toFixed ( ) ; } if ( this . drunkLevel !== 0 ) { storage . drunk = this . drunkLevel . toFixed ( 2 ) ; } } public SaveFlags ( storage ) { const flags = { } ; _ . forIn ( this . flags , ( flag , key ) => { if ( flag !== 0 ) { flags [ key ] = flag ; } } ) ; storage . flags = flags ; } public SavePerks ( storage ) { const perks = [ ] ; for ( const perk of this . perks ) { perks . push ( perk . id ) ; } storage . perks = perks ; } public SaveRecipes ( storage ) { if ( this . recipes ) { storage . recipes = [ ] ; for ( const recipe of this . recipes ) { storage . recipes . push ( recipe . id ) ; } } } public SaveJobs ( storage ) { storage . jobs = { } ; _ . forIn ( this . jobs , ( jd , key ) => { const jobStorage = jd . ToStorage ( ) ; if ( jobStorage ) { storage . jobs [ key ] = jobStorage ; } } ) ; if ( this . currentJob ) { storage . curJob = this . currentJob . name ; } } public SaveEquipment ( storage ) { if ( this . weaponSlot ) { storage . wep = this . weaponSlot . id ; } if ( this . topArmorSlot ) { storage . toparm = this . topArmorSlot . id ; } if ( this . botArmorSlot ) { storage . botarm = this . botArmorSlot . id ; } if ( this . acc1Slot ) { storage . acc1 = this . acc1Slot . id ; } if ( this . acc2Slot ) { storage . acc2 = this . acc2Slot . id ; } if ( this . strapOn ) { storage . toy = this . strapOn . id ; } } public SavePregnancy ( storage ) { storage . preg = this . pregHandler . ToStorage ( ) ; } public SaveLactation ( storage ) { storage . lact = this . lactHandler . ToStorage ( ) ; } public SaveBodyPartial ( storage , opts ) { storage . body = this . body . ToStoragePartial ( opts ) ; } public ToStorage ( ) { const storage = { } ; storage . body = this . body . ToStorage ( ) ; this . SaveCombatStats ( storage ) ; this . SavePersonalityStats ( storage ) ; this . SaveRecipes ( storage ) ; this . SaveJobs ( storage ) ; this . SaveEquipment ( storage ) ; this . SavePregnancy ( storage ) ; this . SaveLactation ( storage ) ; this . SaveFlags ( storage ) ; this . SaveSexFlags ( storage ) ; this . SavePerks ( storage ) ; return storage ; } public LoadCombatStats ( storage ) { this . name = storage . name || this . name ; this . monsterName = storage . mName || this . monsterName ; this . MonsterName = storage . MName || this . MonsterName ; this . experience = ! isNaN ( parseInt ( storage . exp , 10 ) ) ? parseInt ( storage . exp , 10 ) : this . experience ; this . level = ! isNaN ( parseInt ( storage . lvl , 10 ) ) ? parseInt ( storage . lvl , 10 ) : this . level ; this . pendingStatPoints = ! isNaN ( parseInt ( storage . points , 10 ) ) ? parseInt ( storage . points , 10 ) : this . pendingStatPoints ; this . expToLevel = ! isNaN ( parseInt ( storage . exp2lvl , 10 ) ) ? parseInt ( storage . exp2lvl , 10 ) : this . expToLevel ; this . sexperience = ! isNaN ( parseInt ( storage . sexp , 10 ) ) ? parseInt ( storage . sexp , 10 ) : this . sexperience ; this . sexpToLevel = ! isNaN ( parseInt ( storage . sxp2lvl , 10 ) ) ? parseInt ( storage . sxp2lvl , 10 ) : this . sexpToLevel ; this . sexlevel = ! isNaN ( parseInt ( storage . slvl , 10 ) ) ? parseInt ( storage . slvl , 10 ) : this . sexlevel ; this . alchemyLevel = ! isNaN ( parseInt ( storage . alvl , 10 ) ) ? parseInt ( storage . alvl , 10 ) : this . alchemyLevel ; this . curHp = ! isNaN ( parseFloat ( storage . curHp ) ) ? parseFloat ( storage . curHp ) : this . curHp ; this . maxHp . base = ! isNaN ( parseFloat ( storage . maxHp ) ) ? parseFloat ( storage . maxHp ) : this . maxHp . base ; this . curSp = ! isNaN ( parseFloat ( storage . curSp ) ) ? parseFloat ( storage . curSp ) : this . curSp ; this . maxSp . base = ! isNaN ( parseFloat ( storage . maxSp ) ) ? parseFloat ( storage . maxSp ) : this . maxSp . base ; this . curLust = ! isNaN ( parseFloat ( storage . curLust ) ) ? parseFloat ( storage . curLust ) : this . curLust ; this . maxLust . base = ! isNaN ( parseFloat ( storage . maxLust ) ) ? parseFloat ( storage . maxLust ) : this . maxLust . base ; this . strength . base = ! isNaN ( parseFloat ( storage . str ) ) ? parseFloat ( storage . str ) : this . strength . base ; this . stamina . base = ! isNaN ( parseFloat ( storage . sta ) ) ? parseFloat ( storage . sta ) : this . stamina . base ; this . dexterity . base = ! isNaN ( parseFloat ( storage . dex ) ) ? parseFloat ( storage . dex ) : this . dexterity . base ; this . intelligence . base = ! isNaN ( parseFloat ( storage . inte ) ) ? parseFloat ( storage . inte ) : this . intelligence . base ; this . spirit . base = ! isNaN ( parseFloat ( storage . spi ) ) ? parseFloat ( storage . spi ) : this . spirit . base ; this . libido . base = ! isNaN ( parseFloat ( storage . lib ) ) ? parseFloat ( storage . lib ) : this . libido . base ; this . charisma . base = ! isNaN ( parseFloat ( storage . cha ) ) ? parseFloat ( storage . cha ) : this . charisma . base ; this . maxHp . growth = ! isNaN ( parseFloat ( storage . maxHpG ) ) ? parseFloat ( storage . maxHpG ) : this . maxHp . growth ; this . maxSp . growth = ! isNaN ( parseFloat ( storage . maxSpG ) ) ? parseFloat ( storage . maxSpG ) : this . maxSp . growth ; this . maxLust . growth = ! isNaN ( parseFloat ( storage . maxLustG ) ) ? parseFloat ( storage . maxLustG ) : this . maxLust . growth ; this . strength . growth = ! isNaN ( parseFloat ( storage . strG ) ) ? parseFloat ( storage . strG ) : this . strength . growth ; this . stamina . growth = ! isNaN ( parseFloat ( storage . staG ) ) ? parseFloat ( storage . staG ) : this . stamina . growth ; this . dexterity . growth = ! isNaN ( parseFloat ( storage . dexG ) ) ? parseFloat ( storage . dexG ) : this . dexterity . growth ; this . intelligence . growth = ! isNaN ( parseFloat ( storage . inteG ) ) ? parseFloat ( storage . inteG ) : this . intelligence . growth ; this . spirit . growth = ! isNaN ( parseFloat ( storage . spiG ) ) ? parseFloat ( storage . spiG ) : this . spirit . growth ; this . libido . growth = ! isNaN ( parseFloat ( storage . libG ) ) ? parseFloat ( storage . libG ) : this . libido . growth ; this . charisma . growth = ! isNaN ( parseFloat ( storage . chaG ) ) ? parseFloat ( storage . chaG ) : this . charisma . growth ; this . LoadStatusEffects ( storage ) ; } public LoadStatusEffects ( storage ) { if ( storage . stat ) { this . combatStatus . FromStorage ( storage . stat ) ; } } public LoadPersonalityStats ( storage ) { this . subDom . base = parseInt ( storage . subDom , 10 ) || this . subDom . base ; this . slut . base = parseInt ( storage . slut , 10 ) || this . slut . base ; this . relation . base = parseInt ( storage . rel , 10 ) || this . relation . base ; this . drunkLevel = parseFloat ( storage . drunk ) || this . drunkLevel ; } public LoadRecipes ( storage ) { if ( storage . recipes ) { this . recipes = [ ] ; _ . forIn ( storage . recipes , ( value , key ) => { this . recipes . push ( ItemIds [ value ] ) ; } ) ; } } public LoadJobs ( storage ) { if ( storage . jobs ) { _ . forIn ( this . jobs , ( jd , key ) => { jd . FromStorage ( storage . jobs [ jd . job . name ] ) ; } ) ; } if ( storage . curJob ) { this . currentJob = Jobs [ storage . curJob ] ; } } public LoadEquipment ( storage ) { if ( storage . wep ) { this . weaponSlot = ItemIds [ storage . wep ] ; } if ( storage . toparm ) { this . topArmorSlot = ItemIds [ storage . toparm ] ; } if ( storage . botarm ) { this . botArmorSlot = ItemIds [ storage . botarm ] ; } if ( storage . acc1 ) { this . acc1Slot = ItemIds [ storage . acc1 ] ; } if ( storage . acc2 ) { this . acc2Slot = ItemIds [ storage . acc2 ] ; } if ( storage . toy ) { this . strapOn = ItemIds [ storage . toy ] ; } } public LoadFlags ( storage ) { _ . forIn ( storage . flags , ( value , key ) => { this . flags [ key ] = parseInt ( value , 10 ) ; } ) ; } public LoadSexFlags ( storage ) { _ . forIn ( storage . sex , ( value , key ) => { this . sex [ key ] = parseInt ( value , 10 ) ; } ) ; } public LoadPerks ( storage ) { if ( storage . perks ) { this . perks = [ ] ; for ( const perkId of storage . perks ) { this . perks . push ( PerkIds [ perkId ] ) ; } } } public LoadPregnancy ( storage ) { this . pregHandler . FromStorage ( storage . preg ) ; } public LoadLactation ( storage ) { this . lactHandler . FromStorage ( storage . lact ) ; } public FromStorage ( storage ) { storage = storage || { } ; if ( storage . body ) { this . body = new Body ( this ) ; this . body . FromStorage ( storage . body ) ; } this . LoadPregnancy ( storage ) ; this . LoadLactation ( storage ) ; this . LoadFlags ( storage ) ; this . LoadSexFlags ( storage ) ; this . LoadCombatStats ( storage ) ; this . LoadPersonalityStats ( storage ) ; this . LoadRecipes ( storage ) ; this . LoadJobs ( storage ) ; this . LoadEquipment ( storage ) ; this . LoadPerks ( storage ) ; this . RecallAbilities ( ) ; this . SetLevelBonus ( ) ; this . Equip ( ) ; } public RecallAbilities ( ) { _ . forIn ( this . jobs , ( jd , key ) => { for ( let i = 0 ; i < jd . level - 1 ; i ++ ) { if ( i >= jd . job . levels . length ) { break ; } const skills = jd . job . levels [ i ] . skills ; if ( skills ) { for ( const sd of skills ) { const ability = sd . ab ; const set = sd . set ; this . abilities [ set ] . AddAbility ( ability ) ; } } } } ) ; } public PrintDescription ( partial ? ) { const height = Math . floor ( Unit . CmToInch ( this . body . height . Get ( ) ) ) ; const heightFeet = Math . floor ( height / 12 ) ; const heightInches = Math . floor ( height % 12 ) ; let h = heightFeet + " feet" ; if ( heightInches > 0 ) { h += " and " + heightInches + " inch" ; if ( heightInches > 1 ) { h += "es" ; } } const ent = this . Parser ; const armor = this . ArmorDescLong ( ) ; const gender = this . body . GenderStr ( ) ; const race = this . body . RaceStr ( ) ; const weigth = Math . floor ( this . body . weigth . Get ( ) * 2 ) . toString ( ) ; Text . Add ( `${ ent . mName } ${ ent . is } a ${ gender } ${ race }, ${ h } tall and weighing around ${ weigth }lb. ${ ent . HeShe } ${ ent . has } ${ ent . skin }. ` ) ; Text . Add ( `${ ent . HeShe } ${ ent . is } wearing ${ armor }.` ) ; if ( this . LowerArmor ( ) ) { const botarmor = this . LowerArmorDescLong ( ) ; Text . Add ( ` ${ ent . HeShe } ${ ent . is } wearing ${ botarmor }.` ) ; } if ( this . Weapon ( ) ) { const weapon = this . WeaponDescLong ( ) ; Text . Add ( ` ${ ent . HeShe } ${ ent . is } wielding ${ weapon }.` ) ; } Text . NL ( ) ; const eyeCount = Text . NumToText ( this . body . head . eyes . count . Get ( ) ) ; const eyeColor = ColorDesc ( this . body . head . eyes . color ) ; const eyeS = this . body . head . eyes . count . Get ( ) === 1 ? "" : "s" ; Text . Add ( `${ ent . HeShe } ${ ent . has } ${ ent . faceLong }. ${ ent . HisHer } ${ eyeCount } ${ eyeColor } ${ ent . eye }${ eyeS } observe the surroundings. ` ) ; const hairDesc = this . body . head . hair . Long ( ) ; Text . Add ( `A pair of ${ ent . ears } sticks out from ${ ent . poss } ${ hairDesc }. ` ) ; for ( const app of this . body . head . appendages ) { const appDesc = app . Long ( ) ; Text . Add ( `On ${ ent . hisher } head, ${ ent . heshe } ${ ent . has } a ${ appDesc }. ` ) ; } Text . NL ( ) ; let bs = false ; for ( const b of this . body . backSlots ) { const appDesc = b . Long ( ) ; Text . Add ( `On ${ ent . hisher } back, ${ ent . heshe } ${ ent . has } a ${ appDesc }. ` ) ; bs = true ; } if ( bs ) { Text . NL ( ) ; } if ( this . body . legs . count === 2 ) { Text . Add ( `${ ent . mName } ${ ent . has } arms. ${ ent . mName } ${ ent . has } ${ ent . legs }, ending in ${ ent . feet }.` ) ; } else if ( this . body . legs . count > 2 ) { const num = Text . NumToText ( this . body . legs . count ) ; const race = this . body . legs . race . qShort ( ) ; Text . Add ( `${ ent . mName } ${ ent . has } arms and ${ num } ${ race } legs.` ) ; } else { const race = this . body . legs . race . qShort ( ) ; Text . Add ( `${ ent . mName } ${ ent . has } arms and ${ race } lower body.` ) ; } Text . NL ( ) ; const buttDesc = this . Butt ( ) . Long ( ) ; Text . Add ( `${ ent . mName } ${ ent . has } ${ ent . hips }, and ${ buttDesc }.` ) ; Text . NL ( ) ; const breasts = this . body . breasts ; if ( breasts . length === 1 ) { const breastDesc = breasts [ 0 ] . Long ( ) ; Text . Add ( `${ ent . HeShe } ${ ent . has } ${ breastDesc }.` ) ; } else if ( breasts . length > 1 ) { const breast = breasts [ 0 ] ; const breastSize = breast . Desc ( ) . size ; const breastDesc = breasts [ 0 ] . Short ( ) ; Text . Add ( `Multiple rows of ${ breast . nounPlural ( ) } sprout from ${ ent . hisher } chest. ${ ent . HisHer } first pair of ${ breastDesc } are ${ breastSize } in circumference.` ) ; for ( let i = 1 ; i < breasts . length ; i ++ ) { Text . Add ( `<br>Another two breasts.` ) ; } } else { Text . Add ( `${ ent . mName } ${ ent . has } a featureless smooth chest.` ) ; } if ( breasts . length > 0 ) { this . LactationDesc ( ) ; } Text . NL ( ) ; const cocks = this . body . cock ; const vags = this . body . vagina ; if ( cocks . length === 1 ) { const cock = cocks [ 0 ] ; const cockDesc = cock . aLong ( ) ; Text . Add ( `${ ent . mName } ${ ent . has } ${ cockDesc }.` ) ; } else if ( cocks . length > 1 ) { const cock = cocks [ 0 ] ; const numCocks = Text . NumToText ( cocks . length ) ; Text . Add ( `${ ent . mName } ${ ent . has } a brace of ${ numCocks } ${ cock . nounPlural ( ) }.` ) ; for ( const cock of cocks ) { const cockDesc = cock . aLong ( ) ; Text . NL ( ) ; Text . Add ( `${ ent . mName } ${ ent . has } ${ cockDesc }.` ) ; } } if ( cocks [ 0 ] ) { Text . NL ( ) ; } if ( this . HasBalls ( ) ) { const ballsDesc = this . Balls ( ) . Long ( ) ; if ( cocks . length > 0 || vags . length > 0 ) { Text . Add ( `Beneath ${ ent . hisher } other genitalia, ${ ballsDesc } hang.` ) ; } else { Text . Add ( `Strangely, ${ ballsDesc } hang from ${ ent . hisher } otherwise flat crotch.` ) ; } Text . NL ( ) ; } else if ( cocks . length === 0 && vags . length === 0 ) { Text . Add ( `${ ent . mName } ${ ent . has } a smooth, featureless crotch.` ) ; Text . NL ( ) ; } if ( vags . length === 1 ) { const vag = vags [ 0 ] ; const vagDesc = vag . Desc ( ) ; Text . Add ( `${ ent . mName } ${ ent . has } ${ vagDesc . a } ${ vagDesc . adj } ${ vag . noun ( ) }.` ) ; } else if ( vags . length > 1 ) { const vag = vags [ 0 ] ; Text . Add ( `${ ent . mName } ${ ent . has } multiple ${ vag . nounPlural ( ) }. ${ ent . HisHer } first ${ vag . noun ( ) } is slutty.<br>` ) ; for ( let i = 1 ; i < vags . length ; i ++ ) { Text . Add ( `<br>Another of ${ ent . hisher } ${ vag . nounPlural ( ) } is slutty.` ) ; } } if ( vags [ 0 ] ) { Text . NL ( ) ; } if ( partial ) { return ; } const balls = this . Balls ( ) ; Text . Add ( `Cum: ${ balls . cum . Get ( ) . toFixed ( 2 ) } / ${ balls . CumCap ( ) . toFixed ( 2 ) }` ) ; Text . NL ( ) ; Text . Add ( `Milk: ${ this . Milk ( ) . toFixed ( 2 ) } / ${ this . MilkCap ( ) . toFixed ( 2 ) }` ) ; Text . NL ( ) ; let womb = this . pregHandler . Womb ( { slot : PregnancyHandler . Slot . Vag } ) ; if ( womb && womb . pregnant ) { const proc = ( womb . progress * 100 ) . toFixed ( 1 ) ; const hour = womb . hoursToBirth . toFixed ( 1 ) ; Text . Add ( `${ ent . mName } ${ ent . is } pregnant. Current progress, ${ proc }%. ${ hour } hours to term.` ) ; Text . NL ( ) ; } womb = this . pregHandler . Womb ( { slot : PregnancyHandler . Slot . Butt } ) ; if ( womb && womb . pregnant ) { const proc = ( womb . progress * 100 ) . toFixed ( 1 ) ; const hour = womb . hoursToBirth . toFixed ( 1 ) ; Text . Add ( `${ ent . mName } ${ ent . is } butt-pregnant. Current progress, ${ proc }%. ${ hour } hours to term.` ) ; Text . NL ( ) ; } const anusDesc = this . Butt ( ) . AnalLong ( ) ; Text . Add ( `${ ent . mName } ${ ent . has } ${ anusDesc }.` ) ; if ( GetDEBUG ( ) ) { Text . NL ( ) ; Text . Add ( "DEBUG: relation: " + this . relation . Get ( ) , undefined , "bold" ) ; Text . NL ( ) ; Text . Add ( "DEBUG: subDom: " + this . subDom . Get ( ) , undefined , "bold" ) ; Text . NL ( ) ; Text . Add ( "DEBUG: slut: " + this . slut . Get ( ) , undefined , "bold" ) ; Text . NL ( ) ; const race = new RaceScore ( this . body ) ; Text . Add ( race . debug ( ) ) ; Text . NL ( ) ; } const drunk = this . DrunkStr ( ) ; if ( drunk ) { Text . NL ( ) ; Text . Add ( drunk ) ; } Text . Flush ( ) ; } public SubDom ( ) { return this . subDom . Get ( ) ; } public Relation ( ) { return this . relation . Get ( ) ; } public Slut ( ) { return this . slut . Get ( ) ; } public Gender ( ) { return this . body . Gender ( ) ; } public Race ( ) { return this . body . torso . race ; } public MuscleTone ( ) { return this . body . muscleTone . Get ( ) ; } public BodyMass ( ) { return this . body . bodyMass . Get ( ) ; } public Height ( ) { return this . body . height . Get ( ) ; } public Weigth ( ) { return this . body . weigth . Get ( ) ; } public Humanity ( ) { const racescore = new RaceScore ( this . body ) ; const humanScore = new RaceScore ( ) ; humanScore . score [ Race . Human . id ] = 1 ; return racescore . Compare ( humanScore ) ; } public RaceCompare ( race ) { const racescore = new RaceScore ( this . body ) ; return racescore . SumScore ( race ) ; } public Femininity ( ) { return this . body . femininity . Get ( ) ; } public FaceDesc ( ) { return this . body . FaceDesc ( ) ; } public SkinDesc ( ) { return this . body . SkinDesc ( ) ; } public SkinType ( ) { return this . body . torso . race ; } public LipsDesc ( ) { return this . body . LipsDesc ( ) ; } public TongueDesc ( ) { return this . body . TongueDesc ( ) ; } public TongueTipDesc ( ) { return this . body . TongueTipDesc ( ) ; } public LongTongue ( ) { return this . body . LongTongue ( ) ; } public Hair ( ) { return this . body . head . hair ; } public HasHair ( ) { return this . body . head . hair . Bald ( ) === false ; } public HasLongHair ( ) { return this . body . head . hair . Bald ( ) === false ; } public Face ( ) { return this . body . head ; } public Mouth ( ) { return this . body . head . mouth ; } public Tongue ( ) { return this . body . head . mouth . tongue ; } public Eyes ( ) { return this . body . head . eyes ; } public EyeDesc ( ) { return this . body . EyeDesc ( ) ; } public EyesDesc ( ) { return this . body . EyeDesc ( ) + "s" ; } public Ears ( ) { return this . body . head . ears ; } public EarDesc ( plural ? ) { return this . body . EarDesc ( plural ) ; } public HasFlexibleEars ( ) { return this . body . HasFlexibleEars ( ) ; } public HasMuzzle ( ) { return this . body . HasMuzzle ( ) ; } public HasLongSnout ( ) { return this . body . HasLongSnout ( ) ; } public Arms ( ) { return this . body . arms ; } public MultiArm ( ) { return this . body . arms . count > 2 ; } public Legs ( ) { return this . body . legs ; } public LowerBodyType ( ) { if ( this . body . legs . count < 2 ) { return LowerBodyType . Single ; } else if ( this . body . legs . count === 2 ) { return LowerBodyType . Humanoid ; } else { return LowerBodyType . Taur ; } } public NumLegs ( ) { return this . body . legs . count ; } public Humanoid ( ) { return this . LowerBodyType ( ) === LowerBodyType . Humanoid ; } public HasLegs ( ) { return ( this . body . legs . count >= 2 ) ; } public IsNaga ( ) { return ( this . body . legs . count < 2 ) && ( this . body . legs . race . isRace ( Race . Snake ) ) ; } public IsTaur ( ) { return this . LowerBodyType ( ) === LowerBodyType . Taur ; } public IsGoo ( ) { return ( this . body . legs . race . isRace ( Race . Goo ) ) ; } public IsFlexible ( ) { return this . body . IsFlexible ( ) ; } public Butt ( ) { return this . body . ass ; } public HasBalls ( ) { return this . Balls ( ) . count . Get ( ) > 0 ; } public Balls ( ) { return this . body . balls ; } public BallsDesc ( ) { return this . Balls ( ) . Short ( ) ; } public Virility ( ) { return this . body . balls . fertility . Get ( ) ; } public HasFur ( ) { return this . body . HasFur ( ) ; } public HasSkin ( ) { return this . body . HasSkin ( ) ; } public HasScales ( ) { return this . body . HasScales ( ) ; } public LactationDesc ( ) { } public StomachDesc ( ) { const bellysize = this . pregHandler . BellySize ( ) ; return this . body . StomachDesc ( bellysize ) ; } public HipDesc ( ) { return this . body . HipsDesc ( ) ; } public HipsDesc ( ) { return this . body . HipsDesc ( true ) ; } public HipSize ( ) { return this . body . HipSize ( ) ; } public ArmDesc ( ) { return this . body . ArmDesc ( ) ; } public HandDesc ( ) { return this . body . HandDesc ( ) ; } public PalmDesc ( ) { return this . body . PalmDesc ( ) ; } public LegDesc ( ) { return this . body . LegDesc ( ) ; } public LegsDesc ( ) { return this . body . LegsDesc ( ) ; } public ThighDesc ( ) { return this . body . ThighDesc ( ) ; } public ThighsDesc ( ) { return this . body . ThighsDesc ( ) ; } public KneeDesc ( ) { return this . body . KneesDesc ( ) ; } public KneesDesc ( ) { return this . body . KneesDesc ( true ) ; } public FeetDesc ( ) { return this . body . FeetDesc ( ) ; } public FootDesc ( ) { return this . body . FootDesc ( ) ; } public Appendages ( ) { return this . body . head . appendages ; } public HasNightvision ( ) { return this . body . HasNightvision ( ) ; } public HasHorns ( ) { for ( const app of this . body . head . appendages ) { if ( app . type === AppendageType . horn ) { return app ; } } return undefined ; } public HasAntenna ( ) { for ( const app of this . body . head . appendages ) { if ( app . type === AppendageType . antenna ) { return app ; } } return undefined ; } public Back ( ) { return this . body . backSlots ; } public HasTail ( ) { for ( const slot of this . body . backSlots ) { if ( slot . type === AppendageType . tail ) { return slot ; } } return undefined ; } public HasPrehensileTail ( ) { let found = false ; for ( const slot of this . body . backSlots ) { if ( slot . type === AppendageType . tail ) { found = found || slot . Prehensile ( ) ; } } return found ; } public HasWings ( ) { for ( const slot of this . body . backSlots ) { if ( slot . type === AppendageType . wing ) { return slot ; } } return undefined ; } public NumAttributes ( race ) { return this . body . NumAttributes ( race ) ; } public Weapon ( ) { return this . weaponSlot ; } public WeaponDesc ( ) { return this . weaponSlot ? this . weaponSlot . sDesc ( ) : "stick" ; } public WeaponDescLong ( ) { return this . weaponSlot ? this . weaponSlot . lDesc ( ) : "a stick" ; } public Armor ( ) { return this . topArmorSlot ; } public LowerArmor ( ) { return this . botArmorSlot ; } public LowerArmorDesc ( ) { return this . botArmorSlot ? this . botArmorSlot . sDesc ( ) : this . ArmorDesc ( ) ; } public LowerArmorDescLong ( ) { return this . botArmorSlot ? this . botArmorSlot . lDesc ( ) : this . ArmorDescLong ( ) ; } public ArmorDesc ( ) { return this . topArmorSlot ? this . topArmorSlot . sDesc ( ) : "comfortable clothes" ; } public ArmorDescLong ( ) { return this . topArmorSlot ? this . topArmorSlot . lDesc ( ) : "a set of comfortable clothes" ; } public Accessories ( ) { return [ this . acc1Slot , this . acc2Slot ] ; } public nameDesc ( ) { return this . monsterName || this . name ; } public NameDesc ( ) { return this . MonsterName || this . name ; } public possessive ( ) { const name = this . monsterName || this . name || "the entity" ; const letter = name [ name . length - 1 ] ; const s = ( letter === "s" || letter === "x" ) ? "'" : "'s" ; return name + s ; } public Possessive ( ) { const name = this . MonsterName || this . name || "The entity" ; const letter = name [ name . length - 1 ] ; const s = ( letter === "s" || letter === "x" ) ? "'" : "'s" ; return name + s ; } public possessivePlural ( ) { const name = this . groupName || this . name || "the entities" ; return name + "'" ; } public PossessivePlural ( ) { const name = this . GroupName || this . name || "The entities" ; return name + "'" ; } public heshe ( forcegender ? ) { const gender = forcegender ? forcegender : this . body . Gender ( ) ; if ( gender === Gender . male ) { return "he" ; } else if ( gender === Gender . female ) { return "she" ; } else if ( gender === Gender . herm ) { return "she" ; } else { return "they" ; } } public HeShe ( forcegender ? ) { const gender = forcegender ? forcegender : this . body . Gender ( ) ; if ( gender === Gender . male ) { return "He" ; } else if ( gender === Gender . female ) { return "She" ; } else if ( gender === Gender . herm ) { return "She" ; } else { return "They" ; } } public himher ( forcegender ? ) { const gender = forcegender ? forcegender : this . body . Gender ( ) ; if ( gender === Gender . male ) { return "him" ; } else if ( gender === Gender . female ) { return "her" ; } else if ( gender === Gender . herm ) { return "her" ; } else { return "them" ; } } public HimHer ( forcegender ? ) { const gender = forcegender ? forcegender : this . body . Gender ( ) ; if ( gender === Gender . male ) { return "Him" ; } else if ( gender === Gender . female ) { return "Her" ; } else if ( gender === Gender . herm ) { return "Her" ; } else { return "Them" ; } } public hisher ( forcegender ? ) { const gender = forcegender ? forcegender : this . body . Gender ( ) ; if ( gender === Gender . male ) { return "his" ; } else if ( gender === Gender . female ) { return "her" ; } else if ( gender === Gender . herm ) { return "her" ; } else { return "their" ; } } public HisHer ( forcegender ? ) { const gender = forcegender ? forcegender : this . body . Gender ( ) ; if ( gender === Gender . male ) { return "His" ; } else if ( gender === Gender . female ) { return "Her" ; } else if ( gender === Gender . herm ) { return "Her" ; } else { return "Their" ; } } public hishers ( forcegender ? ) { const gender = forcegender ? forcegender : this . body . Gender ( ) ; if ( gender === Gender . male ) { return "his" ; } else if ( gender === Gender . female ) { return "hers" ; } else if ( gender === Gender . herm ) { return "hers" ; } else { return "theirs" ; } } public has ( ) { if ( this . body . Gender ( ) === Gender . none ) { return "have" ; } return "has" ; } public is ( ) { if ( this . body . Gender ( ) === Gender . none ) { return "are" ; } return "is" ; } public plural ( ) { return ( this . body . Gender ( ) === Gender . none ) ; } public mfFem ( male , female ) { return this . body . femininity . Get ( ) > 0 ? female : male ; } public mfTrue ( male , female ) { return ( this . body . Gender ( ) === Gender . male ) ? male : female ; } public ParserPronouns ( parse ? , prefix ? , postfix ? , forcegender ? ) { parse = parse || { } ; prefix = prefix || "" ; postfix = postfix || "" ; parse [ prefix + "HeShe" + postfix ] = this . HeShe ( forcegender ) ; parse [ prefix + "heshe" + postfix ] = this . heshe ( forcegender ) ; parse [ prefix + "HisHer" + postfix ] = this . HisHer ( forcegender ) ; parse [ prefix + "hisher" + postfix ] = this . hisher ( forcegender ) ; parse [ prefix + "HimHer" + postfix ] = this . HimHer ( forcegender ) ; parse [ prefix + "himher" + postfix ] = this . himher ( forcegender ) ; parse [ prefix + "hishers" + postfix ] = this . hishers ( forcegender ) ; return parse ; } public ParserTags ( parse = { } , prefix = "" , p1cock ? ) { const ent = this ; p1cock = p1cock || ent . BiggestCock ( undefined , true ) ; parse [ prefix + "cocks" ] = ( ) => ent . MultiCockDesc ( ) ; parse [ prefix + "cock" ] = ( ) => p1cock . Short ( ) ; parse [ prefix + "cockTip" ] = ( ) => p1cock . TipShort ( ) ; parse [ prefix + "knot" ] = ( ) => p1cock . KnotShort ( ) ; parse [ prefix + "balls" ] = ( ) => ent . BallsDesc ( ) ; parse [ prefix + "butt" ] = ( ) => ent . Butt ( ) . Short ( ) ; parse [ prefix + "anus" ] = ( ) => ent . Butt ( ) . AnalShort ( ) ; parse [ prefix + "vag" ] = ( ) => ent . FirstVag ( ) ? ent . FirstVag ( ) . Short ( ) : "crotch" ; parse [ prefix + "clit" ] = ( ) => ent . FirstVag ( ) . ClitShort ( ) ; parse [ prefix + "breasts" ] = ( ) => ent . FirstBreastRow ( ) . Short ( ) ; parse [ prefix + "nip" ] = ( ) => ent . FirstBreastRow ( ) . NipShort ( ) ; parse [ prefix + "nips" ] = ( ) => ent . FirstBreastRow ( ) . NipsShort ( ) ; parse [ prefix + "tongue" ] = ( ) => ent . TongueDesc ( ) ; parse [ prefix + "tongueTip" ] = ( ) => ent . TongueTipDesc ( ) ; parse [ prefix + "skin" ] = ( ) => ent . SkinDesc ( ) ; parse [ prefix + "hair" ] = ( ) => ent . Hair ( ) . Short ( ) ; parse [ prefix + "face" ] = ( ) => ent . FaceDesc ( ) ; parse [ prefix + "ear" ] = ( ) => ent . EarDesc ( ) ; parse [ prefix + "ears" ] = ( ) => ent . EarDesc ( true ) ; parse [ prefix + "eye" ] = ( ) => ent . EyeDesc ( ) ; parse [ prefix + "eyes" ] = ( ) => ent . EyeDesc ( ) + "s" ; parse [ prefix + "hand" ] = ( ) => ent . HandDesc ( ) ; parse [ prefix + "palm" ] = ( ) => ent . PalmDesc ( ) ; parse [ prefix + "hip" ] = ( ) => ent . HipDesc ( ) ; parse [ prefix + "hips" ] = ( ) => ent . HipsDesc ( ) ; parse [ prefix + "thigh" ] = ( ) => ent . ThighDesc ( ) ; parse [ prefix + "thighs" ] = ( ) => ent . ThighsDesc ( ) ; parse [ prefix + "legs" ] = ( ) => ent . LegsDesc ( ) ; parse [ prefix + "leg" ] = ( ) => ent . LegDesc ( ) ; parse [ prefix + "knee" ] = ( ) => ent . KneeDesc ( ) ; parse [ prefix + "knees" ] = ( ) => ent . KneesDesc ( ) ; parse [ prefix + "foot" ] = ( ) => ent . FootDesc ( ) ; parse [ prefix + "feet" ] = ( ) => ent . FeetDesc ( ) ; parse [ prefix + "belly" ] = ( ) => ent . StomachDesc ( ) ; parse [ prefix + "tail" ] = ( ) => { const tail = ent . HasTail ( ) ; return tail ? tail . Short ( ) : "" ; } ; parse [ prefix + "wings" ] = ( ) => { const wings = ent . HasWings ( ) ; return wings ? wings . Short ( ) : "" ; } ; parse [ prefix + "horns" ] = ( ) => { const horns = ent . HasHorns ( ) ; return horns ? horns . Short ( ) : "" ; } ; parse [ prefix + "weapon" ] = ( ) => ent . WeaponDesc ( ) ; parse [ prefix + "armor" ] = ( ) => ent . ArmorDesc ( ) ; parse [ prefix + "botarmor" ] = ( ) => ent . LowerArmorDesc ( ) ; return parse ; } public toString ( ) { return this . name ; } public Appearance ( ) { return this . NameDesc ( ) + " is a " + this . body . GenderStr ( ) + " " + this . body . RaceStr ( ) + "." ; } public Genitalia ( ) { return this . body . gen ; } public VagCap ( ) { return this . FirstVag ( ) . Capacity ( ) ; } public OralCap ( ) { return this . Mouth ( ) . capacity . Get ( ) ; } public AnalCap ( ) { return this . Butt ( ) . Capacity ( ) ; } public ResetVirgin ( ) { this . Butt ( ) . virgin = true ; const vags = this . AllVags ( ) ; for ( const vag of vags ) { vag . virgin = true ; } } public SetPreferredCock ( cock ) { this . prefCock = cock ; } public GetPreferredCock ( ) { return this . prefCock ; } public NumCocks ( ) { return this . body . cock . length ; } public FirstCock ( ) { return this . body . cock [ 0 ] ; } public FirstClitCockIdx ( ) { for ( let i = 0 , j = this . body . cock . length ; i < j ; i ++ ) { const c = this . body . cock [ i ] ; if ( c . vag ) { return i ; } } return - 1 ; } public BiggestCock ( cocks ? , incStrapon ? ) { cocks = cocks || this . body . cock ; let c = cocks [ 0 ] ; if ( c ) { let cSize = cocks [ 0 ] . length . Get ( ) * cocks [ 0 ] . thickness . Get ( ) ; for ( let i = 1 , j = cocks . length ; i < j ; i ++ ) { const newSize = cocks [ i ] . length . Get ( ) * cocks [ i ] . thickness . Get ( ) ; if ( newSize > cSize ) { cSize = newSize ; c = cocks [ i ] ; } } } if ( c ) { return c ; } else if ( incStrapon && this . strapOn ) { return this . strapOn . cock ; } } public CocksThatFit ( orifice ? , onlyRealCocks ? , extension ? ) { const ret = [ ] ; for ( let i = 0 , j = this . body . cock . length ; i < j ; i ++ ) { const c = this . body . cock [ i ] ; if ( ! orifice || orifice . Fits ( c , extension ) ) { ret . push ( c ) ; } } if ( ret . length === 0 && ! onlyRealCocks && this . strapOn ) { const c = this . strapOn . cock ; if ( ! orifice || orifice . Fits ( c , extension ) ) { ret . push ( c ) ; } } return ret ; } public AllCocksCopy ( ) { const ret = [ ] ; for ( let i = 0 , j = this . body . cock . length ; i < j ; i ++ ) { const c = this . body . cock [ i ] ; ret . push ( c ) ; } return ret ; } public AllCocks ( ) { return this . body . cock ; } public MultiCockDesc ( cocks ? ) { cocks = cocks || this . body . cock ; if ( cocks . length === 0 ) { if ( this . strapOn ) { return this . strapOn . cock . Short ( ) ; } else { return "[NO COCKS]" ; } } else if ( cocks . length === 1 ) { return cocks [ 0 ] . Short ( ) ; } else { return Text . Quantify ( cocks . length ) + " of " + cocks [ 0 ] . Desc ( ) . adj + " " + cocks [ 0 ] . nounPlural ( ) ; } } public NumVags ( ) { return this . body . vagina . length ; } public FirstVag ( ) { return this . body . vagina [ 0 ] ; } public VagsThatFit ( capacity ) { const ret = [ ] ; for ( const vag of this . body . vagina ) { const size = vag . capacity . Get ( ) ; if ( size >= capacity ) { ret . push ( vag ) ; } } return ret ; } public AllVags ( ) { return this . body . vagina ; } public UnfertilezedWomb ( ) { const ret = [ ] ; for ( let i = 0 , j = this . body . vagina . length ; i < j ; i ++ ) { const womb = this . body . vagina [ i ] . womb ; if ( womb . pregnant === false ) { ret . push ( womb ) ; } } return ret ; } public HasBreastsBiggerThan ( threshold ) { return this . body . breasts [ 0 ] . Size ( ) >= threshold ; } public NumBreastRows ( ) { return this . body . breasts . length ; } public FirstBreastRow ( ) { return this . body . breasts [ 0 ] ; } public AllBreastRows ( ) { return this . body . breasts ; } public BiggestBreasts ( ) { const breasts = this . body . breasts ; let c = breasts [ 0 ] ; let cSize = breasts [ 0 ] . Size ( ) ; for ( let i = 1 , j = breasts . length ; i < j ; i ++ ) { const newSize = breasts [ i ] . Size ( ) ; if ( newSize > cSize ) { cSize = newSize ; c = breasts [ i ] ; } } return c ; } public SmallestBreasts ( ) { const breasts = this . body . breasts ; let c = breasts [ 0 ] ; let cSize = breasts [ 0 ] . Size ( ) ; for ( let i = 1 , j = breasts . length ; i < j ; i ++ ) { const newSize = breasts [ i ] . Size ( ) ; if ( newSize < cSize ) { cSize = newSize ; c = breasts [ i ] ; } } return c ; } public BiggestNips ( ) { const breasts = this . body . breasts ; let c = breasts [ 0 ] ; let cSize = breasts [ 0 ] . NipSize ( ) ; for ( let i = 1 , j = breasts . length ; i < j ; i ++ ) { const newSize = breasts [ i ] . NipSize ( ) ; if ( newSize > cSize ) { cSize = newSize ; c = breasts [ i ] ; } } return c ; } public SmallestNips ( ) { const breasts = this . body . breasts ; let c = breasts [ 0 ] ; let cSize = breasts [ 0 ] . NipSize ( ) ; for ( let i = 1 , j = breasts . length ; i < j ; i ++ ) { const newSize = breasts [ i ] . NipSize ( ) ; if ( newSize < cSize ) { cSize = newSize ; c = breasts [ i ] ; } } return c ; } public NipplesThatFitLen ( capacity ) { const ret = new Array ( ) ; for ( let i = 0 , j = this . body . breasts . length ; i < j ; i ++ ) { const row = this . body . breasts [ i ] ; if ( row . nippleType === NippleType . lipple || row . nippleType === NippleType . cunt ) { if ( row . NipSize ( ) >= capacity ) { ret . push ( row ) ; } } } return ret ; } public AllOrfices ( capacity ? ) { capacity = capacity || 0 ; const ret = new Array ( ) ; const vags = this . VagsThatFit ( capacity ) ; for ( let i = 0 , j = vags . length ; i < j ; i ++ ) { ret . push ( { type : BodyPartType . vagina , obj : vags [ i ] } ) ; } const nips = this . NipplesThatFitLen ( capacity ) ; for ( let i = 0 , j = nips . length ; i < j ; i ++ ) { ret . push ( { type : BodyPartType . nipple , obj : nips [ i ] } ) ; } if ( this . body . ass . capacity . Get ( ) >= capacity ) { ret . push ( { type : BodyPartType . ass , obj : this . body . ass } ) ; } if ( this . body . head . mouth . capacity . Get ( ) >= capacity ) { ret . push ( { type : BodyPartType . mouth , obj : this . body . head . mouth } ) ; } return ret ; } public AllPenetrators ( orifice ) { const ret = new Array ( ) ; const cocks = this . CocksThatFit ( orifice ) ; for ( let i = 0 , j = cocks . length ; i < j ; i ++ ) { ret . push ( { type : BodyPartType . cock , obj : cocks [ i ] } ) ; } return ret ; } public Fuck ( cock , expMult ? ) { expMult = expMult || 1 ; this . AddSexExp ( expMult ) ; } public FuckOral ( mouth , cock , expMult ? ) { expMult = expMult || 1 ; this . AddSexExp ( expMult ) ; } public FuckAnal ( butt , cock ? , expMult ? ) { const parse = { name : this . NameDesc ( ) , has : this . has ( ) , hisher : this . hisher ( ) , } ; expMult = expMult || 1 ; if ( butt . virgin ) { butt . virgin = false ; Text . Add ( "<b>[name] [has] lost [hisher] anal virginity.</b>" , parse ) ; Text . NL ( ) ; this . AddSexExp ( 5 * expMult ) ; } else { this . AddSexExp ( expMult ) ; } if ( cock ) { butt . StretchOrifice ( this , cock , false ) ; } Text . Flush ( ) ; } public FuckVag ( vag , cock ? , expMult ? ) { const parse = { name : this . NameDesc ( ) , has : this . has ( ) , hisher : this . hisher ( ) , } ; expMult = expMult || 1 ; if ( vag . virgin ) { vag . virgin = false ; Text . Add ( "<b>[name] [has] lost [hisher] virginity.</b>" , parse ) ; Text . NL ( ) ; this . AddSexExp ( 5 * expMult ) ; } else { this . AddSexExp ( expMult ) ; } if ( cock ) { vag . StretchOrifice ( this , cock , false ) ; } Text . Flush ( ) ; } public Sexed ( ) { if ( this . flags . Sexed && this . flags . Sexed !== 0 ) { return true ; } _ . forIn ( this . sex , ( value ) => { if ( value !== 0 ) { return true ; } } ) ; return false ; } public RestoreCum ( quantity ? ) { quantity = quantity || 1 ; const balls = this . Balls ( ) ; return balls . cum . IncreaseStat ( balls . CumCap ( ) , quantity ) ; } public Cum ( ) { return this . Balls ( ) . cum . Get ( ) ; } public CumOutput ( mult ? ) { mult = mult || 1 ; const balls = this . Balls ( ) ; let cum = mult * balls . CumCap ( ) / 4 ; cum *= this . LustLevel ( ) + 0.5 ; cum = Math . min ( cum , this . Cum ( ) ) ; return cum ; } public OrgasmCum ( mult ? ) { mult = mult || 1 ; const balls = this . Balls ( ) ; const cumQ = this . CumOutput ( mult ) ; this . AddLustFraction ( - 1 ) ; balls . cum . DecreaseStat ( 0 , cumQ ) ; if ( GetDEBUG ( ) ) { Text . NL ( ) ; Text . Add ( "<b>[name] came ([cum]).</b>" , { name : this . NameDesc ( ) , cum : cumQ . toFixed ( 2 ) } ) ; Text . NL ( ) ; Text . Flush ( ) ; } return cumQ ; } public Lactation ( ) { return this . lactHandler . Lactation ( ) ; } public Milk ( ) { return this . lactHandler . milk . Get ( ) ; } public MilkCap ( ) { return this . lactHandler . MilkCap ( ) ; } public LactationProgress ( oldMilk , newMilk , lactationRate ) { } }