Example #1
0
void CSpaceObjectList::NotifyOnObjDocked (CSpaceObject *pDockingObj, CSpaceObject *pDockTarget)

//	NotifyOnObjDocked
//
//	Notify that an object docked.

	{
	int i;

	if (GetCount() > 0)
		{
		TArray<CSpaceObject *> List(m_List);

		for (i = 0; i < List.GetCount(); i++)
			{
			CSpaceObject *pObj = List[i];

			//	NOTE: We do not notify the dock target because it got notified
			//	separately.

			if (!pObj->IsDestroyed() 
					&& pObj != pDockTarget 
					&& pObj->HasOnObjDockedEvent())
				pObj->FireOnObjDocked(pDockingObj, pDockTarget);
			}
		}
	}
void AddSystemData (CSystem *pSystem, bool bAll, SNodeDesc *retResult)
	{
	int i;

	//	Loop over all objects

	for (i = 0; i < pSystem->GetObjectCount(); i++)
		{
		CStationType *pType;
		CSpaceObject *pObj = pSystem->GetObject(i);
		if (pObj == NULL 
				|| pObj->IsDestroyed()
				|| (pType = pObj->GetEncounterInfo()) == NULL)
			continue;

		//	Skip if we're not interested in this encounter

		if (!bAll && !pType->CanBeEncounteredRandomly())
			continue;

		//	Get table

		CCountTable *pTable = retResult->Table.SetAt(pSystem->GetType()->GetUNID());

		//	Add to count

		bool bNew;
		int *pCount = pTable->SetAt(pType->GetUNID(), &bNew);
		if (bNew)
			*pCount = 1;
		else
			*pCount += 1;
		}
	}
int GetValidObjCount (CSystem *pSystem)
{
    int i;
    int iCount = 0;

    for (i = 0; i < pSystem->GetObjectCount(); i++)
    {
        CSpaceObject *pObj = pSystem->GetObject(i);
        if (pObj && !pObj->IsDestroyed())
            iCount++;
    }

    return iCount;
}
Example #4
0
void CSpaceObjectList::NotifyOnObjEnteredGate (CSpaceObject *pGatingObj, CTopologyNode *pDestNode, const CString &sDestEntryPoint, CSpaceObject *pStargate)

//	NotifyOnObjEnteredGate
//
//	Notify all objects in the list that the given object has entered a stargate.

	{
	int i;

	if (GetCount() > 0)
		{
		TArray<CSpaceObject *> List(m_List);

		for (i = 0; i < List.GetCount(); i++)
			{
			CSpaceObject *pObj = List[i];
			if (!pObj->IsDestroyed())
				pObj->FireOnObjEnteredGate(pGatingObj, pDestNode, sDestEntryPoint, pStargate);
			}
		}
	}
Example #5
0
void CSpaceObjectList::NotifyOnPlayerBlacklisted (CSpaceObject *pBlacklistingObj)

//	NotifyOnPlayerBlacklisted
//
//	Notify all objects that the player was blacklisted

	{
	int i;

	if (GetCount() > 0)
		{
		TArray<CSpaceObject *> List(m_List);

		for (i = 0; i < List.GetCount(); i++)
			{
			CSpaceObject *pObj = List[i];
			if (!pObj->IsDestroyed())
				pObj->FireOnObjBlacklistedPlayer(pBlacklistingObj);
			}
		}
	}
Example #6
0
void CSpaceObjectList::NotifyOnObjReconned (CSpaceObject *pReconnedObj)

//	NotifyOnObjReconned
//
//	Notify that an object was reconned

	{
	int i;

	if (GetCount() > 0)
		{
		TArray<CSpaceObject *> List(m_List);

		for (i = 0; i < List.GetCount(); i++)
			{
			CSpaceObject *pObj = List[i];
			if (!pObj->IsDestroyed())
				pObj->FireOnObjReconned(pReconnedObj);
			}
		}
	}
Example #7
0
void CSpaceObjectList::NotifyOnObjDestroyed (SDestroyCtx &Ctx)

//	NotifyOnObjDestroyed
//
//	Notify all objects in the list that another object was destroyed.

	{
	int i;

	if (GetCount() > 0)
		{
		//	We make a copy of our list because an event might remove an object
		//	from our list.

 		TArray<CSpaceObject *> List(m_List);

		for (i = 0; i < List.GetCount(); i++)
			{
			CSpaceObject *pObj = List[i];
			if (!pObj->IsDestroyed())
				pObj->OnObjDestroyedNotify(Ctx);
			}
		}
	}
