void ADynamicLight::CollectWithinRadius(const DVector3 &pos, subsector_t *subSec, float radius) { if (!subSec) return; subSec->validcount = ::validcount; touching_subsectors = AddLightNode(&subSec->lighthead, subSec, this, touching_subsectors); if (subSec->sector->validcount != ::validcount) { touching_sector = AddLightNode(&subSec->render_sector->lighthead, subSec->sector, this, touching_sector); subSec->sector->validcount = ::validcount; } for (unsigned int i = 0; i < subSec->numlines; i++) { seg_t * seg = subSec->firstline + i; // check distance from x/y to seg and if within radius add this seg and, if present the opposing subsector (lather/rinse/repeat) // If out of range we do not need to bother with this seg. if (DistToSeg(pos, seg) <= radius) { if (seg->sidedef && seg->linedef && seg->linedef->validcount != ::validcount) { // light is in front of the seg if ((pos.Y - seg->v1->fY()) * (seg->v2->fX() - seg->v1->fX()) + (seg->v1->fX() - pos.X) * (seg->v2->fY() - seg->v1->fY()) <= 0) { seg->linedef->validcount = validcount; touching_sides = AddLightNode(&seg->sidedef->lighthead, seg->sidedef, this, touching_sides); } } if (seg->linedef) { FLinePortal *port = seg->linedef->getPortal(); if (port && port->mType == PORTT_LINKED) { line_t *other = port->mDestination; if (other->validcount != ::validcount) { subsector_t *othersub = R_PointInSubsector(other->v1->fPos() + other->Delta() / 2); if (othersub->validcount != ::validcount) CollectWithinRadius(PosRelative(other), othersub, radius); } } } seg_t *partner = seg->PartnerSeg; if (partner) { subsector_t *sub = partner->Subsector; if (sub != NULL && sub->validcount != ::validcount) { CollectWithinRadius(pos, sub, radius); } } } } sector_t *sec = subSec->sector; if (!sec->PortalBlocksSight(sector_t::ceiling)) { line_t *other = subSec->firstline->linedef; if (sec->GetPortalPlaneZ(sector_t::ceiling) < Z() + radius) { DVector2 refpos = other->v1->fPos() + other->Delta() / 2 + sec->GetPortalDisplacement(sector_t::ceiling); subsector_t *othersub = R_PointInSubsector(refpos); if (othersub->validcount != ::validcount) CollectWithinRadius(PosRelative(othersub->sector), othersub, radius); } } if (!sec->PortalBlocksSight(sector_t::floor)) { line_t *other = subSec->firstline->linedef; if (sec->GetPortalPlaneZ(sector_t::floor) > Z() - radius) { DVector2 refpos = other->v1->fPos() + other->Delta() / 2 + sec->GetPortalDisplacement(sector_t::floor); subsector_t *othersub = R_PointInSubsector(refpos); if (othersub->validcount != ::validcount) CollectWithinRadius(PosRelative(othersub->sector), othersub, radius); } } }
void AFastProjectile::Tick () { int i; DVector3 frac; int changexy; ClearInterpolation(); double oldz = Z(); if (!(flags5 & MF5_NOTIMEFREEZE)) { //Added by MC: Freeze mode. if (bglobal.freeze || level.flags2 & LEVEL2_FROZEN) { return; } } // [RH] Ripping is a little different than it was in Hexen FCheckPosition tm(!!(flags2 & MF2_RIP)); int count = 8; if (radius > 0) { while ( fabs(Vel.X) > radius * count || fabs(Vel.Y) > radius * count) { // we need to take smaller steps. count += count; } } // Handle movement if (!Vel.isZero() || (Z() != floorz)) { // force some lateral movement so that collision detection works as intended. if ((flags & MF_MISSILE) && Vel.X == 0 && Vel.Y == 0 && !IsZeroDamage()) { Vel.X = MinVel; } frac = Vel / count; changexy = frac.X != 0 || frac.Y != 0; int ripcount = count / 8; for (i = 0; i < count; i++) { if (changexy) { if (--ripcount <= 0) { tm.LastRipped.Clear(); // [RH] Do rip damage each step, like Hexen } if (!P_TryMove (this, Pos() + frac, true, NULL, tm)) { // Blocked move if (!(flags3 & MF3_SKYEXPLODE)) { if (tm.ceilingline && tm.ceilingline->backsector && tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum && Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(PosRelative(tm.ceilingline))) { // Hack to prevent missiles exploding against the sky. // Does not handle sky floors. Destroy (); return; } // [RH] Don't explode on horizon lines. if (BlockingLine != NULL && BlockingLine->special == Line_Horizon) { Destroy (); return; } } P_ExplodeMissile (this, BlockingLine, BlockingMobj); return; } } AddZ(frac.Z); UpdateWaterLevel (); oldz = Z(); if (oldz <= floorz) { // Hit the floor if (floorpic == skyflatnum && !(flags3 & MF3_SKYEXPLODE)) { // [RH] Just remove the missile without exploding it // if this is a sky floor. Destroy (); return; } SetZ(floorz); P_HitFloor (this); P_ExplodeMissile (this, NULL, NULL); return; } if (Top() > ceilingz) { // Hit the ceiling if (ceilingpic == skyflatnum && !(flags3 & MF3_SKYEXPLODE)) { Destroy (); return; } SetZ(ceilingz - Height); P_ExplodeMissile (this, NULL, NULL); return; } if (!frac.isZero() && ripcount <= 0) { ripcount = count >> 3; Effect(); } } }