Firstly: modern engines tend to have watervis enabled, so there's no reason a monster/player wouldn't be able to see through water.
Remember that the forent argument ignores the specified entity. Alternatively, the trace will not hit entities that the forent entity owns.
Thus the following code tries multiple traces until it makes progress and should work in ANY quake engine.
Code: Select all
float(entity monster, entity player) canSee =
{
float success = FALSE;
float tries = 10;
monster.owner = world;
trace_endpos = monster.origin;
vector pushdir = normalize(player.origin - monster.origin);
while(tries --> 0)
{
traceline(trace_endpos, player.origin, TRUE, monster);
if (trace_fraction == 1 || trace_ent == player)
{
sucess = TRUE;
break;
}
if (!trace_ent.alpha || trace_ent.alpha >= 1)
break; //this entity is opaque.
//we hit something that was transparent, have another go.
trace_endpos += pushdir; //push forwards slightly so we avoid infinite hitting on boundaries.
monster.owner = trace_ent;
}
monster.owner = world;
return sucess;
};
In exotic situations where two ents somehow overlap, its possible that you'll end up hitting the same two ents every single time. This shouldn't be too frequent though. If it does happen, instead changing the monster's owner you can set them to nonsolid before retracing (and adding them to a list), and then afterwards walking your list to restore the solid flags, due to nomonsters=TRUE they'll thankfully only be SOLID_BSP.
Alternatively in fte, you can always do something like this:
Code: Select all
void() func_window =
{
existing_func_window_code();
if (self.alpha < 1)
self.dimension_solid &= ~1; //default is 255, so this clears the low bit, leaving 7 other bits. all other ents will have bit 1 set.
};
float(entity monster, entity player) canSee =
{
monster.dimension_hit = 1; //only allow the monster and traces belonging to the monster to hit things that are still in dimension&1
traceline(monster.origin, player.origin, TRUE, monster);
monster.dimension_hit = 255; //revert to default
if (trace_fraction == 1 || trace_ent == player)
return TRUE; //trace_ent won't be set to the player, but hey, completeness and paranoia. you might have made them into a bsp object, or maybe you want the bounding boxes of other monsters to block their vision?
return FALSE;
};
Assuming there's no typos, this will allow the monster to see through windows (because they are not solid in dimension 1), and through other monsters (because nomonsters=true ignores non-bsp entities), but NOT other bsp objects like closed doors, and all with a single trace.
Unfortunately dp doesn't support dimension_* so this method will only work in FTE.
In DP, I believe that there's some MOVE_WORLDONLY value you can pass in the nomonsters arg, but this means they'll see through closed doors etc too that you DO want to block their vision, so this probably isn't useful to you.