Example #8
0
EResults RunEncounter (CUniverse &Universe, CSimViewer &Viewer, CStationType *pDefenderType, CShipClass *pAttackerClass, CSovereign *pAttackerSovereign)
	{
	int iTimeOut = DEFAULT_TIME_OUT;

	//	Make sure the universe is clean

	CString sError;
	if (Universe.InitGame(0, &sError) != NOERROR)
		{
		printf("ERROR: %s", sError.GetASCIIZPointer());
		return resultError;
		}

	//	Create an empty system

	CSystem *pSystem;
	if (Universe.CreateEmptyStarSystem(&pSystem) != NOERROR)
		{
		printf("ERROR: Unable to create empty star system.\n");
		return resultError;
		}

	//	Create a station in the center of the system

	CSpaceObject *pStation;
	if (pSystem->CreateStation(pDefenderType, NULL, CVector(), &pStation) != NOERROR)
		{
		printf("ERROR: Unable to create station.\n");
		return resultError;
		}

	//	Set the POV

	Universe.SetPOV(pStation);
	pSystem->SetPOVLRS(pStation);

	//	Prepare system

	Universe.UpdateExtended();
	Universe.GarbageCollectLibraryBitmaps();
	Universe.StartGame(true);

	//	Now create an attacker some distance away

	CVector vPos = PolarToVector(mathRandom(0, 359), INITIAL_DISTANCE);

	CShip *pAttacker;
	if (pSystem->CreateShip(pAttackerClass->GetUNID(), NULL, NULL, pAttackerSovereign, vPos, CVector(), 0, NULL, NULL, &pAttacker) != NOERROR)
		{
		printf("ERROR: Unable to create attacking ship.\n");
		return resultError;
		}

	//	Set the attacker to attack the station

	IShipController *pController = pAttacker->GetController();
	if (pController == NULL)
		{
		printf("ERROR: No controller for ship.\n");
		return resultError;
		}

	pController->AddOrder(IShipController::orderAttackStation, pStation, IShipController::SData());

	//	Watch the attacker

	Universe.SetPOV(pAttacker);
	pSystem->SetPOVLRS(pAttacker);

	//	Update context

	SSystemUpdateCtx Ctx;
	Ctx.bForceEventFiring = true;
	Ctx.bForcePainted = true;

	//	Now keep updating until either the station is destroyed, the ship is destroyed, or we time-out

	int iTime = 0;
	int iDestroyedTime = (Viewer.IsEmpty() ? 0 : DESTROY_TIME);
	bool bDestroyed = false;
	EResults iResult = resultTimeout;
	while (iTime < iTimeOut && (!bDestroyed || iDestroyedTime > 0))
		{
		iTime++;
		Universe.Update(Ctx);

		if (!Viewer.IsEmpty())
			Viewer.PaintViewport(Universe);

		if (bDestroyed)
			iDestroyedTime--;
		else if (pStation->IsDestroyed() || pStation->IsAbandoned())
			{
			bDestroyed = true;
			iResult = resultDefenderDestroyed;
			}
		else if (pAttacker->IsDestroyed())
			{
			bDestroyed = true;
			iResult = resultAttackerDestroyed;
			}
		}

	//	Done

	return iResult;
	}
Example #9
0
EDamageResults CArmorClass::AbsorbDamage (CItemCtx &ItemCtx, SDamageCtx &Ctx)

