Files
roll20-character-sheets/Pathfinder Community/dev/src/PFInventory.js
T
vince 8da6ffaa6f - updated how slotted items are handled when their location is changed or deleted.
- specific handling given to armor and shield to test and clear Defenses attrs for Armor3 and Shield3 if applicable.
2025-11-18 14:54:19 -08:00

2197 lines
81 KiB
JavaScript

'use strict';
import _ from 'underscore';
import {PFLog, PFConsole} from './PFLog';
import TAS from './TheAaronSheet.js';
import PFConst from './PFConst';
import * as SWUtils from './SWUtils';
import * as PFUtils from './PFUtils';
import * as PFMacros from './PFMacros';
import * as PFMenus from './PFMenus';
import * as PFMigrate from './PFMigrate';
import * as PFDefense from './PFDefense';
import * as PFAttackOptions from './PFAttackOptions';
import * as PFAttackGrid from './PFAttackGrid';
import * as PFAttacks from './PFAttacks';
import * as PFInventory from './PFInventory';
var locationNamesOld = ['Belt', 'Body', 'Chest', 'Eyes', 'Feet', 'Hands', 'Head', 'Headband', 'Neck', 'Ring1', 'Ring2', 'Shoulders', 'Wrist'],
wornSlotTypes = locationNamesOld.concat(['Armor3', 'Shield3', 'Armor', 'Shield']), // added Armor and Shield to help match
wornSlots = _.map(wornSlotTypes, function (row) {
return 'worn-' + row;
}),
wornSlotsRolls = _.map(wornSlotTypes, function (row) {
return 'worn-' + row + '-roll';
}),
locationNames = [
'Carried',
'NotCarried',
'Armor',
'Belt',
'Body',
'Chest',
'Eyes',
'Feet',
'Hands',
'Head',
'Headband',
'Neck',
'Ring1',
'Ring2',
'Shield',
'Shoulders',
'Wrist',
],
locationMap = {
Carried: 0,
NotCarried: 1,
Armor: 2,
Belt: 3,
Body: 4,
Chest: 5,
Eyes: 6,
Feet: 7,
Hands: 8,
Head: 9,
Headband: 10,
Neck: 11,
Ring1: 12,
Ring2: 13,
Shield: 14,
Shoulders: 15,
Wrist: 16,
equipped: 2,
},
equipMap = {noEquipType: 0, Weapon: 1, Armor: 2, Ammo: 3, Consumables: 4, OtherMagic: 5, Gear: 6, Other: 7, Charged: 8, Other2: 9},
groupMapForMenu = {
0: '',
1: 'weapons',
2: 'armor-shield',
3: 'ammunition',
4: 'consumables',
5: 'other-magic-items',
6: 'gear-tool',
7: 'other-items',
8: 'charged-magics',
9: 'other-items-2',
},
totaledFields = {value: 1, hp: 1, weight: 1},
commonLinkedAttributes = [
'attack-type',
'range',
'masterwork',
'crit-target',
'crit-multiplier',
'damage-dice-num',
'damage-die',
'damage',
'precision_dmg_macro',
'precision_dmg_type',
'critical_dmg_macro',
'critical_dmg_type',
];
/** resetCommandMacro sets command button macro with all rows from one ability list.
* calls PFMenus.getRepeatingCommandMacro
* sets the returned string to macro with attribute name: section+"_buttons_macro"
*@param {function} callback when done
*/
export function resetCommandMacro(callback) {
var done = _.once(function () {
//TAS.debug("leaving PFInventory.resetCommandMacro: ");
if (typeof callback === 'function') {
callback();
}
}),
doneOne = _.after(2, done);
PFMenus.resetOneCommandMacro('item', true, doneOne, '', groupMapForMenu);
PFMenus.resetOneCommandMacro('item', false, doneOne, '', groupMapForMenu);
}
/** Gets the worn item grid row name corresponding to location number in dropdown
*@param {Number|string} location a value from repeating_item_$X_location or name of location
*@returns {string} name of "worn-space" to set
*/
function getWornItemNameField(location) {
var wornSlot = '';
if (isNaN(location) && location !== null && location !== undefined) {
return 'worn-' + location;
} else if (location > 1 && locationNames[location]) {
try {
wornSlot = 'worn-' + locationNames[location];
} catch (e) {
TAS.error('PFInventory.getWornItemNameField', e);
}
}
return wornSlot;
}
/**
*
* @param {int} location must be in locationNames
*/
function takeOffWornItem(location) {
var namefield = '',
rollfield = '';
namefield = getWornItemNameField(location);
rollfield = namefield + '-roll';
getAttrs([namefield, rollfield], function (vout) {
var id = '',
setter = {};
if (vout[rollfield]) {
setter[rollfield] = '';
id = SWUtils.getRowId(vout[rollfield]);
if (id) {
setter['repeating_item_' + id + '_location'] = locationMap.Carried;
setter['repeating_item_' + id + '_old_location'] = locationMap.Carried;
}
}
if (vout[namefield]) {
setter[namefield] = '';
}
if (_.size(setter)) {
SWUtils.setWrapper(setter, PFConst.silentParams);
}
});
}
/** updateRepeatingItems totals columns
*@param {function} callback to call when done
*@param {bool} silently if true send PFConst.silentParams to SWUtils.setWrapper
*/
export function updateRepeatingItems(callback, silently, attrToUpdate) {
var done = _.once(function () {
if (typeof callback === 'function') {
callback();
}
});
try {
if (!attrToUpdate) {
attrToUpdate = totaledFields;
}
//TAS.debug("at updateRepeatingItems");
TAS.repeating('item')
.attrs('use_metrics', 'item_total_weight', 'item-total-hp', 'item-total-hp_max', 'item-total-value')
.fields('item-weight', 'qty', 'qty_max', 'location', 'item-hp', 'item-hp_max', 'value')
.reduce(
function (m, r) {
try {
//TAS.debug("in weight add row, variables: weight: "+r.F['item-weight']+", qty:"+r.I.qty+", max:"+r.I.qty_max +", loc:"+ r.I.location);
if (r.I.qty > 0) {
if (r.I.qty_max === 0 || r.I.qty_max === 1) {
if (attrToUpdate.weight && r.I.location !== locationMap.NotCarried) {
m['item-weight'] += r.F['item-weight'] * r.F.qty;
}
if (attrToUpdate.value) {
m.value += r.F.value * r.F.qty;
}
if (attrToUpdate.hp) {
m['item-hp'] += r.I['item-hp'] * r.I.qty;
m['item-hp_max'] += r.I['item-hp_max'] * r.I.qty;
}
} else {
if (attrToUpdate.weight && r.I.location !== locationMap.NotCarried) {
m['item-weight'] += r.F['item-weight'];
}
if (attrToUpdate.value) {
m.value += r.F.value;
}
if (attrToUpdate.hp) {
m['item-hp'] += r.I['item-hp'];
m['item-hp_max'] += r.I['item-hp_max'];
}
}
}
} catch (errinner) {
TAS.error('PFInventory.updateRepeatingItems inner error', errinner);
} finally {
return m;
}
},
{
'item-weight': 0,
'item-hp': 0,
'item-hp_max': 0,
value: 0,
},
function (m, r, a) {
//metric multiplier lbs to kgs
let use_metrics = 1;
if (a['use_metrics'] > 0) {
use_metrics = 0.454;
}
if (attrToUpdate.weight) {
a.S['item_total_weight'] = Math.floor(m['item-weight'] * use_metrics * 100) / 100;
}
if (attrToUpdate.hp) {
a.S['item-total-hp'] = m['item-hp'];
a.S['item-total-hp_max'] = m['item-hp_max'];
}
if (attrToUpdate.value) {
a.S['item-total-value'] = Math.floor(m.value * 100) / 100;
}
},
)
.execute(done);
} catch (err) {
TAS.error('PFInventory.updateRepeatingItems', err);
done();
}
}
/** updateCarriedCurrency totals weight for carried currency
*@param {function} callback to call when done
*@param {bool} silently if true send PFConst.silentParams to SWUtils.setWrapper
*/
function updateCarriedCurrency(callback, silently) {
var done = function () {
if (typeof callback === 'function') {
callback();
}
};
getAttrs(['CP', 'SP', 'GP', 'PP', 'carried-currency', 'use_metrics'], function (v) {
var curr = Number(v['carried-currency'] || 0),
params = {},
carried = 0;
try {
//metric multiplier to convert lbs to kgs
let use_metrics = 1;
if (parseInt(v['use_metrics']) > 0) {
use_metrics = 0.454;
}
carried = (parseInt(v['CP'], 10) || 0) + (parseInt(v['SP'], 10) || 0) + (parseInt(v['GP'], 10) || 0) + (parseInt(v['PP'], 10) || 0);
TAS.debug('coin curr=' + curr + ', coin carried=' + carried);
carried = Math.floor((carried / 50) * use_metrics * 100) / 100;
if (curr !== carried) {
if (silently) {
params = PFConst.silentParams;
}
SWUtils.setWrapper(
{
'carried-currency': carried,
},
params,
done,
);
} else {
done();
}
} catch (err) {
TAS.error('PFInventory.updateCarriedCurrency', err);
done();
}
});
}
/** updateCarriedTotal- updates the total for carried weight
*@param {function} callback to call when done
*@param {bool} silently if true send PFConst.silentParams to SWUtils.setWrapper
*/
function updateCarriedTotal(callback, silently) {
var done = function () {
if (typeof callback === 'function') {
callback();
}
};
getAttrs(['carried-currency', 'carried-currency-toggle', 'item_total_weight', 'carried-misc', 'carried-total', 'use_metrics'], function (v) {
var curr,
carried,
currency,
currencyToggle,
params = {};
try {
//metric multiplier to convert lbs to kgs
let use_metrics = 1;
if (parseInt(v['use_metrics']) > 0) {
use_metrics = 0.454;
}
currency = parseFloat(v['carried-currency']) || 0;
currencyToggle = parseInt(v['carried-currency-toggle']);
if (currencyToggle === 0) {
currency = 0;
}
curr = Math.floor(100 * parseFloat(v['carried-total']) || 0);
carried = Math.floor(currency * 100 + (parseFloat(v['item_total_weight']) || 0) * 100 + (parseFloat(v['carried-misc']) || 0) * 100); // Fix bad javascript math
TAS.debug('carried curr=' + curr + ', carried total=' + carried);
if (curr !== carried) {
carried = carried / 100;
SWUtils.setWrapper(
{
'carried-total': carried,
},
params,
done,
);
} else {
done();
}
} catch (err) {
TAS.error('PFInventory.updateCarriedTotal', err);
done();
}
});
}
/** Got rid of the Worn Equipment section, so migrate any values to the Equipment as repeating entries.
* Worn Armor & Worn Shield are now disabled and controlled by the Equipment section in the Inventory tab.
*@param {function} callback to call when done
*@param {bool} silently if true send PFConst.silentParams to SWUtils.setWrapper
*/
function migrateWornEquipment(callback) {
var done = _.once(function () {
//TAS.debug("leaving PFInventory.migrateWornEquipment");
if (typeof callback === 'function') {
callback();
}
}),
doneMigrating = _.once(function () {
SWUtils.setWrapper({migrated_worn_equipment: '1'}, {}, done);
}),
wornEquipmentColumns = ['charges', 'weight', 'hp', 'hp_max', 'value'],
copyWornEquipmentToNewItem = function (row, callback) {
var done = _.once(function () {
//TAS.debug("leaving PFInventory.copyWornEquipmentToNewItem for "+row);
if (typeof callback === 'function') {
callback();
}
}),
attribList = ['worn-' + row];
attribList.push('worn-' + row + '-description');
attribList.push('worn-' + row + '-hardness');
_.each(wornEquipmentColumns, function (col) {
attribList.push('worn-' + row + '-' + col);
});
getAttrs(attribList, function (v) {
var newRowId = '',
newRowAttrs = {},
weightRowAttrs = {},
attrib = '',
newLocation = 0,
newEquipType = equipMap.noEquipType;
// Migrate the worn equipment entry to equipment if the name is populated
try {
//TAS.debug("PFInventory.copyWornEquipmentToNewItem checking "+row+" it is:"+v["worn-" + row]);
if (v['worn-' + row]) {
newRowId = generateRowID();
/* Assign defined worn equipment values to new repeating_item entry */
newRowAttrs['repeating_item_' + newRowId + '_name'] = v['worn-' + row];
newRowAttrs['repeating_item_' + newRowId + '_row_id'] = newRowId;
attrib = v['worn-' + row + '-description'];
if (attrib) {
newRowAttrs['repeating_item_' + newRowId + '_short-description'] = attrib;
}
attrib = v['worn-' + row + '-charges'];
if (attrib) {
newRowAttrs['repeating_item_' + newRowId + '_qty'] = attrib;
newRowAttrs['repeating_item_' + newRowId + '_qty_max'] = v['worn-' + row + '-charges_max'] || 50;
} else {
weightRowAttrs['repeating_item_' + newRowId + '_qty'] = 1;
weightRowAttrs['repeating_item_' + newRowId + '_qty_max'] = 1;
}
attrib = v['worn-' + row + '-weight'];
if (attrib) {
weightRowAttrs['repeating_item_' + newRowId + '_item-weight'] = attrib;
}
attrib = v['worn-' + row + '-hardness'];
if (attrib) {
weightRowAttrs['repeating_item_' + newRowId + '_hardness'] = attrib;
}
attrib = v['worn-' + row + '-hp'];
if (attrib) {
weightRowAttrs['repeating_item_' + newRowId + '_item-hp'] = attrib;
}
attrib = v['worn-' + row + '-hp_max'];
if (attrib) {
newRowAttrs['repeating_item_' + newRowId + '_item-hp_max'] = attrib;
}
attrib = v['worn-' + row + '-value'];
if (attrib) {
weightRowAttrs['repeating_item_' + newRowId + '_value'] = attrib;
}
newRowAttrs['worn-' + row + '-roll'] = '@{repeating_item_' + newRowId + '_macro-text}';
// Location
newLocation = locationMap[row];
//wornEquipmentRowsPlusCarried.indexOf(row);
newRowAttrs['repeating_item_' + newRowId + '_location'] = newLocation;
newRowAttrs['repeating_item_' + newRowId + '_old_location'] = newLocation;
if (newLocation === locationMap.NotCarried) {
newRowAttrs['repeating_item_' + newRowId + 'loctype-tab'] = locationMap.NotCarried;
} else if (newLocation === locationMap.Carried) {
newRowAttrs['repeating_item_' + newRowId + 'loctype-tab'] = locationMap.Carried;
} else if (newLocation > locationMap.NotCarried) {
newRowAttrs['repeating_item_' + newRowId + 'loctype-tab'] = locationMap.equipped;
} else {
newRowAttrs['repeating_item_' + newRowId + 'loctype-tab'] = -1;
}
newEquipType = equipMap.OtherMagic;
newRowAttrs['repeating_item_' + newRowId + '_equip-type'] = newEquipType;
newRowAttrs['repeating_item_' + newRowId + '_equiptype-tab'] = newEquipType;
}
} catch (err) {
TAS.error('PFInventory.copyWornEquipmentToNewItem', err);
} finally {
//TAS.debug("PFInventory.migrateWornEquipment.copyWornEquipmentToNewItem setting:",newRowAttrs);
if (_.size(newRowAttrs) > 0) {
SWUtils.setWrapper(newRowAttrs, PFConst.silentParams, done);
} else {
done();
}
//weight, hardness, qty are set non silently to trigger recalc
if (_.size(weightRowAttrs) > 0) {
SWUtils.setWrapper(weightRowAttrs);
}
}
});
},
// Migrate the armor & worn shield entries to equipment if the name is populated
//item: value from PFDefense.defenseArmorShieldRowsOld
copyWornDefenseToNewItem = function (item, wornAlreadySet, callback) {
var done = _.once(function (wasSetToWorn) {
//TAS.debug("leaving PFInventory.copyWornDefenseToNewItem did we set worn for "+item+"?: "+wasSetToWorn);
if (typeof callback === 'function') {
callback(wasSetToWorn);
}
}),
attribList = [item, item + '-type'],
defenseName = '',
isArmor = 0,
isShield = 0;
//armor or shield?
if (/armor/i.test(item)) {
isArmor = 1;
} else if (/shield/i.test(item)) {
isShield = 1;
} else {
done(0);
return;
}
// Search for pre-existing matching entry in equipment
getAttrs([item], function (vi) {
//TAS.debug("vi[item]=" + vi[item]);
if (!vi[item]) {
done(0);
return;
}
defenseName = vi[item];
getSectionIDs('repeating_item', function (ids) {
//TAS.debug("ids=" + ids);
var fields = [];
fields = _.map(ids, function (id) {
return 'repeating_item_' + id + '_name';
});
_.each(PFDefense.defenseArmorShieldColumns, function (column) {
attribList.push(item + '-' + column);
});
attribList = attribList.concat(fields);
//TAS.debug("copyWornDefenseToNewItem attribList=" + attribList);
getAttrs(attribList, function (v) {
var prefix,
matchingField,
newRowId = '',
newRowAttrs = {},
locationAttrs = {},
maxDex = 0,
attrib = '',
isNewRow = true,
markedEquipped = 0,
isWorn = 0;
try {
//TAS.debug("PFInventory.copyWornDefenseToNewItem item:"+item+" was already set="+wornAlreadySet,v);
markedEquipped = parseInt(v[item + '-equipped'], 10) || 0;
maxDex = parseInt(v[item + '-max-dex'], 10);
if (isNaN(maxDex)) {
maxDex = 99;
}
matchingField = _.find(fields, function (field) {
return defenseName === v[field];
});
//TAS.debug("matchingField=" + matchingField);
if (matchingField) {
isNewRow = false;
newRowId = SWUtils.getRowId(matchingField);
} else {
newRowId = generateRowID();
}
newRowAttrs['repeating_item_' + newRowId + '_equip-type'] = equipMap.Armor;
newRowAttrs['repeating_item_' + newRowId + '_equiptype-tab'] = equipMap.Armor;
/* Assign defined worn equipment values to new repeating_item entry */
if (isNewRow) {
newRowAttrs['repeating_item_' + newRowId + '_name'] = defenseName;
}
newRowAttrs['repeating_item_' + newRowId + '_qty'] = 1;
newRowAttrs['repeating_item_' + newRowId + '_qty_max'] = 1;
if (!wornAlreadySet && markedEquipped === 1) {
isWorn = 1;
if (isArmor) {
if (isNewRow) {
newRowAttrs['repeating_item_' + newRowId + '_location'] = locationMap.Armor;
newRowAttrs['repeating_item_' + newRowId + '_old_location'] = locationMap.Armor;
} else {
locationAttrs['repeating_item_' + newRowId + '_location'] = locationMap.Armor;
}
newRowAttrs['repeating_item_' + newRowId + '_loctype-tab'] = locationMap.equipped;
newRowAttrs['armor3-roll'] = '@{repeating_item_' + newRowId + '_macro-text}';
newRowAttrs['armor3'] = v[item];
} else {
if (isNewRow) {
newRowAttrs['repeating_item_' + newRowId + '_location'] = locationMap.Shield;
newRowAttrs['repeating_item_' + newRowId + '_old_location'] = locationMap.Shield;
} else {
locationAttrs['repeating_item_' + newRowId + '_location'] = locationMap.Shield;
}
newRowAttrs['repeating_item_' + newRowId + '_loctype-tab'] = locationMap.equipped;
newRowAttrs['shield3-roll'] = '@{repeating_item_' + newRowId + '_macro-text}';
newRowAttrs['shield3'] = v[item];
}
//set to blank
if (maxDex > 50) {
newRowAttrs[item + '-max-dex'] = '-';
}
} else {
//do not need to put in locationAttrs since we set it something last time we came through for other row
newRowAttrs['repeating_item_' + newRowId + '_location'] = locationMap.NotCarried; // not Carried
newRowAttrs['repeating_item_' + newRowId + '_old_location'] = locationMap.NotCarried;
newRowAttrs['repeating_item_' + newRowId + '_loctype-tab'] = locationMap.NotCarried;
//ensure it is not marked equipped
if (markedEquipped) {
newRowAttrs[item + '-equipped'] = 0;
}
// Leave the entry there. The player can manage the entry from inventory and equip it on Defenses tab
}
//do not set type, max-dex, or equipped, but do all other columns:
_.each(['acbonus', 'enhance', 'acp', 'spell-fail', 'proficiency'], function (col) {
attrib = v[item + '-' + col];
if (attrib) {
newRowAttrs['repeating_item_' + newRowId + '_item-' + col] = attrib;
}
});
if (maxDex > 50) {
newRowAttrs['repeating_item_' + newRowId + '_item-max-dex'] = '-';
} else {
newRowAttrs['repeating_item_' + newRowId + '_item-max-dex'] = maxDex;
}
attrib = v[item + '-type'];
if (attrib) {
newRowAttrs['repeating_item_' + newRowId + '_item-defense-type'] = attrib;
}
} catch (err) {
TAS.error('PFInventory.copyWornDefenseToNewItem', err);
} finally {
if (_.size(newRowAttrs) > 0) {
//TAS.debug("PFInventory.copyWornDefenseToNewItem item:"+item+",setting:",newRowAttrs);
SWUtils.setWrapper(newRowAttrs, PFConst.silentParams, function () {
if (_.size(locationAttrs) > 0) {
SWUtils.setWrapper(locationAttrs, {}, function () {
done(isWorn);
});
} else {
done(isWorn);
}
});
} else {
done(false);
}
}
});
});
});
};
//TAS.debug("############","at PFInventory.migrateWornEquipment");
getAttrs(['migrated_worn_equipment'], function (v) {
var foundWornArmor = false,
foundWornShield = false,
doneAll = _.after(2, function () {
//TAS.debug("#### PFInventory.migrateWornEquipment.doneAll 2");
doneMigrating();
}),
migrateDefenses = function () {
TAS.debug('checking armor3');
copyWornDefenseToNewItem('armor3', foundWornArmor, function (wasSet) {
foundWornArmor = foundWornArmor || wasSet;
TAS.debug('checking armor2, found=' + foundWornArmor);
copyWornDefenseToNewItem('armor2', foundWornArmor, function (wasSet) {
foundWornArmor = foundWornArmor || wasSet;
TAS.debug('checking armor0, found=' + foundWornArmor);
copyWornDefenseToNewItem('armor', foundWornArmor, doneAll);
});
});
TAS.debug('checking shield3');
copyWornDefenseToNewItem('shield3', foundWornShield, function (wasSet) {
foundWornShield = foundWornShield || wasSet;
TAS.debug('checking shield2, found=' + foundWornShield);
copyWornDefenseToNewItem('shield2', foundWornShield, function (wasSet) {
foundWornShield = foundWornShield || wasSet;
TAS.debug('checking shield0, found=' + foundWornShield);
copyWornDefenseToNewItem('shield', foundWornShield, doneAll);
});
});
},
doneWornRows = _.after(_.size(locationNamesOld), function () {
var wornRows, fieldsToClear, setter;
try {
wornRows = _.map(locationNamesOld, function (field) {
return 'worn-' + field + '-';
});
fieldsToClear = SWUtils.cartesianAppend(wornRows, ['charges', 'weight', 'hp', 'hp_max', 'value', 'description', 'hardness']);
setter = _.reduce(
fieldsToClear,
function (m, f) {
m[f] = '';
return m;
},
{},
);
SWUtils.setWrapper(setter, PFConst.silentParams, migrateDefenses);
} catch (err) {
TAS.error('PFInventory.migrateWornEquipment.doneWornRows err:', err);
migrateDefenses();
}
});
try {
//TAS.debug("PFInventory.migrateWornEquipment flag is ",v," and there are "+_.size(wornEquipBaseRowsOld)+" rows of worn equip");
if (parseInt(v['migrated_worn_equipment'], 10) === 1) {
//TAS.debug("##########","ALREADY MIGRATED WORN EQUIPMENT");
done();
return;
}
//do worn equipment rows before armor, because sometimes they have armor in a slot.
_.each(locationNamesOld, function (row) {
copyWornEquipmentToNewItem(row, doneWornRows);
});
} catch (err) {
TAS.error('PFInventory.migrateWornEquipment', err);
migrateDefenses();
}
});
}
function unsetOtherItems(callback, location, id) {
if (!id || location < 2 || !location) {
if (typeof callback === 'function') {
callback();
}
}
/*
* The player has now changed the location to a worn slot, so check for other repeating items that have the same
* slot and set them to 'carried'.
*/
getSectionIDs('repeating_item', function (idarray) {
// get the repeating set
var attribs = [];
if (_.size(idarray) <= 1) {
if (typeof callback === 'function') {
callback();
}
return;
}
_.each(idarray, function (currentID, i) {
// loop through the set
if (currentID !== id) {
attribs.push('repeating_item_' + currentID + '_location');
}
});
getAttrs(attribs, function (w) {
var setter = {};
_.each(idarray, function (currentID, i) {
// loop through the set
if ((parseInt(w['repeating_item_' + currentID + '_location'], 10) || 0) === location) {
setter['repeating_item_' + currentID + '_location'] = 0;
setter['repeating_item_' + currentID + '_old_location'] = 0;
}
});
if (_.size(setter) > 0) {
SWUtils.setWrapper(setter, {silent: true}, callback);
} else {
if (typeof callback === 'function') {
callback();
}
}
});
});
}
/** set old location to the new location, and unset other items set to this location, also updates loctype-tab
*@param {string} id id of row updated, or null
*@param {function} callback to call when done
*@param {boolean} silently if true call SWUtils.setWrapper with {silent:true}
*@param {object} eventInfo USED - from event, to get id from sourceAttribute
*/
function updateEquipmentLocation(id, callback, silently, eventInfo) {
var done = _.once(function () {
//TAS.debug("leaving PFInventory.updateEquipmentLocation for id "+id);
if (typeof callback === 'function') {
callback();
}
}),
/* unsetOtherItems makes sure any other row than id is not in location */
idStr = SWUtils.getRepeatingIDStr(id),
item_entry = 'repeating_item_' + idStr,
realItemID = id || (eventInfo ? SWUtils.getRowId(eventInfo.sourceAttribute) || '' : ''),
prefix = 'repeating_item_' + realItemID + '_',
locationField = prefix + 'location',
locationTabField = prefix + 'loctype-tab',
nameField = prefix + 'name',
oldLocationField = prefix + 'old_location',
rollField = prefix + 'macro-text';
try {
//TAS.debug("updateEquipmentLocation: called for ID "+ realItemID);
//sample source: repeating_item_-kbkc95wvqw1n4rbgs1c_location
// note that the source is always lowercase, but the actual ID is both cases
//check value of 'location' to see if it is being worn; if not check to see if the player is removing it from 'worn'
//TAS.debug("updateEquipmentLocation source=" + source);
getAttrs([locationField, oldLocationField, nameField, locationTabField], function (v) {
var location = 0,
oldlocation = 0,
wornItemAttrs = {},
wornSlot = '',
loctab = -1,
itemName = '',
setter = {};
//TAS.debug("updateEquipmentLocation: ", v);
try {
location = parseInt(v[locationField], 10);
if (isNaN(location)) {
//TAS.debug("why is location not set!?");
location = locationMap.NotCarried;
wornItemAttrs[locationField] = location;
}
loctab = parseInt(v[locationTabField]);
if (isNaN(loctab)) {
loctab = -2;
}
if (location > locationMap.NotCarried) {
if (loctab !== locationMap.equipped) {
wornItemAttrs[locationTabField] = locationMap.equipped;
}
} else if (location === locationMap.Carried) {
if (loctab !== location) {
wornItemAttrs[locationTabField] = locationMap.Carried;
}
} else if (location === locationMap.NotCarried) {
if (loctab !== location) {
wornItemAttrs[locationTabField] = locationMap.NotCarried;
}
} else {
if (loctab !== -1) {
wornItemAttrs[locationTabField] = '-1';
}
}
oldlocation = parseInt(v[oldLocationField], 10);
if (isNaN(oldlocation)) {
oldlocation = location;
}
wornItemAttrs[oldLocationField] = location;
if (location === locationMap.Carried && oldlocation !== locationMap.NotCarried && oldlocation !== location) {
wornSlot = getWornItemNameField(oldlocation);
if (wornSlot) {
wornItemAttrs[wornSlot] = '';
wornItemAttrs[wornSlot + '-roll'] = '';
}
} else if (location === locationMap.NotCarried) {
wornSlot = getWornItemNameField(oldlocation);
if (wornSlot) {
wornItemAttrs[wornSlot] = '';
wornItemAttrs[wornSlot + '-roll'] = '';
}
if (oldlocation === 2) {
// Armor un-equipped, reset Defenses
setter['armor3-equipped'] = 0;
}
if (oldlocation === 14) {
// Shield un-equipped, reset Defenses
setter['shield3-equipped'] = 0;
}
} else if (location > locationMap.NotCarried) {
wornSlot = getWornItemNameField(location);
TAS.debug('#####################at set location the new location ' + location + ',' + locationNames[location] + ' is ' + wornSlot);
if (wornSlot) {
itemName = v[nameField] || '';
if (itemName) {
wornItemAttrs[wornSlot] = itemName;
} else {
wornItemAttrs[wornSlot] = 'Row ' + realItemID;
}
wornItemAttrs[wornSlot + '-roll'] = '@{' + rollField + '}';
}
if (oldlocation > 1 && oldlocation !== location) {
wornSlot = getWornItemNameField(oldlocation);
if (wornSlot) {
wornItemAttrs[wornSlot] = '';
wornItemAttrs[wornSlot + '-roll'] = '';
}
}
}
} catch (err2) {
TAS.error('updateEquipmentLocation update location error:', err2);
} finally {
if (_.size(wornItemAttrs) > 0) {
TAS.debug('updateEquipmentLocation, setting slot ', wornItemAttrs);
SWUtils.setWrapper(wornItemAttrs, PFConst.silentParams, function () {
if (location > locationMap.NotCarried) {
unsetOtherItems(callback, location, realItemID);
}
done();
});
} else {
done();
}
}
if (_.size(setter)) {
SWUtils.setWrapper(setter, PFConst.silentParams);
}
});
} catch (err) {
TAS.error('PFInventory.updateEquipmentLocation', err);
done();
}
}
/** replace the values on the Defenses tab in disabled fields with this row's values
* from the equipment.
*@param {int} location the value of location attribute in repeating_item
*@param {string} sourceAttribute eventInfo sourceAttribute of change user made that called this
*@param {function} callback call when done
*/
function updateWornArmorAndShield(location, sourceAttribute, callback) {
var done = _.once(function () {
//TAS.debug("leaving PFInventory.updateWornArmorAndShield");
if (typeof callback === 'function') {
callback();
}
}),
defenseItem = '',
attribUpdated = '',
itemFullPrefix = '',
attribList = [],
id = '',
wornSlotField = '',
item_entry = '',
itemFields = [
'item-acbonus',
'item-acenhance',
'item-max-dex',
'item-acp',
'item-spell-fail',
'item-defense-type',
'item-proficiency',
'name',
'set-as-armor',
'set-as-shield',
'location',
'old_location',
'equip-type',
'acenhance',
];
try {
attribUpdated = SWUtils.getAttributeName(sourceAttribute);
id = SWUtils.getRowId(sourceAttribute);
item_entry = 'repeating_item_' + id + '_';
if (item_entry.slice(-1) !== '_') {
item_entry += '_';
}
wornSlotField = getWornItemNameField(location);
itemFullPrefix = item_entry + 'item-';
defenseItem = location === locationMap.Armor ? 'armor3' : 'shield3';
//TAS.debug"at update worn armor, defenseItem=" + defenseItem);
attribList = _.map(itemFields, function (attr) {
return item_entry + attr;
});
attribList = _.reduce(
PFDefense.defenseArmorShieldColumns,
function (memo, col) {
memo.push(defenseItem + '-' + col);
return memo;
},
attribList,
);
attribList.push(defenseItem);
attribList.push(wornSlotField);
//TAS.debug("PFInventory.updateWornArmorAndShield fields ", attribList);
} catch (err) {
TAS.error('PFInventory.updateWornArmorAndShield error before getAttrs', err);
done();
return;
}
//TAS.debug("attribList=" + attribList);
getAttrs(attribList, function (w) {
var i = 0,
setter = {},
silentSetter = {},
equipType = 0,
actualLocation = 0,
attrib = '',
itemName = '';
try {
//if we are setting new, or updating an item in the location, or updating an item in a different location
//so we can set a new ring of shield, but not update it. but we can update armor and shields.
if (attribUpdated === 'set-as-armor' || attribUpdated === 'set-as-shield' || location === locationMap.Armor || location === locationMap.Shield) {
//TAS.debug("updateWornArmorAndShield ", w);
for (i = 0; i < PFDefense.defenseArmorShieldColumns.length; i++) {
if (
PFDefense.defenseArmorShieldColumns[i] !== 'max-dex' &&
PFDefense.defenseArmorShieldColumns[i] !== 'equipped' &&
PFDefense.defenseArmorShieldColumns[i] !== 'type' &&
PFDefense.defenseArmorShieldColumns[i] !== 'enhance'
) {
attrib = parseInt(w[itemFullPrefix + PFDefense.defenseArmorShieldColumns[i]], 10) || 0;
if (parseInt(w[defenseItem + '-' + PFDefense.defenseArmorShieldColumns[i]], 10) !== attrib) {
setter[defenseItem + '-' + PFDefense.defenseArmorShieldColumns[i]] = attrib;
}
}
}
attrib = w[itemFullPrefix + 'acenhance'];
if (attrib) {
setter[defenseItem + '-enhance'] = attrib;
}
attrib = w[itemFullPrefix + 'defense-type'];
if (attrib) {
if (defenseItem === 'shield3' && attrib === 'Medium') {
//invalid choice, prob meant heavy shield
attrib = 'Heavy';
} else if (defenseItem === 'armor3' && attrib === 'Tower Shield') {
//invalid
attrib = 'Heavy';
}
if (w[defenseItem + '-type'] !== attrib) {
setter[defenseItem + '-type'] = attrib;
}
}
attrib = parseInt(w[itemFullPrefix + 'max-dex'], 10);
if (w[itemFullPrefix + 'max-dex'] === '-' || isNaN(attrib)) {
setter[defenseItem + '-max-dex'] = '-';
} else {
setter[defenseItem + '-max-dex'] = attrib;
}
if (w[defenseItem + '-equipped'] !== '1') {
setter[defenseItem + '-equipped'] = 1;
}
//reset the buttons silently so we don't loop.
attrib = parseInt(w[item_entry + 'set-as-armor'], 10);
if (attrib) {
silentSetter[item_entry + 'set-as-armor'] = '0';
}
attrib = parseInt(w[item_entry + 'set-as-shield'], 10);
if (attrib) {
silentSetter[item_entry + 'set-as-shield'] = '0';
}
//set armor3 or shield3 name
itemName = w[item_entry + 'name'];
if (itemName) {
if (w[defenseItem] !== itemName) {
setter[defenseItem] = itemName;
}
} else {
setter[defenseItem] = '';
}
//if we hit "set as armor or shield" on a piece of armor / shield equipment, make sure to slot it.
//do it silently so we don't loop
equipType = parseInt(w[item_entry + 'equip-type'], 10);
actualLocation = parseInt(w[item_entry + 'location'], 10);
//this would only be if "set as armor or shield" checked
if (
(location === locationMap.Armor && equipType === equipMap.Armor && actualLocation !== locationMap.Armor) ||
(location === locationMap.Shield && equipType === equipMap.Armor && actualLocation !== locationMap.Shield)
) {
silentSetter[item_entry + 'old_location'] = actualLocation;
silentSetter[item_entry + 'location'] = location; // should set location to match set armor or shield button
if (itemName && w[wornSlotField] !== itemName) {
silentSetter[wornSlotField] = itemName;
} else if (!itemName) {
silentSetter[wornSlotField] = ''; //when would this happen? never.
}
} else if (equipType !== equipMap.Armor && equipType !== equipMap.Shield) {
//need to remove any others from armor or shield location depending
takeOffWornItem(location);
}
} else {
TAS.warning('no reason to update armor or shield for ' + sourceAttribute + ' in location ' + locationNames[location]);
}
} catch (errinner) {
TAS.error('PFInventory.updateWornArmorAndShield INNER error', errinner);
} finally {
if (_.size(silentSetter) > 0) {
SWUtils.setWrapper(silentSetter, PFConst.silentParams, function () {
if (actualLocation !== location) {
updateEquipmentLocation(id, null, true, null);
}
});
}
if (_.size(setter) > 0) {
//TAS.debug("updating defenses tab for " + defenseItem, setter);
SWUtils.setWrapper(setter, {}, done);
} else {
done();
}
}
});
}
/** calls updateEquipmentLocation for all items
* can be refactored to be faster to do all at once
*/
export function updateLocations(callback) {
var done = _.once(function () {
//TAS.debug("leaving PFInventory.updateLocations");
if (typeof callback === 'function') {
callback();
}
});
getSectionIDs('repeating_item', function (ids) {
var total = 0,
doneOne;
try {
if (!(ids && _.size(ids))) {
done();
return;
}
total = _.size(ids);
//TAS.debug("PFInventory.updateLocations there are "+total+" rows in items");
doneOne = _.after(total, done);
_.each(ids, function (id) {
updateEquipmentLocation(id, doneOne, null, null);
});
} catch (err) {
TAS.error('PFInventory.updateLocations', err);
done();
}
});
}
/** Triggered from a button in repeating_items, it will create a repeating attack entry from the item entry
* @param {string} id the id of the item row
* @param {string} weaponId if the row already exists, overwrite all fields but 'name' this is similar to updateAssociatedAttack
*/
export function createAttackEntryFromRow(id, callback, silently, eventInfo, weaponId) {
var done = _.once(function () {
//TAS.debug("leaving PFInventory.createAttackEntryFromRow");
if (typeof callback === 'function') {
callback();
}
}),
attribList = [],
itemId,
idStr,
item_entry;
if (id === 'DELETED') {
done();
return;
}
itemId = id || (eventInfo ? SWUtils.getRowId(eventInfo.sourceAttribute) : '');
idStr = SWUtils.getRepeatingIDStr(itemId);
item_entry = 'repeating_item_' + idStr;
//TAS.debug("PFInventory.createAttackEntryFromRow: item_entry=" + item_entry + " , weapon:"+weaponId);
attribList.push(item_entry + 'name');
commonLinkedAttributes.forEach(function (attr) {
attribList.push(item_entry + 'item-' + attr);
});
attribList.push(item_entry + 'item-wpenhance');
attribList.push(item_entry + 'item-dmg-type');
attribList.push(item_entry + 'default_size');
//TAS.debug("attribList=" + attribList);
getAttrs(attribList, function (v) {
var newRowId,
setter = {},
deleteditem = false,
// silentSetter={},
enhance = 0,
prof = 0,
itemexists = true,
params = silently ? PFConst.silentParams : {};
try {
if (_.size(v) === 0) {
itemexists = false;
}
if (itemexists) {
//we should check to make sure item exists.
//TAS.debug("weaponId is :"+weaponId);
if (!weaponId) {
newRowId = generateRowID();
} else {
newRowId = weaponId;
}
//TAS.debug("the new row id is: "+newRowId);
//TAS.debug("v[" + item_entry + "name]=" + v[item_entry + "name"]);
if (v[item_entry + 'name']) {
if (!weaponId) {
setter['repeating_weapon_' + newRowId + '_name'] = v[item_entry + 'name'];
}
setter['repeating_weapon_' + newRowId + '_source-item-name'] = v[item_entry + 'name'];
}
commonLinkedAttributes.forEach(function (attr) {
//TAS.debug("v[" + item_entry + "item-" + attr + "]=" + v[item_entry + "item-" + attr]);
if (v[item_entry + 'item-' + attr]) {
setter['repeating_weapon_' + newRowId + '_' + attr] = v[item_entry + 'item-' + attr];
}
});
if (/melee/i.test(v[item_entry + 'item-attack-type'])) {
setter['repeating_weapon_' + newRowId + '_damage-ability'] = 'STR-mod';
} else if (/ranged/i.test(v[item_entry + 'item-attack-type'])) {
setter['repeating_weapon_' + newRowId + '_isranged'] = 1;
}
enhance = parseInt(v[item_entry + 'item-wpenhance'], 10) || 0;
if (enhance) {
setter['repeating_weapon_' + newRowId + '_enhance'] = enhance;
}
//TAS.debug("v[" + item_entry + "item-defense-type]=" + v[item_entry + "item-defense-type"]);
if (v[item_entry + 'item-dmg-type']) {
setter['repeating_weapon_' + newRowId + '_type'] = v[item_entry + 'item-dmg-type'];
}
//TAS.debug("v[" + item_entry + "item-proficiency]=" + v[item_entry + "item-proficiency"]);
prof = parseInt(v[item_entry + 'item-proficiency'], 10) || 0;
if (prof !== 0) {
prof = -4;
setter['repeating_weapon_' + newRowId + '_proficiency'] = prof;
}
if (v[item_entry + 'default_size']) {
setter['repeating_weapon_' + newRowId + '_default_size'] = v[item_entry + 'default_size'];
}
setter['repeating_weapon_' + newRowId + '_default_damage-dice-num'] = v[item_entry + 'damage-dice-num'] || 0;
setter['repeating_weapon_' + newRowId + '_default_damage-die'] = v[item_entry + 'damage-die'] || 0;
setter['repeating_weapon_' + newRowId + '_source-item'] = itemId;
setter['repeating_weapon_' + newRowId + '_link_type'] = PFAttacks.linkedAttackType.equipment;
} else if (weaponId) {
setter['repeating_weapon_' + weaponId + '_source-item'] = 'DELETED';
deleteditem = true;
}
} catch (err) {
TAS.error('PFInventory.createAttackEntryFromRow', err);
} finally {
if (deleteditem) {
SWUtils.setWrapper(setter, PFConst.silentParam, done);
} else if (_.size(setter) > 0) {
setter[item_entry + 'create-attack-entry'] = 0;
//TAS.debug("PFInventory.createAttackEntryFromRow creating new attack", setter);
SWUtils.setWrapper(setter, PFConst.silentParams, function () {
PFAttacks.recalcRepeatingWeapon(newRowId, function () {
PFAttackGrid.resetCommandMacro();
PFAttackOptions.resetOption(newRowId);
done();
});
});
} else {
setter[item_entry + 'create-attack-entry'] = 0;
SWUtils.setWrapper(setter, PFConst.silentParams, done);
}
}
});
}
export function updateAssociatedAttack(source, callback) {
var done = _.once(function () {
//TAS.debug("leaving PFInventory.updateAssociatedAttack");
if (typeof callback === 'function') {
callback();
}
}),
attrib = '',
weaponAttrib = '',
sourceVal = '',
itemId = '',
sectionName = '',
fields = [],
setter = {},
attribList = [];
try {
if (!source) {
done();
return;
}
itemId = SWUtils.getRowId(source);
attrib = SWUtils.getAttributeName(source);
//TAS.debug("attrib=" + attrib);
if (source.indexOf('repeating_weapon_') === 0) {
// source is an attack, so pull all data from the source (item/spell/spell-like ability) to update the attack
// attrib will be source-item, source-spell, or source-ability
TAS.error('PFInventory.updateAssociatedAttack, called on weapon event, no longer supported!');
done();
return;
}
// source is an item, so update all linked attacks with the changed attribute
weaponAttrib = attrib.replace('item-', '');
if (attrib === 'name') {
weaponAttrib = 'source-item-name';
} else if (attrib === 'item-dmg-type') {
weaponAttrib = 'type';
} else if (attrib === 'wpenhance') {
weaponAttrib = 'enhance';
}
} catch (outererror1) {
TAS.error('PFInventory.updateAssociatedAttack outer1', outererror1);
done();
return;
}
getAttrs([source], function (srcv) {
var sourceAttr = '';
sourceVal = srcv[source];
if (typeof sourceVal === 'undefined') {
sourceVal = '';
}
//TAS.debug"sourceVal=" + sourceVal);
if (attrib === 'proficiency') {
sourceVal = parseInt(sourceVal, 10) || 0;
if (sourceVal !== 0) {
sourceVal = -4;
}
}
sourceVal = String(sourceVal);
//TAS.debug("itemId=" + itemId, "attrib=" + attrib, "weaponAttrib=" + weaponAttrib);
getSectionIDs('repeating_weapon', function (idarray) {
// get the repeating set
fields = _.reduce(
idarray,
function (memo, currentID) {
memo = memo.concat(['repeating_weapon_' + currentID + '_source-item', 'repeating_weapon_' + currentID + '_' + weaponAttrib]);
return memo;
},
[],
);
//TAS.debug("processing currentID=" + currentID);
getAttrs(fields, function (w) {
setter = {}; // start with a blank in this loop
try {
//TAS.debug"PFInventory.updateAssociatedAttack ", w);
_.each(idarray, function (currentID) {
// loop through the set
var targetVal = '',
wField = ''; // start with blank in this loop
//TAS.debug("source=" + source, "v[repeating_weapon_" + currentID + "_source-item]=" + v["repeating_weapon_" + currentID + "_source-item"]);
//TAS.debug("itemId=" + itemId)
//TAS.debug"comparing " + itemId + " with " + w["repeating_weapon_" + currentID + "_source-item"]);
if (itemId === w['repeating_weapon_' + currentID + '_source-item']) {
wField = 'repeating_weapon_' + currentID + '_' + weaponAttrib;
targetVal = w[wField];
if (attrib === 'proficiency') {
targetVal = parseInt(targetVal, 10) || 0;
}
targetVal = String(targetVal);
if (targetVal !== sourceVal) {
setter[wField] = sourceVal;
if (sourceAttr === 'damage-die' || sourceAttr === 'damage-dice-num') {
setter['repeating_weapon_' + currentID + '_default_' + sourceAttr] = sourceVal;
}
}
}
});
} catch (innererror) {
TAS.error('PFInventory.updateAssociatedAttack inner1', innererror);
} finally {
if (_.size(setter) > 0) {
//TAS.debug"updating attack", setter);
SWUtils.setWrapper(setter);
}
}
});
});
});
}
/** Determines the equipment type from looking at the name.
* DOES NOT WORK for armor or weapons, this is for after you have already determined it is not an armor or weapon type.
*@param {string} name the name field
*/
export function getEquipmentTypeFromName(name) {
var tempstr,
currType = equipMap.noEquipType,
matches;
if (!name) {
return currType;
}
tempstr = name.toLowerCase();
matches = tempstr.match(
/(?:\bwand\b|\bring\b|\brod\b|plate|sword|shield|mail|spear|potion|spellbook|smokestick|incense|scroll|alchemist|antitoxin|antidote|elixir|staff|acid|\boil\b|water|component pouch|arrow|bolt|bullet|sunrod|flask|ration|armor spike|kit|saddle|tool|spike|pole|ladder|lantern|candle|torch|rope|chain|crowbar|\bnet\b|\bram\b|tanglefoot|tinder|flint|vial)/i,
);
if (matches) {
switch (matches[0]) {
case 'sword':
case 'spear':
case 'armor spike':
case 'net':
currType = equipMap.Weapon;
break;
case 'mail':
case 'plate':
case 'shield':
currType = equipMap.Armor;
break;
case 'vial':
case 'flint':
case 'kit':
case 'tool':
case 'spike':
case 'crowbar':
case 'ram':
case 'lantern':
case 'candle':
case 'torch':
case 'rope':
case 'chain':
case 'saddle':
case 'spyglass':
case 'spellbook':
case 'tinder':
case 'component pouch':
currType = equipMap.Gear;
break;
case 'ring':
currType = equipMap.OtherMagic;
break;
case 'rod':
case 'wand':
case 'staff':
currType = equipMap.Charged;
break;
case 'tanglefoot':
case 'incense':
case 'smokestick':
case 'sunrod':
case 'ration':
case 'water':
case 'alchemist':
case 'oil':
case 'flask':
case 'acid':
case 'potion':
case 'elixir':
case 'scroll':
case 'antitoxin':
case 'antidote':
currType = equipMap.Consumables;
break;
case 'arrow':
case 'bolt':
case 'bullet':
case 'stone':
currType = equipMap.Ammo;
break;
}
}
return currType;
}
export function importFromCompendium(eventInfo) {
var id = SWUtils.getRowId(eventInfo.sourceAttribute),
prefix = 'repeating_item_' + id + '_',
itemprefix = prefix + 'item-',
fields = [
'default_char_size',
'equipment_tab',
itemprefix + 'category_compendium',
itemprefix + 'value_compendium',
itemprefix + 'range_compendium',
itemprefix + 'criticaldamage_compendium',
itemprefix + 'criticalrange_compendium',
itemprefix + 'smalldamage_compendium',
itemprefix + 'meddamage_compendium',
itemprefix + 'damagetype_compendium',
itemprefix + 'speed20_compendium',
itemprefix + 'speed30_compendium',
itemprefix + 'weight_compendium',
itemprefix + 'spell-fail_compendium',
itemprefix + 'acbonus_compendium',
itemprefix + 'acp_compendium',
itemprefix + 'dmg-type',
prefix + 'description',
itemprefix + 'max-dex',
prefix + 'name',
];
//TAS.debug('at importFromCompendium getting fields', fields);
getAttrs(fields, function (v) {
var setter = {},
size = 0,
tempInt = 0,
temp,
name,
matches,
attr = '',
tempstr = '',
isWeapon = 0,
isArmor = 0,
isOther = 0,
currTab = 99,
currType = equipMap.noEquipType,
speed30 = 0,
speed20 = 0;
try {
//TAS.debug("importFromCompendium values are",v);
if (v[itemprefix + 'category_compendium'] !== 'Items') {
TAS.warn('compendium item is ' + v['repeating_item_item-category_compendium'] + ', INVALID');
return;
}
setter[prefix + 'row_id'] = id;
name = v[prefix + 'name'];
PFUtils.getCompendiumIntSet(itemprefix, 'range', v, setter);
TAS.debug('Before calling get value', setter);
PFUtils.getCompendiumFunctionSet(prefix, 'item-value', PFUtils.getCostInGP, v, setter, 'value');
TAS.debug('After calling get value', setter);
PFUtils.getCompendiumIntSet(itemprefix, 'spell-fail', v, setter);
PFUtils.getCompendiumIntSet(itemprefix, 'acbonus', v, setter);
PFUtils.getCompendiumIntSet(itemprefix, 'acp', v, setter);
if (v[itemprefix + 'acbonus_compendium']) {
isArmor = 1;
}
speed20 = parseInt(v[itemprefix + 'speed20_compendium'], 10) || 0;
speed30 = parseInt(v[itemprefix + 'speed30_compendium'], 10) || 0;
if (v[itemprefix + 'max-dex']) {
temp = v[itemprefix + 'max-dex'];
temp = temp.replace(/\u2013|\u2014|-|\\u2013|\\u2014/, '-');
if (temp !== v[itemprefix + 'max-dex']) {
setter[itemprefix + 'max-dex'] = temp;
}
}
if (v[itemprefix + 'damagetype_compendium']) {
temp = v[itemprefix + 'damagetype_compendium'];
temp = temp.replace(/\u2013|\u2014|-|\\u2013|\\u2014/, '');
if (temp) {
if (v[itemprefix + 'dmg-type']) {
temp = v[itemprefix + 'dmg-type'] + ' ' + v[itemprefix + 'damagetype_compendium'];
} else {
temp = v[itemprefix + 'damagetype_compendium'];
}
setter[itemprefix + 'dmg-type'] = temp;
}
}
if (v[itemprefix + 'criticaldamage_compendium']) {
isWeapon = 1;
temp = PFUtils.getCritFromString(v[itemprefix + 'criticaldamage_compendium']);
if (temp) {
if (temp.critmult !== 2) {
setter[itemprefix + 'crit-multiplier'] = temp.critmult;
}
}
}
if (v[itemprefix + 'criticalrange_compendium']) {
isWeapon = 1;
temp = PFUtils.getCritFromString(v[itemprefix + 'criticalrange_compendium']);
if (temp) {
if (temp.crit !== 20) {
setter[itemprefix + 'crit-target'] = temp.crit;
}
}
}
size = parseInt(v['default_char_size'], 10) || 0;
tempstr = 'meddamage_compendium';
tempInt = 0;
if (size >= 1) {
tempInt = 1;
tempstr = 'smalldamage_compendium';
}
if (size !== 0) {
//set default size of item to small or medium, not other, let user do that for now
setter[prefix + 'default_size'] = tempInt;
}
PFUtils.getCompendiumIntSet(itemprefix, 'weight', v, setter);
//small size, weight is 1/2
if (size >= 1) {
tempInt = parseInt(setter[itemprefix + 'weight'], 10) || 0;
if (tempInt) {
tempInt = Math.floor((tempInt / 2) * 100) / 100;
setter[itemprefix + 'weight'] = tempInt;
}
}
if (v[itemprefix + tempstr]) {
isWeapon = 1;
temp = PFUtils.getDiceDieFromString(v[itemprefix + tempstr]);
if (temp) {
if (temp.dice && temp.die) {
setter[itemprefix + 'damage-dice-num'] = temp.dice;
setter[itemprefix + 'damage-die'] = temp.die;
}
if (temp.plus) {
setter[itemprefix + 'damage'] = temp.plus;
}
}
}
if (isWeapon) {
currType = equipMap.Weapon;
if (v[itemprefix + 'range_compendium'] && parseInt(v[itemprefix + 'range_compendium'], 10) > 0) {
setter[itemprefix + 'attack-type'] = 'attk-ranged';
} else {
setter[itemprefix + 'attack-type'] = 'attk-melee';
}
} else if (isArmor) {
currType = equipMap.Armor;
//set encumbrance
//mUST LOOK AT name string and determine armor, then set heavy, medium, or light.
//for shields it is easy
//we can probably look at the change in speed to determine this.
if (name) {
if (/tower/i.test(name)) {
tempstr = 'Tower Shield';
} else if (speed30 === 30 && speed20 === 20) {
tempstr = 'Light';
} else if (/heavy|stone|full|half.plate|splint|banded|iron|tatami|kusari/i.test(name)) {
tempstr = 'Heavy';
} else if (/medium|mountain|chainmail|breastplate|scale|kikko|steel|horn|mirror|hide|maru|armored coat/i.test(name)) {
tempstr = 'Medium';
} else {
tempstr = 'Light';
}
setter[itemprefix + 'defense-type'] = tempstr;
}
} else {
currType = getEquipmentTypeFromName(name);
}
if (currType < 0) {
currType = equipMap.Other;
} else if (currType === equipMap.Weapon) {
setter[prefix + 'weapon-attributes-show'] = 1;
} else if (currType === equipMap.Armor) {
setter[prefix + 'armor-attributes-show'] = 1;
}
//it just ignores it! why!? so don't change tab cause it won't be on the new tab.
if (currType) {
setter['equipment_tab'] = currType;
setter[prefix + 'equip-type'] = currType;
setter[prefix + 'equiptype-tab'] = currType;
}
setter[prefix + 'qty'] = 1;
setter[prefix + 'qty_max'] = 1;
//default to carried or not carried?
setter[prefix + 'location'] = locationMap.Carried;
setter[prefix + 'old_location'] = locationMap.Carried;
setter[prefix + 'loctype-tab'] = locationMap.Carried;
setter[itemprefix + 'category_compendium'] = '';
setter[itemprefix + 'value_compendium'] = '';
setter[itemprefix + 'range_compendium'] = '';
setter[itemprefix + 'criticaldamage_compendium'] = '';
setter[itemprefix + 'criticalranage_compendium'] = '';
setter[itemprefix + 'smalldamage_compendium'] = '';
setter[itemprefix + 'meddamage_compendium'] = '';
setter[itemprefix + 'damagetype_compendium'] = '';
setter[itemprefix + 'speed20_compendium'] = '';
setter[itemprefix + 'speed30_compendium'] = '';
setter[itemprefix + 'weight_compendium'] = '';
setter[itemprefix + 'spell-fail_compendium'] = '';
setter[itemprefix + 'acbonus_compendium'] = '';
setter[itemprefix + 'acp_compendium'] = '';
} catch (err) {
TAS.error('importFromCompendium', err);
} finally {
//TAS.debug"importFromCompendium setting",setter);
if (_.size(setter) > 0) {
SWUtils.setWrapper(setter, PFConst.silentParams, updateRepeatingItems);
}
}
});
}
function updateUses(callback) {
var done = _.once(function () {
//TAS.debug("leaving PFInventory.updateUses");
if (typeof callback === 'function') {
callback();
}
});
//TAS.debug("at PFInventory.updateUses");
getSectionIDs('repeating_item', function (ids) {
var fields = [];
if (!ids || !_.size(ids)) {
done();
return;
}
fields = _.reduce(
ids,
function (m, id) {
m.push('repeating_item_' + id + '_has_uses');
m.push('repeating_item_' + id + '_qty_max');
return m;
},
[],
);
//_.flatten(fields);
getAttrs(fields, function (v) {
var setter = {};
try {
setter = _.reduce(
ids,
function (m, id) {
var prefix = 'repeating_item_' + id + '_',
maxQty = 0;
try {
maxQty = parseInt(v[prefix + 'qty_max'], 10) || 0;
if (maxQty > 1) {
m[prefix + 'has_uses'] = 'true';
} else {
m[prefix + 'has_uses'] = '';
}
} catch (errin) {
TAS.error('PFInventory.updateUses error repeating_item id ' + id, errin);
} finally {
return m;
}
},
{},
);
} catch (err) {
TAS.error('PFInventory.updateUses error setting defaults ', err);
} finally {
if (_.size(setter) > 0) {
SWUtils.setWrapper(setter, PFConst.silentParams, done);
} else {
done();
}
}
});
});
}
/**
* @param {function} callback
*/
function unsetOrphanedWornSlots(callback) {
var done = _.once(function () {
//TAS.debug("leaving PFInventory.deleteOrphanWornRows");
if (typeof callback === 'function') {
callback();
}
});
getSectionIDs('repeating_item', function (ids) {
if (!(ids && _.size(ids) > 0)) {
done();
return;
}
getAttrs(wornSlotsRolls, function (v) {
var notFoundList = [],
lowerIDs = [],
setter = {};
try {
lowerIDs = _.map(ids, function (id) {
return id.toLowerCase();
});
notFoundList = _.chain(v)
.omit(function (val, key) {
if (!val) {
return true;
}
return false;
})
.mapObject(function (val) {
return SWUtils.getRowId(val).toLowerCase();
})
.omit(function (val, key) {
return _.contains(lowerIDs, val);
})
.value();
if (_.size(notFoundList) > 0) {
setter = _.reduce(
notFoundList,
function (m, val, key) {
var nameAttr = key.slice(-5);
m[nameAttr] = '';
m[key] = '';
return m;
},
{},
);
SWUtils.setWrapper(setter, PFConst.params, done);
} else {
done();
}
} catch (err) {
TAS.error('PFInventory.deleteOrphanWornRows', err);
done();
}
});
});
}
function deleteWornRow(source, location, type, name, callback) {
const searchSource = source.toLowerCase();
getAttrs(['armor3', 'shield3', ...wornSlotsRolls], function (v) {
var match = '',
row = '',
attrib = '',
armorName = v.armor3 || '',
shieldName = v.shield3 || '',
setter = {};
try {
match = _.findKey(v, function (val) {
if (!val) {
return false;
}
if (val.toLowerCase().indexOf(searchSource) >= 0) {
// worn item
return true;
}
return false;
});
if (match) {
// Case 1: Slotted item found (worn slot, or as armor3/shield3 roll)
row = match.slice(0, -5);
setter[match] = '';
setter[row] = ''; // Clears the row ID or item name
// If the matched slot was for Armor or Shield, clear Defenses
if (location === 2) {
attrib = 'armor3';
} else if (location === 14) {
attrib = 'shield3';
}
} else {
// Case 2: NO slotted item found, check Defenses for match vs non-slotted equipment
if (type === 2 && name === armorName) {
attrib = 'armor3';
} else if (type === 2 && name === shieldName) {
attrib = 'shield3';
}
}
// Clear Defenses
if (attrib) {
setter[attrib] = '';
setter[attrib + '-equipped'] = 1;
setter[attrib + '-acbonus'] = 0;
setter[attrib + '-enhance'] = 0;
setter[attrib + '-max-dex'] = '-';
setter[attrib + '-acp'] = 0;
setter[attrib + '-spell-fail'] = 0;
setter[attrib + '-type'] = '';
setter[attrib + '-proficiency'] = 1;
}
// Only call setWrapper if the setter object has attributes to update.
if (_.size(setter) > 0) {
SWUtils.setWrapper(setter, PFConst.silent, callback);
} else if (typeof callback === 'function') {
// If no attributes were changed, call the callback immediately.
callback();
}
} catch (err) {
TAS.error('PFInventory.event delete item for attribute: ' + source, err);
if (typeof callback === 'function') {
// Call callback even on error to prevent execution from hanging
callback();
}
}
});
}
export function setNewDefaults(callback, oldversion) {
var done = _.once(function () {
//TAS.debug("leaving PFInventory.setNewDefaults");
if (typeof callback === 'function') {
callback();
}
});
//TAS.debug("at PFInventory.setNewDefaults");
getAttrs(['migrated_itemlist_defaults'], function (vout) {
try {
//TAS.debug("PFInventory.setNewDefaults ",v);
if (parseInt(vout.migrated_itemlist_defaults, 10) === 1) {
done();
return;
}
getSectionIDs('repeating_item', function (ids) {
var fields = [];
try {
if (!ids || !_.size(ids)) {
done();
return;
}
fields = _.map(ids, function (id) {
return ['repeating_item_' + id + '_name', 'repeating_item_' + id + '_location', 'repeating_item_' + id + '_qty_max', 'repeating_item_' + id + '_equip-type'];
});
fields = _.flatten(fields);
} catch (miderror) {
TAS.error('PFInventory.setNewDefaults miderror', miderror);
done();
return;
}
//TAS.debug("PFInventory.setNewDefaults fields:",fields);
getAttrs(fields, function (v) {
var setter = {},
currEquip = 0;
try {
//TAS.debug("PFInventory.setNewDefaults fields ",v);
setter = _.reduce(
ids,
function (m, id) {
var prefix = 'repeating_item_' + id + '_',
maxQty = 0,
nameField = prefix + 'name',
currLoc = 0,
guess = 0;
try {
currLoc = parseInt(v[prefix + 'location'], 10);
if (isNaN(currLoc)) {
//default is carried
currLoc = locationMap.Carried;
m[prefix + 'location'] = currLoc;
}
m[prefix + 'oldlocation'] = currLoc;
if (currLoc === locationMap.NotCarried) {
m[prefix + 'loctype-tab'] = locationMap.NotCarried;
} else if (currLoc === locationMap.Carried) {
m[prefix + 'loctype-tab'] = locationMap.Carried;
} else if (currLoc > locationMap.NotCarried) {
m[prefix + 'loctype-tab'] = locationMap.equipped;
} else {
m[prefix + 'loctype-tab'] = -1;
}
maxQty = parseInt(v[prefix + 'qty_max'], 10);
if (isNaN(maxQty)) {
maxQty = 0;
m[prefix + '_qty_max'] = maxQty;
}
if (maxQty > 1) {
m[prefix + 'has_uses'] = 'true';
} else {
m[prefix + 'has_uses'] = '';
}
currEquip = parseInt(v['repeating_item_' + id + '_equip-type'], 10);
if (!currEquip) {
if (v[nameField]) {
guess = getEquipmentTypeFromName(v[nameField]);
}
if (guess) {
m[prefix + 'equip-type'] = guess;
m[prefix + 'equiptype-tab'] = guess;
} else {
m[prefix + 'equip-type'] = equipMap.noEquipType;
m[prefix + 'equiptype-tab'] = equipMap.noEquipType;
}
} else {
m[prefix + 'equiptype-tab'] = currEquip;
}
m[prefix + 'showinmenu'] = 0;
} catch (errin) {
TAS.error('PFInventory.setNewDefaults error repeating_item id ' + id, errin);
} finally {
return m;
}
},
{},
);
} catch (err) {
TAS.error('PFInventory.setNewDefaults error setting defaults ', err);
} finally {
if (_.size(setter) > 0) {
setter['migrated_itemlist_defaults'] = 1;
//TAS.debug("PFInventory.setNewDefaults setting",setter);
SWUtils.setWrapper(setter, PFConst.silentParams, done);
} else {
done();
}
}
});
});
} catch (outererr) {
TAS.error('PFInventory.setNewDefaults outererr', outererr);
done();
}
});
}
export function migrate(callback, oldversion) {
var done = _.once(function () {
//TAS.debug("leaving PFInventory.migrate");
if (typeof callback === 'function') {
callback();
}
});
//TAS.debug("At PFInventory.migrate");
PFMigrate.migrateRepeatingItemAttributes(
TAS.callback(function callPFInventorySetNewDefaults() {
setNewDefaults(
TAS.callback(function callPFInventoryMigrateWornEquipment() {
migrateWornEquipment(done);
}),
);
}),
);
}
export var recalculate = TAS.callback(function PFInventoryRecalculate(callback, silently, oldversion) {
var done = _.once(function () {
TAS.info('leaving PFInventory.recalculate');
if (typeof callback === 'function') {
callback();
}
}),
setTotals = _.after(2, function () {
TAS.debug('PFInventory.recalculate at setTotals');
updateLocations(updateUses);
resetCommandMacro();
unsetOrphanedWornSlots();
updateCarriedTotal(done);
});
try {
TAS.debug('at PFInventory.recalculate');
migrate(function () {
updateCarriedCurrency(setTotals, silently);
updateRepeatingItems(setTotals, silently);
});
} catch (err) {
TAS.error('PFInventory.recalculate', err);
done();
}
});
function registerEventHandlers() {
var tempstr = '';
on(
'change:repeating_item:item-category_compendium',
TAS.callback(function EventItemCompendium(eventInfo) {
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
importFromCompendium(eventInfo);
}
}),
);
on(
'change:repeating_item:location',
TAS.callback(function eventUpdateItemLocation(eventInfo) {
// TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
getAttrs(['repeating_item_location', 'repeating_item_old_location'], function (v) {
var newLoc = parseInt(v.repeating_item_location, 10),
oldLoc = parseInt(v.repeating_item_old_location, 10);
if (newLoc === locationMap.Armor || newLoc === locationMap.Shield) {
updateWornArmorAndShield(newLoc, eventInfo.sourceAttribute, function () {
updateEquipmentLocation(null, null, null, eventInfo);
});
} else {
updateEquipmentLocation(null, null, null, eventInfo);
}
if (newLoc !== locationMap.NotCarried || (oldLoc !== locationMap.NotCarried && oldLoc !== newLoc)) {
updateRepeatingItems(null, false, {weight: 1});
}
});
}
}),
);
on(
'change:repeating_item:qty_max',
TAS.callback(function eventUpdateItemMaxQty(eventInfo) {
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
updateRepeatingItems();
getAttrs(['repeating_item_qty_max'], function (v) {
if (parseInt(v['repeating_item_qty_max'], 10) > 1) {
SWUtils.setWrapper({repeating_item_has_uses: 'true'}, PFConst.silentParams);
} else {
SWUtils.setWrapper({repeating_item_has_uses: ''}, PFConst.silentParams);
}
});
}
}),
);
on(
'change:repeating_item:qty',
TAS.callback(function eventUpdateItemTotalQty(eventInfo) {
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
getAttrs(['repeating_item_qty_max'], function (v) {
var qtymax = parseInt(v.repeating_item_qty_max, 10) || 0;
if (qtymax === 0 || qtymax === 1) {
updateRepeatingItems();
}
});
}
}),
);
//hp total removed
//on('change:repeating_item:item-hp change:repeating_item:item-hp_max', TAS.callback(function eventUpdateItemTotalHp(eventInfo) {
// TAS.debug("caught " + eventInfo.sourceAttribute + " event: " + eventInfo.sourceType);
// if (eventInfo.sourceType === "player" || eventInfo.sourceType === "api") {
// updateRepeatingItems(null,true,{'hp':1});
// }
//}));
on(
'change:repeating_item:value',
TAS.callback(function eventUpdateItemTotalValue(eventInfo) {
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
updateRepeatingItems(null, true, {value: 1});
}
}),
);
on(
'change:repeating_item:item-weight',
TAS.callback(function eventUpdateItemTotalWeight(eventInfo) {
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
getAttrs(['repeating_item_location'], function (v) {
if (parseInt(v.repeating_item_location, 10) !== locationMap.NotCarried) {
updateRepeatingItems(null, false, {weight: 1});
}
});
}
}),
);
on(
'remove:repeating_item',
TAS.callback(function eventRemoveItem(eventInfo) {
var source = '',
setter = {},
itemId = '',
location = 0,
type = 0,
name = '';
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
// Find the correct key ie exclude 'old_location'
const locationAttr = Object.keys(eventInfo.removedInfo).find((key) => key.endsWith('_location') && key.length > '_old_location'.length);
const typeAttr = Object.keys(eventInfo.removedInfo).find((key) => key.endsWith('_equip-type'));
const nameAttr = Object.keys(eventInfo.removedInfo).find((key) => key.endsWith('_name'));
location = locationAttr ? +eventInfo.removedInfo[locationAttr] : null;
type = typeAttr ? +eventInfo.removedInfo[typeAttr] : null;
name = nameAttr ? eventInfo.removedInfo[nameAttr] : '';
// type and name can be sent to deleteWornRow to check if the deleted row was
// armor or shield that was not worn and also clear it from Defenses
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
console.log(`Change detected: Removed Row location:${location} type:${type} name:${name}`);
updateRepeatingItems();
deleteWornRow(eventInfo.sourceAttribute, location, type, name);
}
PFAttacks.removeLinkedAttack(null, PFAttacks.linkedAttackType.equipment, SWUtils.getRowId(eventInfo.sourceAttribute));
}),
);
on(
'change:CP change:SP change:GP change:PP',
TAS.callback(function eventUpdateCarriedCurrency(eventInfo) {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
updateCarriedCurrency();
}),
);
on(
'change:carried-currency change:carried-currency-toggle change:item_total_weight change:carried-misc',
TAS.callback(function eventUpdateCarriedTotal(eventInfo) {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
updateCarriedTotal();
}),
);
//changing the metric option triggers weight recalc
on(
'change:use_metrics',
TAS.callback(function eventUpdateCarriedTotal(eventInfo) {
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
updateCarriedTotal();
updateCarriedCurrency();
updateRepeatingItems();
}
}),
);
//change item worn in shield or armor location
on(
'change:repeating_item:item-defense-type change:repeating_item:item-acbonus change:repeating_item:item-max-dex change:repeating_item:item-acp change:repeating_item:item-spell-fail change:repeating_item:item-proficiency change:repeating_item:acenhance',
TAS.callback(function eventUpdateEquippedArmorOrShield(eventInfo) {
var location = 0;
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event' + eventInfo.sourceType);
getAttrs(['repeating_item_location'], function (v) {
var location = parseInt(v['repeating_item_location'], 10) || 0;
if (location === locationMap.Armor || location === locationMap.Shield) {
updateWornArmorAndShield(location, eventInfo.sourceAttribute);
}
});
}),
);
_.each(commonLinkedAttributes, function (fieldToWatch) {
var eventToWatch = 'change:repeating_item:item-' + fieldToWatch;
on(
eventToWatch,
TAS.callback(function eventupdateAssociatedAttackLoop(eventInfo) {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event' + eventInfo.sourceType);
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
updateAssociatedAttack(eventInfo.sourceAttribute);
}
}),
);
});
on(
'change:repeating_item:name change:repeating_item:item-dmg-type change:repeating_item:item-proficiency change:repeating_item:default_size change:repeating_item:wpenhance',
TAS.callback(function eventupdateAssociatedAttack(eventInfo) {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event' + eventInfo.sourceType);
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
updateAssociatedAttack(eventInfo.sourceAttribute);
}
}),
);
on(
'change:repeating_item:create-attack-entry',
TAS.callback(function eventcreateAttackEntryFromRow(eventInfo) {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
createAttackEntryFromRow(null, null, false, eventInfo);
}
}),
);
on(
'change:repeating_item:set-as-armor',
TAS.callback(function eventcreateArmorEntryFromRow(eventInfo) {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
updateWornArmorAndShield(locationMap.Armor, eventInfo.sourceAttribute, function () {
updateEquipmentLocation(null, null, null, eventInfo);
});
}
}),
);
on(
'change:repeating_item:set-as-shield',
TAS.callback(function eventcreateShieldEntryFromRow(eventInfo) {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
updateWornArmorAndShield(locationMap.Shield, eventInfo.sourceAttribute, function () {
updateEquipmentLocation(null, null, null, eventInfo);
});
}
}),
);
on(
'change:repeating_item:showinmenu change:repeating_item:equip-type change:repeating_item:name',
TAS.callback(function eventShowItemInMenu(eventInfo) {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
resetCommandMacro();
}
}),
);
on(
'change:repeating_item:name',
TAS.callback(function eventUpdateWornItemName(eventInfo) {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
updateEquipmentLocation(null, null, null, eventInfo);
}
}),
);
on(
'change:repeating_item:equip-type',
TAS.callback(function eventItemEquipTypeChange(eventInfo) {
TAS.debug('caught ' + eventInfo.sourceAttribute + ' event: ' + eventInfo.sourceType);
if (eventInfo.sourceType === 'player' || eventInfo.sourceType === 'api') {
getAttrs(['repeating_item_equip-type', 'repeating_item_equiptype-tab', 'equipment_tab'], function (v) {
var newtype = parseInt(v['repeating_item_equip-type'], 10) || 0,
oldtype = parseInt(v['repeating_item_equiptype-tab'], 10),
equipTab = parseInt(v.equipment_tab, 10) || 0,
setter = {};
//TAS.debug("################","At change:repeating_item:equip-type updating equiptype:"+newtype+", currtab:"+oldtype,v);
if (newtype !== oldtype || isNaN(oldtype)) {
setter['repeating_item_equiptype-tab'] = newtype;
}
if (newtype > 0 && newtype !== equipTab) {
if (equipTab < 9) {
setter['equipment_tab'] = newtype;
}
}
if (_.size(setter)) {
SWUtils.setWrapper(setter, PFConst.silentParams);
}
});
}
}),
);
// toggles the chat menu Show option for all repeating items
on('change:showinmenu_all_items', function () {
getSectionIDs('repeating_item', function (idArray) {
const fieldNames = idArray.map((id) => `repeating_item_${id}_showinmenu`);
getAttrs(['showinmenu_all_items'], function (values) {
const toggle = +values['showinmenu_all_items'] || 0;
const settings = fieldNames.reduce((obj, item) => ((obj[item] = toggle), obj), {});
setAttrs(settings);
PFInventory.recalculate();
});
});
});
}
registerEventHandlers();
//PFConsole.log(' PFInventory module loaded ' );
//PFLog.modulecount++;