123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- /*
- ** 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<IprojectileIGC>::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<IprojectileIGC>::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<IprojectileIGC>::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();
- }
|