2022-06-30 15:16:58 +00:00
|
|
|
// ==UserScript==
|
|
|
|
// @name MBCHC
|
|
|
|
// @version 1
|
|
|
|
// @description Mute's Bondage Club Hacks Collection
|
|
|
|
// @author codename.mute@proton.me
|
|
|
|
// @namespace https://code.fleshless.org/mute/
|
|
|
|
// @homepage https://code.fleshless.org/mute/MBCHC
|
|
|
|
// @updateURL https://code.fleshless.org/mute/MBCHC/raw/branch/master/mbchc.user.js
|
|
|
|
// @downloadURL https://code.fleshless.org/mute/MBCHC/raw/branch/master/mbchc.user.js
|
|
|
|
// @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*
|
|
|
|
// @grant none
|
|
|
|
// ==/UserScript==
|
|
|
|
|
|
|
|
(function() {
|
|
|
|
"use strict";
|
|
|
|
if (!window.AsylumGGTSSAddItems) throw "AsylumGGTSSAddItems() not found, aborting"
|
|
|
|
|
|
|
|
// Static data
|
|
|
|
window.MBCHC = {
|
|
|
|
NEXT_MESSAGE: 1,
|
|
|
|
LOG_MESSAGES: false,
|
|
|
|
LOADED: false,
|
|
|
|
VERSION: "1",
|
|
|
|
AUTOHACK_ENABLED: false,
|
|
|
|
LAST_HACKED: null,
|
|
|
|
RE_TITLE: /^[a-zA-Z]+$/,
|
|
|
|
HIDE_SPECIAL: ["Activity","Emoticon"],
|
|
|
|
HIDE_BODY: ["Blush","BodyLower","BodyUpper","Eyebrows","Eyes","Eyes2","Face","Fluids","HairBack","HairFront","Hands","Head","Mouth","Nipples","Pussy"],
|
|
|
|
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",
|
|
|
|
"ItemHands","ItemPelvis","ItemVulva","ItemVulvaPiercings",
|
|
|
|
"ItemDevices","ItemLegs","ItemFeet","ItemBoots"
|
|
|
|
],
|
|
|
|
COMMANDS: [
|
|
|
|
{ Tag: "disappear",
|
|
|
|
Description: ": Become invisible; requires anal hook (hair)",
|
|
|
|
Action: (argline, cmdline, args) => {
|
|
|
|
try {
|
|
|
|
window.MBCHC.make_my_anal_hook_hide_body()
|
|
|
|
} catch (x) { window.ChatRoomSendLocal(`(Error: ${x.toString()})`) }
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ Tag: "title",
|
|
|
|
Description: "[Title]: (WIP) Set a custom title (one short word, letters only)",
|
|
|
|
Action: (argline, cmdline, args) => {
|
|
|
|
try {
|
|
|
|
window.MBCHC.action_title(args)
|
|
|
|
} catch (x) { window.ChatRoomSendLocal(`(Error: ${x.toString()})`) }
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ Tag: "donate",
|
|
|
|
Description: "[MemberNumber]: Buy data and send it to recipient",
|
|
|
|
Action: (argline, cmdline, args) => {
|
|
|
|
try {
|
|
|
|
window.MBCHC.action_donate(args)
|
|
|
|
} catch (x) { window.ChatRoomSendLocal(`(Error: ${x.toString()})`) }
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ Tag: "autohack",
|
|
|
|
Description: ": Toggle autohack mode",
|
|
|
|
Action: (argline, cmdline, args) => {
|
|
|
|
try {
|
|
|
|
window.MBCHC.action_autohack()
|
|
|
|
} catch (x) { window.ChatRoomSendLocal(`(Error: ${x.toString()})`) }
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ Tag: "nod",
|
|
|
|
Description: ": Nod",
|
|
|
|
Action: (argline, cmdline, args) => {
|
|
|
|
try {
|
|
|
|
window.MBCHC.run_activity(window.Player, "ItemHead", "Nod")
|
|
|
|
} catch (x) { window.ChatRoomSendLocal(`(Error: ${x.toString()})`) }
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ Tag: "shake",
|
|
|
|
Description: ": Shake your head",
|
|
|
|
Action: (argline, cmdline, args) => {
|
|
|
|
try {
|
|
|
|
window.MBCHC.run_activity(window.Player, "ItemHead", "Wiggle")
|
|
|
|
} catch (x) { window.ChatRoomSendLocal(`(Error: ${x.toString()})`) }
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ Tag: "shrug",
|
|
|
|
Description: ": Shrug",
|
|
|
|
Action: (argline, cmdline, args) => {
|
|
|
|
try {
|
|
|
|
window.MBCHC.send_activity(`${window.CharacterNickname(window.Player)} shrugs.`)
|
|
|
|
} catch (x) { window.ChatRoomSendLocal(`(Error: ${x.toString()})`) }
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ Tag: "myself",
|
|
|
|
Description: "[Message]: Send a custom activity as yourself (or \"@Message\")",
|
|
|
|
Action: (argline, cmdline, args) => {
|
|
|
|
if (!window.MBCHC.empty(argline)) {
|
|
|
|
try {
|
|
|
|
let message = window.MBCHC.add_full_stop(argline)
|
|
|
|
window.MBCHC.send_activity(`${window.CharacterNickname(window.Player)} ${message}`)
|
|
|
|
} catch (x) { window.ChatRoomSendLocal(`(Error: ${x.toString()})`) }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ Tag: "activity",
|
|
|
|
Description: "[Message]: Send a custom activity (or \"@@Message\")",
|
|
|
|
Action: (argline, cmdline, args) => {
|
|
|
|
if (!window.MBCHC.empty(argline)) {
|
|
|
|
try {
|
|
|
|
let message = window.MBCHC.add_full_stop(window.MBCHC.capitalise(argline))
|
|
|
|
window.MBCHC.send_activity(message)
|
|
|
|
} catch (x) { window.ChatRoomSendLocal(`(Error: ${x.toString()})`) }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
log: function(msg) {return("MBCHC: " + msg.toString())},
|
|
|
|
empty: function(text) {
|
|
|
|
if (!text) return(true)
|
|
|
|
if (String(text).trim().length < 1) return(true)
|
|
|
|
return(false)
|
|
|
|
},
|
|
|
|
add_full_stop: function(text) {
|
|
|
|
if (text.endsWith('.')) return(text)
|
|
|
|
return(`${text}.`)
|
|
|
|
},
|
|
|
|
capitalise: function(text, lower = false) {
|
|
|
|
let first = text.at(0).toLocaleUpperCase()
|
|
|
|
let rest = text.slice(1)
|
|
|
|
if (lower) rest = rest.toLocaleLowerCase()
|
|
|
|
return(first + rest)
|
|
|
|
},
|
|
|
|
// we need this one here, this is our main loading hook
|
|
|
|
orig_AsylumGGTSSAddItems: window.AsylumGGTSSAddItems,
|
|
|
|
} // MBCHC
|
|
|
|
|
|
|
|
// Loader
|
|
|
|
window.AsylumGGTSSAddItems = function() {
|
|
|
|
if (!window.MBCHC.LOADED) {
|
|
|
|
|
|
|
|
// Save originals hopefully after patching
|
|
|
|
window.MBCHC.orig_ChatRoomMessageInvolvesPlayer = window.ChatRoomMessageInvolvesPlayer
|
|
|
|
window.MBCHC.orig_ChatRoomReceiveSuitcaseMoney = window.ChatRoomReceiveSuitcaseMoney
|
|
|
|
window.MBCHC.orig_ChatRoomSendChat = window.ChatRoomSendChat
|
|
|
|
|
|
|
|
// Functions
|
|
|
|
window.MBCHC.HIDE_ALL = window.MBCHC.HIDE_SPECIAL.concat(window.MBCHC.HIDE_BODY).concat(window.MBCHC.HIDE_CLOTHES).concat(window.MBCHC.HIDE_ITEMS)
|
|
|
|
window.MBCHC.make_my_anal_hook_hide_body = function() {
|
|
|
|
let item = window.InventoryGet(window.Player, "ItemButt")
|
|
|
|
if (!item || !item.Asset || !item.Asset.Name) throw "butt seems empty"
|
|
|
|
if (item.Asset.Name !== "AnalHook") throw "butt seems occupied by something other than the anal hook"
|
|
|
|
if (!item.Property.Type || item.Property.Type !== "Hair") throw "anal hook seems not tied to hair"
|
|
|
|
item.Property = {Type: "Hair", Hide: this.HIDE_ALL}
|
|
|
|
window.CharacterRefresh(window.Player, true, true)
|
|
|
|
}
|
|
|
|
window.MBCHC.donate_data = function(id) {
|
|
|
|
if (id == window.Player.MemberNumber) throw "recipient must not be you"
|
|
|
|
const char = window.ChatRoomCharacter.find( c => c.MemberNumber == id )
|
|
|
|
if (!char) throw "recipient not found"
|
|
|
|
if (!char.IsRestrained()) throw "recipient must be bound"
|
|
|
|
const cost = (Math.random() * 10 + 15).toFixed(0)
|
|
|
|
if (window.Player.Money < cost) throw "not enough money"
|
|
|
|
window.CharacterChangeMoney(window.Player, -cost)
|
|
|
|
window.ServerSend("ChatRoomChat", {Content: "ReceiveSuitcaseMoney", Type: "Hidden", Target: id})
|
|
|
|
return({cost: cost, name: (char.Nickname || char.Name)})
|
|
|
|
}
|
|
|
|
window.MBCHC.run_activity = function(char, ag, action) {
|
|
|
|
try {
|
|
|
|
char.FocusGroup = window.AssetGroupGet(char.AssetFamily, ag)
|
|
|
|
if (!char.FocusGroup) throw "invalid AssetGroup"
|
|
|
|
let activity = window.ActivityAllowedForGroup(char, char.FocusGroup.Name).find( a => a.Name === action)
|
|
|
|
if (!activity) throw "invalid activity"
|
|
|
|
window.ActivityRun(char, activity)
|
|
|
|
} finally {
|
|
|
|
char.FocusGroup = null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
window.MBCHC.send_activity = function(msg) {
|
|
|
|
window.ServerSend("ChatRoomChat", {Type: "Action", Content: "lef_wie234jf_owhwi", Dictionary: [{Tag: 'MISSING PLAYER DIALOG: lef_wie234jf_owhwi', Text: msg}]})
|
|
|
|
}
|
|
|
|
// Command actions
|
|
|
|
window.MBCHC.action_title = function(args) {
|
|
|
|
let title = args.shift()
|
|
|
|
if (!title || !title.length || title.length < 1) throw "empty title"
|
|
|
|
if (title.length > 16) throw "title too long"
|
|
|
|
if (!title.match(window.MBCHC.RE_TITLE)) throw "invalid title"
|
|
|
|
let first = title.at(0).toLocaleUpperCase()
|
|
|
|
let rest = title.slice(1).toLocaleLowerCase()
|
|
|
|
title = first + rest
|
|
|
|
window.TitleSet(title)
|
|
|
|
// TODO: this needs much more work. at least don't push a second title
|
|
|
|
// we need to patch the text cache
|
|
|
|
// we need to check for other players' custom titles
|
|
|
|
window.TitleList.push({Name: title, Requirement: () => {return true}})
|
|
|
|
}
|
|
|
|
window.MBCHC.action_donate = function(args) {
|
|
|
|
let id = Number.parseInt(args.shift())
|
|
|
|
if (isNaN(id)) throw "empty or invalid member number"
|
|
|
|
let result = window.MBCHC.donate_data(id)
|
|
|
|
window.ChatRoomSendLocal(`(You've bought data for $${result.cost} and sent it to ${result.name})`)
|
|
|
|
}
|
|
|
|
window.MBCHC.action_autohack = function() {
|
|
|
|
window.MBCHC.AUTOHACK_ENABLED = !window.MBCHC.AUTOHACK_ENABLED
|
|
|
|
window.ChatRoomSendLocal(`(Autohack is now ${window.MBCHC.AUTOHACK_ENABLED ? "enabled" : "disabled"})`)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hooks
|
|
|
|
window.ChatRoomMessageInvolvesPlayer = function(data) {
|
|
|
|
if (!data.MBCHC_ID) {
|
|
|
|
data.MBCHC_ID = window.MBCHC.NEXT_MESSAGE
|
|
|
|
window.MBCHC.NEXT_MESSAGE += 1
|
|
|
|
if (window.MBCHC.LOG_MESSAGES) console.debug(data)
|
|
|
|
if (("ReceiveSuitcaseMoney" === data.Content) && ("Hidden" === data.Type)) { window.MBCHC.LAST_HACKED = data.Sender }
|
|
|
|
}
|
|
|
|
return(window.MBCHC.orig_ChatRoomMessageInvolvesPlayer(data))
|
|
|
|
}
|
|
|
|
window.ChatRoomReceiveSuitcaseMoney = function() {
|
|
|
|
let result = window.MBCHC.orig_ChatRoomReceiveSuitcaseMoney()
|
|
|
|
if (window.MBCHC.AUTOHACK_ENABLED && window.MBCHC.LAST_HACKED) {
|
|
|
|
window.CurrentCharacter = {MemberNumber: window.MBCHC.LAST_HACKED}
|
|
|
|
window.MBCHC.LAST_HACKED = null
|
|
|
|
window.ChatRoomTryToTakeSuitcase()
|
|
|
|
}
|
|
|
|
return(result)
|
|
|
|
}
|
|
|
|
window.ChatRoomSendChat = function() {
|
|
|
|
let input = window.ElementValue("InputChat")
|
|
|
|
if (!input.startsWith("@@@")) {
|
|
|
|
input = input.replace(/^@@/, "/activity ")
|
|
|
|
input = input.replace(/^@/, "/myself ")
|
|
|
|
window.ElementValue("InputChat", input)
|
|
|
|
}
|
|
|
|
return(window.MBCHC.orig_ChatRoomSendChat())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Actions
|
|
|
|
window.CommandCombine(window.MBCHC.COMMANDS)
|
|
|
|
if (window.bcModSdk) window.bcModSdk.registerMod("MBCHC", window.MBCHC.VERSION)
|
|
|
|
window.MBCHC.LOADED = true
|
|
|
|
console.info(window.MBCHC.log("loaded version " + window.MBCHC.VERSION))
|
|
|
|
}
|
|
|
|
return(window.MBCHC.orig_AsylumGGTSSAddItems())
|
|
|
|
} // Loader
|
|
|
|
})()
|