// Description: // Particles are grouped into ParticleGroups. // // Copyright (C) 2001 Frank Becker // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software // Foundation; either version 2 of the License, or (at your option) any later // version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details // #include #include #include #include hash_map< const string, ParticleType*, hash, equal_to > ParticleGroup::_particleTypeMap; ParticleGroup::ParticleGroup( const string &groupName, int numParticles): _particles( 0), _aliveCount( 0), _groupName( groupName), _numParticles( numParticles) { XTRACE(); _usedList.next = 0; } ParticleGroup::~ParticleGroup() { XTRACE(); LOG_INFO << _groupName << " has " << _aliveCount << " particles still alive.\n"; ParticleInfo *p = _usedList.next; while( p) { p->tod = 0; p->particle->update( p); p = p->next; } delete[] _particles; } void ParticleGroup::reset( void) { XTRACE(); //trigger particles in use to die ParticleInfo *p = _usedList.next; while( p) { p->tod = 0; p->particle->update( p); p = p->next; } //reset free/used lists _freeList.next = &_particles[0]; for( int i=0; i<_numParticles-1; i++) { _particles[i].next = &_particles[i+1]; } _particles[_numParticles-1].next = 0; _usedList.next = 0; _aliveCount = 0; } bool ParticleGroup::init( void) { XTRACE(); //FIXME: do we really need to restrict size? if( _numParticles > MAX_PARTICLES_PER_GROUP) { _numParticles = MAX_PARTICLES_PER_GROUP; } _particles = new ParticleInfo[ _numParticles]; for( int i=0; i<_numParticles-1; i++) { const vec3 zero(0,0,0); _particles[i].position = zero; _particles[i].velocity = zero; _particles[i].color = zero; _particles[i].extra = zero; _particles[i].prevPosition = zero; _particles[i].prevVelocity = zero; _particles[i].prevColor = zero; _particles[i].prevExtra = zero; } reset(); static bool initialized = false; if( !initialized) { new HeroStinger(); new StingerTrail(); new SmokePuff(); new MiniSmoke(); new ExplosionPiece(); new PlasmaBullet(); new Bonus1( "SuperBonus", 1000); new Bonus1( "Bonus1", 100); new ScoreHighlight(); new EnergyBlob(); new ShieldBoost(); new ArmorPierce(); new WeaponUpgrade(); new StatusMessage(); new Spark(); new BallOfFire(); new BallOfIce(); new BallOfPoison(); new SwarmLeader(); new SwarmElement(); new Phaser(); new FireSpark( "FireSpark1"); new FireSpark( "FireSpark2"); new FireSpark( "FireSpark3"); new FlankBurst( "FlankBurstLeft"); new FlankBurst( "FlankBurstRight"); HeroS::instance(); initialized = true; } return true; } ParticleInfo *ParticleGroup::newParticle( const string & name, const ParticleInfo &pi) { // XTRACE(); ParticleType *particleType = getParticleType( name); if( !particleType) { LOG_ERROR << "Unknown particleType [" << name << "]" << endl; return 0; } return newParticle( particleType, pi); } ParticleInfo *ParticleGroup::newParticle( ParticleType *particleType, const ParticleInfo &pi) { // XTRACE(); ParticleInfo *p = _freeList.next; if( !p) { LOG_ERROR << _groupName << " is out of particles!" << endl; return 0; } _freeList.next = p->next; p->next = _usedList.next; _usedList.next = p; p->particle = particleType; p->position = pi.position; p->velocity = pi.velocity; p->extra = pi.extra; p->color = pi.color; p->text = pi.text; p->damage = pi.damage; p->related = pi.related; //particle initializes particle info particleType->init( p); _aliveCount++; return p; } ParticleInfo *ParticleGroup::newParticle( const string & name, float x, float y, float z) { // XTRACE(); ParticleType *particleType = getParticleType( name); if( !particleType) { LOG_ERROR << "Unknown particleType [" << name << "]" << endl; return 0; } return newParticle( particleType, x, y, z); } ParticleInfo *ParticleGroup::newParticle( ParticleType *particleType, float x, float y, float z) { // XTRACE(); ParticleInfo *p = _freeList.next; if( !p) { LOG_ERROR << _groupName << " is out of particles!" << endl; return 0; } _freeList.next = p->next; p->next = _usedList.next; _usedList.next = p; p->particle = particleType; p->position.x = x; p->position.y = y; p->position.z = z; //particle initializes particle info particleType->init( p); _aliveCount++; return p; } static inline bool hasRadiusCollision( const float &minDist, const vec3 &pos1, const vec3 &pos2) { float d2 = minDist; d2 *= d2; float dx = (pos2.x-pos1.x); float dy = (pos2.y-pos1.y); float D2 = dx*dx + dy*dy; if( D2 < d2) { return true; } return false; } void ParticleGroup::detectCollisions( ParticleGroup *pg) { // XTRACE(); ParticleInfo *p1 = _usedList.next; while( p1) { ParticleInfo *p2 = pg->_usedList.next; while( p2) { if( (p1->radius == 0.0f) || (p2->radius == 0.0f)) { //Bosses are made up of multiple radii for( int rc1=0; rc1 < p1->particle->getRadiiCount(); rc1++) { float r1 = p1->particle->getRadius(rc1); if( r1 == 0.0f) r1 = p1->radius; vec3 offset1 = p1->particle->getOffset(rc1); for( int rc2=0; rc2 < p2->particle->getRadiiCount(); rc2++) { float r2 = p2->particle->getRadius(rc2); if( r2 == 0.0f) r2 = p2->radius; vec3 offset2 = p2->particle->getOffset(rc2); vec3 pos1 = p1->position+offset1; vec3 pos2 = p2->position+offset2; // LOG_INFO << "pos1 = " << pos1.x << " " << pos1.y << "\n"; // LOG_INFO << "pos2 = " << pos2.x << " " << pos2.y << "\n"; if( hasRadiusCollision( r1+r2, pos1, pos2)) { p1->particle->hit( p1, p2, rc1); p2->particle->hit( p2, p1, rc2); } } } } else { if( hasRadiusCollision( p1->radius+p2->radius, p1->position, p2->position)) { p1->particle->hit( p1, p2->damage); p2->particle->hit( p2, p1->damage); } } p2 = p2->next; } p1 = p1->next; } } void ParticleGroup::addParticleType( ParticleType *particleType) { XTRACE(); if( particleType) { LOG_INFO << "New Particle type: [" << particleType->name() << "]" << endl; _particleTypeMap[ particleType->name()] = particleType; } } ParticleType * ParticleGroup::getParticleType( const string particleTypeName) { // XTRACE(); ParticleType * particleType = findHash( particleTypeName, _particleTypeMap); if( !particleType) { LOG_ERROR << "ParticleGroup never heard of a " << particleTypeName << " before!" << endl; //trying first in list particleType = _particleTypeMap.begin()->second; } return particleType; }