Double check of math for /face

A forum for feature requests/discussions and user submitted patches that improve MQ2

Moderator: MacroQuest Developers

Mckorr
Developer
Developer
Posts: 2326
Joined: Fri Oct 18, 2002 1:16 pm
Location: Texas

Double check of math for /face

Post by Mckorr » Fri Oct 24, 2003 10:22 am

Code: Select all

            gFaceAngle = (
                atan2(pSpawnClosest->X - pChar->X,
                       pSpawnClosest->Y - pChar->Y)
                * 256.0f / PI);
Okay, on the surface the formula is right, but I do have a question. The format for atan2 is
double atan2( double y, double x );
and yet we are using x,y. Are we doing that because EQ swaps X and Y in locs?
MQ2: Think of it as Evolution in action.

Lax
We're not worthy!
We're not worthy!
Posts: 3524
Joined: Thu Oct 17, 2002 1:01 pm
Location: ISBoxer
Contact:

Post by Lax » Fri Oct 24, 2003 10:27 am

Yes. If you swap the x and y, /face would face you perpendicular to the line between you and the target.

Code: Select all

   target
     +x
     |    
-    |    
y----*---->  swap x,y you face here
     |
     |
You need to look for why you would face -x instead of +x in the coordinate plane above

What conditions are necessary to produce this result?
Lax Lacks
Master of MQ2 Disaster
Purveyor of premium, EULA-safe MMORPG Multiboxing Software
* Multiboxing with ISBoxer: Quick Start Video
* EQPlayNice, WinEQ 2.0

Mckorr
Developer
Developer
Posts: 2326
Joined: Fri Oct 18, 2002 1:16 pm
Location: Texas

Post by Mckorr » Fri Oct 24, 2003 11:11 am

That's what I'm working towards, but I wanted to confirm the math first.

That would place the error here:

Code: Select all

        if (Away) {
            gFaceAngle += 256.0f;
        }
        if (gFaceAngle>=512.0f) gFaceAngle -= 512.0f;
        if (gFaceAngle<0.0f) gFaceAngle += 512.0f;
        if (Fast) {
            pChar->Heading = (FLOAT)gFaceAngle;
            gFaceAngle=10000.0f;
            bRunNextCommand = TRUE;
        }
I think :) Doing a bit of reformatting to make it easier to read and find the error.
MQ2: Think of it as Evolution in action.

Mckorr
Developer
Developer
Posts: 2326
Joined: Fri Oct 18, 2002 1:16 pm
Location: Texas

Post by Mckorr » Fri Oct 24, 2003 11:24 am

Code: Select all

        if (gFaceAngle>=512.0f) gFaceAngle -= 512.0f;
        if (gFaceAngle<0.0f) gFaceAngle += 512.0f;
I'm not convinced these two lines are necessary. If the math is correct (and it seems to be) any angle produced by atan2 should be less than 512. Granted it might be a negative angle, but pChar->Heading should allow for negative values. If it didn't we'd always spin clockwise to face something, meaning if it is off to our left by just a bit we'd spin in a big circle every time we did a /face.

To avoid confusion between 512 and 0 (both identical), a better phrasing would be:

Code: Select all

if (gFaceAngle=512.0f) gFaceAngle=0.0f;
Last edited by Mckorr on Fri Oct 24, 2003 11:36 am, edited 1 time in total.
MQ2: Think of it as Evolution in action.

Lax
We're not worthy!
We're not worthy!
Posts: 3524
Joined: Thu Oct 17, 2002 1:01 pm
Location: ISBoxer
Contact:

Post by Lax » Fri Oct 24, 2003 11:35 am

Sore thumb:

Code: Select all

if (Away) { 
            gFaceAngle += 256.0f; 
        } 
e.g. sticking out.

This is doing an about face. I would have to say that the error in the math comes where Away is set, or perhaps Away isn't necessary at all (I don't know, paste it)
Lax Lacks
Master of MQ2 Disaster
Purveyor of premium, EULA-safe MMORPG Multiboxing Software
* Multiboxing with ISBoxer: Quick Start Video
* EQPlayNice, WinEQ 2.0

Mckorr
Developer
Developer
Posts: 2326
Joined: Fri Oct 18, 2002 1:16 pm
Location: Texas

Post by Mckorr » Fri Oct 24, 2003 12:00 pm

Code: Select all

BOOL Away = FALSE;
and

