Skip to content

Instantly share code, notes, and snippets.

@VoltCruelerz
Forked from oukag/5eOGLInventoryTracker.js
Created March 31, 2018 22:34
Show Gist options
  • Save VoltCruelerz/0e4b939c01576a2c76cc398253a397d3 to your computer and use it in GitHub Desktop.
Save VoltCruelerz/0e4b939c01576a2c76cc398253a397d3 to your computer and use it in GitHub Desktop.
5e OGL equipped inventory tracking
/**
* Inventory Tracker for 5e OGL character sheet
*
* Allows for quick access to the equipped items of a character.
*
* Commands:
* !equipShow [--item|<ITEM_NAME> [--charid|<CHARACTER_ID>]]
* Shows the equipped item(s) for the character that belongs to the selected token.
* If no arguments are given, displays all equipped items of the character representing the selected token.
*
* If --item|<ITEM_NAME> is given, will display the equipped status for the given item.
* If --charid|<CHARACTER_ID> is given, will attempt to find the item on the character with the given ID.
*
* The name of the item(s) in the chat allow a player who can control that character to toggle the equipment
* status for that particular item utilizing the !equipToggle command.
*
* !equipToggle --charid|<CHARACTER_ID> --item|<ITEM_NAME>
* Toggles the equipped status for the given item and outputs the new status. Clicking on the item name in the
* output will toggle the equipment status again. Only players who can control the character can use this command.
*
* !equipPass --item|<ITEM_NAME> --recipientName|<TARGET_CHARACTER_NAME> [--quantity|<QUANTITY>]
* !equipPass --i|<ITEM_NAME> --rn|<TARGET_CHARACTER_NAME> [-q|<QUANTITY>]
* De-equips and passes ownership of an item to the specified target character.
* If QUANTITY is not specified, it assumes 1.
*/
var InventoryTracker5eOGL = InventoryTracker5eOGL ||(function() {
'use strict';
var scriptName = '5e OGL Inventory Tracker',
version = '0.0.4',
ITEM = {
// ==============================================================================
// ITEM_PREFIX + ROW_ID + ATTR_SUFFIX============================================
// Prefix
PREFIX : 'repeating_inventory_',
// Suffixes
COUNT_SUFFIX : '_itemcount',
COUNT_INDEX : 0,
NAME_SUFFIX : '_itemname',
NAME_INDEX : 1,
WEIGHT_SUFFIX : '_itemweight',
WEIGHT_INDEX : 2,
EQUIPPED_SUFFIX : '_equipped',
EQUIPPED_INDEX : 3, // Actually determines whether the item is equipped in regards to other attributes (AC, modifiers, etc.)
USEASARESOURCE_SUFFIX : '_useasaresource',
USEASARESOURCE_INDEX : 4,
HASATTACK_SUFFIX : '_hasattack',
HASATTACK_INDEX : 5,
PROPERTIES_SUFFIX : '_itemproperties',
PROPERTIES_INDEX : 6,
MODIFIERS_SUFFIX : '_itemmodifiers',
MODIFIERS_INDEX : 7,
CONTENT_SUFFIX : '_itemcontent',
CONTENTS_INDEX : 8,
ATTACKID_SUFFIX : '_itemattackid',
ATTACKID_INDEX : 9,
RESOURCEID_SUFFIX : '_itemresourceid',
RESOURCEID_INDEX : 10,
INVENTORYSUBFLAG_SUFFIX: '_inventorysubflag',
INVENTORYSUBFLAG_INDEX: 11,
// These have to be the string equivalent, otherwise the sheet worker will not pick up the change
CHECKED : '1',
UNCHECKED : '0',
// ==============================================================================
// Generatel Utility ============================================================
// Find the name from a given charId and rowId
findNameForCharacterAndRowId : function(charId, rowId) {
log(`findNameForCharacterAndRowId{${charId}, ${rowId})`);
var nameAttr = this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.NAME_SUFFIX);
return nameAttr ? nameAttr.get('current') : '';
},
// Find attribute object for a character at a row id with a given suffix. If none exists, create a new one and return it.
findForCharacterAndRowIdAndSuffix : function(charId, rowId, suffix) {
log(`findForCharacterAndRowIdAndSuffix{${charId}, ${rowId}, ${suffix})`);
var existing = findObjs({
_type: 'attribute',
characterid: charId,
name: this.PREFIX + rowId + suffix
})[0];
return existing ? existing : createObj('attribute', {
characterid: charId,
name: this.PREFIX + rowId + suffix,
current: ''
});
},
// Hunt for the _itemname entry and return its row.
getRowIdFromAttribute : function(attrName) {
log(`getRowIdFromAttribute{${attrName})`);
var regex = new RegExp(this.PREFIX + '(.+?)(?:' + this.NAME_SUFFIX + '|' + this.EQUIPPED_SUFFIX + ')');
return regex.exec(attrName) ? regex.exec(attrName)[1] : '';
},
// Return all attribute objects for an inventory rowId
getAllFromCharAndRowId : function(charId, rowId) {
return [
this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.COUNT_SUFFIX),
this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.NAME_SUFFIX),
this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.WEIGHT_SUFFIX),
this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.EQUIPPED_SUFFIX),
this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.USEASARESOURCE_SUFFIX),
this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.HASATTACK_SUFFIX),
this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.PROPERTIES_SUFFIX),
this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.MODIFIERS_SUFFIX),
this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.CONTENT_SUFFIX),
this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.ATTACKID_SUFFIX),
this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.RESOURCEID_SUFFIX),
this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.INVENTORYSUBFLAG_SUFFIX)
];
},
// ==============================================================================
// IsEquipped ===================================================================
isEquipped : function(equippedAttr) {
// if the current status is blank, it means that the equipped status of the item has not been updated
// since being added to the inventory.
log(`isEquipped{${equippedAttr})`);
return equippedAttr && (equippedAttr.get('current') === this.CHECKED || equippedAttr.get('current') === '');
},
toggleEquip : function(charId, rowId) {
log(`toggleEquip{${charId}, ${rowId})`);
var equipped = this.findEquippedForCharacterAndRowId(charId, rowId);
equipped.setWithWorker({current: this.isEquipped(equipped) ? this.UNCHECKED : this.CHECKED});
return this.getEquippedStatusForAttr(equipped);
},
getEquippedStatusForAttr : function(equipped) {
return this.isEquipped(equipped) ? 'equipped' : 'unequipped';
},
findEquippedForCharacterAndRowId : function(charId, rowId) {
log(`findEquippedForCharacterAndRowId{${charId}, ${rowId})`);
return this.findForCharacterAndRowIdAndSuffix(charId, rowId, this.EQUIPPED_SUFFIX);
},
getEquippedStatusForCharacterAndRow : function(charId, rowId) {
log(`getEquippedStatusForCharacterAndRow{${charId}, ${rowId})`);
return this.getEquippedStatusForAttr(this.findEquippedForCharacterAndRowId(charId, rowId));
},
// ==============================================================================
// Clean for Deletion ===========================================================
cleanForDeletion : function(equipAttr, attackAttr, resourceAttr, countAttr) {
equipAttr.setWithWorker({current: this.UNCHECKED});
attackAttr.setWithWorker({current: this.UNCHECKED});
resourceAttr.setWithWorker({current: this.UNCHECKED});
countAttr.setWithWorker({current: '0'});
},
copyAttrToNewPlayer : function(existingAttr, recipientCharId, newRowId, suffix, overrideMod = null){
let newAttrName = this.PREFIX + newRowId + suffix;
let current = existingAttr ? existingAttr.get('current') : '';
if(overrideMod != null){
current = overrideMod + '';
}
createObj('attribute', {
characterid: recipientCharId,
name: newAttrName,
current: current,
max: existingAttr ? existingAttr.get('max') : ''
});
},
// Returns count actually transferred
transferItemToRecipient : function(rowId, senderCharId, recipientCharId, itemName, quantity, clone) {
log(`transferItemToRecipient(rowId: ${rowId}, senderCharId: ${senderCharId}, recipientCharId: ${recipientCharId}, itemName: ${itemName})`);
var allItemAttributes = this.getAllFromCharAndRowId(senderCharId, rowId);
let newRowId = this.generateRowID();
// Even if the user was not deliberately trying to clone the item, if they are selecting a quantity that
// leaves some left over, mark clone = true.
let existingCount = allItemAttributes[this.COUNT_INDEX] ? allItemAttributes[this.COUNT_INDEX].get('current') : '0';
existingCount = existingCount || 1;
log("Existing Count: " + existingCount);
let newCount = parseInt(existingCount) - parseInt(quantity);
// If the newCount is negative, the user attempted to send more than they had. Set quantity to the existingCount.
if(newCount < 0){
newCount = newCount < 0 ? 0 : newCount;
quantity = existingCount;
}
log("New Count on Sender: " + newCount);
clone = newCount > 0 ? true : clone;
if(clone) {
allItemAttributes[this.COUNT_INDEX].setWithWorker({current: newCount + ''});
}
else {
this.cleanForDeletion(allItemAttributes[this.EQUIPPED_INDEX],
allItemAttributes[this.HASATTACK_INDEX],
allItemAttributes[this.USEASARESOURCE_INDEX],
allItemAttributes[this.COUNT_INDEX]);
}
// Check to see if the recipient already has an item by that name. If so, just stack it.
let existingRecipientItem = findRowIdForCharacterAndItemName(recipientCharId, itemName);
if(existingRecipientItem != null) {
log("Recipient has item. Stack items.");
var recipientRowId = findRowIdForCharacterAndItemName(recipientCharId, itemName);
var recipientCountAttr = this.findForCharacterAndRowIdAndSuffix(recipientCharId, recipientRowId, this.COUNT_SUFFIX);
let existingRecipientCount = recipientCountAttr ? recipientCountAttr.get('current') : '0';
let newRecipientCount = parseInt(existingRecipientCount) + parseInt(quantity);
recipientCountAttr.setWithWorker({current: newRecipientCount + ''});
}
else {
// Create a new item in the recipient's inventory
log("Recipient does not have existing item. Create new stack.");
this.copyAttrToNewPlayer(allItemAttributes[this.COUNT_INDEX], recipientCharId, newRowId, this.COUNT_SUFFIX, quantity);
this.copyAttrToNewPlayer(allItemAttributes[this.NAME_INDEX], recipientCharId, newRowId, this.NAME_SUFFIX);
this.copyAttrToNewPlayer(allItemAttributes[this.WEIGHT_INDEX], recipientCharId, newRowId, this.WEIGHT_SUFFIX);
this.copyAttrToNewPlayer(allItemAttributes[this.EQUIPPED_INDEX], recipientCharId, newRowId, this.EQUIPPED_SUFFIX);
this.copyAttrToNewPlayer(allItemAttributes[this.USEASARESOURCE_INDEX], recipientCharId, newRowId, this.USEASARESOURCE_SUFFIX);
this.copyAttrToNewPlayer(allItemAttributes[this.HASATTACK_INDEX], recipientCharId, newRowId, this.HASATTACK_SUFFIX);
this.copyAttrToNewPlayer(allItemAttributes[this.PROPERTIES_INDEX], recipientCharId, newRowId, this.PROPERTIES_SUFFIX);
this.copyAttrToNewPlayer(allItemAttributes[this.MODIFIERS_INDEX], recipientCharId, newRowId, this.MODIFIERS_SUFFIX);
this.copyAttrToNewPlayer(allItemAttributes[this.CONTENTS_INDEX], recipientCharId, newRowId, this.CONTENT_SUFFIX);
this.copyAttrToNewPlayer(allItemAttributes[this.ATTACKID_INDEX], recipientCharId, newRowId, this.ATTACKID_SUFFIX);
this.copyAttrToNewPlayer(allItemAttributes[this.RESOURCEID_INDEX], recipientCharId, newRowId, this.RESOURCEID_SUFFIX);
this.copyAttrToNewPlayer(allItemAttributes[this.INVENTORYSUBFLAG_INDEX], recipientCharId, newRowId, this.INVENTORYSUBFLAG_SUFFIX);
}
// If the sender has expended all stacks, remove all attributes
if(newCount == 0) {
allItemAttributes.forEach(function(element){element.remove();});
}
return parseInt(quantity);
},
// ==============================================================================
// These functions based on ChatSetAttr's row generation ========================
generateUUID : function() {
var a = 0;
var b = [];
return function () {
var c = (new Date()).getTime() + 0,
d = c === a;
a = c;
for (var e = new Array(8), f = 7; 0 <= f; f--) {
e[f] = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".charAt(c % 64);
c = Math.floor(c / 64);
}
c = e.join("");
if (d) {
for (f = 11; 0 <= f && 63 === b[f]; f--) {
b[f] = 0;
}
b[f]++;
}
else {
for (f = 0; 12 > f; f++) {
b[f] = Math.floor(64 * Math.random());
}
}
for (f = 0; 12 > f; f++) {
c += "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".charAt(b[f]);
}
return c;
};
},
generateRowID : function () {
return this.generateUUID()().replace(/_/g, "Z");
}
},
playerCanControlCharacter = function(charId, playerId) {
var character = getObj('character', charId);
var ctrl = character ? character.get('controlledby') : '';
return playerIsGM(playerId) || ctrl.indexOf('all') !== -1 || ctrl.indexOf(playerId) !== -1;
},
findCharacterIdForToken = function(tokenId) {
log(`findCharacterIdForToken{${tokenId})`);
var token = getObj('graphic', tokenId);
return token.get('represents');
},
filterItemAttrsForCharacterAndSuffixAndValue = function(charId, suffix, value){
log(`filterItemAttrsForCharacterAndSuffixAndValue{${charId}, ${suffix}, ${value})`);
return filterObjs(function(obj){
if(obj.get('type') === 'attribute'
&& obj.get('characterid') === charId
&& obj.get('name').indexOf(ITEM.PREFIX) !== -1 && obj.get('name').indexOf(suffix) !== -1
&& obj.get('current') === value
) {
log(JSON.stringify(obj));
return obj;
}
});
},
findEquippedItemsForCharacter = function(charId){
log(`findEquippedItemsForCharacter{${charId})`);
return filterItemAttrsForCharacterAndSuffixAndValue(charId, ITEM.EQUIPPED_SUFFIX, ITEM.CHECKED)
},
findUnequippedItemsForCharacter = function(charId){
log(`findUnequippedItemsForCharacter{${charId})`);
return filterItemAttrsForCharacterAndSuffixAndValue(charId, ITEM.EQUIPPED_SUFFIX, ITEM.UNEQUIPPED)
},
findRowIdForCharacterAndItemName = function(charId, itemName) {
log(`findRowIdForCharacterAndItemName{${charId}, ${itemName})`);
var nameAttr = filterItemAttrsForCharacterAndSuffixAndValue(charId, ITEM.NAME_SUFFIX, itemName)[0];
return nameAttr ? ITEM.getRowIdFromAttribute(nameAttr.get('name')) : null;
},
STYLES = {
DIV : 'style="width: 189px; border: 1px solid black; background-color: #ffffff; padding: 5px;"',
HEAD : 'style="color: rgb(126, 45, 64); font-size: 18px; text-align: left; font-variant: small-caps; font-family: Times, serif;"',
SUBHEAD : 'style="font-size: 11px; line-height: 13px; margin-top: -3px; font-style: italic;"',
ARROW : 'style="border: none; border-top: 3px solid transparent; border-bottom: 3px solid transparent; border-left: 195px solid rgb(126, 45, 64); margin-bottom: 2px; margin-top: 2px;"',
ASTYLE : 'style="font-size: 12px; color: black; border: 0; margin 0px; background: none; padding: 0;"'
},
outputEquipmentStatusForCharacter = function(charId, sender) {
log(`outputEquippedItemsForCharacter{${charId}, ${sender})`);
var character = getObj('character', charId);
if(!character){
var errorMessage = charId + ' is not a valid character id.';
log(errorMessage);
sendChat(scriptName, '/w ' + sender + ' ' + errorMessage);
return;
}
var tableRowsStr;
var content;
// Equipped Items
tableRowsStr = '';
var equippedItems = findEquippedItemsForCharacter(charId);
_.each(equippedItems, function(equipAttr){
var rowId = ITEM.getRowIdFromAttribute(equipAttr.get('name'));
var name = ITEM.findNameForCharacterAndRowId(equipAttr.get('characterid'), rowId);
log(`Row[${rowId}] | Name: ${name}`);
if(name) {
tableRowsStr = tableRowsStr +
'<tr><td>'+ getToggleHyperlink(charId, rowId, name) + '</td></tr>';
} else {
log('Could not find the name of item with character ID [' + charId + '] and row ID [' + rowId + ']');
}
});
if(tableRowsStr) {
content = '<table>' + tableRowsStr + '</table>';
} else {
content = '<div>None</div>';
}
sendChat(scriptName,
'/w ' + sender + ' ' +
'<div ' + STYLES.DIV + '>' +
'<div ' + STYLES.HEAD + '>' + character.get('name') + '</div>' +
'<div ' + STYLES.SUBHEAD + '>Equipped Items</div>' +
'<div ' + STYLES.ARROW + '></div>' +
content + '</div>'
);
// Unequipped Items
tableRowsStr = '';
var unequippedItems = findUnequippedItemsForCharacter(charId);
_.each(unequippedItems, function(equipAttr){
var rowId = ITEM.getRowIdFromAttribute(equipAttr.get('name'));
var name = ITEM.findNameForCharacterAndRowId(equipAttr.get('characterid'), rowId);
log(`Row[${rowId}] | Name: ${name}`);
if(name) {
tableRowsStr = tableRowsStr +
'<tr><td>'+ getToggleHyperlink(charId, rowId, name) + '</td></tr>';
} else {
log('Could not find the name of item with character ID [' + charId + '] and row ID [' + rowId + ']');
}
});
if(tableRowsStr) {
content = '<table>' + tableRowsStr + '</table>';
} else {
content = '<div>None</div>';
}
sendChat(scriptName,
'/w ' + sender + ' ' +
'<div ' + STYLES.DIV + '>' +
'<div ' + STYLES.HEAD + '>' + character.get('name') + '</div>' +
'<div ' + STYLES.SUBHEAD + '>Unequipped Items</div>' +
'<div ' + STYLES.ARROW + '></div>' +
content + '</div>'
);
},
outputSingleItemForCharacter = function(charId, itemName, sender) {
var rowId = findRowIdForCharacterAndItemName(charId, itemName);
if(!rowId) {
sendChat(scriptName, '/w ' + sender + ' No item with name \'' + itemName + '\' found for the character.');
return;
}
var equippedState = ITEM.getEquippedStatusForCharacterAndRow(charId, rowId);
sendChat(scriptName,
'/w ' + sender + ' ' +
'<div ' + STYLES.DIV + '>' +
'<div ' + STYLES.HEAD + '>' + getObj('character', charId).get('name') + '</div>' +
'<div ' + STYLES.ARROW + '></div>' +
'<div>' + getToggleHyperlink(charId, rowId, itemName) + ' -> ' + equippedState + '</div>' +
'</div>'
);
},
getToggleHyperlink = function(charId, rowId, itemName) {
return '<a ' + STYLES.ASTYLE + ' href="!equipToggle ' +
'--charid|' + charId + ' ' +
'--item|' + itemName +
'">' + itemName + '</a>';
},
toggleEquipment = function(charId, itemName, sender) {
var rowId = findRowIdForCharacterAndItemName(charId, itemName);
if(!rowId) {
sendChat(scriptName, '/w ' + sender + ' No item with name \'' + itemName + '\' found for the character.');
return;
}
var equippedState = ITEM.toggleEquip(charId, rowId);
sendChat(scriptName,
'/w ' + sender + ' ' +
'<div ' + STYLES.DIV + '>' +
'<div ' + STYLES.HEAD + '>' + getObj('character', charId).get('name') + '</div>' +
'<div ' + STYLES.ARROW + '></div>' +
'<div>Has ' + equippedState + ' ' + getToggleHyperlink(charId, rowId, itemName) + '.</div>' +
'</div>'
);
},
passEquipment = function(senderCharId, recipientName, recipientCharId, itemName, sender, quantity, clone) {
var rowId = findRowIdForCharacterAndItemName(senderCharId, itemName);
if(!rowId) {
sendChat(scriptName, '/w ' + sender + ' No item with name \'' + itemName + '\' found for the character.');
return;
}
let countTransferred = ITEM.transferItemToRecipient(rowId, senderCharId, recipientCharId, itemName, quantity, clone);
let plural = countTransferred > 1 ? 's' : '';
if(!recipientName){
return;
}
sendChat(scriptName,
'/w gm ' +
'<div ' + STYLES.DIV + '>' +
'<div ' + STYLES.HEAD + '>' + itemName + '</div>' +
'<div ' + STYLES.ARROW + '></div>' +
'<div>Transferred ' + countTransferred + 'x item' + plural + ' from ' + sender + ' to ' + recipientName + '.</div>' +
'</div>'
);
sendChat(scriptName,
'/w ' + sender + ' ' +
'<div ' + STYLES.DIV + '>' +
'<div ' + STYLES.HEAD + '>' + itemName + '</div>' +
'<div ' + STYLES.ARROW + '></div>' +
'<div>Transferred ' + countTransferred + 'x item' + plural + ' to ' + recipientName + '.</div>' +
'</div>'
);
sendChat(scriptName,
'/w ' + recipientName + ' ' +
'<div ' + STYLES.DIV + '>' +
'<div ' + STYLES.HEAD + '>' + itemName + '</div>' +
'<div ' + STYLES.ARROW + '></div>' +
'<div>' + sender + ' transferred ' + countTransferred + 'x item' + plural + ' to you.</div>' +
'</div>'
);
},
handleInput = function(msg) {
var sender = msg.who;
var charId, itemName, recipientId, recipientName;
let quantity = 1;
let clone = false;
// Assert for single-character commands
var parseCommandsAndAssertValidCharacter = function() {
_.each(msg.content.split('--'), function(str){
var split = str.split('|');
switch(split[0].toLowerCase()) {
case 'charid':
case 'ci': charId = split[1].trim(); break;
case 'item':
case 'i' : itemName = split[1].trim(); break;
}
});
// We need a valid character id to proceed
if(!charId && msg.selected) {
charId = findCharacterIdForToken(msg.selected[0]._id);
} else if (!charId && !msg.selected){
sendChat(scriptName, '/w ' + sender + ' No character ID found. Either selected the token or add --charid|CHARACTER_ID to the command');
return false;
}
return true;
};
// Assert for two-character commands
var parseCommandsAndAssertValidSenderAndReceiver = function() {
_.each(msg.content.split('--'), function(str){
var split = str.split('|');
switch(split[0].toLowerCase()) {
case 'charid':
case 'ci': charId = split[1].trim(); break;
case 'item':
case 'i' : itemName = split[1].trim(); break;
case 'recipientid':
case 'ri': recipientId = split[1].trim(); break;
case 'recipientname':
case 'rn': recipientName = split[1].trim(); break;
case 'quantity':
case 'q':
case 'count': quantity = split[1].trim(); break;
case 'clone': clone = true; break;
}
});
// Ensure quantity is a positive integer
quantity = parseInt(quantity) || 0;
if(quantity < 1) {
sendChat(scriptName, '/w ' + sender + '**ERROR:** invalid quantity. It must be a positive integer.');
return false;
}
// We need a valid character id for the sender in order to proceed
if(!charId && msg.selected) {
charId = findCharacterIdForToken(msg.selected[0]._id);
}
else if (!charId && !msg.selected){
sendChat(scriptName, '/w ' + sender + ' No character ID found. Either selected the token or add --charid|CHARACTER_ID to the command');
return false;
}
// We need a valid character id for the receiver in order to proceed
log("Target ID: " + recipientId + "Target Name: " + recipientName);
if(!recipientId && recipientName) {
let list = findObjs({
_type: "character",
name: recipientName
});
log(JSON.stringify(list));
if (list.length == 0) {
sendChat(scriptName, '/w ' + sender + '**ERROR:** No character exists by the name ' + recipientName + '.');
return false;
}
else if (list.length > 1) {
sendChat(scriptName, '/w ' + sender + '**ERROR:** character name ' + recipientName + ' must be unique.');
return false;
}
recipientId = list[0].id;
}
else if (!recipientId && !recipientName){
sendChat(scriptName, '/w ' + sender + ' No target ID found. Either add --recipientId|TARGET_ID or --recipientName|TARGET_NAME to the command');
return false;
}
return true;
};
if(msg.type === 'api' && msg.content.indexOf('!equipShow') !== -1) {
if(!parseCommandsAndAssertValidCharacter()) { return; }
if(msg.content.indexOf('--item|') !== -1) {
// set the item name and charId from the message
outputSingleItemForCharacter(charId, itemName, sender);
} else {
if (!charId && !msg.selected) {
sendChat(scriptName, '/w ' + sender + ' must have a character selected to use !equipShow');
return;
}
else if(charId){
outputEquipmentStatusForCharacter(charId, sender);
}
else{
_.each(msg.selected, function (sel) {
var charId = findCharacterIdForToken(sel._id);
outputEquipmentStatusForCharacter(charId, sender);
});
}
}
}
else if (msg.type === 'api' && msg.content.indexOf('!equipToggle') !== -1) {
if(!parseCommandsAndAssertValidCharacter()) { return; }
// We need the item's name to proceed
if(!itemName) {
sendChat(scriptName, '/w ' + sender + ' No item provided. Add --item|ITEM_NAME to the command');
return;
}
if(!playerCanControlCharacter(charId, msg.playerid)) {
sendChat(scriptName, '/w ' + sender + ' You cannot modify the equipment of a character you do not control.');
return;
}
toggleEquipment(charId, itemName, sender);
}
else if (msg.type === 'api' && msg.content.indexOf('!equipPass') !== -1) {
if(!parseCommandsAndAssertValidSenderAndReceiver()) { return; }
// We need the item's name to proceed
if(!itemName) {
sendChat(scriptName, '/w ' + sender + ' No item provided. Add --item|ITEM_NAME to the command');
return;
}
if(!playerCanControlCharacter(charId, msg.playerid)) {
sendChat(scriptName, '/w ' + sender + ' You cannot modify the equipment of a character you do not control.');
return;
}
if(charId == recipientId) {
sendChat(scriptName, '/w ' + sender + ' You cannot transfer an item to yourself.');
return;
}
passEquipment(charId, recipientName, recipientId, itemName, sender, quantity, clone);
}
},
checkInstall = function(){
log(scriptName + ' v' + version + ' -> Ready');
},
registerEventHandlers = function() {
on('chat:message', handleInput);
};
return {
CheckInstall: checkInstall,
RegisterEventHandlers: registerEventHandlers
};
}());
on('ready', function(){
'use strict';
InventoryTracker5eOGL.CheckInstall();
InventoryTracker5eOGL.RegisterEventHandlers();
});
<div class="sheet-attack">
<input class="sheet-options-flag" type="checkbox" name="attr_options-flag" checked="checked"><span>y</span>
<div class="sheet-options">
<div class="sheet-row">
<span data-i18n="name:-u">NAME:</span>
<input type="text" name="attr_atkname">
</div>
<div class="sheet-row">
<input type="checkbox" name="attr_atkflag" value="{{attack=1}}" checked="checked">
<span data-i18n="attack:-u">ATTACK:</span>
<select name="attr_atkattr_base">
<option value="@{strength_mod}" selected="selected" data-i18n="str-u">STR</option>
<option value="@{dexterity_mod}" data-i18n="dex-u">DEX</option>
<option value="@{constitution_mod}" data-i18n="con-u">CON</option>
<option value="@{intelligence_mod}" data-i18n="int-u">INT</option>
<option value="@{wisdom_mod}" data-i18n="wis-u">WIS</option>
<option value="@{charisma_mod}" data-i18n="cha-u">CHA</option>
<option value="0">-</option>
</select>
<span>+</span>
<input type="text" class="sheet-num" name="attr_atkmod" placeholder="0">
<span>+</span>
<input type="checkbox" name="attr_atkprofflag" value="(@{pb})" checked="checked" style="margin-left: 3px">
<span data-i18n="proficient-u">PROFICIENT</span>
</div>
<div class="sheet-row">
<span style="margin-left: 17px" data-i18n="range:-u">RANGE:</span>
<input type="text" name="attr_atkrange" placeholder="Self (60-foot cone)" style="width: 170px" data-i18n-placeholder="range-place">
</div>
<div class="sheet-row">
<span style="margin-left: 17px" data-i18n="magic-bonus:-u">MAGIC BONUS:</span>
<input type="text" class="sheet-num" name="attr_atkmagic" placeholder="0">
<span data-i18n="crit-range-u">CRIT RANGE:</span>
<input type="text" class="sheet-num" name="attr_atkcritrange" value="20" placeholder="20">
</div>
<div class="sheet-row">
<input type="checkbox" name="attr_dmgflag" value="{{damage=1}} {{dmg1flag=1}}" checked="checked">
<span data-i18n="damage:-u">DAMAGE:</span>
<input type="text" name="attr_dmgbase" placeholder="1d6" style="width: 50px">
<span>+</span>
<select name="attr_dmgattr">
<option value="@{strength_mod}" selected="selected" data-i18n="str-u">STR</option>
<option value="@{dexterity_mod}" data-i18n="dex-u">DEX</option>
<option value="@{constitution_mod}" data-i18n="con-u">CON</option>
<option value="@{intelligence_mod}" data-i18n="int-u">INT</option>
<option value="@{wisdom_mod}" data-i18n="wis-u">WIS</option>
<option value="@{charisma_mod}" data-i18n="cha-u">CHA</option>
<option value="0">-</option>
</select>
<span>+</span>
<input type="text" class="sheet-num" name="attr_dmgmod" placeholder="0">
</div>
<div class="sheet-row">
<span style="margin-left: 17px" data-i18n="type:-u">TYPE:</span>
<input type="text" name="attr_dmgtype" placeholder="Slashing" style="width: 50px" data-i18n-placeholder="dmg-type-place">
<span data-i18n="crit:-u">CRIT:</span>
<input type="text" name="attr_dmgcustcrit" placeholder="1d6" style="width: 80px">
</div>
<div class="sheet-row">
<input type="checkbox" name="attr_dmg2flag" value="{{damage=1}} {{dmg2flag=1}}" checked="checked">
<span data-i18n="damage2:-u">DAMAGE2:</span>
<input type="text" name="attr_dmg2base" placeholder="1d6" style="width: 50px">
<span>+</span>
<select name="attr_dmg2attr">
<option value="@{strength_mod}" data-i18n="str-u">STR</option>
<option value="@{dexterity_mod}" data-i18n="dex-u">DEX</option>
<option value="@{constitution_mod}" data-i18n="con-u">CON</option>
<option value="@{intelligence_mod}" data-i18n="int-u">INT</option>
<option value="@{wisdom_mod}" data-i18n="wis-u">WIS</option>
<option value="@{charisma_mod}" data-i18n="cha-u">CHA</option>
<option value="0" selected="selected">-</option>
</select>
<span>+</span>
<input type="text" class="sheet-num" name="attr_dmg2mod" placeholder="0">
</div>
<div class="sheet-row">
<span style="margin-left: 17px" data-i18n="type:-u">TYPE:</span>
<input type="text" name="attr_dmg2type" placeholder="Slashing" style="width: 50px" data-i18n-placeholder="dmg-type-place">
<span data-i18n="crit:-u">CRIT:</span>
<input type="text" name="attr_dmg2custcrit" placeholder="1d6" style="width: 80px">
</div>
<div class="sheet-row">
<input type="checkbox" name="attr_saveflag" value="{{save=1}} {{saveattr=@{saveattr}}} {{savedesc=@{saveeffect}}} {{savedc=[[[[@{savedc}]][SAVE]]]}}" checked="checked">
<span data-i18n="saving-throw:-u">SAVING THROW:</span>
<select name="attr_saveattr">
<option value="Strength" selected="selected" data-i18n="str-u">STR</option>
<option value="Dexterity" data-i18n="dex-u">DEX</option>
<option value="Constitution" data-i18n="con-u">CON</option>
<option value="Intelligence" data-i18n="int-u">INT</option>
<option value="Wisdom" data-i18n="wis-u">WIS</option>
<option value="Charisma" data-i18n="cha-u">CHA</option>
</select>
<span data-i18n="vs-dc:-u">VS DC:</span>
<select name="attr_savedc">
<option value="(@{spell_save_dc})" selected="selected" data-i18n="spell-u">SPELL</option>
<option value="(@{strength_mod}+8+@{pb})" data-i18n="str-u">STR</option>
<option value="(@{dexterity_mod}+8+@{pb})" data-i18n="dex-u">DEX</option>
<option value="(@{constitution_mod}+8+@{pb})" data-i18n="con-u">CON</option>
<option value="(@{intelligence_mod}+8+@{pb})" data-i18n="int-u">INT</option>
<option value="(@{wisdom_mod}+8+@{pb})" data-i18n="wis-u">WIS</option>
<option value="(@{charisma_mod}+8+@{pb})" data-i18n="cha-u">CHA</option>
<option value="(@{saveflat})" data-i18n="flat-u">FLAT</option>
</select>
<input class="sheet-flatflag" type="hidden" name="attr_savedc" value="(@{spell_save_dc})">
<input class="sheet-num sheet-flat" type="text" name="attr_saveflat" placeholder="10" value="10">
</div>
<div class="sheet-row">
<span data-i18n="save-effect:-u">SAVE EFFECT:</span>
<input type="text" name="attr_saveeffect" placeholder="half damage" style="width: 160px" data-i18n-placeholder="save-effect-place">
</div>
<div class="sheet-row sheet-ammo">
<span data-i18n="ammunition:-u">AMMUNITION:</span>
<input type="text" name="attr_ammo" placeholder="Arrows" style="width: 160px" data-i18n-placeholder="ammunition-place">
</div>
<div class="sheet-row">
<span data-i18n="description:-u">DESCRIPTION:</span>
<textarea name="attr_atk_desc" placeholder="Up to 2 creatures within 5 feet" data-i18n-placeholder="description-place"></textarea>
</div>
</div>
<div class="sheet-display">
<button type="roll" name="roll_attack" value="@{rollbase}" class="btn ui-draggable">
<span name="attr_atkname" style="width: 85px">Sword</span>
<input type="text" name="attr_atkbonus" style="width: 40px ; text-align: center" value="">
<input type="text" name="attr_atkdmgtype" style="width: 90px" value="">
</button>
</div>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment