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))