//	AbsorbDamage
//
//	Handles getting hit by damage.
//
//	Returns damageNoDamage if all the damage was absorbed and no further processing is necessary
//	Returns damageDestroyed if the source was destroyed
//	Returns damageArmorHit if source was damage and further processing (destroy check) is needed
//
//	Sets Ctx.iDamage to the amount of hit points left after damage absorption.

	{
	CSpaceObject *pSource = ItemCtx.GetSource();
	CInstalledArmor *pArmor = ItemCtx.GetArmor();
	if (pSource == NULL || pArmor == NULL)
		return damageNoDamage;

	//	Compute all the effects (this initializes elements in Ctx).

	CalcDamageEffects(ItemCtx, Ctx);

	//	First give custom weapons a chance

	bool bCustomDamage = Ctx.pDesc->FireOnDamageArmor(Ctx);
	if (pSource->IsDestroyed())
		return damageDestroyed;

	//	Damage adjustment

	CalcAdjustedDamage(ItemCtx, Ctx);

	//	If the armor has custom code to deal with damage, handle it here.

	FireOnArmorDamage(ItemCtx, Ctx);
	if (pSource->IsDestroyed())
		return damageDestroyed;

	//	If this armor section reflects this kind of damage then
	//	send the damage on

	if (Ctx.bReflect)
		{
		if (Ctx.pCause)
			Ctx.pCause->CreateReflection(Ctx.vHitPos, (Ctx.iDirection + 120 + mathRandom(0, 120)) % 360);
		return damageNoDamage;
		}

	//	If this is a disintegration attack, then disintegrate the ship

	if (Ctx.bDisintegrate)
		{
		if (!pSource->OnDestroyCheck(killedByDisintegration, Ctx.Attacker))
			return damageNoDamage;

		pSource->Destroy(killedByDisintegration, Ctx.Attacker);
		return damageDestroyed;
		}

	//	If this is a shatter attack, see if the ship is destroyed

	if (Ctx.bShatter)
		{
		if (!pSource->OnDestroyCheck(killedByShatter, Ctx.Attacker))
			return damageNoDamage;

		pSource->Destroy(killedByShatter, Ctx.Attacker);
		return damageDestroyed;
		}

	//	If this is a paralysis attack and we've gotten past the shields
	//	then freeze the ship.

	if (Ctx.bParalyze)
		pSource->MakeParalyzed(Ctx.iParalyzeTime);

	//	If this is blinding damage then our sensors are disabled

	if (Ctx.bBlind)
		pSource->MakeBlind(Ctx.iBlindTime);

	//	If this attack is radioactive, then contaminate the ship

	if (Ctx.bRadioactive)
		pSource->OnHitByRadioactiveDamage(Ctx);

	//	If this is device damage, then see if any device is damaged

	if (Ctx.bDeviceDamage)
		pSource->OnHitByDeviceDamage();

	if (Ctx.bDeviceDisrupt)
		pSource->OnHitByDeviceDisruptDamage(Ctx.iDisruptTime);

	//	Create a hit effect. (Many weapons show an effect even if no damage was
	//	done.)

	Ctx.pDesc->CreateHitEffect(pSource->GetSystem(), Ctx);

	//	If no damage has reached us, then we're done

	if (Ctx.iDamage == 0 && !bCustomDamage)
		return damageNoDamage;

	//	Give source events a chance to change the damage before we
	//	subtract from armor.

	if (pSource->HasOnDamageEvent())
		{
		pSource->FireOnDamage(Ctx);
		if (pSource->IsDestroyed())
			return damageDestroyed;
		}

	//	Take damage

	if (Ctx.iDamage <= pArmor->GetHitPoints())
		{
		pArmor->IncHitPoints(-Ctx.iDamage);
		Ctx.iDamage = 0;
		}
	else
		{
		Ctx.iDamage -= pArmor->GetHitPoints();
		pArmor->SetHitPoints(0);
		}

	return damageArmorHit;
	}
void CDockingPorts::UpdateAll (SUpdateCtx &Ctx, CSpaceObject *pOwner)

//	UpdateAll
//
//	UpdateAll 

	{
	DEBUG_TRY

	int i;

	CSpaceObject *pPlayer = Ctx.pSystem->GetPlayer();
	Metric rDist2 = (pPlayer ? pPlayer->GetDistance2(pOwner) : 0.0);
	Metric rMaxDist = m_iMaxDist * LIGHT_SECOND;
	Metric rMaxDist2 = rMaxDist * rMaxDist;

	//	If owner is destroyed then don't bother checking for nearest player
	//	port.

	if (pPlayer 
			&& (pOwner->IsDestroyed() 
				|| pOwner->IsInactive() 
				|| pOwner == pPlayer
				|| pPlayer->IsDestroyed()))
		pPlayer = NULL;

	//	Also, don't bother checking if the owner is an enemy of the player.

	if (pPlayer && pPlayer->IsEnemy(pOwner) && !pOwner->IsAbandoned())
		pPlayer = NULL;

	//	Don't bother checking if the station is too far

	if (pPlayer && rDist2 > rMaxDist2)
		pPlayer = NULL;

	//	If this is a stargate and we are at the center (just came through) 
	//	then don't bother showing docking ports.

	if (pPlayer && pOwner->IsStargate() && rDist2 < GATE_DIST2)
		pPlayer = NULL;

	//	Loop over all ports

	for (i = 0; i < m_iPortCount; i++)
		{
		//	If a ship is docking with this port, then maneuver the ship towards
		//	the docking port.

		if (m_pPort[i].iStatus == psDocking)
			UpdateDockingManeuvers(pOwner, m_pPort[i]);

		//	Otherwise, if the port is open, see if this is the nearest port to
		//	the current player position.

		else if (m_pPort[i].iStatus == psEmpty)
			{
			if (pPlayer)
				{
				//	Compute the distance from the player to the port

				CVector vPortPos = pOwner->GetPos() + m_pPort[i].vPos;
				Metric rDist2 = (vPortPos - pPlayer->GetPos()).Length2();

				//	If this is a better port, then replace the existing 
				//	solution.

				if (Ctx.pDockingObj == NULL
							|| rDist2 < Ctx.rDockingPortDist2)
					{
					Ctx.pDockingObj = pOwner;
					Ctx.iDockingPort = i;
					Ctx.rDockingPortDist2 = rDist2;
					Ctx.vDockingPort = vPortPos;
					}
				}
			}
		}

	DEBUG_CATCH
	}
