Spawn.NearestSpawn.Distance returns wrong distance

A forum for reporting bugs NOT related to custom plugins.

Moderator: MacroQuest Developers

Marze
a lesser mummy
a lesser mummy
Posts: 60
Joined: Wed Apr 14, 2004 12:08 pm

Spawn.NearestSpawn.Distance returns wrong distance

Post by Marze » Mon Sep 27, 2004 8:39 pm

${Spawn[whatever].NearestSpawn[1 npc].Distance} returns the distance to you, not the distance from the original Spawn. Workaround is to save the location of both spawns and calculate the distance between two points yourself.

wassup
Official Guardian and Writer of TFM
Official Guardian and Writer of TFM
Posts: 1487
Joined: Sat Oct 26, 2002 5:15 pm

Post by wassup » Mon Sep 27, 2004 9:28 pm

Did you try using NearestSpawn correctly?

spawn NearestSpawn[n,search]
Find the nth nearest spawn matching this search, to this spawn (most efficient on yourself)

Separate the 1 and npc with a comma.

If it doesn't work then come back again.

SlimFastForYou
a hill giant
a hill giant
Posts: 174
Joined: Sat Jan 24, 2004 1:38 am

Post by SlimFastForYou » Mon Sep 27, 2004 10:00 pm

I can confirm this behavior. A while ago (I'd say right before OOW came out), I tried to make my AcquireTarget routine take advantage of this, but it would always give the distance to the player. I thought that maybe it was just me, because nobody else had complained about it.

My target is a decaying skeleton, and on the map it's label is red. I am the arrow pointing northeast near the bottom-center of the map.

Image

Between commands, the decaying skeleton moved southwest a little towards me (the arrow close to the bottom center of the map is me). So when I typed the second command (took me about 5-10 sec), the decaying skeleton had already moved a tiny bit. You can easily tell though that if the decaying skeleton is ~1000 from me, the closest NPC shouldnt also be ~1000.

Now that I know I'm not the only one I might look the code over sometime (after I get MQ2Perl to compile, argh!).

wassup
Official Guardian and Writer of TFM
Official Guardian and Writer of TFM
Posts: 1487
Joined: Sat Oct 26, 2002 5:15 pm

Post by wassup » Tue Sep 28, 2004 3:37 am

Try it this way...

Code: Select all

${Spawn[whatever].NearestSpawn[1, npc radius 150].Distance} 
I always notice some oddities, but as it says, it's more effective when used with Me.

To check on a static spawn you have to use radius also or it doesn not work.

Code: Select all

${Spawn[loc y x npc radius 10]}
y and x might be reversed. This is just off the top of my head.

SlimFastForYou
a hill giant
a hill giant
Posts: 174
Joined: Sat Jan 24, 2004 1:38 am

Post by SlimFastForYou » Tue Sep 28, 2004 5:35 am

(Note: I consider myself merely an intermediate C++ coder, so consider my input on this with an appropriate grain of salt)

Well I found the reason it behaves this way. Take a look at some things:

Here you can see what happens when you do ${Target.Distance}. This is also what happens when you do ${Target.NearestSpawn[1,npc].Distance}. This function is found in MQ2DataTypes.cpp. Please note that pSpawn is whatever spawn is currently being evaluated - whether it is ${Target} or ${Target.NearestSpawn[1,npc]}.

Code: Select all

bool MQ2SpawnType::GetMember(MQ2VARPTR VarPtr, PCHAR Member, PCHAR Index, MQ2TYPEVAR &Dest)
{
.
.
.
	case Distance:
		Dest.Float=GetDistance(pSpawn->X,pSpawn->Y);
		Dest.Type=pFloatType;
		return true;
.
.
.
}
Now, let's examine the GetDistance function. When we go to examine the GetDistance function found in MQ2Inlines.h, we find two different definitions (hurray for polymorphism :) !)

Code: Select all

static inline FLOAT GetDistance(FLOAT X1,FLOAT Y1)
{
	FLOAT dX=X1-((PSPAWNINFO)pCharSpawn)->X;
	FLOAT dY=Y1-((PSPAWNINFO)pCharSpawn)->Y;
	return sqrtf(dX*dX + dY*dY);
}

static inline FLOAT GetDistance(FLOAT X1,FLOAT Y1,FLOAT X2,FLOAT Y2)
{
	FLOAT dX=X1-X2;
	FLOAT dY=Y1-Y2;
	return sqrtf(dX*dX + dY*dY);
}
Currently, the first GetDistance function is called, irregardless of whether it is ${Target} or ${Target.NearestSpawn[1,npc]}.

So, to adjust the code in order to fix this problem, somehow we would have to get the parent spawn's X and Y attributes (when I say parent, I mean the parent of NearestSpawn whether it be the implied ${Me} or a ${Target} across the map) and use those to make a function call to the second definition of GetDistance - not the first which defaultly uses ${Me}. That would be up to the devs to decide how they would want to do this. I can't really think of an easy way to do this besides either doing a significant modification or creating a global variable for the CurrentParent spawn. But I think I identified the cause.

Please let me know if that made any sense or if you strongly suspect me of being on crack :-).

