MBCHC/ambient.d.ts

472 lines
14 KiB
TypeScript
Raw Normal View History

interface ServerChatRoomMessage {
MBCHC_ID?: number
}
namespace BCE {
interface Matcher {
Tester: RegExp
Criteria?: {
TargetIsPlayer?: boolean
SenderIsPlayer?: boolean
DictionaryMatchers?: Array<OBJ<string>>
}
}
interface Trigger {
Event: string
Type: 'Emote' | 'Activity' | 'Action'
Matchers: Matcher[]
}
interface Patcher {
timer: number | undefined
patches: Array<[RegExp, string]>
cfs: {[k in 'anim' | 'pose']: () => Iterable<string>}
gen: (comp_func: () => Iterable<string>) => (this: Optional<ICommand, 'Tag'>) => undefined
copy(t: Trigger): Trigger
patch(): true | undefined
}
}
type SUBCOMMANDS = {
[k: string]: {
desc: string
args?: {[n: string]: OBJ}
cb: (mbchc: Window['MBCHC'], args: string[], __: unknown, ___?: unknown) => void
}
};
interface Window {
MBCHC: {
loader: () => void
DO_DATA: {
zones: OBJ<string>
verbs: {
[verb: string]: {
[zone: string]: {
self: string[]
others: string[]
}
}
}
}
MAP_ACTIONS: {
[verb: string]: {
[zones: string]: {
all?: string
self?: string
others?: string
}
}
}
MAP_ZONES: {[zone: string]: string[]}
LOADED: boolean
NEXT_MESSAGE: number
LOG_MESSAGES: boolean
LAST_HACKED: number | undefined
version: string
VERSION: string
Settings: Settings.Methods
TZ: TZ_Cache
SUBCOMMANDS_MBCHC: SUBCOMMANDS
H: InputHistory
U: Utils
AUTOHACK_ENABLED: boolean
RE_PREF_ACTIVITY_ME: RegExp
RE_PREF_ACTIVITY: RegExp
RE_ACT_CIDS: RegExp
RE_LAST_WORD: RegExp
RE_LAST_LETTER: RegExp
RE_ACTIVITY: RegExp
UTC_OFFSET: number
calculate_maps(): void
normalise_message(text: string, options?: OBJ<boolean>): string
donate_data(target: string): void
run_activity(char: Character, ag: AssetGroupItemName, action: ActivityName): void
send_activity(message: string): void
set_timezone(args: string[]): number | undefined
command_mbchc(this: Optional<ICommand, 'Tag'>, args: string, msg: string, parsed: string[]): undefined
command_activity(this: Optional<ICommand, 'Tag'>, args: string, msg: string, parsed: string[]): undefined
command_do(this: Optional<ICommand, 'Tag'>, args: string, msg: string, parsed: string[]): undefined
}
bcModSdk?: import('./node_modules/bondage-club-mod-sdk/dist/bcmodsdk.d.ts').ModSDKGlobalAPI;
FBC_VERSION?: string
bce_ActivityTriggers?: BCE.Trigger[]
bce_EventExpressions?: OBJ
}
type OBJ<T = unknown> = Record<string, T>;
type FUN = (...args: never[]) => unknown;
/**
* Stands for "Value or Function". Not remotely ideal, but the best I can come up with.
*/
type VOF<F extends FUN> = undefined | boolean | number | bigint | string | symbol | OBJ | Set<unknown> | Map<unknown, unknown> | FP.Interval | F;
/**
* I can write Haskell in every language.
* I was unbelievably tempted to go with emojis here, but I'm not a monster of this caliber.
* @see https://8fw.me/hell/a8aaaefcb6e30ec4b2e398c70d49b72a6b53232f.png
*/
namespace FP {
interface Interval {
proxy: object // eslint-disable-line @typescript-eslint/ban-types
min: number
max: number
mini: boolean
maxi: boolean
has(_: unknown, x: string): boolean
}
interface Pipeline<T> {
proxy: PipelineProxy<T>
me<N>(iterable: Iterable<N>): PipelineProxy<N>
[Symbol.iterator](): Iterator<T>
rdc<R>(initial: R, func: (accumulator: R, value: T) => R): R
any(func: (v: T) => boolean): boolean
all(func: (v: T) => boolean): boolean
map<R>(func: (value: T) => R): PipelineProxy<R>
sel(func: (value: T) => boolean): PipelineProxy<T>
}
interface PipelineProxy<T> extends Pipeline<T> {
[i: number]: T | undefined
}
/**
* Creates an iteration pipeline.
*/
type P = <T>(iterable: Iterable<T>) => PipelineProxy<T>;
/**
* A silly helper to kinda c[au]rry values. Basically equivalent to:
* `const a = value; return func(a)`
* Stands for "Carry, Use, Return".
*/
type cur = <T, R>(value: T, func: (value: T) => R) => R;
/**
* Convert `null` to `undefined`.
*/ // eslint-disable-next-line @typescript-eslint/ban-types
type n2u = <T>(value: T | undefined | null) => T | undefined;
/**
* Enumerate keys of an object. Type-safe, also shorter.
*/
type enu = <O extends OBJ>(object: O) => Array<keyof O>;
/**
* Like `carry()` but does nothing if `value` is `null` or `undefined`.
* Something like an `Option<>` when you want to just pass `undefined` along, but
* run a function on actual values. Also coverts `null` to `undefined`.
*/ // eslint-disable-next-line @typescript-eslint/ban-types
type val = <T, R>(value: T | null | undefined, func: (value: T) => R) => R | undefined;
/**
* `+` as a function
*/
type add = (x: number, y: number) => number;
/**
* `-` as a function
*/
type sub = (x: number, y: number) => number;
/**
* `>` as a function
*/
type cgt = (x: number, y: number) => boolean;
/**
* `>=` as a function
*/
type cge = (x: number, y: number) => boolean;
/**
* `<` as a function
*/
type clt = (x: number, y: number) => boolean;
/**
* `<=` as a function
*/
type cle = (x: number, y: number) => boolean;
/**
* Converts a string into a base 10 integer. Not only is it shorter than `Number.parseInt`,
* it also converts `NaN` to `undefined`, because I find it much easier to only have
* one nil value for everything.
*/
type int = (text: string) => number | undefined;
/**
* This is a type assertion helper for Typescript. Probably not very useful in general.
*/
type fun = <F extends FUN>(func: unknown) => func is F;
/**
* Takes anything, ignores non-functions, calls functions with supplied parameters.
*/
type run = <F extends FUN>(functions_or_values: Array<VOF<F>>, ...args: Parameters<F>) => true;
/**
* Takes anything, ignores non-functions, calls functions with `undefined` as a single parameter.
*/
type yes = (...args: Array<VOF<(_: undefined) => unknown>>) => true;
/**
* Takes anything, ignores non-functions, calls functions with a single provided parameter.
* Always returns the parameter itself.
*/
type mut = <T>(value: T, ...args: Array<VOF<(value: T) => unknown>>) => T;
/**
* `delete` as a function
*/ // eslint-disable-next-line @typescript-eslint/ban-types
type del = <T extends object>(object: T, property: keyof T) => T;
/**
* Short for `assert`. Throws, if value is `undefined`, or if `condition(value)` is false.
*/
type ass = <T>(error: string, value: T | undefined, condition?: (value: T) => boolean) => T | never;
/**
* Casts value as a given prototype or returns undefined.
*/
type asa = <T>(prototype: new () => T, value: unknown) => T | undefined;
/**
* `catch` as a function. Short for `rescue`.
*/
type rsc = (operation: (_: undefined) => unknown, exception_handler: (error: unknown) => unknown) => true;
/**
* Returns a proxy for `in` operator.
* Use it like `2 in rng(0, 4)`.
*/ // eslint-disable-next-line @typescript-eslint/ban-types
type rng = (min: number, max: number, min_inclusive?: boolean, max_inclusive?: boolean) => object;
/**
* Something slightly better than `Boolean()`.
* True is `null`, `undefined`, `false`, empty strings, sets, maps, arrays and objects.
* Short for "empty".
*/
type m_t = (value: unknown) => boolean;
/**
* `while()` as a function. Executes the second callback while the first one is true.
* Always bound by max number of iterations.
* Returns the last value from the action or undefined if the action never ran.
*/
type loo = <T>(max: number, condition: (_: undefined) => boolean, action: (_: undefined) => T) => T | undefined;
}
namespace SDK {
type GDPT<F> = import('./node_modules/bondage-club-mod-sdk/dist/bcmodsdk.d.ts').GetDotedPathType<typeof globalThis, F>;
type Void<F extends FUN> = (...args: Parameters<F>) => unknown;
type Hook = <F extends string>(name: F, hook: Void<GDPT<F>>) => () => unknown;
}
namespace Cons {
type MS = {w: 'warn', i: 'info', d: 'debug', l: 'log'};
type E = (error: unknown) => true;
type F = (message: string) => true;
interface Wrap {
readonly ms: MS
e: E
w: F
i: F
d: F
l: F
gen: (m: keyof MS) => F
}
}
namespace Settings {
/**
* The whole `Player.OnlineSettings`.
*/
type V0 = PlayerOnlineSettings & {MBCHC?: {timezones?: Record<number, number>}};
/**
* Specifically `MBCHC` inside `Player.ExtensionSettings`.
*/
interface V1 {
TZ: Record<number, number>
}
interface Methods {
migrate_0_1(v0: V0): true
save(func?: (v1: V1) => unknown): true
replace(new_v1: V1): true
'purge!'(): true
get v0(): V0 | undefined
get v1(): V1
}
}
/**
* We need a place to cache the timezones instead of the `Character` object itself.
*/
interface TZ_Cache {
map: Map<number, number>
RE: RegExp
parse(description: string | undefined): number | undefined
memo(member_number: number, description?: string | undefined): number | undefined
lookup(character: Character): number | undefined
}
interface Utils {
remove_loader_hook: (() => unknown) | undefined
RE: {SPACES: RegExp, REL: {L: RegExp, R: RegExp}, '@': [RegExp, RegExp]}
RGB: {Polly: string, Mute: string}
ACT: string,
get crc(): Character[]
get ic(): HTMLTextAreaElement | undefined
cid(character: Character): number | undefined
dn(character: Character): string
current(): string
style<T>(query: string, func: (s: CSSStyleDeclaration) => T): T | undefined
inform(html: string): true
report(error: unknown): true
/**
* Splits a string into words by continuous whitespace sequences. Some examples:
* ```
* "" => [""]
* " " => ["", ""]
* "f g" => ["f", "g"]
* " f g " => ["", "f", "g", ""]
* ```
*/
split(text: string): string[]
abs2char(index: number): Character
rel2char(target: string): Character
cid2char(cid: number): Character
target2char(target: string): Character
mkdiv(html?: string): HTMLDivElement
bell(): true
targets(me2?: boolean, check_perms?: boolean): Set<string>
complete_mbchc(this: Optional<ICommand, 'Tag'>): undefined
complete_do_target(actions: {self: unknown, others: unknown}): Set<string>
complete_do(this: Optional<ICommand, 'Tag'>): undefined
replace_me(_match: string, _offset: number, whole: string): string
2024-09-03 16:34:24 +00:00
scroll(): true
get scrolled(): boolean
rescroll(func: (_: undefined) => unknown): true
}
interface Complete {
S_OPTS: {behavior: 'instant'}
/**
* The suggestions panel.
* Its structure is (outer div) -> (container div) -> (multiple suggestion div elements)
*/
e: HTMLDivElement
/**
* The container div.
*/
get div(): Element | undefined
/**
* Longest common prefix, or an empty string for an empty set.
*/
lcp(candidates: Set<string>): string
/**
* !WARNING! Mutate the given set in accordance with the input.
* Returns the input with completion done and removes all failed candidates.
* If the set is empty, the completion failed and the result is the unmodified input.
* If the set has more than one value, these are all new candidates, and the input was completed with the lcp.
* Otherwise, the only successful candidate will remain in the set and the input was completed to it.
*/
complete_word(input: string, candidates: Set<string>, ignore_case?: boolean | undefined): string
/**
* Show the suggestions to the user.
*/
hint(candidates: Set<string>): true
/**
* Returns false if the suggestion panel is visible.
*/
get hidden(): boolean
/**
* Makes the suggestions panel disappear.
*/
hide(): true
/**
* The whole deal. Will read and modify the chat input window.
* Takes a callback that will receive current input split into words
* and should return all possible candidates for the word being completed.
* Note: if the input ends with whitespace, the last word will be empty.
*/
complete(func: (words: string[]) => Set<string>, ignore_case?: boolean | undefined): true
/**
* Case-insensitive complete.
*/
icomplete(func: (words: string[]) => Set<string>): true
}
/**
* So, this is what happens. We have two modes: input mode and history mode. In the history mode the element is read-only.
* In the input mode:
* If the input is empty, we just scroll the history as usual
* Otherwise, we build a history set using the input as prefix
* The history set filters through the history, keeping only unique lines that start with the prefix along with indices
* But we exclude lines that match the input exactly
* It keeps the original input in a separate place too
* If the set is empty, we bell out
* Otherwise, we enter the history mode and invoke the first search
* In the history mode:
* We search up or down, using the index as a starting point for the next match, treating the set as a ring
* If the found line is the same as the current line, we bell out
* Upon finding a next match, we replace the input with its text and set the index appropriately
* We exit the history mode using the InputChat keydown handler, on Tab, Escape or Enter
* Escape restores the saved input, discarding the history line
* Tab keeps the current text and unlocks the element, allowing it to be edited
* Enter keeps the current text and sends it as the message as usual
*/
interface InputHistory {
/**
* Whether the chat log is scrolled to the end when we enter history mode.
*/
bottom: boolean | undefined
/**
* The initial user input when we enter the history mode.
*/
input: string | undefined
/**
* The indices of the lines that match the prefix.
*/
ids: Set<number> | undefined
2024-09-03 16:34:24 +00:00
/**
* Specific key handlers.
*/
key: Record<string, (event: KeyboardEvent, textarea: HTMLTextAreaElement) => true>
2024-09-03 16:34:24 +00:00
/**
* Set or unset the readonly mode on the input.
*/
icro(textarea: HTMLTextAreaElement, readonly: boolean): true
/**
* Enter the history mode.
*/
enter(textarea: HTMLTextAreaElement, input: string, bottom: boolean, ids: Set<number>): true
/**
2024-09-03 16:34:24 +00:00
* Exit the history mode and proc the key event.
*/
exit(textarea: HTMLTextAreaElement, e: KeyboardEvent): true
}
// FIXME spread around readonly where appropriate