View previous topic :: View next topic |
Author |
Message |
frag.machine

Joined: 25 Nov 2006 Posts: 728
|
Posted: Mon Mar 16, 2009 2:51 am Post subject: traceline "seeing" thru walls ? |
|
|
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 |
|
 |
Error Inside3D Staff

Joined: 05 Nov 2004 Posts: 558 Location: VA, USA
|
|
Back to top |
|
 |
frag.machine

Joined: 25 Nov 2006 Posts: 728
|
Posted: Tue Mar 17, 2009 3:30 am Post subject: |
|
|
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 |
|
 |
Supa

Joined: 26 Oct 2004 Posts: 122
|
Posted: Tue Mar 17, 2009 8:24 pm Post subject: |
|
|
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 |
|
 |
frag.machine

Joined: 25 Nov 2006 Posts: 728
|
Posted: Wed Mar 18, 2009 1:00 am Post subject: |
|
|
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 |
|
 |
Spike
Joined: 05 Nov 2004 Posts: 944 Location: UK
|
Posted: Wed Mar 18, 2009 1:41 am Post subject: |
|
|
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 |
|
 |
Lardarse

Joined: 05 Nov 2005 Posts: 243 Location: Bristol, UK
|
Posted: Wed Mar 18, 2009 6:08 am Post subject: |
|
|
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 |
|
 |
frag.machine

Joined: 25 Nov 2006 Posts: 728
|
Posted: Wed Mar 18, 2009 10:55 pm Post subject: |
|
|
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 |
|
 |
|
|
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
|