diff --git a/mbchc-local.user.js b/mbchc-local.user.js index 5bf7368..3d04a59 100644 --- a/mbchc-local.user.js +++ b/mbchc-local.user.js @@ -31,6 +31,7 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER LOADED: false, AUTOHACK_ENABLED: false, LAST_HACKED: null, + HISTORY_MODE: false, RE_TITLE: /^[a-zA-Z]+$/, RE_PREF_ACTIVITY_ME: /^@/, RE_PREF_ACTIVITY: /^@@/, @@ -41,9 +42,11 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER RE_CARET: /^\^/, RE_SPACES: /\s{2,}/g, RE_LAST_WORD: /(^|\s)([^\s]*)$/, + RE_LAST_LETTER: /[\w]$/, RGB_MUTE: "#6c2132", RGB_POLLY: "#81b1e7", - COMP_DIV_ID: "MBCHC_AUTOCOMPLETE_HINT", +// COMP_DIV_ID: "MBCHC_AUTOCOMPLETE_HINT", +// COMP_DIV_SHOWN: false, UTC_OFFSET: new Date().getTimezoneOffset() * 60 * 1000, HAND_PENETRATORS: ["Flogger", "Whip", "TennisRacket", "Gavel", "SmallVibratingWand", "LargeDildo", "Vibrator", "Hairbrush", "SmallDildo", "Baguette", "Spatula", "Broom"], HIDE_SPECIAL: ["Activity","Emoticon"], @@ -193,7 +196,7 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER } window.ServerAccountUpdate.QueueData({OnlineSettings: window.Player.OnlineSettings}) }, - log: function(msg) {return("MBCHC: " + String(msg))}, + log: function(level, msg) {console[level]("MBCHC: " + String(msg))}, empty: function(text) { if (!text) return(true) if (String(text).trim().length < 1) return(true) @@ -208,11 +211,10 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER let rest = result.slice(1) result = first + rest } - if (options.dot && result.match(/[\w]$/)) result = `${result}.` + if (options.dot && result.match(this.RE_LAST_LETTER)) result = `${result}.` return(result) }, - bg_colour: function() { return(document.getElementById("TextAreaChatLog").dataset.colortheme.startsWith("light") ? this.RGB_POLLY : this.RGB_MUTE) }, - inform: function(html, timeout = 60000) { window.ChatRoomSendLocal(`
${html}
`, timeout) }, + inform: function(html, timeout = 60000) { window.ChatRoomSendLocal(`
${html}
`, timeout) }, report: function(x) { this.inform(`Error: ${x.toString()}`) if (this.RETHROW) throw x @@ -224,11 +226,11 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER return(this.ensure(`character ${cid} not found in the room`, () => window.ChatRoomCharacter.find(c => c.cid === cid))) }, pos2char: function(pos) { - if (pos >= window.ChatRoomCharacter.length) throw `invalid position ${pos}` + if (!this.in(pos, 0, window.ChatRoomCharacter.length - 1)) throw `invalid position ${pos}` return(window.ChatRoomCharacter[pos]) }, rel2char: function(target) { - let me = this.ensure("can't find my position", () => window.ChatRoomCharacter.findIndex(char => char.IsPlayer()) + 1) - 1 + let me = this.ensure("can't find my position", () => window.ChatRoomCharacter.findIndex(char => char.IsPlayer()) + 1) - 1 // 0 is falsy, but is valid index let pos = null if (target.match(this.RE_ALL_LEFT)) pos = me - target.length if (target.match(this.RE_ALL_RIGHT)) pos = me + target.length @@ -247,8 +249,8 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER if (target.startsWith("<") || target.startsWith(">")) return(this.rel2char(target)) if (!isNaN(int) && int.toString() === target) { // we got a number if (this.in(int, 0, 9)) return(this.pos2char(int)) - if (this.in(int, 11, 15)) return(this.pos2char((int % 10) - 1)) - if (this.in(int, 21, 25)) return(this.pos2char((5 + int % 20) - 1)) + if (this.in(int, 11, 15)) return(this.pos2char(int - 11)) + if (this.in(int, 21, 25)) return(this.pos2char(int - 16)) found = found.concat(window.ChatRoomCharacter.filter(c => c.cid.toString().indexOf(target) > -1)) } if (target.startsWith("@")) target = target.slice(1) @@ -265,7 +267,7 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER let char = this.target2char(target) if (char.IsPlayer()) throw "target must not be you" if (!char.IsRestrained()) throw "target must be bound" - const cost = (Math.random() * 10 + 15).toFixed(0) + const cost = Math.round((Math.random() * 10 + 15)) if (window.Player.Money < cost) throw "not enough money" window.CharacterChangeMoney(window.Player, -cost) window.ServerSend("ChatRoomChat", {Content: "ReceiveSuitcaseMoney", Type: "Hidden", Target: char.cid}) @@ -412,43 +414,37 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER let action = mbchc.ensure(`invalid action (${verb} ${zone} ${target})`, () => actions.find(name => available.find(a => a.Name === name))) mbchc.run_activity(char, ag, action) } catch (x) { mbchc.report(x) } }, + bell: function() { + setTimeout(() => {document.getElementById("InputChat").style.outline = ""}, 100) + document.getElementById("InputChat").style.outline = "solid red" + }, complete: function(options, space = true) { - const chat = document.getElementById("InputChat") - if (options.length < 1) { - setTimeout(() => {chat.style.outline = ""}, 100) - return(chat.style.outline = "solid red") - } + if (options.length < 1) return(this.bell()) if (options.length > 1) { let width = Math.max(...options.map(o => o.length)) let pref = null for (let i = width; i > 0; i -= 1) { let test = options[0].slice(0, i); if (options.every(o => o.startsWith(test))) {pref = test; break} } if (pref) this.complete([pref], false) this.complete_hint(options) - } else window.ElementValue("InputChat", chat.value.replace(this.RE_LAST_WORD, `$1${options[0]}${space ? " " : ""}`)) + } else window.ElementValue("InputChat", document.getElementById("InputChat").value.replace(this.RE_LAST_WORD, `$1${options[0]}${space ? " " : ""}`)) }, complete_hint: function(options) { - // TODO increase text density - // TODO show the hint - // TODO hide the hint - let log = document.getElementById("TextAreaChatLog") - if (!log) return - let div = document.getElementById(this.COMP_DIV_ID) - if (!div) { - div = document.createElement("div") - div.id = this.COMP_DIV_ID - div.setAttribute('style', `background-color:${this.bg_colour()}`) - } - let hint = options.sort().map(s => `
${s}
`).join("") - div.innerHTML = `
Available completions:
${hint}` -// log.appendChild(div) + this.COMP_HINT.innerHTML = options.sort().map(s => `
${s}
`).join("") + this.COMP_HINT.style.display = "flex" + window.ElementSetDataAttribute(this.COMP_HINT.id, "colortheme", (window.Player.ChatSettings.ColorTheme || "Light")) + let rescroll = window.ElementIsScrolledToEnd("TextAreaChatLog") + window.ChatRoomResize(false) + if (rescroll) window.ElementScrollToEnd("TextAreaChatLog") }, + comp_hint_visible: function() {return(this.COMP_HINT.parentElement && "flex" === this.COMP_HINT.style.display)}, + complete_hint_hide: function(options) {if (!this.comp_hint_visible()) return; this.COMP_HINT.style.display = "none"; window.ChatRoomResize(false)}, complete_target: function(token, me2 = true) { let locase = token.toLocaleLowerCase() - let found = [] - window.ChatRoomCharacter.filter(c => (c.IsPlayer() && !me2) ? null : c.Name.toLocaleLowerCase().startsWith(locase)).forEach(c => {if (!found.includes(c.Name)) found.push(c.Name)}) - window.ChatRoomCharacter.filter(c => (c.IsPlayer() && !me2) ? null : c.Nickname.toLocaleLowerCase().startsWith(locase)).forEach(c => {if (!found.includes(c.Nickname)) found.push(c.Nickname)}) - window.ChatRoomCharacter.filter(c => (c.IsPlayer() && !me2) ? null : c.MemberNumber.toString().startsWith(locase)).forEach(c => {if (!found.includes(c.MemberNumber.toString())) found.push(c.MemberNumber.toString())}) - this.complete(found) + let found = {} + for (let c of window.ChatRoomCharacter) { + if (!c.IsPlayer() || me2) [c.Name, c.Nickname, c.cid.toString()].forEach(s => {if (s.toLocaleLowerCase().startsWith(locase)) found[s] = true}) + } + this.complete(Object.keys(found)) }, complete_common: function() { let input = document.getElementById("InputChat").value @@ -491,6 +487,17 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER return(mbchc.complete_do_target(ags[mbchc.DO_DATA.zones[zone]], tokens[3])) } }, + history: function(down) { + let text = window.ElementValue("InputChat") + if (!this.HISTORY_MODE) { + window.ChatRoomLastMessage.push(text) + this.HISTORY_MODE = true + } + if (down && (window.ChatRoomLastMessageIndex > window.ChatRoomLastMessage.length - 2)) return(this.bell()) + if (!down && (window.ChatRoomLastMessageIndex < 2)) return(this.bell()) + window.ChatRoomLastMessageIndex = (down) ? window.ChatRoomLastMessageIndex + 1 : window.ChatRoomLastMessageIndex - 1 + window.ElementValue("InputChat", window.ChatRoomLastMessage[window.ChatRoomLastMessageIndex]) + }, loader: function() { if (this.remove_load_hook) { this.remove_load_hook() @@ -507,13 +514,40 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER this.CommandsKey = CommandsKey /* eslint-disable-line no-undef */ // window.CommandsKey is undefined this.RE_ACTIVITY = RegExp(`^${this.CommandsKey}activity `) this.PREF_ACTIVITY = `${this.CommandsKey}activity ` + this.COMP_HINT = document.createElement("div") + this.COMP_HINT.id = "mbchcCompHint" + let css = document.createElement("style") + css.type = "text/css" + css.textContent = ` + #TextAreaChatLog .mbchc, #TextAreaChatLog .mbchc { + background-color: ${this.RGB_POLLY}; + } + #TextAreaChatLog[data-colortheme="dark"] .mbchc, #TextAreaChatLog[data-colortheme="dark2"] .mbchc { + background-color: ${this.RGB_MUTE}; + } + #${this.COMP_HINT.id} { + flex-flow: column wrap; + overflow: auto; + display: none; + background-color: ${this.RGB_POLLY}; + color: black; + } + #${this.COMP_HINT.id}[data-colortheme="dark"], #${this.COMP_HINT.id}[data-colortheme="dark2"] { + background-color: ${this.RGB_MUTE}; + color: white; + } + #${this.COMP_HINT.id} div { + margin: 0 0.5ex; + } + ` + document.head.appendChild(css) // Actions this.calculate_maps() this.patch_handheld() window.Player.MBCHC = {VERSION: this.VERSION} window.CommandCombine(COMMANDS) this.LOADED = true - console.info(this.log(`loaded version ${this.VERSION}`)) + this.log("info", `loaded version ${this.VERSION}`) } } // MBCHC @@ -547,12 +581,15 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER }) window.MBCHC.sdk.hookFunction("ChatRoomSendChat", 0, (nextargs, next) => { let input = window.ElementValue("InputChat") - if (!input.startsWith("@@@")) { + if (!input.startsWith("@@@") && input.startsWith("@")) { input = input.replace(window.MBCHC.RE_PREF_ACTIVITY, window.MBCHC.PREF_ACTIVITY) input = input.replace(window.MBCHC.RE_PREF_ACTIVITY_ME, `${window.MBCHC.PREF_ACTIVITY}<${window.Player.cid}:>SourceCharacter `) + window.ElementValue("InputChat", input) } - window.ElementValue("InputChat", input) - return(next(nextargs)) + let result = next(nextargs) + let history = window.ChatRoomLastMessage + if ((history.length > 1) && (history[history.length - 1] === history[history.length - 2])) {history.pop(); window.ChatRoomLastMessageIndex -= 1} + return(result) }) window.MBCHC.sdk.hookFunction("ChatRoomDrawCharacterOverlay", 0, (nextargs, next) => { let [C, CharX, CharY, Zoom, Pos] = nextargs @@ -573,6 +610,39 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER if (("bce_LayerPriority" === ID) && window.CurrentCharacter && window.CurrentCharacter.FocusGroup && window.InventoryLocked(window.CurrentCharacter, window.CurrentCharacter.FocusGroup.Name, true)) window.ElementSetAttribute(ID, "disabled", true) return(result) }) + window.MBCHC.sdk.hookFunction("ChatRoomCreateElement", 0, (nextargs, next) => { + let result = next(nextargs) + if (!window.MBCHC.COMP_HINT.parentElement) document.body.appendChild(window.MBCHC.COMP_HINT) + return(result) + }) + window.MBCHC.sdk.hookFunction("ChatRoomClearAllElements", 0, (nextargs, next) => { + window.MBCHC.complete_hint_hide() + window.MBCHC.COMP_HINT.remove() + return(next(nextargs)) + }) + window.MBCHC.sdk.hookFunction("ChatRoomResize", 0, (nextargs, next) => { + let result = next(nextargs) + if (window.CharacterGetCurrent() == null && window.CurrentScreen == "ChatRoom" && document.getElementById("InputChat") && document.getElementById("TextAreaChatLog") && window.MBCHC.comp_hint_visible()) { // upstream + let fontsize = ChatRoomFontSize /* eslint-disable-line no-undef */ // window.ChatRoomFontSize is undefined + window.ElementPositionFix("TextAreaChatLog", fontsize, 1005, 66, 988, 630) + window.ElementPositionFix(window.MBCHC.COMP_HINT.id, fontsize, 1005, 701, 988, 200) + window.MBCHC.COMP_HINT.style.display = "flex" + } + return(result) + }) + window.MBCHC.sdk.hookFunction("ChatRoomKeyDown", 0, (nextargs, next) => { + window.MBCHC.complete_hint_hide() + if ((window.KeyPress == 33) || (window.KeyPress == 34)) return(window.MBCHC.history(window.KeyPress - 33)) // better history + if (window.MBCHC.HISTORY_MODE) { + window.ChatRoomLastMessage.pop() + window.MBCHC.HISTORY_MODE = false + } + return(next(nextargs)) + }) + window.MBCHC.sdk.hookFunction("ChatRoomClick", 0, (nextargs, next) => { + window.MBCHC.complete_hint_hide() + return(next(nextargs)) + }) window.MBCHC.remove_bce_hook = window.MBCHC.sdk.hookFunction("MainRun", 0, (nextargs, next) => { if (window.bce_ActivityTriggers) window.MBCHC.patch_bce() return(next(nextargs))