-
-
Save VoltCruelerz/0e4b939c01576a2c76cc398253a397d3 to your computer and use it in GitHub Desktop.
5e OGL equipped inventory tracking
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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(); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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