Skip to content

Commit

Permalink
Fixed bugs in the original Hexen P_RoughMonsterSearch logic. During t…
Browse files Browse the repository at this point in the history
…he outwards spiral, the top left, bottom right and bottom left blockmap blocks would be checked twice for each "layer" of the test.

This fix does not change the behaviour of the original algorithm and so has not been compatibility optioned.
  • Loading branch information
danij committed Dec 16, 2007
1 parent 850af10 commit 00a4a11
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 85 deletions.
4 changes: 2 additions & 2 deletions doomsday/plugins/jhexen/src/p_enemy.c
Expand Up @@ -1090,9 +1090,9 @@ void C_DECL A_MinotaurLook(mobj_t *actor)
if(!actor->target) // Near player monster search.
{
if(master && (master->health > 0) && (master->player))
mo = P_RoughMonsterSearch(master, 20);
mo = P_RoughMonsterSearch(master, 20*128);
else
mo = P_RoughMonsterSearch(actor, 20);
mo = P_RoughMonsterSearch(actor, 20*128);
actor->target = mo;
}

Expand Down
184 changes: 105 additions & 79 deletions doomsday/plugins/jhexen/src/p_maputl.c
Expand Up @@ -60,6 +60,8 @@

// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------

static boolean isTargetable(mobj_t *mo, mobj_t *target);

// EXTERNAL DATA DECLARATIONS ----------------------------------------------

// PUBLIC DATA DEFINITIONS -------------------------------------------------
Expand All @@ -72,13 +74,27 @@ int ptflags;

// PRIVATE DATA DEFINITIONS ------------------------------------------------

static mobj_t *RoughBlockCheck(mobj_t *mo, int index);

// CODE --------------------------------------------------------------------

static mobj_t *PIT_MobjBlockLinks(int index, void *data)
{
mobj_t *mo = (mobj_t*) data;
mobj_t *link, *root = P_GetBlockRootIdx(index);

// If this doesn't work, check the backed-up version!
for(link = root->bnext; link != root; link = link->bnext)
{
if(isTargetable(mo, link))
return link;
}

return NULL;
}

