Inside3D!
     

traceline "seeing" thru walls ?

 
Post new topic   Reply to topic    Inside3d Forums Forum Index -> QuakeC Programming
View previous topic :: View next topic  
Author Message
frag.machine



Joined: 25 Nov 2006
Posts: 728

PostPosted: Mon Mar 16, 2009 2:51 am    Post subject: traceline "seeing" thru walls ? Reply with quote

I am trying to make an item pointer for an isometric mod. Imagine the player walking by the map and, when he's facing a nearby item, npc or monster, a fancy arrow pops over the subject. After some tests everything worked as expected, until I realized that my item pointer was also "seeing" thru solid walls. In a test map with two completely separated rooms the item pointer can "sense" a nearby shambler in the other side of the wall. I am using the infront() and visible() functions from the stock ai.qc and, afaik they're correctly checking if trace_fraction returns 1 so this wasn't supposed to happen. Any ideas ?
_________________
frag.machine - Q2K4 Project
http://fragmachine.quakedev.com/
Back to top
View user's profile Send private message Visit poster's website
Error
Inside3D Staff


Joined: 05 Nov 2004
Posts: 558
Location: VA, USA

PostPosted: Mon Mar 16, 2009 9:13 am    Post subject: Reply with quote

should be easy to fix, paste your code here and we'll take a look.

bugs are always easy to fix if we see the problem ourselves
_________________
Inside3D : Knowledge Is Power
Darkplaces Documentation Wiki
Back to top
View user's profile Send private message Send e-mail Visit poster's website AIM Address Yahoo Messenger MSN Messenger
frag.machine



Joined: 25 Nov 2006
Posts: 728

PostPosted: Tue Mar 17, 2009 3:30 am    Post subject: Reply with quote

No problem. The cursor thing is toggled calling CursorSpawn () and CursorRemove () (at the end of the code) thru impulses in weapon.qc. Different skins tell to the player the target nature (monster, NPC, item, etc), and different frames are used according the target height. All this stuff works fine, but the cursor can "see" monsters thru the wall, which basically spoils things a bit from the gameplay viewpoint.

Code:

void () CursorThink;
void (entity csr, entity target, float r) CursorUpdate =
{
    local float f;

    if (csr.oldenemy != target)
    {
        sprint (csr.owner, "DEBUG: cursor now tracking ");
        sprint (csr.owner, target.classname);
        sprint (csr.owner, "\n");
        csr.oldenemy = target;
    }

    setorigin (csr, target.origin);
    if (target.flags & FL_MONSTER)
    {
        if (r == RANGE_MELEE || r == RANGE_NEAR)
        {
            csr.skin = 7;
            csr.effects = csr.effects | EF_MUZZLEFLASH;
        }
        else
        {
            csr.skin = 6;
        }
    }

    if (target.flags & FL_NPC)
    {
        if (r == RANGE_MELEE || r == RANGE_NEAR)
        {
            csr.skin = 2;
            csr.effects = csr.effects | EF_MUZZLEFLASH;
        }
        else
        {
            csr.skin = 3;
        }

    }

    if (target.flags & FL_ITEM)
    {
        if (r == RANGE_MELEE || r == RANGE_NEAR)
        {
            csr.skin = 4;
        }
        else
        {
            csr.skin = 5;
        }

    }

    if (target.flags & FL_QUESTITEM)
    {
        if (r == RANGE_MELEE || r == RANGE_NEAR)
        {
            csr.skin = 0;
            csr.effects = csr.effects | EF_MUZZLEFLASH;
        }
        else
        {
            csr.skin = 1;
        }
    }

    f = target.absmax_z - target.absmin_z;
    f = f / 8;
    f = rint (f);
    f = 8 - f;
    if (f < 1)
    {
        f = 1;
    }
    if (f > 8)
    {
        f = 8;
    }

    csr.frame = f;
};

void () CursorThink =
{
    local entity    csr;
    local entity    tgt;
    local float     r, i;

    self.frame = 0;         // don't show by default
    csr = self;
    self = csr.owner;
    r = 50;
    while (r < 500)
    {
        tgt = findradius (self.origin, r);
        while (tgt)
        {
            i = range (tgt);
            if ((tgt.flags & FL_MONSTER) && (tgt.enemy == self))
            {
                // pissed off monsters have priority over any other stuff
                if ((visible (tgt)) && (infront (tgt)))
                {
                    CursorUpdate (csr, tgt, i);
                }
            }
            else if ((tgt.flags & FL_MONSTER) && (tgt.enemy != self))
            {
                // got an idle monster
                if ((visible (tgt)) && (infront (tgt)))
                {
                    CursorUpdate (csr, tgt, i);
                }
            }
            else if (tgt.flags & FL_NPC)
            {
                if ((visible (tgt)) && (infront (tgt)))
                {
                    CursorUpdate (csr, tgt, i);
                }
            }
            else if (tgt.flags & FL_ITEM)
            {
                if ((visible (tgt)) && (infront (tgt)))
                {
                    CursorUpdate (csr, tgt, i);
                }
            }

            tgt = tgt.chain;
        }

        r = r + 50;
    }

    self = csr;
    self.think = CursorThink;
    self.nextthink = time + 0.05;
};

