mirror of
https://github.com/Nighthawk42/roll20-character-sheets.git
synced 2026-08-30 03:40:32 +00:00
RolemasterUnified: Token makers and Inventory updates
- First version of token markers - Sheet options - Random colours - Trigger on status change. - Fix stacking of popups on main page - Add helper to get total number of bleeds - Add options for token makers - Add options for FX (doesn't do much) - Export to NPC now grabs spell lists. - Inventory (Stuff) - Fix Helmet perception penalty trashing other modifiers - Apply Armor DB - Removed Armor DB & Perception penalties when you remove items - Fix for armor losing it's encumberance. - Add support for "Sets" Armor without a helmet - Add armor material to edit window - Correctly support mixed material encumberances (metal != non-metal)
This commit is contained in:
@@ -3399,7 +3399,7 @@ Lists Selected <input type='number' name='comp_cmbaselistcount'> / 6
|
||||
<section id='stats' class='tab-panel'>
|
||||
<div class="sheet-3colrow">
|
||||
<div class="rmusheet-column">
|
||||
<div class='pcframebox'>
|
||||
<div class='pcframebox' style='z-index: 699'>
|
||||
<h2>Statistics</h2>
|
||||
<div id="stats_pane" class="stats_pane">
|
||||
<div class='stat'><span class='stat_names'><span style='position:relative'><span class="icon" style="font-family: 'Pictos Custom'; color: rgb(150,150,150);">y</span><span name='attr_agility_info' class='stat_info'></span>
|
||||
@@ -3442,13 +3442,13 @@ Lists Selected <input type='number' name='comp_cmbaselistcount'> / 6
|
||||
<span class='stat_attr' name='attr_will'></span>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- pcframebox -->
|
||||
</div> <!-- pcframebox zindex 699 -->
|
||||
|
||||
<div class='pcframebox'>
|
||||
<div class='pcframebox' style='z-index: 698'>
|
||||
<div class='prop_pair'><span class='prop_prop_plain'>Power Level</span><span class='prop_value' name='attr_powerlevel'></span><span class='prop_prop_plain'>Profession</span><span class='prop_value' name='attr_profession'></span><span class='prop_prop_plain'>Race</span><span class='prop_value' name='attr_race'></span><span class='prop_prop_plain'>Culture</span><span class='prop_value' name='attr_culture'></span><span class='prop_prop_plain'>Level</span><span class='prop_value' name='attr_display_level'></span><span class='prop_prop_plain'>EP</span><span class='prop_value'><input type='number' style='width:100%' name='attr_xp'></span><span class='prop_prop_plain'>Fate Points</span><span class='prop_value'><input type='number' style='width:100%' name='attr_fatepoints'></span><span class='prop_prop_plain'>Realm</span><span class='prop_value' name='attr_realm'></span><span class='prop_prop_plain'>Religion</span><span class='prop_value'><input type='text' style='width:100%' name='attr_religion'></span><span class='prop_prop_plain'>Age</span><span class='prop_value'><input type='text' style='width:100%' name='attr_age'></span><span class='prop_prop_plain'>Skin</span><span class='prop_value'><input type='text' style='width:100%' name='attr_skin'></span><span class='prop_prop_plain'>Eyes</span><span class='prop_value'><input type='text' style='width:100%' name='attr_eyes'></span><span class='prop_prop_plain'>Hair</span><span class='prop_value'><input type='text' style='width:100%' name='attr_hair'></span><span class='prop_prop_plain'>Gender</span><span class='prop_value'><input type='text' style='width:100%' name='attr_gender'></span><span class='prop_prop_plain'>Build</span><span class='prop_value'><input type='text' style='width:100%' name='attr_build'></span><span class='prop_prop_plain'>Height</span><span class='prop_value'><input type='text' style='width:100%' name='attr_height'></span><span class='prop_prop_plain'>Weight</span><span class='prop_value'><input type='text' style='width:100%' name='attr_weight'></span><span class='iconwrap'><span class='prop_prop_plain'><span class="icon" style="font-family: 'Pictos Custom'; color: rgb(150,150,150);">y</span><span class='skill_info' name='attr_weightallowance_info'></span>Weight allowance</span></span>
|
||||
<span class='prop_value' name='attr_weightallowance'></span><span class='prop_prop_plain'>Carried</span><span class='prop_value' name='attr_total_weight'></span><span class='prop_prop_plain'>Load (%)</span><span class='prop_value' name='attr_load'></span><span class='prop_prop_plain'>Max Pace</span><span class='prop_value' name='attr_maxpace'></span><span class='prop_prop_plain'>Enc Penalty</span><span class='prop_value' name='attr_encumberance_penalty'></span><span class='iconwrap'><span class='prop_prop_plain'><span class="icon" style="font-family: 'Pictos Custom'; color: rgb(150,150,150);">y</span><span class='skill_info' name='attr_bmr_info'></span>Base Move (BMR)</span></span>
|
||||
<span class='prop_value' name='attr_bmr'></span><span class='prop_prop_plain'>Size</span><span class='prop_value' name='attr_size'></span><span class='prop_prop_plain'>Recovery Multiplier</span><span class='prop_value' name='attr_recovery_multiplier'></span><span class='prop_pair_heading'>Feats of Strength</span><span class='prop_prop_plain'>Routine</span><span class='prop_value' name='attr_strfeat_routine'></span><span class='prop_prop_plain'>Easy</span><span class='prop_value' name='attr_strfeat_easy'></span><span class='prop_prop_plain'>Light</span><span class='prop_value' name='attr_strfeat_light'></span><span class='prop_prop_plain'>Medium</span><span class='prop_value' name='attr_strfeat_medium'></span><span class='prop_prop_plain'>Hard</span><span class='prop_value' name='attr_strfeat_hard'></span><span class='prop_prop_plain'>Very Hard</span><span class='prop_value' name='attr_strfeat_veryhard'></span><span class='prop_prop_plain'>Ext. Hard</span><span class='prop_value' name='attr_strfeat_exthard'></span><span class='prop_prop_plain'>Sheer Folly</span><span class='prop_value' name='attr_strfeat_sheerfolly'></span><span class='prop_prop_plain'>Absurd</span><span class='prop_value' name='attr_strfeat_absurd'></span><span class='prop_prop_plain'>Nigh Impossible</span><span class='prop_value' name='attr_strfeat_nighimpossible'></span>
|
||||
</div> <!-- pcframebox -->
|
||||
</div> <!-- pcframebox zindex 698 -->
|
||||
|
||||
</div>
|
||||
|
||||
@@ -3457,7 +3457,7 @@ Lists Selected <input type='number' name='comp_cmbaselistcount'> / 6
|
||||
|
||||
<div class="rmusheet-column">
|
||||
|
||||
<div class='pcframebox'>
|
||||
<div class='pcframebox' style='z-index: 697'>
|
||||
<h2>Actions</h2>
|
||||
|
||||
|
||||
@@ -3565,9 +3565,9 @@ Lists Selected <input type='number' name='comp_cmbaselistcount'> / 6
|
||||
|
||||
|
||||
|
||||
</div> <!-- status frame box -->
|
||||
</div> <!-- pcframebox zindex 697 -->
|
||||
|
||||
<div class='pcframebox'>
|
||||
<div class='pcframebox' style='z-index: 696'>
|
||||
<h2>Status</h2>
|
||||
|
||||
|
||||
@@ -3741,9 +3741,9 @@ Lists Selected <input type='number' name='comp_cmbaselistcount'> / 6
|
||||
<button type='action' name='act_statussleep'
|
||||
class='rollbutton fancybutton fancybuttoninline'>Sleep</button>
|
||||
|
||||
</div> <!-- status frame box -->
|
||||
|
||||
<div class='pcframebox'>
|
||||
</div> <!-- pcframebox zindex 696 -->
|
||||
|
||||
<div class='pcframebox' style='z-index: 695'>
|
||||
|
||||
<h2>Attacks</h2>
|
||||
|
||||
@@ -3880,12 +3880,12 @@ Lists Selected <input type='number' name='comp_cmbaselistcount'> / 6
|
||||
|
||||
|
||||
<hr>
|
||||
</div> <!-- pcframebox -->
|
||||
</div> <!-- pcframebox zindex 695 -->
|
||||
|
||||
</div> <!-- rmusheet-column -->
|
||||
|
||||
<div class='rmusheet-column'>
|
||||
<div class='pcframebox'>
|
||||
<div class='pcframebox' style='z-index: 694'>
|
||||
|
||||
<h2>Defense</h2>
|
||||
|
||||
@@ -3966,9 +3966,10 @@ Lists Selected <input type='number' name='comp_cmbaselistcount'> / 6
|
||||
<span name='attr_db_fullblock_info' class='stat_info'></span>
|
||||
Full Block (4 AP)</span>
|
||||
<span class='prop_value' name='attr_db_fullblock'></span>
|
||||
</div> <!-- pcframebox -->
|
||||
</div>
|
||||
<div class='pcframebox'>
|
||||
</div>
|
||||
</div> <!-- pcframebox zindex 694 -->
|
||||
|
||||
<div class='pcframebox' style='z-index: 693'>
|
||||
|
||||
<h2>RRs</h2>
|
||||
|
||||
@@ -4010,11 +4011,11 @@ Lists Selected <input type='number' name='comp_cmbaselistcount'> / 6
|
||||
|
||||
|
||||
|
||||
</div> <!-- pcframebox -->
|
||||
</div> <!-- pcframebox zindex 693 -->
|
||||
|
||||
|
||||
|
||||
<div class='pcframebox'>
|
||||
<div class='pcframebox' style='z-index: 692'>
|
||||
<h2>Favorite Skills</h2>
|
||||
|
||||
<div class='favorite_group'>
|
||||
@@ -4036,8 +4037,11 @@ Lists Selected <input type='number' name='comp_cmbaselistcount'> / 6
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class='pcframebox'>
|
||||
</div> <!-- pcframebox zindex 692 -->
|
||||
|
||||
<div class='pcframebox' style='z-index: 691'>
|
||||
|
||||
|
||||
<h2>Talents</h2>
|
||||
|
||||
<input type='hidden' name='attr_edit_talent_toggle' class='edit_control_toggle'>
|
||||
@@ -4053,7 +4057,7 @@ Lists Selected <input type='number' name='comp_cmbaselistcount'> / 6
|
||||
</fieldset>
|
||||
|
||||
<button type='action' class='fancybutton' name='act_talentaddstart'>Add Talent</button>
|
||||
</div> <!-- pcframebox -->
|
||||
</div> <!-- pcframebox zindex 691 -->
|
||||
|
||||
</div> <!-- rmusheet-column -->
|
||||
|
||||
@@ -6234,13 +6238,14 @@ Uses (Lvl/Total) <span name='attr_traps_usecount'></span> / <span name='attr_tra
|
||||
<span class='inventoryarmortoggle'><b>Armor Location</b></span>
|
||||
<select name='attr_inventoryaddarmorsubtype' class='inventoryarmortoggle fancyselect'>
|
||||
<option value='Full'>Full</option>
|
||||
<option value='Set'>Set (All but Helmet)</option>
|
||||
<option value='Vambraces'>Vambraces</option>
|
||||
<option value='Greaves'>Greaves</option>
|
||||
<option value='Torso'>Torso</option>
|
||||
<option value='Helmet'>Helmet</option>
|
||||
</select>
|
||||
<span class='inventoryarmortoggle'><b>Armor Type (AT)</b></span>
|
||||
<select name='attr_inventoryaddarmorat' class='inventoryarmortoggle fancyselect:'>
|
||||
<select name='attr_inventoryaddarmorat' class='inventoryarmortoggle fancyselect'>
|
||||
<option value='1'>1</option>
|
||||
<option value='2'>2</option>
|
||||
<option value='3'>3</option>
|
||||
@@ -6254,6 +6259,13 @@ Uses (Lvl/Total) <span name='attr_traps_usecount'></span> / <span name='attr_tra
|
||||
</select>
|
||||
<span class='inventoryarmortoggle'><b>DB Bonus</b></span>
|
||||
<input type='number' name='attr_inventoryaddarmordbbonus' class='inventoryarmortoggle'>
|
||||
<span class='inventoryarmortoggle'><b>Material</b></span>
|
||||
<select name='attr_inventoryaddarmormaterial' class='inventoryarmortoggle fancyselect'>
|
||||
<option value='cloth'>Cloth</option>
|
||||
<option value='leather'>Leather</option>
|
||||
<option value='metal'>Metal</option>
|
||||
</select>
|
||||
|
||||
|
||||
|
||||
<span class='inventoryshieldtoggle'><b>Number of Attacks</b></span>
|
||||
@@ -6529,6 +6541,11 @@ This is not for usual use. </p>
|
||||
<button type="action" style="-toby-display:none;" name="act_initiative-action">initiative</button>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<input type='text' name='attr_chatcommand'>
|
||||
<button type='action' name='act_sendtochat'>Send to Chat</button>
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
@@ -6542,7 +6559,7 @@ Sheet Version: <span name='attr_version'></span>
|
||||
|
||||
<br>
|
||||
|
||||
Revision 52f9842a63e00550f91634a07b2ecb1db3a83f16
|
||||
Revision d1fa0cd182ccb30369359a6669cdec2e5abfc14d
|
||||
|
||||
|
||||
<hr>
|
||||
@@ -7663,6 +7680,16 @@ function miscBonusRemove(miscstr, name) {
|
||||
return JSON.stringify(misc);
|
||||
}
|
||||
|
||||
// Any item that matches the filter will be remmoebed
|
||||
function miscBonusRemoveFilter(miscstr, fn) {
|
||||
if (typeof(miscstr) != 'string' || miscstr == '') {
|
||||
return '';
|
||||
}
|
||||
let misc = JSON.parse(miscstr);
|
||||
misc = misc.filter(fn);
|
||||
return JSON.stringify(misc);
|
||||
}
|
||||
|
||||
function miscBonusTotal(miscstr, prefix = '') {
|
||||
if (typeof(miscstr) != 'string' || miscstr == '') {
|
||||
return [0, ""];
|
||||
@@ -9713,18 +9740,21 @@ function getSubtlePenalty(realm, type, trickery, subtle, voice, hands, enc, meta
|
||||
|
||||
// Armor and Transcendance
|
||||
console.log("Enc and metalenc", enc, metalenc, pentable, pentable.armorenc != pentable.metalenc);
|
||||
if (enc || metalenc) {
|
||||
if ((enc || metalenc) && (pentable.armorenc || pentable.metalenc)) {
|
||||
// Enc is all encumberance from armor, Metalenc is jsut hte metal bit.
|
||||
RMUSkills.uses("transcendence");
|
||||
let epen = 0;
|
||||
if (enc > 0 && pentable.armorenc) {
|
||||
epen += enc * pentable.armorenc;
|
||||
log += ` -${epen} [${enc} Enc% * ${pentable.armorenc}]`;
|
||||
}
|
||||
if (pentable.armorenc != pentable.metalenc) {
|
||||
// Channeling
|
||||
// FIXME: This is wrong for realsm were metal and non-metal are different but not zero
|
||||
if ((pentable.armorenc == pentable.metalenc) || (enc == metalenc)) {
|
||||
// Easy case: Metal and non metal the same - Essence basically
|
||||
// Ignore metal as enc encompases both
|
||||
epen += enc * pentable.metalenc;
|
||||
log += ` -${epen} [${enc} Enc% * ${pentable.metalenc}]`;
|
||||
} else {
|
||||
let encdelta = enc - metalenc;
|
||||
epen += encdelta * pentable.armorenc;
|
||||
log += ` -${epen} [(${enc} - ${metalenc} Non-metal Enc% * ${pentable.armorenc}]`;
|
||||
epen += metalenc * pentable.metalenc;
|
||||
log += ` -${epen} [${enc} Enc% * ${pentable.metalenc} (metal)]`;
|
||||
log += ` -${epen} [${metalenc} Metal Enc% * ${pentable.metalenc}]`;
|
||||
}
|
||||
// Now apply transcendance
|
||||
if (transcend && epen > 0) {
|
||||
@@ -13734,6 +13764,7 @@ frontpage.updateDB = function () {
|
||||
console.log("dooing update", ev);
|
||||
var updates = {};
|
||||
const db_extra = miscBonusTotal(ev.db_misc || "")[0];
|
||||
console.log("db_extra", db_extra, ev.db_misc)
|
||||
const dbmiscmod = parseIntDefault(ev.dbmod, 0);
|
||||
const basedb = +ev.qu * 3 + db_extra + dbmiscmod;
|
||||
updates.db_base = basedb;
|
||||
@@ -14218,15 +14249,22 @@ RMUInventory.itemfields = [ "itemname", "itemweight", "itemcount", "itemsystem",
|
||||
let percept = 0;
|
||||
let rangedpenalty = 0;
|
||||
let maneuver_penalty = 0;
|
||||
let toget = ['base_at_misc', 'perception_misc']
|
||||
let toget = ['base_at_misc', 'perception_misc', 'db_misc'];
|
||||
ids.forEach(id => {
|
||||
toget.push(`repeating_stuff_${id}_itemname`);
|
||||
toget.push(`repeating_stuff_${id}_itemequipped`);
|
||||
toget.push(`repeating_stuff_${id}_itemsystem`);
|
||||
});
|
||||
|
||||
let armordb = 0;
|
||||
let armordbname = "None";
|
||||
getAttrsPending(toget, (stuff) => {
|
||||
console.log("Fetch equipment", stuff);
|
||||
let updates = {};
|
||||
updates.db_misc = miscBonusRemoveFilter(stuff.db_misc, (item) => {
|
||||
return item.name.startsWith("Armor DB Bonus");
|
||||
});
|
||||
|
||||
|
||||
let atinfo = miscBonusHighest(stuff.base_at_misc || "", 1);
|
||||
// Set default AT to base_at everywhere.
|
||||
updates.at_head = updates.at_torso = updates.at_legs =
|
||||
@@ -14253,10 +14291,12 @@ RMUInventory.itemfields = [ "itemname", "itemweight", "itemcount", "itemsystem",
|
||||
rmuerror("Parsing object JSON", e);
|
||||
return;
|
||||
}
|
||||
console.log(json);
|
||||
// Look for magic fields:
|
||||
// - AT
|
||||
// - attack table
|
||||
if (json.AT) {
|
||||
let db = parseIntDefault(json.DB, 0);
|
||||
switch (json.Subtype) {
|
||||
case 'Helmet':
|
||||
updates.at_head = json.AT;
|
||||
@@ -14265,6 +14305,10 @@ RMUInventory.itemfields = [ "itemname", "itemweight", "itemcount", "itemsystem",
|
||||
case 'Torso':
|
||||
updates.at_torso = json.AT;
|
||||
updates.at_torso_info = name;
|
||||
if (db && db > armordb) {
|
||||
armordb = db;
|
||||
armordbname = name;
|
||||
}
|
||||
break;
|
||||
case 'Vambraces':
|
||||
updates.at_arms = json.AT;
|
||||
@@ -14273,12 +14317,26 @@ RMUInventory.itemfields = [ "itemname", "itemweight", "itemcount", "itemsystem",
|
||||
case 'Greaves':
|
||||
updates.at_legs = json.AT;
|
||||
updates.at_legs_info = name;
|
||||
break
|
||||
break;
|
||||
case 'Set':
|
||||
updates.at_torso = json.AT;
|
||||
updates.at_legs = json.AT;
|
||||
updates.at_arms = json.AT;
|
||||
if (db && db > armordb) {
|
||||
armordb = db;
|
||||
armordbname = name;
|
||||
}
|
||||
updates.at_torso_info = updates.at_legs_info = updates.at_arms_info = name;
|
||||
break;
|
||||
default:
|
||||
updates.at_head = json.AT;
|
||||
updates.at_torso = json.AT;
|
||||
updates.at_legs = json.AT;
|
||||
updates.at_arms = json.AT;
|
||||
if (db && db > armordb) {
|
||||
armordb = db;
|
||||
armordbname = name;
|
||||
}
|
||||
updates.at_head_info = updates.at_torso_info = updates.at_legs_info =
|
||||
updates.at_arms_info = name;
|
||||
}
|
||||
@@ -14296,7 +14354,8 @@ RMUInventory.itemfields = [ "itemname", "itemweight", "itemcount", "itemsystem",
|
||||
});
|
||||
|
||||
// Adjust due to perception penalty
|
||||
updates.perception_misc = miscBonusSet(updates.perception_misc,
|
||||
updates.db_misc = miscBonusSet(stuff.db_misc, `Armor DB Bonus (${armordbname})`, armordb);
|
||||
updates.perception_misc = miscBonusSet(stuff.perception_misc,
|
||||
"Armor Perception Penalty", percept);
|
||||
updates.perception_penalty = percept;
|
||||
updates.ranged_penalty = rangedpenalty;
|
||||
@@ -14305,6 +14364,7 @@ RMUInventory.itemfields = [ "itemname", "itemweight", "itemcount", "itemsystem",
|
||||
console.log("equipment update", updates);
|
||||
setAttrsPending(updates, () => {
|
||||
RMUSkills.updateSingleCategory("Awareness");
|
||||
frontpage.updateDB();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -14563,7 +14623,7 @@ RMUInventory.itemfields = [ "itemname", "itemweight", "itemcount", "itemsystem",
|
||||
"inventoryaddname", "inventoryaddweight", "inventoryaddnotes",
|
||||
"inventoryaddtype",
|
||||
"inventoryaddarmorsubtype", "inventoryaddarmorat",
|
||||
"inventoryaddarmordbbonus",
|
||||
"inventoryaddarmordbbonus", "inventoryaddarmormaterial",
|
||||
"inventoryaddshieldattacks", "inventoryaddshielddb",
|
||||
"inventoryaddweaponmaterialc", "inventoryaddweaponmaterialw",
|
||||
"inventoryaddweaponmateriali", "inventoryaddweaponmaterialm",
|
||||
@@ -14594,6 +14654,9 @@ RMUInventory.itemfields = [ "itemname", "itemweight", "itemcount", "itemsystem",
|
||||
if (db != 0) {
|
||||
system.DB = ia.inventoryaddarmordbbonus;
|
||||
}
|
||||
// If Armor need to make a %
|
||||
update.weight = `${update.weight}%`;
|
||||
update.itemmaterial = ia.inventoryaddarmormaterial;
|
||||
} else if (update.type == 'Shield') {
|
||||
system['Attacks Blocked'] = ia.inventoryaddshieldattacks;
|
||||
system['DB Bonus'] = ia.inventoryaddshielddb;
|
||||
@@ -14687,6 +14750,7 @@ RMUInventory.itemfields = [ "itemname", "itemweight", "itemcount", "itemsystem",
|
||||
if (sys.AT) {
|
||||
update.inventoryaddarmorat = sys.AT;
|
||||
}
|
||||
update.inventoryaddarmormaterial = item[`${basename}_itemmaterial`];
|
||||
update.inventoryaddarmordbbonus = parseIntDefault(sys.DB, 0);
|
||||
}
|
||||
{//
|
||||
@@ -14696,6 +14760,7 @@ RMUInventory.itemfields = [ "itemname", "itemweight", "itemcount", "itemsystem",
|
||||
if (sys['DB Bonus']) {
|
||||
update.inventoryaddshielddb = sys['DB Bonus'];
|
||||
}
|
||||
update.inventoryaddarmormaterial = item[`${basename}_itemmaterial`];
|
||||
}
|
||||
|
||||
// Ideally this should be the same as the above function
|
||||
@@ -16750,6 +16815,7 @@ onCheck("clicked:newcombat", () => {
|
||||
sendMessage(`${ev.character_name} prepares for battle`);
|
||||
});
|
||||
actionsUpdateStatus();
|
||||
updatetokenmarkers();
|
||||
});
|
||||
|
||||
// So this is our per AP stuff
|
||||
@@ -16763,6 +16829,7 @@ onCheck("clicked:deletebleed", () => {
|
||||
getAttrs(["character_name"], (x) => {
|
||||
sendMessage(`${x.character_name} is no longer bleeding`);
|
||||
setAttrs({ bleeding: 0, bleedlist: []});
|
||||
updatetokenmarkers();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16770,6 +16837,7 @@ onCheck("clicked:statusstun75delete", () => {
|
||||
getAttrs(["character_name"], (x) => {
|
||||
sendMessage(`${x.character_name} has stun-75 lifted.`);
|
||||
setAttrs({ statusstun75: 0 }, actionsUpdateStatus);
|
||||
updatetokenmarkers();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16777,6 +16845,7 @@ onCheck("clicked:statusstun50delete", () => {
|
||||
getAttrs(["character_name"], (x) => {
|
||||
sendMessage(`${x.character_name} has stun-50 lifted.`);
|
||||
setAttrs({ statusstun50: 0 }, actionsUpdateStatus);
|
||||
updatetokenmarkers();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16784,6 +16853,7 @@ onCheck("clicked:statusstun25delete", () => {
|
||||
getAttrs(["character_name"], (x) => {
|
||||
sendMessage(`${x.character_name} has stun-25 lifted.`);
|
||||
setAttrs({ statusstun25: 0 }, actionsUpdateStatus);
|
||||
updatetokenmarkers();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16801,7 +16871,7 @@ function handleFreeClicked() {
|
||||
function handleBleed(currentphase, bleedlist) {
|
||||
// Bleedlist is probably a string.
|
||||
if (!bleedlist || typeof(bleedlist) != 'string') {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Shift current phase to 1..4
|
||||
@@ -16823,6 +16893,22 @@ function handleBleed(currentphase, bleedlist) {
|
||||
return total;
|
||||
}
|
||||
|
||||
function totalBleed(bleedlist) {
|
||||
// Bleedlist is probably a string.
|
||||
if (!bleedlist || typeof(bleedlist) != 'string') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const bleeds = JSON.parse(bleedlist);
|
||||
let total = 0;
|
||||
|
||||
for (let bleed of bleeds) {
|
||||
total += bleed.amount;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic handler for the status list updates. Called once per phase.
|
||||
*
|
||||
@@ -16910,7 +16996,7 @@ function actionsUpdateStatus() {
|
||||
updates.statuspercent = Math.max(100 + updates.allpenalties, 0);
|
||||
updates.statuspercent200 = Math.max(200 + updates.allpenalties, 0);
|
||||
|
||||
VrmuSetAttrs(updates)
|
||||
rmuSetAttrs(updates);
|
||||
});
|
||||
|
||||
}
|
||||
@@ -17020,6 +17106,7 @@ function doTurn() {
|
||||
VrmuSetAttrs(updates, ()=> {
|
||||
sendEOTMessage(`${name} completes their turn (Round ${round} / Phase ${relativephase})`);
|
||||
actionsUpdateStatus();
|
||||
updatetokenmarkers();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -17144,14 +17231,6 @@ onCheck("change:bodydevelopment_bonus change:powerdevelopment_bonus", (x) => {
|
||||
pp = 0;
|
||||
}
|
||||
update.pp_max = pp
|
||||
/*
|
||||
update.bar1_max = ev.bodydevelopment_bonus;
|
||||
update.bar1_value = ev.hp;
|
||||
update.bar2_max = ev.powerdevelopment_bonus;
|
||||
update.bar2_value = ev.pp;*/
|
||||
// if (!ev.hasOwnProperty(hp)) {
|
||||
// update.hp = ev.bodydevelopment_bonus;
|
||||
// }
|
||||
setAttrs(update, { silent:true });
|
||||
});
|
||||
});
|
||||
@@ -17162,7 +17241,6 @@ onCheck("change:bodydevelopment_bonus change:endurance_misc change:mentalfocus_b
|
||||
});
|
||||
|
||||
function updateEnduranceBonus() {
|
||||
console.log("updateEnduranceBonus");
|
||||
getAttrs(['bodydevelopment_bonus', 'endurance_misc', 'mentalfocus_bonus'], (ev) => {
|
||||
let log = "Endurance\n" +
|
||||
`${F(ev.bodydevelopment_bonus)} Body Development\n`;
|
||||
@@ -17203,7 +17281,6 @@ onCheck("change:hp", (_) => {
|
||||
} else {
|
||||
update.hppenalty = -100;
|
||||
}
|
||||
update.bar1_value = values.hp; // FIXME: this doesn't do much
|
||||
update.hp_percent = hppercent;
|
||||
setAttrs(update, { slient: true});
|
||||
});
|
||||
@@ -17418,6 +17495,68 @@ function doRollInitiative() {
|
||||
});
|
||||
}
|
||||
|
||||
/**/
|
||||
function updatetokenmarkers() {
|
||||
console.log("updatetokenmarkers start");
|
||||
getAttrs(['option_usetokenmarkers', 'sheetselect', 'character_name',
|
||||
// Stuns & staggered
|
||||
'statusstagger', 'statusstun75', 'statusstun50', 'statusstun25',
|
||||
'bleedlist', 'grapplestatus'], (info) => {
|
||||
console.log("Update token makers", info);
|
||||
if (!info.option_usetokenmarkers || info.option_usetokenmarkers == 'no') {
|
||||
return;
|
||||
}
|
||||
if (info.option_usetokenmarkers == 'pc' && info.sheettype != 'playersheet') {
|
||||
return;
|
||||
}
|
||||
if (info.option_usetokenmarkers == 'npc' && info.sheettype != 'creaturesheet') {
|
||||
return;
|
||||
}
|
||||
let statusstagger = parseIntDefault(info.statusstagger, 0);
|
||||
let statusstun75 = parseIntDefault(info.statusstun75, 0);
|
||||
let statusstun50 = parseIntDefault(info.statusstun50, 0);
|
||||
let statusstun25 = parseIntDefault(info.statusstun25, 0);
|
||||
let grapplestatus = parseIntDefault(info.statusstun25, 0);
|
||||
|
||||
let tokens = []
|
||||
|
||||
let bleeds = totalBleed(info.bleedlist);
|
||||
if (bleeds > 9) bleeds = 9;
|
||||
tokens.push((bleeds > 0) ? `red:${bleeds}` : "!red");
|
||||
|
||||
tokens.push((statusstagger > 0) ? "pink" : "!pink");
|
||||
if (statusstun75 > 0) {
|
||||
let rounds = Math.floor(statusstun75 / 4);
|
||||
tokens.push(`blue:${rounds}`);
|
||||
} else {
|
||||
tokens.push("!blue");
|
||||
}
|
||||
|
||||
if (statusstun50 > 0) {
|
||||
let rounds = Math.floor(statusstun50 / 4);
|
||||
tokens.push(`green:${rounds}`);
|
||||
} else {
|
||||
tokens.push("!green");
|
||||
}
|
||||
if (statusstun25 > 0) {
|
||||
let rounds = Math.floor(statusstun25 / 4);
|
||||
tokens.push(`purple:${rounds}`);
|
||||
} else {
|
||||
tokens.push("!purple");
|
||||
}
|
||||
|
||||
let tstr = tokens.join('|')
|
||||
|
||||
// Join token string. with --set st
|
||||
let message = `!token-mod --ids @{${info.character_name}|character_id} --set statusmarkers|${tstr}`
|
||||
console.log(message)
|
||||
startRoll(message, (t) => finishRoll(t.rollId, t));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -18148,13 +18287,47 @@ function doNpcGeneate() {
|
||||
});
|
||||
});
|
||||
|
||||
// move
|
||||
out['data-Spelllists'] = []
|
||||
addPendingFunction("NPC Gen: Save Spells Base", () => {
|
||||
let spellsToGet = []
|
||||
let prefixs = [];
|
||||
// Messing with the indentation here for sanity
|
||||
getSectionIDsPending("repeating_spelllistspellownbase", (ids1) => {
|
||||
let p1 = ids1.map((id) => "repeating_spelllistspellownbase_" + id);
|
||||
getSectionIDsPending("repeating_spelllistspellopen", (ids2) => {
|
||||
let p2 = ids2.map((id) => "repeating_spelllistspellopen_" + id);
|
||||
getSectionIDsPending("repeating_spelllistspellclosed", (ids3) => {
|
||||
let p3 = ids3.map((id) => "repeating_spelllistspellclosed_" + id);
|
||||
let prefixes = p1.concat(p2, p3);
|
||||
for (prefix of prefixes) {
|
||||
spellsToGet.push(
|
||||
`${prefix}_listname`,
|
||||
`${prefix}_ranks`,
|
||||
`${prefix}_scr`,
|
||||
);
|
||||
}
|
||||
getAttrsPending(spellsToGet, (spells) => {
|
||||
for (prefix of prefixes) {
|
||||
let ranks = parseIntDefault(spells[`${prefix}_ranks`],0);
|
||||
if (!ranks || ranks === 0) { continue; }
|
||||
let name = spells[`${prefix}_listname`];
|
||||
let scr = spells[`${prefix}_scr`];
|
||||
out['data-Spelllists'].push({
|
||||
name: name,
|
||||
scr: scr,
|
||||
ranks: ranks });
|
||||
}
|
||||
});
|
||||
|
||||
}); }); }); // Nest getSectionIds above
|
||||
});
|
||||
|
||||
|
||||
addPendingFunction("NPC Gen: Save NPC String", () => {
|
||||
setAttrs({npcstring: JSON.stringify(out)})
|
||||
});
|
||||
|
||||
// defenses
|
||||
// move
|
||||
// spells
|
||||
|
||||
checkPending();
|
||||
}
|
||||
@@ -18495,7 +18668,10 @@ injury.parseInjuryString = function (str) {
|
||||
}
|
||||
|
||||
// Update the status as soon as the injury is applied.
|
||||
VrmuSetAttrs(updates, actionsUpdateStatus);
|
||||
VrmuSetAttrs(updates, () => {
|
||||
actionsUpdateStatus();
|
||||
updatetokenmarkers();
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
@@ -19292,6 +19468,22 @@ function dX(x) {
|
||||
return Math.floor(Math.random() * x) + 1;
|
||||
}
|
||||
|
||||
|
||||
// Hacky send to chat
|
||||
onCheck("clicked:sendtochat", () => {
|
||||
console.log("Send to chat clicked");
|
||||
getAttrs(["chatcommand"], (ev) => {
|
||||
console.log("command", ev);
|
||||
//macroscript = "!token-mod --set statusmarkers|red";
|
||||
startRoll(ev.chatcommand, (results2) => {
|
||||
console.log(results2);
|
||||
// Holding the computed data in an object is a bit cleaner if your rolls get more complex
|
||||
let rollData2 = results2.results;
|
||||
finishRoll(results2.rollId, rollData2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
@@ -10,14 +10,31 @@
|
||||
"compendium": "RMU",
|
||||
"useroptions": [
|
||||
{
|
||||
"attribute": "default_currency",
|
||||
"displayname": "Currency for the Game",
|
||||
"displaytranslationkey": "defaultcurrency",
|
||||
"type": "text",
|
||||
"default": "GP(Gold Pieces)=10SP;SP(Silver Pieces)*=10BP;BP(Bronze Pieces)=10CP;CP(Copper Pieces)",
|
||||
"description": "Custom currency description",
|
||||
"descriptiontranslationkey": "DefaultCurrency"
|
||||
"attribute": "option_usetokenmarkers",
|
||||
"displayname": "Use Token Markeres",
|
||||
"displaytranslationkey": "option_usetokenmarkers",
|
||||
"type": "select",
|
||||
"options": [
|
||||
"no|No token marker updates",
|
||||
"pc|Token Markers on PC sheets",
|
||||
"npc|Token Markers on NPC/Creature sheets",
|
||||
"all|Token Markers on all sheets"
|
||||
],
|
||||
"default": "no",
|
||||
"description": "Show token makers for character state on the token. Covers stun, bleed and similar states. Requires Token Mod to be installed (and hence a Pro account)."
|
||||
},
|
||||
{
|
||||
"attribute": "option_usefx",
|
||||
"displayname": "Use FX",
|
||||
"displaytranslationkey": "option_usefx",
|
||||
"type": "select",
|
||||
"options": [
|
||||
"no|No FX",
|
||||
"all|All Supported FX"
|
||||
],
|
||||
"default": "all",
|
||||
"description": "Show FX when available based on the sheets guess of the attack"
|
||||
}
|
||||
],
|
||||
"version": "1757570905"
|
||||
"version": "1757999780"
|
||||
}
|
||||
|
||||
@@ -168,6 +168,8 @@
|
||||
"noprofession": "No Profession",
|
||||
"open": "Open",
|
||||
"operation": "Operation",
|
||||
"option_usefx": "Use FX",
|
||||
"option_usetokenmarkers": "Use Token Markers",
|
||||
"paladin": "Paladin",
|
||||
"perception": "Perception",
|
||||
"performanceart": "Performance Art",
|
||||
|
||||
@@ -1,3 +1,28 @@
|
||||
# 2025-09-16
|
||||
|
||||
- First version of token markers
|
||||
- Sheet options
|
||||
- Random colours
|
||||
- Trigger on status change.
|
||||
- Fix stacking of popups on main page
|
||||
- Add helper to get total number of bleeds
|
||||
- Add options for token makers
|
||||
- Add options for FX (doesn't do much)
|
||||
- Export to NPC now grabs spell lists.
|
||||
- Inventory (Stuff)
|
||||
- Fix Helmet perception penalty trashing other modifiers
|
||||
- Apply Armor DB
|
||||
- Removed Armor DB & Perception penalties when you remove items
|
||||
- Fix for armor losing it's encumberance.
|
||||
- Add support for "Sets" Armor without a helmet
|
||||
- Add armor material to edit window
|
||||
- Correctly support mixed material encumberances (metal != non-metal)
|
||||
|
||||
# 2025-09-11
|
||||
|
||||
- Try and get the info popups working again.
|
||||
- fix spurious --> from the rolltemplates page
|
||||
|
||||
# 2025-09-09
|
||||
|
||||
- Can now roll weapon fumbles direct from the sheet.
|
||||
|
||||
Reference in New Issue
Block a user