87 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			87 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// ==UserScript==
 | 
						|
// @name         LILY
 | 
						|
// @namespace    https://code.fleshless.org/mute
 | 
						|
// @version      0.0.1
 | 
						|
// @description  Lily's Integrated Logic Yoke
 | 
						|
// @grant        none
 | 
						|
// @author       Mute
 | 
						|
// @require      https://code.fleshless.org/mute/LILY/raw/branch/mistress/bcmodsdk-1.2.0.mjs
 | 
						|
// @match        https://bondageprojects.elementfx.com/*
 | 
						|
// @match        https://www.bondageprojects.elementfx.com/*
 | 
						|
// @match        https://bondage-europe.com/*
 | 
						|
// @match        https://www.bondage-europe.com/*
 | 
						|
// @match        http://localhost:*/*
 | 
						|
// ==/UserScript==
 | 
						|
// checklist:
 | 
						|
// ? OOC blocked
 | 
						|
// ? custom lenses aren't updated
 | 
						|
// ? custom lenses wrong colour
 | 
						|
 | 
						|
(async function() {
 | 
						|
	'use strict';
 | 
						|
 | 
						|
	const W = /** @type {Window & typeof globalThis & {bcModSdk: import('bondage-club-mod-sdk').ModSDKGlobalAPI}} */ (window)
 | 
						|
	const SDK = W.bcModSdk.registerMod({name: GM_info.script.name, fullName: GM_info.script.description || '', version: GM_info.script.version, repository: 'finger://your.mom'})
 | 
						|
	/** @type {LILY.Utils} */ const U = {
 | 
						|
		with: (v, f) => f(v),
 | 
						|
	}
 | 
						|
	/** @type {LILY.Box} */ const Box = {
 | 
						|
		enable() {},
 | 
						|
		disable() {},
 | 
						|
		get equipped() {return false},
 | 
						|
		get enabled() {return this.equipped && false},
 | 
						|
	}
 | 
						|
	/** @type {LILY.Eyes} */ const Eyes = { // #9C0000 156 0 0
 | 
						|
		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',
 | 
						|
		],
 | 
						|
		timeout: undefined,
 | 
						|
		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'},
 | 
						|
		zones: ['ItemHead', 'Mask'],
 | 
						|
		set_rgb(item, n) {item.Color = [this.rgb[n], 'Default', this.rgb[n], 'Default']; return true},
 | 
						|
		next_rgb() {return !this.check('ItemHead') && U.with(this.check('Mask'), i => i && U.with(this.rgb.indexOf(i.Color?.[0] || this.rgb[0]) + 1, n => this.set_rgb(i, n)))},
 | 
						|
		roll_rgb() {this.next_rgb() && W.ChatRoomCharacterItemUpdate(W.Player, 'Mask')},
 | 
						|
		start() {return Boolean(this.check('Mask')) && !this.timeout && Boolean(this.timeout = setInterval(() => this.roll_rgb(), 1000))},
 | 
						|
		stop() {return Boolean(this.check('Mask')) && Boolean(this.timeout) && !(this.timeout = void clearInterval(this.timeout))},
 | 
						|
		dim() {return !this.check('ItemHead') && !void W.InventoryWear(W.Player, 'AnimeLenses', 'ItemHead', ['#FFFFFF', 'Default', '#FFFFFF', 'Default'], undefined, 71_240, this.craft) && !void W.ChatRoomCharacterUpdate(W.Player)},
 | 
						|
		clear() {return Boolean(this.check('ItemHead')) && !void W.InventoryRemove(W.Player, 'ItemHead') && !void W.ChatRoomCharacterUpdate(W.Player)},
 | 
						|
		check(zone) {return U.with(this.item, item => (item && item.Asset.Group.Name === zone) ? item : undefined)},
 | 
						|
		get item() {return this.zones.map(z => W.InventoryGet(W.Player, z)).find(item => item && item.Asset.Name === 'AnimeLenses') || undefined},
 | 
						|
	}
 | 
						|
	/** @type {LILY.Belt} */ const Belt = {
 | 
						|
		admins: [71_240, 67_994],
 | 
						|
		cli: {'#LILY': {
 | 
						|
			status: _ => '200 OK',
 | 
						|
			box: {
 | 
						|
				on: _ => Box.enable(),
 | 
						|
				off: _ => Box.disable(),
 | 
						|
			},
 | 
						|
			eyes: {
 | 
						|
				start: _ => Eyes.start(),
 | 
						|
				stop: _ => Eyes.stop(),
 | 
						|
				dim: _ => Eyes.dim(),
 | 
						|
				clear: _ => Eyes.clear(),
 | 
						|
			},
 | 
						|
		}},
 | 
						|
		/** @type {LILY.Belt['is_cb']} */ is_cb: s => typeof s === 'function',
 | 
						|
		run(tokens) { /** @type {string | undefined} */ let t, /** @type {LILY.Commands | LILY.CommandCB} */ cmd = this.cli
 | 
						|
			while (t = tokens.shift()) if (U.with(cmd[t], next => !next || this.is_cb(cmd = next))) break // eslint-disable-line no-cond-assign
 | 
						|
			if (!this.is_cb(cmd)) return t ? `unknown token ${t}` : `subcommands: [${Object.keys(cmd).join(', ')}]`
 | 
						|
			return U.with(cmd(...tokens), r => typeof r === 'boolean' ? (r ? 'success' : 'fail') : String(r))
 | 
						|
		},
 | 
						|
		receive(data) { if (!data.Sender) return undefined
 | 
						|
			W.ChatRoomSendLocal(`<span style="color: #666">${data.Content}</span>`)
 | 
						|
			const reply = this.admins.includes(data.Sender) ? this.run(data.Content.split(' ')) : 'access denied'
 | 
						|
			return void W.ChatRoomSendWhisper(data.Sender, `LILY: ${reply}`)
 | 
						|
		},
 | 
						|
	}
 | 
						|
	SDK.hookFunction('SpeechTransformGagGarble', 0, ([text]) => text) // disable garbling
 | 
						|
	SDK.hookFunction('ChatRoomSendChatMessage', 0, (na, n) => Box.enabled || na[0].startsWith('(') ? n(na) : Boolean(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') && (Belt.receive(data) || true)})
 | 
						|
})()
 |