Code: Select all

        } else if (!strcmp(szArg,"away")) {
            Away = TRUE;
It's supposed to let you do a /face away from your target, presumably so you can run away or kite it. I can't see how it is getting set by accident... and the behavior doesn't occur at point blank range.
MQ2: Think of it as Evolution in action.

Mckorr
Developer
Developer
Posts: 2326
Joined: Fri Oct 18, 2002 1:16 pm
Location: Texas

Post by Mckorr » Fri Oct 24, 2003 12:05 pm

As an experiment I've thrown together a dumbed down version of /face. It won't face loc, heading, etc. Will accept "look" as a parameter, or a spawn name. Always does a /face fast.

This is just to test the math behavior, and no, I haven't tried compiling it or using it (at work without a compiler or EQ).

Code: Select all

VOID Face(PSPAWNINFO pChar, PCHAR szLine)
{
    if (!EQADDR_SPAWNLIST && !*EQADDR_SPAWNLIST) return;
    
    PSPAWNINFO pSpawnClosest = NULL;
    PSPAWNINFO pTarget = NULL;
    SPAWNINFO LocSpawn = {0};
    SEARCHSPAWN SearchSpawn;
    ClearSearchSpawn(&SearchSpawn);
    CHAR szMsg[MAX_STRING] = {0};
    CHAR szName[MAX_STRING] = {0};
    CHAR szArg[MAX_STRING] = {0};
    CHAR szLLine[MAX_STRING] = {0};
    PCHAR szFilter = szLLine;
    BOOL bArg = TRUE;
    BOOL bOtherArgs = FALSE;
    BOOL Look = FALSE;
    DOUBLE Distance;

    _strlwr(strcpy(szLLine,szLine));
    
    while (bArg) {
        GetArg(szArg,szFilter,1);
        szFilter = GetNextArg(szFilter,1);
        if (szArg[0]==0) {
            bArg = FALSE;
        } else if (!strcmp(szArg,"look")) {
            Look = TRUE;
        } else {
            bOtherArgs = TRUE;
            szFilter = ParseSearchSpawnArgs(szArg,szFilter,&SearchSpawn);
        }
    }

    if (!pSpawnClosest) {
	    if (!bOtherArgs) {
		       if (EQADDR_TARGET && *EQADDR_TARGET) {
			       pSpawnClosest = *EQADDR_TARGET;
		       }
	       } else {
		       pSpawnClosest = SearchThroughSpawns(&SearchSpawn,pChar);
	       }
    }

    if (!pSpawnClosest) {
	    sprintf(szMsg,"There were no matches for: %s",FormatSearchSpawn(szArg,&SearchSpawn));
        strcpy(gLastError,"FACE_NOTFOUND");
    }

    gFaceAngle = (atan2(pSpawnClosest->X - pChar->X, pSpawnClosest->Y - pChar->Y) * 256.0f / PI);
    if (gFaceAngle=512.0f) gFaceAngle = 0.0f;

    if (Look) {
	    Distance = DistanceToSpawn(pChar, pSpawnClosest);
        gLookAngle = (atan2(pSpawnClosest->Z - pChar->Z, (FLOAT)Distance) * 256.0f / PI);
        pChar->CameraAngle = (FLOAT)gLookAngle;
        gLookAngle=10000.0f;
    }

    pChar->Heading = (FLOAT)gFaceAngle;
    gFaceAngle=10000.0f;
    bRunNextCommand = TRUE;
    
    sprintf(szMsg,"Facing %s'%s'...",(Away)?"away from ":"", CleanupName(strcpy(szName,pSpawnClosest->Name),FALSE));
        gLastError[0]=0;
    if (EQADDR_TARGET && *EQADDR_TARGET) pTarget = *EQADDR_TARGET;
    if ((pSpawnClosest != &LocSpawn) && ((Away) || (pSpawnClosest != pTarget))) WriteChatBuffer(szMsg,USERCOLOR_WHO);
    DebugSpew("Face - %s",szMsg);
    return;
}
MQ2: Think of it as Evolution in action.

Lax
We're not worthy!
We're not worthy!
Posts: 3524
Joined: Thu Oct 17, 2002 1:01 pm
Location: ISBoxer
Contact:

Post by Lax » Fri Oct 24, 2003 12:34 pm

Ok, so it's not the away thing. I think I know what it is.

Not only are X and Y flipped around, but so are + and - for east/west left/right.

So, I *think* this should be right:

Code: Select all

gFaceAngle = (atan2(pSpawnClosest->X - pChar->X, (-pSpawnClosest->Y) - (-pChar->Y)) * 256.0f / PI); 
Give that a shot. It hurts my head to think about it. I really don't even know which between X and Y is east/west in EQ, but I know it's flipped back asswards in addition to the whole Y,X thing.
Lax Lacks
Master of MQ2 Disaster
Purveyor of premium, EULA-safe MMORPG Multiboxing Software
* Multiboxing with ISBoxer: Quick Start Video
* EQPlayNice, WinEQ 2.0

Mckorr
Developer
Developer
Posts: 2326
Joined: Fri Oct 18, 2002 1:16 pm
Location: Texas

Post by Mckorr » Fri Oct 24, 2003 12:46 pm

Hmmm, interesting thought. This is simpler though:

Code: Select all

gFaceAngle = (atan2(pSpawnClosest->X - pChar->X, -(pSpawnClosest->Y - pChar->Y)) * 256.0f / PI); 
MQ2: Think of it as Evolution in action.

Lax
We're not worthy!
We're not worthy!
Posts: 3524
Joined: Thu Oct 17, 2002 1:01 pm
Location: ISBoxer
Contact:

Post by Lax » Fri Oct 24, 2003 12:55 pm

Yes.. but it hurts my head to think about it ;)
If that fixes the problem, then you would always face away (although not *directly*) from your target unless it was on the same Y, without this fix.

