Thread: NPC User Guide
-
February 10th, 2018, 23:49 #11
Supreme Deity
- Join Date
- Mar 2007
- Posts
- 20,561
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
-
February 11th, 2018, 00:01 #12
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.
-
February 11th, 2018, 01:30 #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.
-
February 11th, 2018, 13:53 #14
- Join Date
- Aug 2011
- Posts
- 18
>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.
-
February 11th, 2018, 14:51 #15
- Join Date
- Aug 2011
- Posts
- 18
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);
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 14:52. Reason: misspelling
-
February 11th, 2018, 18:49 #16
- Join Date
- Aug 2011
- Posts
- 18
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);
Code:function parseWords(s, extra_delimiters) local delim = "^%w%+%-'’"; if extra_delimiters then delim = delim .. extra_delimiters; end return split(s, delim, true); end
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
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
-
February 13th, 2018, 23:49 #17
- Join Date
- Aug 2011
- Posts
- 18
And, I'm on my own from this point. QED regarding customer care.
-
February 14th, 2018, 00:56 #18
Supreme Deity
- Join Date
- Mar 2007
- Posts
- 20,561
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
-
February 17th, 2018, 21:08 #19
- Join Date
- Aug 2011
- Posts
- 18
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
-
February 17th, 2018, 21:52 #20
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...
Thread Information
Users Browsing this Thread
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks