∇ince said: Hi Archibael, I like your idea. Anyone think this might conflict with WotC ip? I believe a parser could be built into the sheet to handle the import of a properly formatted statblock for monsters without requiring an additional api script... I'll add it to the suggestions, but will wait until I work out how best to handle adding a monster's page/tab for the sheet. And more specifically, deciding if it's best to create new "monster-specific" attributes or try and use the existing ones. I have a modicum of js skills/knowledge, so any help you can offer will be much appreciated. ;-) Cheers Here's how I did it in Mythus... (my CSS sucks, I'm much better at JS... which sucks too, but I can get by...) I made the Importer hideable so it didn't clutter up the sheet, but when revealed it was just a plain boring text box with a button next to it labeled "Import critter": <input type="checkbox" class="toggle-show-subs" name="attr_critterimportshowcheck" value="1" checked="false" title="@{critterimportshowcheck}" /><span style="font-family:Benguiat" class="lbl">Import New Critter</span> <div class="hideable-subs"> <textarea spellcheck="false" class="weapontext" type="text" placeholder="Paste critter details here" name="attr_critterimport" value="" title="@{critterimport}"></textarea><button type="action" name="act_importcritter" >Import critter</button> </div> Then, in the "scripts" part of the html page, I defined the action the button referred to: const configbuttonlist10 = ["importcritter"]; configbuttonlist10.forEach(button => { on(`clicked:${button}`, function() { characterimport("critter"); }); }); Then in the scripts part of the html page, I created a javascript code at the end to parse the incoming string and populate the stat blocks: const characterimport = (section) => { getAttrs([`${section}import`], v => { newrowattrs = {}; multiweap = v[`${section}import`]; multiweaparray = multiweap.split("}"); multiweaparray.forEach ( (weap) => { weaparray=weap.split("|"); weapobj = {}; weaparray.forEach( (item) => { if (item=="") { throwaway = ""; } else { var pair=item.split("^"); if (pair[0]=="merccoms"||pair[0]=="languages"||pair[0]=="signlanguages"||pair[0]=="florentineweaps"||pair[0]=="fastdrawweaps"||pair[0]=="specifictargetweaps"||pair[0]=="blindfightingweaps"||pair[0]=="streetwisesubs") { if (pair[0]=="languages") { [a bunch of stuff to deal with special cases where the parsing needs to be more complicated than one variable, one value, such as repeating sections]] }; } else { weapobj[pair[0]]=pair[1]; newrowattrs[`${pair[0]}`] = weapobj[pair[0]]; }; }; }); }); setAttrs(newrowattrs); }); }; (A lot of this is needlessly complex for monsters, as usually they don't have a bunch of special cases you have to deal with like repeating blocks for languages, but I made this code to do dual duty for monsters and characters, so there's extra you can ignore.) The Excel sheet then needs to format the plain text someone types into it into something parseable by the Importer:
personahide^0|character_name^Smartypants Hottieface|attractiveness^18|beautyugly^-2|ap^2|joss^3|size^1|sizedetail^6'T,2'W|numberappearing^3d6|invuln^Fire|suscept^Silver
(Insinuation x2)|senses^|avgarmor^3|mentalcunning^0|mmcapatt^19|mmpowatt^14|mmspdatt^18|mrcapatt^15|mrpowatt^12|mrspdatt^11|pmcapatt^20|pmpowatt^19|pmspdatt^15|pncapatt^19|pnpowatt^18|pnspdatt^17|smcapatt^16|smpowatt^12|smspdatt^11|spcapatt^15|sppowatt^12|spspdatt^13|traithekamental_toggle^0|traithekaphysical_toggle^1|traithekaspiritual_toggle^0|fpdweomer^0|fppriest^0|dweomerschool^|priestethos^|vowpact^|vowpact_mult^1|race^Faerie|personality^Savage|quirks^|residence^Arizona||agriculture_kstoggle^1|agriculture_steep^21|architecture_kstoggle^1|architecture_steep^43||astronomy_kstoggle^1|astronomy_steep^24||cryptography_kstoggle^1|cryptography_steep^24||economicsfinanceinvesting_kstoggle^1|economicsfinanceinvesting_steep^30||foreignlanguage_kstoggle^1|foreignlanguage_steep^34||hypnotism_kstoggle^1|hypnotism_steep^14||journalism_kstoggle^1|journalism_steep^18||lipreadingsignlanguage_kstoggle^1|lipreadingsignlanguage_steep^42||nativetongue_kstoggle^1|nativetongue_steep^37||tradelanguage_kstoggle^1|tradelanguage_steep^24||combathandweapons_kstoggle^1|combathandweapons_steep^24||culturedpalate_kstoggle^1|culturedpalate_steep^52||hekaforging_kstoggle^1|hekaforging_steep^32||music_kstoggle^1|music_steep^23||perceptionphysical_kstoggle^1|perceptionphysical_steep^53||sports_kstoggle^1|sports_steep^34||weaponsspecialskill_kstoggle^1|weaponsspecialskill_steep^57||philosophy_kstoggle^1|philosophy_steep^20||streetwise_kstoggle^1|streetwise_steep^32||animalhusbandry_has^1|floraculture_has^1|economics_has^1|mercantilism_has^1|axe_has^1|onehandedswords_has^1|beverages_has^1|wineswinemaking_has^1|beersbrewing_has^1|spirits_has^1|perfumes_has^1|gourmetmealpreparation_has^1|enhancedobjectquality_has^1|enchantedmechanisms_has^1|hekareservoirs_has^1|keyboards_has^1|stringedbowed_has^1|noticingp_has^1|hearing_has^1|searching_has^1|tracking_has^1|individualnonviolentsports_has^1|florentine_has^1|fastdraw_has^1|specifictarget_has^1|blindfighting_has^1|merccoms^Furs,Silver|languages^French:34,Deutsch:58|signlanguages^Romani,Tramps,Thieves|nativetongue_language^Atlantlan|tradelanguage_language^Trade
Phoenecian|florentineweaps^axe,onehandedswords|fastdrawweaps^whipflail,axe|specifictargetweaps^axe|blindfightingweaps^poleaxe|streetwisesubs^Merchants,Artists,Gangs| What I have here is stat1^value1|stat2^value2|stat3^value3|... and for stats which have nested values, like languages, I go one delimiter further with comma and colon (":"): |merccoms^Furs,Silver|languages^French:34,Deutsch:58|signlanguages^Romani,Tramps,Thieves|nativetongue_language^Atlantlan| When you copy that big mess of crazy text gobbledgook into the Import box and click import critter, it parses each stat and stuffs it into the character sheet where it's supposed to go. I have other variations which create repeating blocks for multiple weapons/attacks if appropriate. You need a good delimiter; comma and semicolon are traditional, but Gygax and company used commas and semicolons in the middle of their stat blocks sometimes, and certainly in the description text. I used both pipe ("|") and carat ("^") so I could nest multiple weapons or multiple spells into the general stat block, but you can use whatever makes you comfortable. The beauty of it: since the import format is just YOUR variable names and the values assigned to them, it's on the Excel spreadsheet writer to make sure those are right in the spreadsheet, not on you to do any error checking. >:) And if you come up with a new stat, you just have to give the name to the community and they can add it to their Excel sheet... or not... optional stats don't need to be included, so if I decide I don't like Comeliness or I'm not playing OA and don't need honor or nonweapon proficiencies... I don't need to include them in my import string, and the parser won't try to fill those stats in the sheet. And ordering doesn't matter: you can import stats in any order, skip stats (they'll be blank or at least some default value in the sheet), etc. If I recall correctly, it's incremental, too. You can pull in the hobgoblin stats, and then if you want to add some custom hobgoblin serjeant stats on top of it, you don't have to have an entire stat block dedicated to "hobgoblin serjeant" (although you can if you want to) you can just paste in the stats which change for the serjeant and the rest remain the same. I don't pretend my method is in any way elegant-- real coders would call it clumsy AF... but it works. I can certainly help you with it when you're ready for it, as well as giving you an Excel sheet to give away to people as a sample. I don't see any reason you should have to rename any of your stats for the monster version of the sheet... I think of it as just two different views into the same stats. Of course, there are some cases where that's not the case, such as when Intelligence is an actual stat for PCs but for monsters it's a range of stats. I definitely did some things differently for beasties than for PCs, but unless there's a good reason to, I wouldn't bother.