Exemplo n.º 1
0
void CFlameProjectile::Update()
{
	if (!luaMoveCtrl) {
		SetPosition(pos + speed);
		UpdateGroundBounce();
		SetVelocityAndSpeed(speed + spread);
	}

	UpdateInterception();

	radius = radius + weaponDef->sizeGrowth;
	sqRadius = radius * radius;
	drawRadius = radius * weaponDef->collisionSize;

	curTime += invttl;
	if (curTime > physLife) {
		checkCol = false;
	}
	if (curTime > 1) {
		curTime = 1;
		deleteMe = true;
	}

	explGenHandler->GenExplosion(cegID, pos, speed, curTime, 0.0f, 0.0f, NULL, NULL);
}
void CGeoThermSmokeProjectile::UpdateDir()
{
	if (geo == NULL)
		return;

	const CSolidObject* obj = geo->solidOnTop;

	if (obj == NULL)
		return;
	if (!obj->HasCollidableStateBit(CSolidObject::CSTATE_BIT_SOLIDOBJECTS))
		return;

	float3 geoVector = pos - obj->pos;

	if (geoVector.SqLength() == 0.0f)
		return;
	if (geoVector.SqLength() >= (obj->radius * obj->radius))
		return;

	geoVector *= (obj->radius * fastmath::isqrt_sse(geoVector.SqLength()));

	SetPosition(pos * 0.3f + (obj->pos + geoVector) * 0.7f);

	if (geoVector.y >= (obj->radius * 0.4f))
		return;

	// escape sideways if covered by geothermal object (unreliable)
	const float3 orthoDir = float3(geoVector.z, 0.0f, -geoVector.x);
	const float3 newDir = (geoVector.cross(orthoDir)).ANormalize();

	SetVelocityAndSpeed(newDir * speed.w);
}
Exemplo n.º 3
0
void CFlareProjectile::Update()
{
	CUnit* owner = CProjectile::owner();

	if (gs->frameNum == activateFrame) {
		if (owner != NULL) {
			SetPosition(owner->pos);
			CWorldObject::SetVelocity(owner->speed);
			CWorldObject::SetVelocity(speed + (owner->rightdir * owner->unitDef->flareDropVector.x));
			CWorldObject::SetVelocity(speed + (owner->updir    * owner->unitDef->flareDropVector.y));
			CWorldObject::SetVelocity(speed + (owner->frontdir * owner->unitDef->flareDropVector.z));
			SetVelocityAndSpeed(speed);
		} else {
			deleteMe = true;
		}
	}
	if (gs->frameNum >= activateFrame) {
		SetPosition(pos + speed);
		SetVelocityAndSpeed((speed * 0.95f) + (UpVector * mygravity));

		//FIXME: just spawn new flares, if new missiles incoming?
		if(owner && lastSub < (gs->frameNum - owner->unitDef->flareSalvoDelay) && numSub<owner->unitDef->flareSalvoSize) {
			subPos[numSub] = owner->pos;
			float3 s = owner->speed;
			s += owner->rightdir * owner->unitDef->flareDropVector.x;
			s += owner->updir * owner->unitDef->flareDropVector.y;
			s += owner->frontdir * owner->unitDef->flareDropVector.z;
			subSpeed[numSub] = s;
			++numSub;
			lastSub = gs->frameNum;

			for (CMissileProjectile* missile: owner->incomingMissiles) {
				if (gsRNG.NextFloat() < owner->unitDef->flareEfficiency) {
					missile->SetTargetObject(this);
					missile->AddDeathDependence(this, DEPENDENCE_DECOYTARGET);
				}
			}
		}
		for (int a = 0; a < numSub; ++a) {
			subPos[a] += subSpeed[a];
			subSpeed[a] *= 0.95f;
			subSpeed[a].y += mygravity;
		}
	}

	deleteMe |= (gs->frameNum >= deathFrame);
}
Exemplo n.º 4
0
void CProjectile::Update()
{
	if (luaMoveCtrl)
		return;

	SetPosition(pos + speed);
	SetVelocityAndSpeed(speed + (UpVector * mygravity));
}
Exemplo n.º 5
0
void CFlameProjectile::Collision()
{
	const float3 norm = ground->GetNormal(pos.x, pos.z);
	const float ns = speed.dot(norm);

	SetVelocityAndSpeed(speed - (norm * ns));
	SetPosition(pos + UpVector * 0.05f);

	curTime += 0.05f;
}
Exemplo n.º 6
0
void CGenericParticleProjectile::Update()
{
	SetPosition(pos + speed);
	SetVelocityAndSpeed((speed + gravity) * airdrag);

	life += decayrate;
	size = size * sizeMod + sizeGrowth;

	deleteMe |= (life > 1.0f);
}
Exemplo n.º 7
0
void CPieceProjectile::Update()
{
	if (!luaMoveCtrl) {
		SetVelocityAndSpeed((speed += (UpVector * mygravity)) * 0.997f);
		SetPosition(pos + speed);
	}

	spinParams.y += spinParams.x;
	age += 1;
	checkCol |= (age > 10);

	if ((explFlags & PF_NoCEGTrail) == 0) {
		// TODO: pass a more sensible ttl to the CEG (age-related?)
		explGenHandler->GenExplosion(cegID, pos, speed, 100, 0.0f, 0.0f, nullptr, nullptr);
		return;
	}

	if ((explFlags & PF_Fire) != 0) {
		for (int a = NUM_TRAIL_PARTS - 2; a >= 0; --a) {
			fireTrailPoints[a + 1] = fireTrailPoints[a];
		}

		CMatrix44f m(pos);

		m.Rotate(spinParams.y * math::DEG_TO_RAD, spinVector);
		m.Translate(mix(modelPiece->mins, modelPiece->maxs, float3(guRNG.NextFloat(), guRNG.NextFloat(), guRNG.NextFloat())));

		fireTrailPoints[0] = {m.GetPos(), 1.0f + guRNG.NextFloat()};
	}

	if ((explFlags & PF_Smoke) != 0) {
		if (smokeTrail != nullptr)
			smokeTrail->UpdateEndPos(oldSmokePos = pos, oldSmokeDir = dir);

		if ((age % 8) == 0) {
			// need the temporary to avoid an undefined ref
			const unsigned int smokeTime = TRAIL_SMOKE_TIME;

			smokeTrail = projMemPool.alloc<CSmokeTrailProjectile>(
				owner(),
				projectileDrawer->smoketrailtex,
				pos, oldSmokePos,
				dir, oldSmokeDir,
				smokeTime,
				14.0f,
				0.5f,
				age == (NUM_TRAIL_PARTS - 1),
				false
			);

			useAirLos = smokeTrail->useAirLos;
		}
	}
}
Exemplo n.º 8
0
int CExplosiveProjectile::ShieldRepulse(const float3& shieldPos, float shieldForce, float shieldMaxSpeed)
{
	if (luaMoveCtrl)
		return 0;

	const float3 rdir = (pos - shieldPos).Normalize();

	if (rdir.dot(speed) < shieldMaxSpeed) {
		SetVelocityAndSpeed(speed + (rdir * shieldForce));
		return 2;
	}

	return 0;
}
Exemplo n.º 9
0
void CDirtProjectile::Update()
{
	SetVelocityAndSpeed((speed * slowdown) + (UpVector * mygravity));
	SetPosition(pos + speed);

	alpha = std::max(alpha - alphaFalloff, 0.0f);
	size += sizeExpansion;

	if (ground->GetApproximateHeight(pos.x, pos.z, false) - 40.0f > pos.y) {
		deleteMe = true;
	}
	if (alpha <= 0.0f) {
		deleteMe = true;
	}
}
Exemplo n.º 10
0
void CPieceProjectile::Collision()
{
	Collision(nullptr, nullptr);
	if (gsRNG.NextFloat() < 0.666f) { // give it a small chance to `ground bounce`
		CProjectile::Collision();
		return;
	}

	// ground bounce
	const float3& norm = CGround::GetNormal(pos.x, pos.z);
	const float ns = speed.dot(norm);

	SetVelocityAndSpeed(speed - (norm * ns * 1.6f));
	SetPosition(pos + (norm * 0.1f));
}
Exemplo n.º 11
0
void CWeaponProjectile::UpdateGroundBounce()
{
	// projectile is not allowed to bounce on either surface
	if (!weaponDef->groundBounce && !weaponDef->waterBounce)
		return;
	// max bounce already reached?
	if ((bounces + 1) > weaponDef->numBounce)
		return;
	if (luaMoveCtrl)
		return;
	if (ttl <= 0)
		return;

	// water or ground bounce?
	float3 normal;
	bool bounced = false;
	const float distWaterHit  = (pos.y > 0.0f && speed.y < 0.0f) ? (pos.y / -speed.y) : -1.0f;
	const bool intersectWater = (distWaterHit >= 0.0f) && (distWaterHit <= 1.0f);
	if (intersectWater && weaponDef->waterBounce) {
		pos += speed * distWaterHit;
		pos.y = 0.5f;
		normal = CGround::GetNormalAboveWater(pos.x, pos.z);
		bounced = true;
	} else {
		const float distGroundHit  = CGround::LineGroundCol(pos, pos + speed); //TODO use traj one for traj weapons?
		const bool intersectGround = (distGroundHit >= 0.0f);
		if (intersectGround && weaponDef->groundBounce) {
			static const float dontTouchSurface = 0.99f;
			pos += dir * distGroundHit * dontTouchSurface;
			normal = CGround::GetNormal(pos.x, pos.z);
			bounced = true;
		}
	}

	if (!bounced)
		return;

	// spawn CEG before bouncing, otherwise we might be too
	// far up in the air if it has the (under)water flag set
	explGenHandler->GenExplosion(weaponDef->bounceExplosionGeneratorID, pos, normal, speed.w, 1.0f, 1.0f, owner(), NULL);

	++bounces;
	const float dot = math::fabs(speed.dot(normal));
	CWorldObject::SetVelocity(speed - (speed + normal * dot) * (1 - weaponDef->bounceSlip   ));
	CWorldObject::SetVelocity(         speed + normal * dot  * (1 + weaponDef->bounceRebound));
	SetVelocityAndSpeed(speed);
}
Exemplo n.º 12
0
void CFlameProjectile::Update()
{
	if (!luaMoveCtrl) {
		SetPosition(pos + speed);
		UpdateGroundBounce();
		SetVelocityAndSpeed(speed + spread);
	}

	UpdateInterception();

	radius = radius + weaponDef->sizeGrowth;
	sqRadius = radius * radius;
	drawRadius = radius * weaponDef->collisionSize;

	curTime += invttl;
	checkCol &= (curTime <= physLife);
	curTime = std::min(curTime, 1.0f);
	deleteMe |= (curTime >= 1.0f);

	explGenHandler->GenExplosion(cegID, pos, speed, curTime, 0.0f, 0.0f, nullptr, nullptr);
}
Exemplo n.º 13
0
void CProjectile::Init(const CUnit* owner, const float3& offset)
{
	if (owner != NULL) {
		// must be set before the AddProjectile call
		ownerID = owner->id;
		teamID = owner->team;
		allyteamID =  teamHandler->IsValidTeam(teamID)? teamHandler->AllyTeam(teamID): -1;
	}
	if (!hitscan) {
		SetPosition(pos + offset);
		SetVelocityAndSpeed(speed);
	}
	if (!weapon && !piece) {
		// NOTE:
		//   new CWeapon- and CPieceProjectile*'s add themselves
		//   to CProjectileHandler (other code needs to be able
		//   to dyna-cast CProjectile*'s to those derived types,
		//   and adding them here would throw away too much RTTI)
		projectileHandler->AddProjectile(this);
	}
	if (synced && !weapon) {
		quadField->AddProjectile(this);	
	}
}
Exemplo n.º 14
0
CWeaponProjectile::CWeaponProjectile(const ProjectileParams& params)
	: CProjectile(params.pos, params.speed, params.owner, true, true, false, false)

	, damages(nullptr)
	, weaponDef(params.weaponDef)
	, target(params.target)

	, ttl(params.ttl)
	, bounces(0)

	, targeted(false)

	, startPos(params.pos)
	, targetPos(params.end)
{
	projectileType = WEAPON_BASE_PROJECTILE;

	assert(weaponDef != nullptr);

	if (weaponDef->IsHitScanWeapon()) {
		hitscan = true;
		// the else-case (default) is handled in CProjectile::Init
		//
		// ray projectiles must all set this to false because their collision
		// detection is handled by the weapons firing them, ProjectileHandler
		// will skip any tests for these
		checkCol = false;
		// type has not yet been set by derived ctor's at this point
		// useAirLos = (projectileType != WEAPON_LIGHTNING_PROJECTILE);
		useAirLos = true;

		// NOTE:
		//   {BeamLaser, Lightning}Projectile's do NOT actually move (their
		//   speed is never added to pos) and never alter their speed either
		//   they additionally override our ::Update (so CProjectile::Update
		//   is also never called) which means assigning speed a non-zerovec
		//   value should have no side-effects
		SetPosition(startPos);
		SetVelocityAndSpeed(targetPos - startPos);

		// ProjectileDrawer vis-culls by pos == startPos, but we
		// want to see the beam even if camera is near targetPos
		// --> use full distance for drawRadius
		SetRadiusAndHeight((targetPos - startPos).Length(), 0.0f);
	}

	collisionFlags = weaponDef->collisionFlags;
	weaponNum = params.weaponNum;
	alwaysVisible = weaponDef->visuals.alwaysVisible;
	ignoreWater = weaponDef->waterweapon;

	CSolidObject* so = NULL;
	CWeaponProjectile* po = NULL;

	if ((so = dynamic_cast<CSolidObject*>(target)) != NULL) {
		AddDeathDependence(so, DEPENDENCE_WEAPONTARGET);
	}
	if ((po = dynamic_cast<CWeaponProjectile*>(target)) != NULL) {
		po->SetBeingIntercepted(po->IsBeingIntercepted() || weaponDef->interceptSolo);
		AddDeathDependence(po, DEPENDENCE_INTERCEPTTARGET);
	}

	if (params.model != NULL) {
		model = params.model;
	} else {
		model = weaponDef->LoadModel();
	}

	if (params.owner == NULL) {
		// the else-case (default) is handled in CProjectile::Init
		ownerID = params.ownerID;
		teamID = params.teamID;
		allyteamID = teamHandler->IsValidTeam(teamID)? teamHandler->AllyTeam(teamID): -1;
	}

	if (ownerID != -1u && weaponNum != -1u) {
		const CUnit* owner = unitHandler->GetUnit(ownerID);
		if (owner != nullptr && weaponNum < owner->weapons.size()) {
			damages = DynDamageArray::IncRef(owner->weapons[weaponNum]->damages);
		}
	}
	if (damages == nullptr)
		damages = DynDamageArray::IncRef(&weaponDef->damages);

	if (params.cegID != -1u) {
		cegID = params.cegID;
	} else {
		cegID = weaponDef->ptrailExplosionGeneratorID;
	}

	// must happen after setting position and velocity
	projectileHandler->AddProjectile(this);
	quadField->AddProjectile(this);

	ASSERT_SYNCED(id);

	if (weaponDef->targetable) {
		interceptHandler.AddInterceptTarget(this, targetPos);
	}
}
Exemplo n.º 15
0
void CTorpedoProjectile::Update()
{
	// tracking only works when we are underwater
	if (!weaponDef->submissile && pos.y > 0.0f) {
		if (!luaMoveCtrl) {
			// must update dir and speed.w here
			SetVelocityAndSpeed(speed + (UpVector * mygravity));
		}
	} else {
		if (--ttl > 0) {
			if (!luaMoveCtrl) {
				float3 targetVel;

				if (speed.w < maxSpeed)
					speed.w += std::max(0.2f, tracking);

				if (target != NULL) {
					const CSolidObject* so = dynamic_cast<const CSolidObject*>(target);
					const CWeaponProjectile* po = dynamic_cast<const CWeaponProjectile*>(target);

					targetPos = target->pos;

					if (so != NULL) {
						targetPos = so->aimPos;
						targetVel = so->speed;

						if (allyteamID != -1 && pos.SqDistance(so->aimPos) > Square(150.0f)) {
							const CUnit* u = dynamic_cast<const CUnit*>(so);

							if (u != NULL) {
								targetPos = u->GetErrorPos(allyteamID, true);
							}
						}
					}
					if (po != NULL) {
						targetVel = po->speed;
					}
				}

				if (!weaponDef->submissile && targetPos.y > 0.0f) {
					targetPos.y = 0.0f;
				}

				const float3 targetLeadVec = targetVel * (pos.distance(targetPos) / maxSpeed) * 0.7f;
				const float3 targetLeadDir = (targetPos + targetLeadVec - pos).Normalize();

				float3 targetDirDif = targetLeadDir - dir;

				if (targetDirDif.Length() < tracking) {
					dir = targetLeadDir;
				} else {
					// <tracking> is the projectile's turn-rate
					targetDirDif = (targetDirDif - (dir * targetDirDif.dot(dir))).SafeNormalize();
					dir = (dir + (targetDirDif * tracking)).SafeNormalize();
				}

				// do not need to update dir or speed.w here
				CWorldObject::SetVelocity(dir * speed.w);
			}

			explGenHandler->GenExplosion(cegID, pos, speed, ttl, areaOfEffect, 0.0f, NULL, NULL);
		} else {
			if (!luaMoveCtrl) {
				// must update dir and speed.w here
				SetVelocityAndSpeed((speed * 0.98f) + (UpVector * mygravity));
			}
		}
	}

	if (!luaMoveCtrl) {
		SetPosition(pos + speed);
	}

	if (pos.y < -2.0f) {
		--nextBubble;

		if (nextBubble == 0) {
			nextBubble = 1 + (int) (gs->randFloat() * 1.5f);

			const float3 pspeed = (gs->randVector() * 0.1f) + float3(0.0f, 0.2f, 0.0f);

			new CBubbleProjectile(
				owner(),
				pos + gs->randVector(), pspeed, 40 + gs->randFloat() * GAME_SPEED,
				1 + gs->randFloat() * 2, 0.01f, 0.3f + gs->randFloat() * 0.3f
			);
		}
	}

	UpdateGroundBounce();
	UpdateInterception();
}