void (entity pl) CursorSpawn =
{
    local   entity  csr;

    csr = spawn ();
    csr.classname = "func_cursor";
    csr.owner = pl;
    csr.solid = SOLID_NOT;
    csr.movetype = MOVETYPE_FLY;
    csr.flags = FL_ITEM;
    setmodel (csr, "progs/marker.mdl");
    setsize (self, '-16 -16 -24', '16 16 40');
    csr.skin = 0;
    csr.frame = 0;
    csr.think = CursorThink;
    csr.nextthink = time + 0.1;
};

void (entity pl) CursorRemove =
{
    local   entity  csr;

    csr = find (world, classname, "func_cursor");
    while (csr != world)
    {
        if (csr.owner == pl)
        {
            remove (csr);
            csr = find (world, classname, "func_cursor");
        }
        else
        {
            csr = find (csr, classname, "func_cursor");
        }
    }
};

_________________
frag.machine - Q2K4 Project
http://fragmachine.quakedev.com/
Back to top
View user's profile Send private message Visit poster's website
Supa



Joined: 26 Oct 2004
Posts: 122

PostPosted: Tue Mar 17, 2009 8:24 pm    Post subject: Reply with quote

Is the player that walks around the actual client or just a dummy? Because if the client is the third person camera and the .owner of the cursor, the 'self' that gets passed to visible() would point to the camera. If so, that'd explain why you're able to detect Shamblers through walls. :)
Back to top
View user's profile Send private message Send e-mail
frag.machine



Joined: 25 Nov 2006
Posts: 728

PostPosted: Wed Mar 18, 2009 1:00 am    Post subject: Reply with quote

Yes, the player is the actual client. I am using a modified engine with more flexible chase camera (so I can tilt, yaw and roll besides the stock Quake chase camera). Here follow some images to give more information about what I am doing here:






_________________
frag.machine - Q2K4 Project
http://fragmachine.quakedev.com/
Back to top
View user's profile Send private message Visit poster's website
Spike



Joined: 05 Nov 2004
Posts: 944
Location: UK

PostPosted: Wed Mar 18, 2009 1:41 am    Post subject: Reply with quote

Blame your qcc.

if ((visible (tgt)) && (infront (tgt)))

will expand into:

storeent tgt->ofs_parm0
call1 visible
storeent tgt->ofs_parm0
call1 infront
and ofs_ret, ofs_ret -> temp <- here!!!
ifnot temp, jump over

qc functions store into an invisible global for their return value. The same one for every function.
Chances are, your 'infront' function call is clobbering the return value of 'visible'.
Solutions: use FrikQCC or a recent FTEQCC. Some older fteqcc builds have issues here, but the recent ones should be fine.

Or maybe I'm going crazy. I really have no idea any more.
_________________
What's a signature?
Back to top
View user's profile Send private message Visit poster's website
Lardarse



Joined: 05 Nov 2005
Posts: 243
Location: Bristol, UK

PostPosted: Wed Mar 18, 2009 6:08 am    Post subject: Reply with quote

Spike wrote:
Blame your qcc.

if ((visible (tgt)) && (infront (tgt)))

will expand into:

storeent tgt->ofs_parm0
call1 visible
storeent tgt->ofs_parm0
call1 infront
and ofs_ret, ofs_ret -> temp <- here!!!
ifnot temp, jump over

qc functions store into an invisible global for their return value. The same one for every function.
Chances are, your 'infront' function call is clobbering the return value of 'visible'.

I heard div0 discussing this issue about a year ago in #darkplaces. Easiest way to fix it that will work with all compilers is to split the line into 2 if statements. This is also possibly more efficient, as && and || don't have the short-circuiting behaviour in QuakeC that they do in C.

if(a && b) in C will not evaluate b if a is false, so it is better to put the one that is more likely to be false first. Also, if a might not be able to evaluate properly unless b is true, then it is better to put b first. || Is similar, but it stops evaluating after it finds something is true.

In QuakeC however, it would always evaluate a and b, so if one of them is much more likely to be false (or it is necessary to be true for the other expression to make sense) it should be placed as the first of 2 or more nested if statements. This also has the added benefit of the return values not clobbering each other. You may want to try and work out which is false more often - the profile command (prvm_profile server in DarkPlaces) may be helpful for this..
Back to top
View user's profile Send private message
frag.machine



Joined: 25 Nov 2006
Posts: 728

PostPosted: Wed Mar 18, 2009 10:55 pm    Post subject: Reply with quote

Spike wrote:
Blame your qcc.

if ((visible (tgt)) && (infront (tgt)))

will expand into:

storeent tgt->ofs_parm0
call1 visible
storeent tgt->ofs_parm0
call1 infront
and ofs_ret, ofs_ret -> temp <- here!!!
ifnot temp, jump over

qc functions store into an invisible global for their return value. The same one for every function.
Chances are, your 'infront' function call is clobbering the return value of 'visible'.
Solutions: use FrikQCC or a recent FTEQCC. Some older fteqcc builds have issues here, but the recent ones should be fine.

Or maybe I'm going crazy. I really have no idea any more.


Err... I am using FrikQCC. Actually, it's the first time I give it a try, since proqccw used to be my default QC compiler. :/

But I'll check if your tip works, thanks!

EDIT: Yup, you got it. Splitting the test in two "if's" solved the bug. Many thanks again!
_________________
frag.machine - Q2K4 Project
http://fragmachine.quakedev.com/
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Inside3d Forums Forum Index -> QuakeC Programming All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2004 phpBB Group