Example #1
0
void CProjectileHandler::CheckGroundCollisions(ProjectileContainer& pc) {
	ProjectileContainer::iterator pci;

	for (pci = pc.begin(); pci != pc.end(); ++pci) {
		CProjectile* p = *pci;

		if (!p->checkCol) {
			continue;
		}

		// NOTE: if <p> is a MissileProjectile and does not
		// have selfExplode set, it will never be removed (!)
		if (p->GetCollisionFlags() & Collision::NOGROUND) {
			continue;
		}

		// NOTE: don't add p->radius to groundHeight, or most
		// projectiles will collide with the ground too early
		const float groundHeight = ground->GetHeightReal(p->pos.x, p->pos.z);
		const bool belowGround = (p->pos.y < groundHeight);
		const bool insideWater = (p->pos.y <= 0.0f && !belowGround);
		const bool ignoreWater = p->ignoreWater;

		if (belowGround || (insideWater && !ignoreWater)) {
			// if position has dropped below terrain or into water
			// where we cannot live, adjust it and explode us now
			// (if the projectile does not set deleteMe = true, it
			// will keep hugging the terrain)
			p->pos.y = belowGround? groundHeight: 0.0f;
			p->Collision();
		}
	}
}
void CProjectileHandler::DrawProjectiles(const ProjectileContainer& pc, bool drawReflection, bool drawRefraction) {
	for (ProjectileContainer::render_iterator pci = pc.render_begin(); pci != pc.render_end(); ++pci) {
		CProjectile* pro = *pci;

		pro->UpdateDrawPos();

		if (camera->InView(pro->pos, pro->drawRadius) && (gu->spectatingFullView || loshandler->InLos(pro, gu->myAllyTeam) ||
			(pro->owner() && teamHandler->Ally(pro->owner()->allyteam, gu->myAllyTeam)))) {

			CUnit* owner = pro->owner();
			bool stunned = owner? owner->stunned: false;

			if (owner && stunned && dynamic_cast<CShieldPartProjectile*>(pro)) {
				// if the unit that fired this projectile is stunned and the projectile
				// forms part of a shield (ie., the unit has a CPlasmaRepulser weapon but
				// cannot fire it), prevent the projectile (shield segment) from being drawn
				//
				// also prevents shields being drawn at unit's pre-pickup position
				// (since CPlasmaRepulser::Update() is responsible for updating
				// CShieldPartProjectile::centerPos) if the unit is in a non-fireplatform
				// transport
				continue;
			}

			if (drawReflection) {
				if (pro->pos.y < -pro->drawRadius)
					continue;

				float dif = pro->pos.y - camera->pos.y;
				float3 zeroPos = camera->pos * (pro->pos.y / dif) + pro->pos * (-camera->pos.y / dif);

				if (ground->GetApproximateHeight(zeroPos.x, zeroPos.z) > 3 + 0.5f * pro->drawRadius)
					continue;
			}

			if (drawRefraction && pro->pos.y > pro->drawRadius)
				continue;

			if (pro->s3domodel) {
				if (pro->s3domodel->type == MODELTYPE_S3O) {
					unitDrawer->QueS3ODraw(pro, pro->s3domodel->textureType);
				} else {
					pro->DrawUnitPart();
				}
			}

			pro->tempdist = pro->pos.dot(camera->forward);
			distset.insert(pro);
		}
	}
}
void CProjectileHandler::CheckGroundCollisions(ProjectileContainer& pc) {
	ProjectileContainer::iterator pci;

	for (pci = pc.begin(); pci != pc.end(); ++pci) {
		CProjectile* p = *pci;

		if (p->checkCol) {
			// too many projectiles seem to impact the ground before
			// actually hitting so don't subtract the projectile radius
			if (ground->GetHeight(p->pos.x, p->pos.z) > p->pos.y /* - p->radius*/) {
				p->Collision();
			}
		}
	}
}
void CProjectileHandler::DrawProjectilesShadow(const ProjectileContainer& pc) {
	for (ProjectileContainer::render_iterator pci = pc.render_begin(); pci != pc.render_end(); ++pci) {
		CProjectile* p = *pci;

		if ((gu->spectatingFullView || loshandler->InLos(p, gu->myAllyTeam) ||
			(p->owner() && teamHandler->Ally(p->owner()->allyteam, gu->myAllyTeam)))) {

			if (p->s3domodel) {
				p->DrawUnitPart();
			} else if (p->castShadow) {
				p->Draw();
			}
		}
	}
}
void CProjectileHandler::CheckUnitFeatureCollisions(ProjectileContainer& pc) {
	static std::vector<CUnit*> tempUnits(uh->MaxUnits(), NULL);
	static std::vector<CFeature*> tempFeatures(uh->MaxUnits(), NULL);

	for (ProjectileContainer::iterator pci = pc.begin(); pci != pc.end(); ++pci) {
		CProjectile* p = *pci;

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

			CUnit** endUnit = &tempUnits[0];
			CFeature** endFeature = &tempFeatures[0];

			qf->GetUnitsAndFeaturesExact(p->pos, p->radius + speedf, endUnit, endFeature);

			CheckUnitCollisions(p, tempUnits, endUnit, ppos0, ppos1);
			CheckFeatureCollisions(p, tempFeatures, endFeature, ppos0, ppos1);
		}
	}
}
void CProjectileHandler::DrawProjectilesMiniMap(const ProjectileContainer& pc) {
	if (pc.render_size() > 0) {
		CVertexArray* lines = GetVertexArray();
		CVertexArray* points = GetVertexArray();

		lines->Initialize();
		lines->EnlargeArrays(pc.render_size() * 2, 0, VA_SIZE_C);

		points->Initialize();
		points->EnlargeArrays(pc.render_size(), 0, VA_SIZE_C);

		for (ProjectileContainer::render_iterator pci = pc.render_begin(); pci != pc.render_end(); ++pci) {
			CProjectile* p = *pci;

			if ((p->owner() && (p->owner()->allyteam == gu->myAllyTeam)) ||
				gu->spectatingFullView || loshandler->InLos(p, gu->myAllyTeam)) {
				p->DrawOnMinimap(*lines, *points);
			}
		}

		lines->DrawArrayC(GL_LINES);
		points->DrawArrayC(GL_POINTS);
	}
}
void CProjectileHandler::UpdateProjectileContainer(ProjectileContainer& pc, bool synced) {
	ProjectileContainer::iterator pci = pc.begin();

	while (pci != pc.end()) {
		CProjectile* p = *pci;

		if (p->deleteMe) {
			if (p->synced) {
				assert(synced);
				if(p->weapon || p->piece) {

					//! iterator is always valid
					const ProjectileMap::iterator it = syncedProjectileIDs.find(p->id);
					const ProjectileMapPair& pp = it->second;

					eventHandler.ProjectileDestroyed(pp.first, pp.second);
					syncedProjectileIDs.erase(it);

					if (p->id != 0) {
						freeIDs.push_back(p->id);
					}
				}
				//! push_back this projectile for deletion
				pci = pc.erase_delete_synced(pci);
			}
			else {
				assert(!synced);
				pci = pc.erase_delete(pci);
			}
		} else {
			p->Update();
			GML_GET_TICKS(p->lastProjUpdate);
			++pci;
		}
	}
}
Example #8
0
void CProjectileHandler::CheckGroundCollisions(ProjectileContainer& pc)
{
	for (size_t i = 0; i < pc.size(); ++i) {
		CProjectile* p = pc[i];

		if (!p->checkCol)
			continue;

		// NOTE:
		//   if <p> is a MissileProjectile and does not have
		//   selfExplode set, tbis will cause it to never be
		//   removed (!)
		if (p->GetCollisionFlags() & Collision::NOGROUND)
			continue;

		// don't collide with ground yet if last update scheduled a bounce
		if (p->weapon && static_cast<const CWeaponProjectile*>(p)->HasScheduledBounce())
			continue;

		// NOTE:
		//   don't add p->radius to groundHeight, or most (esp. modelled)
		//   projectiles will collide with the ground one or more frames
		//   too early
		const float groundHeight = CGround::GetHeightReal(p->pos.x, p->pos.z);

		const bool belowGround = (p->pos.y < groundHeight);
		const bool insideWater = (p->pos.y <= 0.0f && !belowGround);
		const bool ignoreWater = p->ignoreWater;

		if (belowGround || (insideWater && !ignoreWater)) {
			// if position has dropped below terrain or into water
			// where we can not live, adjust it and explode us now
			// (if the projectile does not set deleteMe = true, it
			// will keep hugging the terrain)
			p->SetPosition(p->pos * XZVector + UpVector * groundHeight * belowGround);
			p->Collision();
		}
	}
}
Example #9
0
void CProjectileHandler::CheckUnitFeatureCollisions(ProjectileContainer& pc)
{
	static std::vector<CUnit*> tempUnits;
	static std::vector<CFeature*> tempFeatures;
	static std::vector<CPlasmaRepulser*> tempRepulsers;

	for (size_t i = 0; i < pc.size(); ++i) {
		CProjectile* p = pc[i];

		if (!p->checkCol) continue;
		if ( p->deleteMe) continue;

		const float3 ppos0 = p->pos;
		const float3 ppos1 = p->pos + p->speed;

		quadField->GetUnitsAndFeaturesColVol(p->pos, p->radius + p->speed.w, tempUnits, tempFeatures, &tempRepulsers);

		CheckShieldCollisions(p, tempRepulsers, ppos0, ppos1); tempRepulsers.clear();
		CheckUnitCollisions(p, tempUnits, ppos0, ppos1); tempUnits.clear();
		CheckFeatureCollisions(p, tempFeatures, ppos0, ppos1); tempFeatures.clear();
	}
}
Example #10
0
void CProjectileHandler::UpdateProjectileContainer(ProjectileContainer& pc, bool synced) {
	ProjectileContainer::iterator pci = pc.begin();

	#define VECTOR_SANITY_CHECK(v)                              \
		assert(!math::isnan(v.x) && !math::isinf(v.x)); \
		assert(!math::isnan(v.y) && !math::isinf(v.y)); \
		assert(!math::isnan(v.z) && !math::isinf(v.z));
	#define MAPPOS_SANITY_CHECK(v)                 \
		assert(v.x >= -(float3::maxxpos * 16.0f)); \
		assert(v.x <=  (float3::maxxpos * 16.0f)); \
		assert(v.z >= -(float3::maxzpos * 16.0f)); \
		assert(v.z <=  (float3::maxzpos * 16.0f)); \
		assert(v.y >= -MAX_PROJECTILE_HEIGHT);     \
		assert(v.y <=  MAX_PROJECTILE_HEIGHT);
	#define PROJECTILE_SANITY_CHECK(p) \
		VECTOR_SANITY_CHECK(p->pos);   \
		MAPPOS_SANITY_CHECK(p->pos);

	while (pci != pc.end()) {
		CProjectile* p = *pci;

		if (p->deleteMe) {
			ProjectileMap::iterator pIt;

			if (p->synced) {
				//! iterator is always valid
				pIt = syncedProjectileIDs.find(p->id);

				eventHandler.ProjectileDestroyed((pIt->second).first, (pIt->second).second);
				syncedProjectileIDs.erase(pIt);

				freeSyncedIDs.push_back(p->id);

				//! push_back this projectile for deletion
				pci = pc.erase_delete_synced(pci);
			} else {
#if UNSYNCED_PROJ_NOEVENT
				eventHandler.UnsyncedProjectileDestroyed(p);
#else
				pIt = unsyncedProjectileIDs.find(p->id);

				eventHandler.ProjectileDestroyed((pIt->second).first, (pIt->second).second);
				unsyncedProjectileIDs.erase(pIt);

				freeUnsyncedIDs.push_back(p->id);
#endif
#if DETACH_SYNCED
				pci = pc.erase_detach(pci);
#else
				pci = pc.erase_delete(pci);
#endif
			}
		} else {
			PROJECTILE_SANITY_CHECK(p);

			p->Update();
			qf->MovedProjectile(p);

			PROJECTILE_SANITY_CHECK(p);
			GML_GET_TICKS(p->lastProjUpdate);

			++pci;
		}
	}
}
Example #11
0
void CProjectileHandler::UpdateProjectileContainer(ProjectileContainer& pc, bool synced)
{
	// WARNING:
	//   we can't use iterators here because ProjectileCreated
	//   and ProjectileDestroyed events may add new projectiles
	//   to the container!
	for (size_t i = 0; i < pc.size(); /*no-op*/) {
		CProjectile* p = pc[i];

		assert(p != nullptr);
		assert(p->synced == synced);
#ifdef USING_CREG
		assert(p->synced == !!(p->GetClass()->binder->flags & creg::CF_Synced));
#endif

		// creation
		if (p->callEvent) {
			if (synced || !UNSYNCED_PROJ_NOEVENT)
				eventHandler.ProjectileCreated(p, p->GetAllyteamID());

			eventHandler.RenderProjectileCreated(p);
			p->callEvent = false;
		}

		// deletion (FIXME: move outside of loop)
		if (p->deleteMe) {
			pc[i] = pc.back();
			pc.pop_back();

			eventHandler.RenderProjectileDestroyed(p);

			if (synced) {
				eventHandler.ProjectileDestroyed(p, p->GetAllyteamID());
				syncedProjectileIDs[p->id] = nullptr;
				freeSyncedIDs.push_back(p->id);

				ASSERT_SYNCED(p->pos);
				ASSERT_SYNCED(p->id);
			} else {
			#if !UNSYNCED_PROJ_NOEVENT
				eventHandler.ProjectileDestroyed(p, p->GetAllyteamID());
				unsyncedProjectileIDs[p->id] = nullptr;
				freeUnsyncedIDs.push_back(p->id);
			#endif
			}

			projMemPool.free(p);
			continue;
		}

		// neither
		++i;
	}

	SCOPED_TIMER("Sim::Projectiles::Update");

	// WARNING: same as above but for p->Update()
	for (size_t i = 0; i < pc.size(); ++i) {
		CProjectile* p = pc[i];
		assert(p != nullptr);

		MAPPOS_SANITY_CHECK(p->pos);

		p->Update();
		quadField->MovedProjectile(p);

		MAPPOS_SANITY_CHECK(p->pos);
	}
}