Fantasy Grounds Fridays Pre
Page 2 of 3 First 123 Last

Thread: NPC User Guide

  1. #11
    I think that the best answer still is to use the examples from the OGL, and customize to your use in exactly the same format.

    While I understand what you are asking, it's not straightforward or very understandable to represent a word-parsing state machine as a written description, which really just ends up being a bunch of examples of word order from the OGL.

    If you would like to generate the level of documentation you would like, I can point out the relevant code sections for you to peruse.
    rulesets/3.5E/scripts/manager_actor2.lua: isCreatureType, isSize, isAlignment
    rulesets/3.5E/scripts/manager_combat2.lua: addNPC

    Regards,
    JPG

  2. #12
    ddavison's Avatar
    Join Date
    Sep 2008
    Posts
    5,176
    Blog Entries
    21
    I completely get what you are saying. That doesn't exist, unfortunately. The rules were set up by non-techie folks and then used by non-techie folks whenever they created new content. The LUA scripts are open source if you really want to dig in, but most people just care that the monsters from a published book work or not.

  3. #13
    FG's PF/3.5 ruleset does some merging.

    Immunity, Reistances, DR, SR and such are all in the 'SQ' field.

    It's not clear compared to say the 5e sheet which has fields for each discrete detail. I think this is a carry over from 3.5, but it's too far ingrained in the system to change as there's a bunch of stuff out there that expect this behavior now.

    It does need to be documented though.

  4. #14
    >Exactly the same format
    It isn't just word order as we have been discussing. It is an exact (though I agree slightly variation-tolerant) vocabulary, set of delimiters and other structure that is compatible with the regular expressions you have written into the scripts. Thanks for the code snippets. I'm still disappointed that your staff can't be bothered to create this documentation, but this is exactly what I need to do it for myself.

  5. #15

    More on damage reduction example

    Okay, so the code for the damage reduction parser seems to be what is included below. I have some basic questions; Lua isn't a language I use.

    The SQ and only the SQ string is parsed for a possible indication that there is damage reduction. This is part of an SQ words while loop, so theoretically multiple instances of a given concept, e.g. DR could be ingested.

    The first question is how the StringManager function works.
    I went to https://github.com/joshuha/Fantasy-G...master/scripts, but I'm not sure which core script this is included in (or if it is a Lua builtin). The reason that this is important is that you can't tell from the local context how the isWord method defines a word. That is important to know to help understand what delimiters work. The key line appears to be

    Code:
    local aSQWords = StringManager.parseWords(sSpecialQualities);
    If you can point me to how words are defined, the rest looks fairly straightforward. In particular, how would this line be parsed?

    Code:
    can't be knocked back (bastion boots); DR 5/-; DR: cold 10, evil 10; damage reduction evil 10, cold 10, dr magic 10, slashing 10, invisibility

    The recognition of a word as damage reduction appears to be a string match with "dr" (case?) or "damage" AND "reduction" in any order. The script then creates a table of DREffects by type. It looks like the last-ingested DR of any given type would be put into the table (not a sum and not the largest).

    There is a list of canonical damage types (DataCommon.dmgtypes) plus some syntactical exceptions like "cold iron", and ruleset exceptions, e.g. magic and epic. And and or appear to do the same thing.










    Code:
    -- DAMAGE REDUCTION
    		elseif StringManager.isWord(aSQWords[i], "dr") or (StringManager.isWord(aSQWords[i], "damage") and StringManager.isWord(aSQWords[i+1], "reduction")) then
    			if aSQWords[i] ~= "dr" then
    				i = i + 1;
    			end
    			
    			if StringManager.isNumberString(aSQWords[i+1]) then
    				i = i + 1;
    				local sDRAmount = aSQWords[i];
    				local aDRTypes = {};
    				
    				while aSQWords[i+1] do
    					if StringManager.isWord(aSQWords[i+1], { "and", "or" }) then
    						table.insert(aDRTypes, aSQWords[i+1]);
    					elseif StringManager.isWord(aSQWords[i+1], { "epic", "magic" }) then
    						table.insert(aDRTypes, aSQWords[i+1]);
    						table.insert(aAddDamageTypes, aSQWords[i+1]);
    					elseif StringManager.isWord(aSQWords[i+1], "cold") and StringManager.isWord(aSQWords[i+2], "iron") then
    						table.insert(aDRTypes, "cold iron");
    						i = i + 1;
    					elseif StringManager.isWord(aSQWords[i+1], DataCommon.dmgtypes) then
    						table.insert(aDRTypes, aSQWords[i+1]);
    					else
    						break;
    					end
    
    					i = i + 1;
    				end
    				
    				local sDREffect = "DR: " .. sDRAmount;
    				if #aDRTypes > 0 then
    					sDREffect = sDREffect .. " " .. table.concat(aDRTypes, " ");
    				end
    				table.insert(aEffects, sDREffect);
    			end
    Last edited by dradams; February 11th, 2018 at 15:52. Reason: misspelling

  6. #16
    More script diving. In the CoreRPG.pak I found the script manager_string.lua. I presume that this is the code for the string parsers.

    Given this line in manager_combat2.lua

    Code:
    local aSQWords = StringManager.parseWords(sSpecialQualities);
    I presume that this section from manager_string.lua parses the line

    Code:
    function parseWords(s, extra_delimiters)
    	local delim = "^%w%+%-'’";
    	if extra_delimiters then
    		delim = delim .. extra_delimiters;
    	end
    	return split(s, delim, true); 
    end
    Given that no extra delimiters are passed, does this mean that anything is a delimiter if it is not an a-zA-Z0-9 (%w), a plus sign, a minus sign, a hyphen, a single quote, or a backtick? If that is true, the array of words from this example

    Code:
    can't be knocked back (bastion boots); DR 5/-; DR: 10 cold, evil 10 dr 10 cold and evil or adamantine, bludgeoning and piercing 10, evil 10; damage reduction 5 evil cold dr magic 10, slashing 5, invisibility
    would be

    can't
    be
    knocked
    back
    bastion
    boots
    dr [because of the prior string.lower call]
    5
    -
    dr
    10
    cold
    evil
    10
    dr
    10
    cold
    and
    evil
    or
    adamantine
    bludgeoning
    piercing
    10
    evil
    10
    damage
    reduction
    5
    evil
    cold
    dr
    magic
    10
    slashing
    5
    invisibility


    If that is right, then the effects table would have

    DR: 5
    DR: 10 cold evil
    DR: 10 cold and evil or adamantine bludgeoning piercing
    DR: 5 evil cold

    What I am missing is the following:

    1. If where does the word pointer (i) get moved forward two words if the term "damage reduction" is detected?
    2. Is there a test to make sure that the word following dr is a number? I don't see an equivalent of what happens in Hardness:

    Code:
    if StringManager.isWord(aSQWords[i], "hardness") and StringManager.isNumberString(aSQWords[i+1]) then

  7. #17
    And, I'm on my own from this point. QED regarding customer care.

  8. #18
    Not sure what you're referencing. I must have missed your previous post, but it seems from the previous posts that you were digging into what you needed.

    Our official answer is that the code is designed to work with the core monsters as written, according to the official SRD stat blocks. If you want to create custom NPCs with similar special qualities, our official answer is to copy from an existing NPC and change out words. Other than that, we are not able to commit to the level of documentation that you are apparently looking for.

    If you are looking for more help digging into more detail, I'll be happy to answer your questions, if I have time. I'm also responsible for many other portions of the company, so I'm not always available.

    To answer your specific questions:
    * Your interpretation for StringManager.parseWords seems correct.
    * Each DR (or damage reduction) string is parsed as a separate effect.
    * The word pointer for "damage reduction" does not technically need to get moved two places, since "reduction" will not match "damage" on the next pass.
    * The test for the DR number string is a few lines below the test for "dr" or "damage reduction".

    Regards,
    JPG

  9. #19

    More on damage reduction examle

    Thanks for writing back. I'm sorry you changed forum software. This one seems a bit buggy.

    Anyway:

    Let's assume that the original damage reduction text looks like this


    Damage Reduction 10 good


    This gets parsed to this list


    damage
    reduction
    10
    good


    first, damage followed by reduction gets recongized. Let's step through the code

    Code:
    -- DAMAGE REDUCTION
      -- the next line gets us into the loop because damage is followed by reduction
      elseif StringManager.isWord(aSQWords[i], "dr") or (StringManager.isWord(aSQWords[i], "damage") and StringManager.isWord(aSQWords[i+1], "reduction")) then
       if aSQWords[i] ~= "dr" then --this condition is not true, therefore i still equals 1
        i = i + 1;
       end
       
       if (aSQWords[i+1]) then --something exists at aSQWords[2], so the condition is true
        i = i + 1; --i is now incremented to 2
        local sDRAmount = aSQWords[i]; --sDRAmount is now set to aSQWords[2] which is "reduction" 
        local aDRTypes = {};
        
        while aSQWords[i+1] do
         if StringManager.isWord(aSQWords[i+1], { "and", "or" }) then --this condition is not true
          table.insert(aDRTypes, aSQWords[i+1]);  
         elseif StringManager.isWord(aSQWords[i+1], { "epic", "magic" }) then --this condition is not true
          table.insert(aDRTypes, aSQWords[i+1]);  
          table.insert(aAddDamageTypes, aSQWords[i+1]); 
         elseif StringManager.isWord(aSQWords[i+1], "cold") and StringManager.isWord(aSQWords[i+2], "iron") then --this condition is not true
          table.insert(aDRTypes, "cold iron"); 
          i = i + 1;
         elseif StringManager.isWord(aSQWords[i+1], DataCommon.dmgtypes) then --aSQWords[2+1] is "10" which is not in the dmgtypes list
          table.insert(aDRTypes, aSQWords[i+1]);  
         else
          break; --nothing matched; we break out of the while loop
         end
    
         i = i + 1; 
        end
        
        local sDREffect = "DR: " .. sDRAmount; --we create a local variable sDREffect which now equals "DR: reduction"
        if #aDRTypes > 0 then --nothing was added to the aDRTypes list, so this condition is not true
         sDREffect = sDREffect .. " " .. table.concat(aDRTypes, " ");
        end
        table.insert(aEffects, sDREffect); --"DR: reduction" added to the end of the aEffects list
       end
    I presume that “DR: reduction” gets filtered out later, but this damage reduction format in the SQ text will never produce a correctly formatted effect. Is that right?

  10. #20
    damned's Avatar
    Join Date
    Mar 2011
    Location
    Australia
    Posts
    22,942
    Blog Entries
    1
    hey dradams keep up the good work.
    click on the theme at bottom left of the creen and choose FGResponsive for some reason it occasionally reverts back on some browsers...

    MoreCore - Generic Ruleset
    --- Projects ---
    Extensions | Tutorials | MoreCore | MoreCore Themes | Call of Cthulhu | Maelstrom | FG Con

Thread Information

Users Browsing this Thread

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

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Joshua Stream Pre

Log in

Log in