User avatar
blueninja
a grimling bloodguard
a grimling bloodguard
Posts: 541
Joined: Thu Aug 28, 2003 7:03 am
Location: Göteborg, Sweden

Post by blueninja » Tue Sep 28, 2004 11:38 am

${Target} is a Spawn, ${Target.NearestSpawn} is just another Spawn. If Spawn.Distance returns the distance between you and the spawn in one case it will also do so in the second case. Think of it this way: if you compare it to ${Target.Name} and ${Target.NearestSpawn[].Name}, would you expect them to return anything other than the name of the two different spawns?

I realize what you want to do but this is not how you should do it. ${Math.Distance[]} is what you're looking for. Something along these lines. Either that or add a new member to the Spawn type, like Spawn.DistanceToSpawn[].

Code: Select all

/varset SpawnID ${Spawn[whatever].ID}
/varset NearSpawnID ${Spawn[id ${SpawnID}].NearestSpawn[].ID}
/echo Distance: ${Math.Distance[${Spawn[id ${SpawnID}].Y},${Spawn[id ${SpawnID}].Y}:${Spawn[id ${NearSpawnID}].Y},${Spawn[id ${NearSpawnID}].Y}]}

SlimFastForYou
a hill giant
a hill giant
Posts: 174
Joined: Sat Jan 24, 2004 1:38 am

Post by SlimFastForYou » Tue Sep 28, 2004 12:45 pm

I thought about it last night, and although both me and Marze would love it if MQ did that for us, it probably wasn't intended to be so.

In other words, how would one find the distance between a player and the nearest spawn to the target? That's what this function is for. So it really isn't a bug when you think about it. That also explains why I witnessed the same behavior like 5 zips ago and nobody reported it as a bug until now :oops:.

Adding a new member like ${Spawn.NearestSpawnDistance[n,search]} would be useful IMHO. But I could also use a whole bunch of math calculations. My AcquireTarget has already been written, tested and it works. There are features I would like to add to it, and although it would probably go faster if Macroquest was able to naturally calculate distances between spawns, that would really be up to the devs whether to include that or not.

I'll probably whip up a test-of-concept function sometime later today.

User avatar
Night Hawk
a grimling bloodguard
a grimling bloodguard
Posts: 590
Joined: Fri Aug 13, 2004 4:56 pm

Post by Night Hawk » Tue Sep 28, 2004 3:08 pm

a^2+b^2=c^2

:P

SlimFastForYou
a hill giant
a hill giant
Posts: 174
Joined: Sat Jan 24, 2004 1:38 am

Post by SlimFastForYou » Tue Sep 28, 2004 4:51 pm

Night Hawk wrote:a^2+b^2=c^2

:P
Not quite. If you want to check the distances of the nearest 10 mobs against the nearest 15 mobs (I found ways to simplify this).

Code: Select all

Check to see the distance between Candidate and CheckMob (to be used in a loop):

${Math.Sqrt[${Math.Calc[${Math.Calc[${NearestSpawn[${CheckMob},npc].X}-${NearestSpawn[${Candidate},npc].X}]}*${Math.Calc[${NearestSpawn[${CheckMob},npc].X}-${NearestSpawn[${Candidate},npc].X}]}]}+${Math.Calc[${Math.Calc[${NearestSpawn[${CheckMob},npc].Y}-${NearestSpawn[${Candidate},npc].Y}]}+${Math.Calc[${NearestSpawn[${CheckMob},npc].Y}-${NearestSpawn[${Candidate},npc].Y}]}]}]}

Also known as c = sqrt ( (x-x1)^2 + (y-y1)^2  )
I had something like this in my AcquireTarget routine initally. But it was such a mindfuck and I did find ways of simplifying this using various tricks.

Would be more elegant to have

Code: Select all

${NearestSpawn[${Candidate},npc].NearestSpawnDistance[${CheckMob},npc]}
Just MHO, and I found ways to simplify this. Plus, it would be somewhat faster for MacroQuest to natively handle this. Whether this is included as a new feature or not really doesn't matter to me - I believe it would be un-necessary but at the same time nice to have.