bondage-college-mirr/BondageClub/Scripts/Typedef.d.ts
BondageProjects 31123d58e3 Merge branch 'feature/message-replies' into 'master'
Added the ability to reply to whispers, actions and chat messages

See merge request 
2025-03-28 01:14:28 +00:00

4702 lines
162 KiB
TypeScript

//#region Common
declare namespace SocketIO {
type Socket = import("socket.io-client").Socket<ServerToClientEvents, ClientToServerEvents>
}
declare function io(serv: string): SocketIO.Socket;
type ClientEvent = import("@socket.io/component-emitter").EventNames<ClientToServerEvents>;
type ClientEventParams<Ev extends ClientEvent> = import("@socket.io/component-emitter").EventParams<ClientToServerEvents, Ev>;
type _SendRateLimitQueueItem<T extends ClientEvent> = T extends ClientEvent ? { Message: T, args: ClientEventParams<T>} : never;
type SendRateLimitQueueItem = _SendRateLimitQueueItem<ClientEvent>;
interface String {
replaceAt(index: number, character: string): string;
}
declare function parseInt(s: string | number, radix?: number): number;
type MemoizedFunction<T extends Function> = T & {
/** Clears the cache of the memoized function */
clearCache(): void;
};
// GL shim
interface WebGLTextureData {
width: number,
height: number,
texture: WebGLTexture,
}
interface WebGL2RenderingContext {
program?: WebGLProgram;
programFull?: WebGLProgram;
programHalf?: WebGLProgram;
programTexMask?: WebGLProgram;
textureCache?: Map<string, WebGLTextureData>;
maskCache?: Map<string, WebGLTexture>;
}
interface WebGLProgram {
u_alpha?: WebGLUniformLocation;
u_color?: WebGLUniformLocation;
a_position?: number;
a_texcoord?: number;
u_matrix?: WebGLUniformLocation;
u_texture?: WebGLUniformLocation;
u_alpha_texture?: WebGLUniformLocation;
position_buffer?: WebGLBuffer;
texcoord_buffer?: WebGLBuffer;
}
interface HTMLCanvasElement {
GL?: WebGL2RenderingContext;
}
interface HTMLImageElement {
errorcount?: number;
}
interface HTMLElement {
setAttribute(qualifiedName: string, value: any): void;
removeAttribute(qualifiedName: string): void;
}
interface GamepadButton {
/** Whether the button was pressed the last input event */
repeat: boolean;
}
interface RGBColor {
r: number;
g: number;
b: number;
}
interface RGBAColor extends RGBColor {
a: number;
}
/**
* A singleton for explicitly signifying to {@link ElementCreate} that it should have no parent element.
*
* Can be used for overriding any function that would otherwise default to {@link document.body} when a nullish value is provided as parent.
*/
type ElementNoParent = 0;
/**
* A {@link HTMLElementTagNameMap} subtype with all non-scalar properties removed from the HTML elements
*
* Serves as an approximation (and superset) of all element-specific attributes
*/
type HTMLElementScalarTagNameMap = {
[k1 in keyof HTMLElementTagNameMap]: {
[k2 in keyof HTMLElementTagNameMap[k1] as Required<HTMLElementTagNameMap[k1][k2]> extends (boolean | number | string | null) ? k2 : never]:
HTMLElementTagNameMap[k1][k2]
}
};
type HTMLOptions<T extends keyof HTMLElementTagNameMap> = {
/** The elements HTML tag */
tag: T,
/**
* Scalar-valued attributes that will be set on the HTML element.
*
* Note that booleans are interpretted as [boolean attributes](https://developer.mozilla.org/en-US/docs/Glossary/Boolean/HTML).
*/
attributes?: Partial<Record<string, number | boolean | string>>;
/**
* Data attributes that will be set on the HTML element (see {@link HTMLElement.dataset}).
*
* Note that booleans are interpretted as [boolean attributes](https://developer.mozilla.org/en-US/docs/Glossary/Boolean/HTML).
*/
dataAttributes?: Partial<Record<string, number | string | boolean>>;
/** CSS style declarations that will be set on the HTML element (see {@link HTMLElement.style}). */
style?: Record<string, string>;
/** Event listeners that will be attached to the HTML element (see {@link HTMLElement.addEventListener}). */
eventListeners?: { [k in keyof HTMLElementEventMap]?: (this: HTMLElementTagNameMap[T], event: HTMLElementEventMap[k]) => any };
/** The elements parent (if any) to which it will be attached (see {@link HTMLElement.parentElement}). */
parent?: ElementNoParent | Node;
/** A list of CSS classes to-be assigned to the element (see {@link HTMLElement.classList}). */
classList?: readonly (null | undefined | string)[];
/** Any to-be added child elements. */
children?: readonly (null | undefined | string | Node | HTMLOptions<keyof HTMLElementTagNameMap>)[];
/** The {@link HTMLElement.innerHTML} of the element; will be assigned before appending children */
innerHTML?: string;
};
interface HTMLElementEventMap {
/** Custom event fired by {@link ElementButton.Create} buttons whenever a click-event encounters `aria-disabled: "true"`. */
bcClickDisabled: MouseEvent;
}
declare namespace ElementButton {
/** An input type for representing one or more text nodes and/or **non-interactive** DOM elements (_e.g._ `<i>` or `<code>`) */
type StaticNode = null | string | Node | HTMLOptions<any> | readonly (null | undefined | string | Node | HTMLOptions<any>)[];
/** Input options for creating custom button icons */
interface CustomIcon {
/** The {@link HTMLImageElement.src} of the icon */
iconSrc: string,
/** The internal ID of the icon */
name: string,
/** The tooltip component associated with the icon */
tooltipText?: StaticNode,
}
/** Various options that can be passed along to {@link ElementButton.Create} */
interface Options {
/** Optional tooltip content. If not supplied then one should manually prepend it to the tooltip later */
tooltip?: StaticNode;
/** The position of the tooltip w.r.t. the button */
tooltipPosition?: "left" | "right" | "top" | "bottom";
/**
* The aria accessibility role of the the tooltip; defaults to `description` if a {@link ElementButton.Options.label} is present and `label` otherwise:
* * `label` ([`aria-labelledby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby)): A compact, 1-line summary of the button
* * `description` ([`aria-describedby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-describedby)): A longer, potentially multi-line, button description
* * `none`: Nothing
*/
tooltipRole?: "label" | "description" | "none";
/** A button label */
label?: StaticNode;
/** The position of the button label */
labelPosition?: "top" | "center" | "bottom";
/** A background image for the button */
image?: string;
/**
* Button icons to-be displayed in the top-left corner of the button.
*
* Alternatively, one can directly pass the icon's {@link HTMLImageElement.src} and its tooltip component.
*/
icons?: readonly (null | undefined | InventoryIcon | CustomIcon)[];
/** The role of the button. All accepted values are currently special-cased in order to set role-specific event listeners and/or attributes. */
role?: "radio" | "checkbox" | "menuitemradio" | "menuitemcheckbox";
/** Whether to limit the default styling of the button's border and background */
noStyling?: boolean;
/** Whether the button should be disabled or not */
disabled?: boolean;
/** A click event listener to-be fired when a button is disabled via `aria-disabled: "true"`. */
clickDisabled?: (this: HTMLButtonElement, event: MouseEvent) => any;
}
}
declare namespace ElementCheckbox {
/** Various options that can be passed along to {@link ElementCheckbox.Create} */
interface Options {
/** Whether the checkbox is checked by default or not */
checked?: boolean;
/** Whether the checkbox should be disabled or not */
disabled?: boolean;
/**
* The {@link HTMLInputElement.value}/{@link HTMLInputElement.valueAsNumber} associated with the checkbox when checked.
*
* Defaults to `"on"` if not specified.
*/
value?: string | number;
}
}
type Rect = { x: number, y: number, w: number, h: number };
/** A 4-tuple with X & Y coordinates, width and height */
type RectTuple = [X: number, Y: number, W: number, H: number];
/** A 4-tuple with X & Y coordinates and, optionally, width and height */
type PartialRectTuple = [X: number, Y: number, W?: number, H?: number];
type CommonSubstituteReplacer = (match: string, offset: number, replacement: string, string: string) => string;
type CommonSubtituteSubstitution = [tag: string, substitution: string, replacer?: CommonSubstituteReplacer];
interface CommonGenerateGridParameters {
/** Starting X coordinate of the grid */
x: number,
/** Starting Y coordinate of the grid */
y: number,
/** Maximum width of the grid */
width: number,
/** Maximum height of the grid */
height: number,
/** Width of one grid item */
itemWidth: number,
/** Height of one grid item */
itemHeight: number,
/**
* Margin of one grid item in the X direction.
* Not giving a value will calculate a margin from the item's size and the grid size
*/
itemMarginX?: number;
/**
* Margin of one grid item in the Y direction
* Not giving a value will calculate a margin from the item's size and the grid size
*/
itemMarginY?: number;
/**
* The direction the items are layed out
* @default "horizontal"
*/
direction?: "horizontal" | "vertical";
minMarginX?: number;
minMarginY?: number;
}
type CommonGenerateGridCallback<T> = (item: T, x: number, y: number, width: number, height: number) => boolean;
/**
* An object for holding arbitrary values with a mechanism to reset them to a default
*/
type VariableContainer<T1, T2> = T1 & T2 & {
/** Default values that should be restored to the container upon calling {@link Reset} */
readonly Defaults: Readonly<T1>,
/** Restore the container to its default state */
readonly Reset: () => void,
}
//#endregion
//#region Enums
type ChatRoomSpaceLabel = "MIXED" | "FEMALE_ONLY" | "MALE_ONLY" | "ASYLUM";
type ChatRoomVisibilityModeLabel = "PUBLIC" | "ADMIN_WHITELIST" | "ADMIN" | "UNLISTED";
type ChatRoomAccessModeLabel = "PUBLIC" | "ADMIN_WHITELIST" | "ADMIN";
type DialogMenuMode = (
"activities"
| "colorDefault"
| "colorExpression"
| "colorItem"
| "crafted"
| "dialog"
| "extended"
| "items"
| "layering"
| "locking"
| "locked"
| "permissions"
| "struggle"
| "tighten"
);
type DialogMenuButton = "Activity" |
"ColorCancel" | "ColorChange" | "ColorChangeMulti" | "ColorDefault" | "ColorPickDisabled" | "ColorSelect" |
"Crafting" |
"NormalMode" | "PermissionMode" |
"Dismount" | "Escape" | "Remove" |
"Exit" |
"GGTSControl" |
"InspectLock" | "InspectLockDisabled" |
"Layering" |
"Lock" | "LockDisabled" | "LockMenu" |
"Swap" | "Next" | "Prev" | `PickLock${PickLockAvailability}` |
"Remote" | "RemoteDisabled" | `RemoteDisabledFor${VibratorRemoteAvailability}` |
"Unlock" | "Use" | "UseDisabled" | "Struggle" | "TightenLoosen" |
// Wardrobe buttons
"Wardrobe" | "WardrobeDisabled" | "Reset" | "WearRandom" | "Random" | "Copy" | "Paste" | "Naked" | "Accept" | "Cancel" | "Character"
;
declare namespace DialogMenu {
/** Customization options for {@link DialogMenu.Reload} */
interface ReloadOptions {
/** Whether to hard reset and reconstruct the button grid, rather than just re-evaluating the existing button's states via a soft reset. */
reset?: boolean;
/** The to-be assigned custom status message */
status?: string;
/** Display the {@link ReloadOptions.status} message on a timer; units are in ms */
statusTimer?: number;
/**
* Reset the position of the scroll bar to the checked button, or, if unavailable, the top of the button grid.
*
* Defaults to `true` if {@link ReloadOptions.reset} is specified.
*/
resetScrollbar?: boolean;
/**
* Whether to regenerate the subscreen's underlying item or activity list (see {@link DialogBuildActivities} and {@link DialogInventoryBuild}).
*
* Defaults to `true` if {@link ReloadOptions.reset} is specified.
*/
resetDialogItems?: boolean;
}
/** Internal {@link DialogMenu.Reload} parameters for dialog subscreens without a focus group */
interface ReloadParam<T extends InitProperties> {
root: HTMLElement;
newProperties: T;
oldProperties: T;
textCache: TextCache;
}
/**
* All valid init properties that a {@link DialogMenu} subclass may choose to implement.
*
* Init properties represent a set of {@link DialogMenu.Init}-initialized properties which are exclusively active during the matching screen's lifetime.
*/
interface InitProperties {
C: Character;
focusGroup?: AssetGroup;
}
}
type DialogSortOrder = | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
type DialogStruggleActionType = "ActionUse" | "ActionSwap" | "ActionRemove" | "ActionUnlock" | "ActionUnlockAndRemove" | "ActionStruggle" | "ActionEscape" | "ActionDismount";
type CharacterType = "player" | "online" | "npc" | "simple";
type CharacterPronouns = "SheHer" | "HeHim";
type VibratorIntensity = -1 | 0 | 1 | 2 | 3;
type VibratorModeState = "Default" | "Deny" | "Orgasm" | "Rest";
type VibratorMode = "Off" | "Low" | "Medium" | "High" | "Maximum" | "Random" | "Escalate" | "Tease" | "Deny" | "Edge";
type VibratorRemoteAvailability = "Available" | "NoRemote" | "NoRemoteOwnerRuleActive" | "NoLoversRemote" | "RemotesBlocked" | "CannotInteract" | "NoAccess" | "InvalidItem";
type PickLockAvailability = "" | "Disabled" | "PermissionsDisabled" | "InaccessibleDisabled" | "NoPicksDisabled";
type ItemVulvaFuturisticVibratorAccessMode = "" | "ProhibitSelf" | "LockMember";
type SpeechTransformName = "gagGarble" | "stutter" | "babyTalk" | "deafen";
/** The {@link EffectName} values for all gag-related effects. */
type GagEffectName = (
"GagVeryLight"
| "GagEasy"
| "GagLight"
| "GagNormal"
| "GagMedium"
| "GagHeavy"
| "GagVeryHeavy"
| "GagTotal"
// Those are only supposed to be "transient", as in, they appear because of stacked gags
| "GagTotal2"
| "GagTotal3"
| "GagTotal4"
);
/** The {@link EffectName} values for all blindness-related effects. */
type BlindEffectName = "BlindLight" | "BlindNormal" | "BlindHeavy" | "BlindTotal";
/** The {@link EffectName} values for all blurring-related effects. */
type BlurEffectName = "BlurLight" | "BlurNormal" | "BlurHeavy" | "BlurTotal";
/** The {@link EffectName} values for all deafness-related effects. */
type DeafEffectName = "DeafLight" | "DeafNormal" | "DeafHeavy" | "DeafTotal";
/** All known effects */
type EffectName =
GagEffectName | BlindEffectName | BlurEffectName | DeafEffectName |
"Freeze" | "BlockWardrobe" | "Block" | "Mounted" |
"CuffedFeet" | "CuffedLegs" | "CuffedArms" | "IsChained" | "FixedHead" | "MergedFingers" |
"Shackled" | "Tethered" | "MapImmobile" | "Enclose" | "OneWayEnclose" | "OnBed" | "Lifted" | "Suspended" |
"Slow" | "FillVulva" | "VulvaShaft" | "IsPlugged" |
"Egged" | "Vibrating" | "ForcedErection" |
"Edged" | "DenialMode" | "RuinOrgasms" |
"Remote" | "UseRemote" | "BlockRemotes" |
"Lock" | "NotSelfPickable" |
"Chaste" | "BreastChaste" | "ButtChaste" |
"Leash" | "IsLeashed" | "CrotchRope" |
"ReceiveShock" | "TriggerShock" |
"OpenPermission" | "OpenPermissionArm" | "OpenPermissionLeg" | "OpenPermissionChastity" |
"BlockMouth" | "OpenMouth" |
"VR" | "VRAvatars" | "KinkyDungeonParty" |
"RegressedTalk" |
"HideRestraints" |
"UnlockMetalPadlock" | "UnlockOwnerPadlock" | "UnlockOwnerTimerPadlock" |
"UnlockLoversPadlock" | "UnlockLoversTimerPadlock" |
"UnlockFamilyPadlock" | "UnlockMistressPadlock" | "UnlockMistressTimerPadlock" |
"UnlockPandoraPadlock" | "UnlockMetalCuffs" | "UnlockEscortAnkleCuffs" | "UnlockPortalPanties" |
"ProtrudingMouth" | "Wiggling" | "CanEdge"
;
interface ExpressionNameMap {
Eyebrows: null | "Raised" | "Lowered" | "OneRaised" | "Harsh" | "Angry" | "Soft",
Eyes: (
null | "Closed" | "Dazed" | "Shy" | "Sad" | "Horny" | "Lewd" | "VeryLewd" |
"Heart" | "HeartPink" | "LewdHeart" | "LewdHeartPink" | "Dizzy" | "Daydream" |
"ShylyHappy" | "Angry" | "Surprised" | "Scared"
),
Eyes2: ExpressionNameMap["Eyes"],
Mouth: (
null | "Frown" | "Sad" | "Pained" | "Angry" | "HalfOpen" | "Open" | "Ahegao" | "Moan" |
"TonguePinch" | "LipBite" | "Happy" | "Devious" | "Laughing" | "Grin" | "Smirk" | "Pout"
),
Pussy: null | "Hard",
Blush: null | "Low" | "Medium" | "High" | "VeryHigh" | "Extreme" | "ShortBreath",
Fluids: (
null | "DroolLow" | "DroolMedium" | "DroolHigh" | "DroolSides" | "DroolMessy" | "DroolTearsLow" |
"DroolTearsMedium" | "DroolTearsHigh" | "DroolTearsMessy" | "DroolTearsSides" |
"TearsHigh" | "TearsMedium" | "TearsLow"
),
Emoticon: (
null | "Afk" | "Whisper" | "Sleep" | "Hearts" | "Tear" | "Hearing" | "Confusion" | "Exclamation" |
"Annoyed" | "Read" | "RaisedHand" | "Spectator" | "ThumbsDown" | "ThumbsUp" | "LoveRope" |
"LoveGag" | "LoveLock" | "Wardrobe" | "Gaming" | "Coffee" | "Fork" | "Music" | "Car" | "Hanger" |
"Call" | "Lightbulb" | "Warning" | "BrokenHeart" | "Drawing" | "Coding" | "TV" | "Bathing"
),
}
type ExpressionGroupName = keyof ExpressionNameMap;
type ExpressionName = ExpressionNameMap[ExpressionGroupName];
type AssetGroupItemName =
'ItemAddon' | 'ItemArms' | 'ItemBoots' | 'ItemBreast' | 'ItemButt' |
'ItemDevices' | 'ItemEars' | 'ItemFeet' | 'ItemHands' | 'ItemHead' |
'ItemHood' | 'ItemLegs' | 'ItemMisc' | 'ItemMouth' | 'ItemMouth2' |
'ItemMouth3' | 'ItemNeck' | 'ItemNeckAccessories' | 'ItemNeckRestraints' |
'ItemNipples' | 'ItemNipplesPiercings' | 'ItemNose' | 'ItemPelvis' |
'ItemTorso' | 'ItemTorso2'| 'ItemVulva' | 'ItemVulvaPiercings' |
'ItemHandheld'
;
type AssetGroupScriptName = 'ItemScript';
type AssetGroupBodyName =
ExpressionGroupName | 'AnkletLeft' | 'AnkletRight' | 'ArmsLeft' | 'ArmsRight' |
'BodyLower' | 'BodyUpper' | 'BodyMarkings' | 'Bra' | 'Bracelet' | 'Cloth' |
'ClothAccessory' | 'ClothLower' | 'Corset' | 'EyeShadow' | 'FacialHair' | 'Garters' | 'Glasses' | 'Gloves' |
'HairAccessory1' | 'HairAccessory2' | 'HairAccessory3' | 'HairBack' |
'HairFront' | 'HandAccessoryLeft' | 'HandAccessoryRight' | 'FacialHair' | 'Hat' | 'Head' | 'Height' | 'Jewelry' | 'Mask' |
'Necklace' | 'Nipples' | 'Panties' | 'Pronouns' |
'Shoes' | 'Socks' | 'SocksLeft' | 'SocksRight' | 'Suit' | 'SuitLower' | 'TailStraps' | 'Wings' |
'HandsLeft' | 'HandsRight' | 'FaceMarkings'
;
type AssetGroupName = AssetGroupBodyName | AssetGroupItemName | AssetGroupScriptName;
interface AssetPoseMap {
BodyHands: 'TapedHands',
BodyUpper: 'BaseUpper' | 'BackBoxTie' | 'BackCuffs' | 'BackElbowTouch' | 'OverTheHead' | 'Yoked',
BodyLower: 'BaseLower' | 'Kneel' | 'KneelingSpread' | 'LegsClosed' | 'LegsOpen' | 'Spread',
BodyFull: 'Hogtied' | 'AllFours',
BodyAddon: 'Suspension',
}
type AssetPoseCategory = keyof AssetPoseMap;
type AssetPoseName = AssetPoseMap[keyof AssetPoseMap];
/**
* A record mapping pose names to the actually to-be drawn poses.
* Special values can be specified, via use of {@link PoseType}, for either hiding the asset or using pose-agnostic assets.
*/
type AssetPoseMapping = Partial<Record<AssetPoseName, AssetPoseName | PoseType>>;
type PoseType = "Hide" | PoseTypeDefault;
type PoseTypeDefault = "";
type PoseChangeStatus = 0 | 1 | 2 | 3;
type AssetLockType =
"CombinationPadlock" | "ExclusivePadlock" | "HighSecurityPadlock" |
"IntricatePadlock" | "LoversPadlock" | "LoversTimerPadlock" | "FamilyPadlock" |
"MetalPadlock" | "MistressPadlock" | "MistressTimerPadlock" |
"OwnerPadlock" | "OwnerTimerPadlock" | "PandoraPadlock" |
"PasswordPadlock" | "PortalLinkPadlock" | "SafewordPadlock" | "TimerPadlock" |
"TimerPasswordPadlock"
;
type CraftingPropertyType =
"Normal" | "Large" | "Small" | "Thick" | "Thin" | "Secure" | "Loose" | "Decoy" |
"Malleable" | "Rigid" | "Simple" | "Puzzling" | "Painful" | "Comfy" | "Strong" |
"Flexible" | "Nimble" | "Arousing" | "Dull" | "Edging" | "Heavy" | "Light"
;
type AssetAttribute =
"Skirt" | "SuitLower" | "UpperLarge" |
"ShortHair" | "SmallEars" | "NoEars" | "NoseRing" | "HoodieFix" |
"CanAttachMittens" |
"IsChestHarness" | "IsHipHarness" |
"PenisLayer" | "PussyLayer" | "GenitaliaCover" | "Pussy1" | "Pussy2" | "Pussy3" |
"CagePlastic2" | "CageTechno" | "CageFlat" |
"FuturisticRecolor" | "FuturisticRecolorDisplay" |
"PortalLinkLockable" | `PortalLinkChastity${string}` | `PortalLinkActivity${ActivityName}` | `PortalLinkTarget${AssetGroupItemName}`
;
type PosePrerequisite = `Can${AssetPoseName}`;
type AssetPrerequisite =
PosePrerequisite | "AccessBreast" | "AccessBreastSuitZip" | "AccessButt" | "AccessFullPenis" | "AccessMouth" | "AccessTorso" | "AccessVulva" | "AccessCrotch" |
"BlockedMouth" | "ButtEmpty" | "CanBeCeilingTethered" | "CanCoverVulva" | "CanHaveErection" | "CanBeLimp" | "CanKneel" | "CannotBeSuited" | "CannotHaveWand" |
"CanAttachMittens" |
"ClitEmpty" | "Collared" | "CuffedArms" | "CuffedArmsOrEmpty" | "CuffedFeet" | "CuffedFeetOrEmpty" | "CuffedLegs" | "CuffedLegsOrEmpty" |
"DisplayFrame" | "EyesEmpty" | "GagCorset" | "GagFlat" | "GagUnique" | "GasMask" | "HasBreasts" | "HasFlatChest" | "HasPenis" | "HasVagina" |
"HoodEmpty" | "NakedFeet" | "NakedHands" | "NeedsChestHarness" | "NeedsHipHarness" | "NeedsNippleRings" |
"NoChastityCage" | "NoErection" | "NoClothLower" | "NoItemArms" |
"NoItemFeet" | "NoItemHands" | "NoItemLegs" | "NoMaidTray" | "NoOuterClothes" | "NotChained" | "NotChaste" | "NotKneeling" |
"NotLifted" | "NotMasked" | "NotMounted" | "NotProtrudingFromMouth" | "NotSuspended" | "OnBed" |
"RemotesAllowed" | "VulvaEmpty"
;
type CraftingStatusType = 0 | 1 | 2;
type ItemColorMode = "Default" | "ColorPicker";
type CharacterHook = "BeforeSortLayers" | "AfterLoadCanvas";
type ChatColorThemeType = "Light" | "Dark" | "Light2" | "Dark2";
type ChatEnterLeaveType = "Normal" | "Smaller" | "Hidden";
type ChatMemberNumbersType = "Always" | "Never" | "OnMouseover";
type ChatFontSizeType = "Small" | "Medium" | "Large";
type ArousalActiveName = "Inactive" | "NoMeter" | "Manual" | "Hybrid" | "Automatic";
type ArousalVisibleName = "All" | "Access" | "Self";
type ArousalAffectStutterName = "None" | "Arousal" | "Vibration" | "All";
/**
* A listener for KeyboardEvents
*
* Cheat-sheet about how to do key checks with it:
* - {@link KeyboardEvent.code} is the layout-insensitive code
* for the key (so KeyA, Space, etc.) Use this if you want to
* keep the QWERTY location, like movement keys.
*
* {@link KeyboardEvent.key} is the layout-dependent string
* for the key (so "a" (or "q" on AZERTY), "A" (or "Q"), " ", etc.)
* Use this if you want the key to correspond to what's actually on
* the user's keyboard.
*
* @see {@link CommonKeyMove}
*/
type KeyboardEventListener = ScreenFunctions["KeyDown"];
type MouseEventListener = ScreenFunctions["MouseDown"];
type SettingsSensDepName = "SensDepLight" | "Normal" | "SensDepNames" | "SensDepTotal" | "SensDepExtreme";
type SettingsVFXName = "VFXInactive" | "VFXSolid" | "VFXAnimatedTemp" | "VFXAnimated";
type SettingsVFXVibratorName = "VFXVibratorInactive" | "VFXVibratorSolid" | "VFXVibratorAnimated";
type SettingsVFXFilterName = "VFXFilterLight" | "VFXFilterMedium" | "VFXFilterHeavy";
type GraphicsFontName =
"Arial" | "TimesNewRoman" | "Papyrus" | "ComicSans" | "Impact" | "HelveticaNeue" | "Verdana" |
"CenturyGothic" | "Georgia" | "CourierNew" | "Copperplate"
;
type PreferenceSubscreenName =
"General" | "Difficulty" | "Restriction" | "Chat" | "CensoredWords" | "Audio" | "Arousal" |
"Security" | "Online" | "Visibility" | "Immersion" | "Graphics" | "Controller" | "Notifications" |
"Gender" | "Scripts" | "Extensions" | "Main"
;
interface PreferenceSubscreen {
name: PreferenceSubscreenName;
description?: string;
icon?: string;
hidden?: boolean;
load?: () => void;
run: () => void;
click: () => void;
exit?: () => boolean;
unload?: () => void;
}
interface PreferenceGenderSetting {
/** Whether the setting is active for female cases */
Female: boolean;
/** Whether the setting is active for male cases */
Male: boolean;
}
type FetishName =
"Bondage" | "Gagged" | "Blindness" | "Deafness" | "Chastity" | "Exhibitionist" | "Masochism" |
"Sadism" | "Rope" | "Latex" | "Leather" | "Metal" | "Tape" | "Nylon" | "Lingerie" | "Pet" |
"Pony" | "ABDL" | "Forniphilia"
;
type BackgroundTag =
"Filter by tag" | "Indoor" | "Outdoor" | "Aquatic" | "Special Events" | "SciFi & Fantasy" |
"Club & College" | "Regular house" | "Dungeon" | "Asylum" | "Pandora"
;
// NOTE: `NPCArchetype` is for NPC's only
type TitleName =
NPCArchetype | "None" | "Mistress" | "Master" | "Mistree" | "ClubSlave" | "Maid" | "HeadMaid" | "BondageMaid" | "Kidnapper" |
"MasterKidnapper" | "Patient" | "PermanentPatient" | "EscapedPatient" | "Nurse" | "Doctor" | "AnimeBoy" |
"LadyLuck" | "LordFortune" | "Patron" | "CollegeStudent" |"Nawashi" | "Houdini" | "PonyAlicorn" |
"PonyPegasus" | "PonyUnicorn" | "PonyWild" | "PonyHot" | "PonyWarm" | "PonyCold" | "PonyFarm" |
"PonyFoal" | "InfilrationMole" | "InfilrationInfiltrator" | "InfilrationAgent" |
"InfilrationOperative" | "InfilrationSuperspy" | "MagicSchoolWizard" | "MagicSchoolMagus" |
"MagicSchoolMagician" | "MagicSchoolSorcerer" | "MagicSchoolSage" | "MagicSchoolOracle" |
"MagicSchoolWitch" | "MagicSchoolWarlock" | "Duchess" | "Duke" | "LittleOne" | "Baby" | "DL" |
"BondageBaby" | "Switch" | "Princess" | "Prince" | "Liege" | "Majesty" | "Missy" | "Sissy" | "Tomboy" | "Femboy" | "GoodOne" |
"Pet" | "Brat" | "Kitten" | "Puppy" | "Foxy" | "Bunny" | "Doll" | "Demon" | "Angel" | "Alien" | "Captain" | "Admiral" |
"Succubus" | "Incubus" | "Concubus" | "GoodGirl" | "GoodBoy" | "GoodSlaveGirl" | "GoodSlaveBoy" | "GoodSlave" | "Drone"
;
type MagicSchoolHouse = "Maiestas" | "Vincula" | "Amplector" | "Corporis";
type ModuleType = keyof ModuleScreens;
interface ModuleScreens {
Character:
| "Appearance"
| "BackgroundSelection"
| "Cheat"
| "Creation"
| "Disclaimer"
| "FriendList"
| "InformationSheet"
| "ItemColor"
| "Login"
| "OnlineProfile"
| "PasswordReset"
| "Player"
| "Preference"
| "Relog"
| "Title"
| "Wardrobe"
;
Cutscene:
| "NPCCollaring"
| "NPCSlaveAuction"
| "NPCWedding"
| "PlayerCollaring"
| "PlayerMistress"
| "SarahIntro"
;
MiniGame:
| "Chess" | "ChestLockpick"
| "ClubCard" | "ClubCardBuilder"
| "DojoStruggle"
| "GetUp"
| "HorseWalk"
| "Kidnap"
| "KinkyDungeon"
| "Lockpick"
| "MagicBattle" | "MagicPuzzle"
| "MaidCleaning" | "MaidDrinks"
| "PlayerAuction"
| "PuppyWalker"
| "RhythmGame"
| "SlaveAuction"
| "Tennis"
| "Therapy"
| "WheelFortune"
;
Online:
| "AdvancedRule"
| "ChatAdmin" | "ChatAdminRoomCustomization" | "ChatBlockItem"
| "ChatRoom" | "ChatSearch" | "ChatSelect"
| "ForbiddenWords"
| "Game" | "GameClubCard" | "GameLARP" | "GameMagicBattle"
| "NicknameManagement"
| "WheelFortuneCustomize"
;
Room:
| "Arcade"
| "AsylumBedroom" | "AsylumEntrance" | "AsylumGGTS" | "AsylumMeeting" | "AsylumTherapy"
| "Cafe" | "Cell" | "ClubCardLounge"
| "CollegeCafeteria" | "CollegeChess" | "CollegeDetention" | "CollegeEntrance" | "CollegeTeacher" | "CollegeTennis" | "CollegeTheater"
| "Crafting" | "DailyJob" | "Empty" | "Gambling"
| "Infiltration" | "InfiltrationPerks"
| "Introduction"
| "KidnapLeague"
| "LARP"
| "Magic" | "MagicSchoolEscape" | "MagicSchoolLaboratory"
| "MaidQuarters" | "MainHall" | "Management" | "MovieStudio" | "Nursery"
| "Pandora" | "PandoraPrison"
| "Photographic"
| "Platform" | "PlatformIntro" | "PlatformDialog" | "PlatformProfile"
| "Poker" | "Prison"
| "Private" | "PrivateBed" | "PrivateRansom"
| "Sarah"
| "Shibari"
| "Shop" | "Shop2"
| "SlaveMarket" | "Stable"
;
}
type RoomName = ModuleScreens[ModuleType];
interface RelogDataBase<T extends ModuleType> {
Screen: ModuleScreens[T],
Module: T,
Character: Character,
ChatRoomName: string | null,
}
type _RelogDataMap<T> = T extends ModuleType ? RelogDataBase<T> : never;
type RelogData = _RelogDataMap<ModuleType>;
type _ScreenSpecifier<T extends ModuleType> = [module: T, screen: ModuleScreens[T]];
type ScreenSpecifier = _ScreenSpecifier<"Character"> | _ScreenSpecifier<"Cutscene"> | _ScreenSpecifier<"MiniGame"> | _ScreenSpecifier<"Online"> | _ScreenSpecifier<"Room">;
type AssetCategory = "Medical" | "Extreme" | "Pony" | "SciFi" | "ABDL" | "Fantasy";
type PortalLinkStatus = "PortalLinkInvalidCode" | "PortalLinkClipboardError" | "PortalLinkValidCode" | `PortalLinkSearching${number}` | "PortalLinkDuplicateCode" | "PortalLinkTargetNotFound" | "PortalLinkEstablished";
type PortalLinkFunction = "PortalLinkFunctionLock" | "PortalLinkFunctionUnlock" | "PortalLinkFunctionCycleChastity" | `PortalLinkFunctionActivity${ActivityName}`;
/** Valid thumb icons for range slider elements */
type ThumbIcon = "lock" | "blindfold" | "lightbulb" | "player" | "rope";
//#endregion
//#region Chat
type ChatRoomLovershipOption = "" | "CanOfferBeginWedding" | "CanBeginWedding";
type ChatRoomOwnershipOption = "" | "CanOfferEndTrial" | "CanOfferTrial" | "CanEndTrial";
type ChatRoom = ServerChatRoomData;
type ChatRoomSettings = ServerChatRoomSettings;
/** ChatRoom results once received by the client */
type ChatRoomSearchResult = (ServerChatRoomSearchData & { DisplayName: string, Order: number });
type StimulationAction = "Kneel" | "Walk" | "Struggle" | "StruggleFail" | "Talk";
interface StimulationEvent {
/** The chance that this event will trigger at 0 arousal */
Chance: number;
/** Scaling factor for chance, depending on the arousal */
ArousalScaling?: number;
/** Scaling factor for chance, depending on the vibe intensity */
VibeScaling?: number;
/** Scaling factor for chance, depending on the inflation amount */
InflationScaling?: number;
/** The chance that this event will trigger when talking */
TalkChance?: number;
}
type StimulationEventType = "CrotchRope" | "Talk" | "Vibe" | "Inflated" | "Wiggling" | "PlugFront" | "PlugBack" | "PlugBoth";
interface StimulationEventItem {
/** The item that caused the stimulation event */
item: Item;
/** The type of stimulation event */
event: StimulationEventType;
/** The chance of the event occurring */
chance: number;
/** Arousal booost from the event */
arousal: number;
}
interface ChatRoomChatLogEntry {
Chat: string;
Garbled: string;
Original: string;
SenderName: string;
SenderMemberNumber: number;
Time: number;
}
interface IChatRoomMessageMetadata {
/** The name of the sender character, appropriately garbled if deafened */
senderName?: string;
/** The character targetted by the message */
TargetCharacter?: Character;
AdditionalTargets?: Record<number, Character>;
/** The character sending the message */
SourceCharacter?: Character;
/** The member number of the target */
TargetMemberNumber?: number;
/** Whether the message is considered game-initiated. Used for automatic vibe changes for example. */
Automatic?: boolean;
/** The group that has been interacted with to trigger the message */
FocusGroup?: AssetItemGroup;
/** The name of the group that has been interacted with to trigger the message */
GroupName?: AssetGroupName;
/** The assets referenced in the message */
Assets?: Record<string, Asset>;
/** The {@link CraftingItem.Name} of the assets referenced in the message (if applicable) */
CraftingNames?: Record<string, string>;
/** The groups referenced in the message */
Groups?: Partial<Record<AssetGroupName, AssetGroup[]>>;
/** How intense the shock should be */
ShockIntensity?: number;
ActivityCounter?: number;
/** The triggered activity */
ActivityName?: ActivityName;
/** The name of the asset used for the activity */
ActivityAsset?: Asset;
/** The name of the chatroom, appropriately garbled */
ChatRoomName?: string;
/** The original, ungarbled message, if provided by the sender */
OriginalMsg?: string;
/** The ID of the message being replied to */
ReplyId?: string;
/** The ID of the message */
MsgId?: string;
}
/**
* A metadata extractor for a given message.
*
* @param data - The chat message to extract from.
* @param sender - The character that sent the message.
* @return An object with the following keys:
* - `metadata`: an object for the extracted metadata (key/value)
* - `substitutions`: an array of [tag, substitutions] to perform on the message.
* @return null if the extraction has nothing to report.
*/
type ChatRoomMessageExtractor =
(data: ServerChatRoomMessage, sender: Character) => { metadata: IChatRoomMessageMetadata, substitutions: CommonSubtituteSubstitution[] } | null;
/**
* A chat message handler.
*
* This is used in ChatRoomMessage to perform filtering and actions on
* the recieved message. You can register one of those with
* ChatRoomRegisterMessageHandler if you need to peek at incoming messages.
*
* Message processing is done in three phases:
* - all pre-handlers are called
* - metadata extraction & tag substitutions are collected
* from the message's dictionary, then latter are applied to
* the message's contents.
* - finally, post-handlers are called.
*
* The handler's priority determines when the handler will get executed:
* - Negative values make the handler run before metadata extraction
* - Positive values make it run afterward.
* In both cases, lower values mean higher priority, so -100 handler will
* run before a -1, and a 1 handler will run before a 100.
*
* The return from the callback determines what will happen: if it's true,
* message processing will stop, making the filter act like a handler.
* If it's false, then it will continue. You can also return an object with
* a `msg` property if the handler is a transformation and wishes to update
* the message's contents inflight and/or a `skip` property if you'd like
* to cause a subsequent handler to not be called.
*
* @warning Note that the in-flight message is only escaped when it gets
* sent to the chat log via ChatRoomMessageDisplay. If you're manipulating
* that by any other means, make sure to call ChatRoomEscapeEntities on its
* content to close any injection attacks.
*
* A few notable priority values are:
*
* -200: ghosted player cutoff
* -1: default Hidden message processing (and cutoff)
* 0: emotes reformatting
* 100: sensory-deprivation processing
* 200: automatic actions on others' cutoff
* 300: sensory-deprivation cutoff.
* 500: usually output handlers. That's when audio, notifications and the
* message being added to the chat happens.
*
* Hidden messages never make it to post-processing.
*
*/
interface ChatRoomMessageHandler {
/** A short description of what the handler does. For debugging purposes */
Description?: string;
/**
* This handler's priority, used to determine when the code should run.
*/
Priority: number;
/**
* Actual action to perform.
* @param data - The chat message to handle.
* @param sender - The character that sent the message.
* @param msg - The formatted string extracted from the message.
* If the handler is in "post" mode, all substitutions have been performed.
* @param metadata - The collected metadata from the message's dictionary, only available in "post" mode.
* @returns {boolean} true if the message was handled and the processing should stop, false otherwise.
*/
Callback: (data: ServerChatRoomMessage, sender: Character, msg: string, metadata?: IChatRoomMessageMetadata) => boolean | { msg?: string; skip?: (handler: ChatRoomMessageHandler) => boolean };
}
//#endregion
//#region FriendList
interface IFriendListBeepLogMessage {
MemberNumber?: number; /* undefined for NPCs */
MemberName: string;
ChatRoomName?: string;
Private: boolean;
ChatRoomSpace?: ServerChatRoomSpace;
Sent: boolean;
Time: Date;
Message?: string;
}
//#endregion
/**
* Make all properties in T mutable.
* Opposite of {@link Readonly}
*/
type Mutable<T> = {
-readonly[P in keyof T]: T[P];
};
//#region Assets
type IAssetFamily = "Female3DCG";
type WardrobeReorderType = "None" | "Select" | "Place";
interface AssetGroup {
readonly Family: IAssetFamily;
readonly Name: AssetGroupName;
readonly Description: string;
readonly Asset: readonly Asset[];
/** @deprecated - superseded by {@link ParentGroup} */
readonly ParentGroupName?: never;
/** An object mapping pose names to group names from which to inherit body sizes. */
readonly ParentGroup: ParentGroup.Data;
readonly Category: 'Appearance' | 'Item' | 'Script';
readonly IsDefault: boolean;
readonly IsRestraint: boolean;
readonly AllowNone: boolean;
readonly AllowColorize: boolean;
readonly AllowCustomize: boolean;
readonly Random?: boolean;
readonly ColorSchema: readonly string[];
/**
* The first color in the groups {@link ColorSchema}.
* The value is used for padding the {@link Asset.DefaultColor} array if required.
*/
readonly DefaultColor: string;
readonly ParentSize: AssetGroupName | "";
readonly ParentColor: AssetGroupName | "";
readonly Clothing: boolean;
readonly Underwear: boolean;
readonly BodyCosplay: boolean;
readonly Hide?: readonly AssetGroupName[];
readonly Block?: readonly AssetGroupItemName[];
readonly Zone?: readonly RectTuple[];
readonly SetPose?: readonly AssetPoseName[];
/** @deprecated - Superceded by {@link PoseMapping} */
readonly AllowPose?: never;
readonly PoseMapping: AssetPoseMapping;
readonly AllowExpression?: readonly ExpressionName[];
readonly Effect: readonly EffectName[];
readonly MirrorGroup: AssetGroupName | "";
readonly RemoveItemOnRemove: readonly Readonly<{ Group: AssetGroupItemName; Name: string; TypeRecord?: TypeRecord }>[];
readonly EditOpacity: boolean;
readonly MinOpacity: number;
readonly MaxOpacity: number;
readonly DrawingPriority: number;
readonly DrawingLeft: TopLeft.Data;
readonly DrawingTop: TopLeft.Data;
readonly DrawingBlink: boolean;
readonly InheritColor: AssetGroupName | null;
/** @deprecated Use {@link Asset.AllowActivePose} instead */
readonly FreezeActivePose?: never;
readonly PreviewZone?: RectTuple;
readonly DynamicGroupName: AssetGroupName;
readonly MirrorActivitiesFrom?: AssetGroupItemName;
readonly ArousalZone?: AssetGroupItemName;
readonly ArousalZoneID?: number;
/** A dict mapping colors to custom filename suffices.
The "HEX_COLOR" key is special-cased to apply to all color hex codes. */
readonly ColorSuffix: Readonly<Record<string, string>>;
readonly ExpressionPrerequisite?: readonly AssetPrerequisite[];
readonly HasPreviewImages: boolean;
/** Return whether this group belongs to the `Appearance` {@link AssetGroup.Category} */
IsAppearance(): this is AssetAppearanceGroup;
/** Return whether this group belongs to the `Item` {@link AssetGroup.Category} */
IsItem(): this is AssetItemGroup;
/** Return whether this group belongs to the `Script` {@link AssetGroup.Category} */
IsScript(): this is AssetScriptGroup;
}
/** An AssetGroup subtype for the `Appearance` {@link AssetGroup.Category} */
interface AssetAppearanceGroup extends AssetGroup {
readonly Category: "Appearance";
readonly Name: AssetGroupBodyName;
readonly IsRestraint: false;
}
/** An AssetGroup subtype for the `Item` {@link AssetGroup.Category} */
interface AssetItemGroup extends AssetGroup {
readonly Category: "Item";
readonly Name: AssetGroupItemName;
readonly Underwear: false;
readonly BodyCosplay: false;
readonly Clothing: false;
readonly IsDefault: false;
readonly Zone: readonly RectTuple[];
}
/** An AssetGroup subtype for the `Script` {@link AssetGroup.Category} */
interface AssetScriptGroup extends AssetGroup {
readonly Category: "Script";
readonly Name: AssetGroupScriptName;
readonly IsRestraint: false;
readonly BodyCosplay: false;
readonly Underwear: false;
readonly Clothing: false;
readonly IsDefault: false;
}
/** An object defining a drawable layer of an asset */
interface AssetLayer {
/** The name of the layer - may be null if the asset only contains a single default layer */
readonly Name: string | null;
/** whether or not this layer can be colored */
readonly AllowColorize: boolean;
/** if not null, specifies that this layer should always copy the color of the named layer */
readonly CopyLayerColor: string | null;
/** specifies the name of a color group that this layer belongs to. Any layers within the same color group can be colored together via the item color UI */
readonly ColorGroup: string | null;
/** whether or not this layer can be colored in the coloring UI */
readonly HideColoring: boolean;
/** A record mapping stringified {@link PartialType} values to a set of unique IDs. */
readonly AllowTypes: AllowTypes.Data | null;
/** @deprecated - superceded by {@link CreateLayerTypes} */
readonly HasType?: never;
/** @deprecated - superseded by {@link ParentGroup} */
readonly ParentGroupName?: never;
/** An object mapping pose names to group names from which to inherit body sizes. */
readonly ParentGroup: ParentGroup.Data;
/** @deprecated - Superceded by {@link PoseMapping} */
readonly AllowPose?: never;
/** @deprecated - Superceded by {@link PoseMapping} */
readonly HideForPose?: never;
/** An array of objects mapping poses to other poses to determine their draw folder */
readonly PoseMapping: Readonly<AssetPoseMapping>;
/** The drawing priority of this layer. Inherited from the parent asset/group if not specified in the layer
definition. */
readonly Priority: number;
readonly InheritColor: AssetGroupName | null;
readonly Alpha: readonly Alpha.Data[];
/** The asset that this layer belongs to */
readonly Asset: Asset;
readonly DrawingLeft: TopLeft.Data;
readonly DrawingTop: TopLeft.Data;
readonly HideAs?: Readonly<{ Group: AssetGroupName; Asset?: string }>;
/** That layer is drawing at a fixed Y position */
readonly FixedPosition?: boolean;
readonly HasImage: boolean;
readonly Opacity: number;
readonly MinOpacity: number;
readonly MaxOpacity: number;
readonly BlendingMode: GlobalCompositeOperation;
readonly LockLayer: boolean;
readonly MirrorExpression?: AssetGroupName;
/** @deprecated */
readonly AllowModuleTypes?: never;
/** The coloring index for this layer */
readonly ColorIndex: number;
/** Any group-specific alpha masks that should be applied when drawing the layer. Only available on layers that have
been created prior to drawing */
readonly GroupAlpha?: readonly Alpha.Data[];
/** @deprecated - Superceded by {@link CreateLayerTypes} */
readonly ModuleType?: never;
/**
* A list of {@link TypeRecord} keys for which a single layer expects multiple type-specific .png files.
*
* By default files are expected for _all_ option indices associated with the key(s), unless the valid option set has been narrowed down according to {@link AssetLayer.AllowTypes}.
*/
readonly CreateLayerTypes: readonly string[];
/* Specifies that this layer should not be drawn if the character is wearing any item with the given attributes */
readonly HideForAttribute: readonly AssetAttribute[] | null;
/* Specifies that this layer should not be drawn unless the character is wearing an item with one of the given attributes */
readonly ShowForAttribute: readonly AssetAttribute[] | null;
/** Used along with a hook to make layers of an asset disappear in some cases. */
readonly Visibility: "Player" | "AllExceptPlayerDialog" | "Others" | "OthersExceptDialog" | "Owner" | "Lovers" | "Mistresses" | null;
readonly ColorSuffix: Readonly<Record<string, string>> | null;
}
interface TintDefinition {
Color: number | string;
Strength: number;
DefaultColor?: string;
}
interface ResolvedTintDefinition extends TintDefinition {
Item: Item;
}
interface ExpressionTriggerBase<GroupName extends ExpressionGroupName> {
Group: GroupName;
Name: ExpressionNameMap[GroupName];
Timer: number;
}
type ExpressionTriggerMap<T> = T extends ExpressionGroupName ? ExpressionTriggerBase<T> : never;
type ExpressionTrigger = ExpressionTriggerMap<ExpressionGroupName>;
interface ExpressionItem {
Appearance: Item,
Group: ExpressionGroupName,
CurrentExpression: null | ExpressionName,
ExpressionList: ExpressionName[],
}
/**
* The internal Asset definition of an asset.
*
* See {@link AssetDefinition} in Female3DCG.d.ts for documentation.
*/
interface Asset {
readonly Name: string;
readonly Description: string;
readonly Group: AssetGroup;
readonly ParentItem?: string;
/** @deprecated - superseded by {@link ParentGroup} */
readonly ParentGroupName?: never;
/** An object mapping pose names to group names from which to inherit body sizes. */
readonly ParentGroup: ParentGroup.Data;
readonly Enable: boolean;
readonly Visible: boolean;
readonly NotVisibleOnScreen?: readonly string[];
readonly Wear: boolean;
readonly Activity: ActivityName | null;
readonly AllowActivity?: readonly ActivityName[];
readonly ActivityAudio?: readonly string[];
readonly ActivityExpression: Readonly<Partial<Record<ActivityName, readonly ExpressionTrigger[]>>>;
readonly AllowActivityOn: readonly AssetGroupItemName[];
readonly InventoryID?: number;
readonly BuyGroup?: string;
readonly Effect: readonly EffectName[];
readonly Bonus?: AssetBonusName;
readonly Block?: readonly AssetGroupItemName[];
readonly Expose: readonly AssetGroupItemName[];
readonly Hide?: readonly AssetGroupName[];
readonly HideItem?: readonly string[];
readonly HideItemExclude: readonly string[];
readonly HideItemAttribute: readonly AssetAttribute[];
readonly Require: readonly AssetGroupBodyName[];
readonly SetPose?: readonly AssetPoseName[];
/** @deprecated - Superceded by {@link Asset.PoseMapping} */
readonly AllowPose?: never;
/** @deprecated - Superceded by {@link Asset.PoseMapping} */
readonly HideForPose?: never;
readonly PoseMapping: Readonly<AssetPoseMapping>;
readonly AllowActivePose?: readonly AssetPoseName[];
/** @deprecated Use {@link Asset.AllowActivePose} instead */
readonly WhitelistActivePose?: never;
readonly Value: number;
readonly NeverSell: boolean;
readonly Difficulty: number;
readonly SelfBondage: number;
readonly SelfUnlock: boolean;
readonly ExclusiveUnlock: boolean;
readonly Random: boolean;
readonly RemoveAtLogin: boolean;
readonly WearTime: number;
readonly RemoveTime: number;
readonly RemoveTimer: number;
readonly MaxTimer: number;
readonly DrawingPriority?: number;
readonly DrawingLeft: TopLeft.Data;
readonly DrawingTop: TopLeft.Data;
readonly HeightModifier: number;
readonly ZoomModifier: number;
readonly Alpha: null | readonly Alpha.Data[];
readonly Prerequisite: readonly AssetPrerequisite[];
readonly Extended: boolean;
readonly AlwaysExtend: boolean;
readonly AlwaysInteract: boolean;
readonly AllowLock: boolean;
readonly LayerVisibility: boolean;
readonly IsLock: boolean;
readonly PickDifficulty: number;
readonly OwnerOnly: boolean;
readonly LoverOnly: boolean;
readonly FamilyOnly: boolean;
readonly ExpressionTrigger?: readonly ExpressionTrigger[];
readonly RemoveItemOnRemove: readonly { Name: string; Group: AssetGroupName; TypeRecord?: TypeRecord; }[];
readonly AllowEffect?: readonly EffectName[];
readonly AllowBlock?: readonly AssetGroupItemName[];
readonly AllowHide?: readonly AssetGroupName[];
readonly AllowHideItem?: readonly string[];
/** @deprecated */
readonly AllowTypes?: never;
readonly AllowTighten: boolean;
/**
* The default color of the item: an array of length {@link Asset.ColorableLayerCount} consisting of {@link AssetGroup.DefaultColor} and/or valid color hex codes.
*/
readonly DefaultColor: readonly string[];
readonly Opacity: number;
readonly MinOpacity: number;
readonly MaxOpacity: number;
readonly EditOpacity: boolean;
readonly Audio?: string;
readonly Category?: readonly AssetCategory[];
readonly Fetish?: readonly FetishName[];
readonly CustomBlindBackground?: string;
readonly ArousalZone: AssetGroupItemName;
readonly IsRestraint: boolean;
readonly BodyCosplay: boolean;
readonly OverrideBlinking: boolean;
readonly DialogSortOverride?: DialogSortOrder;
readonly DynamicDescription: (C: Character) => string;
readonly DynamicPreviewImage: (C: Character) => string;
readonly DynamicAllowInventoryAdd: (C: Character) => boolean;
readonly DynamicName: (C: Character) => string;
readonly DynamicGroupName: AssetGroupName;
readonly DynamicActivity: (C: Character) => ActivityName | null | undefined;
readonly DynamicAudio: ((C: Character) => string) | null;
/**
* Whether the asset is restricted to a given character.
*
* When the asset is added to a character, the member number of the character using the
* asset will be stored along in its properties, and all subsequent modifications will
* only be possible for that character.
*
* @deprecated Discontinued in favor of the {@link FamilyOnly}/{@link LoverOnly}/{@link OwnerOnly} trio
*/
readonly CharacterRestricted?: never;
readonly AllowRemoveExclusive: boolean;
readonly InheritColor: null | AssetGroupName;
readonly DynamicBeforeDraw: boolean;
readonly DynamicAfterDraw: boolean;
readonly DynamicScriptDraw: boolean;
/** @deprecated - superceded by {@link CreateLayerTypes} */
readonly HasType?: never;
/** A list of {@link TypeRecord} keys for which a single layer expects multiple type-specific .png files. */
readonly CreateLayerTypes: readonly string[];
/** A record that maps {@link ExtendedItemData.name} to a set with all option indices that support locks */
readonly AllowLockType: null | Record<string, Set<number>>;
readonly AllowColorizeAll: boolean;
readonly AvailableLocations: readonly string[];
readonly OverrideHeight?: Readonly<AssetOverrideHeight>;
/** @deprecated Use {@link Asset.AllowActivePose} instead */
readonly FreezeActivePose?: never;
readonly DrawLocks: boolean;
readonly AllowExpression?: readonly ExpressionName[];
readonly MirrorExpression?: AssetGroupName;
readonly FixedPosition: boolean;
readonly Layer: readonly AssetLayer[];
/** The number of colorable layers. Guaranteed to be >= 1 */
readonly ColorableLayerCount: number;
readonly Archetype?: ExtendedArchetype;
readonly Attribute: readonly AssetAttribute[];
readonly PreviewIcons: readonly InventoryIcon[];
readonly Tint: readonly Readonly<TintDefinition>[];
readonly AllowTint: boolean;
readonly DefaultTint?: string;
readonly Gender?: AssetGender;
readonly CraftGroup: string;
readonly ColorSuffix: Readonly<Record<string, string>>;
readonly FullAlpha: boolean;
readonly ExpressionPrerequisite?: readonly AssetPrerequisite[];
readonly AllowColorize: boolean;
}
//#endregion
type ItemBundle = ServerItemBundle;
/** A tuple-based version of {@link ItemBundle} */
type WardrobeItemBundle = [
Name: string,
Group: AssetGroupName,
Color?: ItemColor,
Property?: ItemProperties,
];
/** An AppearanceBundle is whole minified appearance of a character */
type AppearanceBundle = ItemBundle[];
interface ClipboardItemBundle {
/** The item's asset group name */
G: AssetGroupName;
/** The item's asset name */
A: string;
/** The item's color */
C?: string;
}
type ClipboardAppearanceBundle = ClipboardItemBundle[];
interface Pose {
Name: AssetPoseName;
Category: AssetPoseCategory;
AllowMenu?: true;
/** Only show in menu if an asset supports it */
AllowMenuTransient?: true;
OverrideHeight?: AssetOverrideHeight;
MovePosition?: { Group: AssetGroupName; X: number; Y: number; }[];
}
type ActivityNameBasic = "Bite" | "Caress" | "Choke" | "Cuddle" | "FrenchKiss" |
"GagKiss" | "GaggedKiss" | "Grope" | "HandGag" | "Kick" |
"Kiss" | "Lick" | "MassageFeet" | "MassageHands" | "MasturbateFist" |
"MasturbateFoot" |"MasturbateHand" | "MasturbateTongue" |
"MoanGag" | "MoanGagAngry" | "MoanGagGiggle" | "MoanGagGroan" | "MoanGagTalk" |
"MoanGagWhimper" | "Nibble" | "Nod" | "PenetrateFast" |
"PenetrateSlow" | "Pet" | "Pinch" | "PoliteKiss" | "Pull" |
"RestHead" | "Rub" | "Scratch" | "Sit" | "Slap" | "Spank" | "Step" | "StruggleArms" | "StruggleLegs" |
"Suck" | "TakeCare" | "Tickle" | "Whisper" | "Wiggle" |
"SistersHug" | "BrothersHandshake" | "SiblingsCheekKiss" | "CollarGrab"
;
type ActivityNameItem = "Inject" | "MasturbateItem" | "PenetrateItem" | "PourItem" | "RollItem" | "RubItem" | "ShockItem" | "SipItem" | "SpankItem" | "TickleItem" | "EatItem" | "Scratch" | "ThrowItem";
type ActivityName = ActivityNameBasic | ActivityNameItem;
type ActivityPrerequisite =
"AssEmpty" | "CantUseArms" | "CantUseFeet" | "CanUsePenis" | "CanUseTongue" | "HasVagina" | "IsGagged" | "MoveHead" |
`Needs-${ActivityNameItem}` |
"TargetCanUseTongue" | "TargetKneeling" | "TargetMouthBlocked" | "TargetMouthOpen" | "TargetZoneAccessible" | "TargetZoneNaked" |
"UseArms" | "UseFeet" | "UseHands" | "UseMouth" | "UseTongue" | "VulvaEmpty" | "ZoneAccessible" | "ZoneNaked" |
"Sisters" | "Brothers" | "SiblingsWithDifferentGender" | "Collared"
;
interface Activity {
Name: ActivityName;
ActivityID: number,
MaxProgress: number;
MaxProgressSelf?: number;
Prerequisite: ActivityPrerequisite[];
Target: AssetGroupItemName[];
TargetSelf?: AssetGroupItemName[] | true;
/** Whether to reverse the prerequisite checks for that one */
Reverse?: true;
/** used for setting {@link ExtendedItemAutoPunishHandled} */
MakeSound?: boolean;
/** An action that trigger when that activity is used */
StimulationAction?: StimulationAction;
/** The default expression for that activity. Can be overriden using ActivityExpression on the asset */
ActivityExpression?: ExpressionTrigger[];
}
type ItemActivityRestriction = "blocked" | "limited" | "unavail";
interface ItemActivity {
/** The activity performed */
Activity: Activity;
/** The target group of the activity */
Group: AssetGroupName;
/** An optional item used for the activity. Null if the player is used their hand, for example. */
Item?: Item;
/** Whether the item is blocked or limited on the target character, or unavailable because the player is blocked. Undefined means no restriction. */
Blocked?: ItemActivityRestriction;
}
type ItemColor = string | string[];
/** An item is a pair of asset and its dynamic properties that define a worn asset. */
interface Item {
Asset: Asset;
Color?: ItemColor;
Difficulty?: number;
Craft?: CraftingItem;
Property?: ItemProperties;
}
type FavoriteIcon = "Favorite" | "FavoriteBoth" | "FavoritePlayer";
type ItemEffectIcon = "BlindLight" | "BlindNormal" | "BlindHeavy" | "DeafLight" | "DeafNormal" | "DeafHeavy" | "GagLight" | "GagNormal" | "GagHeavy" | "GagTotal" | "Freeze" | "Block";
type ShopIcon = "Extended" | "BuyGroup";
type InventoryIcon = (
FavoriteIcon
| ItemEffectIcon
| "AllowedLimited"
| "Handheld"
| "Locked"
| "LoverOnly"
| "FamilyOnly"
| "OwnerOnly"
| "Unlocked"
| "Blocked"
| AssetLockType
| ShopIcon
);
interface InventoryBundle {
Group: AssetGroupName;
Name: string
}
interface InventoryItem extends InventoryBundle {
Asset: Asset;
}
type SkillType = "Bondage" | "SelfBondage" | "LockPicking" | "Evasion" | "Willpower" | "Infiltration" | "Dressage";
interface Skill {
Type: SkillType;
Level: number;
Progress: number;
Ratio?: number;
ModifierLevel?: number;
ModifierTimeout?: number;
}
type ReputationType =
"Dominant" | "Kidnap" | "ABDL" | "Gaming" | "Maid" | "LARP" | "Asylum" | "Gambling" |
"HouseMaiestas" | "HouseVincula" | "HouseAmplector" | "HouseCorporis";
interface Reputation {
Type: ReputationType;
Value: number;
}
interface Ownership {
Name: string;
MemberNumber: number;
Stage: 0 | 1;
Start: number;
}
interface Lovership {
/** The name of the loved one. */
Name: string;
/** The member number of the loved one. Only exists for online characters */
MemberNumber?: number;
/** The stage of the love. 0 is Girlfriend, 1 is Fiancée, 2 is Wife */
Stage?: 0 | 1 | 2;
/** The timestamp of the beginning of the relationship */
Start?: number;
// Bad data sometimes received from server
BeginDatingOfferedByMemberNumber?: never;
BeginEngagementOfferedByMemberNumber?: never;
BeginWeddingOfferedByMemberNumber?: never;
}
interface ScreenFunctions {
// Required
/**
* Called each frame
* @param {number} time - The current time for frame
*/
Run(time: number): void;
/**
* Called if the user presses the mouse button or touches the touchscreen on the canvas
* @param {MouseEvent | TouchEvent} event - The event that triggered this
*/
MouseDown?(event: MouseEvent | TouchEvent): void;
/**
* Called if the user releases the mouse button or the touchscreen on the canvas
* @param {MouseEvent | TouchEvent} event - The event that triggered this
*/
MouseUp?(event: MouseEvent | TouchEvent): void;
/**
* Called if the user moves the mouse cursor or the touch on the touchscreen over the canvas
* @param {MouseEvent | TouchEvent} event - The event that triggered this
*/
MouseMove?(event: MouseEvent | TouchEvent): void;
/**
* Called if the user moves the mouse wheel on the canvas
* @param {MouseEvent | TouchEvent} event - The event that triggered this
*/
MouseWheel?(event: WheelEvent): void;
/**
* Called if the user clicks on the canvas
* @param {MouseEvent | TouchEvent} event - The event that triggered this
*/
Click(event: MouseEvent | TouchEvent): void;
// Optional
/** Called when screen is loaded using `CommonSetScreen` */
Load?(): void;
/** Called when this screen is being replaced */
Unload?(): void;
/** Called each frame when the screen needs to be drawn. */
Draw?() : void;
/**
* Called when screen size or position changes or after screen load
* @param {boolean} load - If the reason for call was load (`true`) or window resize (`false`)
*/
Resize?(load: boolean): void;
/**
* Called if the the user presses any key
* @param {KeyboardEvent} event - The event that triggered this
*/
KeyDown?(event: KeyboardEvent): boolean;
/**
* Called if the user releases a pressed key
* @param {KeyboardEvent} event - The event that triggered this
*/
KeyUp?(event: KeyboardEvent): void;
/** Called when user presses Esc */
Exit?(): void;
}
//#region Characters
/** The different types of (mutually exclusive) permissions an item or item option can have */
type ItemPermissionMode = "Default" | "Block" | "Limited" | "Favorite";
/**
* A struct for representing an item with special permissions (limited, favorited, etc) in the client.
*/
interface ItemPermissions {
/** Whether the item is hidden */
Hidden: boolean;
/** The permission associated with the item */
Permission: ItemPermissionMode;
/** The permission associated with specific extended options of the item */
TypePermissions: Record<string, ItemPermissionMode>;
}
interface ScriptPermission {
permission: number;
}
type ScriptPermissionProperty = "Hide" | "Block";
type ScriptPermissionLevel = "Self" | "Owner" | "Lovers" | "Friends" | "Whitelist" | "Public";
type ScriptPermissions = Record<ScriptPermissionProperty, ScriptPermission>;
interface DialogLine {
Stage: string;
NextStage: string;
Option: string;
Result: string;
Function: string;
Prerequisite: string;
Group: string;
Trait: string;
}
interface DialogInfo {
module: ModuleType;
screen: string;
name: string;
}
/** The packed representation of a Private Room NPC */
interface PrivateCharacterData {
Name: string;
Love: number;
Title: TitleName;
Trait: NPCTrait[];
Cage: boolean;
Owner: string;
Lover: string;
AssetFamily: "Female3DCG";
Appearance: AppearanceBundle,
AppearanceFull: AppearanceBundle,
ArousalSettings: Character["ArousalSettings"];
Event: NPCEvent[];
FromPandora?: boolean;
}
interface Character {
/**
* The character's cache slot ID in the Character array
*
* Usually meaningless, except that ID 0 is always the player,
* but please use `IsPlayer()` instead of checking that.
*/
ID: number;
/**
* The unique identifier for the character
*
* A value of `""` indicates the player before the login happens
*/
CharacterID: string;
/** The type of character: online, npc, or simple */
Type: CharacterType;
/**
* The character's account name
*
* Note that it's only meaningful for the logged in player as the server never provides account names.
* Online characters will use `"Online-"` plus their character ID, NPCs will have their dialog identifier,
* and simple characters set it to CharacterID.
*/
AccountName: string;
/**
* The character's loaded dialog info
*/
DialogInfo?: DialogInfo;
/**
* A deprecated identifier for online characters
* Only exists on the player, has the same value as their character ID.
* @deprecated
*/
OnlineID?: string;
/** The asset family used by the character */
AssetFamily: IAssetFamily;
Name: string;
Nickname?: string; // technically never as it's Online-only
Owner: string;
Lover: string;
Money: number;
Inventory: InventoryItem[];
InventoryData?: string;
Appearance: Item[];
/**
* @private
* @see {@link Character.Stage}
*/
_Stage: string;
/** Set or get the current stage, performing a dialog {@link DialogMenu.Reload} if required */
get Stage(): string;
set Stage(value: string);
/**
* @private
* @see {@link Character.CurrentDialog}
*/
_CurrentDialog: string;
ClickedOption: null | string;
/** Set or get the current dialog, performing a dialog status update if required (see {@link DialogSetStatus}) */
get CurrentDialog(): string;
set CurrentDialog(value: string);
Dialog: DialogLine[];
Reputation: Reputation[];
Skill: Skill[];
/**
* Get a copy or set the array of currently enabled poses.
* @see {@link PoseMapping} - The underlying record of this property, usage of which is recommended
*/
get Pose(): readonly AssetPoseName[];
set Pose(value: readonly AssetPoseName[]);
/**
* Get a copy or set the array of the last set of manually activated poses.
*
* Note that these poses are by no means guaranted to be enabled, as they do not reflect any item-specific automatic pose changes (see {@link Pose}).
* @see {@link ActivePoseMapping} - The underlying record of this property, usage of which is recommended
*/
get ActivePose(): readonly AssetPoseName[];
set ActivePose(value: readonly AssetPoseName[]);
/**
* Get a copy or set the array of the last of a subset of all allowed poses.
*
* Only guaranteed to reflect the total number of allowed poses if, for a given pose category, at least one pose is allowed.
* @see {@link ActivePoseMapping} - The underlying record of this property, usage of which is recommended
*/
get AllowedActivePose(): readonly AssetPoseName[];
set AllowedActivePose(value: readonly AssetPoseName[]);
/**
* Get a copy or set the array of something something poses.
* @see {@link DrawPoseMapping} - The underlying record of this property, usage of which is recommended
*/
get DrawPose(): readonly AssetPoseName[];
set DrawPose(value: readonly AssetPoseName[]);
/**
* A record mapping pose categories to the currently enabled pose belonging to it.
*
* @see {@link ItemProperties.SetPose} - The item-/asset-level equivalent of this property
*/
PoseMapping: Partial<Record<AssetPoseCategory, AssetPoseName>>;
/**
* A record mapping pose categories to the last manually enabled pose belonging to it.
*
* Note that these poses are by no means guaranted to be enabled, as they do not reflect any item-specific automatic pose changes (see {@link PoseMapping}).
*/
ActivePoseMapping: Partial<Record<AssetPoseCategory, AssetPoseName>>;
/**
* A record mapping pose categories to all allowed poses belonging to it.
*
* A value of `null` implies that all poses within the category are allowed.
*
* @see {@link ItemProperties.AllowActivePose} - The item-/asset-level equivalent of this property
*/
AllowedActivePoseMapping: Partial<Record<AssetPoseCategory, AssetPoseName[]>>;
/**
* A record mapping pose categories to something something.
*/
DrawPoseMapping: Partial<Record<AssetPoseCategory, AssetPoseName>>;
Effect: EffectName[];
Tints: ResolvedTintDefinition[];
Attribute: AssetAttribute[];
FocusGroup: AssetItemGroup | null;
Canvas: HTMLCanvasElement | null;
CanvasBlink: HTMLCanvasElement | null;
MustDraw: boolean;
BlinkFactor: number;
AllowItem: boolean;
/** @deprecated - superseded by {@link Character.PermissionItems} */
BlockItems?: never;
/** @deprecated - superseded by {@link Character.PermissionItems} */
FavoriteItems?: never;
/** @deprecated - superseded by {@link Character.PermissionItems} */
LimitedItems?: never;
/** A record with all asset- and type-specific permission settings */
PermissionItems: Partial<Record<`${AssetGroupName}/${string}`, ItemPermissions>>;
WhiteList: number[];
HeightModifier: number;
MemberNumber?: number;
ItemPermission: 0 | 1 | 2 | 3 | 4 | 5;
Ownership: Ownership | null;
Lovership: Lovership[];
ExpressionQueue?: ExpressionQueueItem[];
CanTalk: () => boolean;
CanWalk: () => boolean;
CanKneel: () => boolean;
CanInteract: () => boolean;
/**
* Check whether a character can change its own outfit.
*
* @warning Only usable on Player
* @returns {boolean} - TRUE if changing is possible, FALSE otherwise.
*/
CanChangeOwnClothes: () => boolean;
/**
* Check whether a character can change another one's outfit.
*/
CanChangeClothesOn: (C: Character) => boolean;
IsRestrained: () => boolean;
IsBlind: () => boolean;
IsEnclose: () => boolean;
IsChaste: () => boolean;
IsVulvaChaste: () => boolean;
IsBreastChaste: () => boolean;
IsButtChaste: () => boolean;
IsEgged: () => boolean;
/**
* Whether the character is owned, and who owns it
*/
IsOwned: () => "online"|"npc"|"ggts"|"player"|false;
/** Whether the character is owned by the given character */
IsOwnedByCharacter: (C: Character) => boolean;
/** Whether the character is owned by the given character, number form */
IsOwnedByMemberNumber: (memberNumber: number) => boolean;
/** Whether the character has completed their ownership trial */
IsFullyOwned: () => boolean;
/** The name of this character's owner */
OwnerName: () => string;
/** The character's owner number. Might be -1 for non-online characters */
OwnerNumber: () => number;
/** Whether the player owns that character */
IsOwnedByPlayer: () => boolean;
/** The number of days since the character has been owned (-1 means not owned) */
OwnedSince: () => number;
/** Whether the given character owns the player */
IsOwner: () => boolean;
IsKneeling: () => boolean;
IsStanding: () => boolean;
IsNaked: () => boolean;
IsDeaf: () => boolean;
IsGagged: () => boolean;
HasNoItem: () => boolean;
/** Whether the character is in love with the given character */
IsLoverOfCharacter: (C: Character) => boolean;
/** Whether the character is in love with the given character, number form */
IsLoverOfMemberNumber: (memberNumber: number) => boolean;
/** The character's lover name. NPC-only */
LoverName: () => string;
/** Whether the character is in love with the player */
IsLoverOfPlayer: () => boolean;
/** Returns the list of member numbers (or names, for NPCs) the character is in love with */
GetLoversNumbers: (MembersOnly?: boolean) => (number | string)[];
/** Returns the lovership data for the character */
GetLovership: (MembersOnly?: boolean) => Lovership[];
/** @deprecated Use IsLoverOfCharacter() */
IsLover: (C: Character) => boolean;
/** @deprecated - superseded by {@link Character.PermissionItems} */
HiddenItems?: never;
HeightRatio: number;
HasHiddenItems: boolean;
SavedColors: HSVColor[];
GetBlindLevel: (eyesOnly?: boolean) => number;
GetBlurLevel: () => number;
IsLocked: () => boolean;
IsMounted: () => boolean;
IsPlugged: () => boolean;
IsShackled: () => boolean;
IsSlow: () => boolean;
GetSlowLevel: () => number;
IsMouthBlocked: () => boolean;
IsMouthOpen: () => boolean;
IsVulvaFull: () => boolean;
IsAssFull: () => boolean;
IsFixedHead: () => boolean;
GetDeafLevel: () => number;
CanPickLocks: () => boolean;
IsEdged: () => boolean;
IsPlayer: () => this is PlayerCharacter;
IsBirthday: () => boolean;
IsSiblingOfCharacter: (C: Character) => boolean;
IsFamilyOfPlayer: () => boolean;
IsInFamilyOfMemberNumber: (MemberNum: number) => boolean;
IsOnline: () => this is Character;
IsNpc: () => this is NPCCharacter;
IsSimple: () => boolean;
GetDifficulty: () => number;
IsSuspended: () => boolean;
IsInverted: () => boolean;
CanChangeToPose: (Pose: AssetPoseName) => boolean;
GetClumsiness: () => number;
HasEffect: (Effect: EffectName) => boolean;
HasTints: () => boolean;
GetTints: () => RGBAColor[];
HasAttribute: (attribute: AssetAttribute) => boolean;
DrawAppearance?: Item[];
AppearanceLayers?: Mutable<AssetLayer>[];
Hooks: Map<CharacterHook, Map<string, () => void>> | null;
RegisterHook: (hookName: CharacterHook, hookInstance: string, callback: () => void) => boolean;
UnregisterHook: (hookName: CharacterHook, hookInstance: string) => boolean;
RunHooks: (hookName: CharacterHook) => void;
HeightRatioProportion?: number;
GetGenders: () => AssetGender[];
GetPronouns: () => CharacterPronouns;
HasPenis: () => boolean;
HasVagina: () => boolean;
IsFlatChested: () => boolean;
WearingCollar: () => boolean;
// Properties created in other places
ArousalSettings: ArousalSettingsType;
AppearanceFull?: Item[]; // Private NPCs only
// Online character properties
Title?: TitleName;
LabelColor?: HexColor;
Creation?: number; // technically never as it is Online-only
Description?: string; // technically never as it is Online-only
OnlineSharedSettings?: CharacterOnlineSharedSettings; // technically never as it is Online-only
Game?: CharacterGameParameters; // technically never as it is Online-only
MapData?: ChatRoomMapData;
BlackList: number[];
RunScripts?: boolean;
HasScriptedAssets?: boolean;
Cage?: boolean;
Difficulty?: { Level: number }; // technically never as it is Online-only
ArousalZoom?: boolean;
FixedImage?: string;
Rule?: LogRecord[];
Status?: string | null;
StatusTimer?: number;
Crafting: (CraftingItem | null)[]; // technically never as it is Online-only
LastMapData?: ChatRoomMapData;
/**
* The custom background to use for the current room
* Only valid on {@link Player}
*/
CustomBackground?: string;
}
interface CharacterGameParameters {
LARP?: GameLARPParameters,
MagicBattle?: GameMagicBattleParameters,
GGTS?: GameGGTSParameters,
Poker?: GamePokerParameters,
ClubCard?: GameClubCardParameters,
Prison? : GamePrisonParameters;
}
/**
* The characters online shared settings.
* @see {@link Character.OnlineSharedSettings}
*/
interface CharacterOnlineSharedSettings {
AllowFullWardrobeAccess: boolean;
BlockBodyCosplay: boolean;
AllowPlayerLeashing: boolean;
AllowRename: boolean;
DisablePickingLocksOnSelf: boolean;
GameVersion?: string;
ItemsAffectExpressions: boolean;
ScriptPermissions: ScriptPermissions;
WheelFortune: string;
}
type NPCArchetype =
/* Pandora NPCs */
"MemberNew"|"MemberOld"|"Cosplay"|"Mistress"|"Slave"|"Maid"|"Guard"|
/* Pandora Special */
"Victim"|"Target"|"Chest"|
// Misc
"Dominatrix" | "Nurse" | "Submissive" | "Mistress" | "Patient" | "Maid" | "Mistress" | "Maiestas" | "Vincula" | "Amplector" | "Corporis" | "AnimeGirl" | "Bunny" | "Succubus"
;
/** NPC Character extension */
// FIXME: That one should find its way down to NPCCharacter, but
// there's too many accesses to those properties from Character
// to do so.
interface Character {
/** NPC type: Slave, Maid, etc. */
Archetype?: NPCArchetype;
Love?: number; /** The NPC's love value */
WillRelease?(): boolean; /** Shop NPC-only: will it release the player when asked */
}
/** NPC-only */
interface NPCCharacter extends Character {
Archetype?: NPCArchetype;
Trait?: NPCTrait[];
Event?: NPCEvent[];
Affection?: number;
Domination?: number;
}
/** College & Asylum */
interface NPCCharacter {
GoneAway?: boolean;
}
/** Movie Studio */
interface NPCCharacter {
TrialDone?: boolean;
CanGetLongDuster?: boolean;
CanGetForSaleSign?: boolean;
OweFavor?: boolean;
KissCount?: number;
MasturbateCount?: number;
ClothesTaken?: boolean;
}
/** Sarah */
interface Character {
OrgasmMeter?: number;
OrgasmDone?: boolean;
}
/** Private Room & Private Bed */
interface Character {
PrivateBed?: boolean;
PrivateBedActivityTimer?: number;
PrivateBedLeft?: number;
PrivateBedTop?: number;
PrivateBedMoveTimer?: number;
PrivateBedAppearance?: string;
}
interface KidnapCard {
Move: number;
Value?: number;
}
/** Kidnap minigame */
interface Character {
KidnapWillpower?: number;
KidnapMaxWillpower?: number;
KidnapCard?: KidnapCard[];
KidnapStat?: [number, number, number, number];
}
type PandoraPrisonActivity = "Beat" | "Water" | "Transfer" | "Quickie" | "Strip" | "Chastity" | "Tickle" | "ChangeBondage";
/** Pandora NPCs */
interface Character {
Recruit?: number;
RecruitOdds?: number;
RandomOdds?: number;
QuizLog?: number[];
QuizFail?: number;
AllowMove?: boolean;
DrinkValue?: number;
TriggerIntro?: boolean;
FromPandora?: boolean;
// Pandora Prison
LastActivity?: PandoraPrisonActivity;
}
/** Magic School */
interface Character {
House?: "" | MagicSchoolHouse;
}
/** MovieStudio */
interface Character {
Friendship?: string;
InterviewCleanCount?: number;
}
/** Slave market */
interface Character {
ExpectedTraining?: number;
CurrentTraining?: number;
TrainingIntensity?: number;
TrainingCount?: number;
TrainingCountLow?: number;
TrainingCountHigh?: number;
TrainingCountPerfect?: number;
}
interface ExtensionSettings {
[key: string]: any;
}
interface ControllerSettingsOld {
ControllerA: number;
ControllerB: number;
ControllerX: number;
ControllerY: number;
ControllerStickUpDown: number;
ControllerStickLeftRight: number;
ControllerStickRight: number;
ControllerStickDown: number;
ControllerDPadUp: number;
ControllerDPadDown: number;
ControllerDPadLeft: number;
ControllerDPadRight: number;
}
type DifficultyLevel =
| 0 // Roleplay
| 1 // Regular
| 2 // Hardcore
| 3 // Extreme
;
interface PlayerCharacter extends Character {
// All the following are guaranteed to be set on login
MemberNumber: number;
Nickname: string;
LabelColor: HexColor;
Game: CharacterGameParameters;
Description: string;
Creation: number;
Difficulty: {
Level: DifficultyLevel;
LastChange?: number;
};
Crafting: (null | CraftingItem)[];
ItemPermission: 0 | 1 | 2 | 3 | 4 | 5;
// PreferenceInitPlayer() must be updated with defaults, when adding a new setting
ChatSettings: ChatSettingsType;
VisualSettings: VisualSettingsType;
AudioSettings: AudioSettingsType;
ControllerSettings: ControllerSettingsType;
GameplaySettings: GameplaySettingsType;
ImmersionSettings: ImmersionSettingsType;
/** The chat room we were previous in. Used for relog room re-creation */
// TODO: the fact that this is set *might* be used to also fold the "relog" enabled checks
// If we have a chatroom, then we relog to it. If we don't, then the player didn't have the
// setting enabled in the first place
LastChatRoom?: ChatRoomSettings;
RestrictionSettings: RestrictionSettingsType;
OnlineSettings: PlayerOnlineSettings;
GraphicsSettings: GraphicsSettingsType;
NotificationSettings: NotificationSettingsType;
OnlineSharedSettings: CharacterOnlineSharedSettings; // technically never as it is Online-only
GhostList?: number[];
Wardrobe: ItemBundle[][];
WardrobeCharacterNames: string[];
SavedExpressions?: ({ Group: ExpressionGroupName, CurrentExpression?: ExpressionName }[] | null)[];
SavedColors: HSVColor[];
FriendList: number[];
FriendNames: Map<number, string>;
SubmissivesList: Set<number>;
ChatSearchFilterTerms: string;
GenderSettings: GenderSettingsType;
/** The list of items we got confiscated in the Prison */
ConfiscatedItems: { Group: AssetGroupName, Name: string }[];
ExtensionSettings: ExtensionSettings;
}
/** A type defining which genders a setting is active for */
interface GenderSetting {
/** Whether the setting is active for female cases */
Female: boolean;
/** Whether the setting is active for male cases */
Male: boolean;
}
interface GenderSettingsType {
HideShopItems: GenderSetting;
AutoJoinSearch: GenderSetting;
HideTitles: GenderSetting;
}
interface NotificationSettingsType {
/** @deprecated */
Audio?: boolean;
Beeps: NotificationSetting;
/** @deprecated */
Chat?: any;
ChatMessage: NotificationSetting & {
/** @deprecated */
IncludeActions?: any;
Mention: boolean;
Normal: boolean;
Whisper: boolean;
Activity: boolean;
};
/** @deprecated */
ChatActions?: any;
ChatJoin: NotificationSetting & {
/** @deprecated */
Enabled?: any;
Owner: boolean;
Lovers: boolean;
Friendlist: boolean;
Subs: boolean;
};
Disconnect: NotificationSetting;
Larp: NotificationSetting;
Test: NotificationSetting;
}
interface GraphicsSettingsType {
Font: GraphicsFontName;
InvertRoom: boolean;
DoBlindFlash: boolean;
AnimationQuality: number;
StimulationFlash: boolean;
SmoothZoom: boolean;
CenterChatrooms: boolean;
AllowBlur: boolean;
ShowFPS: boolean;
/** 0 means unlimited */
MaxFPS: number;
MaxUnfocusedFPS: number;
}
interface RestrictionSettingsType {
BypassStruggle: boolean;
SlowImmunity: boolean;
BypassNPCPunishments: boolean;
NoSpeechGarble: boolean;
}
interface ImmersionSettingsType {
/** @deprecated Removed as it prevents players from having the possibility of using OOC to discuss the scene */
BlockGaggedOOC: never;
StimulationEvents: boolean;
ReturnToChatRoom: boolean;
ReturnToChatRoomAdmin: boolean;
ChatRoomMapLeaveOnExit: boolean;
SenseDepMessages: boolean;
ChatRoomMuffle: boolean;
BlindAdjacent: boolean;
AllowTints: boolean;
/**
* Whether garbled messages that have a non-garbled variant will be decoded.
*/
ShowUngarbledMessages: boolean;
}
type ControllerButton = typeof ControllerButton[keyof typeof ControllerButton];
type ControllerAxis = typeof ControllerAxis[keyof typeof ControllerAxis];
interface ControllerSettingsType {
ControllerActive: boolean;
ControllerSensitivity: number;
ControllerDeadZone: number;
Buttons: Record<ControllerButton, number>;
Axis: Record<ControllerAxis, number>;
}
interface ChatSettingsType {
ColorActions: boolean;
ColorActivities: boolean;
ColorEmotes: boolean;
ColorNames: boolean;
ColorTheme: ChatColorThemeType;
DisplayTimestamps: boolean;
EnterLeave: ChatEnterLeaveType;
FontSize: ChatFontSizeType;
MemberNumbers: ChatMemberNumbersType;
MuStylePoses: boolean;
ShowActivities: boolean;
ShowAutomaticMessages: boolean;
ShowBeepChat: boolean;
ShowChatHelp: boolean;
ShrinkNonDialogue: boolean;
WhiteSpace: "" | "Preserve";
CensoredWordsList: string;
CensoredWordsLevel: number;
/** Whether to preserve the chat log when switching rooms */
PreserveChat: boolean;
OOCAutoClose: boolean;
}
interface GameplaySettingsType {
SensDepChatLog: SettingsSensDepName;
BlindDisableExamine: boolean;
DisableAutoRemoveLogin: boolean;
ImmersionLockSetting: boolean;
EnableSafeword: boolean;
DisableAutoMaid: boolean;
OfflineLockedRestrained: boolean;
}
interface AudioSettingsType {
Volume: number;
MusicVolume: number;
PlayBeeps: boolean;
/** Play items sounds in chatrooms */
PlayItem: boolean;
/** Play sounds only if the player is involved */
PlayItemPlayerOnly: boolean;
Notifications: boolean;
}
interface VisualSettingsType {
ForceFullHeight: boolean;
UseCharacterInPreviews: boolean;
MainHallBackground: string;
PrivateRoomBackground: string;
}
/**
* The player's online settings.
* @see {@link Player.OnlineSettings}
*/
interface PlayerOnlineSettings {
AutoBanBlackList: boolean;
AutoBanGhostList: boolean;
DisableAnimations: boolean;
SearchShowsFullRooms: boolean;
SearchFriendsFirst: boolean;
SendStatus: boolean;
ShowStatus: boolean;
EnableAfkTimer: boolean;
ShowRoomCustomization: 0 | 1 | 2 | 3; // 0 - Never, 1 - No by default, 2 - Yes by default, 3 - Always
FriendListAutoRefresh: boolean;
}
/** Pandora Player extension */
interface PlayerCharacter {
Infiltration?: InfiltrationType;
}
interface InfiltrationType {
Punishment?: {
Minutes: number;
Timer?: number;
Background: string;
Difficulty: number;
FightDone?: boolean;
}
Perks?: string;
}
/** Kinky Dungeon Player extension */
interface PlayerCharacter {
KinkyDungeonKeybindings?: any;
KinkyDungeonExploredLore?: any[];
}
type NPCTraitType =
| "Dominant" | "Submissive"
| "Violent" | "Peaceful"
| "Horny" | "Frigid"
| "Rude" | "Polite"
| "Wise" | "Dumb"
| "Serious" | "Playful";
interface NPCTrait {
Name: NPCTraitType;
/** 1 to 100 */
Value: number;
}
type NPCEventType =
| "LastInteraction"
| "Wife" | "Fiancee" | "Girlfriend"
| "PrivateRoomEntry"
| "NPCCollaring" | "PlayerCollaring"
| "NextGift" | "LastGift"
| "Kidnap" | "NextKidnap"
| "NPCBrainwashing"
| "EndSubTrial" | "EndDomTrial"
| "NextBed"
| "NewCloth"
| "RefusedActivity"
| "SlaveMarketRent"
| "AsylumSent"
| "LastDecay"
;
interface NPCEvent {
Name: NPCEventType;
/** timestamp */
Value: number;
}
//#endregion
//#region Extended items
/**
* An interface with all available element metadata fields.
* Note that only a subset of fields are generally used by a given archetype.
* @see {@link ElementData}
* @see {@link ExtendedItemDrawData}
*/
interface ElementMetaData {
/** Whether to draw an element-accompanying image or not */
drawImage?: boolean,
/**
* The static image path of the to-be drawn image.
* A value of `null` either implies that it should not be drawn (per {@link ElementMetaData.drawImage})
* or that it's a dynamic image path (_e.g._ modular item modules).
*/
imagePath?: null | string,
/** The name of a supported thumbnail image in \CSS\Styles.css that will show the current position on the slider */
icon?: ThumbIcon,
/** Whether an options shows up in the UI. Useful for options that are managed programmatically. */
hidden?: boolean,
}
declare namespace ElementMetaData {
interface Typed { drawImage: boolean, hidden: boolean, imagePath: null | string }
interface Modular { drawImage: boolean, hidden: boolean, imagePath: null | string }
interface Vibrating { drawImage: false, hidden: false, imagePath: null }
interface Text {}
interface VariableHeight { icon: ThumbIcon }
type NoArch = ElementMetaData;
}
/** @see {@link ElementData} */
type ElementConfigData<MetaData extends ElementMetaData> = {
/** A 4-tuple with X & Y coordinates, width and height. */
position?: PartialRectTuple,
} & MetaData;
/**
* An interface with element coordinates and additional (archetype-specific metadata).
* @template MetaData A record with (archetype-specific) additional element metadata
* @see {@link ExtendedItemDrawData}
*/
type ElementData<MetaData extends ElementMetaData> = {
/** A 4-tuple with X & Y coordinates, width and height. */
position: RectTuple,
} & MetaData;
/** @see {@link ExtendedItemDrawData} */
interface ExtendedItemConfigDrawData<MetaData extends ElementMetaData> {
/** An array with two-tuples of X and Y coordinates for the buttons and, optionally, the buttons width and height */
elementData?: ElementConfigData<MetaData>[],
/** The number of buttons to be drawn per page */
itemsPerPage?: number,
}
/** @see {@link ExtendedItemDrawData} */
interface VariableHeightConfigDrawData extends ExtendedItemConfigDrawData<{}> {
elementData: { position: RectTuple, icon: ThumbIcon }[],
}
/** @see {@link ExtendedItemDrawData} */
interface NoArchConfigDrawData extends ExtendedItemConfigDrawData<ElementMetaData> {
elementData?: ElementData<ElementMetaData>[],
}
/**
* An interface with element-specific drawing data for a given screen.
* @template MetaData A record with (archetype-specific) additional element metadata
*/
interface ExtendedItemDrawData<MetaData extends ElementMetaData> extends Required<ExtendedItemConfigDrawData<MetaData>> {
/** A list of {@link ElementData} interfaces, one for each to-be drawn element (_e.g._ buttons) */
elementData: ElementData<MetaData>[],
/** The number of pages */
pageCount: number,
/** Whether pagination is required; i.e. if the number of buttons is larger than {@link ExtendedItemDrawData.itemsPerPage} */
paginate: boolean,
}
type ExtendedItemHeaderCallback<DataType extends ExtendedItemData<any>> = (
data: DataType,
C: Character,
item: Item,
) => string;
/** A record containing various dialog keys used by the extended item screen */
interface ExtendedItemDialog<
DataType extends ExtendedItemData<any>,
OptionType extends ExtendedItemOption,
> {
/** The dialogue prefix for the player prompt that is displayed on each module's menu screen */
header: string | ExtendedItemHeaderCallback<DataType>;
/** The dialogue prefix for the name of each module */
module?: string;
/** The dialogue prefix for the name of each option */
option?: string;
/** The dialogue prefix that will be used for each of the item's chatroom messages */
chat?: string | ExtendedItemChatCallback<OptionType>;
/** The prefix used for dialog keys representing an NPC's reactions to item type changes */
npc?: string | ExtendedItemNPCCallback<OptionType>;
}
/** A record containing various dialog keys used by the extended item screen */
interface ExtendedItemCapsDialog<
DataType extends ExtendedItemData<any>,
OptionType extends ExtendedItemOption,
> {
/** The dialogue prefix for the player prompt that is displayed on each module's menu screen */
Header?: string | ExtendedItemHeaderCallback<DataType>;
/** The dialogue prefix for the name of each module */
Module?: string;
/** The dialogue prefix for the name of each option */
Option?: string;
/** The dialogue prefix that will be used for each of the item's chatroom messages */
Chat?: string | ExtendedItemChatCallback<OptionType>;
/** The prefix used for dialog keys representing an NPC's reactions to item type changes */
Npc?: string | ExtendedItemNPCCallback<OptionType>;
}
/** Basic callback for extended item script hooks */
type ExtendedItemScriptHookCallback<DataType extends ExtendedItemData<any>, T extends any[], RT=void> = (
data: DataType,
originalFunction: null | ((...args: T) => RT),
...args: T,
) => RT;
type ExtendedItemScriptHookCallbackNoNull<DataType extends ExtendedItemData<any>, T extends any[], RT=void> = (
data: DataType,
originalFunction: ((...args: T) => RT),
...args: T,
) => RT;
/** Basic callback for extended item functions */
type ExtendedItemCallback<T extends any[], RT=void> = (
...args: T,
) => RT;
/** An interface-based version of {@link ExtendedItemScriptHookCallbacks} with decapitalized keys */
interface ExtendedItemScriptHookStruct<
DataType extends ExtendedItemData<any>,
OptionType extends ExtendedItemOption
> {
init: ExtendedItemScriptHookCallbacks.Init<DataType>,
load: ExtendedItemScriptHookCallbacks.Load<DataType>,
draw: ExtendedItemScriptHookCallbacks.Draw<DataType>,
click: ExtendedItemScriptHookCallbacks.Click<DataType>,
exit: null | ExtendedItemScriptHookCallbacks.Exit<DataType>,
validate: null | ExtendedItemScriptHookCallbacks.Validate<DataType, OptionType>,
publishAction: null | ExtendedItemScriptHookCallbacks.PublishAction<DataType, OptionType>,
setOption: null | ExtendedItemScriptHookCallbacks.SetOption<DataType, OptionType>,
beforeDraw: null | ExtendedItemScriptHookCallbacks.BeforeDraw<DataType>,
afterDraw: null | ExtendedItemScriptHookCallbacks.AfterDraw<DataType>,
scriptDraw: null | ExtendedItemScriptHookCallbacks.ScriptDraw<DataType>,
}
/** An interface-based version of {@link ExtendedItemScriptHookCallbacks} */
interface ExtendedItemCapsScriptHooksStruct<
DataType extends ExtendedItemData<any>,
OptionType extends ExtendedItemOption
> {
Init?: ExtendedItemScriptHookCallbacks.Init<DataType>,
Load?: ExtendedItemScriptHookCallbacks.Load<DataType>,
Draw?: ExtendedItemScriptHookCallbacks.Draw<DataType>,
Click?: ExtendedItemScriptHookCallbacks.Click<DataType>,
Exit?: ExtendedItemScriptHookCallbacks.Exit<DataType>,
Validate?: ExtendedItemScriptHookCallbacks.Validate<DataType, OptionType>,
PublishAction?: ExtendedItemScriptHookCallbacks.PublishAction<DataType, OptionType>,
SetOption?: ExtendedItemScriptHookCallbacks.SetOption<DataType, OptionType>,
BeforeDraw?: ExtendedItemScriptHookCallbacks.BeforeDraw<DataType>,
AfterDraw?: ExtendedItemScriptHookCallbacks.AfterDraw<DataType>,
ScriptDraw?: ExtendedItemScriptHookCallbacks.ScriptDraw<DataType>,
}
/** An interface-based version of {@link ExtendedItemCallbacks} with decapitalized keys*/
interface ExtendedItemCallbackStruct<
OptionType extends ExtendedItemOption
> {
init: ExtendedItemCallbacks.Init,
load: ExtendedItemCallbacks.Load,
draw: ExtendedItemCallbacks.Draw,
click: ExtendedItemCallbacks.Click,
exit?: ExtendedItemCallbacks.Exit,
validate?: ExtendedItemCallbacks.Validate<OptionType>,
publishAction?: ExtendedItemCallbacks.PublishAction<OptionType>,
setOption?: ExtendedItemCallbacks.SetOption<OptionType>,
beforeDraw?: ExtendedItemCallbacks.BeforeDraw,
afterDraw?: ExtendedItemCallbacks.AfterDraw,
scriptDraw?: ExtendedItemCallbacks.ScriptDraw,
}
/** Namespace with item-specific functions typically called by extended items. */
declare namespace ExtendedItemCallbacks {
/**
* Callback for extended item `Load` functions.
* `Load` functions are responsible for setting up the UI when initially opening the extended item menu.
*/
type Load = ExtendedItemCallback<[]>;
/**
* Callback for extended item `Draw` functions.
* `Draw` functions are responsible for drawing any UI elements within the extended item menu.
*/
type Draw = ExtendedItemCallback<[]>;
/**
* Callback for extended item `Click` functions.
* `Click` functions are responsible for managing any mouse clicks within the extended item menu.
*/
type Click = ExtendedItemCallback<[]>;
/**
* Callback for extended item `Exit` functions.
* `Exit` functions are responsible for cleaning up any UI elements when closing the extended item menu.
*/
type Exit = ExtendedItemCallback<[]>;
/**
* Callback for extended item `Validate` functions.
* `Validate` functions are responsible for validating any change in an item's properties.
* @param C The character that has the item equiped
* @param item The item in question
* @param newOption The newly selected extended item option
* @param previousOption The previusly selected extended item option
* @param permitExisting - Determines whether the validation should allow the new option and previous option
* to be identical. Defaults to false.
* @returns A non-empty message string if the item failed validation, or an empty string otherwise
*/
type Validate<
OptionType extends ExtendedItemOption
> = ExtendedItemCallback<[C: Character, item: Item, newOption: OptionType, previousOption: OptionType, permitExisting?: boolean], string>;
/**
* Callback for extended item `PublishAction` functions.
* `PublishAction` functions are responsible for reporting any changes to an item's properties via a chat message.
* @param C The character that has the item equiped
* @param item The item in question
* @param newOption The newly selected extended item option
* @param previousOption The previusly selected extended item option
*/
type PublishAction<
OptionType extends ExtendedItemOption
> = ExtendedItemCallback<[C: Character, item: Item, newOption: OptionType, previousOption: OptionType]>;
/**
* Callback for extended item `Init` functions.
* `Init` functions are responsible for setting the initial properties of an extended item.
* @param C The character that has the item equiped
* @param item The item in question
* @param push Whether to push to changes to the server
* @param refresh Whether to refresh the character. This should generally be `true`, with custom script hooks being a potential exception.
* @returns Whether the items properties were actually updated or not
*/
type Init = ExtendedItemCallback<[C: Character, item: Item, push: boolean, refresh: boolean], boolean>;
/**
* Callback for extended item `SetOption` functions.
* @param C The character that has the item equiped
* @param item The item in question
* @param newOption The newly selected extended item option
* @param previousOption The previusly selected extended item option
* @param push Whether to push to changes to the server
* @param refresh Whether to refresh the character. This should generally be `true`, with custom script hooks being a potential exception.
*/
type SetOption<
OptionType extends ExtendedItemOption
> = ExtendedItemCallback<[C: Character, item: Item, newOption: OptionType, previousOption: OptionType, push: boolean, refresh: boolean]>;
/**
* Callback for extended item `AfterDraw` functions.
* Relevant for assets that define {@link Asset.DynamicAfterDraw}.
* @param drawData The dynamic draw data
*/
type AfterDraw<
PersistentData extends Record<string, any> = Record<string, unknown>
> = ExtendedItemCallback<[drawData: DynamicDrawingData<PersistentData>]>;
/**
* Callback for extended item `BeforeDraw` functions.
* Relevant for assets that define {@link Asset.DynamicBeforeDraw}.
* @param drawData The dynamic draw data
* @returns A record with any and all to-be overriden draw data
*/
type BeforeDraw<
PersistentData extends Record<string, any> = Record<string, unknown>
> = ExtendedItemCallback<[drawData: DynamicDrawingData<PersistentData>], DynamicBeforeDrawOverrides>;
/**
* Callback for extended item `ScriptDraw` functions.
* Relevant for assets that define {@link Asset.DynamicScriptDraw}.
* @param drawData The dynamic draw data
*/
type ScriptDraw<
PersistentData extends Record<string, any> = Record<string, unknown>
> = ExtendedItemCallback<[drawData: DynamicScriptCallbackData<PersistentData>]>;
}
/**
* Namespace with item-specific script hooks used for constructing typical extended items functions.
* @see {@link ExtendedItemCallbacks}
*/
declare namespace ExtendedItemScriptHookCallbacks {
/**
* Callback for extended item `Load` script hooks.
* `Load` functions are responsible for setting up the UI when initially opening the extended item menu.
* @param data The items extended item data
* @param originalFunction The function that is normally called when an archetypical item reaches this point
*/
type Load<
DataType extends ExtendedItemData<any>
> = ExtendedItemScriptHookCallbackNoNull<DataType, []>;
/**
* Callback for extended item `Draw` script hooks.
* `Draw` functions are responsible for drawing any UI elements within the extended item menu.
* @param data The items extended item data
* @param originalFunction The function that is normally called when an archetypical item reaches this point
*/
type Draw<
DataType extends ExtendedItemData<any>
> = ExtendedItemScriptHookCallbackNoNull<DataType, []>;
/**
* Callback for extended item `Click` script hooks.
* `Click` functions are responsible for managing any mouse clicks within the extended item menu.
* @param data The items extended item data
* @param originalFunction The function that is normally called when an archetypical item reaches this point
*/
type Click<
DataType extends ExtendedItemData<any>
> = ExtendedItemScriptHookCallbackNoNull<DataType, []>;
/**
* Callback for extended item `Exit` script hooks.
* `Exit` functions are responsible for cleaning up any UI elements when closing the extended item menu.
* @param data The items extended item data
* @param originalFunction The function (if any) that is normally called when an archetypical item reaches this point
*/
type Exit<
DataType extends ExtendedItemData<any>
> = ExtendedItemScriptHookCallback<DataType, []>;
/**
* Callback for extended item `Validate` script hooks.
* `Validate` functions are responsible for validating any change in an item's properties.
* @param data The items extended item data
* @param originalFunction The function (if any) that is normally called when an archetypical item reaches this point
* @param C The character that has the item equiped
* @param item The item in question
* @param newOption The newly selected extended item option
* @param previousOption The previusly selected extended item option
* @param permitExisting - Determines whether the validation should allow the new option and previous option
* to be identical. Defaults to false.
* @returns A non-empty message string if the item failed validation, or an empty string otherwise
*/
type Validate<
DataType extends ExtendedItemData<any>,
OptionType extends ExtendedItemOption
> = ExtendedItemScriptHookCallback<DataType, [C: Character, item: Item, newOption: OptionType, previousOption: OptionType, permitExisting?: boolean], string>;
/**
* Callback for extended item `PublishAction` script hooks.
* `PublishAction` functions are responsible for reporting any changes to an item's properties via a chat message.
* @param data The items extended item data
* @param originalFunction The function (if any) that is normally called when an archetypical item reaches this point
* @param C The character that has the item equiped
* @param item The item in question
* @param newOption The newly selected extended item option
* @param previousOption The previusly selected extended item option
*/
type PublishAction<
DataType extends ExtendedItemData<any>,
OptionType extends ExtendedItemOption
> = ExtendedItemScriptHookCallback<DataType, [C: Character, item: Item, newOption: OptionType, previousOption: OptionType]>;
/**
* Callback for extended item `Init` script hooks.
* `Init` functions are responsible for setting the initial properties of an extended item.
* @param data The items extended item data
* @param originalFunction The function (if any) that is normally called when an archetypical item reaches this point
* @param C The character that has the item equiped
* @param item The item in question
* @param push Whether to push to changes to the server
* @param refresh Whether to refresh the character. This should generally be `true`, with custom script hooks being a potential exception.
* @returns Whether the items properties were actually updated or not
*/
type Init<
DataType extends ExtendedItemData<any>
> = ExtendedItemScriptHookCallbackNoNull<DataType, [C: Character, item: Item, push: boolean, refresh: boolean], boolean>;
/**
* Callback for extended item `SetOption` functions.
* @param data The items extended item data
* @param originalFunction The function that is normally called when an archetypical item reaches this point
* @param C The character that has the item equiped
* @param item The item in question
* @param newOption The newly selected extended item option
* @param previousOption The previusly selected extended item option
* @param push Whether to push to changes to the server
* @param refresh Whether to refresh the character. This should generally be `true`, with custom script hooks being a potential exception.
* @returns
*/
type SetOption<
DataType extends ExtendedItemData<any>,
OptionType extends ExtendedItemOption
> = ExtendedItemScriptHookCallback<DataType, [C: Character, item: Item, newOption: OptionType, previousOption: OptionType, push: boolean, refresh: boolean]>;
/**
* Callback for extended item `AfterDraw` functions.
* Relevant for assets that define {@link Asset.DynamicAfterDraw}.
* @param data The items extended item data
* @param originalFunction The function (if any) that is normally called when an archetypical item reaches this point
* @param drawData The dynamic draw data
*/
type AfterDraw<
DataType extends ExtendedItemData<any>,
PersistentData extends Record<string, any> = Record<string, unknown>
> = ExtendedItemScriptHookCallback<DataType, [drawData: DynamicDrawingData<PersistentData>]>;
/**
* Callback for extended item `BeforeDraw` functions.
* Relevant for assets that define {@link Asset.DynamicBeforeDraw}.
* @param data The items extended item data
* @param originalFunction The function (if any) that is normally called when an archetypical item reaches this point
* @param drawData The dynamic draw data
* @returns A record with any and all to-be overriden draw data
*/
type BeforeDraw<
DataType extends ExtendedItemData<any>,
PersistentData extends Record<string, any> = Record<string, unknown>
> = ExtendedItemScriptHookCallback<DataType, [drawData: DynamicDrawingData<PersistentData>], DynamicBeforeDrawOverrides>;
/**
* Callback for extended item `ScriptDraw` functions.
* Relevant for assets that define {@link Asset.DynamicScriptDraw}.
* @param data The items extended item data
* @param originalFunction The function (if any) that is normally called when an archetypical item reaches this point
* @param drawData The dynamic draw data
*/
type ScriptDraw<
DataType extends ExtendedItemData<any>,
PersistentData extends Record<string, any> = Record<string, unknown>
> = ExtendedItemScriptHookCallback<DataType, [drawData: DynamicScriptCallbackData<PersistentData>]>;
}
/** Union of all (archetype-specific) {@link ExtendedItemData.chatSetting} allowed values. */
type ExtendedItemChatSetting = "default" | TypedItemChatSetting | ModularItemChatSetting;
/**
* Abstract extended item data interface that all archetypical item data interfaces must implement.
* Archetypes are free to demand any appropriate subtype for a given property.
*/
interface ExtendedItemData<OptionType extends ExtendedItemOption> {
/** The archetype of the extended item data */
archetype: ExtendedArchetype;
/**
* The chat message setting for the item. This can be provided to allow
* finer-grained chatroom message keys for the item.
* Archetypes must use the `"default"` literal string as default value.
*/
chatSetting: ExtendedItemChatSetting;
/** A record containing various dialog keys used by the extended item screen */
dialogPrefix: ExtendedItemDialog<any, OptionType>;
/**
* A recond containing functions that are run on load, click, draw, exit, and validate, with the original archetype function
* and parameters passed on to them. If undefined, these are ignored.
* Note that scripthook functions must be loaded before `Female3DCGExtended.js` in `index.html`.
*/
scriptHooks: ExtendedItemScriptHookStruct<any, OptionType>;
/** The asset reference */
asset: Asset;
/** A key uniquely identifying the asset */
key: string;
/** The common prefix used for all extended item functions associated with the asset */
functionPrefix: string;
/** The common prefix used for all dynamic asset hook functions for the asset */
dynamicAssetsFunctionPrefix: string;
/** An array of the chat message tags that should be included in the item's chatroom messages. */
chatTags: CommonChatTags[];
/** Contains custom dictionary entries in the event that the base ones do not suffice. */
dictionary: ExtendedItemDictionaryCallback<OptionType>[];
/**
* To-be initialized properties independent of the selected item module(s).
* Relevant if there are properties that are (near) exclusively managed by {@link ExtendedItemData.scriptHooks} functions.
*/
baselineProperty: PropertiesNoArray.Item | null;
/** The extended item option of the super screen that this archetype was initialized from (if any) */
parentOption: null | ExtendedItemOption;
/** An interface with element-specific drawing data for a given screen. */
drawData: ExtendedItemDrawData<{}>;
/**
* A list with extra to-be allowed effect names.
* Should only defined when there are effects that are exclusively managed by script hooks and thus cannot be extracted from the normal extended item options.
*/
allowEffect: readonly EffectName[];
/**
* The unique name for this (sub)-screen used for the automatic construction of {@link ItemProperties.TypeRecord} keys.
* Names *should* be short.
*
* If not explicitly specified defaults to the name of {@link ExtendedItemData.parentOption}
* for sub screens and the name of the archetype in case of the (outer-most) super screen.
*/
name: string;
}
/** A struct-type that maps archetypes to their respective extended item data. */
interface ExtendedDataLookupStruct {
[ExtendedArchetype.TYPED]: TypedItemData;
[ExtendedArchetype.MODULAR]: ModularItemData;
[ExtendedArchetype.VIBRATING]: VibratingItemData;
[ExtendedArchetype.VARIABLEHEIGHT]: VariableHeightData;
[ExtendedArchetype.TEXT]: TextItemData;
[ExtendedArchetype.NOARCH]: NoArchItemData;
}
interface AssetOverrideHeight {
Height: number;
Priority: number;
HeightRatioProportion?: number;
}
/**
* The type for OverridePriority in extended items.
*
* Either a single number that will cause all of the asset's layer to
* inherit that priority, or a more precise specifier keyed by layer name.
*/
type AssetLayerOverridePriority = Record<string, number> | number;
/**
* Base properties of extended items derived from their respective {@link Asset} definition.
*
* Those are the properties the main game code enforces.
*/
interface AssetDefinitionProperties {
/**
* The difficulty of the item
* @see {@link Asset.Difficulty}
*/
Difficulty?: number;
/**
* ???
* @see {@link Asset.Attribute}
*/
Attribute?: AssetAttribute[];
/**
* Override the height of the item
* @see {@link Asset.OverrideHeight}
*/
OverrideHeight?: AssetOverrideHeight;
/**
* How much the character should be moved up
* @see {@link Asset.HeightModifier}
*/
HeightModifier?: number;
/**
* The drawing priority of the item
* @see {@link Asset.OverridePriority}
*/
OverridePriority?: AssetLayerOverridePriority;
/**
* The default color of the item.
* Used by extended items that need one of their layers to have a different per-type default color
* FIXME: That should be hoisted in the extended config, since it's set by the definition and {@link Item.Color} should be the actual colors used
* @see {@link Asset.DefaultColor}
*/
DefaultColor?: ItemColor;
/**
* A list of allowed activities
* @see {@link Asset.AllowActivity}
*/
AllowActivity?: ActivityName[];
/**
* A list of groups allowed activities
* @see {@link Asset.AllowActivityOn}
*/
AllowActivityOn?: AssetGroupName[];
/**
* Items that should be hidden by this item
* @see {@link Asset.HideItem}
*/
HideItem?: string[];
/**
* Items that should not be hidden by this item
* @see {@link Asset.HideItemExclude}
*/
HideItemExclude?: string[];
/**
* Items groups that should be hidden by this item
* @see {@link Asset.Hide}
*/
Hide?: AssetGroupName[];
/**
* The groups that this item blocks
* @see {@link Asset.Block}
*/
Block?: AssetGroupItemName[];
/**
* Effects that are applied by this item
* @see {@link Asset.Effect}
*/
Effect?: EffectName[];
/**
* A list of custom tints
* @see {@link Asset.Tint}
*/
Tint?: TintDefinition[];
// Pose-related properties
/**
* A list of poses that should forcefully be set
* @see {@link Asset.SetPose}
*/
SetPose?: AssetPoseName[];
/**
* A list of poses
* @see {@link Asset.AllowActivePose}
*/
AllowActivePose?: AssetPoseName[];
/**
* A list of allowed poses
* @see {@link Asset.AllowPose}
* @deprecated - Was never actually functional
*/
AllowPose?: never;
/**
* A list of poses
* @see {@link Asset.WhitelistActivePose}
* @deprecated Use {@link ItemProperties.AllowActivePose} instead
*/
WhitelistActivePose?: never;
/**
* A list of poses that should be frozen
* @see {@link Asset.FreezeActivePose}
* @deprecated Use {@link ItemProperties.AllowActivePose} instead
*/
FreezeActivePose?: never;
/**
* Whether an item can be unlocked by the player even if they're restrained
* @see {@link Asset.SelfUnlock}
*/
SelfUnlock?: boolean;
/**
* The timer for after how long until a lock should be removed.
* @see {@link Asset.RemoveTimer}
*/
RemoveTimer?: number;
/**
* The asset's draw opacity
* @see {@link Asset.Opacity}
*/
Opacity?: number | number[];
/**
* A custom background for this option that overrides the default
* @see {@link Asset.CustomBlindBackground}
*/
CustomBlindBackground?: string;
/**
* A list of fetishes affected by the item
* @see {@link Asset.Fetish}
*/
Fetish?: FetishName[];
}
/** A concatenation of a single {@link TypeRecord} key/value pair. */
type PartialType = `${string}${number}`;
/**
* A record mapping extended item data/module names (see {@link ExtendedItemData.Name} and {@link ModularItemModule.Key}) to option indices.
* @see {@link PartialType} A concatenation of a single `TypeRecord` key/value pair.
*/
type TypeRecord = Record<string, number>;
/**
* Properties for Expression Queue item
*/
interface ExpressionQueueItem {
Time?: number;
Group?: ExpressionGroupName;
Expression?: ExpressionName;
}
/**
* Base properties for extended items
*
* Those are the properties the main game code enforces.
*/
interface ItemPropertiesBase {
/**
* A string (or `null`) denoting the state of an extended item.
* How the type-string translate to concrete properties depends on the Archetype in question.
* @deprecated Superseded by {@link ItemPropertiesBase.TypeRecord}. Old type strings can be convert to records via {@link ExtendedItemTypeToRecord}.
*/
Type?: null | string;
/** A record mapping screen names to option indices. */
TypeRecord?: TypeRecord;
/** A facial expression */
Expression?: ExpressionName;
// Vibratory-related properties
/** The vibrator mode */
Mode?: VibratorMode;
/** The vibrator intensity */
Intensity?: VibratorIntensity;
/** The vibrator's state; only relevant for advanced vibrator modes */
State?: VibratorModeState;
/** KD modules */
// FIXME: Note that, as far as I can see, it's only ever set, never read
Modules?: number[];
}
/**
* Custom properties for extended items
*
* Those are properties that are asset-specific, so the handling might be done
* per-item.
*/
interface ItemPropertiesCustom {
/**
* The member number of the player adding the item.
* Only set if the asset is marked as {@link AssetDefinition.CharacterRestricted}.
*
* @deprecated Discontinued in favor of the {@link Asset.FamilyOnly}/{@link Asset.LoverOnly}/{@link Asset.OwnerOnly} trio
*/
ItemMemberNumber?: never;
//#region Lock properties
/** Asset name of the lock */
LockedBy?: AssetLockType;
/** The member number of the person that applied the lock */
LockMemberNumber?: number | string;
/** `/^[A-Z]{1,8}$/`, Used by `PasswordPadlock`, `SafewordPadlock` and `TimerPasswordPadlock` lock */
Password?: string;
/** Comma separated numbers */
LockPickSeed?: string;
/** `/^[0-9]{4}$/`, Used by `CombinationPadlock` lock */
CombinationNumber?: string;
/** Comma separated numbers; used by `HighSecurityPadlock` */
MemberNumberListKeys?: string;
/** Used by `PasswordPadlock`, `SafewordPadlock` and `TimerPasswordPadlock` locks */
Hint?: string;
/** Used by `PasswordPadlock`, `SafewordPadlock` and `TimerPasswordPadlock` locks; if the lock has been set with password */
LockSet?: boolean;
/** Whether to remove item on timer lock unlock; used by `LoversTimerPadlock`, `MistressTimerPadlock`, `OwnerTimerPadlock`, `TimerPadlock`, `TimerPasswordPadlock` */
RemoveItem?: boolean;
/** Only for `PasswordPadlock` */
RemoveOnUnlock?: boolean;
/** Whether time is shown or "Unknown time left"; used by `LoversTimerPadlock`, `MistressTimerPadlock`, `OwnerTimerPadlock`, `TimerPasswordPadlock` */
ShowTimer?: boolean;
/** Enable input; used by `LoversTimerPadlock`, `MistressTimerPadlock`, `OwnerTimerPadlock`, `TimerPasswordPadlock` */
EnableRandomInput?: boolean;
/** List of people who publicly modified time on lock; used by `LoversTimerPadlock`, `MistressTimerPadlock`, `OwnerTimerPadlock`, `TimerPasswordPadlock` */
MemberNumberList?: number[];
//#endregion
/** The inflation level of inflatable items */
InflateLevel?: 0 | 1 | 2 | 3 | 4;
/** The suction level of items with a suction effect */
SuctionLevel?: 0 | 1 | 2 | 3 | 4;
/** 1st line of text for user-entered text data */
Text?: string;
/** 2nd line of text for user-entered text data */
Text2?: string;
/** 3rd line of text for user-entered text data */
Text3?: string;
/** Whether the item blocks access to the butt */
LockButt?: boolean;
// #region Futuristic Set open permissions
/** Whether all players can use futuristic head devices */
OpenPermission?: boolean;
/** Whether all players can use futuristic arm devices */
OpenPermissionArm?: boolean;
/** Whether all players can use futuristic leg devices */
OpenPermissionLeg?: boolean;
/** Whether all players can use futuristic chastity devices */
OpenPermissionChastity?: boolean;
/** Whether the usage of remotes is blocked */
BlockRemotes?: boolean;
// #endregion
/** The futuristic bra's heart rate value */
HeartRate?: number;
// #region Futuristic gag & panel gag settings */
/** The item's auto-punishment sensitivity */
AutoPunish?: 0 | 1 | 2 | 3;
/** The remaining time for the gag's auto-inflation */
AutoPunishUndoTime?: number;
/** The default time for the gag's auto-inflation */
AutoPunishUndoTimeSetting?: 120000 | 300000 | 900000 | 3600000 | 72000000;
/** The gag module-index prior to triggering auto-inflation */
OriginalSetting?: 0 | 1 | 2 | 3;
/** Whether gag's blinking light is on or off */
BlinkState?: boolean;
/**
* An extended item option
* @todo Investigate whether this property still actually exists
*/
Option?: ExtendedItemOption;
// #endregion
// #region Futuristic chastity settings
/** Whether attempting to remove the belt should result in punishment */
PunishStruggle?: boolean;
/** Whether attempting to remove an item in general should result in punishment */
PunishStruggleOther?: boolean;
/** Whether orgasms should result in punishment */
PunishOrgasm?: boolean;
/** Whether standing up should result in punishment */
PunishStandup?: boolean;
/** Whether performing activities should result in punishment */
PunishActivity?: boolean;
/** The punishment for talking; represents an index of {@link FuturisticTrainingBeltSpeechPunishments} */
PunishSpeech?: 0 | 1 | 2 | 3;
/** The punishment for not speaking a required word; represents an index of {@link FuturisticTrainingBeltSpeechPunishments} */
PunishRequiredSpeech?: 0 | 1 | 2 | 3;
/** A string with comma-separated required words */
PunishRequiredSpeechWord?: string;
/** The punishment for speaking a prohibited word; represents an index of {@link FuturisticTrainingBeltSpeechPunishments} */
PunishProhibitedSpeech?: 0 | 1 | 2 | 3;
/** A string with comma-separated prohibited words */
PunishProhibitedSpeechWords?: string;
/** Internal cooldown timer for automatic shocks */
NextShockTime?: number;
/** The mode of the belts vibrator; represents an index of {@link FuturisticTrainingBeltModes} */
PublicModeCurrent?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
/** An integer denoting who can access the belt; represents an index of {@link FuturisticTrainingBeltPermissions} */
PublicModePermission?: 0 | 1 | 2;
// #endregion
/** A comma-separated string with the futuristic vibrator's trigger words */
TriggerValues?: string;
/** A string denoting who has permission to use the vibrator's trigger words */
AccessMode?: ItemVulvaFuturisticVibratorAccessMode;
/** How intense the shock should be */
ShockLevel?: 0 | 1 | 2;
/** The number of inserted beads */
InsertedBeads?: 1 | 2 | 3 | 4 | 5;
/** Whether the item displays a chat message to all other people in the room */
ShowText?: boolean;
/** Number of times the item was triggered; often used by shock collars */
TriggerCount?: number;
/** Modular Belt: Number of times the wearer had orgasm;*/
OrgasmCount?: number;
/** Modular Belt: Number of times the wearer had ruined orgasm;*/
RuinedOrgasmCount?: number;
/** Modular Belt: Amount of time since the item is being worn;*/
TimeWorn?: number;
/** Modular Belt: Amount of time since last detected orgasm;*/
TimeSinceLastOrgasm?: number;
/** Number of times the suitcase got cracked */
Iterations?: number;
/** Allows reverting back to these properties on exiting an extended menu */
Revert?: boolean;
/** Whether the kennel door is open */
Door?: boolean;
/** Whether the kennel has padding */
Padding?: boolean;
/** Only available as overrides on the script item */
UnHide?: AssetGroupName[];
/** Lucky Wheel: the section labels */
Texts?: string[];
/** Lucky Wheel: the angle the wheel should spin to */
TargetAngle?: number;
/** PortalLink: Used to link a remote to its target asset. */
PortalLinkCode?: string;
}
interface ItemProperties extends ItemPropertiesBase, AssetDefinitionProperties, ItemPropertiesCustom { }
/** All item/asset/group properties with all array-based values removed */
declare namespace PropertiesNoArray {
/** All {@link ItemProperties} properties with array-based values removed */
type Item = { [k in keyof ItemProperties as NonNullable<ItemProperties[k]> extends readonly any[] ? never : k]: ItemProperties[k] };
/** All {@link Asset} properties with array-based values removed */
type Asset = { [k in keyof globalThis.Asset as NonNullable<globalThis.Asset[k]> extends readonly any[] ? never : k]: globalThis.Asset[k] };
/** All {@link Group} properties with array-based values removed */
type Group = { [k in keyof AssetGroup as NonNullable<AssetGroup[k]> extends readonly any[] ? never : k]: AssetGroup[k] };
}
type PropertiesNoArray = PropertiesNoArray.Item & PropertiesNoArray.Asset & PropertiesNoArray.Group;
/** All item/asset/group properties with array-based values */
declare namespace PropertiesArray {
/** All {@link ItemProperties} properties with array-based values */
type Item = { [k in keyof ItemProperties as NonNullable<ItemProperties[k]> extends readonly any[] ? k : never]: ItemProperties[k] };
/** All {@link Asset} properties with array-based values */
type Asset = { [k in keyof globalThis.Asset as NonNullable<globalThis.Asset[k]> extends readonly any[] ? k : never]: globalThis.Asset[k] };
/** All {@link Group} properties with array-based values */
type Group = { [k in keyof AssetGroup as NonNullable<AssetGroup[k]> extends readonly any[] ? k : never]: AssetGroup[k] };
}
type PropertiesArray = PropertiesArray.Item & PropertiesArray.Asset & PropertiesArray.Group;
/**
* All item/asset/group properties with record-based values.
* @note This includes a number of somewhat unexpected values as arrays are treated as a record subtype.
*/
declare namespace PropertiesRecord {
/** All {@link ItemProperties} properties with record-based values. */
type Item = { [k in keyof ItemProperties as NonNullable<ItemProperties[k]> extends Record<string, any> ? k : never]: ItemProperties[k] };
/** All {@link Asset} properties with record-based values. */
type Asset = { [k in keyof globalThis.Asset as NonNullable<globalThis.Asset[k]> extends Record<string, any> ? k : never]: globalThis.Asset[k] };
/** All {@link Group} properties with record-based values. */
type Group = { [k in keyof AssetGroup as NonNullable<AssetGroup[k]> extends Record<string, any> ? k : never]: AssetGroup[k] };
}
type PropertiesRecord = PropertiesRecord.Item & PropertiesRecord.Asset & PropertiesRecord.Group;
//#endregion
/** An object containing modular item configuration for an asset. Contains all of the necessary information for the
* item's load, draw & click handlers.
*/
interface ModularItemData extends ExtendedItemData<ModularItemOption> {
archetype: "modular";
/**
* The item's chatroom message setting. Determines the level of
* granularity for chatroom messages when the item's module values change.
*/
chatSetting: ModularItemChatSetting;
/** The total number of types permitted by the item */
typeCount: number;
/** A record containing various dialog keys used by the extended item screen */
dialogPrefix: {
/** The dialogue prefix for the player prompt that is displayed on each module's menu screen */
header: string | ExtendedItemHeaderCallback<ModularItemData>;
/** The dialogue prefix for the name of each module */
module: string;
/** The dialogue prefix for the name of each option */
option: string;
/** The dialogue prefix that will be used for each of the item's chatroom messages */
chat: string | ExtendedItemChatCallback<ModularItemOption>;
};
/** The module definitions for the modular item */
modules: ModularItemModule[];
/** Name of currently active module */
currentModule: string;
/** A lookup for the current page in the extended item menu for each of the item's modules */
pages: Record<string, number>;
/** A lookup for the draw data for each of the item's modules */
drawData: ExtendedItemDrawData<ElementMetaData.Modular>;
/** A lookup for the draw functions for each of the item's modules */
drawFunctions: Record<string, () => void>;
/** A lookup for the click functions for each of the item's modules */
clickFunctions: Record<string, () => void>;
/**
* A recond containing functions that are run on load, click, draw, exit, and validate, with the original archetype function
* and parameters passed on to them. If undefined, these are ignored.
* Note that scripthook functions must be loaded before `Female3DCGExtended.js` in `index.html`.
*/
scriptHooks: ExtendedItemScriptHookStruct<ModularItemData, ModularItemOption>;
parentOption: null;
}
/** A 3-tuple containing data for drawing a button in a modular item screen. A button definition takes the
* format:
* ```
* [moduleOrOption, currentOption, prefix]
* ```
* The moduleOrOption is the to be drawn item module or option.
* The currentOption is currently active option within the relevant module.
* The prefix is the dialog prefix for the buttons text.
*/
type ModularItemButtonDefinition = [ModularItemOption | ModularItemModule, ModularItemOption, string]
//#endregion
//#region Typed Items
/**
* An object containing typed item configuration for an asset. Contains all of the necessary information for the item's
* load, draw & click handlers.
*/
interface TypedItemData extends ExtendedItemData<TypedItemOption> {
archetype: "typed";
drawData: ExtendedItemDrawData<ElementMetaData.Typed>;
/** The list of extended item options available for the item */
options: TypedItemOption[];
/** A record containing various dialog keys used by the extended item screen */
dialogPrefix: {
/** The dialog key for the item's load text (usually a prompt to select the type) */
header: string | ExtendedItemHeaderCallback<TypedItemData>;
/** The prefix used for dialog keys representing the display names of the item's types */
option: string;
/** The prefix used for dialog keys representing the item's chatroom messages when its type is changed */
chat: string | ExtendedItemChatCallback<TypedItemOption>;
/** The prefix used for dialog keys representing an NPC's reactions to item type changes */
npc: string | ExtendedItemNPCCallback<TypedItemOption>;
};
/**
* The chat message setting for the item. This can be provided to allow
* finer-grained chatroom message keys for the item. Defaults to {@link TypedItemChatSetting.TO_ONLY}
*/
chatSetting: TypedItemChatSetting;
/**
* A recond containing functions that are run on load, click, draw, exit, validate and publishaction,
* with the original archetype function and parameters passed on to them. If undefined, these are ignored.
* Note that scripthook functions must be loaded before `Female3DCGExtended.js` in `index.html`.
*/
scriptHooks: ExtendedItemScriptHookStruct<TypedItemData, TypedItemOption>;
parentOption: null;
}
//#region Validation
/**
* A parameter object containing information used to validate and sanitize character appearance update diffs. An
* appearance update has a source character (the player that sent the update) and a target character (the character
* being updated). What is allowed in an update varies depending on the status of the target character in relation to
* the source character (i.e. whether they are the target's lover/owner, or the target themselves, and also whether or
* not they have been whitelisted by the target).
*/
interface AppearanceUpdateParameters {
/** The character whose appearance is being updated */
C: Character;
/** Whether or not the source player is the same as the target player */
fromSelf: boolean;
/**
* Whether or not the source player has permissions to use owner-only items (i.e. they are either the target
* themselves, or the target's owner)
*/
fromOwner: boolean;
/**
* Whether or not the source player has permissions to use lover-only items (i.e. they are the target themselves,
* one of the target's lovers, or the target's owner, provided the target's lover rules permit their owner using
* lover-only items)
*/
fromLover: boolean;
/**
* Whether or not the source player has permissions to use family-only items (in same BDSM family)
*/
fromFamily: boolean;
/** The script permission levels that the source player has with respect to the receiver */
permissions: ScriptPermissionLevel[];
/** The member number of the source player */
sourceMemberNumber: number;
}
/**
* A map containing appearance item diffs, keyed according to the item group. Used to compare and validate before/after
* for appearance items.
*/
type AppearanceDiffMap = Partial<Record<AssetGroupName, [before: Item, after: Item]>>
/**
* A wrapper object containing the results of a diff resolution. This includes the final item that the diff resolved to
* (or null if the diff resulted in no item, for example in the case of item removal), along with a valid flag which
* indicates whether or not the diff was fully valid or not.
*/
interface ItemDiffResolution {
/**
* The resulting item after resolution of the item diff, or null if the diff resulted in no item being equipped in
* the given group
*/
item: Item | null;
/**
* Whether or not the diff was fully valid. In most cases, an invalid diff will result in the whole appearance
* update being rolled back, but in some cases the change will be accepted, but some properties may be modified to
* keep the resulting item valid - in both situations, the valid flag will be returned as false, indicating that a
* remedial appearance update should be made by the target player.
*/
valid: boolean;
}
/**
* A wrapper object containing the results of an appearance validation. Contains a sanitized appearance array and a
* valid flag which indicates whether or not the appearance was fully valid or not.
*/
interface AppearanceValidationWrapper {
/** The resulting appearance after validation */
appearance: Item[];
/**
* Whether or not the appearance was valid. A value of false indicates that the appearance has been modified, and a
* remedial appearance update should be made by the target player.
*/
valid: boolean;
}
//#endregion
//#region Vibrating items
interface VibratingItemData extends ExtendedItemData<VibratingItemOption> {
archetype: "vibrating";
drawData: ExtendedItemDrawData<ElementMetaData.Vibrating>;
/** The list of extended item options available for the item */
options: VibratingItemOption[];
/** The list with all groups of extended item options available for the item */
modeSet: VibratorModeSet[];
/** A record containing various dialog keys used by the extended item screen */
dialogPrefix: {
/** The dialog key for the item's load text (usually a prompt to select the type) */
header: string | ExtendedItemHeaderCallback<VibratingItemData>;
/** The dialogue prefix for the name of each option */
option: string;
/** The prefix used for dialog keys representing the item's chatroom messages when its type is changed */
chat: string | ExtendedItemChatCallback<VibratingItemOption>;
};
/**
* A record containing functions that are run on load, click, draw, exit, and validate, with the original archetype function
* and parameters passed on to them. If undefined, these are ignored.
* Note that scripthook functions must be loaded before `Female3DCGExtended.js` in `index.html`.
*/
scriptHooks: ExtendedItemScriptHookStruct<VibratingItemData, VibratingItemOption>;
chatSetting: "default";
}
/**
* A wrapper object defining a vibrator state and intensity
*/
interface StateAndIntensity {
/** The vibrator state */
State: VibratorModeState;
/** The vibrator intensity */
Intensity: VibratorIntensity;
}
//#endregion
//#region Variable Height items
/** The function that handles applying the height setting to the character */
type VariableHeightGetHeightCallback = (
property: ItemProperties,
) => number | null;
/** The function that handles finding the current variable height setting */
type VariableHeightSetHeightCallback = (
property: ItemProperties,
height: number,
maxHeight: number,
minHeight: number,
) => void;
/**
* An object containing typed item configuration for an asset. Contains all of the necessary information for the item's
* load, draw & click handlers.
*/
interface VariableHeightData extends ExtendedItemData<VariableHeightOption> {
archetype: "variableheight";
/** The highest Y co-ordinate that can be set */
maxHeight: number;
/** The lowest Y co-ordinate that can be set */
minHeight: number;
/** A record containing various dialog keys used by the extended item screen */
dialogPrefix: {
/** The dialog key for the item's load text (usually a prompt to select the type) */
header: string | ExtendedItemHeaderCallback<VariableHeightData>,
/** The prefix used for dialog keys representing the item's chatroom messages when its type is changed */
chat: string | ExtendedItemChatCallback<VariableHeightOption>;
/** The dialogue prefix for the name of each option */
option: string;
};
scriptHooks: ExtendedItemScriptHookStruct<VariableHeightData, VariableHeightOption>;
/** The function that handles finding the current variable height setting */
getHeight: VariableHeightGetHeightCallback;
/** The function that handles applying the height setting to the character */
setHeight: VariableHeightSetHeightCallback;
chatSetting: "default";
drawData: ExtendedItemDrawData<ElementMetaData.VariableHeight>;
}
//#endregion
// #region TextItem
interface TextItemData extends ExtendedItemData<TextItemOption> {
archetype: "text";
/** A record with the maximum length for each text-based properties with an input field. */
maxLength: TextItemRecord<number>;
/** A record containing various dialog keys used by the extended item screen */
dialogPrefix: {
/** The dialog key for the item's load text (usually a prompt to select the type) */
header: string | ExtendedItemHeaderCallback<TextItemData>,
/** The prefix used for dialog keys representing the item's chatroom messages when its type is changed */
chat: string | ExtendedItemChatCallback<TextItemOption>;
};
scriptHooks: ExtendedItemScriptHookStruct<TextItemData, TextItemOption>;
chatSetting: "default";
baselineProperty: PropertiesNoArray.Item;
eventListeners: TextItemRecord<TextItemEventListener>;
drawData: ExtendedItemDrawData<ElementMetaData.Text>;
pushOnPublish: boolean;
textNames: TextItemNames[];
/**
* The font used for dynamically drawing text.
* Requires {@link AssetDefinition.DynamicAfterDraw} to be set.
*/
font: null | string;
}
// NOTE: Use the intersection operator to enforce that the it remains a `keyof ItemProperties` subtype
/** Property keys of {@link ItemProperties} with text input fields */
type TextItemNames = keyof ItemProperties & (
"Text" | "Text2" | "Text3"
);
type TextItemRecord<T> = Partial<Record<TextItemNames, T>>;
/**
* A callback signature for handling (throttled) text changes.
* @param C - The character being modified
* @param item - The item being modified
* @param name - The property wherein the updated text should be stored
* @param text - The new text to be assigned to the item
*/
type TextItemEventListener = (
C: Character,
item: Item,
name: TextItemNames,
text: string,
) => void;
// #endregion
// #region noarch
interface NoArchItemData extends ExtendedItemData<NoArchItemOption> {
archetype: "noarch";
scriptHooks: ExtendedItemScriptHookStruct<NoArchItemData, NoArchItemOption>;
chatSetting: "default";
baselineProperty: null | ItemProperties;
drawData: ExtendedItemDrawData<ElementMetaData.NoArch>;
dialogPrefix: {
/** The dialog key for the item's load text (usually a prompt to select the type) */
header: string | ExtendedItemHeaderCallback<NoArchItemData>;
/** The prefix used for dialog keys representing the display names of the item's types */
option?: string;
/** The prefix used for dialog keys representing the item's chatroom messages when its type is changed */
chat?: string | ExtendedItemChatCallback<NoArchItemOption>;
}
}
// #endregion
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
interface ICommand {
Tag: string;
Description?: string;
Reference?: string;
Action?: (this: Optional<ICommand, 'Tag'>, args: string, msg: string, parsed: string[]) => void
Prerequisite?: (this: Optional<ICommand, 'Tag'>) => boolean;
AutoComplete?: (this: Optional<ICommand, 'Tag'>, parsed: string[], low: string, msg: string) => void;
Clear?: false;
}
// #region Struggle Minigame
type StruggleKnownMinigames = "Strength" | "Flexibility" | "Dexterity" | "Loosen" | "LockPick";
interface StruggleMinigame {
Setup: (C: Character, PrevItem: Item, NextItem: Item) => void;
Draw: (C: Character) => void;
HandleEvent?: (EventType: "KeyDown"|"Click", event: Event) => boolean;
DisablingCraftedProperty?: CraftingPropertyType;
}
interface StruggleCompletionData {
Progress: number;
PrevItem: Item;
NextItem?: Item;
Skill: number;
Attempts: number;
Interrupted: boolean;
Auto?: boolean;
}
type StruggleCompletionCallback = (character: Character, game: StruggleKnownMinigames, data: StruggleCompletionData) => void;
// #endregion
//#region Poker Minigame
type PokerGameType = "TwoCards" | "TexasHoldem";
type PokerMode = "" | "DEAL" | "FLOP" | "TURN" | "RIVER" | "RESULT" | "END";
type PokerPlayerType = "None" | "Set" | "Character";
type PokerPlayerFamily = "None" | "Player" | "Illustration" | "Model";
type PokerHand = number[];
interface PokerAsset {
Family: PokerPlayerFamily;
Type: PokerPlayerType;
Opponent: string[];
}
interface PokerPlayer {
Type: PokerPlayerType;
Family: PokerPlayerFamily;
Name: string;
Chip: number;
/* Runtime values */
Difficulty?: number;
Hand?: PokerHand;
HandValue?: number;
Cloth?: Item;
ClothLower?: Item;
ClothAccessory?: Item;
Panties?: Item;
Bra?: Item;
Character?: Character;
Data?: TextCache;
Image?: string;
TextColor?: string;
TextSingle?: TextCache;
TextMultiple?: TextCache;
Text?: string;
WebLink?: string;
Alternate?: number;
}
interface GamePokerParameters {
Challenge?: string;
}
interface GameClubCardParameters {
Deck: string[];
DeckName?: string[];
Reward?: string;
Status?: OnlineGameStatus;
PlayerSlot?: number;
}
interface GamePrisonParameters {
Timer?: number;
Role?: string;
}
//#endregion
// #region Online Games
/**
* Online game status values.
*
* @property "" - The game is in the setup phase.
* @property "Running" - The game is currently running.
*
* @fix FIXME: "" should really be renamed Setup
*/
type OnlineGameStatus = "" | "Running";
interface GameLARPParameters {
Status?: OnlineGameStatus;
Class?: string;
Team?: string;
TimerDelay?: number;
Level?: {
Name: string;
Level: number;
Progress: number;
}[];
}
type GameLARPOptionName = "Pass" | "Seduce" | "Struggle" | "Hide" | "Cover" |
"Strip" | "Tighten" | "RestrainArms" | "RestrainLegs" | "RestrainMouth" |
"Silence" | "Immobilize" | "Detain" | "Dress" | "Costume" | "";
interface GameLARPOption {
Name: GameLARPOptionName;
Odds: number;
}
interface GameMagicBattleParameters {
Status: OnlineGameStatus;
House: "Independent" | "NotPlaying" | "HouseMaiestas" | "HouseVincula" | "HouseAmplector" | "HouseCorporis";
TeamType: "FreeForAll" | "House";
}
interface GameGGTSParameters {
Level: number;
Time: number;
Strike: number;
Rule: string[];
}
// #endregion
// #region Audio
type AudioSoundEffect = [string, number];
interface AudioEffect {
/** The sound effect name */
Name: string;
/** The sound file, or files to choose from randomly */
File: string | string[];
}
/**
* Sound effect detector for chat messages.
*/
interface AudioChatAction {
/** Is that action applicable for that chat message? */
IsAction: (data: ServerChatRoomMessage) => boolean;
/** Extracts the actual sound effect from the chat message */
GetSoundEffect: (data: ServerChatRoomMessage, metadata: IChatRoomMessageMetadata) => (AudioSoundEffect | string | null);
}
// #endregion
// #region Character drawing
/** Options available to most draw calls */
type DrawOptions = {
/** Transparency between 0-1 */
Alpha?: number;
/** Area in original image to draw in format `[left, top, width, height]` */
SourcePos?: RectTuple;
/** Width of the drawn image, defaults to width of original image */
Width?: number;
/** Height of the drawn image, defaults to height of original image */
Height?: number;
/** If image should be flipped vertically */
Invert?: boolean;
/** If image should be flipped horizontally */
Mirror?: boolean;
/** Zoom factor */
Zoom?: number;
/* Color of the image to draw */
HexColor?: string;
/* Whether or not it is drawn in full alpha mode */
FullAlpha?: boolean;
/** A list of alpha masks to apply to the call */
readonly AlphaMasks?: readonly RectTuple[];
/** Blending mode for drawing the image */
BlendingMode?: GlobalCompositeOperation;
}
/**
* A callback function used for clearing a rectangular area of a canvas
* @param {number} x - The x coordinate of the left of the rectangle to clear
* @param {number} y - The y coordinate of the top of the rectangle to clear
* @param {number} w - The width of the rectangle to clear
* @param {number} h - The height of the rectangle to clear
*/
type ClearRectCallback = (x: number, y: number, w: number, h: number) => void;
/**
* A callback function used to draw a canvas on a canvas
* @param {HTMLImageElement | HTMLCanvasElement} Img - The canvas to draw
* @param {number} x - The x coordinate to draw the canvas at
* @param {number} y - The y coordinate to draw the canvas at
*/
type DrawCanvasCallback = (
img: HTMLImageElement | HTMLCanvasElement,
x: number,
y: number,
alphaMasks?: RectTuple[],
) => void;
/**
* A callback function used to draw an image to a canvas
* @param {string} src - The URL of the image to draw
* @param {number} x - The x coordinate to draw the image at
* @param {number} y - The y coordinate to draw the image at
* @param {RectTuple[]} [alphaMasks] - A list of alpha masks to apply to the image when drawing
* @param {number} [opacity=1] - The opacity at which to draw the image with
* @param {boolean} [rotate=false] - If the image should be rotated by 180 degrees
* @param {string} [blendingMode="source-over"] - blending mode for drawing the image
*/
type DrawImageCallback = (
src: string,
x: number,
y: number,
options?: DrawOptions
) => void;
/**
* A callback function used to draw a colorized image to a canvas
* @callback drawImageColorize
* @param {string} src - The URL of the image to draw
* @param {number} x - The x coordinate to draw the image at
* @param {number} y - The y coordinate to draw the image at
* @param {string} color - The color to apply to the image
* @param {boolean} fullAlpha - Whether or not to apply color to the entire image
* @param {RectTuple[]} [alphaMasks] - A list of alpha masks to apply to the image when drawing
* @param {number} [opacity=1] - The opacity at which to draw the image with
* @param {boolean} [rotate=false] - If the image should be rotated by 180 degrees
* @param {GlobalCompositeOperation} [blendingMode="source-over"] - blending mode for drawing the image
*/
type DrawImageColorizeCallback = (
src: string,
x: number,
y: number,
options?: DrawOptions
) => void;
interface CommonDrawCallbacks {
/**
* A callback to clear an area of the main character canvas
*/
clearRect: ClearRectCallback;
/**
* A callback to clear an area of the blink character canvas
*/
clearRectBlink: ClearRectCallback;
/**
* Function used to draw a canvas on top of the normal canvas
*/
drawCanvas: DrawCanvasCallback;
/**
* Function used to draw a canvas on top of the blink canvas
*/
drawCanvasBlink: DrawCanvasCallback;
/**
* A callback to draw an image to the main character canvas
*/
drawImage: DrawImageCallback;
/**
* A callback to draw an image to the blink character canvas
*/
drawImageBlink: DrawImageCallback;
/**
* A callback to draw a colorized image to the main character canvas
*/
drawImageColorize: DrawImageColorizeCallback;
/**
* A callback to draw a colorized image to the blink character canvas
*/
drawImageColorizeBlink: DrawImageColorizeCallback;
}
interface DynamicDrawingData<T extends Record<string, any> = Record<string, unknown>> {
C: Character;
X: number;
Y: number;
CA: Item;
GroupName: AssetGroupName;
Color: string;
Opacity: number;
Property: ItemProperties;
A: Asset;
G: string;
AG: AssetGroup;
L: string;
Pose: AssetPoseName;
LayerType: string;
BlinkExpression: string;
drawCanvas: DrawCanvasCallback;
drawCanvasBlink: DrawCanvasCallback;
AlphaMasks: RectTuple[];
PersistentData: () => T;
}
/**
* Drawing overrides that can be returned by a dynamic BeforeDraw function
*/
interface DynamicBeforeDrawOverrides {
Property?: ItemProperties;
CA?: Item;
GroupName?: AssetGroupName;
Color?: string;
Opacity?: number;
X?: number;
Y?: number;
LayerType?: string;
L?: string;
AlphaMasks?: RectTuple[];
Pose?: AssetPoseName;
}
type DynamicDrawTextEffect = "burn";
interface DynamicScriptCallbackData<T extends Record<string, any> = Record<string, unknown>> {
C: Character;
Item: Item;
PersistentData: () => T;
}
// #endregion
//#region Infiltration/Pandora
type InfiltrationMissionType = "Rescue" | "Kidnap" | "Retrieve" | "CatBurglar" | "ReverseMaid" | "Steal";
type InfiltrationTargetType = "NPC" | "USBKey" | "BDSMPainting" | "GoldCollar" | "GeneralLedger" | "SilverVibrator" | "DiamondRing" | "SignedPhoto" | "PandoraPadlockKeys";
interface InfiltrationMissionTarget {
Type: InfiltrationTargetType;
Name: string;
/** Whether the target was found */
Found?: boolean;
/** Whether the mission failed */
Fail?: boolean;
/** Whether this is an Rescue NPC mission from having a Private Room character kidnapped */
PrivateRoom?: boolean;
}
type PandoraDirection = "North" | "South" | "East" | "West";
type PandoraFloorDirection = "StairsUp" | "StairsDown" | PandoraDirection;
type PandoraFloors = "Ground" | "Second" | "Underground";
interface PandoraSpecialRoom {
Floor: "Exit" | "Search" | "Rest" | "Paint";
}
interface PandoraBaseRoom {
Floor: PandoraFloors;
Background: string;
Character: NPCCharacter[];
Path: (PandoraBaseRoom | PandoraSpecialRoom)[];
PathMap: PandoraBaseRoom[];
Direction: string[];
DirectionMap: PandoraFloorDirection[];
/* SearchRoom */
SearchSquare?: {
X: number;
Y: number;
W: number;
H: number;
}[];
ItemX?: number;
ItemY?: number;
/* PaintRoom */
Graffiti?: number;
}
//#endregion
//#region Crafting items
type CraftingMode = (
"Slot"
| "Name"
| "Color"
| "Extended"
| "Tighten"
| "OverridePriority"
);
type CraftingReorderType = "None" | "Select" | "Place";
/**
* A struct with an items crafting-related information.
* @see {@link Item.Craft}
*/
interface CraftingItem {
/** The name of the crafted item. */
Name: string;
/** The name of the crafter. */
MemberName?: string;
/** The member ID of the crafter. */
MemberNumber?: number;
/** The custom item description. */
Description: string;
/** The crafted item propery. */
Property: CraftingPropertyType;
/** The comma-separated color(s) of the item. */
Color: string;
/** The name of the lock or, if absent, an empty string. */
Lock: "" | AssetLockType;
/** The name of the item; see {@link Asset.Name}. */
Item: string;
/** Whether the crafted item should be private or not. */
Private: boolean;
/**
* The type of the crafted item; only relevant for extended items and should be an empty string otherwise.
* @deprecated superseded by {@link CraftingItem.TypeRecord}. Old type strings can be convert to records via {@link ExtendedItemTypeToRecord}.
* @see {@link ItemProperties.Type}
*/
Type?: string | null;
/**
* An integer (or `null`) representing the item layering priority; see {@link ItemProperties.OverridePriority}.
* @deprecated - superseded by {@link CraftingItem.ItemProperty}
*/
OverridePriority?: null | number;
/**
* A record with a select few (optional) extra item properties:
* * {@link ItemProperties.OverridePriority} in either its record or number form.
* * Properties as specified in {@link ExtendedItemData.baselineProperty}
*/
ItemProperty: ItemProperties | null;
/**
* A record for extended items mapping screen names to option indices.
* @see {@link ItemProperties.TypeRecord}
*/
TypeRecord?: null | TypeRecord;
/**
* Whether the crafting item is elligble for use.
* Only relevant if the player is the craft's owner but do they not own the underlying item (_e.g._ due to an inventory wipe).
*/
Disabled?: boolean;
/**
* A tighten-/loosen-specific modifier to-be added to the base difficulty[1] of the item
*
* [1] The sum of the asset difficulty, `Bondage` skill modifier and crafted property `Secure`/`Loose` modifiers.
*/
DifficultyFactor?: number;
}
/**
* A currently selected struct with an items crafting-related information.
* @see {@link Item.Craft}
*/
interface CraftingItemSelected {
/** The name of the crafted item. */
Name: string;
/** The custom item description. */
Description: string;
/**
* A tighten-/loosen-specific modifier to-be added to the base difficulty[1] of the item
*
* [1] The sum of the asset difficulty, `Bondage` skill modifier and crafted property `Secure`/`Loose` modifiers.
*/
DifficultyFactor: number;
/** The comma-separated color(s) of the item. */
Color: string;
/** The names of the crafted item's supported assets. */
Assets: readonly Asset[];
/**
* The first member of the {@link CraftingItemSelected.Assets} array.
*
* The asset is guaranteed to satisfy `Asset.Group.Name === Asset.DynamicGroupName` _if_ any of the list members satisfy this condition.
*/
get Asset(): Asset | undefined;
/** The crafted item propery. */
Property: CraftingPropertyType;
/** The lock as equiped on the item or, if absent, `null`. */
Lock: Asset | null;
/** Whether the crafted item should be private or not. */
Private: boolean;
/**
* A record for extended items mapping screen names to option indices.
* @see {@link ItemProperties.TypeRecord}
*/
TypeRecord: null | TypeRecord;
/**
* A record with a select few (optional) extra item properties:
* * {@link ItemProperties.OverridePriority} in either its record or number form.
* * Properties as specified in {@link ExtendedItemData.baselineProperty}
*/
ItemProperty: ItemProperties;
/** Get or set the `OverridePriority` property of {@link CraftingItemSelected.ItemProperty} */
get OverridePriority(): null | AssetLayerOverridePriority;
set OverridePriority(value: null | AssetLayerOverridePriority);
}
/**
* A struct with tools for validating {@link CraftingItem} properties.
* @property {function} Validate - The validation function
* @property {function} GetDefault - A function that creates default values for when the validation fails
* @property {CraftingStatusType} - The {@link CraftingStatusType} code for when the validation fails
*/
interface CratingValidationStruct {
Validate: (craft: CraftingItem, asset: Asset | null, checkPlayerInventory?: boolean) => boolean;
GetDefault: (craft: CraftingItem, asset: Asset | null, checkPlayerInventory?: boolean) => any;
StatusCode: CraftingStatusType;
}
//#endregion
//#region Color
/** An object defining a group of layers which can be colored together */
interface ColorGroup {
/** The name of the color group */
name: string;
/** The layers contained within the color group */
layers: AssetLayer[];
/** The color index for the color group - this is the lowest color index of any of the layers within the color group */
colorIndex: number;
}
/**
* A callback function that is called when the item color UI exits
* @param c - The character being colored
* @param item - The item being colored
* @param save - Whether the item's appearance changes should be saved
*/
type itemColorExitListener = (
c: Character,
item: Item,
save: boolean,
) => void;
interface ItemColorStateType {
colorGroups: ColorGroup[];
colors: string[];
/**
* The underlying assets default colors.
* @see {@link Asset.DefaultColor}
*/
defaultColors: readonly string[];
simpleMode: boolean;
paginationButtonX: number;
cancelButtonX: number;
saveButtonX: number;
colorPickerButtonX: number;
colorDisplayButtonX: number;
contentY: number;
groupButtonWidth: number;
pageSize: number;
pageCount: number;
colorInputWidth: number;
colorInputX: number;
colorInputY: number;
editOpacity: boolean;
exportButtonX: number;
importButtonX: number;
resetButtonX: number;
drawImport: () => Promise<string>;
drawExport: (data: string) => Promise<void>;
}
/** A hexadecimal color code */
type HexColor = string;
/** A HSV color value */
interface HSVColor {
H: number;
S: number;
V: number;
}
/** The color picker callback called when selection completes. */
type ColorPickerCallbackType = (Color: string) => void;
//#end region
// #region Log
interface LogRecord {
Name: LogNameType[LogGroupType];
Group: LogGroupType;
Value: number;
}
/** The logging groups as supported by the {@link LogRecord.Group} */
type LogGroupType = keyof LogNameType;
type LogNameAdvanced = (
`BlockScreen${string}`
| `BlockAppearance${string}`
| `BlockItemGroup${string}`
| `ForbiddenWords${string}`
);
/** An interface mapping {@link LogRecord.Group} types to valid {@link LogRecord.Name} types */
interface LogNameType {
Arcade: "DeviousChallenge",
Asylum: "Committed" | "Isolated" | "ForceGGTS" | "ReputationMaxed" | "Escaped",
BadGirl: "Caught" | "Joined" | "Stolen" | "Hide",
Cell: "Locked" | "KeyDeposit",
College: "TeacherKey",
Import: "BondageCollege",
Introduction: "MaidOpinion" | "DailyJobDone",
LockPick: "FailedLockPick",
LoverRule: "BlockLoverLockSelf" | "BlockLoverLockOwner",
MagicSchool: "Mastery",
Maid: "JoinedSorority" | "LeadSorority" | "MaidsDisabled",
MainHall: "IntroductionDone",
Management: "ClubMistress" | "ClubSlave" | "ReleasedFromOwner" | "MistressWasPaid",
"NPC-Amanda": "AmandaLover" | "AmandaCollared" | "AmandaCollaredWithCurfew" | "AmandaMistress",
"NPC-AmandaSarah": "AmandaSarahLovers",
"NPC-Jennifer": "JenniferLover" | "JenniferCollared" | "JenniferMistress" | "JenniferCollaredWithCurfew",
"NPC-Sarah": "SarahLover" | "SarahCollared" | "SarahCollaredWithCurfew",
"NPC-SarahIntro": "SarahWillBePunished" | "SarahCameWithPlayer",
"NPC-Sidney": "SidneyLover" | "SidneyMistress" | "SidneyCollared" | "SidneyCollaredWithCurfew",
"NPC-Julia": "Dominant" | "Submissive",
"NPC-Yuki": "Dominant" | "Submissive",
"NPC-Mildred": "Dominant" | "Submissive",
// NOTE: A number of owner rules can have arbitrary suffices, and can thus not be fully expressed as string literals
OwnerRule: (
"BlockChange"
| "BlockTalk"
| "BlockEmote"
| "BlockWhisper"
| "BlockChangePose"
| "BlockAccessSelf"
| "BlockAccessOther"
| "BlockKey"
| "BlockFamilyKey"
| "BlockOwnerLockSelf"
| "BlockRemote"
| "BlockRemoteSelf"
| "BlockNickname"
| "ReleasedCollar"
| "BlockScreen"
| "BlockAppearance"
| "BlockItemGroup"
| "ForbiddenWords"
| "BlockTalkForbiddenWords"
| LogNameAdvanced
),
Pony: "JoinedStable",
PonyExam: "JoinedStable",
PrivateRoom: (
"RentRoom"
| "Expansion"
| "SecondExpansion"
| "Wardrobe"
| "Cage"
| "OwnerBeepActive"
| "OwnerBeepTimer"
| "Security"
| "BedWhite"
| "BedBlack"
| "BedPink"
),
Rule: "BlockChange" | "LockOutOfPrivateRoom" | "BlockCage" | "SleepCage",
Sarah: "KidnapSophie",
Shibari: "Training",
SkillModifier: "ModifierDuration" | "ModifierLevel",
SlaveMarket: "Auctioned",
Trainer: "JoinedStable",
TrainerExam: "JoinedStable",
}
// #end region
// #region dialog
interface FavoriteState {
TargetFavorite: boolean;
PlayerFavorite: boolean;
Icon: FavoriteIcon;
UsableOrder: DialogSortOrder;
UnusableOrder: DialogSortOrder;
}
interface DialogInventoryItem extends Item {
Worn: boolean;
Icons: InventoryIcon[];
SortOrder: string;
Vibrating: boolean;
}
interface DialogSelfMenuOptionType {
Name: string;
IsAvailable: () => boolean;
Load?: () => void;
Draw: () => void;
Click: () => void;
}
// #end region
// #region Notification
type NotificationAudioType = 0 | 1 | 2;
type NotificationAlertType = 0 | 1 | 3 | 2;
type NotificationEventType = "ChatMessage" | "ChatJoin" | "Beep" | "Disconnect" | "Test" | "Larp";
interface NotificationSetting {
AlertType: NotificationAlertType,
Audio: NotificationAudioType,
}
interface NotificationData {
body?: string,
character?: Character,
useCharAsIcon?: boolean,
memberNumber?: number,
characterName?: string,
chatRoomName?: string,
}
// #end region
// #region preference
interface ActivityEnjoyment {
/** The relevant activity type */
Name: ActivityName,
/** The arousal factor for when the activity is performed on the player character */
Self: ArousalFactor,
/** The arousal factor for when the activity is performed on someone else */
Other: ArousalFactor,
}
interface ArousalZone {
/** The relevant zone */
Name: AssetGroupItemName,
/** The arousal factor associated with the zone */
Factor: ArousalFactor,
/** Whether one can orgasm from stimulating the zone */
Orgasm: boolean,
}
interface ArousalFetish {
/** The name of the fetish */
Name: FetishName,
/** The arousal factor associated with the fetish */
Factor: ArousalFactor,
}
/** The factor of the sexual activity (0 is horrible, 2 is normal, 4 is great) */
type ArousalFactor = 0 | 1 | 2 | 3 | 4;
interface ArousalSettingsType {
Active: ArousalActiveName;
Visible: ArousalVisibleName;
ShowOtherMeter: boolean;
AffectExpression: boolean;
AffectStutter: ArousalAffectStutterName;
VFX: SettingsVFXName;
VFXVibrator: SettingsVFXVibratorName;
VFXFilter: SettingsVFXFilterName;
Progress: number;
ProgressTimer: number;
VibratorLevel: 0 | 1 | 2 | 3 | 4;
ChangeTime: number;
Activity: string;
Zone: string;
Fetish: string;
OrgasmTimer?: number;
OrgasmStage?: 0 | 1 | 2;
OrgasmCount?: number;
DisableAdvancedVibes: boolean;
}
/** Preference Menu info for extensions settings*/
interface PreferenceExtensionsSettingItem {
/**
* The identifier of the extension.
* This is used to identify the extension and must be unique.
*/
Identifier: string;
/**
* The label for the extension button.
* If it's a Function, it will be called once when entering
* the extension setting menu. Use the return value as button text.
*/
ButtonText: string | (()=>string);
/**
* The image path of the extension.
*
* This is passed to {@link DrawButton} directly. You can use a `data` URL here.
*
* If it's a Function, it will be called once when entering
* the extension setting menu. Use the return value as image
* path.
* If it's undefined, there will be no image for the button
*/
Image?: string | (()=>string);
/**
* Called when the extension screen is about to be displayed.
*
* You can create your own HTML elements in here, or load your data.
*
* Note that HTML elements with the `HideOnPopup` class will be hidden
* automatically when a popup is shown.
*/
load?: () => void;
/**
* Called when a click happens on the extension screen.
*
* Note: your exit button handling *must* call {@link PreferenceSubscreenExit};
*/
click: () => void;
/**
* Called every frame while the extension screen is shown.
*/
run: () => void;
/**
* Called when the extension screen is about to be closed.
*
* Handles the unloading of the extension setting, usually when the user clicks the exit button,
* but it can also be called by the relog screen being triggered because of a disconnect.
*
* If you created any HTML elements in {@link PreferenceExtensionsSettingItem.load}, this is a good place to remove them.
*/
unload?: () => void;
/**
* Called when the extension screen is about to exit.
*
* Happens either through a click of the exit button, or the ESC key.
* This will **not** be called if a disconnect happens, so clean up should be
* done in {@link PreferenceExtensionsSettingItem.unload}.
*
* @returns {boolean | void} If you have some validation that needs to happen
* (for example, ensuring that a textfield contains a valid color code), return false;
* this will stop the subscreen from exiting.
* You might want to show a message to the user explaining why "nothing is happening" in that case,
* either through your own means or by setting `PreferenceMessage` to a string.
*
* If you return true or nothing, your screen's {@link PreferenceExtensionsSettingItem.unload} handler
* will be called afterward. And the setting screen for the extension will be closed.
*/
exit: () => boolean | void;
}
/** Preference Menu info for extensions settings*/
type PreferenceExtensionsMenuButtonInfo = {
Button: string;
Image?: string;
click: () => void;
}
// #end region
// #region fortune wheel
/** A union of valid wheel of fortune button colors */
type WheelFortuneColor = "Blue" | "Gold" | "Gray" | "Green" | "Orange" | "Purple" | "Red" | "Yellow";
/** Base type for fortune wheel options */
interface WheelFortuneOptionType {
/** A single-character UTF16 string with the option's ID */
ID: string;
/** The color of the option button */
Color: WheelFortuneColor;
/** An optional script that will be executed whenever the option is picked */
Script?: () => void;
}
// #end region
interface ClubCard {
ID: number;
Name: string;
ArrayIndex?: number;
Type?: string;
Title?: string;
Text?: string;
Prerequisite?: string;
Reward?: string;
RewardMemberNumber?: number;
MoneyPerTurn?: number;
FamePerTurn?: number;
RequiredLevel?: number;
Time?: number;
ExtraTime?: number;
ExtraDraw?: number;
ExtraPlay?: number;
Group?: string[];
Location?: string;
Negated?: boolean;
GlowTimer?: number;
GlowColor?: string;
OnPlay?: (C: ClubCardPlayer) => void;
BeforeTurnEnd?: (C: ClubCardPlayer) => void;
AfterTurnEnd?: (C: ClubCardPlayer) => void;
BeforeOpponentTurnEnd?: (C: ClubCardPlayer) => void;
AfterOpponentTurnEnd?: (C: ClubCardPlayer) => void;
CanPlay?: (C: ClubCardPlayer) => boolean;
/**
* @param C Player that owns the card and played a card
* @param Card that was played
*/
onPlayedCard?: (C: ClubCardPlayer, Card: ClubCard) => void;
/**
* @param C player that owns the card (not the one who played it in this case)
* @param Card the card that was played
*/
onOpponentPlayedCard?: (C: ClubCardPlayer, Card: ClubCard) => void;
/**
* Hook to run when card is removed from the board.
* @param C Player that owns the card
*/
onLeaveClub?: (C: ClubCardPlayer) => void;
turnStart?: (C: ClubCardPlayer) => void;
onLevelUp?: (C: ClubCardPlayer) => void;
}
interface ClubCardPlayer {
Character: Character;
Control: string;
Index: number;
Sleeve: string;
Deck: ClubCard[];
FullDeck: ClubCard[];
Hand: ClubCard[];
Board: ClubCard[];
Event: ClubCard[];
DiscardPile: ClubCard[];
Level: number;
Money: number;
Fame: number;
LastFamePerTurn?: number;
LastMoneyPerTurn?: number;
ClubCardTurnCounter: number;
CardsPlayedThisTurn: Record<number, ClubCard[]>
}
interface ClubCardMessage {
TextGetKey: string; // Localization key
MessageText?: string; // Message Text
MessageType: string; // Type of message (e.g., ACTION, SYSTEM, IMMEDIATE)
PlayerId: string; // ID of the player who triggered the message
TurnCounter: number; // Turn number when the message was created
Placeholders: { // Dynamic data for text replacement
[key: string]: string | number;
};
PlayerName?: string;
SourcePlayer?: string;
OpponentPlayer?: string;
}
// #region drawing
/** Drawing options for an item's preview box */
interface PreviewDrawOptions {
/** The character using the item (used to calculate dynamic item descriptions/previews) */
C?: Character;
/** The preview box description. */
Description?: string;
/** The background color to draw the preview box in - defaults to white */
Background?: string;
/** The foreground (text) color to draw the description in - defaults to black */
Foreground?: string;
/** Whether or not to add vibration effects to the item - defaults to false */
Vibrating?: boolean;
/** Whether or not to draw a border around the preview box */
Border?: boolean;
/** Whether or not the button should enable hover behavior (background color change) */
Hover?: boolean;
/** The background color that should be used on mouse hover, if any */
HoverBackground?: string;
/** Whether or not the element is disabled (prevents hover functionality) */
Disabled?: boolean;
/** A list of images to draw in the top-left of the preview box */
Icons?: readonly InventoryIcon[];
/** The crafted properties of the item */
Craft?: CraftingItem;
/** The width of the preview rectangle */
Width?: number;
/** The height of the preview rectangle */
Height?: number;
}
// #end region
// #region Chat Room Maps
interface ChatRoomView extends Pick<ScreenFunctions, "Run" | "MouseDown" | "MouseUp" | "MouseMove" | "MouseWheel" | "Click" | "Draw" | "KeyDown"> {
Activate?: () => void;
Deactivate?: () => void;
Draw: () => void;
DrawUi: () => void;
DisplayMessage: (data: ServerChatRoomMessage, msg: string, SenderCharacter: Character, metadata: IChatRoomMessageMetadata) => string|null;
SyncRoomProperties?: (data: ServerChatRoomSyncMessage) => void;
CanStartWhisper?: (C: Character) => boolean;
CanLeave?: () => boolean;
Screenshot: () => void;
}
type ChatRoomMapType = "Always" | "Hybrid" | "Never";
type ChatRoomMapPos = {
X: number;
Y: number;
}
type ChatRoomMapData = {
Pos: ChatRoomMapPos
PrivateState: Record<string, Object>
}
type ChatRoomMapDirection = "" | "R" | "L" | "D" | "U";
type ChatRoomMapObjectType = (
"FloorDecoration"
| "FloorDecorationThemed"
| "FloorDecorationParty"
| "FloorDecorationCamping"
| "FloorDecorationExpanding"
| "FloorDecorationAnimal"
| "FloorItem"
| "FloorObstacle"
| "WallDecoration"
| "WallPath"
);
type ChatRoomMapTileType = "Floor" | "FloorExterior" | "Wall" | "Water";
interface ChatRoomMapDoodad {
ID: number;
Style: string;
OccupiedStyle?: "WoodOpen" | "MetalOpen";
CanEnter?: (direction: ChatRoomMapDirection) => boolean;
OnEnter?: () => void;
}
interface ChatRoomMapTile extends ChatRoomMapDoodad {
Type: ChatRoomMapTileType;
Transparency?: number;
TransparencyCutoutHeight?: number;
BlockVision?: boolean;
BlockHearing?: boolean;
}
interface ChatRoomMapObject extends ChatRoomMapDoodad {
Type: ChatRoomMapObjectType;
Top?: number;
Left?: number;
Width?: number;
Height?: number;
Transparency?: number;
TransparencyCutoutHeight?: number;
Exit?: boolean;
Unique?: boolean;
AssetGroup?: AssetGroupItemName;
AssetName?: string;
BlockVision?: boolean;
BlockHearing?: boolean;
IsVisible?: () => boolean;
BuildImageName?: (X: number, Y: number) => string;
}
interface ChatRoomMapMovement {
X: number;
Y: number;
Direction: "West" | "East" | "North" | "South";
TimeStart: number;
TimeEnd: number;
}
// #endregion
// #region shop
/** The current shop mode */
type ShopMode = "Buy" | "Sell" | "Preview" | "Color" | "Extended" | "Layering";
/** The current dressing state of the preview character */
type ShopClothesMode = "Clothes" | "Underwear" | "Cosplay" | "Nude";
/** The currently active dropdown menu */
type ShopDropdownState = "None" | "Group" | "Pose";
interface ShopScreenFunctions extends Omit<Partial<ScreenFunctions>, "Draw"> {
Draw(...coords: RectTuple): void,
/** Coordinates associated with a particular to-be drawn/clicked element */
Coords: RectTuple,
/** A set of shop modes for which the screen functions must be active */
Mode: Set<ShopMode>,
}
interface ShopItem {
/** The underlying asset */
readonly Asset: Asset,
/** The assets sorting priority within the asset list; lower values take priority */
readonly SortPriority: number,
/** Whether an item should never be able to be sold */
readonly NeverSell: boolean,
/** Whether the asset can be bought; `false` implies that it can be sold */
Buy: boolean,
}
// #endregion
// #region layering
interface LayeringExitOptions {
screen?: string;
callback?: (C: Character, item: Item) => void;
}
/** Various display options for the layering screen */
interface LayeringDisplay extends Rect {
/** The gap between buttons */
buttonGap: number;
}
// #endregion
// #region deprecation
/** @deprecated superseded by {@link PoseAvailable} */
declare const CharacterItemsHavePoseAvailable: never;
/** @deprecated superseded by {@link PoseAvailable} */
declare const InventoryPrerequisiteCanChangeToPose: never;
/** @deprecated superseded by {@link PoseSetByItems} */
declare const CharacterItemsHavePose: never;
/** @deprecated superseded by {@link PoseSetByItems} */
declare const CharacterDoItemsSetPose: never;
/** @deprecated superseded by {@link PoseCategoryAvailable} */
declare const CharacterItemsHavePoseType: never;
/** @deprecated superseded by {@link PoseRefresh} */
declare const CharacterLoadPose: never;
/** @deprecated superseded by {@link PoseToMapping} */
declare const AssetPoseToMapping: never;
/** @deprecated superseded by {@link InventoryPrerequisiteConflicts.GagPrerequisite} */
declare const InventoryPrerequisiteConflictingGags: never;
/** @deprecated the chat log is now hidden via {@link ChatRoomHideElements}; use {@link ChatRoomShowElements} to unhide it */
declare const RelogChatLog: never;
/** @deprecated the chat log is now hidden via {@link ChatRoomHideElements}; use {@link ChatRoomShowElements} to unhide it */
declare const RelogInputText: never;