STAR TREK 2d20
Page 1 of 2 12 Last
  1. #1
    GKEnialb's Avatar
    Join Date
    Jul 2017
    Location
    Castle Rock, CO
    Posts
    523

    Can the range calculation be overridden?

    I created an extension to allow height the height of tokens to be set https://www.fantasygrounds.com/forum...ight-Indicator and somebody asked if I could update the range arrow with a distance taking height into account. The distance calculations are straight-forward enough, but I can't find a way to either update the text displayed on the range arrow or modify the underlying range calculation (and let the arrow just use that). Is it possible to do either? I see there's an Interface function to setDistanceDiagMult, which isn't listed in the Interface package API, so I was hoping there was some other undocumented API with more distance controls (or any other method).

  2. #2

  3. #3
    GKEnialb's Avatar
    Join Date
    Jul 2017
    Location
    Castle Rock, CO
    Posts
    523
    Great - thanks!

  4. #4
    GKEnialb's Avatar
    Join Date
    Jul 2017
    Location
    Castle Rock, CO
    Posts
    523
    I was able to do this after getting info from several threads, so figured I'd put what I found here so it's consolidated (and to see if I got anything wrong ).

    - onMeasurePointer is found in campaign/scipts/image.lua (from CoreRPG) - it's not actually in the CoreRPG version, so it needs to be appended
    - You have to override everything in image.lua and the original functions aren't available to call (so can't just override a portion and call the original for the rest) -- actually, see the post below
    - image.lua has to called out in your xml file as below (including being inside of <base>)
    Code:
    		
    <base>
      <template name="image_record_step">
      <imagecontrol name="image">
         <indicators locked="image_locked" loading="image_loading" />
         <default snap="on" drawingsize="500,500" />
         <script file="campaign/scripts/image.lua" />
      </imagecontrol>
    </template>	
    </base>
    - getGridSize(), getDistanceBaseUnits(), and Interface.getDistanceDiagMult() are your friends
    - You can't just override the targeting arrows; the same logic is used for the pointers as well
    - I had to look at the endpoint of the arrow to see what token it was pointing to (so I could get its height). Comparing that endpoint to the position of a tiny/small/medium creature worked just fine; for a large or huge creature, I had to adjust their position by half a gridsize and a full gridsize, respectively; gargantuan creatures are a little wacky - I had to just check if the endpoint was within 1.5 gridsizes (as opposed to being exactly 1.5 gridsizes off)

    This is the code I wrote for the actual distance calculations is as follows (and doesn't quite work for "variant" coming from a corner)
    Code:
    function distanceBetween(startx,starty,startz,endx,endy,endz)
    	local diagMult = Interface.getDistanceDiagMult()
    	local units = getDistanceBaseUnits()
    	local gridsize = getGridSize()
    	local totalDistance = 0
    	local dx = math.abs(endx-startx)
    	local dy = math.abs(endy-starty)
    	local dz = math.abs(endz-startz)
    	
    	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 longest = math.max(dx, dy, dz)
    		if longest == dx then
    			totalDistance = dx + (dy+dz)/2
    		elseif longest == dy then
    			totalDistance = dy + (dx+dz)/2
    		else	
    			totalDistance = dz + (dx+dy)/2
    		end
    		
    		-- Convert to feet
    		totalDistance = (totalDistance / gridsize + 0.5) * units	
    		totalDistance = math.floor(totalDistance / units) * units		
    	end
    		
    	return totalDistance
    end
    Last edited by GKEnialb; March 31st, 2021 at 02:51.

  5. #5
    I believe you can override a control's script using a windowclass merge.

    Example:
    Code:
    <windowclass name="imagewindow" merge="join">
    	<sheetdata>
    		<image_record name="image">
    			<script file="campaign/scripts/image_overrides.lua" />
    		</image_record>
    	</sheetdata>
    </windowclass>
    and include the onMeasurePointer code as the only function in the override file.

    Regards,
    JPG

  6. #6
    GKEnialb's Avatar
    Join Date
    Jul 2017
    Location
    Castle Rock, CO
    Posts
    523
    Awesome - that will be a lot less maintenance!

    And confirmed that you're correct; I was able to use the merge and remove all of the base functions.
    Last edited by GKEnialb; March 31st, 2021 at 02:44.

  7. #7
    GKEnialb's Avatar
    Join Date
    Jul 2017
    Location
    Castle Rock, CO
    Posts
    523
    To expand on the figuring out the target, I couldn't find a method to determine which target the arrow was pointing to, so I made this general function.

    Code:
    function getCTNodeAt(basex, basey, gridsize)
    	local allTokens = getTokens()
    	local theToken = nil
    	for _, oneToken in pairs(allTokens) do
    		x,y = oneToken.getPosition()
    		local ctNode = CombatManager.getCTFromToken(oneToken)
    
    		local sSize = StringManager.trim(DB.getValue(ctNode, "size", ""):lower());
    		local bExact = true
    		local sizeMultiplier = 0
    		if sSize == "large" then
    			sizeMultiplier = 0.5
    		elseif sSize == "huge" then
    			sizeMultiplier = 1
    		elseif sSize == "gargantuan" then
    			-- Gargantuan creatures behave a bit differently. Can be anywhere within bounds
    			sizeMultiplier = 1.5
    			bExact = false
    		end
    		
    		local found = false
    		if bExact then
    			found = exactMatch(basex, basey, x, y, sizeMultiplier, gridsize)
    		else
    			found = matchWithinSize(basex, basey, x, y, sizeMultiplier, gridsize)
    		end
    		
    		if found then
    			local ctNode = CombatManager.getCTFromToken(oneToken)
    			theToken = ctNode
    			break
    		end
        end
    	return theToken
    end
    For non-gargantuan creatures, this finds an exact match.
    Code:
    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
    For gargantuan creatures, this just checks to see if the pointer is within the creatures token.
    Code:
    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
    end
    Of course if there's a better way to do that, I'd be happy to hear it.

  8. #8
    GKEnialb's Avatar
    Join Date
    Jul 2017
    Location
    Castle Rock, CO
    Posts
    523
    And just one more (hopefully) question - is there a way to force a redraw of the targeting arrow programmatically? If I change my height on a token, I have to move the pointer until it loses focus and return it to gain focus to get the onMeasurePointer to activate.

  9. #9
    No, the onMeasurePointer function is only called when the the targeting line changes.

    Regards,
    JPG

  10. #10
    GKEnialb's Avatar
    Join Date
    Jul 2017
    Location
    Castle Rock, CO
    Posts
    523
    Thanks for the confirmation - the workaround isn't that bad. Do you know of an easier way of determining what's at the other end of the arrow within onMeasurePointer than looking up each token's position as I have above?

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
  •  
FG Spreadshirt Swag

Log in

Log in