void CParticleEffect::OnUpdate (SUpdateCtx &Ctx, Metric rSecondsPerTick)

//	OnUpdate
//
//	Update the effect

	{
	int iTick = GetSystem()->GetTick() + GetDestiny();

	//	Do not bother updating everything if we are far from the POV

	bool bFarAway = false;
	if (g_pUniverse->GetPOV() 
			&& g_pUniverse->GetCurrentSystem() == GetSystem())
		{
		Metric rPOVDist2 = (GetPos() - g_pUniverse->GetPOV()->GetPos()).Length2();
		Metric rMaxUpdateDist2 = LIGHT_SECOND * LIGHT_SECOND * 3600;
		bFarAway = (rPOVDist2 > rMaxUpdateDist2);
		}

	//	Update the particles

	SParticleArray *pGroup = m_pFirstGroup;
	while (pGroup)
		{
		SParticleType *pType = pGroup->pType;

		//	Max distance for a particle in this group

		Metric rMaxDist2 = pType->rRadius * pType->rRadius;
		Metric rMinDist2 = pType->rHoleRadius * pType->rHoleRadius;

		//	If the particle field causes damage then we need to
		//	compute its average density

		int iDensity = 0;
		if (pType->pDamageDesc)
			{
			Metric rRadius2 = pType->rRadius * pType->rRadius;
			Metric rArea = rRadius2 / (LIGHT_SECOND * LIGHT_SECOND);
			iDensity = (int)(4 * pGroup->iCount / rArea);
			}

		//	Get an array of objects in the particle field that
		//	may influence the particles

		CSpaceObject *Objects[ctMaxObjsInField];
		int iObjCount = 0;
		if (!bFarAway && (pType->m_fWake || pType->pDamageDesc))
			{
			Metric rMaxInfluenceDist2 = rMaxDist2;
			for (int i = 0; i < GetSystem()->GetObjectCount(); i++)
				{
				CSpaceObject *pObj = GetSystem()->GetObject(i);

				if (pObj 
						&& pObj->GetCategory() == catShip
						&& !pObj->IsInactive()
						&& pObj->CanBeHit()
						&& !pObj->IsDestroyed()
						&& pObj != this)
					{
					CVector vDist = GetPos() - pObj->GetPos();
					Metric rDist2 = vDist.Length2();

					if (rDist2 < rMaxInfluenceDist2 
							&& (pObj->GetVel().Length2() > g_KlicksPerPixel)
							&& iObjCount < ctMaxObjsInField)
						{
						Objects[iObjCount++] = pObj;

						//	See if the object should take damage

						if (pType->pDamageDesc)
							{
							CVector vDeltaV = pObj->GetVel() - GetVel();
							int iSpeed = (int)(vDeltaV.Length() / g_KlicksPerPixel);
							if (iSpeed == 0)
								iSpeed = 1;

							if (mathRandom(1, 1000) < (iDensity * iSpeed))
								{
								SDamageCtx Ctx;
								Ctx.pObj = pObj;
								Ctx.pDesc = pType->pDamageDesc;
								Ctx.Damage = pType->pDamageDesc->m_Damage;
								if (IsAutomatedWeapon())
									Ctx.Damage.SetAutomatedWeapon();
								Ctx.iDirection = VectorToPolar(vDeltaV);
								Ctx.vHitPos = pObj->GetPos();
								Ctx.pCause = this;
								Ctx.Attacker = CDamageSource(this, killedByDamage);

								pObj->Damage(Ctx);
								}
							}
						}
					}
				}
			}

		//	If we're computing drag then we need to compute the new velocity
		//	of the whole particle system

		CVector vNewVel;
		if (pType->m_fDrag)
			vNewVel = GetVel() * g_SpaceDragFactor;

		//	Iterate over all particles

		SParticle *pParticle = pGroup->pParticles;
		SParticle *pEnd = pParticle + pGroup->iCount;
		while (pParticle < pEnd)
			{
			if (pParticle->IsValid())
				{
				//	Lifespan. If we're far away and we're regenerating,
				//	then don't bother to compute lifespan.

				if (pType->m_fLifespan 
						&& !(bFarAway && (pType->m_fRegenerate && pType->iRegenerationTimer)))
					{
					if (--pParticle->iLifeLeft == 0)
						{
						//	Do we regenerate?

						if (pType->m_fRegenerate && pType->iRegenerationTimer)
							{
							pParticle->iLifeLeft = pType->iLifespan;
							pParticle->vPos = NullVector;

							//	Speed

							Metric rSpeed = mathRandom(1, 100) * (pType->rAveSpeed / 100.0);
							if (pType->iDirection == -1)
								pParticle->vVel = PolarToVector(mathRandom(0, 359), rSpeed);
							else
								{
								int iAngle = (pType->iDirection + 360 + mathRandom(0, 2 * pType->iDirRange) - pType->iDirRange) % 360;
								pParticle->vVel = PolarToVector(iAngle, rSpeed);
								}
							}

						//	Otherwise we die

						else
							{
							pParticle->iLifeLeft = -1;
							pGroup->iAlive--;
							pParticle++;
							continue;
							}
						}
					}

				//	Update the position

				if (!bFarAway)
					{
					pParticle->vPos = pParticle->vPos + pParticle->vVel;

					//	Change the velocity to keep the particles within
					//	the radius

					if (pType->m_fMaxRadius)
						{
						Metric rDist2 = pParticle->vPos.Length2();
						if (pType->m_fMaxRadius && rDist2 > rMaxDist2)
							{
							CVector vChange = pParticle->vPos + g_KlicksPerPixel * pParticle->vPos.Perpendicular().Normal();
							pParticle->vVel = pParticle->vVel - (0.00005 * vChange);
							}
						else if (rDist2 < rMinDist2)
							{
							CVector vNormal = pParticle->vPos.Normal();
							CVector vChange = g_KlicksPerPixel * (400 * vNormal - 50 * vNormal.Perpendicular());
							pParticle->vVel = pParticle->vVel + (0.00005 * vChange);
							}
						else
							pParticle->vVel = pParticle->vVel * pType->rDampening;
						}

					if (pType->m_fDrag)
						{
						//	Compute the new absolute velocity (after drag)
						CVector vAbsolute = pType->rDampening * (pParticle->vVel + GetVel());

						//	The particle velocity is the absolute vel minus the
						//	system velocity.
						pParticle->vVel = vAbsolute - vNewVel;
						}

					//	Change the velocity based on influences from other objects

					if (pType->m_fWake && (iTick % 4) == 0)
						{
						for (int i = 0; i < iObjCount; i++)
							{
							Metric rDist2 = (Objects[i]->GetPos() - (pParticle->vPos + GetPos())).Length2();
							if (rDist2 < g_KlicksPerPixel * g_KlicksPerPixel * 1000)
								{
								if (Objects[i]->GetVel().Dot(pParticle->vVel) < Objects[i]->GetVel().Length2())
									pParticle->vVel = pParticle->vVel + 0.2 * Objects[i]->GetVel();
								}
							}
						}
					}
				}

			pParticle++;
			}

		//	Regeneration timer

		if (pType->m_fRegenerate && pType->iRegenerationTimer)
			pType->iRegenerationTimer--;

		//	If there are no more particles left alive in this group then kill
		//	the group

		if (pGroup->iAlive == 0)
			{
			SParticleArray *pNext = pGroup->pNext;
			SParticleArray *pPrev = NULL;

			//	Find the previous group

			SParticleArray *pFind = m_pFirstGroup;
			while (pFind != pGroup)
				{
				if (pPrev)
					pPrev = pPrev->pNext;
				else
					pPrev = m_pFirstGroup;

				pFind = pFind->pNext;
				}

			//	Fix up the linked list

			if (pPrev)
				pPrev->pNext = pNext;
			else
				m_pFirstGroup = pNext;

			//	Delete the group

			delete pGroup;
			pGroup = pNext;
			}

		//	Otherwise, next group

		else
			pGroup = pGroup->pNext;
		}

	//	If we have no more groups then we destroy ourselves

	if (m_pFirstGroup == NULL)
		{
		Destroy(removedFromSystem, CDamageSource());
		return;
		}

	//	If we're moving, slow down

	SetVel(CVector(GetVel().GetX() * g_SpaceDragFactor, GetVel().GetY() * g_SpaceDragFactor));
	}