mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 14:51:51 +00:00
- added portal awareness to several functions.
* Arch-Vile resurrection * Boom point pushers (due to complete lack of z-handling only for line portals.) * A_RadiusGive These also require a more thorough collection of portal groups than simple position checks.
This commit is contained in:
parent
8be690fbf2
commit
d4f87203bd
6 changed files with 187 additions and 91 deletions
|
@ -154,6 +154,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale)
|
||||||
PARAM_ACTION_PROLOGUE;
|
PARAM_ACTION_PROLOGUE;
|
||||||
|
|
||||||
AActor *thing;
|
AActor *thing;
|
||||||
|
// This doesn't need to iterate through portals.
|
||||||
FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), self->radius));
|
FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), self->radius));
|
||||||
while ((thing = it.Next()))
|
while ((thing = it.Next()))
|
||||||
{
|
{
|
||||||
|
|
|
@ -2604,26 +2604,33 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
|
||||||
fixedvec2 viletry = self->Vec2Offset(
|
fixedvec2 viletry = self->Vec2Offset(
|
||||||
FixedMul (absSpeed, xspeed[self->movedir]),
|
FixedMul (absSpeed, xspeed[self->movedir]),
|
||||||
FixedMul (absSpeed, yspeed[self->movedir]), true);
|
FixedMul (absSpeed, yspeed[self->movedir]), true);
|
||||||
AActor *corpsehit;
|
|
||||||
|
|
||||||
FBlockThingsIterator it(FBoundingBox(viletry.x, viletry.y, 32*FRACUNIT));
|
FPortalGroupArray check(FPortalGroupArray::PGA_Full3d);
|
||||||
while ((corpsehit = it.Next()))
|
|
||||||
|
FMultiBlockThingsIterator it(check, viletry.x, viletry.y, self->Z() - 64* FRACUNIT, self->Top() + 64 * FRACUNIT, 32 * FRACUNIT);
|
||||||
|
FMultiBlockThingsIterator::CheckResult cres;
|
||||||
|
while (it.Next(&cres))
|
||||||
{
|
{
|
||||||
|
AActor *corpsehit = cres.thing;
|
||||||
FState *raisestate = corpsehit->GetRaiseState();
|
FState *raisestate = corpsehit->GetRaiseState();
|
||||||
if (raisestate != NULL)
|
if (raisestate != NULL)
|
||||||
{
|
{
|
||||||
// use the current actor's radius instead of the Arch Vile's default.
|
// use the current actor's radius instead of the Arch Vile's default.
|
||||||
fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius;
|
fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius;
|
||||||
|
|
||||||
if (abs(corpsehit->X() - viletry.x) > maxdist ||
|
if (abs(cres.position.x - viletry.x) > maxdist ||
|
||||||
abs(corpsehit->Y() - viletry.y) > maxdist)
|
abs(cres.position.y - viletry.y) > maxdist)
|
||||||
continue; // not actually touching
|
continue; // not actually touching
|
||||||
// Let's check if there are floors in between the archvile and its target
|
// Let's check if there are floors in between the archvile and its target
|
||||||
|
|
||||||
|
if (corpsehit->Sector->PortalGroup != self->Sector->PortalGroup)
|
||||||
|
{
|
||||||
// if in a different section of the map, only consider possible if a line of sight exists.
|
// if in a different section of the map, only consider possible if a line of sight exists.
|
||||||
if (corpsehit->Sector->PortalGroup != self->Sector->PortalGroup && !P_CheckSight(self, corpsehit))
|
if (!P_CheckSight(self, corpsehit))
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
sector_t *vilesec = self->Sector;
|
sector_t *vilesec = self->Sector;
|
||||||
sector_t *corpsec = corpsehit->Sector;
|
sector_t *corpsec = corpsehit->Sector;
|
||||||
// We only need to test if at least one of the sectors has a 3D floor.
|
// We only need to test if at least one of the sectors has a 3D floor.
|
||||||
|
@ -2640,6 +2647,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
corpsehit->velx = corpsehit->vely = 0;
|
corpsehit->velx = corpsehit->vely = 0;
|
||||||
// [RH] Check against real height and radius
|
// [RH] Check against real height and radius
|
||||||
|
|
|
@ -129,6 +129,14 @@ struct polyblock_t;
|
||||||
|
|
||||||
struct FPortalGroupArray
|
struct FPortalGroupArray
|
||||||
{
|
{
|
||||||
|
// Controls how groups are connected
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PGA_NoSectorPortals,// only collect line portals
|
||||||
|
PGA_CheckPosition, // only collects sector portals at the actual position
|
||||||
|
PGA_Full3d, // Goes up and down sector portals at any linedef within the bounding box (this is a lot slower and should only be done if really needed.)
|
||||||
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
LOWER = 0x4000,
|
LOWER = 0x4000,
|
||||||
|
@ -141,8 +149,9 @@ struct FPortalGroupArray
|
||||||
MAX_STATIC = 4
|
MAX_STATIC = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
FPortalGroupArray()
|
FPortalGroupArray(int collectionmethod = PGA_CheckPosition)
|
||||||
{
|
{
|
||||||
|
method = collectionmethod;
|
||||||
varused = 0;
|
varused = 0;
|
||||||
inited = false;
|
inited = false;
|
||||||
}
|
}
|
||||||
|
@ -171,6 +180,7 @@ struct FPortalGroupArray
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inited;
|
bool inited;
|
||||||
|
int method;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WORD entry[MAX_STATIC];
|
WORD entry[MAX_STATIC];
|
||||||
|
|
|
@ -2249,11 +2249,14 @@ void DPusher::Tick ()
|
||||||
// Seek out all pushable things within the force radius of this
|
// Seek out all pushable things within the force radius of this
|
||||||
// point pusher. Crosses sectors, so use blockmap.
|
// point pusher. Crosses sectors, so use blockmap.
|
||||||
|
|
||||||
FBlockThingsIterator it(FBoundingBox(m_X, m_Y, m_Radius));
|
FPortalGroupArray check(FPortalGroupArray::PGA_NoSectorPortals); // no sector portals because this thing is utterly z-unaware.
|
||||||
AActor *thing;
|
FMultiBlockThingsIterator it(check, m_X, m_Y, 0, 0, m_Radius);
|
||||||
|
FMultiBlockThingsIterator::CheckResult cres;
|
||||||
|
|
||||||
while ((thing = it.Next()))
|
|
||||||
|
while (it.Next(&cres))
|
||||||
{
|
{
|
||||||
|
AActor *thing = cres.thing;
|
||||||
// Normal ZDoom is based only on the WINDTHRUST flag, with the noclip cheat as an exemption.
|
// Normal ZDoom is based only on the WINDTHRUST flag, with the noclip cheat as an exemption.
|
||||||
bool pusharound = ((thing->flags2 & MF2_WINDTHRUST) && !(thing->flags & MF_NOCLIP));
|
bool pusharound = ((thing->flags2 & MF2_WINDTHRUST) && !(thing->flags & MF_NOCLIP));
|
||||||
|
|
||||||
|
|
|
@ -1117,20 +1117,23 @@ void P_CreateLinkedPortals()
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
static bool ProcessLayer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t upperz, fixed_t checkradius, FPortalGroupArray &out)
|
bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t upperz, fixed_t checkradius, FPortalGroupArray &out)
|
||||||
{
|
{
|
||||||
// Keep this temporary work stuff static. This function can never be called recursively
|
// Keep this temporary work stuff static. This function can never be called recursively
|
||||||
// and this would have to be reallocated for each call otherwise.
|
// and this would have to be reallocated for each call otherwise.
|
||||||
static FPortalBits processMask;
|
static FPortalBits processMask;
|
||||||
static TArray<FLinePortal*> foundPortals;
|
static TArray<FLinePortal*> foundPortals;
|
||||||
|
static TArray<int> groupsToCheck;
|
||||||
|
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
out.inited = true;
|
out.inited = true;
|
||||||
if (linkedPortals.Size() == 0)
|
if (linkedPortals.Size() != 0)
|
||||||
{
|
{
|
||||||
// If there are no portals, all sectors are in group 0.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
processMask.setSize(linkedPortals.Size());
|
processMask.setSize(linkedPortals.Size());
|
||||||
processMask.clear();
|
processMask.clear();
|
||||||
foundPortals.Clear();
|
foundPortals.Clear();
|
||||||
|
@ -1174,6 +1177,9 @@ bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (out.method != FPortalGroupArray::PGA_NoSectorPortals)
|
||||||
|
{
|
||||||
sector_t *sec = P_PointInSector(position.x, position.y);
|
sector_t *sec = P_PointInSector(position.x, position.y);
|
||||||
sector_t *wsec = sec;
|
sector_t *wsec = sec;
|
||||||
while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->SkyBoxes[sector_t::ceiling]->threshold)
|
while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->SkyBoxes[sector_t::ceiling]->threshold)
|
||||||
|
@ -1199,6 +1205,70 @@ bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t
|
||||||
wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat
|
wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat
|
||||||
retval = true;
|
retval = true;
|
||||||
}
|
}
|
||||||
|
if (out.method == FPortalGroupArray::PGA_Full3d)
|
||||||
|
{
|
||||||
|
groupsToCheck.Clear();
|
||||||
|
groupsToCheck.Push(startgroup);
|
||||||
|
int thisgroup = startgroup;
|
||||||
|
for (unsigned i = 0; i < groupsToCheck.Size();i++)
|
||||||
|
{
|
||||||
|
fixedvec2 disp = Displacements.getOffset(startgroup, thisgroup & ~FPortalGroupArray::FLAT);
|
||||||
|
FBoundingBox box(position.x + disp.x, position.y + disp.y, checkradius);
|
||||||
|
FBlockLinesIterator it(box);
|
||||||
|
line_t *ld;
|
||||||
|
while ((ld = it.Next()))
|
||||||
|
{
|
||||||
|
if (box.Right() <= ld->bbox[BOXLEFT]
|
||||||
|
|| box.Left() >= ld->bbox[BOXRIGHT]
|
||||||
|
|| box.Top() <= ld->bbox[BOXBOTTOM]
|
||||||
|
|| box.Bottom() >= ld->bbox[BOXTOP])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (box.BoxOnLineSide(ld) != -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(thisgroup & FPortalGroupArray::LOWER))
|
||||||
|
{
|
||||||
|
for (int s = 0; s < 2; s++)
|
||||||
|
{
|
||||||
|
sector_t *sec = s ? ld->backsector : ld->frontsector;
|
||||||
|
if (sec && !(sec->PortalBlocksMovement(sector_t::ceiling)))
|
||||||
|
{
|
||||||
|
if (sec->SkyBoxes[sector_t::ceiling]->threshold < upperz)
|
||||||
|
{
|
||||||
|
int grp = sec->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup;
|
||||||
|
if (!(processMask.getBit(grp)))
|
||||||
|
{
|
||||||
|
processMask.setBit(grp);
|
||||||
|
groupsToCheck.Push(grp | FPortalGroupArray::UPPER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(thisgroup & FPortalGroupArray::UPPER))
|
||||||
|
{
|
||||||
|
for (int s = 0; s < 2; s++)
|
||||||
|
{
|
||||||
|
sector_t *sec = s ? ld->backsector : ld->frontsector;
|
||||||
|
if (sec && !(sec->PortalBlocksMovement(sector_t::floor)))
|
||||||
|
{
|
||||||
|
if (sec->SkyBoxes[sector_t::floor]->threshold > position.z)
|
||||||
|
{
|
||||||
|
int grp = sec->SkyBoxes[sector_t::floor]->Sector->PortalGroup;
|
||||||
|
if (!(processMask.getBit(grp)))
|
||||||
|
{
|
||||||
|
processMask.setBit(grp);
|
||||||
|
groupsToCheck.Push(grp | FPortalGroupArray::LOWER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5570,10 +5570,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance));
|
FPortalGroupArray check(FPortalGroupArray::PGA_Full3d);
|
||||||
while ((thing = it.Next()))
|
fixed_t mid = self->Z() + self->height / 2;
|
||||||
|
FMultiBlockThingsIterator it(check, self->X(), self->Y(), mid-distance, mid+distance, distance);
|
||||||
|
FMultiBlockThingsIterator::CheckResult cres;
|
||||||
|
|
||||||
|
while ((it.Next(&cres)))
|
||||||
{
|
{
|
||||||
given += DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist);
|
given += DoRadiusGive(self, cres.thing, item, amount, distance, flags, filter, species, mindist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ACTION_RETURN_INT(given);
|
ACTION_RETURN_INT(given);
|
||||||
|
|
Loading…
Reference in a new issue