예제 #1
0
void        CweaponIGC::FireWeapon(Time now)
{
	assert(m_mountID >= 0);
	assert(m_ship);

	bool    fFiredShot = false;

	if (m_fActive && (m_nextFire < now))
	{
		Time    lastUpdate = m_ship->GetLastUpdate();

		//Never fire retroactively.
		if (m_nextFire < lastUpdate)
			m_nextFire = lastUpdate;

		bool    fSelected = fIsWeaponSelected();

		float   energy = m_ship->GetEnergy();                   //the energy the ship would have at "now"
		if (energy >= m_typeData->energyPerShot)
		{
			//We'd be able to fire before now and would have enough energy at now to fire, so ...
			float   rechargeRate = m_ship->GetHullType()->GetRechargeRate();

			float   energyDeficit = (m_nextFire - now) *            //this is how much we are in the hole because we
				rechargeRate;                   //are shooting sooner than "now" (must be < 0)

			short     ammo = m_ship->GetAmmo();

			if ((ammo > 0) || (m_typeData->cAmmoPerShot == 0))
			{
				// we are firing at least once this frame
				fFiredShot = true;
				m_pMission->GetIgcSite()->PlayFFEffect(effectFire, m_pshipGunner ? m_pshipGunner : m_ship);

				//Get the stuff that won't change between shots
				IclusterIGC*    cluster = m_ship->GetCluster();
				assert(cluster);

				const Orientation&  shipOrientation = m_ship->GetOrientation();

				//Orientation         orientationBfr;
				const Orientation*  pMyOrientation;
				if (m_pshipGunner)
				{
					/*
					orientationBfr = m_pshipGunner->GetOrientation() * (*m_porientation * shipOrientation);
					pMyOrientation = &orientationBfr;
					*/
					pMyOrientation = &(m_pshipGunner->GetOrientation());
				}
				else
				{
					pMyOrientation = &shipOrientation;
				}

				//This is how much energy deficit recovers between shots
				float   dtimeBurst = GetDtBurst();

				float   recharge = rechargeRate * dtimeBurst;

				const Vector&       myVelocity = m_ship->GetVelocity();
				Vector              myPosition = m_ship->GetPosition() + *m_pposition * shipOrientation; //*pMyOrientation;


				/*
				m_ship->GetThingSite()->AddMuzzleFlare(
					m_emissionPt,
					min(dtimeBurst * 0.5f, 0.05f)
				);
				*/

				DataProjectileIGC   dataProjectile;
				dataProjectile.projectileTypeID = m_projectileType->GetObjectID();

				float   lifespan = GetLifespan();

				float   speed = m_projectileType->GetSpeed();
				if (m_typeData->cAmmoPerShot)
					speed *= m_ship->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaSpeedAmmo);
				bool    absoluteF = m_projectileType->GetAbsoluteF();

				const Vector*   ppositionTarget;
				const Vector*   pvelocityTarget;
				ImodelIGC*  ptarget = NULL;
				if (m_projectileType->GetBlastPower() != 0.0f)
				{
					if (m_pshipGunner)
						ptarget = m_pshipGunner->GetCommandTarget(c_cmdCurrent);
					else
						ptarget = m_ship->GetCommandTarget(c_cmdCurrent);

					if (ptarget)
					{
						if ((ptarget->GetCluster() == cluster) && m_ship->CanSee(ptarget))
						{
							ppositionTarget = &(ptarget->GetPosition());
							pvelocityTarget = &(ptarget->GetVelocity());
						}
						else
							ptarget = NULL;
					}
				}

				int nShots = fSelected ? 10 : 0;    //Only allow a single shot if the weapon is no longer selected

				do
				{
					if (energy + energyDeficit < m_typeData->energyPerShot)
					{
						//We don't have enough energy to fire at our prefered time ... so wait until we do.
						m_nextFire += (m_typeData->energyPerShot - (energy + energyDeficit)) / rechargeRate;
					}

					//Permute the "forward" direction slightly by a random amount
					dataProjectile.forward = pMyOrientation->GetForward();
					if (m_typeData->dispersion != 0.0f)
					{
						float   r = random(0.0f, m_typeData->dispersion);
						float   a = random(0.0f, 2.0f * pi);
						dataProjectile.forward += (r * cos(a)) * pMyOrientation->GetRight();
						dataProjectile.forward += (r * sin(a)) * pMyOrientation->GetUp();

						dataProjectile.forward.SetNormalize();
					}

					dataProjectile.velocity = speed * dataProjectile.forward;
					if (!absoluteF)
						dataProjectile.velocity += myVelocity;

					Vector  position = myPosition + myVelocity * (m_nextFire - lastUpdate);
					dataProjectile.lifespan = lifespan;
					if (ptarget)
					{
						Vector      dV = *pvelocityTarget - dataProjectile.velocity;

						float       dV2 = dV.LengthSquared();
						if (dV2 != 0.0f)
						{
							Vector      dP = position - *ppositionTarget;  //reverse so time has right sense

							dataProjectile.lifespan = (dV * dP) / dV2;
							if (dataProjectile.lifespan > lifespan)
								dataProjectile.lifespan = lifespan;
							else if (dataProjectile.lifespan < 0.1f)
								dataProjectile.lifespan = 0.1f;     //Don't let it explode in our face
						}
					}

					IprojectileIGC*  p = (IprojectileIGC*)(m_pMission->CreateObject(m_nextFire, OT_projectile,
						&dataProjectile, sizeof(dataProjectile)));
					if (p)
					{
						if (m_pshipGunner)
							p->SetGunner(m_pshipGunner);
						else
							p->SetLauncher(m_ship);

						p->SetPosition(position);

						p->SetCluster(cluster);

						p->Release();
					}

					energyDeficit += rechargeRate * dtimeBurst;
					energy -= m_typeData->energyPerShot;
					ammo -= m_typeData->cAmmoPerShot;

					m_nextFire += dtimeBurst;
				} while ((nShots-- > 0) &&
					(m_nextFire < now) &&
					(energy + energyDeficit >= m_typeData->energyPerShot) &&
					(ammo > 0));

				m_ship->SetAmmo(ammo > 0 ? ammo : 0);

				if ((ammo == 0) && (m_typeData->cAmmoPerShot != 0))
					fSelected = false;

				m_ship->SetEnergy(energy);
			}
		}

		if (!fSelected)
			Deactivate();
	}

	// if we fired a shot, keep track of it (note - stored localy because the 
	// call to deactivate (above) clears the member variable).
	m_fFiringShot = fFiredShot;

	// if we are still firing and have the energy and ammo for the next shot,
	// assume we are firing a burst.
	if ((m_ship->GetEnergy() >= m_typeData->energyPerShot)
		&& (m_ship->GetAmmo() >= m_typeData->cAmmoPerShot)
		&& (m_fFiringBurst || (m_fActive && m_fFiringShot)) // a burst starts with a shot
		)
	{
		m_fFiringBurst = true;
	}
	else
	{
		m_fFiringBurst = false;
	}

}
예제 #2
0
	void PartSysParser::ParseEmitter(const TabFileRecord& record) {
		auto systemName = record[COL_PARTSYS_NAME].AsString();

		auto& system = mSpecs[tolower(systemName)];
		// Create it on demand
		if (!system) {
			system = std::make_shared<PartSysSpec>(systemName);
		}

		// Add the emitter
		auto emitter = system->CreateEmitter(record[COL_EMITTER_NAME].AsString());

		ParseOptionalFloat(record, COL_DELAY, "Delay", [&] (float value) {
			                   emitter->SetDelay(value / 30.0f);
		                   });

		ParseLifespan(record, emitter);

		ParseParticleLifespan(record, emitter);

		ParseParticleRate(record, emitter);

		ParseOptionalEnum<PartSysEmitterSpace>(record, COL_EMITTER_SPACE, "emitter space", EmitterSpaceMapping, [&](auto space) {
			                                       emitter->SetSpace(space);
		                                       });

		ParseEmitterNodeName(record, emitter);

		ParseOptionalEnum<PartSysCoordSys>(record, COL_EMITTER_COORD_SYS, "emitter coord sys", CoordSysMapping, [&](auto coordSys) {
			                                   emitter->SetCoordSys(coordSys);
		                                   });

		ParseOptionalEnum<PartSysCoordSys>(record, COL_EMITTER_OFFSET_COORD_SYS, "emitter offset coord sys", CoordSysMapping, [&](auto coordSys) {
			                                   emitter->SetOffsetCoordSys(coordSys);
		                                   });

		ParseOptionalEnum<PartSysParticleType>(record, COL_PARTICLE_TYPE, "particle type", ParticleTypeMapping, [&](PartSysParticleType type) {
			                                       emitter->SetParticleType(type);
		                                       });

		ParseOptionalEnum<PartSysBlendMode>(record, COL_BLEND_MODE, "blend mode", BlendModeMapping, [&](auto mode) {
			                                    emitter->SetBlendMode(mode);
		                                    });

		ParseMaterial(record, emitter);

		ParseOptionalEnum<PartSysCoordSys>(record, COL_PARTICLE_POS_COORD_SYS, "particle pos coord sys", CoordSysMapping, [&](auto coordSys) {
			                                   emitter->SetParticlePosCoordSys(coordSys);
		                                   });
		ParseOptionalEnum<PartSysCoordSys>(record, COL_PARTICLE_VELOCITY_COORD_SYS, "particle velocity coord sys", CoordSysMapping, [&](auto coordSys) {
			                                   emitter->SetParticleVelocityCoordSys(coordSys);
		                                   });
		ParseOptionalEnum<PartSysParticleSpace>(record, COL_PARTICLE_SPACE, "particle space", ParticleSpaceMapping, [&](auto space) {
			                                        emitter->SetParticleSpace(space);
		                                        });

		ParseMesh(record, emitter);

		// Parse the bounding box
		ParseOptionalFloat(record, COL_BB_LEFT, "bb left", [&](float val) {
			                   emitter->SetBoxLeft(val);
		                   });
		ParseOptionalFloat(record, COL_BB_TOP, "bb top", [&](float val) {
			                   emitter->SetBoxTop(val);
		                   });
		ParseOptionalFloat(record, COL_BB_RIGHT, "bb right", [&](float val) {
			                   emitter->SetBoxRight(val);
		                   });
		ParseOptionalFloat(record, COL_BB_BOTTOM, "bb bottom", [&](float val) {
			                   emitter->SetBoxBottom(val);
		                   });

		for (int paramId = 0; paramId <= part_attractorBlend; paramId++) {
			int colIdx = 22 + paramId;
			auto col = record[colIdx];
			if (col) {
				bool success;
				std::unique_ptr<PartSysParam> param(ParserParams::Parse((PartSysParamId) paramId,
				                                                        col,
				                                                        emitter->GetLifespan(),
				                                                        emitter->GetParticleLifespan(),
				                                                        success));
				if (success) {
					emitter->SetParam((PartSysParamId)paramId, param);
				} else {
					logger->warn("Unable to parse particle system param {} for particle system {} and emitter {} with value {}",
					             paramId, systemName, emitter->GetName(), col.AsString());
				}
			}
		}

	}