ApplyDamage
/* global log, _, getObj, HealthColors, playerIsGM, sendChat, on */ | |
const ApplyDamage = (() => { | |
"use strict"; | |
const version = "1.1", | |
observers = { | |
"change": [], | |
}, | |
boundedBar = false, | |
checkInstall = () => { | |
log(`-=> ApplyDamage v${version} <=-`); | |
}, | |
defaultOpts = { | |
type: "half", | |
ids: "", | |
saves: "", | |
DC: "-1", | |
dmg: "0", | |
bar: "1" | |
}, | |
statusMarkers = [ | |
"red", "blue", "green", "brown", "purple", "pink", "yellow", "dead", "skull", "sleepy", "half-heart", | |
"half-haze", "interdiction", "snail", "lightning-helix", "spanner", "chained-heart", "chemical-bolt", | |
"death-zone", "drink-me", "edge-crack", "ninja-mask", "stopwatch", "fishing-net", "overdrive", "strong", | |
"fist", "padlock", "three-leaves", "fluffy-wing", "pummeled", "tread", "arrowed", "aura", "back-pain", | |
"black-flag", "bleeding-eye", "bolt-shield", "broken-heart", "cobweb", "broken-shield", "flying-flag", | |
"radioactive", "trophy", "broken-skull", "frozen-orb", "rolling-bomb", "white-tower", "grab", "screaming", | |
"grenade", "sentry-gun", "all-for-one", "angel-outfit", "archery-target" | |
], | |
getWhisperPrefix = (playerid) => { | |
const player = getObj("player", playerid); | |
if (player && player.get("_displayname")) { | |
return `/w "${player.get("_displayname")}" `; | |
} | |
else { | |
return "/w GM "; | |
} | |
}, | |
parseOpts = (content, hasValue) => { | |
return content | |
.replace(/<br\/>\n/g, " ") | |
.replace(/({{(.*?)\s*}}\s*$)/g, "$2") | |
.split(/\s+--/) | |
.slice(1) | |
.reduce((opts, arg) => { | |
const kv = arg.split(/\s(.+)/); | |
if (hasValue.includes(kv[0])) { | |
opts[kv[0]] = (kv[1] || ""); | |
} else { | |
opts[arg] = true; | |
} | |
return opts; | |
}, {}); | |
}, | |
processInlinerolls = function (msg) { | |
if (msg.inlinerolls && msg.inlinerolls.length) { | |
return msg.inlinerolls.map(v => { | |
const ti = v.results.rolls.filter(v2 => v2.table) | |
.map(v2 => v2.results.map(v3 => v3.tableItem.name).join(", ")) | |
.join(", "); | |
return (ti.length && ti) || v.results.total || 0; | |
}).reduce((m, v, k) => m.replace(`$[[${k}]]`, v), msg.content); | |
} else { | |
return msg.content; | |
} | |
}, | |
handleError = (whisper, errorMsg) => { | |
const output = `${whisper}<div style="border:1px solid black;background:#FFBABA;padding:3px">` + | |
`<h4>Error</h4><p>${errorMsg}</p></div>`; | |
sendChat("ApplyDamage", output); | |
}, | |
finalApply = (results, dmg, type, bar, status) => { | |
const barCur = `bar${bar}_value`, | |
barMax = `bar${bar}_max`; | |
Object.entries(results).forEach(([id, saved]) => { | |
const token = getObj("graphic", id), | |
prev = JSON.parse(JSON.stringify(token || {})); | |
let newValue; | |
if (token && !saved) { | |
if (boundedBar) { | |
newValue = Math.min(Math.max(parseInt(token.get(barCur)) - dmg, 0), parseInt(token.get(barMax))); | |
} else { | |
newValue = parseInt(token.get(barCur)) - dmg; | |
} | |
if (status) token.set(`status_${status}`, true); | |
} | |
else if (token && type === "half") { | |
if (boundedBar) { | |
newValue = Math.min(Math.max(parseInt(token.get(barCur)) - Math.floor(dmg / 2), 0), parseInt(token.get(barMax))); | |
} else { | |
newValue = parseInt(token.get(barCur)) - Math.floor(dmg / 2); | |
} | |
} | |
if (!_.isUndefined(newValue)) { | |
if (Number.isNaN(newValue)) newValue = token.get(barCur); | |
token.set(barCur, newValue); | |
notifyObservers("change", token, prev); | |
} | |
}); | |
}, | |
handleInput = (msg) => { | |
if (msg.type === "api" && msg.content.search(/^!apply-damage\b/) !== -1) { | |
const hasValue = ["ids", "saves", "DC", "type", "dmg", "bar", "status"], | |
opts = Object.assign({}, defaultOpts, parseOpts(processInlinerolls(msg), hasValue)); | |
opts.ids = opts.ids.split(/,\s*/g); | |
opts.saves = opts.saves.split(/,\s*/g); | |
opts.DC = parseInt(opts.DC); | |
opts.dmg = parseInt(opts.dmg); | |
if (!playerIsGM(msg.playerid) && getObj("player", msg.playerid)) { | |
handleError(getWhisperPrefix(msg.playerid), "Permission denied."); | |
return; | |
} | |
if (!["1", "2", "3"].includes(opts.bar)) { | |
handleError(getWhisperPrefix(msg.playerid), "Invalid bar."); | |
return; | |
} | |
if (opts.status === "none") { | |
delete opts.status; | |
} | |
if (opts.status && !statusMarkers.includes(opts.status)) { | |
handleError(getWhisperPrefix(msg.playerid), "Invalid status."); | |
return; | |
} | |
const results = _.reduce(opts.ids, function (m, id, k) { | |
m[id] = parseInt(opts.saves[k] || "0") >= opts.DC; | |
return m; | |
}, {}); | |
finalApply(results, opts.dmg, opts.type, opts.bar, opts.status); | |
const output = `${ | |
getWhisperPrefix(msg.playerid) | |
}<div style="border:1px solid black;background:#FFF;padding:3px"><p>${ | |
(opts.dmg ? `${opts.dmg} damage applied to tokens, with ${ | |
(opts.type === "half" ? "half" : "no") | |
} damage on a successful saving throw.` : "")}${ | |
(opts.status ? ` ${opts.status} status marker applied to tokens that failed the save.` : "") | |
}</p></div>`; | |
sendChat("ApplyDamage", output, null, { noarchive: true }); | |
} | |
return; | |
}, | |
notifyObservers = (event, obj, prev) => { | |
observers[event].forEach(observer => observer(obj, prev)); | |
}, | |
registerObserver = (event, observer) => { | |
if (observer && _.isFunction(observer) && observers.hasOwnProperty(event)) { | |
observers[event].push(observer); | |
} else { | |
log("ApplyDamage event registration unsuccessful."); | |
} | |
}, | |
registerEventHandlers = () => { | |
on("chat:message", handleInput); | |
}; | |
return { | |
checkInstall, | |
registerEventHandlers, | |
registerObserver | |
}; | |
})(); | |
on("ready", () => { | |
"use strict"; | |
ApplyDamage.checkInstall(); | |
ApplyDamage.registerEventHandlers(); | |
if ("undefined" !== typeof HealthColors) { | |
ApplyDamage.registerObserver("change", HealthColors.Update); | |
} | |
}); |
This comment has been minimized.
This comment has been minimized.
Use the |
This comment has been minimized.
This comment has been minimized.
I was having trouble getting the "-- bar" to work in macros so I just changed line 18 to default 3. Would the proper syntax be "!apply-damage --bar3"? hmm also it is being put in a button... so brackets of somekind are needed? |
This comment has been minimized.
This comment has been minimized.
I have the GroupCheck API installed and your ApplyDamage as well. When I do a group check and apply the damage afterwards, it works. But then when I try to change an individual token's hp it affects all of them. So, the API works correctly, but afterwards any changes made to an individual token will apply to all. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
Is there any way I can make this apply damage to a specific bar?