void CCompositeImageDesc::InitDamagePainters (void) // InitDamagePainters // // Initializes station damage bitmaps { if (g_pMediumDamage == NULL) { CEffectCreator *pEffect = g_pUniverse->FindEffectType(MEDIUM_STATION_DAMAGE_UNID); if (pEffect) g_pMediumDamage = pEffect->CreatePainter(); } if (g_pLargeDamage == NULL) { CEffectCreator *pEffect = g_pUniverse->FindEffectType(LARGE_STATION_DAMAGE_UNID); if (pEffect) g_pLargeDamage = pEffect->CreatePainter(); } }
ALERROR IEffectPainter::ValidateClass (SLoadCtx &Ctx, const CString &sOriginalClass) // ValidateClass // // Reads the class string. If the class does not match the current painter, // we read the old data and return ERR_FAIL. { if (Ctx.dwVersion >= 40) { CString sClass; sClass.ReadFromStream(Ctx.pStream); // If the original class doesn't match the current one, then it means // that the design changed. In that case, we load the painter using the // old class. if (!strEquals(sClass, sOriginalClass)) { // If sClass is blank, then it means that the original did not have // an effect painter (but the current design does) if (!sClass.IsBlank()) { // Get the original creator CEffectCreator *pOriginalCreator; if (CEffectCreator::CreateFromTag(sClass, &pOriginalCreator) != NOERROR) { kernelDebugLogMessage("Unable to find original effect creator: %s", sClass.GetASCIIZPointer()); return ERR_FAIL; } // Load the original painter IEffectPainter *pOriginalPainter = pOriginalCreator->CreatePainter(); pOriginalPainter->ReadFromStream(Ctx); // Discard pOriginalPainter->Delete(); delete pOriginalCreator; } // Done return ERR_FAIL; } } return NOERROR; }
void CEffectVariantPainter::Paint (CG16bitImage &Dest, int x, int y, SViewportPaintCtx &Ctx) // Paint // // Paint the effect { // Find the appropriate effect int iIndex = m_pCreator->GetVariantCreatorIndex(Ctx.iVariant); if (m_Cache[iIndex] == NULL) { CEffectCreator *pCreator = m_pCreator->GetVariantCreator(iIndex); m_Cache[iIndex] = pCreator->CreatePainter(CCreatePainterCtx()); } // Paint m_Cache[iIndex]->Paint(Dest, x, y, Ctx); }
CSmokeTrailPainter::CSmokeTrailPainter (CSmokeTrailEffectCreator *pCreator) : m_pCreator(pCreator), m_iLastDirection(-1), m_iTick(0) // CSmokeTrailPainter constructor { int iMaxParticleCount = m_pCreator->GetParticleLifetimeMax() * m_pCreator->GetNewParticleMax(); m_Particles.Init(iMaxParticleCount); int iTotalLifetime = m_pCreator->GetLifetime(); m_iEmitLifetime = (iTotalLifetime == -1 ? -1 : m_pCreator->GetEmitLifetime() * iTotalLifetime / 100); CEffectCreator *pEffect = pCreator->GetParticleEffect(); if (pEffect) m_pParticlePainter = pEffect->CreatePainter(); else m_pParticlePainter = NULL; }
CParticleJetEffectPainter::CParticleJetEffectPainter (CCreatePainterCtx &Ctx, CParticleJetEffectCreator *pCreator) : m_pCreator(pCreator), m_iXformRotation(0), m_rXformTime(1.0), m_iLifetime(0), m_iCurDirection(-1), m_iLastDirection(-1), m_bUseObjectCenter(Ctx.UseObjectCenter()), m_bUseObjectMotion(false), m_bTrackingObject(Ctx.IsTracking()) // CParticleJetEffectPainter constructor { // Initialize the single particle painter CEffectCreator *pEffect = m_pCreator->GetParticleEffect(); if (pEffect) m_pParticlePainter = pEffect->CreatePainter(Ctx); else m_pParticlePainter = NULL; }
IEffectPainter *CEffectCreator::CreatePainterFromStream (SLoadCtx &Ctx, bool bNullCreator) // CreatePainterFromStream // // Load a painter from a stream { CEffectCreator *pCreator; // For previous versions, we only stored UNID if we had a creator if (Ctx.dwVersion < 43 && bNullCreator) return NULL; // At version 15 we started saving versions as string UNIDs. We need to do this // because sometimes the effect creator is inside a weapon fire desc // structure (also identified by string UNIDs). if (Ctx.dwVersion >= 15) { CString sUNID; sUNID.ReadFromStream(Ctx.pStream); pCreator = (sUNID.IsBlank() ? NULL : CEffectCreator::FindEffectCreator(sUNID)); // Load the creator class that saved the painter if (IEffectPainter::ValidateClass(Ctx, (pCreator ? pCreator->GetTag() : NULL_STR)) != NOERROR) return NULL; // Error if (pCreator == NULL) { if (!sUNID.IsBlank()) kernelDebugLogMessage("Invalid painter creator: %s", sUNID.GetASCIIZPointer()); return NULL; } } // Old style uses DWORD UNIDs else { // The first DWORD is the UNID of the creator DWORD dwUNID; Ctx.pStream->Read((char *)&dwUNID, sizeof(DWORD)); if (dwUNID == 0) return NULL; pCreator = g_pUniverse->FindEffectType(dwUNID); // Error if (pCreator == NULL) { kernelDebugLogMessage("Invalid painter creator: %x", dwUNID); return NULL; } } // Let the creator create the object IEffectPainter *pPainter = pCreator->CreatePainter(); // Load it pPainter->ReadFromStream(Ctx); // Done return pPainter; }
ALERROR CMissile::Create (CSystem *pSystem, CWeaponFireDesc *pDesc, int iBonus, DestructionTypes iCause, const CDamageSource &Source, const CVector &vPos, const CVector &vVel, int iRotation, CSpaceObject *pTarget, CMissile **retpMissile) // Create // // Creates a missile { ALERROR error; CMissile *pMissile; pMissile = new CMissile; if (pMissile == NULL) return ERR_MEMORY; pMissile->Place(vPos, vVel); // We can't save missiles without an UNID ASSERT(!pDesc->m_sUNID.IsBlank()); // Don't bother telling others when we are destroyed (Note that // if we do this then we also need to set the CannotBeHit flag; // otherwise we will crash when a beam hits us. This is because // m_pHit is setup in Move and the object can go away between then // and our Update event.) if (pDesc->GetInteraction() == 0) { pMissile->DisableObjectDestructionNotify(); pMissile->SetCannotBeHit(); } // Get notifications when other objects are destroyed pMissile->SetObjectDestructionHook(); pMissile->m_pDesc = pDesc; pMissile->m_iBonus = iBonus; pMissile->m_iCause = iCause; pMissile->m_iHitPoints = pDesc->GetHitPoints(); pMissile->m_iLifeLeft = pDesc->GetLifetime(); pMissile->m_iTick = 0; pMissile->m_Source = Source; pMissile->m_pHit = NULL; pMissile->m_iRotation = iRotation; pMissile->m_pTarget = pTarget; pMissile->m_fDestroyed = false; pMissile->m_fReflection = false; pMissile->m_fDetonate = false; pMissile->m_fPassthrough = false; pMissile->m_dwSpareFlags = 0; // Friendly fire if (!pDesc->CanHitFriends()) pMissile->SetNoFriendlyFire(); // Remember the sovereign of the source (in case the source is destroyed) pMissile->m_pSovereign = pMissile->m_Source.GetSovereign(); // Create a painter instance CEffectCreator *pEffect; if (pEffect = pDesc->GetEffect()) { pMissile->m_pPainter = pEffect->CreatePainter(); pMissile->SetBounds(pMissile->m_pPainter); } // Create exhaust trail, if necessary if (pDesc->m_iExhaustRate > 0) { int iCount = (pDesc->m_iExhaustLifetime / pDesc->m_iExhaustRate) + 1; pMissile->m_pExhaust = new TQueue<SExhaustParticle>(iCount); } else pMissile->m_pExhaust = NULL; // Create vapor trail, if necessary if (pDesc->GetVaporTrailWidth()) pMissile->SetBounds(2048.0 * g_KlicksPerPixel); // Add to system if (error = pMissile->AddToSystem(pSystem)) { delete pMissile; return error; } // Done if (retpMissile) *retpMissile = pMissile; return NOERROR; }
ALERROR CParticleDamage::Create (CSystem *pSystem, CWeaponFireDesc *pDesc, CItemEnhancementStack *pEnhancements, DestructionTypes iCause, const CDamageSource &Source, const CVector &vPos, const CVector &vVel, int iDirection, CSpaceObject *pTarget, CParticleDamage **retpObj) // Create // // Create the object { ALERROR error; // Make sure we have a valid CWeaponFireDesc (otherwise we won't be // able to save the object). ASSERT(!pDesc->m_sUNID.IsBlank()); // Create the area CParticleDamage *pParticles = new CParticleDamage; if (pParticles == NULL) return ERR_MEMORY; pParticles->Place(vPos, vVel); // Get notifications when other objects are destroyed pParticles->SetObjectDestructionHook(); // Set non-linear move, meaning that we are responsible for // setting the position and velocity in OnMove pParticles->SetNonLinearMove(); pParticles->m_pDesc = pDesc; pParticles->m_pTarget = pTarget; pParticles->m_pEnhancements = (pEnhancements ? pEnhancements->AddRef() : NULL); pParticles->m_iCause = iCause; pParticles->m_iEmitDirection = iDirection; pParticles->m_vEmitSourcePos = vPos; pParticles->m_vEmitSourceVel = (Source.GetObj() ? Source.GetObj()->GetVel() : CVector()); pParticles->m_iEmitTime = Max(1, pDesc->GetParticleEmitTime()); pParticles->m_iLifeLeft = pDesc->GetMaxLifetime() + pParticles->m_iEmitTime; pParticles->m_Source = Source; pParticles->m_iTick = 0; pParticles->m_iDamage = pDesc->m_Damage.RollDamage(); // Friendly fire if (!pDesc->CanHitFriends()) pParticles->SetNoFriendlyFire(); // Painter CEffectCreator *pEffect; if (pEffect = pDesc->GetEffect()) { CCreatePainterCtx Ctx; Ctx.SetWeaponFireDesc(pDesc); pParticles->m_pPainter = pEffect->CreatePainter(Ctx); } // Remember the sovereign of the source (in case the source is destroyed) if (Source.GetObj()) pParticles->m_pSovereign = Source.GetObj()->GetSovereign(); else pParticles->m_pSovereign = NULL; // Compute the maximum number of particles that we might have int iMaxCount = pParticles->m_iEmitTime * pDesc->GetMaxParticleCount(); pParticles->m_Particles.Init(iMaxCount, vPos); // Create the initial particles int iInitCount = pDesc->GetParticleCount(); pParticles->InitParticles(iInitCount, CVector(), vVel, iDirection); // Figure out the number of particles that will cause full damage if (pParticles->m_iEmitTime > 1) pParticles->m_iParticleCount = pParticles->m_iEmitTime * pDesc->GetAveParticleCount(); else pParticles->m_iParticleCount = iInitCount; pParticles->m_iParticleCount = Max(1, pParticles->m_iParticleCount); // Add to system if (error = pParticles->AddToSystem(pSystem)) { delete pParticles; return error; } // Done if (retpObj) *retpObj = pParticles; return NOERROR; }