PDA

View Full Version : Question about IF and IFT and changing them



rmilmine
April 13th, 2025, 03:54
In 3.5/pathfinder 1e IF and IFT have the following ALIGN, SIZE, TYPE, CUSTOM, healthy, Wounded, bloodied.
If I wanted to add something new to that list where should I start looking on where to add the code to add the new item?
Are the strings and a callback function in someway registered or is it more complicated with replacing functions in multiple managers_ files?
Some simple direction to start looking would be greatly appreciated.

Or if someone knows of an extension for pathfinder 1e that would allow something like the following: IFT: RANGE(>n) or IFT: RANGE(<=n), etc please point me that way.

Thanks.

Moon Wizard
April 13th, 2025, 19:59
Perform a search for those strings in the 3.5E ruleset to find where those are used/checked. I recommend using a text editor that can perform multi-file/folder searching. It would require an extension to override the functions that check those tags.

Regards,
JPG

rmilmine
April 13th, 2025, 20:03
I wasn't sure even which ruleset they were in, but 3.5 makes sense.

Thanks.

rmilmine
April 13th, 2025, 23:37
Another couple of questions.

Question 1:
I found the checkConditional function and I can add what I wanted there.
Looking at other items in that function I have rActor and rTarget.

I found in the API documentation the Token object and it's functions getDistanceBetween and getToken.

To use getDistanceBetween I need the token for both rActor and rTarget.

getToken requires containernodename, containerid being passed to it.
What do I need to do to get that information from rActor and rTarget?

Question 2:
getDistanceBetween says, "Returns the distance (in game system units) between two tokens. If the tokens specified are not in the same image value (i.e. map), then zero will be returned."
The return value it says would be, "The distance between the two specified tokens in game system units."

This sounds like it is returning the distance between the outside edges of the two tokens.
So, if both tokens overlap each other or one is completely within the area of the other what would this function return?

For visual within 3.5 or pathfinder you have an ogre that takes up a 10 foot by 10 foot square and a human that is 5 feet by 5 feet. The human could be within the area the ogre takes up.
Or if you have a huge dragon that is taking up 15 feet by 15 feet and the human again could be within the area that the dragon takes up.
Will it return 0 or will it return something that would indicate that there is overlap? like say a negative number?

Trenloe
April 14th, 2025, 02:47
Use CombatManager.getTokenFromCT(rActor); to get the token instance.

Have a look at the function getRangeBetween in the PFRPG2 ruleset scripts\manager_action_attack.lua file for example of how to get the range between rActor and rTarget. Hopefully this will get you going in the right direction.

I suggest you test out the various range calculation examples you mention.

rmilmine
April 15th, 2025, 00:14
Thank you. I figured it out.

I modified the checkConditional function in scripts\manager_effect_35E.lua file.


local sRangeCheck = sLower:match("^range%s*%(([^)]+)%)$"); -- added after the line getting a string for the variable sCustomCheck.

-- The following was added after the elseif sCustomCheck then
elseif sRangeCheck then
if not checkConditionalRangeHelper(rActor, sRangeCheck, rTarget) then
bReturn = false;
break;
end
-- The following function was added to the above file.
function checkConditionalRangeHelper(source, sEffect, target)
if not source or not target then
return false;
end
local sInequality, sRange = sEffect:match("^([<>=]+)(%d+)");
local nRange = tonumber(sRange);
if not nRange then
return false;
end

local sourceNode = ActorManager.getCTNode(source);
local targetNode = ActorManager.getCTNode(target);

if not sourceNode or not targetNode then
return false;
end;

local sourceToken = CombatManager.getTokenFromCT(sourceNode);
local targetToken = CombatManager.getTokenFromCT(targetNode);

if not sourceToken or not targetToken then
return false;
end

nTokenDistance = Token.getDistanceBetween(sourceToken, targetToken);

if sInequality == "=" and nRange == nTokenDistance then
return true;
elseif sInequality == ">" and nTokenDistance > nRange then
return true;
elseif sInequality == "<" and nTokenDistance < nRange then
return true;
elseif sInequality == ">=" and nTokenDistance >= nRange then
return true;
elseif sInequality == "<=" and nTokenDistance <= nRange then
return true;
end
return false;
end


If you want to use the above you are welcome to do so. I asked Kelrugem to add it to his extension, but I think it would be something useful for it to be in the base code for everyone.

MrDDT
April 16th, 2025, 05:05
Thank you. I figured it out.

I modified the checkConditional function in scripts\manager_effect_35E.lua file.


local sRangeCheck = sLower:match("^range%s*%(([^)]+)%)$"); -- added after the line getting a string for the variable sCustomCheck.

-- The following was added after the elseif sCustomCheck then
elseif sRangeCheck then
if not checkConditionalRangeHelper(rActor, sRangeCheck, rTarget) then
bReturn = false;
break;
end
-- The following function was added to the above file.
function checkConditionalRangeHelper(source, sEffect, target)
if not source or not target then
return false;
end
local sInequality, sRange = sEffect:match("^([<>=]+)(%d+)");
local nRange = tonumber(sRange);
if not nRange then
return false;
end

local sourceNode = ActorManager.getCTNode(source);
local targetNode = ActorManager.getCTNode(target);

if not sourceNode or not targetNode then
return false;
end;

local sourceToken = CombatManager.getTokenFromCT(sourceNode);
local targetToken = CombatManager.getTokenFromCT(targetNode);

if not sourceToken or not targetToken then
return false;
end

