diff --git a/mbchc-local.user.js b/mbchc-local.user.js
index 36f6f67..05a74b0 100644
--- a/mbchc-local.user.js
+++ b/mbchc-local.user.js
@@ -160,7 +160,7 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER
"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])},
"title": {desc: "set a custom title (WIP)", args: {TITLE: {}}, cb: (mbchc, args) => mbchc.title(args[0])},
- "tz": {desc: "set target's UTC offset", args: {TARGET: {}, OFFSET: {}}, 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 => {if (window.Player.OnlineSettings.MBCHC) {delete window.Player.OnlineSettings.MBCHC; mbchc.save_settings()}}},
},
ensure: function(error, callback) {
@@ -367,10 +367,10 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER
this.hello()
},
set_timezone: function(args) {
- let char = this.target2char(args[0])
- let tz = Number.parseInt(args[1])
- if (isNaN(tz)) throw "invalid offset"
+ let tz = Number.parseInt(args[0])
+ if (isNaN(tz)) throw `invalid offset "${args[0]}"`
if (!this.in(tz, -12, 12)) throw "offset should be [-12,12]"
+ let char = this.target2char(args[1])
char.MBCHC_LOCAL.TZ = tz
this.save_settings(s => {if (!s.timezones) s.timezones = {}; s.timezones[char.cid] = tz})
},
@@ -411,10 +411,6 @@ 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) } },
- complete_common: function() {
- let input = document.getElementById("InputChat").value
- return([this, input, input.replace(this.RE_SPACES, " ").split(" ")])
- },
complete: function(options) {
const chat = document.getElementById("InputChat")
if (options.length < 1) {
@@ -424,7 +420,8 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER
if (options.length > 1) {
// TODO
// autocomplete to common prefix
- // better hint: hide on input
+ // better hint: replace existing or hide previous on new hint
+ // better hint: hide on input?
// better hint: increase density
this.inform(options.sort().map(s => `
${s}
`).join(""), 10000)
} else {
@@ -432,17 +429,54 @@ var bcModSdk=function(){"use strict";const o="1.0.2";function e(o){alert("Mod ER
window.ElementFocus("InputChat")
}
},
+ 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)
+ },
+ complete_common: function() {
+ let input = document.getElementById("InputChat").value
+ return([this, input, input.replace(this.RE_SPACES, " ").split(" ")])
+ },
complete_mbchc: function(args, locase, cmdline) { const [mbchc, input, tokens] = window.MBCHC.complete_common(); // `this` is command object
-//console.debug([input, tokens])
if (tokens.length < 1) return
- if (tokens.length < 2) mbchc.complete([`${mbchc.CommandsKey}${this.Tag}`])
- if (tokens.length < 3) mbchc.complete(Object.keys(mbchc.SUBCOMMANDS_MBCHC).filter(c => c.startsWith(tokens[1]))) // complete subcommand name
+ if (tokens.length < 2) return(mbchc.complete([`${mbchc.CommandsKey}${this.Tag}`]))
+ if (tokens.length < 3) return(mbchc.complete(Object.keys(mbchc.SUBCOMMANDS_MBCHC).filter(c => c.startsWith(tokens[1])))) // complete subcommand name
+ let sub = mbchc.SUBCOMMANDS_MBCHC[tokens[1]]
+ if (sub && sub.args) {
+ let argname = Object.keys(sub.args)[tokens.length - 3]
+ if ("TARGET" === argname) return(mbchc.complete_target(tokens[tokens.length - 1], false))
+ if ("[TARGET]" === argname) return(mbchc.complete_target(tokens[tokens.length - 1]), true)
+ }
+ },
+ complete_do_target: function(actions, token) {
+ if (!actions) return
+ if (actions.self.length > 0) {
+ if (actions.others.length < 1) return(this.complete([window.Player.cid.toString()])) // target is always the player
+ this.complete_target(token, true)
+ } else this.complete_target(token, false)
},
complete_do: function(args, locase, cmdline) { const [mbchc, input, tokens] = window.MBCHC.complete_common(); // `this` is command object
-//console.debug([input, tokens])
if (tokens.length < 1) return
- if (tokens.length < 2) mbchc.complete([`${mbchc.CommandsKey}${this.Tag}`])
- if (tokens.length < 3) mbchc.complete(Object.keys(mbchc.DO_DATA.verbs).filter(c => c.startsWith(tokens[1]))) // complete verb
+ if (tokens.length < 2) return(mbchc.complete([`${mbchc.CommandsKey}${this.Tag}`]))
+ // FIXME filter only available actions
+ if (tokens.length < 3) return(mbchc.complete(Object.keys(mbchc.DO_DATA.verbs).filter(c => c.startsWith(tokens[1])))) // complete verb
+ let verb = tokens[1].toLocaleLowerCase()
+ let ags = mbchc.DO_DATA.verbs[verb]
+ if (!ags) return
+ if (tokens.length < 4) { // complete zone or target
+ if (Object.keys(ags).length < 2) return(mbchc.complete_do_target(ags[Object.keys(ags)[0]], tokens[2])) // zone implied, complete target
+ let zones = Object.entries(mbchc.DO_DATA.zones).filter(([zone, ag]) => zone.startsWith(tokens[2]) && ags[ag]).map(([zone,ag]) => zone)
+ return(mbchc.complete(zones))
+ }
+ if (tokens.length < 5) { // complete target where it belongs
+ if (Object.keys(ags).length < 2) return // zone implied, target already given
+ let zone = tokens[2].toLocaleLowerCase()
+ return(mbchc.complete_do_target(ags[mbchc.DO_DATA.zones[zone]], tokens[3]))
+ }
},
loader: function() {
if (this.remove_load_hook) {