/**
* Searches though the surrounding mapblocks for monsters/players within the
* specified distance (in MAPBLOCKUNITS).
* Searches around for targetable monsters/players near mobj.
*
* @return Ptr to the targeted mobj if found, ELSE @c NULL;
*/
mobj_t *P_RoughMonsterSearch(mobj_t *mo, int distance)
{
Expand All @@ -94,12 +110,15 @@ mobj_t *P_RoughMonsterSearch(mobj_t *mo, int distance)
uint bmapwidth = *(uint*) DD_GetVariable(DD_BLOCKMAP_WIDTH);
uint bmapheight = *(uint*) DD_GetVariable(DD_BLOCKMAP_HEIGHT);

// Convert from world units to map block units.
distance /= 128;

P_PointToBlock(mo->pos[VX], mo->pos[VY], &startX, &startY);

if(startX >= 0 && startX < bmapwidth &&
startY >= 0 && startY < bmapheight)
{
target = RoughBlockCheck(mo, startY * bmapwidth + startX);
target = PIT_MobjBlockLinks(startY * bmapwidth + startX, mo);
if(target)
{ // Found a target right away!
return target;
Expand Down Expand Up @@ -160,31 +179,39 @@ mobj_t *P_RoughMonsterSearch(mobj_t *mo, int distance)
// Trace the first block section (along the top).
for(; blockIndex <= firstStop; blockIndex++)
{
target = RoughBlockCheck(mo, blockIndex);
int x = blockIndex % bmapwidth;
int y = blockIndex / bmapwidth;
target = PIT_MobjBlockLinks(blockIndex, mo);
if(target)
return target;
}

// Trace the second block section (right edge).
for(blockIndex--; blockIndex <= secondStop; blockIndex += bmapwidth)
for(blockIndex += -1 + bmapwidth; blockIndex <= secondStop; blockIndex += bmapwidth)
{
target = RoughBlockCheck(mo, blockIndex);
int x = blockIndex % bmapwidth;
int y = blockIndex / bmapwidth;
target = PIT_MobjBlockLinks(blockIndex, mo);
if(target)
return target;
}

// Trace the third block section (bottom edge).
for(blockIndex -= bmapwidth; blockIndex >= thirdStop; blockIndex--)
for(blockIndex -= 1 + bmapwidth; blockIndex >= thirdStop; blockIndex--)
{
target = RoughBlockCheck(mo, blockIndex);
int x = blockIndex % bmapwidth;
int y = blockIndex / bmapwidth;
target = PIT_MobjBlockLinks(blockIndex, mo);
if(target)
return target;
}

// Trace the final block section (left edge).
for(blockIndex++; blockIndex > finalStop; blockIndex -= bmapwidth)
for(blockIndex += 1 - bmapwidth; blockIndex > finalStop; blockIndex -= bmapwidth)
{
target = RoughBlockCheck(mo, blockIndex);
int x = blockIndex % bmapwidth;
int y = blockIndex / bmapwidth;
target = PIT_MobjBlockLinks(blockIndex, mo);
if(target)
return target;
}
Expand All @@ -193,83 +220,82 @@ mobj_t *P_RoughMonsterSearch(mobj_t *mo, int distance)
return NULL;
}

static mobj_t *RoughBlockCheck(mobj_t *mo, int index)
static boolean isTargetable(mobj_t *mo, mobj_t *target)
{
mobj_t *link, *root = P_GetBlockRootIdx(index);
mobj_t *master;
angle_t angle;

// If this doesn't work, check the backed-up version!
for(link = root->bnext; link != root; link = link->bnext)
{
if(mo->player)
{ // Minotaur looking around player.
if((link->flags & MF_COUNTKILL) || (link->player && (link != mo)))
{
if(!(link->flags & MF_SHOOTABLE) ||
(link->flags2 & MF2_DORMANT) ||
((link->type == MT_MINOTAUR) && (link->tracer == mo)) ||
(IS_NETGAME && !deathmatch && link->player))
continue;

if(P_CheckSight(mo, link))
return link;
}
if(mo->player)
{ // Minotaur looking around player.
if((target->flags & MF_COUNTKILL) || (target->player && (target != mo)))
{
if(!(target->flags & MF_SHOOTABLE) ||
(target->flags2 & MF2_DORMANT) ||
((target->type == MT_MINOTAUR) && (target->tracer == mo)) ||
(IS_NETGAME && !deathmatch && target->player))
return false;

if(P_CheckSight(mo, target))
return true;
}
else if(mo->type == MT_MINOTAUR)
{ // Looking around minotaur.
master = mo->tracer;
if((link->flags & MF_COUNTKILL) ||
(link->player && (link != master)))
{
if(!(link->flags & MF_SHOOTABLE) ||
(link->flags2 & MF2_DORMANT) ||
((link->type == MT_MINOTAUR) && (link->tracer == mo->tracer)) ||
(IS_NETGAME && !deathmatch && link->player))
continue;

if(P_CheckSight(mo, link))
return link;
}
}
else if(mo->type == MT_MINOTAUR)
{ // Looking around minotaur.
mobj_t *master = mo->tracer;

if((target->flags & MF_COUNTKILL) ||
(target->player && (target != master)))
{
if(!(target->flags & MF_SHOOTABLE) ||
(target->flags2 & MF2_DORMANT) ||
((target->type == MT_MINOTAUR) && (target->tracer == mo->tracer)) ||
(IS_NETGAME && !deathmatch && target->player))
return false;

if(P_CheckSight(mo, target))
return true;
}
else if(mo->type == MT_MSTAFF_FX2)
{ // bloodscourge.
if((link->flags & MF_COUNTKILL || (link->player && link != mo->target)) &&
!(link->flags2 & MF2_DORMANT))
{
if(!(link->flags & MF_SHOOTABLE) ||
(IS_NETGAME && !deathmatch && link->player))
continue;
}
else if(mo->type == MT_MSTAFF_FX2)
{ // bloodscourge.
if(((target->flags & MF_COUNTKILL) ||
(target->player && target != mo->target)) &&
!(target->flags2 & MF2_DORMANT))
{
if(!(target->flags & MF_SHOOTABLE) ||
(IS_NETGAME && !deathmatch && target->player))
return false;

if(P_CheckSight(mo, link))
if(P_CheckSight(mo, target))
{
angle_t angle;
mobj_t *master;

master = mo->target;
angle =
R_PointToAngle2(master->pos[VX], master->pos[VY],
target->pos[VY], target->pos[VY]) -
master->angle;
angle >>= 24;
if(angle > 226 || angle < 30)
{
master = mo->target;
angle =
R_PointToAngle2(master->pos[VX], master->pos[VY],
link->pos[VY], link->pos[VY]) - master->angle;
angle >>= 24;
if(angle > 226 || angle < 30)
{
return link;
}
return true;
}
}
}
else
{ // spirits.
if(((link->flags & MF_COUNTKILL) || (link->player && link != mo->target)) &&
!(link->flags2 & MF2_DORMANT))
{
if(!(link->flags & MF_SHOOTABLE) ||
(IS_NETGAME && !deathmatch && link->player) ||
link == mo->target)
continue;
}
else
{ // spirits.
if(((target->flags & MF_COUNTKILL) ||
(target->player && target != mo->target)) &&
!(target->flags2 & MF2_DORMANT))
{
if(!(target->flags & MF_SHOOTABLE) ||
(IS_NETGAME && !deathmatch && target->player) ||
target == mo->target)
return false;

if(P_CheckSight(mo, link))
return link;
}
if(P_CheckSight(mo, target))
return true;
}
}

return NULL;
return false;
}
8 changes: 4 additions & 4 deletions doomsday/plugins/jhexen/src/p_pspr.c
Expand Up @@ -1106,7 +1106,7 @@ void MStaffSpawn(mobj_t *mo, angle_t angle)
if(pmo)
{
pmo->target = mo;
pmo->tracer = P_RoughMonsterSearch(pmo, 10);
pmo->tracer = P_RoughMonsterSearch(pmo, 10*128);
}
}

Expand Down Expand Up @@ -1184,7 +1184,7 @@ void C_DECL A_MStaffTrack(mobj_t *mo)
{
if((mo->tracer == 0) && (P_Random() < 50))
{
mo->tracer = P_RoughMonsterSearch(mo, 10);
mo->tracer = P_RoughMonsterSearch(mo, 10*128);
}
P_SeekerMissile(mo, ANGLE_1 * 2, ANGLE_1 * 10);
}
Expand All @@ -1200,7 +1200,7 @@ void MStaffSpawn2(mobj_t *mo, angle_t angle)
if(pmo)
{
pmo->target = mo;
pmo->tracer = P_RoughMonsterSearch(pmo, 10);
pmo->tracer = P_RoughMonsterSearch(pmo, 10*128);
}
}

Expand Down Expand Up @@ -1726,7 +1726,7 @@ static void CHolyFindTarget(mobj_t *mo)
{
mobj_t *target;

target = P_RoughMonsterSearch(mo, 6);
target = P_RoughMonsterSearch(mo, 6*128);
if(target)
{
Con_Message("CHolyFindTarget: mobj_t* converted to int! Not 64-bit compatible.\n");
Expand Down

0 comments on commit 00a4a11

Please sign in to comment.