From 1d8e3b100b66dbfb6ab3f1372e1257a083b8073c Mon Sep 17 00:00:00 2001 From: Mute Date: Wed, 6 Jul 2022 07:02:59 +0000 Subject: [PATCH] Update 'mbchc-local.user.js' --- mbchc-local.user.js | 57 ++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/mbchc-local.user.js b/mbchc-local.user.js index 043b508..aa099d1 100644 --- a/mbchc-local.user.js +++ b/mbchc-local.user.js @@ -19,6 +19,8 @@ /** @type {ModSDKGlobalAPI} */ // eslint-disable-next-line var bcModSdk=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:\nPattern:\n${e}\nPatch1:\n${t.get(e)||""}\nPatch2:\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>>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(ao.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.\nWas 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 r}`);for(const[n,i]of Object.entries(r))"string"==typeof i?a.patches.set(n,i):null===i?a.patches.delete(n):e(`Mod '${o}' failed to patch function '${t}': Invalid format of patch '${n}'`);f()},removePatches:o=>{c.loaded||e(`Mod '${c.name}' attempted to call SDK function after being unloaded`);i(o).patches.clear(),f()},callOriginal:(t,n,r)=>(c.loaded||e(`Mod '${c.name}' attempted to call SDK function after being unloaded`),"string"==typeof t&&t||e(`Mod '${o}' failed to call a function: Expected function name string, got ${typeof t}`),Array.isArray(n)||e(`Mod '${o}' failed to call a function: Expected args array, got ${typeof n}`),function(o,e,t=window){return l(o).original.apply(t,e)}(t,n,r)),getOriginalHash:t=>("string"==typeof t&&t||e(`Mod '${o}' failed to get hash: Expected function name string, got ${typeof t}`),l(t).originalHash)},c={name:o,version:t,allowReplace:r,api:d,loaded:!0,patching:new Map};return u.set(o,c),Object.freeze(d)}function m(){const o=[];for(const e of u.values())o.push({name:e.name,version:e.version});return o}let w;const y=void 0===window.bcModSdk?window.bcModSdk=function(){const e={version:o,apiVersion:1,registerMod:g,getModsInfo:m,getPatchingInfo:p,errorReporterHooks:Object.seal({hookEnter:null,hookChainExit:null})};return w=e,Object.freeze(e)}():(n(window.bcModSdk)||e("Failed to init Mod SDK: Name already in use"),1!==window.bcModSdk.apiVersion&&e(`Failed to init Mod SDK: Different version already loaded ('1.0.2' vs '${window.bcModSdk.version}')`),window.bcModSdk.version!==o&&alert(`Mod SDK warning: Loading different but compatible versions ('1.0.2' vs '${window.bcModSdk.version}')\nOne of mods you are using is using an old version of SDK. It will work for now but please inform author to update`),window.bcModSdk);return"undefined"!=typeof exports&&(Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=y),y}(); +// FIXME read chars as they enter +// TODO BCE emotes detector -> activities (function() { "use strict"; if (!window.AsylumGGTSSAddItems) throw "AsylumGGTSSAddItems() not found, aborting MBCHC loading" @@ -153,7 +155,7 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER "
/mbchc versions : show the mod versions across the room
", "
/mbchc autohack : toggle the autohack feature
", "
/mbchc disappear : become invisible (requires anal hook -> hair)
", - "
/mbchc donate MEMBERNUMBER : Buy data and send it to recipient
", + "
/mbchc donate TARGET : Buy data and send it to recipient
", "
/mbchc title TITLE : set a custom title (WIP)
", "
/mbchc tz TARGET NUM : set target's UTC offset
", "
/mbchc purge! : delete MBCHC online saved data
", @@ -163,6 +165,11 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER { Tag: "activity", Description: "[Message]: Send a custom activity (or \"@@Message\", or \"@Message\" as yourself)", Action: (argline, cmdline, args) => { window.MBCHC.command_activity(argline, cmdline, args) } }, { Tag: "do", Description: ": Do an activity, as if clicked on its button (\"/do\" for help)", Action: (argline, cmdline, args) => { window.MBCHC.command_do(argline, cmdline, args) } }, ], + ensure: function(error, callback) { + let result = callback.call(this) + if (!result) throw error + return(result) + }, calculate_maps: function() { this.DO_DATA = {verbs: {}, zones: {}} for (let [verbs, data] of Object.entries(this.MAP_ACTIONS)) { @@ -208,11 +215,10 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER id2char: function(id) { return(window.ChatRoomCharacter.find( c => c.MemberNumber === Number.parseInt(id) )) }, donate_data: function(recipient) { let id = Number.parseInt(recipient) - if (isNaN(id)) throw "empty or invalid recipient" - if (id === window.Player.MemberNumber) throw "recipient must not be you" - const char = this.id2char(id) - if (!char) throw "recipient not found" - if (!char.IsRestrained()) throw "recipient must be bound" + if (isNaN(id)) throw "empty or invalid target" + if (id === window.Player.MemberNumber) throw "target must not be you" + const char = this.ensure("target not found", () => this.id2char(id)) + if (!char.IsRestrained()) throw "target 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) @@ -220,10 +226,8 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER return({cost: cost, name: window.CharacterNickname(char)}) }, 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, true).find( a => a.Name === action) - if (!activity) throw "invalid activity" + char.FocusGroup = this.ensure("invalid AssetGroup", () => window.AssetGroupGet(char.AssetFamily, ag)) + let activity = this.ensure("invalid activity", () => window.ActivityAllowedForGroup(char, char.FocusGroup.Name, true).find( a => a.Name === action)) if (activity.Name.endsWith("Item")) { var dict = [{Tag: "NextAsset", AssetName: "SpankingToys"}, {Tag: "FocusAssetGroup", AssetGroupName: ag}, {Tag: "SourceCharacter", Text: window.CharacterNickname(window.Player), MemberNumber: window.Player.MemberNumber}] dict.push({Tag: "DestinationCharacter", Text: window.CharacterNickname(char), MemberNumber: char.MemberNumber}) @@ -247,10 +251,8 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER }, receive: function(data) { if (data.Sender === window.Player.MemberNumber) return // this is our own message, sent back to us - let char = this.id2char(data.Sender) - if (!char) throw `Invalid message sender: ${data.Sender}` - let payload = data.Dictionary[0] - if (!payload) throw "Empty message" + let char = this.ensure(`Invalid message sender: ${data.Sender}`, () => this.id2char(data.Sender)) + let payload = this.ensure("Empty message", () => data.Dictionary[0]) switch (payload.type) { case "greetings": case "hello": char.MBCHC = payload.value @@ -328,8 +330,7 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER } }, set_timezone: function(args) { - let char = this.id2char(args[0]) - if (!char) throw "invalid target" + let char = this.ensure("invalid target", ()=> this.id2char(args[0])) let tz = Number.parseInt(args[1]) if (isNaN(tz)) throw "invalid offset" if ((tz < -12) || (tz > 12)) throw "offset should be [-12,12]" @@ -369,28 +370,26 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER this.send_activity(message) } catch (x) { this.report(x) } } }, command_do: function(argline, cmdline, args) { try { - // 1. verb target - // 2. arousal for items + // FIXME arousal for items if (args.length < 1) return(this.inform("
Usage: /do VERB [ZONE] [TARGET]
Available verbs:
" + Object.keys(this.MAP_ACTIONS).join(", ") + "
Available zones:
" + Object.keys(this.DO_DATA.zones).join(", "))) let [verb, zone, target] = args if (!this.DO_DATA.verbs[verb]) throw `unknown verb "${verb}"` let zones = this.DO_DATA.verbs[verb] - if (1 === Object.keys(zones).length) zone = this.MAP_ZONES[Object.keys(zones)[0]][0] - if (!zone) throw "zone missing" - let ag = this.DO_DATA.zones[zone] - let char = window.Player - if (target && ((zones[ag].self.length < 1) || (zones[ag].others.length > 0))) { - char = this.id2char(target) - if (!char) throw "invalid target" + if (1 === Object.keys(zones).length) { + if (!target) target = zone + zone = this.MAP_ZONES[Object.keys(zones)[0]][0] } + if (!zone) throw "zone missing" + let ag = this.ensure(`unknown zone "${zone}"`, () => this.DO_DATA.zones[zone]) + let types = this.ensure(`zone "${zone}" invalid for "${verb}"`, () => zones[ag]) + let char = window.Player + if (target && ((types.self.length < 1) || (types.others.length > 0))) char = this.ensure("invalid target", () => this.id2char(target)) let type = (char.MemberNumber === window.Player.MemberNumber) ? "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))) - let actions = zones[ag][type] - if (!actions) throw `zone "${zone}" invalid for verb "${verb}"` - let action = actions.find(name => available.find(a => a.Name === name)) - if (!action) throw "invalid action" + let actions = this.ensure(`zone "${zone}" invalid for ("${verb}" "${type}")`, () => types[type]) + let action = this.ensure(`invalid action (${verb} ${zone} ${target})`, () => actions.find(name => available.find(a => a.Name === name))) this.run_activity(char, ag, action) } catch (x) { this.report(x) } }, loader: function() {