Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Writing an attack action block directly to an NPC character sheet from an API?

Has anyone already figured out how to write an attack action block straight to an NPC sheet from an API? It's a nut I just cannot seem to crack. I can get all the fields to populate for the attack and damage rolls but can't fully get the API to write the block so it can be clicked and create rolls. Trying to adjust the character sheet on the fly when running an API for spells like Summon Fey that have variable attack and damage rolls based on the level of the cast and the caster's spell attack modifier. I can get the API to write into the NPC character sheet, but it's outlined in red and isn't clickable to roll and the cog doesn't work. I am guessing hidden fields that the UI writes but I cannot see. Any thoughts or direction would be appreciated.
1740202823
Gauss
Forum Champion
Hi HunterS, Which character sheet are you using?
I am using the NPC character sheet from the DnD 5E 2014 by Roll20.
1740235910
timmaugh
Forum Champion
API Scripter
Are you using a script you wrote yourself? (If so, can you share the code) Are you using a community script? (If so, can you share your command line to activate it) This will help get you better suggestions.
1740240156

Edited 1740240237
I don't want to be misleading. I had Grok 3 try to figure this out. It's proved to be obviously beyond me. Grok 3 with a little help from me on how to write to the NPC Character sheet directly got farther than I could. But it couldn't quite complete the process despite my best effort/thoughts on what flags we were missing to clue Roll20 into the fact that our attack block was an attack block. Basically, the insertion of the attack into the NPC character sheet is not recognized as an attack in Roll20. Despite my best efforts, I cannot figure out what the UI manipulates to flag an attack block on the NPC character sheet as a clickable attack block with a functional cog. Hence my desperate appeal to the forum. I can write in the block, but can't make it work. The red outline around my created block also seems to indicate Roll20 is quite aware I have done it incorrectly. But, with a little Grok 3 assistance, here is as far as I got. This is as far as I was able to get testing how to insert a block under actions as a melee attack into the NPC sheet from the API. I am not posting the rest of my actual script for the spell implementation as it's not relevant. Happy to share it though if someone wants it. Everything works with the token creation and chat log output in that script. It's just writing to the NPC Character sheet (specifically in the actions block, I can write to HP and AC as intended) that I am too inept to sort out. on("chat:message", function(msg) { if (msg.type === "api" && msg.content.indexOf("!summonFey") === 0) { let args = msg.content.split(" --"); if (args.length < 2) { sendChat("Summon Fey", "Error: Specify Fey type."); return; } let feyType = null; if (args[1].toLowerCase() === "fuming") feyType = "Fuming Fey"; else if (args[1].toLowerCase() === "mirthful") feyType = "Mirthful Fey"; else if (args[1].toLowerCase() === "tricksy") feyType = "Tricksy Fey"; else { sendChat("Summon Fey", "Error: Invalid Fey type."); return; } let spellLevel = 3; if (args.length > 2 && args[2].startsWith("level")) { spellLevel = parseInt(args[2].split(" ")[1]) || 3; } if (spellLevel < 3 || spellLevel > 9) spellLevel = 3; let damageMod = 3 + spellLevel; let attackBonus = 6; if (msg.selected) { let token = getObj("graphic", msg.selected[0]._id); let charId = token.get("represents"); if (charId) { let char = getObj("character", charId); let attrs = findObjs({ type: "attribute", characterid: charId }); let spellAttackAttr = attrs.find(a => a.get("name") === "spell_attack_bonus"); if (spellAttackAttr) { let bonus = parseInt(spellAttackAttr.get("current")); if (!isNaN(bonus)) attackBonus = bonus; } } } sendChat("Summon Fey", `Using attack bonus: +${attackBonus}`); let char = findObjs({ type: "character", name: feyType })[0]; if (!char) { sendChat("Summon Fey", `Error: "${feyType}" not found.`); return; } sendChat("Summon Fey", `Found ${feyType} with ID: ${char.id}`); let newRowId = generateRowID(); sendChat("Summon Fey", `Creating attack with ID: ${newRowId}`); try { createObj("attribute", { name: `repeating_npcaction_${newRowId}_name`, characterid: char.id, current: "Shortsword (Higher Level Cast)" }); setTimeout(() => { createObj("attribute", { name: `repeating_npcaction_${newRowId}_attack_flag`, characterid: char.id, current: "on" }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_attack_tohit`, characterid: char.id, current: `${attackBonus}` }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_attack_tohitrange`, characterid: char.id, current: `+${attackBonus}, Reach 5 ft.` }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_attack_onhit`, characterid: char.id, current: `${damageMod + 1} (1d6+${damageMod}) Piercing damage plus 3 (1d6) force damage` }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_attack_damage`, characterid: char.id, current: `1d6+${damageMod}` }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_attack_damagetype`, characterid: char.id, current: "Piercing" }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_attack_damage2`, characterid: char.id, current: "1d6" }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_attack_damagetype2`, characterid: char.id, current: "force" }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_attack_range`, characterid: char.id, current: "5 ft." }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_attack_target`, characterid: char.id, current: "One Target" }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_damage_flag`, characterid: char.id, current: "{{damage=1}} {{dmg1flag=1}} {{dmg2flag=1}}" }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_attack_crit`, characterid: char.id, current: "1d6" }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_attack_crit2`, characterid: char.id, current: "1d6" }); createObj("attribute", { name: `repeating_npcaction_${newRowId}_description`, characterid: char.id, current: "Testy MctestFace" // Exact match to Test Sword }); sendChat("Summon Fey", "Attack added with Testy MctestFace description! Refresh, click cog to save if needed, then test."); }, 1000); // Delay to mimic UI timing } catch (e) { sendChat("Summon Fey", `Error: ${e.message}`); } } }); function generateRowID() { return "-" + Math.random().toString(36).substr(2, 9); }
This might help too. The red boxed texts writes in. But the COG for it does not function and clicking Shortsword (Higher Level Cast) does not create a die roll in the chat log.