diff --git a/HuntersMark/0.4.0/huntersmark.js b/HuntersMark/0.4.0/huntersmark.js
new file mode 100644
index 0000000000..9711d8f98e
--- /dev/null
+++ b/HuntersMark/0.4.0/huntersmark.js
@@ -0,0 +1,253 @@
+/*
+ !hunters-mark
+ !hunters-mark add
+ !hunters-mark delete
+ !hunters-mark help
+ !hunters-mark show
+ !hunters-mark menu
+ !hunters-mark @{selected|character_id} @{target|token_id}
+
+ add adds selected character as a new hunter.
+ must have exactly one marker
+ delete removes currently selected character from hunters list
+ help shows help menu, and description of each feature
+ show shows current hunters in state
+ menu shows the menu of buttons
+
+ if none of above
+ assumes arg[1] is a hunter character_id, and arg[2] is target token id.
+ if not, will send a warning and end script.
+
+*/
+const HUNTERSMARK = (() => { // eslint-disable-line no-unused-vars
+
+ const script_name = 'HUNTERSMARK';
+ const version = '0.3.0';
+ const lastUpdate = 1593500895369;
+
+ const tokenName = token => token.get('name') ? token.get('name') : (token.get('_id') ? token.get('_id') : 'Unknown');
+ const findHunter = (hunter, hunted = 'hunter') => state.HUNTERSMARK.hunters.findIndex(item => item[hunted] === hunter);
+ const getWho = who => who.split(' (GM)')[0];
+ const mark = '@{selected|character_id} @{target|token_id}';
+ const CSS = {
+ container: 'border: 1pt solid green; background-color: white; font-size: 0.9em; border-radius: 10px;',
+ table: '
',
+ trow: '| ',
+ tmiddle: ' | ' ,
+ trowend: ' |
',
+ tend: '
',
+ button: 'border:0; margin-left: 3px; margin-right: 3px; padding-left: 5px; padding-right: 5px; border-radius: 7px; background:green;color:white;font-weight:bold;',
+ center: 'text-align: center;',
+ leftpad: 'padding-left: 10px;',
+ heading: 'text-align: center; text-decoration: underline; font-size: 16px; line-height: 24px;'
+ };
+
+ const checkState = () => {
+ if(!state.hasOwnProperty('HUNTERSMARK')) {
+ state.HUNTERSMARK = {
+ schema: 0.0,
+ hunters: []
+ };
+ }
+ /* hunter: {
+ hunter: id of character,
+ mark: tag of status marker to assign,
+ marked: id of last character marked, or ''
+ }
+ */
+ };
+
+ const checkInstall = () => {
+ log(`-=> ${script_name.toUpperCase()} v${version} <=- [${new Date(lastUpdate)}]`);
+ // include state checking here
+ checkState();
+
+ };
+
+ const handleInput = (msg) => {
+ if (msg.type !== 'api' || !/!hunters-mark\b/.test(msg.content.toLowerCase())) {
+ return;
+ }
+
+ const args = msg.content.split(/\s/);
+ const command = args[1] || '';
+
+ if(!command || command.toLowerCase() === 'help') {
+ showHelp(getWho(msg.who));
+ } else if(command.toLowerCase() === 'add') {
+ hunter(msg, 1);
+ } else if(command.toLowerCase() === 'delete') {
+ hunter(msg, -1);
+ } else if(command.toLowerCase() === 'show') {
+ showState(getWho(msg.who));
+ } else if(command.toLowerCase() === 'menu') {
+ showMenu(getWho(msg.who));
+ /*} else if(command.toLowerCase() === 'mark') {
+ sendChat('player|' + getWho(msg.who),`!hunters-mark ${mark}`);*/
+ } else {
+ if(msg.selected > 1) {
+ sendChat(script_name,`/w "${getWho(msg.who)}" You must have only one token selected.`);
+ return;
+ }
+ tokenMarker(args[1], args[2], getWho(msg.who));
+ }
+ };
+
+ const showHelp = who => {
+ const help = {
+ show: 'This shows the current list of hunters, and their marks.',
+ add: 'To add a new hunter, select a token representing the character and apply the status marker you want to use as their mark. Then click Add.',
+ 'delete': 'To remove a character from the list of hunters, select a token representing them and click Delete.',
+ help: 'Show this description.',
+ menu: "Show a set of buttons to activate the script's features.",
+ 'mark a target': `To mark a target, use !hunters-mark [character id of hunter] [token id of target].
A good way to do this is !hunters-mark ${mark}
`
+ };
+ let output = `Hunter's Mark Instructions
Use !hunters-mark followed by one of the commands below.${CSS.table}`;
+ Object.entries(help).forEach(([key, value]) => {
+ output += `${CSS.trow}${key}${CSS.tmiddle}${value}${CSS.trowend}`;
+ });
+ output += CSS.tend + ' ';
+ sendChat(script_name, `/w "${who}" ${output}`);
+ showMenu(who);
+ };
+
+ const showMenu = (who) => {
+ const buttons = {
+ Show: 'show',
+ Add: 'add',
+ 'Delete': 'delete',
+ Help: 'help'
+
+ };
+ const output = `Hunters Mark Menu
` +
+ `
${makeButton('Mark / Unmark Target', mark, 'width: 192px; font-size: 1.1em; text-align:center;')}
`
+ + `
${Object.entries(buttons).reduce((list, [key, value]) => list + makeButton(key, value), '')}
`;
+ sendChat(script_name, `/w "${who}" ${output}`);
+ };
+
+ const makeButton = (label, button, width='') => {
+ return `${label}`;
+ };
+
+ const showState = (who) => {
+ const tokenMarkers = JSON.parse(Campaign().get('token_markers'));
+ const getIcon = tag => tokenMarkers.find(item => tag === item.tag).url;
+ const hunters = state.HUNTERSMARK.hunters.map(hunter => `}) | **${getObj('character', hunter.hunter).get('name')}**${hunter.marked ? ` Marked: ${getObj('graphic',hunter.marked).get('name')}` : ''} |
`);
+ sendChat(script_name, `/w "${who}" `);
+ };
+
+ const hunter = (msg, addordelete) => {
+ if (!msg.selected) {
+ sendChat(script_name,`/w "${getWho(msg.who)}" You need to select at least one character's token, and each must have a single status marker assigned.`);
+ return;
+ }
+ let showstate = false;
+ let excluded = [];
+ (msg.selected||[]).forEach((obj) => {
+ let token = getObj('graphic', obj._id);
+ if (token) {
+ let character = getObj('character', token.get('represents'));
+ if (character) {
+ if(addordelete === -1) {
+ // delete selected characters from state
+ const found = findHunter(character.get('_id'));
+ if(found === -1) {
+ excluded.push(tokenName(token));
+ } else {
+ state.HUNTERSMARK.hunters.splice(found, 1);
+ }
+ } else if (addordelete === 1) {
+ // only need to check marker if adding.
+ const marker = token.get('statusmarkers').split(',');
+ if(marker.length === 0 || marker.length > 1 || marker[0] === '') {
+ excluded.push(tokenName(token));
+ } else {
+ const newHunter = {
+ hunter: character.get('_id'),
+ marked: '',
+ mark: marker[0]
+ };
+ const found = findHunter(newHunter.hunter);
+ if(found === -1) {
+ state.HUNTERSMARK.hunters.push(newHunter);
+ } else {
+ state.HUNTERSMARK.hunters.splice(found, 1, newHunter);
+ }
+ }
+ }
+ showstate = true;
+ // report characters in state.
+ } else {
+ excluded.push(tokenName(token));
+ }
+ }
+
+ });
+
+ if(showstate) {
+ showState(getWho(msg.who));
+ }
+ if(excluded.length > 0) {
+ sendChat(script_name, `/w "${getWho(msg.who)}" The following tokens were either missing elements or had too many markers, and were not updated: ${excluded.join(', ')}.`);
+ }
+ };
+
+ const tokenMarker = (hunter_id, target_id, who) => {
+ const hunter_index = findHunter(hunter_id);
+ if(hunter_index === -1) {
+ sendChat(script_name, `/w "${who}" Hunter is not found. Check they are set up properly.`);
+ return;
+ }
+ const token = getObj('graphic', target_id);
+ if(!token) {
+ sendChat(script_name, `/w "${who}" Target token is not a valid target.`);
+ return;
+ }
+ /* here starts the actual work of the script */
+ if(target_id == state.HUNTERSMARK.hunters[hunter_index].marked) {
+ // the target token matches the id stored in owner.
+ // This character is already marked, so unmark him and clear mark_id
+ state.HUNTERSMARK.hunters[hunter_index].marked = '';
+ changeMarker(target_id, state.HUNTERSMARK.hunters[hunter_index].mark, 'remove');
+ } else {
+ // marking a new target so:
+ // get old mark, and remove mark from previous character
+ // update mark_id and add marker
+ const oldmark = state.HUNTERSMARK.hunters[hunter_index].marked;
+ if(oldmark !== '') {
+ // find old character, remove mark from them, then:
+ changeMarker(oldmark, state.HUNTERSMARK.hunters[hunter_index].mark, 'remove');
+ }
+ state.HUNTERSMARK.hunters[hunter_index].marked = target_id;
+ changeMarker(target_id, state.HUNTERSMARK.hunters[hunter_index].mark, 'add');
+
+ }
+ };
+
+ const changeMarker = (tid, marker, addorremove = 'add') => {
+ const token = getObj('graphic', tid);
+ if(token) {
+ let tokenMarkers = token.get('statusmarkers').split(',');
+ if(addorremove === 'add') {
+ if(!tokenMarkers.includes(marker)) {
+ tokenMarkers.push(marker);
+ }
+ } else if(addorremove === 'remove') {
+ tokenMarkers = tokenMarkers.filter(item => item !== marker);
+ } else {
+ return;
+ }
+ token.set('statusmarkers', tokenMarkers.join(','));
+ }
+ };
+
+ const registerEventHandlers = () => {
+ on('chat:message', handleInput);
+ };
+
+ on('ready', () => {
+ checkInstall();
+ registerEventHandlers();
+ });
+
+})();
diff --git a/HuntersMark/README.md b/HuntersMark/README.md
index a2dc36f468..da608d8d0f 100644
--- a/HuntersMark/README.md
+++ b/HuntersMark/README.md
@@ -1,22 +1,28 @@
Hunter's Mark
=============
-A script that lets each character have their own custom Status Marker, which they can use to mark other tokens. You can make only one target at a time. When you mark a new target, the old marker is removed. This is perfect for abilities like D&D's Hunter's Mark.
+A script that lets each character have their own custom Status Marker, which they can use to mark other tokens. There are two settings. If you are a hunter-like character, you can mark only one target at a time. When you mark a new target, the old marker is removed frm all tokens but yourself and the target. This is perfect for abilities like D&D's Hunter's Mark.
+The second setting lets you mark any number of characters.
-Run it with !hunters-mark followed by one of the commands below.
+Run this script with `!hunters-mark ` followed by one of the commands below.
Available Commands
==================
-* `help`: Shows a help file like this one.
-* `add`: Select a character, and make sure they have one status marker applied. Then click Add, and that character will be added to the list of hunters, and the marker will be the one they use to mark targets.
-* `delete`: Delete a character from the list of hunters.
-* `show`: Show a list of hunters, their markers, and their current marked target, if any.
+* `help`: Shows a detailed help file, and the menu buttons afterwards.
+* `add`: Select a character who has exactly one token marker assigned. Then click Add or Hunter, and that character will be added to the list of hunter-like characters, and the marker will be the one they use to mark targets.
+* `bard`: exactly as above. Select a character with one status mark assigned. But they rae added to rhe list of bard-like characters, and can assign marks to multiple targets simultaneously. Maybe all characters will be added here, depending on how you use marks.
+* `delete`: Delete a character from all displayed lists.
+* `show`: Show a list of characters with their markers, and the menu buttons afterwards.
* `menu`: prints a set of buttons, to activate the scripts commands.
Marking or Unmarking a Target
=============================
-* `!hunters-mark @{selected|character_id} @{target|token_id}`: To mark or unmark a target, you need to supply your character id, and the token id of a target. The same command is used to mark or unmark a target.
+* `!hunters-mark @{selected|token_id} @{target|token_id}`: To mark or unmark a target, you need to supply your own token id, and the token id of a target. The same command is used to mark or unmark a target.
+Important: this has changed with version 0.4 to support bard-like characters. Previous versions used to use `@{selected|character_id}` - but you MUST now use `@{selected|token_id}`. Update any macros (this script's buttons are automatically updated).
+Hunter and Bard
+===============
+The two types of behaviour are classified as Hunter and Bard, because most people will be familiar with D&D. If you can think of alternate terms for these, send then to Gigs on the roll20 forums.
diff --git a/HuntersMark/huntersmark.js b/HuntersMark/huntersmark.js
index 9711d8f98e..c37a164d43 100644
--- a/HuntersMark/huntersmark.js
+++ b/HuntersMark/huntersmark.js
@@ -1,34 +1,51 @@
/*
!hunters-mark
!hunters-mark add
+ !hunters-mark bard
!hunters-mark delete
!hunters-mark help
!hunters-mark show
!hunters-mark menu
- !hunters-mark @{selected|character_id} @{target|token_id}
+ !hunters-mark @{selected|token_id} @{target|token_id}
+ this used to be !hunters-mark @{selected|character_id} @{target|token_id}
add adds selected character as a new hunter.
must have exactly one marker
- delete removes currently selected character from hunters list
+ bard as above, but adds a bard-like character
+ delete removes the currently selected character from all lists
help shows help menu, and description of each feature
show shows current hunters in state
menu shows the menu of buttons
if none of above
- assumes arg[1] is a hunter character_id, and arg[2] is target token id.
- if not, will send a warning and end script.
+ assumes arg[1] is a the acting character's token_id, and arg[2] is the target's token id.
+ (note: this is a change - earlier versions of the script used character_id for args[1])
+ if not, will send a warning and end the script.
*/
+var API_Meta = API_Meta || {};
+API_Meta.Reporter = {
+ offset: Number.MAX_SAFE_INTEGER,
+ lineCount: -1
+}; {
+ try {
+ throw new Error('');
+ } catch (e) {
+ API_Meta.Reporter.offset = (parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/, '$1'), 10) - (4));
+ }
+}
+
const HUNTERSMARK = (() => { // eslint-disable-line no-unused-vars
const script_name = 'HUNTERSMARK';
- const version = '0.3.0';
+ const version = '0.4.0';
const lastUpdate = 1593500895369;
const tokenName = token => token.get('name') ? token.get('name') : (token.get('_id') ? token.get('_id') : 'Unknown');
const findHunter = (hunter, hunted = 'hunter') => state.HUNTERSMARK.hunters.findIndex(item => item[hunted] === hunter);
+ const findBard = (hunter, hunted = 'hunter') => state.HUNTERSMARK.bards.findIndex(item => item[hunted] === hunter);
const getWho = who => who.split(' (GM)')[0];
- const mark = '@{selected|character_id} @{target|token_id}';
+ const mark = '@{selected|token_id} @{target|token_id}';
const CSS = {
container: 'border: 1pt solid green; background-color: white; font-size: 0.9em; border-radius: 10px;',
table: '',
@@ -46,8 +63,14 @@ const HUNTERSMARK = (() => { // eslint-disable-line no-unused-vars
if(!state.hasOwnProperty('HUNTERSMARK')) {
state.HUNTERSMARK = {
schema: 0.0,
- hunters: []
+ hunters: [],
+
};
+ } else {
+ if(!state.HUNTERSMARK.bards) {
+ state.HUNTERSMARK.bards = [];
+ state.HUNTERSMARK.schema = 0.1;
+ }
}
/* hunter: {
hunter: id of character,
@@ -74,8 +97,10 @@ const HUNTERSMARK = (() => { // eslint-disable-line no-unused-vars
if(!command || command.toLowerCase() === 'help') {
showHelp(getWho(msg.who));
- } else if(command.toLowerCase() === 'add') {
+ } else if(command.toLowerCase() === 'add' || command.toLowerCase() === 'hunter') {
hunter(msg, 1);
+ } else if(command.toLowerCase() === 'bard') {
+ hunter(msg, 2);
} else if(command.toLowerCase() === 'delete') {
hunter(msg, -1);
} else if(command.toLowerCase() === 'show') {
@@ -89,18 +114,31 @@ const HUNTERSMARK = (() => { // eslint-disable-line no-unused-vars
sendChat(script_name,`/w "${getWho(msg.who)}" You must have only one token selected.`);
return;
}
- tokenMarker(args[1], args[2], getWho(msg.who));
+ const target_id = args[2];
+ const token_id = args[1];
+ let character_id;
+ try {
+ const token = getObj('graphic', token_id);
+ const rep = token.get('represents');
+ const character = getObj('character', rep);
+ character_id = character.id;
+ } catch(e) {
+ sendChat(script_name,`/w "${getWho(msg.who)}" Check the character's token - is the REPRESENTS field assigned?`);
+ return;
+ }
+ tokenMarker(character_id, token_id, target_id, getWho(msg.who));
}
};
const showHelp = who => {
const help = {
- show: 'This shows the current list of hunters, and their marks.',
- add: 'To add a new hunter, select a token representing the character and apply the status marker you want to use as their mark. Then click Add.',
- 'delete': 'To remove a character from the list of hunters, select a token representing them and click Delete.',
+ show: 'This shows the current list of activated tokens, and their marks.',
+ hunter: 'To define a new hunter-like character, select a token representing the character and apply the status marker you want to use as their mark. Then click Hunter.',
+ bard: 'To define a new bard-like character, select a token representing the character and apply the status marker you want to use as their mark. Then click Bard.',
+ 'delete': 'To remove a character from their current list, select a token representing them and click Delete.',
help: 'Show this description.',
- menu: "Show a set of buttons to activate the script's features.",
- 'mark a target': `To mark a target, use !hunters-mark [character id of hunter] [token id of target].
A good way to do this is !hunters-mark ${mark}
`
+ menu: "Displays a button to activate each of the script's features. For convenience, this menu is always shown after Help and Show.",
+ 'mark a target': `To mark a target, use !hunters-mark [token id of hunter] [token id of target].
For example: !hunters-mark ${mark}
`
};
let output = `Hunter's Mark Instructions
Use !hunters-mark followed by one of the commands below.${CSS.table}`;
Object.entries(help).forEach(([key, value]) => {
@@ -114,7 +152,8 @@ const HUNTERSMARK = (() => { // eslint-disable-line no-unused-vars
const showMenu = (who) => {
const buttons = {
Show: 'show',
- Add: 'add',
+ Hunter: 'add',
+ Bard: 'bard',
'Delete': 'delete',
Help: 'help'
@@ -132,8 +171,12 @@ const HUNTERSMARK = (() => { // eslint-disable-line no-unused-vars
const showState = (who) => {
const tokenMarkers = JSON.parse(Campaign().get('token_markers'));
const getIcon = tag => tokenMarkers.find(item => tag === item.tag).url;
- const hunters = state.HUNTERSMARK.hunters.map(hunter => `}) | **${getObj('character', hunter.hunter).get('name')}**${hunter.marked ? ` Marked: ${getObj('graphic',hunter.marked).get('name')}` : ''} |
`);
- sendChat(script_name, `/w "${who}" `);
+ //const hunters = state.HUNTERSMARK.hunters.map(hunter => `}) | **${getObj('character', hunter.hunter).get('name')}**${hunter.marked ? ` Marked: ${getObj('graphic',hunter.marked).get('name')}` : ''} |
`);
+
+ const hunters = state.HUNTERSMARK.hunters.map(hunter => `}) | **${getObj('character', hunter.hunter).get('name')}** |
`);
+ const bards = state.HUNTERSMARK.bards.map(hunter => `}) | **${getObj('character', hunter.hunter).get('name')}** |
`);
+ sendChat(script_name, `/w "${who}" Hunter-like Characters
Only one target can be marked.
Bard-like Characters
Multiple targets can be marked.
`);
+ showMenu(who);
};
const hunter = (msg, addordelete) => {
@@ -148,16 +191,26 @@ const HUNTERSMARK = (() => { // eslint-disable-line no-unused-vars
if (token) {
let character = getObj('character', token.get('represents'));
if (character) {
+ const found_hunter = findHunter(character.get('_id'));
+ const found_bard = findBard(character.get('_id'));
if(addordelete === -1) {
// delete selected characters from state
- const found = findHunter(character.get('_id'));
- if(found === -1) {
+ if(found_hunter === -1) {
excluded.push(tokenName(token));
} else {
- state.HUNTERSMARK.hunters.splice(found, 1);
+ state.HUNTERSMARK.hunters.splice(found_hunter, 1);
}
- } else if (addordelete === 1) {
+
+ if(found_bard === -1) {
+ excluded.push(tokenName(token));
+ } else {
+ state.HUNTERSMARK.bards.splice(found_bard, 1);
+ }
+ } else if (addordelete >= 1) {
// only need to check marker if adding.
+
+ const colour_markers = ["red", "blue", "green", "brown", "purple", "pink", "yellow", "dead"];
+
const marker = token.get('statusmarkers').split(',');
if(marker.length === 0 || marker.length > 1 || marker[0] === '') {
excluded.push(tokenName(token));
@@ -167,14 +220,23 @@ const HUNTERSMARK = (() => { // eslint-disable-line no-unused-vars
marked: '',
mark: marker[0]
};
- const found = findHunter(newHunter.hunter);
- if(found === -1) {
+ //problem with coloured status markers - they cause sandbox to crash
+ if (colour_markers.includes(newHunter.mark)) {
+ sendChat(script_name,`You cannot use the pure color or dead markers (the top row).`);
+ return;
+ }
+
+ // need to delete the token if it already exists, then add it again.
+ if(found_hunter > -1) state.HUNTERSMARK.hunters.splice(found_hunter, 1)
+ if(found_bard > -1) state.HUNTERSMARK.bards.splice(found_bard, 1);
+ if(addordelete == 2) {
+ state.HUNTERSMARK.bards.push(newHunter);
+ } else if (addordelete == 1) {
state.HUNTERSMARK.hunters.push(newHunter);
- } else {
- state.HUNTERSMARK.hunters.splice(found, 1, newHunter);
}
}
- }
+ }
+
showstate = true;
// report characters in state.
} else {
@@ -192,52 +254,39 @@ const HUNTERSMARK = (() => { // eslint-disable-line no-unused-vars
}
};
- const tokenMarker = (hunter_id, target_id, who) => {
- const hunter_index = findHunter(hunter_id);
- if(hunter_index === -1) {
- sendChat(script_name, `/w "${who}" Hunter is not found. Check they are set up properly.`);
+ const tokenMarker = (character_id, token_id, target_id, who) => {
+ const hunter_index = findHunter(character_id);
+ const bard_index = findBard(character_id);
+ if(hunter_index === -1 && bard_index === -1) {
+ sendChat(script_name, `/w "${who}" Marker is not found. Check they are set up properly.`);
return;
}
- const token = getObj('graphic', target_id);
- if(!token) {
+ const target_token = getObj('graphic', target_id);
+ if(!target_token) {
sendChat(script_name, `/w "${who}" Target token is not a valid target.`);
return;
}
- /* here starts the actual work of the script */
- if(target_id == state.HUNTERSMARK.hunters[hunter_index].marked) {
- // the target token matches the id stored in owner.
- // This character is already marked, so unmark him and clear mark_id
- state.HUNTERSMARK.hunters[hunter_index].marked = '';
- changeMarker(target_id, state.HUNTERSMARK.hunters[hunter_index].mark, 'remove');
- } else {
- // marking a new target so:
- // get old mark, and remove mark from previous character
- // update mark_id and add marker
- const oldmark = state.HUNTERSMARK.hunters[hunter_index].marked;
- if(oldmark !== '') {
- // find old character, remove mark from them, then:
- changeMarker(oldmark, state.HUNTERSMARK.hunters[hunter_index].mark, 'remove');
- }
- state.HUNTERSMARK.hunters[hunter_index].marked = target_id;
- changeMarker(target_id, state.HUNTERSMARK.hunters[hunter_index].mark, 'add');
-
+
+ const mark = (hunter_index > -1) ? state.HUNTERSMARK.hunters[hunter_index].mark : state.HUNTERSMARK.bards[bard_index].mark;
+ // ERROR: want to handle if undefined
+ if(hunter_index > -1) {
+ removeMarkers(mark, target_id, token_id);
}
+ updateMarker(target_id, mark);
};
- const changeMarker = (tid, marker, addorremove = 'add') => {
+ const updateMarker = (tid, marker) => {
const token = getObj('graphic', tid);
if(token) {
let tokenMarkers = token.get('statusmarkers').split(',');
- if(addorremove === 'add') {
- if(!tokenMarkers.includes(marker)) {
- tokenMarkers.push(marker);
- }
- } else if(addorremove === 'remove') {
+ //sendChat('', `marker: ${marker}; markers: ${tokenMarkers}`)
+ if(!tokenMarkers.includes(marker)) {
+ tokenMarkers.push(marker);
+ } else {
tokenMarkers = tokenMarkers.filter(item => item !== marker);
- } else {
- return;
- }
+ }
token.set('statusmarkers', tokenMarkers.join(','));
+
}
};
@@ -250,4 +299,40 @@ const HUNTERSMARK = (() => { // eslint-disable-line no-unused-vars
registerEventHandlers();
});
+ const removeMarkers = (marker, ...token_ids) => {
+ // tokens is a rest array - it will be an array of tokens to ignore with this function
+ let tokens = findObjs({_subtype: "token"});
+ // want to loop thtrough every token t
+ tokens.forEach(token => {
+ const tid = token.id;
+ if(!token_ids.includes(tid)) {
+ let tokenMarkers = token.get('statusmarkers').split(',');
+ if(tokenMarkers.includes(marker)) {
+ tokenMarkers = tokenMarkers.filter(item => item !== marker);
+ token.set('statusmarkers', tokenMarkers.join(','));
+ }
+ }
+ });
+ }
})();
+/* CHANGES
+ make sure to use token_id at the start in place of character_id
+ Removes a crash when selecting any of the first row markers (coloutred and dead).
+ Adds bard-like characters that can assign marks to multiple characters.
+ Can change the assigned marker just by adding them again (before, you had to delete then re-add)
+ Can swap characters between lists just by adding them to relevant list
+ Can't add the same character multiple times to the same list.
+ The way last-marked character is recorded has changed, so it isn't displayted in the Show list any more.
+
+
+ Might want clear marks:
+ clear all tokens of all marks. (Clear All)
+ clear a single token of all marks (use target). (Clear Token)
+ Remove a specific mark from all tokens. (clear Mark) select a token with one or mor marks, and remove them from all tokens.
+ if a character can mark, add that on to their token (Show Mark). Marke select multiple tokens - could be useful before Clear Mark
+ these would be different functions. Culd add another row of buttons.
+
+ What if a character has a token-marker that doesn't exist? For example, it was created with a custom set in one game, and that was changed.
+
+ Show function: when displaying chsraacters, maybe don't show a list if it has no characters. If no characters in both, have a boilerplate message.
+*/
\ No newline at end of file
diff --git a/HuntersMark/script.json b/HuntersMark/script.json
index 7562ac3d2f..6c4fc75dcf 100644
--- a/HuntersMark/script.json
+++ b/HuntersMark/script.json
@@ -1,8 +1,8 @@
{
"name": "Hunter's Mark",
"script": "huntersmark.js",
- "version": "0.3.0",
- "previousversions": [],
+ "version": "0.4.0",
+ "previousversions": ["0.3.0"],
"description": "A script that lets each character have their own custom Status Marker, which they can use to mark other tokens. You can make only one target at a time. When you mark a new target, the old marker is removed. This is perfect for abilities like D&D's Hunter's Mark.\r\rFor instructions run `!hunters-mark --help`.",
"authors": "GiGs",
"roll20userid": "157788"