Пример #1
0
void CProjectileHandler::CheckUnitCollisions(
	CProjectile* p,
	std::vector<CUnit*>& tempUnits,
	CUnit** endUnit,
	const float3& ppos0,
	const float3& ppos1)
{
	CollisionQuery q;

	for (CUnit** ui = &tempUnits[0]; ui != endUnit; ++ui) {
		CUnit* unit = *ui;

		const CUnit* attacker = p->owner();
		const bool raytraced = (unit->collisionVolume->GetTestType() == CollisionVolume::COLVOL_HITTEST_CONT);

		// if this unit fired this projectile, always ignore
		if (attacker == unit) {
			continue;
		}

		if (p->GetCollisionFlags() & Collision::NOFRIENDLIES) {
			if (attacker != NULL && (unit->allyteam == attacker->allyteam)) { continue; }
		}
		if (p->GetCollisionFlags() & Collision::NOENEMIES) {
			if (attacker != NULL && (unit->allyteam != attacker->allyteam)) { continue; }
		}
		if (p->GetCollisionFlags() & Collision::NONEUTRALS) {
			if (unit->IsNeutral()) { continue; }
		}

		if (CCollisionHandler::DetectHit(unit, ppos0, ppos1, &q)) {
			if (q.lmp != NULL) {
				unit->SetLastAttackedPiece(q.lmp, gs->frameNum);
			}

			// The current projectile <p> won't reach the raytraced surface impact
			// position until ::Update() is called (same frame). This is a problem
			// when dealing with fast low-AOE projectiles since they would do almost
			// no damage if detonated outside the collision volume. Therefore, smuggle
			// a bit with its position now (rather than rolling it back in ::Update()
			// and waiting for the next-frame CheckUnitCol(), which is problematic
			// for noExplode projectiles).

			// const float3& pimpp = (q.b0)? q.p0: q.p1;
			const float3 pimpp =
				(q.b0 && q.b1)? ( q.p0 +  q.p1) * 0.5f:
				(q.b0        )? ( q.p0 + ppos1) * 0.5f:
								(ppos0 +  q.p1) * 0.5f;

			p->pos = (raytraced)? pimpp: ppos0;
			p->Collision(unit);
			p->pos = (raytraced)? ppos0: p->pos;
			break;
		}
	}
}
Пример #2
0
bool CAICheats::IsUnitNeutral(int unitid) {
	if (!CHECK_UNITID(unitid))
		return false;

	CUnit* unit = uh->units[unitid];
	if (unit) {
		return (unit->IsNeutral());
	}

	return false;
}
Пример #3
0
bool CAICallback::IsUnitNeutral(int unitId) {
	verify();

	if (CHECK_UNITID(unitId)) {
		CUnit* unit = uh->units[unitId];

		if (unit && (unit->losStatus[gs->AllyTeam(team)] & LOS_INLOS)) {
			if (unit->IsNeutral())
				return true;
		}
	}

	return false;
}
Пример #4
0
/** same as TestTrajectoryAllyCone, but looks for neutral units */
bool CGameHelper::TestTrajectoryNeutralCone(const float3& from, const float3& flatdir, float length, float linear, float quadratic, float spread, float baseSize, CUnit* owner)
{
    int quads[1000];
    int* endQuad = quads;
    qf->GetQuadsOnRay(from, flatdir, length, endQuad);

    for (int* qi = quads; qi != endQuad; ++qi) {
        const CQuadField::Quad& quad = qf->GetQuad(*qi);
        for (std::list<CUnit*>::const_iterator ui = quad.units.begin(); ui != quad.units.end(); ++ui) {
            CUnit* u = *ui;

            if (u == owner)
                continue;

            if (u->IsNeutral()) {
                if (TestTrajectoryConeHelper(from, flatdir, length, linear, quadratic, spread, baseSize, u))
                    return true;
            }
        }
    }
    return false;
}
Пример #5
0
/** same as TestAllyCone, but looks for neutral units */
bool TestNeutralCone(const float3& from, const float3& weaponDir, float length, float spread, CUnit* owner)
{
	int quads[1000];
	int* endQuad = quads;
	qf->GetQuadsOnRay(from, weaponDir, length, endQuad);

	for (int* qi = quads; qi != endQuad; ++qi) {
		const CQuadField::Quad& quad = qf->GetQuad(*qi);

		for (std::list<CUnit*>::const_iterator ui = quad.units.begin(); ui != quad.units.end(); ++ui) {
			CUnit* u = *ui;

			if (u == owner)
				continue;

			if (u->IsNeutral()) {
				if (TestConeHelper(from, weaponDir, length, spread, u))
					return true;
			}
		}
	}
	return false;
}
Пример #6
0
// called by {CRifle, CBeamLaser, CLightningCannon}::Fire()
float CGameHelper::TraceRay(const float3& start, const float3& dir, float length, float /*power*/, CUnit* owner, CUnit *&hit, int collisionFlags)
{
    float groundLength = ground->LineGroundCol(start, start + dir * length);
    const bool ignoreAllies = !!(collisionFlags & COLLISION_NOFRIENDLY);
    const bool ignoreFeatures = !!(collisionFlags & COLLISION_NOFEATURE);
    const bool ignoreNeutrals = !!(collisionFlags & COLLISION_NONEUTRAL);

    if (length > groundLength && groundLength > 0) {
        length = groundLength;
    }

    CollisionQuery cq;

    int quads[1000];
    int* endQuad = quads;
    qf->GetQuadsOnRay(start, dir, length, endQuad);

    if (!ignoreFeatures) {
        for (int* qi = quads; qi != endQuad; ++qi) {
            const CQuadField::Quad& quad = qf->GetQuad(*qi);

            for (std::list<CFeature*>::const_iterator ui = quad.features.begin(); ui != quad.features.end(); ++ui) {
                CFeature* f = *ui;

                if (!f->blocking || !f->collisionVolume) {
                    // NOTE: why check the blocking property?
                    continue;
                }

                if (CCollisionHandler::Intersect(f, start, start + dir * length, &cq)) {
                    const float3& intPos = (cq.b0)? cq.p0: cq.p1;
                    const float tmpLen = (intPos - start).Length();

                    // we want the closest feature (intersection point) on the ray
                    if (tmpLen < length) {
                        length = tmpLen;
                    }
                }
            }
        }
    }

    hit = 0;

    for (int* qi = quads; qi != endQuad; ++qi) {
        const CQuadField::Quad& quad = qf->GetQuad(*qi);

        for (std::list<CUnit*>::const_iterator ui = quad.units.begin(); ui != quad.units.end(); ++ui) {
            CUnit* u = *ui;

            if (u == owner)
                continue;
            if (ignoreAllies && u->allyteam == owner->allyteam)
                continue;
            if (ignoreNeutrals && u->IsNeutral()) {
                continue;
            }

            if (CCollisionHandler::Intersect(u, start, start + dir * length, &cq)) {
                const float3& intPos = (cq.b0)? cq.p0: cq.p1;
                const float tmpLen = (intPos - start).Length();

                // we want the closest unit (intersection point) on the ray
                if (tmpLen < length) {
                    length = tmpLen;
                    hit = u;
                }
            }
        }
    }

    return length;
}
Пример #7
0
void CProjectileHandler::CheckUnitCol()
{
	Projectile_List::iterator psi;

	static std::vector<CUnit*> tempUnits(uh->MaxUnits(), NULL);
	static std::vector<CFeature*> tempFeatures(uh->MaxUnits(), NULL);
	CollisionQuery q;

	for (psi = ps.begin(); psi != ps.end(); ++psi) {
		CProjectile* p = (*psi);

		if (p->checkCol && !p->deleteMe) {
			const float3 ppos0 = p->pos;
			const float3 ppos1 = p->pos + p->speed;

			float speedf = p->speed.Length();

			CUnit** endUnit = &tempUnits[0];
			CFeature** endFeature = &tempFeatures[0];
			qf->GetUnitsAndFeaturesExact(p->pos, p->radius + speedf, endUnit, endFeature);

			for (CUnit** ui = &tempUnits[0]; ui != endUnit; ++ui) {
				CUnit* unit = *ui;
				const bool friendlyShot = (p->owner() && (unit->allyteam == p->owner()->allyteam));
				const bool raytraced =
					(unit->collisionVolume &&
					unit->collisionVolume->GetTestType() == COLVOL_TEST_CONT);

				// if this unit fired this projectile or (this unit is in the
				// same allyteam as the unit that shot this projectile and we
				// are ignoring friendly collisions)
				if (p->owner() == unit || !unit->collisionVolume ||
					((p->collisionFlags & COLLISION_NOFRIENDLY) && friendlyShot)) {
					continue;
				}

				if (p->collisionFlags & COLLISION_NONEUTRAL) {
					if (unit->IsNeutral()) {
						continue;
					}
				}

				if (CCollisionHandler::DetectHit(unit, ppos0, ppos1, &q)) {
					// this projectile won't reach the raytraced surface impact pos
					// until Update() is called (right after we return, same frame)
					// which is a problem when dealing with fast low-AOE projectiles
					// since they would do almost no damage if detonated outside the
					// volume, so smuggle a bit ("rolling back" its pos in Update()
					// and waiting for the next-frame CheckUnitCol() is problematic
					// for noExplode projectiles)

					// const float3& pimpp = (q.b0)? q.p0: q.p1;
					const float3 pimpp =
						(q.b0 && q.b1)? (q.p0 + q.p1) * 0.5f:
						(q.b0        )? (q.p0 + ppos1) * 0.5f:
						                (ppos0 + q.p1) * 0.5f;

					p->pos = (raytraced)? pimpp: ppos0;
					p->Collision(unit);
					p->pos = (raytraced)? ppos0: p->pos;
					break;
				}
			}

			if (!(p->collisionFlags & COLLISION_NOFEATURE)) {
				for (CFeature** fi = &tempFeatures[0]; fi != endFeature; ++fi) {
					CFeature* feature = *fi;
					const bool raytraced =
						(feature->collisionVolume &&
						feature->collisionVolume->GetTestType() == COLVOL_TEST_CONT);

					// geothermals do not have a collision volume, skip them
					if (!feature->blocking || feature->def->geoThermal || !feature->collisionVolume) {
						continue;
					}

					if (CCollisionHandler::DetectHit(feature, ppos0, ppos1, &q)) {
						const float3 pimpp =
							(q.b0 && q.b1)? (q.p0 + q.p1) * 0.5f:
							(q.b0        )? (q.p0 + ppos1) * 0.5f:
							                (ppos0 + q.p1) * 0.5f;

						p->pos = (raytraced)? pimpp: ppos0;
						p->Collision(feature);
						p->pos = (raytraced)? ppos0: p->pos;
						break;
					}
				}
			}
		}
	}
}
Пример #8
0
// called by {CRifle, CBeamLaser, CLightningCannon}::Fire(), CWeapon::HaveFreeLineOfFire(), and Skirmish AIs
float TraceRay(
	const float3& start,
	const float3& dir,
	float length,
	int collisionFlags,
	const CUnit* owner,
	CUnit*& hitUnit,
	CFeature*& hitFeature
) {
	const bool ignoreEnemies  = ((collisionFlags & Collision::NOENEMIES   ) != 0);
	const bool ignoreAllies   = ((collisionFlags & Collision::NOFRIENDLIES) != 0);
	const bool ignoreFeatures = ((collisionFlags & Collision::NOFEATURES  ) != 0);
	const bool ignoreNeutrals = ((collisionFlags & Collision::NONEUTRALS  ) != 0);
	const bool ignoreGround   = ((collisionFlags & Collision::NOGROUND    ) != 0);

	const bool ignoreUnits = ignoreEnemies && ignoreAllies && ignoreNeutrals;

	hitFeature = NULL;
	hitUnit = NULL;

	if (dir == ZeroVector) {
		return -1.0f;
	}

	if (!ignoreFeatures || !ignoreUnits) {
		GML_RECMUTEX_LOCK(quad); // TraceRay
		CollisionQuery cq;

		int* begQuad = NULL;
		int* endQuad = NULL;

		qf->GetQuadsOnRay(start, dir, length, begQuad, endQuad);

		// feature intersection
		if (!ignoreFeatures) {
			for (int* quadPtr = begQuad; quadPtr != endQuad; ++quadPtr) {
				const CQuadField::Quad& quad = qf->GetQuad(*quadPtr);

				for (std::list<CFeature*>::const_iterator ui = quad.features.begin(); ui != quad.features.end(); ++ui) {
					CFeature* f = *ui;

					// NOTE:
					//     if f is non-blocking, ProjectileHandler will not test
					//     for collisions with projectiles so we can skip it here
					if (!f->blocking)
						continue;

					if (CCollisionHandler::DetectHit(f, start, start + dir * length, &cq, true)) {
						const float3& intPos = (cq.b0)? cq.p0: cq.p1;
						const float len = (intPos - start).dot(dir); // same as (intPos - start).Length()

						// we want the closest feature (intersection point) on the ray
						if (len < length) {
							length = len;
							hitFeature = f;
						}
					}
				}
			}
		}

		// unit intersection
		if (!ignoreUnits) {
			for (int* quadPtr = begQuad; quadPtr != endQuad; ++quadPtr) {
				const CQuadField::Quad& quad = qf->GetQuad(*quadPtr);

				for (std::list<CUnit*>::const_iterator ui = quad.units.begin(); ui != quad.units.end(); ++ui) {
					CUnit* u = *ui;

					if (u == owner)
						continue;
					if (ignoreAllies && u->allyteam == owner->allyteam)
						continue;
					if (ignoreNeutrals && u->IsNeutral())
						continue;
					if (ignoreEnemies && u->allyteam != owner->allyteam)
						continue;

					if (CCollisionHandler::DetectHit(u, start, start + dir * length, &cq, true)) {
						const float3& intPos = (cq.b0)? cq.p0: cq.p1;
						const float len = (intPos - start).dot(dir); // same as (intPos - start).Length()

						// we want the closest unit (intersection point) on the ray
						if (len < length) {
							length = len;
							hitUnit = u;
						}
					}
				}
			}
			if (hitUnit)
				hitFeature = NULL;
		}
	}

	if (!ignoreGround) {
		// ground intersection
		const float groundLength = ground->LineGroundCol(start, start + dir * length);
		if (length > groundLength && groundLength > 0) {
			length = groundLength;
			hitUnit = NULL;
			hitFeature = NULL;
		}
	}

	return length;
}
Пример #9
0
// called by {CRifle, CBeamLaser, CLightningCannon}::Fire() and Skirmish AIs
float TraceRay(const float3& start, const float3& dir, float length, int collisionFlags, const CUnit* owner, CUnit*& hitUnit, CFeature*& hitFeature)
{
	const bool ignoreEnemies  = !!(collisionFlags & Collision::NOENEMIES);
	const bool ignoreAllies   = !!(collisionFlags & Collision::NOFRIENDLIES);
	const bool ignoreFeatures = !!(collisionFlags & Collision::NOFEATURES);
	const bool ignoreNeutrals = !!(collisionFlags & Collision::NONEUTRALS);
	const bool ignoreGround   = !!(collisionFlags & Collision::NOGROUND);

	const bool ignoreUnits = ignoreEnemies && ignoreAllies && ignoreNeutrals;

	hitFeature = NULL;
	hitUnit = NULL;

	if (dir == ZeroVector) {
		return -1.0f;
	}

	CollisionQuery cq;

	{
		GML_RECMUTEX_LOCK(quad); // TraceRay
		const vector<int> &quads = qf->GetQuadsOnRay(start, dir, length);

		//! feature intersection
		if (!ignoreFeatures) {
			for (vector<int>::const_iterator qi = quads.begin(); qi != quads.end(); ++qi) {
				const CQuadField::Quad& quad = qf->GetQuad(*qi);

				for (std::list<CFeature*>::const_iterator ui = quad.features.begin(); ui != quad.features.end(); ++ui) {
					CFeature* f = *ui;

					if (!f->blocking || !f->collisionVolume) {
						// NOTE: why check the blocking property?
						continue;
					}

					if (CCollisionHandler::Intersect(f, start, start + dir * length, &cq)) {
						const float3& intPos = (cq.b0)? cq.p0: cq.p1;
						const float len = (intPos - start).dot(dir); //! same as (intPos - start).Length()

						//! we want the closest feature (intersection point) on the ray
						if (len < length) {
							length = len;
							hitFeature = f;
						}
					}
				}
			}
		}

		//! unit intersection
		if (!ignoreUnits) {
			for (vector<int>::const_iterator qi = quads.begin(); qi != quads.end(); ++qi) {
				const CQuadField::Quad& quad = qf->GetQuad(*qi);

				for (std::list<CUnit*>::const_iterator ui = quad.units.begin(); ui != quad.units.end(); ++ui) {
					CUnit* u = *ui;

					if (u == owner)
						continue;
					if (ignoreAllies && u->allyteam == owner->allyteam)
						continue;
					if (ignoreNeutrals && u->IsNeutral())
						continue;
					if (ignoreEnemies && u->allyteam != owner->allyteam)
						continue;

					if (CCollisionHandler::Intersect(u, start, start + dir * length, &cq)) {
						const float3& intPos = (cq.b0)? cq.p0: cq.p1;
						const float len = (intPos - start).dot(dir); //! same as (intPos - start).Length()

						//! we want the closest unit (intersection point) on the ray
						if (len < length) {
							length = len;
							hitUnit = u;
						}
					}
				}
			}
			if (hitUnit)
				hitFeature = NULL;
		}
	} //GML_RECMUTEX_LOCK(quad);

	if (!ignoreGround) {
		//! ground intersection
		float groundLength = ground->LineGroundCol(start, start + dir * length);
		if (length > groundLength && groundLength > 0) {
			length = groundLength;
			hitUnit = NULL;
			hitFeature = NULL;
		}
	}

	return length;
}
Пример #10
0
// called by {CRifle, CBeamLaser, CLightningCannon}::Fire(), CWeapon::HaveFreeLineOfFire(), and Skirmish AIs
float TraceRay(
	const float3& start,
	const float3& dir,
	float length,
	int avoidFlags,
	const CUnit* owner,
	CUnit*& hitUnit,
	CFeature*& hitFeature,
	CollisionQuery* hitColQuery
) {
	const bool ignoreEnemies  = ((avoidFlags & Collision::NOENEMIES   ) != 0);
	const bool ignoreAllies   = ((avoidFlags & Collision::NOFRIENDLIES) != 0);
	const bool ignoreFeatures = ((avoidFlags & Collision::NOFEATURES  ) != 0);
	const bool ignoreNeutrals = ((avoidFlags & Collision::NONEUTRALS  ) != 0);
	const bool ignoreGround   = ((avoidFlags & Collision::NOGROUND    ) != 0);

	const bool ignoreUnits = ignoreEnemies && ignoreAllies && ignoreNeutrals;

	hitFeature = NULL;
	hitUnit = NULL;

	if (dir == ZeroVector)
		return -1.0f;

	if (!ignoreFeatures || !ignoreUnits) {
		GML_RECMUTEX_LOCK(quad); // TraceRay

		CollisionQuery cq;

		int* begQuad = NULL;
		int* endQuad = NULL;

		quadField->GetQuadsOnRay(start, dir, length, begQuad, endQuad);

		// locally point somewhere non-NULL; we cannot pass hitColQuery
		// to DetectHit directly because each call resets it internally
		if (hitColQuery == NULL)
			hitColQuery = &cq;

		// feature intersection
		if (!ignoreFeatures) {
			for (int* quadPtr = begQuad; quadPtr != endQuad; ++quadPtr) {
				const CQuadField::Quad& quad = quadField->GetQuad(*quadPtr);

				for (std::list<CFeature*>::const_iterator ui = quad.features.begin(); ui != quad.features.end(); ++ui) {
					CFeature* f = *ui;

					// NOTE:
					//     if f is non-blocking, ProjectileHandler will not test
					//     for collisions with projectiles so we can skip it here
					if (!f->HasCollidableStateBit(CSolidObject::CSTATE_BIT_QUADMAPRAYS))
						continue;

					if (CCollisionHandler::DetectHit(f, start, start + dir * length, &cq, true)) {
						const float len = cq.GetHitPosDist(start, dir);

						// we want the closest feature (intersection point) on the ray
						if (len < length) {
							length = len;
							hitFeature = f;
							*hitColQuery = cq;
						}
					}
				}
			}
		}

		// unit intersection
		if (!ignoreUnits) {
			for (int* quadPtr = begQuad; quadPtr != endQuad; ++quadPtr) {
				const CQuadField::Quad& quad = quadField->GetQuad(*quadPtr);

				for (std::list<CUnit*>::const_iterator ui = quad.units.begin(); ui != quad.units.end(); ++ui) {
					CUnit* u = *ui;

					if (u == owner)
						continue;
					if (!u->HasCollidableStateBit(CSolidObject::CSTATE_BIT_QUADMAPRAYS))
						continue;
					if (ignoreAllies && u->allyteam == owner->allyteam)
						continue;
					if (ignoreNeutrals && u->IsNeutral())
						continue;
					if (ignoreEnemies && u->allyteam != owner->allyteam)
						continue;

					if (CCollisionHandler::DetectHit(u, start, start + dir * length, &cq, true)) {
						const float len = cq.GetHitPosDist(start, dir);

						// we want the closest unit (intersection point) on the ray
						if (len < length) {
							length = len;
							hitUnit = u;
							*hitColQuery = cq;
						}
					}
				}
			}
			if (hitUnit)
				hitFeature = NULL;
		}
	}

	if (!ignoreGround) {
		// ground intersection
		const float groundLength = ground->LineGroundCol(start, start + dir * length);

		if (length > groundLength && groundLength > 0.0f) {
			length = groundLength;
			hitUnit = NULL;
			hitFeature = NULL;
		}
	}

	return length;
}