2022-07-04 22:07:57 +00:00
// ==UserScript==
// @name MBCHC-local
// @version trunk
// @description Mute's Bondage Club Hacks Collection (development version)
// @author codename.mute@proton.me
// @namespace https://code.fleshless.org/mute/
// @homepage https://code.fleshless.org/mute/MBCHC
2022-07-07 23:10:18 +00:00
// @updateURL https://code.fleshless.org/mute/MBCHC/raw/branch/master/mbchc-local.user.js
// @downloadURL https://code.fleshless.org/mute/MBCHC/raw/branch/master/mbchc-local.user.js
2022-07-04 22:07:57 +00:00
// @match https://bondageprojects.elementfx.com/R*
// @match https://www.bondageprojects.elementfx.com/R*
// @match https://bondage-europe.com/R*
// @match https://www.bondage-europe.com/R*
2022-11-03 18:17:20 +00:00
// @match http://localhost:*/*
// @match http://127.0.0.1:*/*
2022-07-04 22:07:57 +00:00
// @grant none
// ==/UserScript==
// Bondage Club Mod Development Kit (1.0.2)
// For more info see: https://github.com/Jomshir98/bondage-club-mod-sdk
/** @type {ModSDKGlobalAPI} */ // eslint-disable-next-line
2022-11-07 04:52:25 +00:00
; ( function ( ) { "use strict" ; const o = "1.0.2" ; function e ( o ) { alert ( "Mod ERROR:\n" + o ) ; const e = new Error ( o ) ; throw console . error ( e ) , e } const t = new TextEncoder ; function n ( o ) { return ! ! o && "object" == typeof o && ! Array . isArray ( o ) } function r ( o ) { const e = new Set ; return o . filter ( ( o => ! e . has ( o ) && e . add ( o ) ) ) } const a = new Map , i = new Set ; function d ( o ) { i . has ( o ) || ( i . add ( o ) , console . warn ( o ) ) } function c ( o , e ) { if ( 0 === e . size ) return o ; let t = o . toString ( ) . replaceAll ( "\r\n" , "\n" ) ; for ( const [ n , r ] of e . entries ( ) ) t . includes ( n ) || d ( ` ModSDK: Patching ${ o . name } : Patch ${ n } not applied ` ) , t = t . replaceAll ( n , r ) ; return ( 0 , eval ) ( ` ( ${ t } ) ` ) } function s ( o ) { const e = [ ] , t = new Map , n = new Set ; for ( const r of u . values ( ) ) { const a = r . patching . get ( o . name ) ; if ( a ) { e . push ( ... a . hooks ) ; for ( const [ e , i ] of a . patches . entries ( ) ) t . has ( e ) && t . get ( e ) !== i && d ( ` ModSDK: Mod ' ${ r . name } ' is patching function ${ o . name } with same pattern that is already applied by different mod, but with different pattern: \n Pattern: \n ${ e } \n Patch1: \n ${ t . get ( e ) || "" } \n Patch2: \n ${ i } ` ) , t . set ( e , i ) , n . add ( r . name ) } } return e . sort ( ( ( o , e ) => e . priority - o . priority ) ) , { hooks : e , patches : t , patchesSources : n , final : c ( o . original , t ) } } function l ( o , e = ! 1 ) { let r = a . get ( o ) ; if ( r ) e && ( r . precomputed = s ( r ) ) ; else { let e = window ; const i = o . split ( "." ) ; for ( let t = 0 ; t < i . length - 1 ; t ++ ) if ( e = e [ i [ t ] ] , ! n ( e ) ) throw new Error ( ` ModSDK: Function ${ o } to be patched not found; ${ i . slice ( 0 , t + 1 ) . join ( "." ) } is not object ` ) ; const d = e [ i [ i . length - 1 ] ] ; if ( "function" != typeof d ) throw new Error ( ` ModSDK: Function ${ o } to be patched not found ` ) ; const c = function ( o ) { let e = - 1 ; for ( const n of t . encode ( o ) ) { let o = 255 & ( e ^ n ) ; for ( let e = 0 ; e < 8 ; e ++ ) o = 1 & o ? - 306674912 ^ o >>> 1 : o >>> 1 ; e = e >>> 8 ^ o } return ( ( - 1 ^ e ) >>> 0 ) . toString ( 16 ) . padStart ( 8 , "0" ) . toUpperCase ( ) } ( d . toString ( ) . replaceAll ( "\r\n" , "\n" ) ) , l = { name : o , original : d , originalHash : c } ; r = Object . assign ( Object . assign ( { } , l ) , { precomputed : s ( l ) } ) , a . set ( o , r ) , e [ i [ i . length - 1 ] ] = function ( o ) { return function ( ... e ) { const t = o . precomputed , n = t . hooks , r = t . final ; let a = 0 ; const i = d => { var c , s , l , f ; if ( a < n . length ) { const e = n [ a ] ; a ++ ; const t = null === ( s = ( c = w . errorReporterHooks ) . hookEnter ) || void 0 === s ? void 0 : s . call ( c , o . name , e . mod ) , r = e . hook ( d , i ) ; return null == t || t ( ) , r } { const n = null === ( f = ( l = w . errorReporterHooks ) . hookChainExit ) || void 0 === f ? void 0 : f . call ( l , o . name , t . patchesSources ) , a = r . apply ( this , e ) ; return null == n || n ( ) , a } } ; return i ( e ) } } ( r ) } return r } function f ( ) { const o = new Set ; for ( const e of u . values ( ) ) for ( const t of e . patching . keys ( ) ) o . add ( t ) ; for ( const e of a . keys ( ) ) o . add ( e ) ; for ( const e of o ) l ( e , ! 0 ) } function p ( ) { const o = new Map ; for ( const [ e , t ] of a ) o . set ( e , { name : e , originalHash : t . originalHash , hookedByMods : r ( t . precomputed . hooks . map ( ( o => o . mod ) ) ) , patchedByMods : Array . from ( t . precomputed . patchesSources ) } ) ; return o } const u = new Map ; function h ( o ) { u . get ( o . name ) !== o && e ( ` Failed to unload mod ' ${ o . name } ': Not registered ` ) , u . delete ( o . name ) , o . loaded = ! 1 } function g ( o , t , r ) { "string" == typeof o && o || e ( "Failed to register mod: Expected non-empty name string, got " + typeof o ) , "string" != typeof t && e ( ` Failed to register mod ' ${ o } ': Expected version string, got ${ typeof t } ` ) , r = ! 0 === r ; const a = u . get ( o ) ; a && ( a . allowReplace && r || e ( ` Refusing to load mod ' ${ o } ': it is already loaded and doesn't allow being replaced. \n Was the mod loaded multiple times? ` ) , h ( a ) ) ; const i = t => { "string" == typeof t && t || e ( ` Mod ' ${ o } ' failed to patch a function: Expected function name string, got ${ typeof t } ` ) ; let n = c . patching . get ( t ) ; return n || ( n = { hooks : [ ] , patches : new Map } , c . patching . set ( t , n ) ) , n } , d = { unload : ( ) => h ( c ) , hookFunction : ( t , n , r ) => { c . loaded || e ( ` Mod ' ${ c . name } ' attempted to call SDK function after being unloaded ` ) ; const a = i ( t ) ; "number" != typeof n && e ( ` Mod ' ${ o } ' failed to hook function ' ${ t } ': Expected priority number, got ${ typeof n } ` ) , "function" != typeof r && e ( ` Mod ' ${ o } ' failed to hook function ' ${ t } ': Expected hook function, got ${ typeof r } ` ) ; const d = { mod : c . name , priority : n , hook : r } ; return a . hooks . push ( d ) , f ( ) , ( ) => { const o = a . hooks . indexOf ( d ) ; o >= 0 && ( a . hooks . splice ( o , 1 ) , f ( ) ) } } , patchFunction : ( t , r ) => { c . loaded || e ( ` Mod ' ${ c . name } ' attempted to call SDK function after being unloaded ` ) ; const a = i ( t ) ; n ( r ) || e ( ` Mod ' ${ o } ' failed to patch function ' ${ t } ': Expected patches object, got ${ typeof
2022-07-04 22:07:57 +00:00
2022-11-07 04:52:25 +00:00
; ( function ( ) {
"use strict" ;
if ( ! window . AsylumGGTSSAddItems ) throw new Error ( "AsylumGGTSSAddItems() not found, aborting MBCHC loading" )
if ( window . MBCHC ) throw new Error ( "MBCHC found, aborting loading" )
window . MBCHC = {
LOADED : false ,
VERSION : "trunk" ,
TARGET _VERSION : "R85" ,
NEXT _MESSAGE : 1 ,
LOG _MESSAGES : false ,
RETHROW : false ,
AUTOHACK _ENABLED : false ,
LAST _HACKED : null ,
HISTORY _MODE : false ,
DO _DATA : { } ,
RGB _MUTE : "#6c2132" ,
RGB _POLLY : "#81b1e7" ,
UTC _OFFSET : new Date ( ) . getTimezoneOffset ( ) * 60 * 1000 ,
HAND _PENETRATORS : [ "Flogger" , "Whip" , "TennisRacket" , "Gavel" , "SmallVibratingWand" , "LargeDildo" , "Vibrator" , "Hairbrush" , "SmallDildo" , "Baguette" , "Spatula" , "Broom" ] ,
HIDE _SPECIAL : [ "Activity" , "Emoticon" ] ,
HIDE _BODY : [ "Blush" , "BodyLower" , "BodyUpper" , "Eyebrows" , "Eyes" , "Eyes2" , "Face" , "Fluids" , "HairBack" , "HairFront" , "Hands" , "Head" , "LeftHand" , "Mouth" , "Nipples" , "Pussy" , "RightHand" ] ,
HIDE _CLOTHES : [
"Cloth" , "ClothAccessory" , "Necklace" , "Suit" , "ClothLower" , "SuitLower" , "Bra" , "Corset" , "Panties" ,
"Socks" , "RightAnklet" , "LeftAnklet" , "Garters" , "Shoes" , "Hat" , "HairAccessory3" , "HairAccessory1" , "HairAccessory2" ,
"Gloves" , "Bracelet" , "Glasses" , "Mask" , "TailStraps" , "Wings"
] ,
HIDE _ITEMS : [
"ItemMisc" , "ItemEars" , "ItemHead" , "ItemNose" , "ItemHood" , "ItemAddon" , "ItemMouth" , "ItemMouth2" , "ItemMouth3" ,
"ItemArms" , "ItemNeckAccessories" , "ItemNeck" , "ItemNeckRestraints" , "ItemNipples" , "ItemNipplesPiercings" , "ItemBreast" , "ItemTorso" , "ItemTorso2" ,
"ItemHands" , "ItemPelvis" , "ItemVulva" , "ItemVulvaPiercings" ,
"ItemDevices" , "ItemLegs" , "ItemFeet" , "ItemBoots"
] ,
MAP _ACTIONS : { //ActivityFemale3DCG
// ------- action
"nod|yes" : { Head : { self : "Nod" } } ,
no : { Head : { self : "Wiggle" } } ,
moan : { Mouth : { self : "MoanGag" } } ,
mumble : { Mouth : { self : "MoanGagTalk" } } ,
whimper : { Mouth : { self : "MoanGagWhimper" } } ,
groan : { Mouth : { self : "MoanGagGroan" } } ,
scream : { Mouth : { self : "MoanGagAngry" } } ,
giggle : { Mouth : { self : "MoanGagGiggle" } } ,
struggle : { Arms : { self : "StruggleArms" } } ,
thrash : { Legs : { self : "StruggleLegs" } } ,
// ------- action zone
"wiggle|shake" : { "Arms,Breast,Boots,Butt,Ears,Feet,Hands,Nose,Pelvis,Torso" : { self : "Wiggle" } } ,
// ------- action target
whisper : { Ears : { others : "Whisper" } } ,
choke : { Neck : { all : "Choke" } } ,
brush : { Head : { all : "TakeCare" } } ,
french : { Mouth : { others : "FrenchKiss" } } ,
sit : { Legs : { others : "Sit" } } ,
rim : { Butt : { others : "MasturbateTongue" } } ,
press : { Butt : { others : "Step" } } ,
rest : { Torso : { others : "Step" } } ,
pet : { Head : { all : "Pet" } } ,
boop : { Nose : { all : "Pet" } } ,
cuddle : { Arms : { others : "Cuddle" } } ,
nuzzle : { Nose : { others : "Cuddle" } } ,
grab : { Arms : { others : "Grope" } } ,
clean : { Mouth : { all : "Caress" } } ,
lap : { Legs : { others : "RestHead" } } ,
lean : { Breast : { others : "RestHead" } } ,
peck : { Mouth : { others : "PoliteKiss" } } ,
// ------- action zone target
item : {
"Breast,Butt,Feet,Legs" : { all : "SpankItem|TickleItem|RubItem|RollItem|MasturbateItem|PourItem|ShockItem|Inject" } ,
"Nipples,Pelvis" : { all : "SpankItem|TickleItem|RubItem|RollItem|MasturbateItem|PourItem|ShockItem" } ,
Arms : { all : "SpankItem|TickleItem|RubItem|RollItem|PourItem|ShockItem|Inject" } ,
Boots : { all : "SpankItem|TickleItem|RubItem|RollItem|PourItem|ShockItem" } ,
"Ears,Mouth" : { all : "TickleItem|RubItem|RollItem" } ,
"Hood,Nose" : { all : "TickleItem|RubItem" } ,
Neck : { all : "TickleItem|RubItem|RollItem|Inject" } ,
Torso : { all : "SpankItem|TickleItem|RubItem|RollItem|PourItem|ShockItem" } ,
Vulva : { all : "SpankItem|TickleItem|RubItem|MasturbateItem|ShockItem" } ,
VulvaPiercings : { all : "SpankItem|TickleItem|RubItem|MasturbateItem|ShockItem|Inject" } ,
} ,
kiss : {
Mouth : { others : "GagKiss|Kiss|GaggedKiss" } ,
"Boots,Hands" : { self : "PoliteKiss" , others : "PoliteKiss|GaggedKiss" } ,
"Arms,Breast,Nipples" : { self : "Kiss" , others : "Kiss|GaggedKiss" } ,
"Butt,Ears,Feet,Head,Legs,Neck,Nose,Pelvis,Torso,Vulva,VulvaPiercings" : { others : "Kiss|GaggedKiss" }
} ,
smooch : { "Hands,Boots" : { all : "Kiss" } } ,
"nibble|chew" : { "Arms,Hands,Boots,Mouth,Nipples" : { all : "Nibble" } , "Ears,Feet,Legs,Neck,Nose,Pelvis,Torse,Vulva,VulvaPiercings" : { others : "Nibble" } } ,
"slap|spank" : { "Head,Breast,Vulva,VulvaPiercings" : { all : "Slap" } , "Arms,Boots,Butt,Feet,Hands,Legs,Pelvis,Torso" : { all : "Spank" } } ,
tickle : { "Arms,Boots,Breast,Feet,Legs,Neck,Pelvis,Torso" : { all : "Tickle" } } ,
massage : { "Arms,Boots,Feet,Legs,Neck,Pelvis,Torso" : { all : "MassageHands" } } ,
lick : { "Arms,Boots,Breast,Hands,Mouth,Nipples" : { all : "Lick" } , "Ears,Feet,Legs,Neck,Nose,Pelvis,Torso,Vulva,VulvaPiercings" : { others : "Lick" } } ,
suck : { "Nipples,Hands,Boots" : { all : "Suck" } } ,
bite : { "Arms,Boots,Feet,Hands,Legs,Mouth" : { all : "Bite" } , "Breast,Butt,Ears,Head,Neck,Nipples,Nose,Torso" : { others : "Bite" } } ,
pinch : { "Arms,Ears,Nipples,Nose,Pelvis" : { all : "Pinch" } } ,
clamp : { Mouth : { all : "HandGag" } , Nose : { all : "Choke" } } ,
step : { "Breast,Neck,Pelvis" : { others : "Step" } } ,
pull : { "Head,Nose,Nipples" : { all : "Pull" } } ,
grope : { "Butt,Breast" : { all : "Grope" } , "Feet,Legs,Pelvis" : { others : "Grope" } } ,
rub : { "Head,Torso" : { others : "Rub" } , Nose : { all : "Rub" } , Legs : { self : "Wiggle" } , Hands : { self : "Caress" } } ,
caress : { Hands : { others : "Caress" } , "Arms,Breast,Butt,Ears,Feet,Head,Legs,Neck,Nipples,Nose,Pelvis,Torso,Vulva,VulvaPiercings" : { all : "Caress" } } ,
polish : { "Hands,Boots" : { all : "TakeCare" } } ,
foot : { "Head,Nose" : { others : "Step" } , "Torso,Boots" : { others : "MassageFeet" } , "Vulva,VulvaPiercings" : { others : "MasturbateFoot" } } ,
fist : { "Vulva,Butt" : { all : "MasturbateFist" } } ,
fuck : { "Mouth,Vulva,Butt" : { others : "PenetrateSlow" } } , //peg?
pound : { "Mouth,Vulva,Butt" : { others : "PenetrateFast" } } ,
tongue : { "Vulva,VulvaPiercings" : { others : "MasturbateTongue" } } ,
finger : { "Breast,Butt,Vulva,VulvaPiercings" : { all : "MasturbateHand" } } ,
} ,
MAP _ZONES : {
Boots : "foot,feet,boot,boots,shoe,shoes,toes,toenails,sole,soles,heel,heels" ,
Feet : "leg,legs,ankle,ankles" ,
Legs : "hip,hips,thigh,thighs" ,
Vulva : "vulva,pussy" ,
VulvaPiercings : "clit,clitoris" ,
Butt : "butt,ass" ,
Pelvis : "tummy,pelvis" ,
Torso : "body,torso,back,ribs" ,
Breast : "breast,breasts,boob,boobs,booby,boobie,boobies,tit,tits,titty,tittie,titties" ,
Nipples : "nip,nips,nipple,nipples" ,
Hands : "hand,hands,fingers,fingernails,nails" ,
Arms : "arm,arms,elbow,elbows" ,
Neck : "neck" ,
Mouth : "mouth,lip,lips,teeth,tongue,gag,cheek,cheeks" ,
Nose : "nose,nostrils" ,
Ears : "ear,ears,earlobe,earlobes" ,
Head : "head,face,hair,eyes,forehead" ,
} ,
FBC _TESTER _PATCHES : [
[ /^\^('s)?( )?/g , "^SourceCharacter$1\\s+" ] ,
[ /([^\\])\$/g , "$1\\.?$$" ] ,
] ,
SUBCOMMANDS _MBCHC : {
"versions" : { desc : "show the mod versions across the room" , cb : mbchc => mbchc . inform ( mbchc . gather _versions ( ) . map ( c => ` <div><b> ${ c . name } </b> ( ${ c . cid } ): ${ c . version } </div> ` ) . join ( "" ) ) } ,
"autohack" : { desc : "toggle the autohack feature" , cb : mbchc => mbchc . inform ( ` Autohack is now ${ ( mbchc . AUTOHACK _ENABLED = ! mbchc . AUTOHACK _ENABLED ) ? "enabled" : "disabled" } ` ) } ,
"disappear" : { desc : "become invisible (requires anal hook -> hair)" , cb : mbchc => mbchc . disappear ( ) } ,
"donate" : { desc : "Buy data and send it to recipient" , args : { TARGET : { } } , cb : ( mbchc , args ) => mbchc . donate _data ( args [ 0 ] ) } ,
"title" : { desc : "set a custom title (<b>WIP</b>)" , args : { TITLE : { } } , cb : ( mbchc , args ) => mbchc . title ( args [ 0 ] ) } ,
"tz" : { desc : "set target's UTC offset" , args : { OFFSET : { } , "[TARGET]" : { } } , cb : ( mbchc , args ) => mbchc . set _timezone ( args ) } ,
"purge!" : { desc : "delete MBCHC online saved data" , cb : mbchc => window . Player . OnlineSettings . MBCHC && mbchc . save _settings ( s => delete window . Player . OnlineSettings . MBCHC ) } ,
} ,
fiasco : new Proxy ( { } , { has ( _ , error ) { throw new Error ( error ) } } ) ,
settings : ( ) => window . Player . OnlineSettings . MBCHC || { } ,
save _settings : ( cb = null ) => {
cb ? . ( window . Player . OnlineSettings . MBCHC || = { } )
window . ServerAccountUpdate . QueueData ( { OnlineSettings : window . Player . OnlineSettings } )
} ,
log : ( level , msg ) => console [ level ] ( "MBCHC: " + String ( msg ) ) ,
empty : text => ! text || String ( text ) . trim ( ) . length < 1 ,
normalise _message : ( text , options = { } ) => {
let result = text
if ( options . trim ) result = result . trim ( )
if ( options . low ) result = result . toLocaleLowerCase ( )
if ( options . up ) result = result . at ( 0 ) . toLocaleUpperCase ( ) + result . slice ( 1 )
if ( options . dot && result . match ( /[\w]$/ ) ) result += "."
return result
} ,
tokenise : text => text . replaceAll ( /\s{2,}/g , " " ) . split ( " " ) ,
inform : ( html , timeout = 60000 ) => window . ChatRoomSendLocal ( ` <div class="mbchc"> ${ html } </div> ` , timeout ) ,
report : x => {
this . inform ( x . toString ( ) )
if ( this . RETHROW ) throw x
} ,
in : ( x , floor , ceiling ) => x >= floor && x <= ceiling ,
cid2char : cid => cid === window . Player . cid ? window . Player : window . ChatRoomCharacter . find ( c => c . cid === cid ) || ` character ${ cid } not found in the room ` in this . fiasco ,
target2char : target => { // target should be lowcase
if ( this . empty ( target ) ) return window . Player
const position = pos => window . ChatRoomCharacter . at ( pos ) || ` invalid position ${ pos } ` in this . fiasco
const input = target , int = Number . parseInt ( target )
target = String ( target )
let found = [ ]
if ( target . startsWith ( "=" ) ) return this . cid2char ( target . slice ( 1 ) )
if ( target . startsWith ( "<" ) || target . startsWith ( ">" ) ) {
let pos = ( window . ChatRoomCharacter . findIndex ( char => char . IsPlayer ( ) ) + 1 || "can't find my position" in this . fiasco ) - 1 // findIndex returns -1 if not found
pos += target . match ( /^<+$/ ) ? - target . length : target . match ( /^>+$/ ) ? target . length : ` failed to parse target " ${ target } " ` in this . fiasco
return position ( pos % window . ChatRoomCharacter . length )
}
if ( ! isNaN ( int ) && int . toString ( ) === target ) { // we got a number
if ( this . in ( int , 0 , 9 ) ) return position ( int )
if ( this . in ( int , 11 , 15 ) ) return position ( int - 11 )
if ( this . in ( int , 21 , 25 ) ) return position ( int - 16 )
found . push ( ... window . ChatRoomCharacter . filter ( c => c . cid . toString ( ) . includes ( target ) ) )
}
if ( target . startsWith ( "@" ) ) target = target . slice ( 1 )
found . push ( ... window . ChatRoomCharacter . filter ( c => c . Name . toLocaleLowerCase ( ) . includes ( target ) ) )
found . push ( ... window . ChatRoomCharacter . filter ( c => c . Nickname ? . toLocaleLowerCase ( ) . includes ( target ) ) )
let map = { }
found . forEach ( c => { if ( ! map [ c . cid ] ) map [ c . cid ] = c } )
found = Object . values ( map )
found . length < 1 && ` target " ${ input } ": no match ` in this . fiasco
found . length > 1 && ` target " ${ input } ": multiple matches ( ${ found . map ( c => ` ${ c . cid } | ${ c . Name } | ${ c . Nickname || c . Name } ` ) . join ( "," ) } ) ` in this . fiasco
return found [ 0 ]
} ,
char2targets : char => {
const result = new Set ( ) , cid = char . cid . toString ( )
result . add ( cid ) . add ( ` = ${ cid } ` )
this . tokenise ( char . Name ) . forEach ( t => { result . add ( t ) ; result . add ( ` @ ${ t } ` ) } )
if ( char . Nickname ) this . tokenise ( char . Nickname ) . forEach ( t => { result . add ( t ) ; result . add ( ` @ ${ t } ` ) } )
return result
} ,
donate _data : target => {
let char = this . target2char ( target )
char . IsPlayer ( ) && "target must not be you" in this . fiasco
char . IsRestrained ( ) || "target must be bound" in this . fiasco
const cost = Math . round ( ( Math . random ( ) * 10 + 15 ) )
window . Player . Money < cost && "not enough money" in this . fiasco
window . CharacterChangeMoney ( window . Player , - cost )
window . ServerSend ( "ChatRoomChat" , { Content : "ReceiveSuitcaseMoney" , Type : "Hidden" , Target : char . cid } )
window . ChatRoomMessage ( { Sender : window . Player . cid , Type : "Action" , Content : ` You've bought data for $ ${ cost } and sent it to ${ char . dn } . ` , Dictionary : [ { Tag : "MISSING PLAYER DIALOG: " , Text : "" } ] } )
} ,
run _activity : ( char , ag , action ) => { try {
window . ActivityAllowed ( ) || "activities disabled in this room" in this . fiasco
window . ServerChatRoomGetAllowItem ( window . Player , char ) || "no permissions" in this . fiasco
char . FocusGroup = window . AssetGroupGet ( char . AssetFamily , ag ) || "invalid AssetGroup" in this . fiasco
const activity = window . ActivityAllowedForGroup ( char , char . FocusGroup . Name , true ) . find ( a => a . Name === action ) || "invalid activity" in this . fiasco
if ( activity . Name . endsWith ( "Item" ) ) {
const item = window . Player . Inventory . find ( i => i . Asset ? . Name === "SpankingToys" && i . Asset . Group ? . Name === char . FocusGroup . Name && window . AssetSpankingToys . DynamicActivity ( char ) === activity . Name ) || "no toy found" in this . fiasco
window . DialogPublishAction ( char , item )
} else window . ActivityRun ( char , activity )
} finally {
char . FocusGroup = null
} } ,
send _activity : msg => {
const RE _ACT _CIDS = /^<(\d+)?:(\d+)?>/
const cid2dict = ( type , cid ) => ( { Tag : ` ${ type } Character ` , MemberNumber : cid , Text : this . cid2char ( cid ) . dn } )
const dict = [ { Tag : "MISSING PLAYER DIALOG: " , Text : "" } ]
const cids = msg . match ( RE _ACT _CIDS )
if ( cids ) {
msg = msg . replace ( RE _ACT _CIDS , "" )
cids . length > 0 && dict . push ( cid2dict ( "Source" , cids [ 1 ] ) )
cids . length > 1 && dict . push ( cid2dict ( "Target" , cids [ 2 ] ) , cid2dict ( "Destination" , cids [ 2 ] ) )
}
window . ServerSend ( "ChatRoomChat" , { Type : "Action" , Content : msg , Dictionary : dict } )
} ,
receive : data => {
let char = this . cid2char ( data . Sender )
if ( char . IsPlayer ( ) ) return // this is our own message, sent back to us
const payload = data . Dictionary [ 0 ] || "Empty MBCHC message" in this . fiasco
switch ( payload . type ) {
case "greetings" : case "hello" :
char . MBCHC = payload . value
if ( "greetings" === payload . type ) this . hello ( char )
break
default : // if we don't know the type it may be from a newer version
}
} ,
hello : ( char = null ) => {
let payload = { type : "greetings" , value : window . Player . MBCHC }
if ( char ) payload . type = "hello"
let message = { Content : "MBCHC" , Type : "Hidden" , Dictionary : [ payload ] }
if ( char ) message . Target = char . cid
window . ServerSend ( "ChatRoomChat" , message )
} ,
disappear : ( ) => {
const item = window . InventoryGet ( window . Player , "ItemButt" )
item ? . Asset ? . Name || "butt seems empty" in this . fiasco
"AnalHook" === item . Asset . Name || "butt seems occupied by something other than the anal hook" in this . fiasco
"Hair" === item . Property ? . Type || "anal hook seems not tied to hair" in this . fiasco
item . Property = { Type : "Hair" , Hide : this . HIDE _ALL }
window . CharacterRefresh ( window . Player , true , true )
} ,
title : title => { // WIP
this . empty ( title ) && "empty title" in this . fiasco
title = this . normalise _message ( title , { trim : true , up : true , low : true } )
title . length > 16 && "title too long" in this . fiasco
title . match ( /^[a-zA-Z]+$/ ) || "invalid title" in this . fiasco
window . TitleSet ( title )
//window.TitleList.push({Name: title, Requirement: () => true}) // check for existing first
} ,
patch _fbc : ( ) => {
void this . remove _fbc _hook ( ) || delete this . remove _fbc _hook
if ( ! window . bce _ActivityTriggers ) return
const copy _fbc _trigger = trigger => ( { Type : "Action" , Event : trigger . Event , Matchers : trigger . Matchers . map ( m => ( { Tester : new RegExp ( this . FBC _TESTER _PATCHES . reduce ( ( ax , [ f , r ] ) => ax . replaceAll ( f , r ) , m . Tester . source ) , "u" ) } ) ) } )
window . bce _ActivityTriggers . push ( ... window . bce _ActivityTriggers . filter ( t => "Emote" === t . Type ) . map ( t => copy _fbc _trigger ( t ) ) )
; [ "anim" , "pose" ] . forEach ( tag => ( window . Commands . filter ( c => tag === c . Tag ) . forEach ( c => ( c . AutoComplete = this [ ` complete_fbc_ ${ tag } ` ] ) ) ) )
} ,
gather _versions : ( ) => window . ChatRoomCharacter . filter ( c => c . MBCHC ) . map ( c => ( { name : c . dn , cid : c . cid , version : c . MBCHC . VERSION } ) ) ,
find _timezone : char => {
let timezones = this . settings . timezones
if ( timezones && timezones [ char . cid ] ) return ( timezones [ char . cid ] )
let match = ( char . Description ) ? char . Description . match ( /(?:GMT|UTC)([+-]\d\d?)/i ) : null
if ( match ) return ( Number . parseInt ( match [ 1 ] ) )
return ( null )
} ,
player _enters _room : ( ) => { // or if the mod is loaded while player is in the room
this . hello ( )
} ,
set _timezone : args => {
const tz = Number . parseInt ( args [ 0 ] )
isNaN ( tz ) && ` invalid offset " ${ args [ 0 ] } " ` in this . fiasco
this . in ( tz , - 12 , + 12 ) || "offset should be from -12 to +12" in this . fiasco
const char = this . target2char ( args [ 1 ] )
char . MBCHC _LOCAL . TZ = tz
this . save _settings ( s => ( s . timezones ? ? = { } ) [ char . cid ] = tz ) /* eslint-disable-line no-return-assign */
} ,
update _char : char => {
char . cid = char . MemberNumber // Club ID (shorter)
char . dn = window . CharacterNickname ( char ) // DisplayName (shortcut)
char . MBCHC _LOCAL || = { }
char . MBCHC _LOCAL . TZ || = this . find _timezone ( char )
} ,
command _mbchc : ( argline , cmdline , args ) => { const mbchc = window . MBCHC ; try { // `this` is command object
if ( args . length < 1 ) return ( mbchc . inform ( Object . entries ( mbchc . SUBCOMMANDS _MBCHC ) . map ( ( [ cmd , sub ] ) => ` <div>/mbchc ${ cmd } ${ sub . args ? Object . keys ( sub . args ) . join ( " " ) : "" } : ${ sub . desc } </div> ` ) . join ( "" ) ) )
const cmd = String ( args . shift ( ) )
( mbchc . SUBCOMMANDS _MBCHC [ cmd ] || ` unknown subcommand " ${ cmd } " ` in mbchc . fiasco ) . cb . call ( mbchc , mbchc , args , argline , cmdline )
} catch ( x ) { mbchc . report ( x ) } } ,
command _activity : ( argline , cmdline , args ) => { const mbchc = window . MBCHC ; if ( ! mbchc . empty ( argline ) ) { try { // `this` is command object
let message = mbchc . normalise _message ( cmdline . replace ( mbchc . RE _ACTIVITY , '' ) , { trim : true , dot : true , up : true } )
mbchc . send _activity ( message )
} catch ( x ) { mbchc . report ( x ) } } } ,
command _do : ( argline , cmdline , args ) => { const mbchc = window . MBCHC ; try { // `this` is command object
if ( args . length < 1 ) return ( mbchc . inform ( "<div>Usage: /do VERB [ZONE] [TARGET]</div><div>Available verbs:</div>" + Object . keys ( mbchc . MAP _ACTIONS ) . join ( ", " ) + "<div>Available zones:</div>" + Object . keys ( mbchc . DO _DATA . zones ) . join ( ", " ) ) )
let [ verb , zone , target ] = args
const zones = mbchc . DO _DATA . verbs [ verb ] || ` unknown verb " ${ verb } " ` in mbchc . fiasco
if ( 1 === Object . keys ( zones ) . length ) {
if ( ! target ) target = zone
zone = mbchc . MAP _ZONES [ Object . keys ( zones ) [ 0 ] ] [ 0 ]
}
zone || "zone missing" in this . fiasco
const ag = mbchc . DO _DATA . zones [ zone ] || ` unknown zone " ${ zone } " ` in mbchc . fiasco
const types = zones [ ag ] || ` zone " ${ zone } " invalid for " ${ verb } " ` in mbchc . fiasco
let char = window . Player
if ( target && ( ( types . self . length < 1 ) || ( types . others . length > 0 ) ) ) char = mbchc . target2char ( target )
let type = char . IsPlayer ( ) ? "self" : "others"
let available = window . ActivityAllowedForGroup ( char , ag )
let toy = window . InventoryGet ( window . Player , "ItemHands" )
if ( toy && toy . Asset . Name === "SpankingToys" ) available . push ( window . AssetAllActivities ( char . AssetFamily ) . find ( a => a . Name === window . InventorySpankingToysGetActivity ( window . Player ) ) )
const actions = types [ type ] || ` zone " ${ zone } " invalid for (" ${ verb } " " ${ type } ") ` in mbchc . fiasco
const action = actions . find ( name => available . find ( a => a . Name === name ) ) || ` invalid action ( ${ verb } ${ zone } ${ target } ) ` in mbchc . fiasco
mbchc . run _activity ( char , ag , action )
} catch ( x ) { mbchc . report ( x ) } } ,
bell : ( ) => {
setTimeout ( ( ) => document . getElementById ( "InputChat" ) . style . outline = "" , 100 ) /* eslint-disable-line no-return-assign */
document . getElementById ( "InputChat" ) . style . outline = "solid red"
} ,
complete : ( options , space = true ) => {
if ( options . length < 1 ) return ( this . bell ( ) )
if ( options . length > 1 ) {
let width = Math . max ( ... options . map ( o => o . length ) )
let pref = null
for ( let i = width ; i > 0 ; i -= 1 ) { let test = options [ 0 ] . slice ( 0 , i ) ; if ( options . every ( o => o . startsWith ( test ) ) ) { pref = test ; break } }
if ( pref ) this . complete ( [ pref ] , false )
this . complete _hint ( options )
} else window . ElementValue ( "InputChat" , document . getElementById ( "InputChat" ) . value . replace ( /(^|\s)([^\s]*)$/ , ` $ 1 ${ options [ 0 ] } ${ space ? " " : "" } ` ) )
} ,
complete _hint : options => {
this . COMP _HINT . innerHTML = options . sort ( ) . map ( s => ` <div> ${ s } </div> ` ) . join ( "" )
this . COMP _HINT . style . display = "flex"
window . ElementSetDataAttribute ( this . COMP _HINT . id , "colortheme" , ( window . Player . ChatSettings . ColorTheme || "Light" ) )
let rescroll = window . ElementIsScrolledToEnd ( "TextAreaChatLog" )
window . ChatRoomResize ( false )
if ( rescroll ) window . ElementScrollToEnd ( "TextAreaChatLog" )
} ,
comp _hint _visible : ( ) => { return ( this . COMP _HINT . parentElement && "flex" === this . COMP _HINT . style . display ) } ,
complete _hint _hide : options => { if ( ! this . comp _hint _visible ( ) ) return ; this . COMP _HINT . style . display = "none" ; window . ChatRoomResize ( false ) } ,
complete _target : ( token , me2 = true , check _perms = false ) => {
let [ locase , found ] = [ token . toLocaleLowerCase ( ) , new Set ( ) ]
for ( let c of window . ChatRoomCharacter ) {
if ( ( c . IsPlayer ( ) && ! me2 ) || ( check _perms && ! window . ServerChatRoomGetAllowItem ( window . Player , c ) ) ) continue
this . char2targets ( c ) . forEach ( s => { if ( s . toLocaleLowerCase ( ) . startsWith ( locase ) ) found . add ( s ) } )
}
this . complete ( Array . from ( found ) )
} ,
complete _common : ( ) => {
const input = document . getElementById ( "InputChat" ) . value
return [ this , input , this . tokenise ( input ) ]
} ,
complete _mbchc : ( args , locase , cmdline ) => { const [ mbchc , input , tokens ] = window . MBCHC . complete _common ( ) ; // `this` is command object
if ( tokens . length < 1 ) return
if ( tokens . length < 2 ) return ( mbchc . complete ( [ ` ${ mbchc . CommandsKey } ${ this . Tag } ` ] ) )
let subname = tokens [ 1 ] . toLocaleLowerCase ( )
if ( tokens . length < 3 ) return ( mbchc . complete ( Object . keys ( mbchc . SUBCOMMANDS _MBCHC ) . filter ( c => c . startsWith ( subname ) ) ) ) // complete subcommand name
let sub = mbchc . SUBCOMMANDS _MBCHC [ subname ]
if ( sub && sub . args ) {
let argname = Object . keys ( sub . args ) [ tokens . length - 3 ]
if ( "TARGET" === argname ) return ( mbchc . complete _target ( tokens [ tokens . length - 1 ] , false ) )
if ( "[TARGET]" === argname ) return ( mbchc . complete _target ( tokens [ tokens . length - 1 ] ) , true )
}
} ,
complete _do _target : ( actions , token ) => {
if ( ! actions ) return
let me2 = ( actions . self . length > 0 )
if ( me2 && actions . others . length < 1 ) return ( this . complete ( [ window . Player . cid . toString ( ) ] ) ) // target is always the player
this . complete _target ( token , me2 , true )
} ,
complete _do : ( args , locase , cmdline ) => { const [ mbchc , input , tokens ] = window . MBCHC . complete _common ( ) ; // `this` is command object
if ( tokens . length < 1 ) return
if ( tokens . length < 2 ) return ( mbchc . complete ( [ ` ${ mbchc . CommandsKey } ${ this . Tag } ` ] ) )
// now, we *could* run a filter to exclude impossible activities, but it isn't very useful, and also seems like a lot of CPU to iterate over every action on every zone of every char in the room
let low = tokens [ 1 ] . toLocaleLowerCase ( )
if ( tokens . length < 3 ) return ( mbchc . complete ( Object . keys ( mbchc . DO _DATA . verbs ) . filter ( c => c . startsWith ( low ) ) ) ) // complete verb
let ags = mbchc . DO _DATA . verbs [ low ]
if ( ! ags ) return ( mbchc . bell ( ) )
low = tokens [ 2 ] . toLocaleLowerCase ( )
if ( tokens . length < 4 ) { // complete zone or target
if ( Object . keys ( ags ) . length < 2 ) return ( mbchc . complete _do _target ( ags [ Object . keys ( ags ) [ 0 ] ] , tokens [ 2 ] ) ) // zone implied, complete target
let zones = Object . entries ( mbchc . DO _DATA . zones ) . filter ( ( [ zone , ag ] ) => zone . startsWith ( low ) && ags [ ag ] ) . map ( ( [ zone , ag ] ) => zone )
return ( mbchc . complete ( zones ) )
}
if ( tokens . length < 5 ) { // complete target where it belongs
if ( Object . keys ( ags ) . length < 2 ) return // zone implied, target already given
return ( mbchc . complete _do _target ( ags [ mbchc . DO _DATA . zones [ low ] ] , tokens [ 3 ] ) )
}
mbchc . bell ( )
} ,
complete _fbc _anim : ( args , locase , cmdline ) => { const [ mbchc , input , tokens ] = window . MBCHC . complete _common ( ) ; // `this` is command object
if ( tokens . length < 1 ) return
if ( tokens . length < 2 ) return ( mbchc . complete ( [ ` ${ mbchc . CommandsKey } ${ this . Tag } ` ] ) )
if ( tokens . length > 2 ) return ( mbchc . bell ( ) )
let anim = tokens [ 1 ] . toLocaleLowerCase ( )
return ( mbchc . complete ( Object . keys ( window . bce _EventExpressions ) . filter ( a => a . toLocaleLowerCase ( ) . startsWith ( anim ) ) ) )
} ,
complete _fbc _pose : ( args , locase , cmdline ) => { const [ mbchc , input , tokens ] = window . MBCHC . complete _common ( ) ; // `this` is command object
if ( tokens . length < 1 ) return
if ( tokens . length < 2 ) return ( mbchc . complete ( [ ` ${ mbchc . CommandsKey } ${ this . Tag } ` ] ) )
let pose = tokens [ tokens . length - 1 ] . toLocaleLowerCase ( )
return ( mbchc . complete ( window . PoseFemale3DCG . map ( p => p . Name ) . filter ( p => p . toLocaleLowerCase ( ) . startsWith ( pose ) ) ) )
} ,
history : down => {
let [ text , history ] = [ window . ElementValue ( "InputChat" ) , window . ChatRoomLastMessage ]
if ( ! this . HISTORY _MODE ) { history . push ( text ) ; this . HISTORY _MODE = true }
let ids = history . map ( ( t , i ) => [ t , i ] ) . filter ( ( [ t , i ] ) => t . startsWith ( history [ history . length - 1 ] ) ) . map ( ( [ t , i ] ) => i )
if ( ! down ) ids . reverse ( )
let found = ids . find ( id => ( down ) ? id > window . ChatRoomLastMessageIndex : id < window . ChatRoomLastMessageIndex )
if ( ! found ) return ( this . bell ( ) )
window . ElementValue ( "InputChat" , history [ found ] )
window . ChatRoomLastMessageIndex = found
} ,
create _element : ( tag , properties = { } ) => Object . assign ( document . createElement ( tag ) , properties ) ,
loader : ( ) => {
void this . remove _load _hook ? . ( ) || delete this . remove _load _hook
if ( this . LOADED ) return
// Calculated values
this . HIDE _ALL = this . HIDE _SPECIAL . concat ( this . HIDE _BODY ) . concat ( this . HIDE _CLOTHES ) . concat ( this . HIDE _ITEMS )
this . CommandsKey = CommandsKey /* eslint-disable-line no-undef */ // window.CommandsKey is undefined
this . RE _ACTIVITY = RegExp ( ` ^ ${ this . CommandsKey } activity ` )
this . PREF _ACTIVITY = ` ${ this . CommandsKey } activity `
this . COMP _HINT = this . create _element ( "div" , { id : "mbchcCompHint" } )
document . head . appendChild ( this . create _element ( "css" , { type : "text/css" , textContent : `
# TextAreaChatLog . mbchc { background - color : $ { this . RGB _POLLY } }
# TextAreaChatLog [ data - colortheme = "dark" ] . mbchc , # TextAreaChatLog [ data - colortheme = "dark2" ] . mbchc { background - color : $ { this . RGB _MUTE } }
# $ { this . COMP _HINT . id } { flex - flow : column wrap ; overflow : auto ; display : none ; background - color : $ { this . RGB _POLLY } ; color : black }
# $ { this . COMP _HINT . id } [ data - colortheme = "dark" ] , # $ { this . COMP _HINT . id } [ data - colortheme = "dark2" ] { background - color : $ { this . RGB _MUTE } ; color : white }
# $ { this . COMP _HINT . id } div { margin : 0 0.5 ex }
` }))
const map = ( obj , cb ) => new Map ( Object . entries ( obj ) . flatMap ( cb ) )
const split = ( str , val , cb = null ) => str . split ( /[|,]/ ) . map ( x => [ cb ? . ( x ) ? ? x , val ] )
const extract = ( actions , k ) => [ [ k , new Set ( ( actions [ k ] ? . split ( "|" ) ? ? [ ] ) . concat ( actions . all ? . split ( "|" ) ? ? [ ] ) ) ] ]
this . DO _DATA . verbs = map ( this . MAP _ACTIONS , ( [ verbs , data ] ) => split ( verbs , map ( data , ( [ zones , actions ] ) => split ( zones , map ( [ "self" , "others" ] , ( [ _ , k ] ) => extract ( actions , k ) ) , zone => ` Item ${ zone } ` ) ) ) )
this . DO _DATA . zones = map ( this . MAP _ZONES , ( [ zone , labels ] ) => split ( labels , ` Item ${ zone } ` ) )
// Actions
this . HAND _PENETRATORS . map ( name => InventoryItemHandsSpankingToysOptions . find ( o => o . Name === name ) ) . forEach ( o => o ? . Property && ! ( o . Property . AllowActivity || = [ ] ) . includes ( "PenetrateItem" ) && o . Property . AllowActivity . push ( "PenetrateItem" ) ) /* eslint-disable-line no-undef */ // window.InventoryItemHandsSpankingToysOptions is undefined
window . Player . MBCHC = { VERSION : this . VERSION }
window . CommandCombine ( [
{ Tag : "mbchc" , Description : ": Utility functions (\"/mbchc\" for help)" , Action : this . command _mbchc , AutoComplete : this . complete _mbchc } ,
{ Tag : "activity" , Description : "[Message]: Send a custom activity (or \"@@Message\", or \"@Message\" as yourself)" , Action : this . command _activity } ,
{ Tag : "do" , Description : ": Do an activity, as if clicked on its button (\"/do\" for help)" , Action : this . command _do , AutoComplete : this . complete _do } ,
] )
this . LOADED = ! void this . log ( "info" , ` loaded version ${ this . VERSION } ` )
window . GameVersion === this . TARGET _VERSION || this . log ( "warn" , ` Game version doesn't match the target (" ${ this . TARGET _VERSION } "), beware of incompatibilities ` ) // TODO: check betas & cheat
}
} // MBCHC
2022-07-04 22:07:57 +00:00
2022-11-07 04:52:25 +00:00
// Hooks
window . MBCHC . sdk = window . bcModSdk . registerMod ( "MBCHC" , window . MBCHC . VERSION )
window . MBCHC . sdk . hookFunction ( "CharacterOnlineRefresh" , 0 , ( nextargs , next ) => {
const result = next ( nextargs )
window . MBCHC . update _char ( nextargs [ 0 ] )
return result
} )
window . MBCHC . sdk . hookFunction ( "ChatRoomReceiveSuitcaseMoney" , 0 , ( nextargs , next ) => {
let result = next ( nextargs )
if ( window . MBCHC . AUTOHACK _ENABLED && window . MBCHC . LAST _HACKED ) {
window . CurrentCharacter = window . MBCHC . cid2char ( window . MBCHC . LAST _HACKED )
window . MBCHC . LAST _HACKED = null
window . ChatRoomTryToTakeSuitcase ( )
}
return ( result )
} )
window . MBCHC . sdk . hookFunction ( "ChatRoomSendChat" , 0 , ( nextargs , next ) => {
const input = window . ElementValue ( "InputChat" )
input . startsWith ( "@" ) && ! input . startsWith ( "@@@" ) && window . ElementValue ( "InputChat" , input . replace ( /^@@/ , window . MBCHC . PREF _ACTIVITY ) . replace ( /^@(['\s])?/ , ( _ , suf ) => ` ${ window . MBCHC . PREF _ACTIVITY } < ${ window . Player . cid } :>SourceCharacter ${ suf || " " } ` ) )
const result = next ( nextargs )
const history = window . ChatRoomLastMessage
history . length > 1 && history . at ( - 1 ) === history . at ( - 2 ) && ! void history . pop ( ) && window . ChatRoomLastMessageIndex --
return result
} )
window . MBCHC . sdk . hookFunction ( "ChatRoomDrawCharacterOverlay" , 0 , ( nextargs , next ) => {
let [ C , CharX , CharY , Zoom , Pos ] = nextargs
if ( window . ChatRoomHideIconState < 1 && C . MBCHC ) {
let colour = ( C . MBCHC . VERSION === window . Player . MBCHC . VERSION ) ? window . MBCHC . RGB _POLLY : window . MBCHC . RGB _MUTE
window . DrawRect ( CharX + 175 * Zoom , CharY , 50 * Zoom , 50 * Zoom , colour )
}
if ( window . ChatRoomHideIconState < 1 && C . MBCHC _LOCAL && C . MBCHC _LOCAL . TZ ) {
let hours = new Date ( window . CommonTime ( ) + window . MBCHC . UTC _OFFSET + C . MBCHC _LOCAL . TZ * 60 * 60 * 1000 ) . getHours ( )
let text = ( hours < 10 ) ? "0" + hours . toString ( ) : hours . toString ( )
window . DrawTextFit ( text , CharX + 200 * Zoom , CharY + 25 * Zoom , 46 * Zoom , "white" , "black" )
}
return ( next ( nextargs ) )
} )
window . MBCHC . sdk . hookFunction ( "ElementValue" , 0 , ( nextargs , next ) => { // FIXME: layer priority will be locked too if it's the same as difficulty
const [ ID , Value ] = nextargs , result = next ( nextargs )
"bce_LayerPriority" === ID && window . CurrentCharacter ? . FocusGroup && window . InventoryGet ( window . CurrentCharacter , window . CurrentCharacter . FocusGroup . Name ) ? . Difficulty . toString ( ) === Value && window . InventoryLocked ( window . CurrentCharacter , window . CurrentCharacter . FocusGroup . Name , true ) && window . ElementSetAttribute ( ID , "disabled" , true )
return result
} )
window . MBCHC . sdk . hookFunction ( "ChatRoomCreateElement" , 0 , ( nextargs , next ) => {
const result = next ( nextargs )
window . MBCHC . COMP _HINT . parentElement || document . body . appendChild ( window . MBCHC . COMP _HINT )
return result
} )
window . MBCHC . sdk . hookFunction ( "ChatRoomClearAllElements" , 0 , ( nextargs , next ) => void window . MBCHC . complete _hint _hide ( ) || void window . MBCHC . COMP _HINT . remove ( ) || next ( nextargs ) )
window . MBCHC . sdk . hookFunction ( "ChatRoomResize" , 0 , ( nextargs , next ) => {
let result = next ( nextargs )
if ( window . CharacterGetCurrent ( ) == null && window . CurrentScreen == "ChatRoom" && document . getElementById ( "InputChat" ) && document . getElementById ( "TextAreaChatLog" ) && window . MBCHC . comp _hint _visible ( ) ) { // upstream
let fontsize = ChatRoomFontSize /* eslint-disable-line no-undef */ // window.ChatRoomFontSize is undefined
window . ElementPositionFix ( "TextAreaChatLog" , fontsize , 1005 , 66 , 988 , 630 )
window . ElementPositionFix ( window . MBCHC . COMP _HINT . id , fontsize , 1005 , 701 , 988 , 200 )
window . MBCHC . COMP _HINT . style . display = "flex"
}
return ( result )
} )
window . MBCHC . sdk . hookFunction ( "DocumentKeyDown" , 0 , ( nextargs , next ) => {
let [ event ] = nextargs
if ( "InputChat" === document . activeElement . id || "bce-message-input" === document . activeElement . id ) return ( next ( nextargs ) )
if ( "inline" === document . getElementById ( "InputChat" ) ? . style . display && [ event . altKey , event . ctrlKey , event . metaKey ] . every ( i => ! i ) ) window . ElementFocus ( "InputChat" ) // alt, ctrl and meta should all be false
// TODO: this is not ideal, but it will have to do for now
// TODO: Ctrl+V should still paste
return ( next ( nextargs ) )
} )
window . MBCHC . sdk . hookFunction ( "ChatRoomKeyDown" , 0 , ( nextargs , next ) => {
let [ event ] = nextargs
window . MBCHC . complete _hint _hide ( )
if ( 33 == window . KeyPress || 34 == window . KeyPress ) { // better history
event . preventDefault ( )
return ( window . MBCHC . history ( window . KeyPress - 33 ) )
}
if ( window . MBCHC . HISTORY _MODE ) {
window . ChatRoomLastMessage . pop ( )
window . MBCHC . HISTORY _MODE = false
}
return ( next ( nextargs ) )
} )
window . MBCHC . sdk . hookFunction ( "ChatRoomClick" , 0 , ( nextargs , next ) => void window . MBCHC . complete _hint _hide ( ) || next ( nextargs ) )
window . MBCHC . remove _fbc _hook = window . MBCHC . sdk . hookFunction ( "MainRun" , 0 , ( nextargs , next ) => void window . MBCHC . patch _fbc ( ) || next ( nextargs ) )
2022-07-04 22:07:57 +00:00
2022-11-07 04:52:25 +00:00
// Chat room handlers
window . ChatRoomRegisterMessageHandler ( { Priority : - 220 , Description : "MBCHC preprocessor" , Callback : ( data , sender , msg , metadata ) => {
data . MBCHC _ID = window . MBCHC . NEXT _MESSAGE ++
window . MBCHC . LOG _MESSAGES && console . debug ( { data , sender , msg , metadata } )
"Action" === data . Type && "ServerEnter" === data . Content && data . Sender === window . Player . cid && window . MBCHC . player _enters _room ( )
"Hidden" === data . Type && "ReceiveSuitcaseMoney" === data . Content && ( window . MBCHC . LAST _HACKED = data . Sender )
return "Hidden" === data . Type && "MBCHC" === data . Content && ! void window . MBCHC . receive ( data )
} } )
2022-10-22 12:07:11 +00:00
2022-11-07 04:52:25 +00:00
// MAIN SCREEN TURN ON
if ( ! window . CurrentModule || ! window . CurrentScreen || "Character" === window . CurrentModule && "Login" === window . CurrentScreen ) { // we need a load hook
window . MBCHC . remove _load _hook = window . MBCHC . sdk . hookFunction ( "AsylumGGTSSAddItems" , 0 , ( nextargs , next ) => void window . MBCHC . loader ( ) || next ( nextargs ) )
} else {
void window . MBCHC . loader ( ) || "Online" === window . CurrentModule && "ChatRoom" === window . CurrentScreen && ! void window . ChatRoomCharacter . forEach ( c => window . MBCHC . update _char ( c ) ) && window . MBCHC . player _enters _room ( )
}
2022-07-04 22:07:57 +00:00
} ) ( )