nTokenDistance = Token.getDistanceBetween(sourceToken, targetToken);

if sInequality == "=" and nRange == nTokenDistance then
return true;
elseif sInequality == ">" and nTokenDistance > nRange then
return true;
elseif sInequality == "<" and nTokenDistance < nRange then
return true;
elseif sInequality == ">=" and nTokenDistance >= nRange then
return true;
elseif sInequality == "<=" and nTokenDistance <= nRange then
return true;
end
return false;
end


If you want to use the above you are welcome to do so. I asked Kelrugem to add it to his extension, but I think it would be something useful for it to be in the base code for everyone.


I've not tested your coding, but what happens if neither the target nor the attacker are on a map?

rmilmine
April 16th, 2025, 17:53
I've not tested your coding, but what happens if neither the target nor the attacker are on a map?

I believe that getTokenFromCT will return nil if either character/npc on the combat tracker are not on a map. Which means that the if not after the getTokenFromCT will return false. This would mean that the IFT is returning fasle and the rest of the effect after it will be ignored.

If both charactyers/npcs are on a map, but not the same one then, looking at the refrence material for the getDistanceBetween it will return zero if the tokens aren't on the same map. Being that zero is also returned for icons that are overlaping the code will end up treating IFT: Range(=0) to be the same as the Tokens not being on the same map.

I think that if both tokens are on a map but they aren't on the same map then the getDistanceBetween should return nil instead of zero as zero also means they are overlapping.

Moon Wizard
April 16th, 2025, 18:15
The Token.getDistanceBetween API already does that. I'll update the Image.getDistanceBetween and imagecontrol.getDistanceBetween APIs to do the same.

Regards,
JPG

rmilmine
April 16th, 2025, 18:46
The Token.getDistanceBetween API already does that. I'll update the Image.getDistanceBetween and imagecontrol.getDistanceBetween APIs to do the same.

Regards,
JPG

The reference material for Token.getDistanceBetween is out of date then as it says it returns Zero if the tokens are not on the same Image.
The code I posted then needs to check for nil.



function checkConditionalRangeHelper(source, sEffect, target)
if not source or not target then
return false;
end
local sInequality, sRange = sEffect:match("^([<>=]+)(%d+)");
if not sInequality or not sRange then
return false;
end
local nRange = tonumber(sRange);
if not nRange then
return false;
end

local sourceNode = ActorManager.getCTNode(source);
local targetNode = ActorManager.getCTNode(target);

if not sourceNode or not targetNode then
return false;
end;

local sourceToken = CombatManager.getTokenFromCT(sourceNode);
local targetToken = CombatManager.getTokenFromCT(targetNode);

if not sourceToken or not targetToken then
return false;
end

nTokenDistance = Token.getDistanceBetween(sourceToken, targetToken);

if not nTokenDistance then
return false;
end
if sInequality == "=" and nRange == nTokenDistance then
return true;
elseif sInequality == ">" and nTokenDistance > nRange then
return true;
elseif sInequality == "<" and nTokenDistance < nRange then
return true;
elseif sInequality == ">=" and nTokenDistance >= nRange then
return true;
elseif sInequality == "<=" and nTokenDistance <= nRange then
return true;
end
return false;
end


Thanks for the help.

rmilmine
April 16th, 2025, 18:54
So checkConditionalRangeHelper should look like this:



function checkConditionalRangeHelper(source, sEffect, target)
if not source or not target then
return false;
end
local sInequality, sRange = sEffect:match("^([<>=]+)(%d+)");
if not sInequality or not sRange then
return false;
end
local nRange = tonumber(sRange);
if not nRange then
return false;
end

local sourceNode = ActorManager.getCTNode(source);
local targetNode = ActorManager.getCTNode(target);

if not sourceNode or not targetNode then
return false;
end;

local sourceToken = CombatManager.getTokenFromCT(sourceNode);
local targetToken = CombatManager.getTokenFromCT(targetNode);

if not sourceToken or not targetToken then
return false;
end

nTokenDistance = Token.getDistanceBetween(sourceToken, targetToken);

if not nTokenDistance THEN
return false;
end
if sInequality == "=" and nRange == nTokenDistance then
return true;
elseif sInequality == ">" and nTokenDistance > nRange then
return true;
elseif sInequality == "<" and nTokenDistance < nRange then
return true;
elseif sInequality == ">=" and nTokenDistance >= nRange then
return true;
elseif sInequality == "<=" and nTokenDistance <= nRange then
return true;
end
return false;
end


Every variable is now checked after trying to retrieve it's data. If the variables values is nil after doing so the function returns false.
If all the variables have data in them, then the function returns true based on the if statements at the end, or it returns false if none of the if statements are true.

Moon Wizard
April 17th, 2025, 00:27
Docs updated. Note that the changes for Image/imagecontrol returning nil are only available in v4.7.0+.

Regards,
JPG

rmilmine
April 17th, 2025, 00:45
Thanks Moon Wizard.

Again, if you think that having this would be good in the base code for 3.5/Pathfinder or any other game you want it in you are welcome to use this code.

Moon Wizard
April 17th, 2025, 00:54
Appreciate that. Definitely something that I think would be useful; but I was trying to wait until I had time for some of the prototypes I had to allow easier registration of these sorts of checks.

Regards,
JPG

rmilmine
April 17th, 2025, 01:16
I was thinking that having something that registers effects tags along with say tag type and possibly a call back function would be kinda nice for doing effects. Just not sure how efficient it would be.