Try it. It's either on X or Y, I have no idea.. my hunch is Y.
Lax Lacks
Master of MQ2 Disaster
Purveyor of premium, EULA-safe MMORPG Multiboxing Software
* Multiboxing with ISBoxer: Quick Start Video
* EQPlayNice, WinEQ 2.0

Amadeus
The Maestro
The Maestro
Posts: 2036
Joined: Sat Jun 29, 2002 3:51 pm

Post by Amadeus » Fri Oct 24, 2003 3:43 pm

I'm confused...what was wrong with /face in the first place? ....lol

Lax
We're not worthy!
We're not worthy!
Posts: 3524
Joined: Thu Oct 17, 2002 1:01 pm
Location: ISBoxer
Contact:

Post by Lax » Fri Oct 24, 2003 4:05 pm

If you face a spawn, it's reported that you sometimes face AWAY from the target. Looking at the math and how EQ actually uses it, it's sort of obvious why.

Oh, I just thought of a better way to simplify it too.

Code: Select all

gFaceAngle = (atan2(pSpawnClosest->X - pChar->X, [color=red]pChar->Y - pSpawnClosest->Y[/color]) * 256.0f / PI); 
Swap them instead of using another -, achieves same effect
Lax Lacks
Master of MQ2 Disaster
Purveyor of premium, EULA-safe MMORPG Multiboxing Software
* Multiboxing with ISBoxer: Quick Start Video
* EQPlayNice, WinEQ 2.0

Mckorr
Developer
Developer
Posts: 2326
Joined: Fri Oct 18, 2002 1:16 pm
Location: Texas

Post by Mckorr » Fri Oct 24, 2003 5:17 pm

They all achieve the same effect... you face 90 degrees off from the mob.

Okay, ya got me why this is buggy. No code adjustments help the situation.
MQ2: Think of it as Evolution in action.

User avatar
dont_know_at_all
Developer
Developer
Posts: 5450
Joined: Sun Dec 01, 2002 4:15 am
Location: Florida, USA
Contact:

Post by dont_know_at_all » Fri Oct 24, 2003 6:08 pm

Does /face nopredict ever misbehave? I always thought that the predict part was buggy.

Mckorr
Developer
Developer
Posts: 2326
Joined: Fri Oct 18, 2002 1:16 pm
Location: Texas

Post by Mckorr » Sat Oct 25, 2003 7:20 am

predict/nopredict doesn't matter. For some reason range to taget matters. And it's not facing away, so much as FIRST facing away, then turning back to face the target. But I'm looping through the command a lot, so it could be the first instance is facing away, and successive instances are behaving correctly.

I ended up editing my code so nopredict was the default, and in the tests I ran yesterday didn't see this behavior... well, maybe once, but it was so fast I couldn't be sure.
MQ2: Think of it as Evolution in action.