2024-07-10 01:57:42 +00:00
// ==UserScript==
// @name LILY
// @namespace https://code.fleshless.org/mute
2024-09-18 20:32:34 +00:00
// @version 0.0.2
2024-07-10 01:57:42 +00:00
// @description Lily's Integrated Logic Yoke
// @grant none
// @author Mute
2024-09-18 20:32:34 +00:00
// @require https://jomshir98.github.io/bondage-club-mod-sdk/bcmodsdk.js
// @match https://*.bondageprojects.elementfx.com/R*/*/
// @match https://*.bondage-europe.com/R*/*/
// @match https://*.bondageprojects.com/R*/*/
2024-07-10 01:57:42 +00:00
// ==/UserScript==
2024-07-10 23:08:50 +00:00
( function () {
2024-07-10 01:57:42 +00:00
'use strict' ;
const W = /** @type {Window & typeof globalThis & {bcModSdk: import('bondage-club-mod-sdk').ModSDKGlobalAPI}} */ ( window )
2024-07-12 00:58:51 +00:00
const SDK = W . bcModSdk . registerMod ({ name : GM_info . script . name , fullName : GM_info . script . description ?? '' , version : GM_info . script . version , repository : 'finger://your.mom' })
2024-07-10 23:08:50 +00:00
/** @type {LILY.Utils} */ const U = { remove_hook : undefined ,
true ( f ) { f (); return true },
2024-07-10 01:57:42 +00:00
with : ( v , f ) => f ( v ),
2024-07-12 00:58:51 +00:00
send : f => f () && U . true (() => void W . ChatRoomCharacterUpdate ( W . Player )),
2024-07-10 01:57:42 +00:00
}
/** @type {LILY.Box} */ const Box = {
2024-07-12 00:58:51 +00:00
enable ( item ) { if ( item === undefined ) return false // TODO Okay, we need to be more clever here. The light should be above the box itself
return U . with ( item . Property , ip => typeof ip ? . OverridePriority === 'object' && ( ip . OverridePriority [ 'Light' ] = 41 ) > 0 )
2024-07-10 23:08:50 +00:00
},
2024-07-12 00:58:51 +00:00
disable ( item ) { return item === undefined ? false : U . with ( item . Property ??= {}, ip => U . with ( ip . OverridePriority ??= {}, op =>
typeof op === 'number' ? Boolean ( ip . OverridePriority = { Lock : op , Unit : op }) : (( op [ 'Light' ] = 0 ) < 1 )
))},
2024-07-10 23:08:50 +00:00
on : () => U . with ( Box . item , i => U . send (() => Box . enable ( i ))),
off : () => U . with ( Box . item , i => U . send (() => Box . disable ( i ))),
get item () { return U . with ( W . InventoryGet ( W . Player , 'ItemNeckAccessories' ), item => item ? . Craft ? . Name === 'Lily\'s voicebox' ? item : undefined )},
2024-07-12 00:58:51 +00:00
get enabled () { return U . with ( Box . item , i => i !== undefined && U . with ( i ? . Property ? . OverridePriority , op => typeof op !== 'object' || ! Object . hasOwn ( op , 'Light' ) || ( op [ 'Light' ] ?? 1 ) > 0 ))}, // TODO check if the light is above the box
2024-07-10 01:57:42 +00:00
}
2024-07-10 23:08:50 +00:00
/** @type {LILY.Eyes} */ const Eyes = { timeout : undefined , zones : [ 'ItemHead' , 'Mask' ],
2024-07-10 01:57:42 +00:00
rgb : [
'#990000' , '#990f00' , '#991f00' , '#992e00' , '#993d00' , '#994d00' , '#995c00' , '#996b00' , '#997a00' , '#998a00' ,
'#999900' , '#8a9900' , '#7a9900' , '#6b9900' , '#5c9900' , '#4d9900' , '#3d9900' , '#2e9900' , '#1f9900' , '#0f9900' ,
'#009900' , '#00990f' , '#00991f' , '#00992e' , '#00993d' , '#00994d' , '#00995c' , '#00996b' , '#00997a' , '#00998a' ,
'#009999' , '#008a99' , '#007a99' , '#006b99' , '#005c99' , '#004d99' , '#003d99' , '#002e99' , '#001f99' , '#000f99' ,
'#000099' , '#0f0099' , '#1f0099' , '#2e0099' , '#3d0099' , '#4d0099' , '#5c0099' , '#6b0099' , '#7a0099' , '#8a0099' ,
'#990099' , '#99008a' , '#99007a' , '#99006b' , '#99005c' , '#99004d' , '#99003d' , '#99002e' , '#99001f' , '#99000f' ,
],
craft : { Item : 'AnimeLenses' , Name : 'Akihabara souvenir' , Description : 'you will never be the same uwu' , Color : '#FFFFFF,Default,#FFFFFF,Default' , Property : 'Thick' , Lock : '' , Private : true , ItemProperty : {}, Type : null , TypeRecord : null , MemberNumber : 71_240 , MemberName : 'Mute' },
2024-07-12 00:58:51 +00:00
set_rgb : ( item , n ) => U . true (() => item . Color = [ Eyes . rgb [ n ] ?? 'Default' , 'Default' , Eyes . rgb [ n ] ?? 'Default' , 'Default' ]),
2024-07-12 01:21:46 +00:00
next_rgb : () => Eyes . check ( 'ItemHead' ) === undefined && U . with ( Eyes . check ( 'Mask' ), i => i !== undefined && U . with ( Eyes . rgb . indexOf ( i . Color ? .[ 0 ] ?? Eyes . rgb [ 0 ] ?? '' ) + 1 , n => Eyes . set_rgb ( i , n ))),
roll_rgb : () => Eyes . next_rgb () && void W . ChatRoomCharacterItemUpdate ( W . Player , 'Mask' ),
2024-07-12 00:58:51 +00:00
start : () => Eyes . check ( 'Mask' ) !== undefined && Eyes . timeout === undefined && Boolean ( Eyes . timeout = setInterval ( Eyes . roll_rgb , 1000 )),
stop : () => Eyes . check ( 'Mask' ) !== undefined && Eyes . timeout !== undefined && U . true (() => Eyes . timeout = void clearInterval ( Eyes . timeout )),
dim : () => U . send (() => Eyes . check ( 'ItemHead' ) === undefined && U . true (() => W . InventoryWear ( W . Player , 'AnimeLenses' , 'ItemHead' , [ '#FFFFFF' , 'Default' , '#FFFFFF' , 'Default' ], undefined , 71_240 , Eyes . craft ))),
clear : () => U . send (() => Eyes . check ( 'ItemHead' ) !== undefined && U . true (() => void W . InventoryRemove ( W . Player , 'ItemHead' ))),
check : zone => U . with ( Eyes . item , item => item ? . Asset . Group . Name === zone ? item : undefined ),
get item () { return Eyes . zones . map ( z => W . InventoryGet ( W . Player , z )). find ( item => item ? . Asset . Name === 'AnimeLenses' ) ?? undefined },
2024-07-10 01:57:42 +00:00
}
2024-07-10 23:08:50 +00:00
/** @type {LILY.Belt} */ const Belt = { users : [ 119_643 , 154_662 ], admins : [ 71_240 , 67_994 ],
2024-07-10 01:58:29 +00:00
cli : { '#LILY' : {
2024-07-10 01:57:42 +00:00
status : _ => '200 OK' ,
2024-07-10 23:08:50 +00:00
box : { on : Box . on , off : Box . off },
eyes : { start : Eyes . start , stop : Eyes . stop , dim : Eyes . dim , clear : Eyes . clear },
2024-07-10 01:57:42 +00:00
}},
/** @type {LILY.Belt['is_cb']} */ is_cb : s => typeof s === 'function' ,
2024-07-10 23:08:50 +00:00
run ( tokens ) { /** @type {string | undefined} */ let t , /** @type {LILY.Commands | LILY.CommandCB} */ cmd = Belt . cli
2024-07-12 00:58:51 +00:00
while (( t = tokens . shift ()) !== undefined ) if ( U . with ( cmd [ t ], next => next !== undefined && Belt . is_cb ( cmd = next ))) break // eslint-disable-line @typescript-eslint/no-loop-func
if ( ! Belt . is_cb ( cmd )) return t === undefined ? `subcommands: [ ${ Object . keys ( cmd ). join ( ', ' ) } ]` : `unknown token ${ t } `
2024-07-10 01:57:42 +00:00
return U . with ( cmd (... tokens ), r => typeof r === 'boolean' ? ( r ? 'success' : 'fail' ) : String ( r ))
},
2024-07-12 00:58:51 +00:00
receive ( data ) { if ( data . Sender === undefined ) return undefined
2024-07-10 02:23:08 +00:00
W . ChatRoomSendLocal ( `<span style="color: #666"> ${ data . Content } </span>` )
2024-07-10 23:08:50 +00:00
return void W . ChatRoomSendWhisper ( data . Sender , `LILY: ${ Belt . admins . includes ( data . Sender ) ? Belt . run ( data . Content . split ( ' ' )) : 'access denied' } ` )
2024-07-10 01:57:42 +00:00
},
}
2024-07-12 00:58:51 +00:00
/** @type {(text: string) => undefined} */ const unload = text => U . true ( SDK . unload ) && void console . debug ( `LILY: ${ text } , unloading the mod` )
2024-07-10 23:08:50 +00:00
const load_after_login = () => {
2024-07-12 00:58:51 +00:00
if ( U . remove_hook !== undefined ) { U . remove_hook ? .(); U . remove_hook = undefined }
if ( W . Player . MemberNumber === undefined ) return void unload ( 'member not identified' )
if ( ! Belt . users . includes ( W . Player . MemberNumber )) return void unload ( 'member not eligible for loading' )
2024-09-18 20:32:34 +00:00
// SDK.hookFunction('SpeechTransformGagGarble', 0, ([text]) => text) // disable garbling // unfortunately affects hearing as well
SDK . hookFunction ( 'SpeechTransformGagGarbleIntensity' , 0 , _ => 0 ) // disable garbling
2024-07-12 00:58:51 +00:00
SDK . hookFunction ( 'ChatRoomSendChatMessage' , 0 , ( na , n ) => Box . enabled || na [ 0 ]. startsWith ( '(' ) ? n ( na ) : ! U . true (() => void W . ChatRoomSendLocal ( '<span style="color: red">You try to talk, but nothing comes out.</span>' )))
W . ChatRoomRegisterMessageHandler ({ Priority : - 169 , Description : 'LILY' , Callback : data => data . Type === 'Whisper' && data . Content . startsWith ( '#LILY' ) && U . true (() => void Belt . receive ( data ))})
2024-07-10 23:08:50 +00:00
console . debug ( `LILY: eligible member detected, loaded version ${ GM_info . script . version } ` )
}
2024-07-12 00:58:51 +00:00
U . remove_hook = SDK . hookFunction ( 'AsylumGGTSSAddItems' , 0 , ( na , n ) => U . true ( load_after_login ) && void n ( na ))
2024-07-10 01:57:42 +00:00
})()