FG Spreadshirt Swag
Page 1 of 2 12 Last
  1. #1

    Advanced Bestiary NPC Factory for 3.5

    Hello everyone,

    I am having trouble using the NPC factory for 3.5 creatures. I just can't seem to figure out the correct format for importing monster data. I have searched for days now. Granted, I'm not the best at using advanced search functions, but I have tried my best.

    Literally, everything I come across is for Pathfinder and the PF format. I bought the Advanced Bestiary because it specifically states compatibility with 3.5 and not just Pathfinder. I guess I wouldn't ask for a refund, because the template tool is also handy, but not having this functionality detracts from the value to a significant degree. It's 80% of the reason I bought it. I feel like it's something simple and I'm just missing it. Is there an example of D&D 3.5 NPC format necessary for the import function to work? (again, i only ever see PF examples and that doesn't work w/o so much editing I might as well type everything in by hand anyway).

    I tried searching for a thread addressing this. This has to have been addressed before, but I can't find it.

    Thank you.

  2. #2
    Trenloe's Avatar
    Join Date
    May 2011
    Location
    Colorado, USA
    Posts
    33,402
    Quote Originally Posted by Kelevraa View Post
    I just can't seem to figure out the correct format for importing monster data.
    Use the Paizo statblock format. Info here: https://legacy.aonprd.com/bestiary/introduction.html

    Also see the video on the product page for some guidelines: https://www.fantasygrounds.com/store...hp?id=GRR2901e
    Private Messages: My inbox is forever filling up with PMs. Please don't send me PMs unless they are actually private/personal messages. General FG questions should be asked in the forums - don't be afraid, the FG community don't bite and you're giving everyone the chance to respond and learn!

  3. #3
    ddavison's Avatar
    Join Date
    Sep 2008
    Posts
    6,134
    Blog Entries
    21
    It looks like this one was a little light on the documentation for the statblock importer. It was tested with statblocks I could find at the time for 3.5E and Pathfinder, but I remember there being some finicky bits. Do you have a sample stat block you are trying to do?

    During the 3.5E era, it was hard to find any two companies or sites that did them the same.
    From this page: https://mikael.borjesson.net/dnd/mon...l,+Astral+Deva

    ORIGINAL:
    Code:
    Angel, Astral Deva CR 14
    Always good (any) Medium Outsider (Angel, Extraplanar, Good)
    Init +8; Senses darkvision 60 ft., low-light vision; Listen +23, Spot +23
    Languages Celestal, Infernal, Draconic; tongues
    AC 29, touch 14, flat-footed 25; protective aura, uncanny dodge (+4 Dex, +15 natural)
    hp 102 (12 HD); DR 10/evil
    Immune acid, cold, petrification
    Resist electricity 10, fire 10; SR 30
    Fort +14 (+18 against poison), Ref +12, Will +12
    Speed 50 ft., fly 100 ft. (good)
    Melee +3 heavy mace of disruption +21/+16/+11 (1d8+12 plus stun); or Melee Slam +18 (1d8+9)
    Space 5 ft.; Reach 5 ft.
    Base Atk +12; Grp +18
    Atk Options Cleave, Power Attack
    Special Actions change shape
    Spell-like Abilities (CL 12):
    At will—aid, continual flame, detect evil, discern lies (DC 19), dispel evil (DC 20), dispel magic, holy aura (DC 23), holy smite (DC 19), holy word (DC 22), invisibility (self only), plane shift (DC 22), remove curse (DC 18), remove disease (DC 18), remove fear (DC 16)
    7/day—cure light wounds (DC 16), see invisibility
    1/day—blade barrier (DC 21), heal (DC 21)
    The save DCs are Charisma-based
    Abilities Str 22, Dex 18, Con 18, Int 18, Wis 18, Cha 20
    Feats Alertness, Cleave, Great Fortitude, Improved Initiative, Power Attack
    Skills Concentration +19, Craft or Knowledge (any three) +19, Diplomacy +22, Escape Artist +19, Hide +19, Intimidate +20, Listen +23, Move Silently +19, Sense Motive +19, Spot +23, Use Rope +4 (+6 with bindings)
    Advancement 13-18 HD (Medium); 19-36 HD (Large)
    Level adjustment +8
    Stun (Su) If an astral deva strikes an opponent twice in one round with its mace, that creature must succeed on a DC 22 Fortitude save or be stunned for 1d6 rounds. The save DC is Strength-based.
    Uncanny Dodge (Ex) An astral deva retains its Dexterity bonus to AC when flat-footed, and it cannot be flanked except by a rogue of at least 16th level. It can flank characters with the uncanny dodge ability as if it were a 12th-level rogue.
    Change Shape (Su) An astral deva can assume the form of any Small or Medium humanoid.
    MODIFIED TO PARSE:
    Code:
    Angel, Astral Deva
    CR 14
    LG Medium Outsider (Angel, Extraplanar, Good)
    Init +8; Senses darkvision 60 ft., low-light vision; Listen +23, Spot +23
    Languages Celestal, Infernal, Draconic; tongues
    AC 29, touch 14, flat-footed 25; protective aura, uncanny dodge (+4 Dex, +15 natural)
    hp 102 (12 HD); 
    DR 10/evil
    Immune acid, cold, petrification;
    Resist electricity 10, fire 10; SR 30;
    OFFENSE
    Fort +14 (+18 against poison), Ref +12, Will +12
    Speed 50 ft., fly 100 ft. (good)
    Melee +3 heavy mace of disruption +21/+16/+11 (1d8+12 plus stun); or Melee Slam +18 (1d8+9)
    Space 5 ft.; Reach 5 ft.
    Base Atk +12; Grp +18
    Special Attacks Cleave, Power Attack, Change Shape.
    Spell-like Abilities (CL 12): At will—aid, continual flame, detect evil, discern lies (DC 19), dispel evil (DC 20), dispel magic, holy aura (DC 23), holy smite (DC 19), holy word (DC 22), invisibility (self only), plane shift (DC 22), remove curse (DC 18), remove disease (DC 18), remove fear (DC 16);7/day—cure light wounds (DC 16), see invisibility;1/day—blade barrier (DC 21), heal (DC 21)
    The save DCs are Charisma-based
    STATISTICS
    Abilities Str 22, Dex 18, Con 18, Int 18, Wis 18, Cha 20
    Feats Alertness, Cleave, Great Fortitude, Improved Initiative, Power Attack
    Skills Concentration +19, Craft or Knowledge (any three) +19, Diplomacy +22, Escape Artist +19, Hide +19, Intimidate +20, Listen +23, Move Silently +19, Sense Motive +19, Spot +23, Use Rope +4 (+6 with bindings).
    Advancement 13-18 HD (Medium); 19-36 HD (Large)
    Level Adjustment: +8
    Stun (Su) If an astral deva strikes an opponent twice in one round with its mace, that creature must succeed on a DC 22 Fortitude save or be stunned for 1d6 rounds. The save DC is Strength-based.
    Uncanny Dodge (Ex) An astral deva retains its Dexterity bonus to AC when flat-footed, and it cannot be flanked except by a rogue of at least 16th level. It can flank characters with the uncanny dodge ability as if it were a 12th-level rogue.
    Change Shape (Su) An astral deva can assume the form of any Small or Medium humanoid.
    Notable changes:
    • For the type, it looks for alignment to be one of the standard values like LG, CG, LE, etc. and then grabs the type from the rest of that line.
    • Put CR on a new line
    • Special Actions should actually be Special Attacks: {whatever}
    • After the Special Attacks, there should be a section called STATISTICS just before the abilities start. That tells the parser to grab everything between for the SA section
    • You can add an OFFENSE tag as well, just before the saves
    • If it is picking up "extra" stuff for certain fields, you can often control this by appending a ; or a . at the end of a line.


    The new NPC should be added to the NPCs window under the New group heading.

  4. #4
    ddavison's Avatar
    Join Date
    Sep 2008
    Posts
    6,134
    Blog Entries
    21
    Here is the extension for this. It has an ext extension that you can unzip into a folder in your extensions folder and then modify from there. The script with the statblock importer is found in the template_npc_factory_build_npc_rom_statblock.lua file.

    Here is the relative code for the parsing routine:
    PART 1:
    Code:
    function onButtonPress()
    	local templateFactory = DB.findNode("template_npc_factory_data");
    	strStatblock = DB.getText(templateFactory,"statblock","");
    	ABUtility.Trace(strStatblock);
    	
    	wndNPCs = Interface.openWindow("masterindex","npc");
    	wndNPCs.setRecordType("npc");
    	local nodeNPC = DB.createChild("npc");
    	--ABUtility.update(nodeNPC,"name","New NPC");
    
    	-- Name and CR
    	_,_,sName,sCR = string.find(strStatblock,"^(.-)%s*%(*CR*%s*(%d+)%)*");
    	if sName == nil then
    		_,_,sName = string.find(strStatblock,"^(.-)%s*[:;\n]+");
    	end
    	setNodeValue(nodeNPC,"name",stripCRLF(sName),"string","New NPC");
    	setNodeValue(nodeNPC,"cr",sCR,"number",0);
    	
    	-- Abilities
    	_,_,sSTR = string.find(strStatblock,"[sS][tT][rR]:?%s*(%d+),*%s*");
    	_,_,sDEX = string.find(strStatblock,"[dD][eE][xX]:?%s*(%d+),*%s*");
    	_,_,sCON = string.find(strStatblock,"[cC][oO][nN]:?%s*(%d+),*%s*");
    	_,_,sWIS = string.find(strStatblock,"[wW][iI][sS]:?%s*(%d+),*%s*");
    	_,_,sINT = string.find(strStatblock,"[iI][nN][tT]:?%s*(%d+),*%s*");
    	_,_,sCHA = string.find(strStatblock,"[cC][hH][aA]:?%s*(%d+),*%s*");
    	setNodeValue(nodeNPC,"strength",sSTR,"number",0);
    	setNodeValue(nodeNPC,"dexterity",sDEX,"number",0);
    	setNodeValue(nodeNPC,"constitution",sCON,"number",0);
    	setNodeValue(nodeNPC,"wisdom",sWIS,"number",0);
    	setNodeValue(nodeNPC,"intelligence",sINT,"number",0);
    	setNodeValue(nodeNPC,"charisma",sCHA,"number",0);
    	
    	-- AC, HP and HD
    	_,_,sAC1,sAC2,sHP,sHD = string.find(strStatblock,"[aA][cC]:?%s*(%d+)(.-)%s*[hH][pP]:?%s*(%d+)%s*%((.-)%)%s*[fF][oO][rR][tT]");
    	if sAC1 == nil then
    		_,_,sAC1,sAC2 = string.find(strStatblock,"[aA][cC]:?%s*(%d+)%s*(.-)[.;\n]");
    	end
    	if sAC1 == nil then
    		-- look for armor class spelled out
    		_,_,sAC1,sAC2 = string.find(strStatblock,"[aA][rR][mM][oO][rR]%s*[cC][lL][aA][sS][sS]:?%s*(%d+)%s*(.-);");
    	end
    	if sAC1 == nil then
    		sAC1 = 10;
    		sAC2 = "";
    	end
    	if sHP == nil then
    		_,_,sHP,sHD = string.find(strStatblock,"[hH][pP]:?%s*(%d+)%s*%((.-)%);?%s*");
    	end
    	if sHP == nil then
    		-- look for older hit point style 2d8+2 (11 hp)
    		_,_,sHP = string.find(strStatblock,"%((%d+) [hH][pP]");
    	end
    	if sHD == nil then
    		_,_,sHD = string.find(strStatblock,"[hH][dD]:?%s*(.-)%s*;");
    		_,_,sHD2 = string.find(strStatblock,"[hH][iI][tT]%s*[dD][iI][cC][eE]:?%s*(.-)%s*;");
    		sHD = getSmallest(sHD,sHD2);
    	end
    	setNodeValue(nodeNPC,"hp",sHP,"number",0);
    	setNodeValue(nodeNPC,"ac",stripCRLF(sAC1 .. sAC2), "string","0");
    	setNodeValue(nodeNPC,"hd",stripCRLF(sHD), "string", "0");
    	
    	-- Saves
    	_,_,sFort = string.find(strStatblock,"[fF][oO][rR][tT]:?%s*%+%s*(%d+)");
    	_,_,sRef = string.find(strStatblock,"[rR][eE][fF]:?%s*%+%s*(%d+)");
    	_,_,sWill = string.find(strStatblock,"[wW][iI][lL][lL]:?%s*%+%s*(%d+)");
    	setNodeValue(nodeNPC,"fortitudesave",sFort,"number",0);
    	setNodeValue(nodeNPC,"reflexsave",sRef,"number",0);
    	setNodeValue(nodeNPC,"willsave",sWill,"number",0);
    	
    	-- Senses
    	_,_,sSenses = string.find(strStatblock,"[sS][eE][nN][sS][eE][sS]:?%s*(.-)%s*[aAdD][uUeE][rRfF][aAeE]");
    	_,_,sSenses2 = string.find(strStatblock,"[dD][eE][tT][eE][cC][tT][iI][oO][nN]%s*:?%-?%s*(.-)%s*[.;\n]");
    	sSenses = getSmallest(sSenses,sSenses2);
    	setNodeValue(nodeNPC,"senses",stripCRLF(sSenses),"string","");
    	
    	-- Initiative
    	_,_,sInit = string.find(strStatblock,"[iI][nN][iI][tT]:?%s*%+?%-?(%d+)");
    	setNodeValue(nodeNPC,"init",sInit,"number",0);
    	
    	-- Space / Reach
    	_,_,sSpace = string.find(strStatblock,"[sS][pP][aA][cC][eE]:?%s*(%d+)%s?[fF][tT]");
    	_,_,sReach = string.find(strStatblock,"[rR][eE][aA][cC][hH]:?%s*(%d+)%s?[fF][tT]");
    	if sSpace then
    		if sReach then
    			sSpaceReach = sSpace .. " ft./" .. sReach .. " ft.";
    		end
    	end
    	setNodeValue(nodeNPC,"spacereach",sSpaceReach,"string","5 ft./5 ft.");
    	
    	-- Attack
    	-- Replace cases like Crossbow, Heavy and Crossbow, Light in attack strings.
    	strStatblock = string.gsub(strStatblock,"%s+[oO][rR]%s*[\n]%s*"," or ");
    	strStatblock = string.gsub(strStatblock,"%s+[aA][nN][dD]%s*[\n]%s*"," and ");
    	strStatblock = string.gsub(strStatblock, "(%w+),%s?[hH][eE][aA][vV][yY]","Heavy %1");
    	strStatblock = string.gsub(strStatblock, "(%w+),%s?[lL][iI][gG][hH][tT]","Light %1");
    	ABUtility.Trace(strStatblock);
    	_,_,sAtk = string.find(strStatblock,"[mM][eE][lL][eE][eE]:?%s*(.-)%s*[sStT][aApP][aAcCeE][cCtT][eEiI]");
    	_,_,sAtk2 = string.find(strStatblock,"[aA][tT][tT][aA][cC][kK]:+%s*(.-)%s*;");
    	sAtk = getSmallest(sAtk,sAtk2);
    	if sAtk then
    		sAtk = string.gsub(sAtk,"\n[rR][aA][nN][gG][eE][dD]"," or Ranged");
    		--sAtk = ABUtility.stringReplace(sAtk,")%s*ranged"," or");
    	end
    	if sAtk == nil then
    		_,_,sAtk = string.find(strStatblock,"[mM][eE][lL][eE][eE]%s*(.-)%s*[sS][pP][aAeE][cC][eEiI]");
    	end
    	if sAtk == nil then
    		_,_,sAtk = string.find(strStatblock,"[mMrR][eEaA][lLnN][eEgG][eEeE][dD]*%s*(.-)%s*[.;]");
    	end
    	setNodeValue(nodeNPC,"atk",ABUtility.stringReplace(stripCRLF(sAtk),","," or "),"string","");
    	setNodeValue(nodeNPC,"fullatk",ABUtility.stringReplace(stripCRLF(sAtk),","," and "),"string","");
    	
    	-- Aura (may be missing from many statblocks
    	_,_,sAura = string.find(strStatblock,"[aA][uU][rR][aA]:?%s+(.-)[)]");
    	if sAura then
    		sAura = sAura .. ")";
    	end
    	if sAura == nil then 
    		_,_,sAura = string.find(strStatblock,"[aA][uU][rR][aA]:?%s+(.-);");
    	end
    	setNodeValue(nodeNPC,"aura",stripCRLF(sAura),"string","");
    	
    	-- Speed
    	_,_,sSpeed = string.find(strStatblock,"[sS][pP][eE]*[eE]*[dD]:?%s*(.-)%s*;?%s*[mMrR][eEaA][lLnN][eEgG][eE]");
    	_,_,sSpeed2 = string.find(strStatblock,"[sS][pP][eE]*[eE]*[dD]:?%s*(.-)%s*;");
    	sSpeed = getSmallest(sSpeed,sSpeed2);
    	setNodeValue(nodeNPC,"speed",stripCRLF(sSpeed),"string","");
    	
    	-- BAB, CM and CMD
    	_,_,sBAB = string.find(strStatblock,"[bB][aA][sS][eE] [aA][tT][kK]:?%s*%+?(%d+);+%s*");
    	_,_,sCM = string.find(strStatblock,"[cC][mM][bB]:?%s*%+?(%d+);?%s*");
    	_,_,sCMD = string.find(strStatblock,"[cC][mM][dD]:?%s*%+?(.-)%s*[sSfF][kKeE][iIaA][lLtT]");
    	if sBAB then
    		sBABCMD = "+" .. sBAB;
    	else
    		sBABCMD = "-";
    	end
    	if sCM then
    		sBABCMD = sBABCMD .. "/+" .. sCM .. "; ";
    	else
    		sBABCMD = sBABCMD .. "/-; ";
    	end
    	if sCMD then
    		sBABCMD = sBABCMD .. "CMD " .. sCMD;
    	end
    	setNodeValue(nodeNPC,"babgrp",sBABCMD,"string","");
    	
    	-- Feats
    	_,_,sFeats = string.find(strStatblock,"[fF][eE][aA][tT][sS]:?%s*(.-)%s*[eEsS][cCkK][oOiI][lL][oOlL][gGsS]:?");
    	_,_,sFeats2 = string.find(strStatblock,"[fF][eE][aA][tT][sS]:?%s*(.-)%s*;%s*");
    	if sFeats2 then
    		sFeats = getSmallest(sFeats, sFeats2);
    	end
    	setNodeValue(nodeNPC,"feats",stripCRLF(sFeats),"string","");
    	
    	-- Skills
    	_,_,sSkills = string.find(strStatblock,"[sS][kK][iI][lL][lL][sS]:?(.-)%s*[lL][aA][nN][gG][uU][aA][gG][eE][sS]");
    	if sSkills then
    		setNodeValue(nodeNPC,"skills",stripCRLF(sSkills),"string","");
    	else
    		_,_,sSkills = string.find(strStatblock,"[sS][kK][iI][lL][lL][sS]:?(.-)[sS][qQ]:?%s+");
    	end
    	_,_,sSkills2 = string.find(strStatblock,"[sS][kK][iI][lL][lL][sS]:?(.-)%s*;%s*");
    	if sSkills2 then
    		sSkills = getSmallest(sSkills,sSkills2);
    	end
    	_,_,sSkills2 = string.find(strStatblock,"[sS][kK][iI][lL][lL][sS]:?(.-)[pP][oO][sS][sS][eE][sS][iI][oO][nN]");
    	if sSkills2 then
    		sSkills = getSmallest(sSkills, sSkills2);
    	end
    	if sSkills then
    		setNodeValue(nodeNPC,"skills",stripCRLF(sSkills),"string","");
    	end
    Attached Files Attached Files

  5. #5
    ddavison's Avatar
    Join Date
    Sep 2008
    Posts
    6,134
    Blog Entries
    21
    Part 2:

    Code:
    	-- SQ
    	_,_,sSQ1 = string.find(strStatblock,"SQ:?%s*(.-)%s*[gG][eE][aA][rR]:?%s*");
    	_,_,sSQ2 = string.find(strStatblock,"SQ:?%s*(.-)%s*[eE][cC][oO][lL][oO][gG][yY]");	
    	_,_,sSQ3 = string.find(strStatblock,"SQ:?%s*(.-)%s*[sS][pP][eE][cC][iI][aA][lL] [aA][bB][iI][lL][iI][tT][iI][eE][sS]");
    	_,_,sSQ4 = string.find(strStatblock,"SQ:?%s*(.-)%s*[oO][fF][fF][eE][nN][sS][eE]");	
    	sSQ = getSmallest(sSQ1, sSQ2);
    	sSQ = getSmallest(sSQ, sSQ3);
    	sSQ = getSmallest(sSQ, sSQ4);
    	_,_,sSQ4 = string.find(strStatblock,"SQ:?%s*(.-)%s*;");	
    	sSQ = getSmallest(sSQ, sSQ4);
    	if sSQ then
    		sSQ = sSQ .. "; ";
    	end
    	setNodeValue(nodeNPC,"specialqualities",sSQ,"string","");
    	
    	_,_,sSA = string.find(strStatblock,"[sS][pP][eE][cC][iI][aA][lL] [aA][tT][tT][aA][cC][kK][sS]:?%s*(.-)%s*[sS][tT][aA][tT][iI][sS][tT][iI][cC][sS]");
    	setNodeValue(nodeNPC,"specialattacks",sSA,"string","");
    	
    	-- Languages
    	_,_,sLanguages = string.find(strStatblock,"[lL][aA][nN][gG][uU][aA][gG][eE][sS]*:?%s*(.-)[;.]");
    	_,_,sLanguages2 = string.find(strStatblock,"[lL][aA][nN][gG][uU][aA][gG][eE][sS]*:?%s*(.-)%s*SQ");
    	sLanguages = getSmallest(sLanguages,sLanguages2);
    	_,_,sLanguages2 = string.find(strStatblock,"[lL][aA][nN][gG][uU][aA][gG][eE][sS]*:?%s*(.-)%s*[dD][eE][fF][eE][nN][sS][eE]");
    	if sLanguages2 then
    		sLanguages = getSmallest(sLanguage,sLanguages2);
    	end
    	setNodeValue(nodeNPC,"languages",stripCRLF(sLanguages),"string","");
    	
    	-- Environment
    	_,_,sEnv = string.find(strStatblock,"[eE][nN][vV][iI][rR][oO][nN][mM][eE][nN][tT]:?%s*(.-)%s*[oO][rR][gG][aA][nN][iI][zZ][aA][tT][iI][oO][nN]");
    	if not sEnv then
    		_,_,sEnv = string.find(strStatblock,"[eE][nN][vV][iI][rR][oO][nN][mM][eE][nN][tT]:?%s*(.-)[.;]");
    	end
    	_,_,sEnv2 = string.find(strStatblock,"[eE][nN][vV][iI][rR][oO][nN][mM]?[eE]?[nN]?[tT]?:?%s*(.-)%s*;");
    	sEnv = getSmallest(sEnv,sEnv2);
    	setNodeValue(nodeNPC,"environment",stripCRLF(sEnv),"string","");
    	
    	-- Organization
    	_,_,sOrg = string.find(strStatblock,"[oO][rR][gG][aA][nN][iI][zZ][aA][tT][iI][oO][nN]:?%s*(.-)%s*[tT][rR][eE][aA][sS][uU][rR][eE]");
    	if not sOrg then
    		_,_,sOrg = string.find(strStatblock,"[oO][rR][gG][aA][nN][iI][zZ][aA][tT][iI][oO][nN]:?%s*(.-)[.;]");
    	end
    	_,_,sOrg2 = string.find(strStatblock,"[oO][rR][gG][aA][nN][iI][zZ][aA][tT][iI][oO][nN]:?%s*(.-)%s*;");
    	if sOrg2 then
    		sOrg = getSmallest(sOrg,sOrg2);
    	end
    	setNodeValue(nodeNPC,"organization",stripCRLF(sOrg),"string","");
    	
    	-- Treasure
    	_,_,sTreasure = string.find(strStatblock,"[tT][rR][eE][aA][sS][uU][rR][eE]:?%s*(.-)[.;]");
    	_,_,sTreasure2 = string.find(strStatblock,"[tT][rR][eE][aA][sS][uU][rR][eE]:?%s*(.-)$");
    	_,_,sTreasure3 = string.find(strStatblock,"[tT][rR][eE][aA][sS][uU][rR][eE]:?%s*(.-)%s*[sS][pP][eE][cC][iI][aA][lL] [aA][bB]");
    	sTreasure = getSmallest(sTreasure,sTreasure2);
    	sTreasure = getSmallest(sTreasure,sTreasure3);
    	if sTreasure == nil then
    		_,_,sTreasure = string.find(strStatblock,"[pP][oO][sS][sS][eE][sS][sS][iI][oO][nN][sS]:?%s*(.-)[.;]");
    		_,_,sTreasure2 = string.find(strStatblock,"[pP][oO][sS][sS][eE][sS][sS][iI][oO][nN][sS]:?%s*(.-)$");
    		sTreasure = getSmallest(sTreasure,sTreasure2);
    	end
    	if sTreasure == nil then
    		_,_,sTreasure = string.find(strStatblock,"[gG][eE][aA][rR]:?%s*(.-)[.;]");
    		_,_,sTreasure2 = string.find(strStatblock,"[gG][eE][aA][rR]:?%s*(.-)$");
    		sTreasure = getSmallest(sTreasure,sTreasure2);		
    		_,_,sTreasure2 = string.find(strStatblock,"[gG][eE][aA][rR]:?%s*(.-)[sS][pP][eE][cC][iI][aA][lL] [aA][bB][iI][lL]");
    		sTreasure = getSmallest(sTreasure,sTreasure2);		
    	end
    	setNodeValue(nodeNPC,"treasure",stripCRLF(sTreasure),"string","");
    	
    	-- DR, Immune, Resist, SR, Weakness
    	-- Immunities
    	_,_,sImmune = string.find(strStatblock,"[iI][mM][mM][uU][nN][eE]:?%s*(.-)[.;\n]");
    	_,_,sImmune2 = string.find(strStatblock,"[iI][mM][mM][uU][nN][eE]:?%s*(.-)%s*[oO][fF][eE][nN][sS][eE]");
    	sImmune = getSmallest(sImmune,sImmune2);
    	if sImmune then
    		sImmune = " Immune " .. sImmune .. "; ";
    	end
    	appendNodeValue(nodeNPC,"specialqualities",stripCRLF(sImmune));
    	-- Resistances
    	_,_,sResist = string.find(strStatblock,"[rR][eE][sS][iI][sS][tT]:?%s*(.-)[.;]");
    	_,_,sResist2 = string.find(strStatblock,"[rR][eE][sS][iI][sS][tT]:?%s*(.-)%s*[oO][fF][eE][nN][sS][eE]");
    	sResist = getSmallest(sResist,sResist2);
    	if sResist then
    		sResist = " Resist " .. sResist .. "; ";
    	end
    	appendNodeValue(nodeNPC,"specialqualities",stripCRLF(sResist));	
    	-- Weaknesses
    	_,_,sWeak = string.find(strStatblock,"[wW][eE][aA][kK][nN][eE][sS][sS][eE]?[sS]?:?%s*(.-)[.;]");
    	_,_,sWeak2 = string.find(strStatblock,"[wW][eE][aA][kK][nN][eE][sS][sS][eE]?[sS]?:?%s*(.-)%s*[oO][fF][eE][nN][sS][eE]");
    	sWeak = getSmallest(sWeak,sWeak2);
    	if sWeak then
    		sWeak = " Weakness " .. sWeak .. "; ";
    	end
    	appendNodeValue(nodeNPC,"specialqualities",stripCRLF(sWeak));	
    	-- DR
    	_,_,sDR = string.find(strStatblock,"DR:?%s*(.-)[.;]");
    	_,_,sDR2 = string.find(strStatblock,"DR:?%s*(.-)%s*[oO][fF][eE][nN][sS][eE]");
    	sDR = getSmallest(sDR,sDR2);
    	if sDR then
    		sDR = " DR " .. sDR .. "; ";
    	end
    	appendNodeValue(nodeNPC,"specialqualities",stripCRLF(sDR));	
    	-- SR
    	_,_,sSR = string.find(strStatblock,"SR:?%s*(.-)[.;]");
    	_,_,sSR2 = string.find(strStatblock,"SR:?%s*(.-)%s*[oO][fF][eE][nN][sS][eE]");
    	sSR = getSmallest(sSR,sSR2);
    	if sSR then
    		sSR = " SR " .. sSR .. "; ";
    	end	
    	appendNodeValue(nodeNPC,"specialqualities",stripCRLF(sSR));	
    	
    	-- Type
    	_,_,sAlignment,sType = string.find(strStatblock,"%s+([LCN][EGN ])%s*(.-)%s*[dDiI][eEnN][fFiItT][eEtT]");
    	_,_,sName2,sType2 = string.find(strStatblock,"^(.-)%s*[:](.-);");
    	sType = getSmallest(sType,sType2);
    	if sAlignment and sType then
    		sType = sAlignment .. " " .. sType;
    	end
    	setNodeValue(nodeNPC,"type",stripCRLF(sType),"string","");
    	setNodeValue(nodeNPC,"alignment",sAlignment,"string","");
    	
    	-- Description
    	strStatblock = DB.getValue(templateFactory,"statblock","");
    	if strStatblock then
    		strStatblock = 	"<linklist><link class=\"\" recordname=\"\">Image</link></linklist>" .. strStatblock;
    	end
    	setNodeValue(nodeNPC,"text",strStatblock,"formattedtext","<p></p>");
    	
    	-- Token set to defaul letter of first character in name
    	if sName then
    		_,_,sLetter = string.find(sName,"^(%a)");
    		if sLetter then
    			sLetter = "tokens/Medium/" .. sLetter .. ".png@Letter Tokens";
    			setNodeValue(nodeNPC,"token",sLetter,"token","");
    		end
    	end
    	
    end

  6. #6
    Quote Originally Posted by Trenloe View Post
    Use the Paizo statblock format. Info here: https://legacy.aonprd.com/bestiary/introduction.html

    Also see the video on the product page for some guidelines: https://www.fantasygrounds.com/store...hp?id=GRR2901e
    Yeah, that's clearly the thought process I see throughout the site. I just don't want to use the PF format. I was hoping it was just a minor alteration, but putting 3.5 into PF format takes slightly longer than it does for me to enter stats by hand. Maybe I type faster than I can highlight, cut, paste, cleanup. Idk, but it's negative value for me to try and convert to PF overall.

    So I gave up and started altering a pathfinder import tool. Which is kinda hard, because idk enough about programming in any language. I just barely grasp the entry-level concepts. So I can walk, but I'm blind and deaf. But I'm grabbing 80% of everything (which is nice since i started at 0%) and making steady progress.

    Damned's videos should be stickied just about everywhere. By far the best resource I've come across in my search for diy FG problem solving.

    I also watched those videos you linked, it's just putting PF creatures into a PF import tool. Which is not what I'm trying to do. Unless someone made a tool to format it correctly form 3.5. Then maybe, as long as the end result is 3.5 format and not PF. There was one part in a third video (I think, I'm very tired) not shown on the product page, but buried on their YT channel, where he struggled with a 3.5 stat block. I can only assume that path was abandoned as the feature is not very usable in the 3.5 ruleset as is. Just a little disappointed that it says 3.5 compatible, but only if you convert everything to PF. Which isn't really 3.5. The templates were still worth the purchase imo. Just a slight bummer is all.

    Frankencoding will only get me so far I'm sure.

  7. #7
    Quote Originally Posted by ddavison View Post
    Part 2:

    Code:
    	-- SQ
    	_,_,sSQ1 = string.find(strStatblock,"SQ:?%s*(.-)%s*[gG][eE][aA][rR]:?%s*");
    	_,_,sSQ2 = string.find(strStatblock,"SQ:?%s*(.-)%s*[eE][cC][oO][lL][oO][gG][yY]");	
    	_,_,sSQ3 = string.find(strStatblock,"SQ:?%s*(.-)%s*[sS][pP][eE][cC][iI][aA][lL] [aA][bB][iI][lL][iI][tT][iI][eE][sS]");
    	_,_,sSQ4 = string.find(strStatblock,"SQ:?%s*(.-)%s*[oO][fF][fF][eE][nN][sS][eE]");	
    	sSQ = getSmallest(sSQ1, sSQ2);
    	sSQ = getSmallest(sSQ, sSQ3);
    	sSQ = getSmallest(sSQ, sSQ4);
    	_,_,sSQ4 = string.find(strStatblock,"SQ:?%s*(.-)%s*;");	
    	sSQ = getSmallest(sSQ, sSQ4);
    	if sSQ then
    		sSQ = sSQ .. "; ";
    	end
    	setNodeValue(nodeNPC,"specialqualities",sSQ,"string","");
    	
    	_,_,sSA = string.find(strStatblock,"[sS][pP][eE][cC][iI][aA][lL] [aA][tT][tT][aA][cC][kK][sS]:?%s*(.-)%s*[sS][tT][aA][tT][iI][sS][tT][iI][cC][sS]");
    	setNodeValue(nodeNPC,"specialattacks",sSA,"string","");
    	
    	-- Languages
    	_,_,sLanguages = string.find(strStatblock,"[lL][aA][nN][gG][uU][aA][gG][eE][sS]*:?%s*(.-)[;.]");
    	_,_,sLanguages2 = string.find(strStatblock,"[lL][aA][nN][gG][uU][aA][gG][eE][sS]*:?%s*(.-)%s*SQ");
    	sLanguages = getSmallest(sLanguages,sLanguages2);
    	_,_,sLanguages2 = string.find(strStatblock,"[lL][aA][nN][gG][uU][aA][gG][eE][sS]*:?%s*(.-)%s*[dD][eE][fF][eE][nN][sS][eE]");
    	if sLanguages2 then
    		sLanguages = getSmallest(sLanguage,sLanguages2);
    	end
    	setNodeValue(nodeNPC,"languages",stripCRLF(sLanguages),"string","");
    	
    	-- Environment
    	_,_,sEnv = string.find(strStatblock,"[eE][nN][vV][iI][rR][oO][nN][mM][eE][nN][tT]:?%s*(.-)%s*[oO][rR][gG][aA][nN][iI][zZ][aA][tT][iI][oO][nN]");
    	if not sEnv then
    		_,_,sEnv = string.find(strStatblock,"[eE][nN][vV][iI][rR][oO][nN][mM][eE][nN][tT]:?%s*(.-)[.;]");
    	end
    	_,_,sEnv2 = string.find(strStatblock,"[eE][nN][vV][iI][rR][oO][nN][mM]?[eE]?[nN]?[tT]?:?%s*(.-)%s*;");
    	sEnv = getSmallest(sEnv,sEnv2);
    	setNodeValue(nodeNPC,"environment",stripCRLF(sEnv),"string","");
    	
    	-- Organization
    	_,_,sOrg = string.find(strStatblock,"[oO][rR][gG][aA][nN][iI][zZ][aA][tT][iI][oO][nN]:?%s*(.-)%s*[tT][rR][eE][aA][sS][uU][rR][eE]");
    	if not sOrg then
    		_,_,sOrg = string.find(strStatblock,"[oO][rR][gG][aA][nN][iI][zZ][aA][tT][iI][oO][nN]:?%s*(.-)[.;]");
    	end
    	_,_,sOrg2 = string.find(strStatblock,"[oO][rR][gG][aA][nN][iI][zZ][aA][tT][iI][oO][nN]:?%s*(.-)%s*;");
    	if sOrg2 then
    		sOrg = getSmallest(sOrg,sOrg2);
    	end
    	setNodeValue(nodeNPC,"organization",stripCRLF(sOrg),"string","");
    	
    	-- Treasure
    	_,_,sTreasure = string.find(strStatblock,"[tT][rR][eE][aA][sS][uU][rR][eE]:?%s*(.-)[.;]");
    	_,_,sTreasure2 = string.find(strStatblock,"[tT][rR][eE][aA][sS][uU][rR][eE]:?%s*(.-)$");
    	_,_,sTreasure3 = string.find(strStatblock,"[tT][rR][eE][aA][sS][uU][rR][eE]:?%s*(.-)%s*[sS][pP][eE][cC][iI][aA][lL] [aA][bB]");
    	sTreasure = getSmallest(sTreasure,sTreasure2);
    	sTreasure = getSmallest(sTreasure,sTreasure3);
    	if sTreasure == nil then
    		_,_,sTreasure = string.find(strStatblock,"[pP][oO][sS][sS][eE][sS][sS][iI][oO][nN][sS]:?%s*(.-)[.;]");
    		_,_,sTreasure2 = string.find(strStatblock,"[pP][oO][sS][sS][eE][sS][sS][iI][oO][nN][sS]:?%s*(.-)$");
    		sTreasure = getSmallest(sTreasure,sTreasure2);
    	end
    	if sTreasure == nil then
    		_,_,sTreasure = string.find(strStatblock,"[gG][eE][aA][rR]:?%s*(.-)[.;]");
    		_,_,sTreasure2 = string.find(strStatblock,"[gG][eE][aA][rR]:?%s*(.-)$");
    		sTreasure = getSmallest(sTreasure,sTreasure2);		
    		_,_,sTreasure2 = string.find(strStatblock,"[gG][eE][aA][rR]:?%s*(.-)[sS][pP][eE][cC][iI][aA][lL] [aA][bB][iI][lL]");
    		sTreasure = getSmallest(sTreasure,sTreasure2);		
    	end
    	setNodeValue(nodeNPC,"treasure",stripCRLF(sTreasure),"string","");
    	
    	-- DR, Immune, Resist, SR, Weakness
    	-- Immunities
    	_,_,sImmune = string.find(strStatblock,"[iI][mM][mM][uU][nN][eE]:?%s*(.-)[.;\n]");
    	_,_,sImmune2 = string.find(strStatblock,"[iI][mM][mM][uU][nN][eE]:?%s*(.-)%s*[oO][fF][eE][nN][sS][eE]");
    	sImmune = getSmallest(sImmune,sImmune2);
    	if sImmune then
    		sImmune = " Immune " .. sImmune .. "; ";
    	end
    	appendNodeValue(nodeNPC,"specialqualities",stripCRLF(sImmune));
    	-- Resistances
    	_,_,sResist = string.find(strStatblock,"[rR][eE][sS][iI][sS][tT]:?%s*(.-)[.;]");
    	_,_,sResist2 = string.find(strStatblock,"[rR][eE][sS][iI][sS][tT]:?%s*(.-)%s*[oO][fF][eE][nN][sS][eE]");
    	sResist = getSmallest(sResist,sResist2);
    	if sResist then
    		sResist = " Resist " .. sResist .. "; ";
    	end
    	appendNodeValue(nodeNPC,"specialqualities",stripCRLF(sResist));	
    	-- Weaknesses
    	_,_,sWeak = string.find(strStatblock,"[wW][eE][aA][kK][nN][eE][sS][sS][eE]?[sS]?:?%s*(.-)[.;]");
    	_,_,sWeak2 = string.find(strStatblock,"[wW][eE][aA][kK][nN][eE][sS][sS][eE]?[sS]?:?%s*(.-)%s*[oO][fF][eE][nN][sS][eE]");
    	sWeak = getSmallest(sWeak,sWeak2);
    	if sWeak then
    		sWeak = " Weakness " .. sWeak .. "; ";
    	end
    	appendNodeValue(nodeNPC,"specialqualities",stripCRLF(sWeak));	
    	-- DR
    	_,_,sDR = string.find(strStatblock,"DR:?%s*(.-)[.;]");
    	_,_,sDR2 = string.find(strStatblock,"DR:?%s*(.-)%s*[oO][fF][eE][nN][sS][eE]");
    	sDR = getSmallest(sDR,sDR2);
    	if sDR then
    		sDR = " DR " .. sDR .. "; ";
    	end
    	appendNodeValue(nodeNPC,"specialqualities",stripCRLF(sDR));	
    	-- SR
    	_,_,sSR = string.find(strStatblock,"SR:?%s*(.-)[.;]");
    	_,_,sSR2 = string.find(strStatblock,"SR:?%s*(.-)%s*[oO][fF][eE][nN][sS][eE]");
    	sSR = getSmallest(sSR,sSR2);
    	if sSR then
    		sSR = " SR " .. sSR .. "; ";
    	end	
    	appendNodeValue(nodeNPC,"specialqualities",stripCRLF(sSR));	
    	
    	-- Type
    	_,_,sAlignment,sType = string.find(strStatblock,"%s+([LCN][EGN ])%s*(.-)%s*[dDiI][eEnN][fFiItT][eEtT]");
    	_,_,sName2,sType2 = string.find(strStatblock,"^(.-)%s*[:](.-);");
    	sType = getSmallest(sType,sType2);
    	if sAlignment and sType then
    		sType = sAlignment .. " " .. sType;
    	end
    	setNodeValue(nodeNPC,"type",stripCRLF(sType),"string","");
    	setNodeValue(nodeNPC,"alignment",sAlignment,"string","");
    	
    	-- Description
    	strStatblock = DB.getValue(templateFactory,"statblock","");
    	if strStatblock then
    		strStatblock = 	"<linklist><link class=\"\" recordname=\"\">Image</link></linklist>" .. strStatblock;
    	end
    	setNodeValue(nodeNPC,"text",strStatblock,"formattedtext","<p></p>");
    	
    	-- Token set to defaul letter of first character in name
    	if sName then
    		_,_,sLetter = string.find(sName,"^(%a)");
    		if sLetter then
    			sLetter = "tokens/Medium/" .. sLetter .. ".png@Letter Tokens";
    			setNodeValue(nodeNPC,"token",sLetter,"token","");
    		end
    	end
    	
    end
    Thank you so much. I watch just about all your videos realted to any products I use on FG. I'll get right on trying to figure that all out. I appreciate it very much!

  8. #8
    [QUOTE=ddavison;416556]It looks like this one was a little light on the documentation for the statblock importer. It was tested with statblocks I could find at the time for 3.5E and Pathfinder, but I remember there being some finicky bits. Do you have a sample stat block you are trying to do?

    During the 3.5E era, it was hard to find any two companies or sites that did them the same.
    From this page: https://mikael.borjesson.net/dnd/mon...l,+Astral+Deva

    I see what you mean, that would make it very difficult. I never thought of all the other products out there. I stayed very close to just the wizards products and didn't notice any variations in stat blocks. Never had anything like FG before though, so wasn't paying attention either. I love this tool, I just want to understand it better =] (again, damned's videos are incredible.)

  9. #9
    ddavison's Avatar
    Join Date
    Sep 2008
    Posts
    6,134
    Blog Entries
    21
    Do you have a link to the stat blocks you are trying to import? It might be a common thing that they are doing that could be accounted for with a few quick changes.

  10. #10
    I don't have a link but it's the standard mm format and most of the core rules format. I think oozes are safe and not copyrighted (I hope?). This one comes from the planar Handbook.

    VOID OOZE
    Large Ooze (Extraplanar)
    Hit Dice: 10d10+80 (135 hp)
    Initiative: –5
    Speed: Fly 30 ft. (6 squares) (perfect)
    Armor Class: 4 (–5 Dex, –1 size), touch 4, flat-footed 4
    Base Attack/Grapple: +7/+16
    Attack: Slam +11 melee (2d4+5 plus 1d8 negative energy
    plus energy drain)
    Full Attack: Slam +11 melee (2d4+5 plus 1d8 negative
    energy plus energy drain)
    Space/Reach: 10 ft./5 ft.
    Special Attacks: Energy drain, engulf
    Special Qualities: Blindsight 60 ft., death ward, ooze traits,
    shadow shield, split
    Saves: Fort +11, Ref +0, Will +0
    Abilities: Str 20, Dex 1, Con 26, Int —, Wis 1, Cha 1
    Skills: —
    Feats: —
    Environment: Negative Energy Plane
    Organization: Solitary, midnight (2–7)
    Challenge Rating: 8
    Treasure: None
    Alignment: Always neutral
    Advancement: —
    Level Adjustment: —


    I have noticed what you mean that even within wizards own publications they vary a bit from this, but this is the format I see the most. Some other (I assume later publications) seem like they would fit with only a few tweaks like you mention. Some look almost exactly like PF format. I never knew there was such variance. TBH I'm going to put myself through the gauntlet and alter the NPC sheet a tiny bit, so I'm probably going to use your posts to guide me on making my own thing. But I have already learned a lot by hacking up cgen. Which I hope is ok. So I'm going to hack up those functions you pointed out and see what kind of abomination I can come up with. To handle importing that standard mm style statblock.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
DICE PACKS BUNDLE

Log in

Log in