• Announcements

    • Ashal

      SITE MOVED - IN READ ONLY MODE   12/08/2015

      Please use http://www.loverslab.com moving forward. Site has been restored to a previous version, and this one placed into a read-only mode. This is available for a limited time so users may reference/copy content that has been lost in the transition. This will no longer be accessible by December 22nd, 2015.

Archived

This topic is now archived and is closed to further replies.

thomthom

Distances in Scripting and Interior Cells

So for the mod I am working on I need a good way to say which of two actors is closer to a third actor.

The simple way that "should" work is (in psuedocode):


set distb to ActorA.getdistance ActorB
set distc to ActorA.getdistance ActorC
if (distb>distc)
; AcotrC is closer to ActorA
else
; ActorB is closer to ActorA
endif

This works if all of the actors are in the same interior. However if the actors are in different interiors/exteriors then getdistance returns a giant maximum for all "GetDistance" calls (something like 3.4*10^28). Either way this is unacceptable. I dug through the obse command documentation hoping to find some sort of answer, along with looking at a few mods to see if they handled it in a good way. This produced not much, so I decided to make my own long winded and somewhat hacky fix to my problem.

I assumed (hopefully correctly) that all exterior spaces are part of the same coordinate system.  My method works by finding the nearest exterior teleporting door for a given reference, then returning the X,Y worldspace coordinates for that door. Once have have run this function for two actors, I can do a Pythagorean distance calculation for the two points.

I tried a few different ideas, but oblivion wont let you calulcate distance between cells, I think I understand now why. There isnt a good way to use the pathing grid to calculate distances between two points (This should be possible but I don't want to write a tree walking algorithim yet). Somewhere, somehow oblivion is already doing something like this for the mapmarkers, time passes during fast travel based on your speed and the distance between markers, however this function isnt available to anyone, as I think it is buried in the engine.

I posted this hoping for a few possible replies:

A. "Your script is useless because obse has an undocumented 'GetActualDistanceBetweenTwoRefsRegardlessOfWhereTheyAre'"

B. "That might work but there is an easier function already written by someone else"

C. "What?"

I ran into some oddities with the obse methods, and I commented a few of them in the script below.


scn ZMCFindNearestExternalDoor

ref startRef
ref currentCell
ref doorRef
ref linkedDoorRef
ref linkedTeleportCellRef
float linkedDoorX
float linkedDoorY
string_var teleportCellName
float teleportX
float teleportY

array_var returnArray

;; This function returns x,y world coordinates (I hope) for a ref in an interior cell
;; The logic is still a bit mucky, as when we call "GetTeleportCell" it returns a blank ref, although
;; it appears we can call getteleportcellname without issue
;; This only works for refs 1 layer deep in an interior, I could make it recursive ... maybe when I feel like it
;; The hackiest part of this is when we check if the teleportcell ref is 0...
;;

begin function { startRef }
set currentCell to startRef.getParentCell
let returnArray := ar_Construct StringMap
set doorRef to GetFirstRefInCell currentCell 24 2 ;depth doesnt matter in interior cells, a depth of 2 works the same as depth of 1
while (doorRef)
set linkedDoorRef to doorRef.GetLinkedDoor
if (linkedDoorRef != 0) ; if this door is actually linked to something
set linkedTeleportCellRef to doorRef.GetTeleportCell
if (linkedTeleportCellRef == 0) ; See why does a linked door to the exterior end up with a zero ref??
let teleportCellName := doorRef.GetTeleportCellName
set teleportX to doorRef.GetDoorTeleportX
set teleportY to doorRef.GetDoorTeleportY
PrintToConsole "Teleport CellName: %z x,y: %0.f , %0.f" teleportCellName teleportX teleportY
let returnArray["X"] := teleportX
let returnArray["Y"] := teleportY
endif
endif

set linkedDoorX to 0
set linkedDoorY to 0
set doorRef to GetNextRef
loop

SetFunctionValue returnArray

end

Any assistance towards getting this going would be nice.

0

Share this post


Link to post

If I remember correctly, GetPos is only relative to the current cell (including exterior cells). Since I can imagine what you'd be using the script for, it might be easier to wait until the player/NPC is in an exterior cell, then use GetDistance. Before that, if you need an NPC to move somewhere, just have their package go to the default location until they get outside.

Then again, I don't know much about OBSE functions or advanced scripting, so there could very easily be a better way.

0

Share this post


Link to post

Not something I've ever had to deal with myself, but I can well believe your findings.

I presume the actors you are trying to get a distance for are arbitrary?

Possibly one for the Official Forums OBSE thread?

0

Share this post


Link to post

Yes, the NPCs are completely arbitrary, I was thinking about the OBSE forums as my next shot, thanks for your help! :)

I tested the function out a bit more and it seems to work well enough. I suppose I don't need very precise math to determine which is closer, and this method seems to work well enough. Once I clean it up a bit more and make it recursive I will repost it if anyone ever needs such a weird thing.

0

Share this post


Link to post