dev.9
* Fixed MISSING PLAYER DIALOG in donate subcommand * Removed the club version check, it really doesn't do anything * Removed the broken disappear subcommand * Removed the mostly useless title subcommand * Removed the versions subcommand, it was superceded by /versions * Took another dive in the keystroke catcher, should fix all known conflicts * Disabled the indicator square * Thought about moving the time digits to a proper place, but ultimately decided to leave them be for now
This commit is contained in:
		
							
								
								
									
										201
									
								
								mbchc.mjs
									
									
									
									
									
								
							
							
						
						
									
										201
									
								
								mbchc.mjs
									
									
									
									
									
								
							@@ -1,10 +1,11 @@
 | 
				
			|||||||
export {}
 | 
					export {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (!window.AsylumGGTSSAddItems) throw new Error('AsylumGGTSSAddItems() not found, aborting MBCHC loading')
 | 
					// Zero-width non-joiner, used to break up ligatures, does nothing here, but an empty string is a falsy value
 | 
				
			||||||
 | 
					const MISSING_PLAYER_DIALOG = {Tag: 'MISSING PLAYER DIALOG: ', Text: '\u200C'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (window.MBCHC) throw new Error('MBCHC found, aborting loading')
 | 
					if (window.MBCHC) throw new Error('MBCHC found, aborting loading')
 | 
				
			||||||
window.MBCHC = {
 | 
					window.MBCHC = {
 | 
				
			||||||
	VERSION: 'dev.9',
 | 
						VERSION: 'dev.9',
 | 
				
			||||||
	TARGET_VERSION: 'R99',
 | 
					 | 
				
			||||||
	NEXT_MESSAGE: 1,
 | 
						NEXT_MESSAGE: 1,
 | 
				
			||||||
	LOG_MESSAGES: false,
 | 
						LOG_MESSAGES: false,
 | 
				
			||||||
	RETHROW: false,
 | 
						RETHROW: false,
 | 
				
			||||||
@@ -12,7 +13,7 @@ window.MBCHC = {
 | 
				
			|||||||
	AUTOHACK_ENABLED: false,
 | 
						AUTOHACK_ENABLED: false,
 | 
				
			||||||
	LAST_HACKED: null,
 | 
						LAST_HACKED: null,
 | 
				
			||||||
	HISTORY_MODE: false,
 | 
						HISTORY_MODE: false,
 | 
				
			||||||
	RE_TITLE: /^[a-zA-Z]+$/,
 | 
						// RE_TITLE: /^[a-zA-Z]+$/,
 | 
				
			||||||
	RE_PREF_ACTIVITY_ME: /^@/,
 | 
						RE_PREF_ACTIVITY_ME: /^@/,
 | 
				
			||||||
	RE_PREF_ACTIVITY: /^@@/,
 | 
						RE_PREF_ACTIVITY: /^@@/,
 | 
				
			||||||
	RE_ACT_CIDS: /^<(\d+)?:(\d+)?>/,
 | 
						RE_ACT_CIDS: /^<(\d+)?:(\d+)?>/,
 | 
				
			||||||
@@ -25,62 +26,62 @@ window.MBCHC = {
 | 
				
			|||||||
	RGB_MUTE: '#6c2132',
 | 
						RGB_MUTE: '#6c2132',
 | 
				
			||||||
	RGB_POLLY: '#81b1e7',
 | 
						RGB_POLLY: '#81b1e7',
 | 
				
			||||||
	UTC_OFFSET: new Date().getTimezoneOffset() * 60 * 1000,
 | 
						UTC_OFFSET: new Date().getTimezoneOffset() * 60 * 1000,
 | 
				
			||||||
	HIDE_SPECIAL: ['Activity', 'Emoticon'],
 | 
						// HIDE_SPECIAL: ['Activity', 'Emoticon'],
 | 
				
			||||||
	HIDE_BODY: ['Blush', 'BodyLower', 'BodyUpper', 'Eyebrows', 'Eyes', 'Eyes2', 'Face', 'Fluids', 'HairBack', 'HairFront', 'Hands', 'Head', 'LeftHand', 'Mouth', 'Nipples', 'Pussy', 'RightHand'],
 | 
						// HIDE_BODY: ['Blush', 'BodyLower', 'BodyUpper', 'Eyebrows', 'Eyes', 'Eyes2', 'Face', 'Fluids', 'HairBack', 'HairFront', 'Hands', 'Head', 'LeftHand', 'Mouth', 'Nipples', 'Pussy', 'RightHand'],
 | 
				
			||||||
	HIDE_CLOTHES: [
 | 
						// HIDE_CLOTHES: [
 | 
				
			||||||
		'Cloth',
 | 
						// 	'Cloth',
 | 
				
			||||||
		'ClothAccessory',
 | 
						// 	'ClothAccessory',
 | 
				
			||||||
		'Necklace',
 | 
						// 	'Necklace',
 | 
				
			||||||
		'Suit',
 | 
						// 	'Suit',
 | 
				
			||||||
		'ClothLower',
 | 
						// 	'ClothLower',
 | 
				
			||||||
		'SuitLower',
 | 
						// 	'SuitLower',
 | 
				
			||||||
		'Bra',
 | 
						// 	'Bra',
 | 
				
			||||||
		'Corset',
 | 
						// 	'Corset',
 | 
				
			||||||
		'Panties',
 | 
						// 	'Panties',
 | 
				
			||||||
		'Socks',
 | 
						// 	'Socks',
 | 
				
			||||||
		'RightAnklet',
 | 
						// 	'RightAnklet',
 | 
				
			||||||
		'LeftAnklet',
 | 
						// 	'LeftAnklet',
 | 
				
			||||||
		'Garters',
 | 
						// 	'Garters',
 | 
				
			||||||
		'Shoes',
 | 
						// 	'Shoes',
 | 
				
			||||||
		'Hat',
 | 
						// 	'Hat',
 | 
				
			||||||
		'HairAccessory3',
 | 
						// 	'HairAccessory3',
 | 
				
			||||||
		'HairAccessory1',
 | 
						// 	'HairAccessory1',
 | 
				
			||||||
		'HairAccessory2',
 | 
						// 	'HairAccessory2',
 | 
				
			||||||
		'Gloves',
 | 
						// 	'Gloves',
 | 
				
			||||||
		'Bracelet',
 | 
						// 	'Bracelet',
 | 
				
			||||||
		'Glasses',
 | 
						// 	'Glasses',
 | 
				
			||||||
		'Mask',
 | 
						// 	'Mask',
 | 
				
			||||||
		'TailStraps',
 | 
						// 	'TailStraps',
 | 
				
			||||||
		'Wings',
 | 
						// 	'Wings',
 | 
				
			||||||
	],
 | 
						// ],
 | 
				
			||||||
	HIDE_ITEMS: [
 | 
						// HIDE_ITEMS: [
 | 
				
			||||||
		'ItemMisc',
 | 
						// 	'ItemMisc',
 | 
				
			||||||
		'ItemEars',
 | 
						// 	'ItemEars',
 | 
				
			||||||
		'ItemHead',
 | 
						// 	'ItemHead',
 | 
				
			||||||
		'ItemNose',
 | 
						// 	'ItemNose',
 | 
				
			||||||
		'ItemHood',
 | 
						// 	'ItemHood',
 | 
				
			||||||
		'ItemAddon',
 | 
						// 	'ItemAddon',
 | 
				
			||||||
		'ItemMouth',
 | 
						// 	'ItemMouth',
 | 
				
			||||||
		'ItemMouth2',
 | 
						// 	'ItemMouth2',
 | 
				
			||||||
		'ItemMouth3',
 | 
						// 	'ItemMouth3',
 | 
				
			||||||
		'ItemArms',
 | 
						// 	'ItemArms',
 | 
				
			||||||
		'ItemNeckAccessories',
 | 
						// 	'ItemNeckAccessories',
 | 
				
			||||||
		'ItemNeck',
 | 
						// 	'ItemNeck',
 | 
				
			||||||
		'ItemNeckRestraints',
 | 
						// 	'ItemNeckRestraints',
 | 
				
			||||||
		'ItemNipples',
 | 
						// 	'ItemNipples',
 | 
				
			||||||
		'ItemNipplesPiercings',
 | 
						// 	'ItemNipplesPiercings',
 | 
				
			||||||
		'ItemBreast',
 | 
						// 	'ItemBreast',
 | 
				
			||||||
		'ItemTorso',
 | 
						// 	'ItemTorso',
 | 
				
			||||||
		'ItemTorso2',
 | 
						// 	'ItemTorso2',
 | 
				
			||||||
		'ItemHands',
 | 
						// 	'ItemHands',
 | 
				
			||||||
		'ItemPelvis',
 | 
						// 	'ItemPelvis',
 | 
				
			||||||
		'ItemVulva',
 | 
						// 	'ItemVulva',
 | 
				
			||||||
		'ItemVulvaPiercings',
 | 
						// 	'ItemVulvaPiercings',
 | 
				
			||||||
		'ItemDevices',
 | 
						// 	'ItemDevices',
 | 
				
			||||||
		'ItemLegs',
 | 
						// 	'ItemLegs',
 | 
				
			||||||
		'ItemFeet',
 | 
						// 	'ItemFeet',
 | 
				
			||||||
		'ItemBoots',
 | 
						// 	'ItemBoots',
 | 
				
			||||||
	],
 | 
						// ],
 | 
				
			||||||
	MAP_ACTIONS: { // ActivityFemale3DCG
 | 
						MAP_ACTIONS: { // ActivityFemale3DCG
 | 
				
			||||||
		// action
 | 
							// action
 | 
				
			||||||
		'nod|yes': {Head: {self: 'Nod'}},
 | 
							'nod|yes': {Head: {self: 'Nod'}},
 | 
				
			||||||
@@ -182,11 +183,11 @@ window.MBCHC = {
 | 
				
			|||||||
		[/([^\\])\$/g, '$1\\.?$$'],
 | 
							[/([^\\])\$/g, '$1\\.?$$'],
 | 
				
			||||||
	],
 | 
						],
 | 
				
			||||||
	SUBCOMMANDS_MBCHC: {
 | 
						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(''))},
 | 
							// 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'}`)}, // eslint-disable-line no-cond-assign
 | 
							autohack: {desc: 'toggle the autohack feature', cb: mbchc => mbchc.inform(`Autohack is now ${(mbchc.AUTOHACK_ENABLED = !mbchc.AUTOHACK_ENABLED) ? 'enabled' : 'disabled'}`)}, // eslint-disable-line no-cond-assign
 | 
				
			||||||
		disappear: {desc: 'become invisible (requires anal hook -> hair)', cb: mbchc => mbchc.disappear()},
 | 
							// 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])},
 | 
							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])},
 | 
							// 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)},
 | 
							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) {
 | 
							'purge!': {desc: 'delete MBCHC online saved data', cb(mbchc) {
 | 
				
			||||||
			if (window.Player.OnlineSettings.MBCHC) {
 | 
								if (window.Player.OnlineSettings.MBCHC) {
 | 
				
			||||||
@@ -209,10 +210,8 @@ window.MBCHC = {
 | 
				
			|||||||
				const processed = {self: (actions.self) ? actions.self.split('|').concat(all) : all, others: (actions.others) ? actions.others.split('|').concat(all) : all}
 | 
									const processed = {self: (actions.self) ? actions.self.split('|').concat(all) : all, others: (actions.others) ? actions.others.split('|').concat(all) : all}
 | 
				
			||||||
				for (const zone of zones.split(',')) unwound[`Item${zone}`] = processed
 | 
									for (const zone of zones.split(',')) unwound[`Item${zone}`] = processed
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					 | 
				
			||||||
			for (const verb of verbs.split('|')) this.DO_DATA.verbs[verb] = unwound
 | 
								for (const verb of verbs.split('|')) this.DO_DATA.verbs[verb] = unwound
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (const [ag, zones] of Object.entries(this.MAP_ZONES)) for (const zone of zones) this.DO_DATA.zones[zone] = ag
 | 
							for (const [ag, zones] of Object.entries(this.MAP_ZONES)) for (const zone of zones) this.DO_DATA.zones[zone] = ag
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	settings(setting = null) {
 | 
						settings(setting = null) {
 | 
				
			||||||
@@ -224,7 +223,6 @@ window.MBCHC = {
 | 
				
			|||||||
			if (!window.Player.OnlineSettings.MBCHC) window.Player.OnlineSettings.MBCHC = {}
 | 
								if (!window.Player.OnlineSettings.MBCHC) window.Player.OnlineSettings.MBCHC = {}
 | 
				
			||||||
			cb.call(this, window.Player.OnlineSettings.MBCHC)
 | 
								cb.call(this, window.Player.OnlineSettings.MBCHC)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		window.ServerAccountUpdate.QueueData({OnlineSettings: window.Player.OnlineSettings})
 | 
							window.ServerAccountUpdate.QueueData({OnlineSettings: window.Player.OnlineSettings})
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	log(level, message) {
 | 
						log(level, message) {
 | 
				
			||||||
@@ -244,7 +242,6 @@ window.MBCHC = {
 | 
				
			|||||||
			const rest = result.slice(1)
 | 
								const rest = result.slice(1)
 | 
				
			||||||
			result = first + rest
 | 
								result = first + rest
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (options.dot && this.RE_LAST_LETTER.test(result)) result = `${result}.`
 | 
							if (options.dot && this.RE_LAST_LETTER.test(result)) result = `${result}.`
 | 
				
			||||||
		return (result)
 | 
							return (result)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
@@ -331,7 +328,7 @@ window.MBCHC = {
 | 
				
			|||||||
		if (window.Player.Money < cost) throw new Error('not enough money')
 | 
							if (window.Player.Money < cost) throw new Error('not enough money')
 | 
				
			||||||
		window.CharacterChangeMoney(window.Player, -cost)
 | 
							window.CharacterChangeMoney(window.Player, -cost)
 | 
				
			||||||
		window.ServerSend('ChatRoomChat', {Content: 'ReceiveSuitcaseMoney', Type: 'Hidden', Target: char.cid})
 | 
							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: ''}]})
 | 
							window.ChatRoomMessage({Sender: window.Player.cid, Type: 'Action', Content: `You've bought data for $${cost} and sent it to ${char.dn}.`, Dictionary: [MISSING_PLAYER_DIALOG]})
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	run_activity(char, ag, action) {
 | 
						run_activity(char, ag, action) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
@@ -357,14 +354,13 @@ window.MBCHC = {
 | 
				
			|||||||
		return ({Tag: `${type}Character`, MemberNumber: cid, Text: this.cid2char(cid).dn})
 | 
							return ({Tag: `${type}Character`, MemberNumber: cid, Text: this.cid2char(cid).dn})
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	send_activity(message) {
 | 
						send_activity(message) {
 | 
				
			||||||
		const dict = [{Tag: 'MISSING PLAYER DIALOG: ', Text: '\u200C'}] // Zero-width non-joiner, used to break up ligatures, does nothing here, but an empty string is a falsy value
 | 
							const dict = [MISSING_PLAYER_DIALOG]
 | 
				
			||||||
		const cids = message.match(this.RE_ACT_CIDS)
 | 
							const cids = message.match(this.RE_ACT_CIDS)
 | 
				
			||||||
		if (cids) {
 | 
							if (cids) {
 | 
				
			||||||
			message = message.replace(this.RE_ACT_CIDS, '')
 | 
								message = message.replace(this.RE_ACT_CIDS, '')
 | 
				
			||||||
			if (cids[1]) dict.push(this.cid2dict('Source', cids[1]))
 | 
								if (cids[1]) dict.push(this.cid2dict('Source', cids[1]))
 | 
				
			||||||
			if (cids[2]) dict.push(this.cid2dict('Target', cids[2]), this.cid2dict('Destination', cids[2]))
 | 
								if (cids[2]) dict.push(this.cid2dict('Target', cids[2]), this.cid2dict('Destination', cids[2]))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		window.ServerSend('ChatRoomChat', {Type: 'Action', Content: message, Dictionary: dict})
 | 
							window.ServerSend('ChatRoomChat', {Type: 'Action', Content: message, Dictionary: dict})
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	receive(data) {
 | 
						receive(data) {
 | 
				
			||||||
@@ -377,10 +373,8 @@ window.MBCHC = {
 | 
				
			|||||||
				if (payload.type === 'greetings') this.hello(char)
 | 
									if (payload.type === 'greetings') this.hello(char)
 | 
				
			||||||
				break
 | 
									break
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					 | 
				
			||||||
			default: // If we don't know the type it may be from a newer version
 | 
								default: // If we don't know the type it may be from a newer version
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	hello(char = null) {
 | 
						hello(char = null) {
 | 
				
			||||||
@@ -390,22 +384,22 @@ window.MBCHC = {
 | 
				
			|||||||
		if (char) message.Target = char.cid
 | 
							if (char) message.Target = char.cid
 | 
				
			||||||
		window.ServerSend('ChatRoomChat', message)
 | 
							window.ServerSend('ChatRoomChat', message)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	disappear() {
 | 
						// disappear() {
 | 
				
			||||||
		const item = window.InventoryGet(window.Player, 'ItemButt')
 | 
						// 	const item = window.InventoryGet(window.Player, 'ItemButt')
 | 
				
			||||||
		if (!item || !item.Asset || !item.Asset.Name) throw new Error('butt seems empty')
 | 
						// 	if (!item || !item.Asset || !item.Asset.Name) throw new Error('butt seems empty')
 | 
				
			||||||
		if (item.Asset.Name !== 'AnalHook') throw new Error('butt seems occupied by something other than the anal hook')
 | 
						// 	if (item.Asset.Name !== 'AnalHook') throw new Error('butt seems occupied by something other than the anal hook')
 | 
				
			||||||
		if (!item.Property.Type || item.Property.Type !== 'Hair') throw new Error('anal hook seems not tied to hair')
 | 
						// 	if (!item.Property.Type || item.Property.Type !== 'Hair') throw new Error('anal hook seems not tied to hair')
 | 
				
			||||||
		item.Property = {Type: 'Hair', Hide: this.HIDE_ALL}
 | 
						// 	item.Property = {Type: 'Hair', Hide: this.HIDE_ALL}
 | 
				
			||||||
		window.CharacterRefresh(window.Player, true, true)
 | 
						// 	window.CharacterRefresh(window.Player, true, true)
 | 
				
			||||||
	},
 | 
						// },
 | 
				
			||||||
	title(title) { // WIP
 | 
						// title(title) { // WIP
 | 
				
			||||||
		if (this.empty(title)) throw new Error('empty title')
 | 
						// 	if (this.empty(title)) throw new Error('empty title')
 | 
				
			||||||
		title = this.normalise_message(title, {trim: true, up: true, low: true})
 | 
						// 	title = this.normalise_message(title, {trim: true, up: true, low: true})
 | 
				
			||||||
		if (title.length > 16) throw new Error('title too long')
 | 
						// 	if (title.length > 16) throw new Error('title too long')
 | 
				
			||||||
		if (!this.RE_TITLE.test(title)) throw new Error('invalid title')
 | 
						// 	if (!this.RE_TITLE.test(title)) throw new Error('invalid title')
 | 
				
			||||||
		window.TitleSet(title)
 | 
						// 	window.TitleSet(title)
 | 
				
			||||||
		// Window.TitleList.push({Name: title, Requirement: () => true}) // check for existing first
 | 
						// 	// Window.TitleList.push({Name: title, Requirement: () => true}) // check for existing first
 | 
				
			||||||
	},
 | 
						// },
 | 
				
			||||||
	copy_fbc_trigger(trigger) {
 | 
						copy_fbc_trigger(trigger) {
 | 
				
			||||||
		const result = {
 | 
							const result = {
 | 
				
			||||||
			Type: 'Action',
 | 
								Type: 'Action',
 | 
				
			||||||
@@ -418,15 +412,15 @@ window.MBCHC = {
 | 
				
			|||||||
		this.remove_fbc_hook()
 | 
							this.remove_fbc_hook()
 | 
				
			||||||
		delete this.remove_fbc_hook
 | 
							delete this.remove_fbc_hook
 | 
				
			||||||
		window.bce_ActivityTriggers.push(...window.bce_ActivityTriggers.filter(t => t.Type === 'Emote').map(t => this.copy_fbc_trigger(t)))
 | 
							window.bce_ActivityTriggers.push(...window.bce_ActivityTriggers.filter(t => t.Type === 'Emote').map(t => this.copy_fbc_trigger(t)))
 | 
				
			||||||
		/* (["anim", "pose"]).forEach(tag => {let cmd = window.Commands.find(c => tag === c.Tag); if (cmd) cmd.AutoComplete = this[`complete_fbc_${tag}`]}) */ // this line explodes, don't ask me why
 | 
							/* (["anim", "pose"]).forEach(tag => {let cmd = window.Commands.find(c => tag === c.Tag); if (cmd) cmd.AutoComplete = this[`complete_fbc_${tag}`]}) */ // this line explodes, because it needs a semicolon in front if it
 | 
				
			||||||
		let cmd = window.Commands.find(c => c.Tag === 'anim')
 | 
							let cmd = window.Commands.find(c => c.Tag === 'anim')
 | 
				
			||||||
		if (cmd) cmd.AutoComplete = this.complete_fbc_anim
 | 
							if (cmd) cmd.AutoComplete = this.complete_fbc_anim
 | 
				
			||||||
		cmd = window.Commands.find(c => c.Tag === 'pose')
 | 
							cmd = window.Commands.find(c => c.Tag === 'pose')
 | 
				
			||||||
		if (cmd) cmd.AutoComplete = this.complete_fbc_pose
 | 
							if (cmd) cmd.AutoComplete = this.complete_fbc_pose
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	gather_versions() {
 | 
						// gather_versions() {
 | 
				
			||||||
		return (window.ChatRoomCharacter.filter(c => c.MBCHC).map(c => ({name: c.dn, cid: c.cid, version: c.MBCHC.VERSION})))
 | 
						// 	return (window.ChatRoomCharacter.filter(c => c.MBCHC).map(c => ({name: c.dn, cid: c.cid, version: c.MBCHC.VERSION})))
 | 
				
			||||||
	},
 | 
						// },
 | 
				
			||||||
	find_timezone(char) {
 | 
						find_timezone(char) {
 | 
				
			||||||
		const timezones = this.settings('timezones')
 | 
							const timezones = this.settings('timezones')
 | 
				
			||||||
		if (timezones && typeof timezones[char.cid] === 'number') return (timezones[char.cid])
 | 
							if (timezones && typeof timezones[char.cid] === 'number') return (timezones[char.cid])
 | 
				
			||||||
@@ -629,15 +623,20 @@ window.MBCHC = {
 | 
				
			|||||||
		window.ElementValue('InputChat', history[found])
 | 
							window.ElementValue('InputChat', history[found])
 | 
				
			||||||
		window.ChatRoomLastMessageIndex = found
 | 
							window.ChatRoomLastMessageIndex = found
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						focus_chat_checks() { // we only want to catch chatlog and canvas (no map though) keypresses
 | 
				
			||||||
 | 
							if (document.activeElement === document.body) return true
 | 
				
			||||||
 | 
							if (document.activeElement.id !== 'MainCanvas') return false
 | 
				
			||||||
 | 
							return !window.ChatRoomMapVisible
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	focus_chat_whitelist(event) {
 | 
						focus_chat_whitelist(event) {
 | 
				
			||||||
		if (event.ctrlKey && event.key === 'v') return true // Ctrl+V should paste
 | 
							if (event.ctrlKey && event.key === 'v') return true // Ctrl+V should paste
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	focus_chat(event) { // TODO: this is not ideal, but it will have to do for now
 | 
						focus_chat(event) {
 | 
				
			||||||
		if (event.repeat) return // Only unique presses please
 | 
							if (event.repeat) return // Only unique presses please
 | 
				
			||||||
		if (document.querySelector('#InputChat')?.style.display !== 'inline') return // Input chat missing
 | 
							if (!this.focus_chat_checks()) return
 | 
				
			||||||
		if (['InputChat', 'bce-message-input'].includes(document.activeElement.id)) return // Focus already set
 | 
					 | 
				
			||||||
		if ([event.altKey, event.ctrlKey, event.metaKey].some(Boolean) && !this.focus_chat_whitelist(event)) return // Alt, ctrl and meta should all be false
 | 
							if ([event.altKey, event.ctrlKey, event.metaKey].some(Boolean) && !this.focus_chat_whitelist(event)) return // Alt, ctrl and meta should all be false
 | 
				
			||||||
 | 
							if (document.querySelector('#InputChat')?.style.display !== 'inline') return // Input chat missing
 | 
				
			||||||
		window.ElementFocus('InputChat')
 | 
							window.ElementFocus('InputChat')
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	loader() {
 | 
						loader() {
 | 
				
			||||||
@@ -653,14 +652,13 @@ window.MBCHC = {
 | 
				
			|||||||
			{Tag: 'activity', Description: '[Message]: Send a custom activity (or "@@Message", or "@Message" as yourself)', Action: this.command_activity},
 | 
								{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},
 | 
								{Tag: 'do', Description: ': Do an activity, as if clicked on its button ("/do" for help)', Action: this.command_do, AutoComplete: this.complete_do},
 | 
				
			||||||
		]
 | 
							]
 | 
				
			||||||
		this.HIDE_ALL = this.HIDE_SPECIAL.concat(this.HIDE_BODY).concat(this.HIDE_CLOTHES).concat(this.HIDE_ITEMS)
 | 
							// 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.CommandsKey = CommandsKey /* eslint-disable-line no-undef */ // window.CommandsKey is undefined
 | 
				
			||||||
		this.RE_ACTIVITY = new RegExp(`^${this.CommandsKey}activity `)
 | 
							this.RE_ACTIVITY = new RegExp(`^${this.CommandsKey}activity `)
 | 
				
			||||||
		this.PREF_ACTIVITY = `${this.CommandsKey}activity `
 | 
							this.PREF_ACTIVITY = `${this.CommandsKey}activity `
 | 
				
			||||||
		this.COMP_HINT = document.createElement('div')
 | 
							this.COMP_HINT = document.createElement('div')
 | 
				
			||||||
		this.COMP_HINT.id = 'mbchcCompHint'
 | 
							this.COMP_HINT.id = 'mbchcCompHint'
 | 
				
			||||||
		const css = document.createElement('style')
 | 
							const css = document.createElement('style')
 | 
				
			||||||
		css.type = 'text/css'
 | 
					 | 
				
			||||||
		css.textContent = `
 | 
							css.textContent = `
 | 
				
			||||||
			#TextAreaChatLog .mbchc, #TextAreaChatLog .mbchc {
 | 
								#TextAreaChatLog .mbchc, #TextAreaChatLog .mbchc {
 | 
				
			||||||
				background-color: ${this.RGB_POLLY};
 | 
									background-color: ${this.RGB_POLLY};
 | 
				
			||||||
@@ -715,9 +713,9 @@ window.MBCHC = {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
		this.before('ChatRoomDrawCharacterOverlay', (C, CharX, CharY, Zoom, _Pos) => {
 | 
							this.before('ChatRoomDrawCharacterOverlay', (C, CharX, CharY, Zoom, _Pos) => {
 | 
				
			||||||
			if (window.ChatRoomHideIconState < 1 && C.MBCHC) {
 | 
								// if (window.ChatRoomHideIconState < 1 && C.MBCHC) {
 | 
				
			||||||
				window.DrawRect(CharX + (175 * Zoom), CharY, 50 * Zoom, 50 * Zoom, C.MBCHC.VERSION === window.Player.MBCHC.VERSION ? this.RGB_POLLY : this.RGB_MUTE)
 | 
								// 	window.DrawRect(CharX + (175 * Zoom), CharY, 50 * Zoom, 50 * Zoom, C.MBCHC.VERSION === window.Player.MBCHC.VERSION ? this.RGB_POLLY : this.RGB_MUTE)
 | 
				
			||||||
			}
 | 
								// }
 | 
				
			||||||
			if (window.ChatRoomHideIconState < 1 && C.MBCHC_LOCAL && typeof C.MBCHC_LOCAL.TZ === 'number') {
 | 
								if (window.ChatRoomHideIconState < 1 && C.MBCHC_LOCAL && typeof C.MBCHC_LOCAL.TZ === 'number') {
 | 
				
			||||||
				const hours = new Date(window.CommonTime() + this.UTC_OFFSET + (C.MBCHC_LOCAL.TZ * 60 * 60 * 1000)).getHours()
 | 
									const hours = new Date(window.CommonTime() + this.UTC_OFFSET + (C.MBCHC_LOCAL.TZ * 60 * 60 * 1000)).getHours()
 | 
				
			||||||
				window.DrawTextFit(hours < 10 ? '0' + hours.toString() : hours.toString(), CharX + (200 * Zoom), CharY + (25 * Zoom), 46 * Zoom, 'white', 'black')
 | 
									window.DrawTextFit(hours < 10 ? '0' + hours.toString() : hours.toString(), CharX + (200 * Zoom), CharY + (25 * Zoom), 46 * Zoom, 'white', 'black')
 | 
				
			||||||
@@ -780,13 +778,14 @@ window.MBCHC = {
 | 
				
			|||||||
		// Footer
 | 
							// Footer
 | 
				
			||||||
		this.LOADED = true
 | 
							this.LOADED = true
 | 
				
			||||||
		this.log('info', `loaded version ${this.VERSION}`)
 | 
							this.log('info', `loaded version ${this.VERSION}`)
 | 
				
			||||||
		if (window.GameVersion !== this.TARGET_VERSION) this.log('warn', `Game version doesn't match the target ("${this.TARGET_VERSION}"), beware of incompatibilities`) // TODO: betas are like R86Beta1; cheat?
 | 
					 | 
				
			||||||
		if ((window.CurrentModule === 'Online') && (window.CurrentScreen === 'ChatRoom')) {
 | 
							if ((window.CurrentModule === 'Online') && (window.CurrentScreen === 'ChatRoom')) {
 | 
				
			||||||
			for (const c of window.ChatRoomCharacter) this.update_char(c)
 | 
								for (const c of window.ChatRoomCharacter) this.update_char(c)
 | 
				
			||||||
			this.player_enters_room()
 | 
								this.player_enters_room()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	preloader() {
 | 
						preloader() {
 | 
				
			||||||
 | 
							if (!window.AsylumGGTSSAddItems) throw new Error('AsylumGGTSSAddItems() not found, aborting MBCHC loading')
 | 
				
			||||||
 | 
							if (!window.bcModSdk) throw new Error('SDK not found, please load with (or after) FUSAM')
 | 
				
			||||||
		this.SDK = window.bcModSdk.registerMod({name: 'MBCHC', fullName: 'Mute\'s Bondage Club Hacks Collection', version: this.VERSION, repository: 'https://code.fleshless.org/mute/MBCHC/'})
 | 
							this.SDK = window.bcModSdk.registerMod({name: 'MBCHC', fullName: 'Mute\'s Bondage Club Hacks Collection', version: this.VERSION, repository: 'https://code.fleshless.org/mute/MBCHC/'})
 | 
				
			||||||
		this.before = (name, cb) => this.SDK.hookFunction(name, 0, (nextargs, next) => {
 | 
							this.before = (name, cb) => this.SDK.hookFunction(name, 0, (nextargs, next) => {
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
@@ -811,3 +810,5 @@ window.MBCHC = {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
window.MBCHC.preloader()
 | 
					window.MBCHC.preloader()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: with the removal of /mbchc versions it makes no sense to keep track of the mod version and the whole hello() infrastructure can go away
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user