Thread: 5E - Token Height Indicator
-
May 4th, 2021, 03:59 #131I see your point, but that's also what happens in the 2D calculations as well - going diagonally 500 feet is 707 feet mathematically but 750 feet with the 3.5/PFRPG movement rules. They did that for simplicity, not for accuracy (and 5E goes even further). I'd prefer to follow that spirit and a quick search on people asking that question in a tabletop setting seems to agree with the formula I have. That being said, I'm easy - if there's enough of a request for a different method, I'd entertain it (at the risk of annoying people who like it as it is).it seems to calculate a more "real" distance since halving both smaller legs tends to generate a much further distance than the real hypotenuse.
-
May 4th, 2021, 06:28 #132Patriarch
- Join Date
- Mar 2016
- Location
- Bergen
- Posts
- 327
Of course, that makes sense. I got stuck last night with the idea that the real distance was the same as pathfinder distance diagonally, which is only correct for small distances. I understand it now, and since 99% of pathfinder rules are written for 2 dimensions we dont actually have good 3d measurement rules 😃.
And thank you for your other answers, I am new to lua, and new to the fantasy grounds code.
I will test this out later today, but it sounds like it is correct now. Thank you everybody.
-
May 4th, 2021, 08:40 #133Patriarch
- Join Date
- Mar 2016
- Location
- Bergen
- Posts
- 327
Well, I still think the problem is that the function getDistanceBetween does not take into account the token size at all. It only measures distances between token mid points.
The combat modifier extension calls the function getDistanceBetween when you make a ranged attack.
I added a Debug.chat in your code to see what distance gets returned. Look in the chat. As you can see it does not take into account token size when it returns the distance. And the distance returned is not the same as the measured distance with the "targeting function". The targeting function when measuring does something else than call the function getDistanceBetween to take into account token size.
See screenshot for details. The bug is there even with "standard" sized tokens.
-
May 4th, 2021, 12:00 #134
It does look like token size is taken into account for pointers but not for getDistanceBetween. However, I think this might be consistent with how FG normally handles the getDistanceBetween function?
It's all a bit vague anyway since we don't know how tall creatures are.Last edited by bmos; May 4th, 2021 at 12:07.
-
May 4th, 2021, 13:53 #135
MoonWizard described how the getDistanceBetween() function works in this post. https://www.fantasygrounds.com/forum...l=1#post576016
So calculation is NOT done from center of token to center of token, but instead its done from center of grid square to center of grid square. whichever two grid squares within the token's space are closest.
For a visual representation of how it works, in this image the PC outlined in purple is targeting each of the NPCs. The distance calculation is done from the center of the purple square, to the center of each of the green squares. The green squares represent the closest grid square to the purple square.
For support with any of my extensions, visit my #mattekure-stuff channel on Rob2e's discord https://discord.gg/rob2e
-
May 4th, 2021, 13:54 #136
I had a thought last night about sizes and why you need to do the fuzzy search. I was unfortunately right, it has to do with which square the targeting pointer is on with larger creatures. I've slightly updated my size multiplier code to account for this. Basically anything over 3 * GameSystem.getDistanceUnitsPerGrid() in size needs to be fuzzy matched.
Code:local nSpace = DB.getValue(ctNode, "space"); local distancePerGrid = GameSystem.getDistanceUnitsPerGrid() sizeMultiplier = ((nSpace / distancePerGrid) - 1) * 0.5 if nSpace > distancePerGrid * 3 then bExact = false end
-
May 4th, 2021, 14:03 #137For support with any of my extensions, visit my #mattekure-stuff channel on Rob2e's discord https://discord.gg/rob2e
-
May 4th, 2021, 15:17 #138
I think this should do it. I have consolidated these calls to a single function so that it is easier to modify them in one place. It includes the bExact code posted by SoxMax as well, but not the proposed distance calculation change.
the image settings could alternately be called onInit and then set script-wide variables so that they don't have to be re-checked over and over (although then it would not pick up changes live so I think the solution I have set up here is best).Code:---------------------- -- CUSTOM ADDITIONS -- ---------------------- local function getImageSettings() local gridsize = getGridSize() local units = DB.getValue(getDatabaseNode(), "distancebaseunit") or getDistanceBaseUnits() local suffix = getDistanceSuffix() local diagmult = getDistanceDiagMult() or Interface.getDistanceDiagMult() -- Debug.chat(gridsize, units, suffix, diagmult) return gridsize, units, suffix, diagmult end local function getDistanceBetween(sourceToken, targetToken) if not sourceToken or not targetToken then return end local gridsize, units, _, _ = getImageSettings() local startz = 0 local endz = 0 local ctNodeOrigin = CombatManager.getCTFromToken(sourceToken) if ctNodeOrigin then startz = TokenHeight.getHeight(ctNodeOrigin) * gridsize / units local ctNodeTarget = CombatManager.getCTFromToken(targetToken) if ctNodeTarget then endz = TokenHeight.getHeight(ctNodeTarget) * gridsize / units end end local startx, starty = sourceToken.getPosition() local endx, endy = targetToken.getPosition() return distanceBetween(startx,starty,startz,endx,endy,endz) end function onInit() if super and super.onInit() then super.onInit() end Token.getDistanceBetween = getDistanceBetween end -- Distance between two locations in 3 dimensions. local function distanceBetween(startx,starty,startz,endx,endy,endz,bSquare) local gridsize, units, suffix, diagmult = getImageSettings() local totalDistance = 0 local dx = math.abs(endx-startx) local dy = math.abs(endy-starty) local dz = math.abs(endz-startz) if bSquare then local hyp = math.sqrt((dx^2)+(dy^2)+(dz^2)) totalDistance = (hyp / gridsize)* units * 2 else if diagmult == 1 then -- Just a max of each dimension local longestLeg = math.max(dx, dy, dz) totalDistance = math.floor(longestLeg/gridsize+0.5)*units elseif diagmult == 0 then -- Get 3D distance directly local hyp = math.sqrt((dx^2)+(dy^2)+(dz^2)) totalDistance = (hyp / gridsize)* units else -- You get full amount of the longest path and half from each of the others local straight = math.max(dx, dy, dz) local diagonal = 0 if straight == dx then diagonal = math.floor((math.ceil(dy/gridsize) + math.ceil(dz/gridsize)) / 2) * gridsize elseif straight == dy then diagonal = math.floor((math.ceil(dx/gridsize) + math.ceil(dz/gridsize)) / 2) * gridsize else diagonal = math.floor((math.ceil(dx/gridsize) + math.ceil(dy/gridsize)) / 2) * gridsize end totalDistance = math.floor((straight + diagonal) / gridsize) totalDistance = totalDistance * units end end return totalDistance end function onMeasurePointer(pixellength,pointertype,startx,starty,endx,endy) local gridsize, units, suffix, diagmult = getImageSettings() if not (gridsize and units and suffix and diagmult) then return; end local bSquare = false if pointertype == "rectangle" then bSquare = true end local startz = 0 local endz = 0 local ctNodeOrigin = getCTNodeAt(startx,starty,gridsize) if ctNodeOrigin then local ctNodeTarget = getCTNodeAt(endx,endy,gridsize) if ctNodeTarget then startz = TokenHeight.getHeight(ctNodeOrigin) * gridsize / units endz = TokenHeight.getHeight(ctNodeTarget) * gridsize / units end end local distance = distanceBetween(startx,starty,startz,endx,endy,endz,bSquare) if distance == 0 then return "" else local stringDistance = nil if diagmult == 0 then stringDistance = string.format("%.1f", distance) else stringDistance = string.format("%.0f", distance) end return stringDistance .. suffix end end function getCTNodeAt(basex, basey, gridsize) local allTokens = getTokens() for _, oneToken in pairs(allTokens) do local x,y = oneToken.getPosition() local ctNode = CombatManager.getCTFromToken(oneToken) local bExact = true local sizeMultiplier = 0 -- bmos / SoxMax supporting other rulesets local nSpace = DB.getValue(ctNode, "space"); local distancePerGrid = GameSystem.getDistanceUnitsPerGrid() sizeMultiplier = ((nSpace / distancePerGrid) - 1) * 0.5 if nSpace > distancePerGrid * 3 then bExact = false end local bFound = false if bExact then bFound = exactMatch(basex, basey, x, y, sizeMultiplier, gridsize) else bFound = matchWithinSize(basex, basey, x, y, sizeMultiplier, gridsize) end if bFound then return ctNode end end end function exactMatch(startx, starty, endx, endy, sizeMultiplier, gridsize) local equal = false local modx = endx local mody = endy if modx > startx then modx = modx - gridsize * sizeMultiplier elseif modx < startx then modx = modx + gridsize * sizeMultiplier end if mody > starty then mody = mody - gridsize * sizeMultiplier elseif mody < starty then mody = mody + gridsize * sizeMultiplier end if modx == startx and mody == starty then equal = true end return equal end function matchWithinSize(startx, starty, endx, endy, sizeMultiplier, gridsize) local equal = false local modx = endx local mody = endy local lowerBoundx = endx local lowerBoundy = endy local upperBoundx = endx local upperBoundy = endy if endx > startx then lowerBoundx = endx - gridsize * sizeMultiplier elseif endx < startx then upperBoundx = endx + gridsize * sizeMultiplier end if endy > starty then lowerBoundy = endy - gridsize * sizeMultiplier elseif endy < starty then upperBoundy = upperBoundy + gridsize * sizeMultiplier end if startx >= lowerBoundx and startx <= upperBoundx and starty >= lowerBoundy and starty <= upperBoundy then equal = true end return equal endLast edited by bmos; May 4th, 2021 at 18:15.
-
May 4th, 2021, 15:42 #139
For some reason, making the map full screen/"sending to background" seems to make the distance calculation revert to original smiteworks version.
Is anyone else noticing this? I don't recall seeing it discussed here.
EDIT: It looks like there are other windowclass names for images sent to background or full screen. Probably the extension.xml file needs to have a change made so that image.lua is used in all these places.
EDIT3: You can use this in extension.xml instead of the current windowclass merge you're using to replace image.lua:
Code:<template name="image_record_step"> <imagecontrol name="image" merge="join"> <script file="campaign/scripts/image.lua" /> </imagecontrol> </template>
Last edited by bmos; May 4th, 2021 at 17:03.
-
May 4th, 2021, 18:27 #140
Wow, great discussion and super helpful updates. I've folded it all into the extension (made a minor mod to use bmos's updates in the SoxMax code with mattekure's suggestion) and released v3.2. Tried it with the various sizes and seems to work fine, but the off-nominal cases is where all the bugs are lurking. Svandal is the expert at finding those!
Hopefully now it'll work. (oh, I should have paid more attention to your screenshot - I'll check to see why onMeasurePointer and getDistanceBetween are giving different results. Presumably they're getting different starting locations for the same tokens).
Thread Information
Users Browsing this Thread
There are currently 1 users browsing this thread. (0 members and 1 guests)

Reply With Quote


Bookmarks