/* ** Copyright (C) 1996, 1997 Microsoft Corporation. All Rights Reserved. ** ** File: projectileIGC.cpp ** ** Author: ** ** Description: ** Implementation of the CprojectileIGC class. This file was initially created by ** the ATL wizard for the core object. ** ** This particular implementation of projectiles supports non-tracking missiles with ** a fixed run (time at which they expire). ** ** History: */ // projectileIGC.cpp : Implementation of CprojectileIGC #include "pch.h" #include "projectileIGC.h" ///////////////////////////////////////////////////////////////////////////// // CprojectileIGC CprojectileIGC::CprojectileIGC(void) : m_launcher(NULL), m_projectileType(NULL), m_pExplosionData(NULL) { } CprojectileIGC::~CprojectileIGC(void) { } HRESULT CprojectileIGC::Initialize(ImissionIGC* pMission, Time now, const void* data, int dataSize) { TmodelIGC::Initialize(pMission, now, data, dataSize); ZRetailAssert (data && (dataSize == sizeof(DataProjectileIGC))); { DataProjectileIGC* dataProjectile = (DataProjectileIGC*)data; m_projectileType = pMission->GetProjectileType(dataProjectile->projectileTypeID); if (m_projectileType) { m_projectileType->AddRef(); DataProjectileTypeIGC* dataProjectileType = (DataProjectileTypeIGC*)m_projectileType->GetData(); assert (dataProjectileType); //Load the model for the projectile if (iswalpha(dataProjectileType->modelName[0])) { HRESULT hr = Load(0, dataProjectileType->modelName, dataProjectileType->textureName, NULL, c_mtCastRay | c_mtNotPickable); assert (SUCCEEDED(hr)); SetRadius(dataProjectileType->radius); } else { HRESULT hr = LoadDecal(dataProjectileType->textureName, NULL, Color((float)dataProjectileType->color.r, (float)dataProjectileType->color.g, (float)dataProjectileType->color.b, (float)dataProjectileType->color.a), dataProjectileType->bDirectional, dataProjectileType->width, c_mtCastRay | c_mtNotPickable); assert (SUCCEEDED(hr)); GetHitTest()->SetRadius(0.0f); GetThingSite()->SetRadius(dataProjectileType->radius); } //position set after being initialized SetVelocity(dataProjectile->velocity); { Orientation o(dataProjectile->forward); SetOrientation(o); } { Rotation r(dataProjectile->forward, dataProjectileType->rotation); SetRotation(r); } { HitTest* ht = GetHitTest(); //lifespan == 0 => immortal projectile that can hit until it gets terminated on the next update; this is bad assert (dataProjectile->lifespan > 0.0f); ht->SetTimeStart(now); ht->SetTimeStop(m_timeExpire = now + dataProjectile->lifespan); //intentional assignment assert (m_timeExpire != now); } SetMass(0.0f); } } return S_OK; } void CprojectileIGC::Terminate(void) { AddRef(); TmodelIGC::Terminate(); if (m_launcher) { m_launcher->Release(); m_launcher = NULL; } if (m_projectileType) { m_projectileType->Release(); m_projectileType = NULL; } Release(); } void CprojectileIGC::Update(Time now) { if (GetMyLastUpdate() >= m_timeExpire) Terminate(); else { if (now >= m_timeExpire) { float p = m_projectileType->GetBlastPower(); if (p != 0.0f) { m_pExplosionData = GetCluster()->CreateExplosion(m_projectileType->GetDamageType(), p * GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaDamageGuns), m_projectileType->GetBlastRadius(), c_etProjectile, m_timeExpire, GetPosition() + GetVelocity() * (m_timeExpire - GetMyLastUpdate()), m_launcher); } } TmodelIGC::Update(now); } } int CprojectileIGC::Export(void* data) { if (data) { DataProjectileIGC* dataProjectile = (DataProjectileIGC*)data; dataProjectile->projectileTypeID = m_projectileType->GetObjectID(); dataProjectile->velocity = GetVelocity(); dataProjectile->forward = GetOrientation().GetForward(); } return sizeof(DataProjectileIGC); } void CprojectileIGC::HandleCollision(Time timeCollision, float tCollision, const CollisionEntry& entry, ImodelIGC* pModel) { if (pModel->GetObjectType() == OT_mine) { //Ignore collisions with minefields return; } //A projectile hit something other than a minefield bool fExplosion; Vector position1 = GetPosition() + GetVelocity() * tCollision; Vector position2 = pModel->GetPosition() + pModel->GetVelocity() * tCollision; DamageTypeID type = m_projectileType->GetDamageType(); if (pModel->GetAttributes() & c_mtDamagable) { //The target can take damage IdamageIGC* pDamage = (IdamageIGC*)pModel; pModel->AddRef(); DamageResult dr = pDamage->ReceiveDamage(type, m_projectileType->GetPower() * GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaDamageGuns), timeCollision, position2, position1, m_launcher); //No explosion because no hull damage, not visible or we killed it. fExplosion = (dr <= c_drHullDamage) && pModel->GetVisibleF() && (pModel->GetCluster() != NULL); pModel->Release(); } else fExplosion = false; if (m_pExplosionData) { //This projectile would have exploded anyway -- change the explosion position & time. m_pExplosionData->time = timeCollision; m_pExplosionData->position = position1; } else { float p = m_projectileType->GetBlastPower(); if (p != 0.0f) { //Area effect weapon: create an explosion (no matter what) GetCluster()->CreateExplosion(type, p, m_projectileType->GetBlastRadius(), c_etProjectile, timeCollision, position1, m_launcher); } else if (fExplosion && ((type & c_dmgidNoDebris) == 0)) { Vector pos = position1 - position2; pModel->GetThingSite()->AddHullHit(pos, pos.Normalize()); } } //In any case, kill the projectile Terminate(); }