NS/main/source/mod/AvHParticleSystemEntity.cpp

519 lines
15 KiB
C++
Raw Normal View History

//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. =========
//
// The copyright to the contents herein is the property of Charles G. Cleveland.
// The contents may be used and/or copied only with the written permission of
// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose:
//
// $Workfile: AvHParticleSystemEntity.cpp $
// $Date: 2002/11/22 21:28:16 $
//
//-------------------------------------------------------------------------------
// $Log: AvHParticleSystemEntity.cpp,v $
// Revision 1.13 2002/11/22 21:28:16 Flayra
// - mp_consistency changes
//
// Revision 1.12 2002/05/23 02:33:20 Flayra
// - Post-crash checkin. Restored @Backup from around 4/16. Contains changes for last four weeks of development.
//
//===============================================================================
#include "../util/nowarnings.h"
#include "AvHParticleSystemEntity.h"
#include "AvHParticleTemplateServer.h"
#include "AvHParticleSystemManager.h"
#include "AvHConstants.h"
#include "AvHMarineEquipmentConstants.h"
#include "AvHSpecials.h"
#include "AvHParticleTemplate.h"
#include "AvHParticleConstants.h"
extern AvHParticleTemplateListServer gParticleTemplateList;
uint32 AvHParticleSystemEntity::sCurrentHandle = 1;
const float kDefaultParticleSystemThinkRate = 0.05f;
LINK_ENTITY_TO_CLASS( keParticles, AvHParticleSystemEntity );
LINK_ENTITY_TO_CLASS( keParticlesCustom, AvHCustomParticleSystemEntity );
AvHParticleSystemEntity::AvHParticleSystemEntity()
{
this->mTemplateIndex = -1;
this->mIsOn = false;
//this->mClientIsOn = false;
this->mUseState = false;
this->mHandle = 0;
this->mCreatedTemplate = false;
this->mTimeParticlesCreated = 0;
this->mCustomData = 0;
}
void AvHParticleSystemEntity::SetTemplateIndex(int inTemplateIndex)
{
this->mTemplateIndex = inTemplateIndex;
}
uint16 AvHParticleSystemEntity::GetCustomData() const
{
return this->mCustomData;
}
void AvHParticleSystemEntity::SetCustomData(uint16 inCustomData)
{
this->mCustomData = inCustomData;
this->pev->weaponmodel = this->mCustomData;
}
// Fetch template if we have a valid template index, create a new custom template if we don't
AvHParticleTemplate*
AvHParticleSystemEntity::GetCustomTemplate()
{
AvHParticleTemplate* theTemplate = NULL;
if(!this->mCreatedTemplate)
{
if(this->mTemplateIndex == -1)
{
// Create a new template, none was specified in the name field
ASSERT(!this->mCreatedTemplate);
this->mTemplateIndex = gParticleTemplateList.CreateTemplateFromIndex();
}
//else
//{
// // Create a template from our existing base template
// this->mTemplateIndex = gParticleTemplateList.CreateTemplateFromIndex(this->mTemplateIndex);
//}
// Set the name of our new custom particle system
theTemplate = gParticleTemplateList.GetTemplateAtIndex(this->mTemplateIndex);
ASSERT(theTemplate);
string theName = STRING(this->pev->targetname);
theTemplate->SetName(theName);
this->mCreatedTemplate = true;
}
ASSERT(this->mTemplateIndex != -1);
if(!theTemplate)
theTemplate = gParticleTemplateList.GetTemplateAtIndex(this->mTemplateIndex);
return theTemplate;
}
void
AvHParticleSystemEntity::KeyValue( KeyValueData* inPkvd )
{
if(FStrEq(inPkvd->szKeyName, kpscSystemName))
{
uint32 theIndex;
if(gParticleTemplateList.GetTemplateIndexWithName(inPkvd->szValue, theIndex))
{
this->mTemplateIndex = theIndex;
inPkvd->fHandled = TRUE;
}
}
else
{
// Call down to base class
CBaseEntity::KeyValue(inPkvd);
}
}
void
AvHParticleSystemEntity::ParticleThink()
{
this->UpdateClientData();
// Look up particle system
AvHParticleSystem* theParticleSystem = AvHParticleSystemManager::Instance()->GetParticleSystem(this->mHandle);
if(theParticleSystem)
{
// Call UpdatePhysics()
theParticleSystem->UpdatePhysics(this->pev);
// The actual entity's position is the regular position of the entity, unless it's using a generaton entity, then use it instead
//theParticleSystem->GetEffectiveOrigin(this->pev->origin);
////UTIL_SetOrigin(this->pev, theGenerationEntityOrigin);
}
this->pev->nextthink = gpGlobals->time + kDefaultParticleSystemThinkRate;
}
void
AvHParticleSystemEntity::ParticleTouch( CBaseEntity* /*pOther*/ )
{
//EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark1.wav", 1.0f, ATTN_NORM);
}
void
AvHParticleSystemEntity::ParticleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
switch(useType)
{
case USE_OFF:
this->mUseState = false;
break;
case USE_ON:
this->mUseState = true;
break;
case USE_SET:
// Handle this?
break;
case USE_TOGGLE:
this->mUseState = !this->mUseState;
break;
}
}
void
AvHParticleSystemEntity::Precache(void)
{
CBaseEntity::Precache();
PRECACHE_UNMODIFIED_MODEL(kNullModel);
}
void AvHParticleSystemEntity::SetUseState(USE_TYPE inUseType)
{
this->ParticleUse(NULL, NULL, inUseType, 0.0f);
}
void
AvHParticleSystemEntity::Spawn( void )
{
// Just in case our class derives off of something else in the future
CBaseEntity::Spawn();
this->Precache();
this->pev->classname = MAKE_STRING(kesParticlesCustom);
this->pev->solid = SOLID_NOT;
this->pev->movetype = MOVETYPE_NONE;
//this->pev->movetype = MOVETYPE_PUSH;
//this->pev->effects = EF_BRIGHTLIGHT;
this->SetTouch(&AvHParticleSystemEntity::ParticleTouch);
this->SetUse(&AvHParticleSystemEntity::ParticleUse);
SET_MODEL(ENT(this->pev), kNullModel);
UTIL_SetOrigin(this->pev, this->pev->origin);
// Set the other flags
AvHParticleTemplate* theTemplate = gParticleTemplateList.GetTemplateAtIndex(this->mTemplateIndex);
//ASSERT(theTemplate);
if(theTemplate)
{
//theTemplate->SetFlags(theSpawnFlags);
string theTargetName = STRING(this->pev->targetname);
if(!FStrEq(theTargetName.c_str(), ""))
{
theTemplate->SetName(theTargetName);
}
this->SetThink(&AvHParticleSystemEntity::ParticleThink);
pev->nextthink = gpGlobals->time + kDefaultParticleSystemThinkRate;
// The spawn flags field is the only one that doesn't get set through KeyValue(), so
// we set it in the template this way
int theSpawnFlags = this->pev->spawnflags;
if(!theSpawnFlags)
{
theSpawnFlags = theTemplate->GetFlags();
}
// Did they check the "start on" flag?
if(theSpawnFlags & 1)
{
this->mUseState = true;
}
theTemplate->SetFlags(theSpawnFlags);
}
else
{
ALERT(at_logged, "Couldn't find particle system template: %d\n", this->mTemplateIndex);
UTIL_Remove(this);
}
}
void
AvHParticleSystemEntity::UpdateClientData()
{
// Turn the system on or off
if(this->mIsOn != this->mUseState)
{
this->mIsOn = this->mUseState;
// set up entity so it's propagated correctly
if(this->mIsOn)
{
// TODO: Reset sCurrentHandle to 1 every time a new game starts?
this->mHandle = sCurrentHandle++;
// Create server side system for collision only
int theEntIndex = this->entindex();
AvHParticleSystemManager::Instance()->CreateParticleSystemIfNotCreated(theEntIndex, this->mTemplateIndex, this->mHandle);
// Replicate action to everyone
this->pev->iuser3 = AVH_USER3_PARTICLE_ON;
const AvHParticleTemplate* theTemplate = gParticleTemplateList.GetTemplateAtIndex(this->mTemplateIndex);
ASSERT(theTemplate);
int theGenEntityIndex = theTemplate->GetGenerationEntityIndex();
if(theGenEntityIndex == -1)
{
theGenEntityIndex = 0;
}
//this->pev->fuser1 = /*this->mTemplateIndex;*/ (theGenEntityIndex << 16) | this->mTemplateIndex;
ASSERT(this->mTemplateIndex < 256);
this->pev->fuser1 = (theGenEntityIndex << 16) | ((this->mTemplateIndex & 0xFF) << 8);
this->pev->fuser2 = this->mHandle;
// Store our custom data
this->SetCustomData(this->mCustomData);
this->mTimeParticlesCreated = gpGlobals->time;
}
else
{
// Destroy server side particle system
//AvHParticleSystemManager::Instance()->DestroyParticleSystemIfNotDestroyed(this->entindex(), this->mHandle);
AvHParticleSystemManager::Instance()->MarkParticleSystemForDeletion(this->entindex(), this->mHandle);
// Replicate action to everyone
this->pev->iuser3 = AVH_USER3_PARTICLE_OFF;
this->pev->fuser1 = this->mHandle;
}
}
if(this->mIsOn)
{
AvHParticleTemplate* theTemplate = gParticleTemplateList.GetTemplateAtIndex(this->mTemplateIndex);
ASSERT(theTemplate);
// If particle system was set to expire, make sure to realize when it turns off
int theParticleSystemLifetime = theTemplate->GetParticleSystemLifetime();
if(theParticleSystemLifetime != -1)
{
if(gpGlobals->time - this->mTimeParticlesCreated >= theParticleSystemLifetime)
{
//this->mIsOn = false;
this->mUseState = false;
}
}
}
}
// Create a custom particle system. Create a new template instead of reading
// one off disk.
void
AvHCustomParticleSystemEntity::KeyValue( KeyValueData* inPkvd )
{
// Read tag with ps name and create a new template using it
if(FStrEq(inPkvd->szKeyName, kpscSystemName))
{
// Custom particle systems shouldn't be specifying a system in the .ps to use
ASSERT(false);
}
else if(FStrEq(inPkvd->szKeyName, kpscGenSource) || FStrEq(inPkvd->szKeyName, "particleGenerationSource"))
{
char* theEntityName = inPkvd->szValue;
this->GetCustomTemplate()->SetGenerationEntityName(theEntityName);
inPkvd->fHandled = TRUE;
}
else if(FStrEq(inPkvd->szKeyName, kpscGenShape) || FStrEq(inPkvd->szKeyName, "particleGenerationShape"))
{
int theGenerationShape = 0;
if(sscanf(inPkvd->szValue, "%d", &theGenerationShape))
{
ShapeType theShape = PS_Point;
switch(theGenerationShape)
{
case 4:
theShape = PS_Box;
break;
case 5:
theShape = PS_Sphere;
break;
case 8:
theShape = PS_Blob;
break;
}
this->GetCustomTemplate()->SetGenerationShape(theShape);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscSprite) || FStrEq(inPkvd->szKeyName, "particleSprite"))
{
// relative path to sprite
string theSpriteName(inPkvd->szValue);
this->GetCustomTemplate()->SetSprite(theSpriteName);
inPkvd->fHandled = TRUE;
}
else if(FStrEq(inPkvd->szKeyName, kpscSpriteNumFrames) || FStrEq(inPkvd->szKeyName, "particleSpriteNumFrames"))
{
// int number of frames
int theNumFrames = 0;
if(sscanf(inPkvd->szValue, "%d", &theNumFrames) == 1)
{
this->GetCustomTemplate()->SetNumSpriteFrames(theNumFrames);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscGenShapeParams) || FStrEq(inPkvd->szKeyName, "particleGenerationShapeParams"))
{
float theParameter = 0;
if(sscanf(inPkvd->szValue, "%f", &theParameter) == 1)
{
this->GetCustomTemplate()->SetGenerationEntityParameter(theParameter);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscNumParticles) || FStrEq(inPkvd->szKeyName, "particleNumParticles"))
{
// max particles, or density
int theNumParticles = 0;
if(sscanf(inPkvd->szValue, "%d", &theNumParticles) == 1)
{
this->GetCustomTemplate()->SetMaxParticles(theNumParticles);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscGenRate) || FStrEq(inPkvd->szKeyName, "particleGenerationRate"))
{
// num particles per second
int theNumParticles = 0;
if(sscanf(inPkvd->szValue, "%d", &theNumParticles) == 1)
{
this->GetCustomTemplate()->SetGenerationRate(theNumParticles);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscSize) || FStrEq(inPkvd->szKeyName, "particleSize"))
{
// float particle size
float theParticleSize = 0;
if(sscanf(inPkvd->szValue, "%f", &theParticleSize) == 1)
{
this->GetCustomTemplate()->SetParticleSize(theParticleSize);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscSystemLifetime) || FStrEq(inPkvd->szKeyName, "particleSystemLifetime"))
{
// string system lifetime
float theLifetime = -1;
if(sscanf(inPkvd->szValue, "%f", &theLifetime) == 1)
{
this->GetCustomTemplate()->SetParticleSystemLifetime(theLifetime);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscAnimationSpeed) || FStrEq(inPkvd->szKeyName, "particleAnimationSpeed"))
{
// Sprite animation speed
float theAnimSpeed = 1.0f;
if(sscanf(inPkvd->szValue, "%f", &theAnimSpeed) == 1)
{
this->GetCustomTemplate()->SetAnimationSpeed(theAnimSpeed);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscParticleLifetime) || FStrEq(inPkvd->szKeyName, "particleLifetime"))
{
// string particle lifetime
float theLifetime = -1;
if(sscanf(inPkvd->szValue, "%f", &theLifetime) == 1)
{
this->GetCustomTemplate()->SetParticleLifetime(theLifetime);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscVelocityShape) || FStrEq(inPkvd->szKeyName, "particleStartingVelocityShape"))
{
int theVelocityShape = 0;
if(sscanf(inPkvd->szValue, "%d", &theVelocityShape))
{
ShapeType theShape = PS_Point;
switch(theVelocityShape)
{
case 1:
theShape = PS_Point;
break;
case 2:
theShape = PS_Box;
break;
case 3:
theShape = PS_Sphere;
break;
case 4:
theShape = PS_Blob;
break;
}
this->GetCustomTemplate()->SetStartingVelocityShape(theShape);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscVelocityParams) || FStrEq(inPkvd->szKeyName, "particleStartingVelParams"))
{
// string, 8 comma-delimited parms
ParticleParams theVelParms;
if(sscanf(inPkvd->szValue, "%d,%d,%d,%d,%d,%d,%d,%d", theVelParms + 0, theVelParms + 1, theVelParms + 2, theVelParms + 3, theVelParms + 4, theVelParms + 5, theVelParms + 6, theVelParms + 7) == 8)
{
this->GetCustomTemplate()->SetStartingVelocityParams(theVelParms);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscScale) || FStrEq(inPkvd->szKeyName, "particleScaling"))
{
// float/string particle scaling
float theScaling = 1.0f;
if(sscanf(inPkvd->szValue, "%f", &theScaling) == 1)
{
this->GetCustomTemplate()->SetParticleScaling(theScaling);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscRendermode) || FStrEq(inPkvd->szKeyName, "particleRenderMode"))
{
// 0-5 render mode
int theRenderMode = 0;
if(sscanf(inPkvd->szValue, "%d", &theRenderMode) == 1)
{
this->GetCustomTemplate()->SetRenderMode(theRenderMode);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscMaxAlpha) || FStrEq(inPkvd->szKeyName, "particleMaxAlpha"))
{
float theMaxAlpha = 1.0f;
if(sscanf(inPkvd->szValue, "%f", &theMaxAlpha) == 1)
{
this->GetCustomTemplate()->SetMaxAlpha(theMaxAlpha);
inPkvd->fHandled = TRUE;
}
}
else if(FStrEq(inPkvd->szKeyName, kpscSystemToGen) || FStrEq(inPkvd->szKeyName, "particleSystemToGenerate"))
{
string theSystemToGenerate = inPkvd->szValue;
this->GetCustomTemplate()->SetParticleSystemToGenerate(theSystemToGenerate);
inPkvd->fHandled = TRUE;
}
else
{
// Call down to base class
AvHParticleSystemEntity::KeyValue(inPkvd);
}
}