static void CL_ParticleFunction (ptl_t *p, ptlCmd_t *cmd) { int stackIdx; ptrdiff_t e; int type; int i, j, n; void *cmdData; float arg; ptl_t *pnew; /* test for null cmd */ if (!cmd) return; /* run until finding PC_END */ for (stackIdx = 0, e = 0; cmd->cmd != PC_END; cmd++) { if (cmd->ref > RSTACK) cmdData = CL_ParticleCommandGetDataLocation(p, cmd); else { if (!stackIdx) Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow"); /* pop an element off the stack */ e = (byte *) stackPtr[--stackIdx] - cmdStack; i = RSTACK - cmd->ref; if (!i) { /* normal stack reference */ cmdData = stackPtr[stackIdx]; cmd->type = stackType[stackIdx]; } else { /* stack reference to element of vector */ if ((1 << stackType[stackIdx]) & V_VECS) { cmd->type = V_FLOAT; cmdData = (float *) stackPtr[stackIdx] + (i - 1); } else { Com_Error(ERR_DROP, "CL_ParticleFunction: can't get components of a non-vector type (particle %s)", p->ctrl->name); } } } switch (cmd->cmd) { case PC_PUSH: /* check for stack overflow */ if (stackIdx >= MAX_STACK_DEPTH) Com_Error(ERR_DROP, "CL_ParticleFunction: stack overflow"); /* store the value in the stack */ stackPtr[stackIdx] = &cmdStack[e]; stackType[stackIdx] = cmd->type; e += Com_SetValue(stackPtr[stackIdx++], cmdData, (valueTypes_t)cmd->type, 0, 0); break; case PC_POP: case PC_KPOP: /* check for stack underflow */ if (stackIdx == 0) Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow"); /* get pics and models */ if (offsetof(ptl_t, pic) == -cmd->ref) { if (stackType[--stackIdx] != V_STRING) Com_Error(ERR_DROP, "Bad type '%s' for pic (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name); p->pic = CL_ParticleGetArt((char *) stackPtr[stackIdx], p->frame, ART_PIC); e = (byte *) stackPtr[stackIdx] - cmdStack; break; } if (offsetof(ptl_t, model) == -cmd->ref) { if (stackType[--stackIdx] != V_STRING) Com_Error(ERR_DROP, "Bad type '%s' for model (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name); p->model = CL_ParticleGetArt((char *) stackPtr[stackIdx], p->frame, ART_MODEL); e = (byte *) stackPtr[stackIdx] - cmdStack; break; } if (offsetof(ptl_t, program) == -cmd->ref) { if (stackType[--stackIdx] != V_STRING) Com_Error(ERR_DROP, "Bad type '%s' for program (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name); p->program = R_LoadProgram((char *) stackPtr[stackIdx], R_InitParticleProgram, R_UseParticleProgram); if (p->program) p->program->userdata = p; e = (byte *) stackPtr[stackIdx] - cmdStack; break; } /* get different data */ if (cmd->cmd == PC_POP) e -= Com_SetValue(cmdData, stackPtr[--stackIdx], (valueTypes_t)cmd->type, 0, 0); else Com_SetValue(cmdData, stackPtr[stackIdx - 1], (valueTypes_t)cmd->type, 0, 0); break; case PC_ADD: case PC_SUB: /* check for stack underflow */ if (stackIdx == 0) Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow"); type = stackType[stackIdx - 1]; if (!((1 << type) & V_VECS)) Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' for add (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name); /* float based vector addition */ if (type != cmd->type) Com_Error(ERR_DROP, "CL_ParticleFunction: bad vector dimensions for add/sub (particle %s)", p->ctrl->name); n = type - V_FLOAT + 1; for (i = 0; i < n; i++) { if (cmd->cmd == PC_SUB) arg = -(*((float *) cmdData + i)); else arg = *((float *) cmdData + i); *((float *) stackPtr[stackIdx - 1] + i) += arg; } break; case PC_MUL: case PC_DIV: /* check for stack underflow */ if (stackIdx == 0) Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow"); type = stackType[stackIdx - 1]; if (!((1 << type) & V_VECS)) Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' for add (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name); n = type - V_FLOAT + 1; if (type > V_FLOAT && cmd->type > V_FLOAT) { /* component wise multiplication */ if (type != cmd->type) Com_Error(ERR_DROP, "CL_ParticleFunction: bad vector dimensions for mul/div (particle %s)", p->ctrl->name); for (i = 0; i < n; i++) { if (cmd->cmd == PC_DIV) arg = 1.0 / (*((float *) cmdData + i)); else arg = *((float *) cmdData + i); *((float *) stackPtr[stackIdx - 1] + i) *= arg; } break; } if (cmd->type > V_FLOAT) Com_Error(ERR_DROP, "CL_ParticleFunction: bad vector dimensions for mul/div (particle %s)", p->ctrl->name); /* scalar multiplication with scalar in second argument */ if (cmd->cmd == PC_DIV) arg = 1.0 / (*(float *) cmdData); else arg = *(float *) cmdData; for (i = 0; i < n; i++) *((float *) stackPtr[stackIdx - 1] + i) *= arg; break; case PC_SIN: if (cmd->type != V_FLOAT) Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' for sin (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name); stackPtr[stackIdx] = &cmdStack[e]; stackType[stackIdx] = cmd->type; *(float *) stackPtr[stackIdx++] = sin(*(float *) cmdData * (2 * M_PI)); e += sizeof(float); break; case PC_COS: if (cmd->type != V_FLOAT) Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' for cos (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name); stackPtr[stackIdx] = &cmdStack[e]; stackType[stackIdx] = cmd->type; *(float *) stackPtr[stackIdx++] = sin(*(float *) cmdData * (2 * M_PI)); e += sizeof(float); break; case PC_TAN: if (cmd->type != V_FLOAT) Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' for tan (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name); stackPtr[stackIdx] = &cmdStack[e]; stackType[stackIdx] = cmd->type; *(float *) stackPtr[stackIdx++] = sin(*(float *) cmdData * (2 * M_PI)); e += sizeof(float); break; case PC_RAND: case PC_CRAND: stackPtr[stackIdx] = &cmdStack[e]; stackType[stackIdx] = cmd->type; n = cmd->type - V_FLOAT + 1; if (cmd->cmd == PC_RAND) for (i = 0; i < n; i++) *((float *) stackPtr[stackIdx] + i) = *((float *) cmdData + i) * frand(); else for (i = 0; i < n; i++) *((float *) stackPtr[stackIdx] + i) = *((float *) cmdData + i) * crand(); e += n * sizeof(float); stackIdx++; break; case PC_V2: case PC_V3: case PC_V4: n = cmd->cmd - PC_V2 + 2; j = 0; if (stackIdx < n) Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow"); for (i = 0; i < n; i++) { if (!((1 << stackType[--stackIdx]) & V_VECS)) Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' for vector creation (particle %s)", vt_names[stackType[stackIdx]], p->ctrl->name); j += stackType[stackIdx] - V_FLOAT + 1; } if (j > 4) Com_Error(ERR_DROP, "CL_ParticleFunction: created vector with dim > 4 (particle %s)", p->ctrl->name); stackType[stackIdx++] = V_FLOAT + j - 1; break; case PC_KILL: CL_ParticleFree(p); return; case PC_SPAWN: pnew = CL_ParticleSpawn((const char *) cmdData, p->levelFlags, p->s, p->v, p->a); if (!pnew) Com_Printf("PC_SPAWN: Could not spawn child particle for '%s' (%s)\n", p->ctrl->name, (const char *) cmdData); break; case PC_TNSPAWN: /* check for stack underflow */ if (stackIdx < 2) Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow"); /* pop elements off the stack */ /* amount of timed particles */ type = stackType[--stackIdx]; if (type != V_INT) Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' int required for tnspawn (particle %s)", vt_names[stackType[stackIdx]], p->ctrl->name); n = *(int *) stackPtr[stackIdx]; /* delta time */ type = stackType[--stackIdx]; if (type != V_INT) Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' int required for tnspawn (particle %s)", vt_names[stackType[stackIdx]], p->ctrl->name); i = *(int *) stackPtr[stackIdx]; /** @todo make the children boolean configurable */ CL_ParticleSpawnTimed((const char *) cmdData, p, true, i, n); e -= 2 * sizeof(int); break; case PC_NSPAWN: /* check for stack underflow */ if (stackIdx == 0) Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow"); type = stackType[--stackIdx]; if (type != V_INT) Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' int required for nspawn (particle %s)", vt_names[stackType[stackIdx]], p->ctrl->name); n = *(int *) stackPtr[stackIdx]; e -= sizeof(int); for (i = 0; i < n; i++) { pnew = CL_ParticleSpawn((const char *) cmdData, p->levelFlags, p->s, p->v, p->a); if (!pnew) Com_Printf("PC_NSPAWN: Could not spawn child particle for '%s'\n", p->ctrl->name); } break; case PC_CHILD: pnew = CL_ParticleSpawn((const char *)cmdData, p->levelFlags, p->s, p->v, p->a); if (pnew) { pnew->next = p->children; pnew->parent = p; p->children = pnew; } else { Com_Printf("PC_CHILD: Could not spawn child particle for '%s'\n", p->ctrl->name); } break; default: Com_Error(ERR_DROP, "CL_ParticleFunction: unknown cmd type %i", cmd->type); break; } } }
void CLQ2_RailTrail( vec3_t start, vec3_t end ) { byte clr = 0x74; vec3_t move; VectorCopy( start, move ); vec3_t vec; VectorSubtract( end, start, vec ); float len = VectorNormalize( vec ); vec3_t right, up; MakeNormalVectors( vec, right, up ); for ( int i = 0; i < len; i++ ) { cparticle_t* p = CL_AllocParticle(); if ( !p ) { return; } p->type = pt_q2static; VectorClear( p->accel ); float d = i * 0.1; float c = cos( d ); float s = sin( d ); vec3_t dir; VectorScale( right, c, dir ); VectorMA( dir, s, up, dir ); p->alpha = 1.0; p->alphavel = -1.0 / ( 1 + frand() * 0.2 ); p->color = clr + ( rand() & 7 ); for ( int j = 0; j < 3; j++ ) { p->org[ j ] = move[ j ] + dir[ j ] * 3; p->vel[ j ] = dir[ j ] * 6; } VectorAdd( move, vec, move ); } float dec = 0.75; VectorScale( vec, dec, vec ); VectorCopy( start, move ); while ( len > 0 ) { len -= dec; cparticle_t* p = CL_AllocParticle(); if ( !p ) { return; } p->type = pt_q2static; VectorClear( p->accel ); p->alpha = 1.0; p->alphavel = -1.0 / ( 0.6 + frand() * 0.2 ); p->color = rand() & 15; for ( int j = 0; j < 3; j++ ) { p->org[ j ] = move[ j ] + crand() * 3; p->vel[ j ] = crand() * 3; p->accel[ j ] = 0; } VectorAdd( move, vec, move ); } }
void CLQ2_TrapParticles( vec3_t origin ) { origin[ 2 ] -= 14; vec3_t start; VectorCopy( origin, start ); vec3_t end; VectorCopy( origin, end ); origin[ 2 ] += 14; end[ 2 ] += 64; vec3_t move; VectorCopy( start, move ); vec3_t vec; VectorSubtract( end, start, vec ); float len = VectorNormalize( vec ); int dec = 5; VectorScale( vec, 5, vec ); // FIXME: this is a really silly way to have a loop while ( len > 0 ) { len -= dec; cparticle_t* p = CL_AllocParticle(); if ( !p ) { return; } p->type = pt_q2static; VectorClear( p->accel ); p->alpha = 1.0; p->alphavel = -1.0 / ( 0.3 + frand() * 0.2 ); p->color = 0xe0; for ( int j = 0; j < 3; j++ ) { p->org[ j ] = move[ j ] + crand(); p->vel[ j ] = crand() * 15; p->accel[ j ] = 0; } p->accel[ 2 ] = PARTICLE_GRAVITY; VectorAdd( move, vec, move ); } vec3_t org; VectorCopy( origin, org ); for ( int i = -2; i <= 2; i += 4 ) { for ( int j = -2; j <= 2; j += 4 ) { for ( int k = -2; k <= 2; k += 4 ) { cparticle_t* p = CL_AllocParticle(); if ( !p ) { return; } p->type = pt_q2static; p->color = 0xe0 + ( rand() & 3 ); p->alpha = 1.0; p->alphavel = -1.0 / ( 0.3 + ( rand() & 7 ) * 0.02 ); p->org[ 0 ] = org[ 0 ] + i + ( ( rand() & 23 ) * crand() ); p->org[ 1 ] = org[ 1 ] + j + ( ( rand() & 23 ) * crand() ); p->org[ 2 ] = org[ 2 ] + k + ( ( rand() & 23 ) * crand() ); vec3_t dir; dir[ 0 ] = j * 8; dir[ 1 ] = i * 8; dir[ 2 ] = k * 8; VectorNormalize( dir ); float vel = 50 + ( rand() & 63 ); VectorScale( dir, vel, p->vel ); p->accel[ 0 ] = p->accel[ 1 ] = 0; p->accel[ 2 ] = -PARTICLE_GRAVITY; } } } }
void CL_Heatbeam (vec3_t start, vec3_t end) { vec3_t move; vec3_t vec; float len; int j; cparticle_t *p; vec3_t forward, right, up; int i; float d, c, s; vec3_t dir; float ltime; float step = 32.0, rstep; float start_pt; float rot; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); // MakeNormalVectors (vec, right, up); VectorCopy (cl.v_forward, forward); VectorCopy (cl.v_right, right); VectorCopy (cl.v_up, up); VectorMA (move, -0.5, right, move); VectorMA (move, -0.5, up, move); for (i=0; i<8; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); d = crand()*M_PI; c = cos(d)*30; s = sin(d)*30; p->alpha = 1.0; p->alphavel = -5.0 / (1+frand()); p->color = 223 - (rand()&7); for (j=0 ; j<3 ; j++) { p->org[j] = move[j]; } VectorScale (vec, 450, p->vel); VectorMA (p->vel, c, right, p->vel); VectorMA (p->vel, s, up, p->vel); } /* ltime = (float) cl.time/1000.0; start_pt = fmod(ltime*16.0,step); VectorMA (move, start_pt, vec, move); VectorScale (vec, step, vec); // Com_Printf ("%f\n", ltime); rstep = M_PI/12.0; for (i=start_pt ; i<len ; i+=step) { if (i>step*5) // don't bother after the 5th ring break; for (rot = 0; rot < M_PI*2; rot += rstep) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); // rot+= fmod(ltime, 12.0)*M_PI; // c = cos(rot)/2.0; // s = sin(rot)/2.0; c = cos(rot)/1.5; s = sin(rot)/1.5; // trim it so it looks like it's starting at the origin if (i < 10) { VectorScale (right, c*(i/10.0), dir); VectorMA (dir, s*(i/10.0), up, dir); } else { VectorScale (right, c, dir); VectorMA (dir, s, up, dir); } p->alpha = 0.5; // p->alphavel = -1.0 / (1+frand()*0.2); p->alphavel = -1000.0; // p->color = 0x74 + (rand()&7); p->color = 223 - (rand()&7); for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + dir[j]*3; // p->vel[j] = dir[j]*6; p->vel[j] = 0; } } VectorAdd (move, vec, move); } */ }
void CLQ2_DiminishingTrail( vec3_t start, vec3_t end, q2centity_t* old, int flags ) { vec3_t move; VectorCopy( start, move ); vec3_t vec; VectorSubtract( end, start, vec ); float len = VectorNormalize( vec ); float dec = 0.5; VectorScale( vec, dec, vec ); float orgscale; float velscale; if ( old->trailcount > 900 ) { orgscale = 4; velscale = 15; } else if ( old->trailcount > 800 ) { orgscale = 2; velscale = 10; } else { orgscale = 1; velscale = 5; } while ( len > 0 ) { len -= dec; // drop less particles as it flies if ( ( rand() & 1023 ) < old->trailcount ) { cparticle_t* p = CL_AllocParticle(); if ( !p ) { return; } p->type = pt_q2static; VectorClear( p->accel ); if ( flags & Q2EF_GIB ) { p->alpha = 1.0; p->alphavel = -1.0 / ( 1 + frand() * 0.4 ); p->color = 0xe8 + ( rand() & 7 ); for ( int j = 0; j < 3; j++ ) { p->org[ j ] = move[ j ] + crand() * orgscale; p->vel[ j ] = crand() * velscale; p->accel[ j ] = 0; } p->vel[ 2 ] -= PARTICLE_GRAVITY; } else if ( flags & Q2EF_GREENGIB ) { p->alpha = 1.0; p->alphavel = -1.0 / ( 1 + frand() * 0.4 ); p->color = 0xdb + ( rand() & 7 ); for ( int j = 0; j < 3; j++ ) { p->org[ j ] = move[ j ] + crand() * orgscale; p->vel[ j ] = crand() * velscale; p->accel[ j ] = 0; } p->vel[ 2 ] -= PARTICLE_GRAVITY; } else { p->alpha = 1.0; p->alphavel = -1.0 / ( 1 + frand() * 0.2 ); p->color = 4 + ( rand() & 7 ); for ( int j = 0; j < 3; j++ ) { p->org[ j ] = move[ j ] + crand() * orgscale; p->vel[ j ] = crand() * velscale; } p->accel[ 2 ] = 20; } } old->trailcount -= 5; if ( old->trailcount < 100 ) { old->trailcount = 100; } VectorAdd( move, vec, move ); } }
/* =============== CL_RailTrail =============== */ void CL_RailTrail (vec3_t start, vec3_t end) { vec3_t move; vec3_t vec; float len; int j; cparticle_t *p; float dec; vec3_t right, up; int i; float d, c, s; vec3_t dir; byte clr = 0x74; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); MakeNormalVectors (vec, right, up); for (i=0 ; i<len ; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); d = i * 0.1; c = cos(d); s = sin(d); VectorScale (right, c, dir); VectorMA (dir, s, up, dir); p->alpha = 1.0; p->alphavel = -1.0 / (1+frand()*0.2); p->color = clr + (rand()&7); for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + dir[j]*3; p->vel[j] = dir[j]*6; } VectorAdd (move, vec, move); } dec = 0.75; VectorScale (vec, dec, vec); VectorCopy (start, move); while (len > 0) { len -= dec; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); p->alpha = 1.0; p->alphavel = -1.0 / (0.6+frand()*0.2); p->color = 0x0 + rand()&15; for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand()*3; p->vel[j] = crand()*3; p->accel[j] = 0; } VectorAdd (move, vec, move); } }
// RAFAEL void CL_TrapParticles (entity_t *ent) { vec3_t move; vec3_t vec; vec3_t start, end; float len; int j; cparticle_t *p; int dec; ent->origin[2]-=14; VectorCopy (ent->origin, start); VectorCopy (ent->origin, end); end[2]+=64; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); dec = 5; VectorScale (vec, 5, vec); // FIXME: this is a really silly way to have a loop while (len > 0) { len -= dec; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0 / (0.3+frand()*0.2); p->color = 0xe0; for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand(); p->vel[j] = crand()*15; p->accel[j] = 0; } p->accel[2] = PARTICLE_GRAVITY; VectorAdd (move, vec, move); } { int i, j, k; cparticle_t *p; float vel; vec3_t dir; vec3_t org; ent->origin[2]+=14; VectorCopy (ent->origin, org); for (i=-2 ; i<=2 ; i+=4) for (j=-2 ; j<=2 ; j+=4) for (k=-2 ; k<=4 ; k+=4) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; p->color = 0xe0 + (rand()&3); p->alpha = 1.0; p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02); p->org[0] = org[0] + i + ((rand()&23) * crand()); p->org[1] = org[1] + j + ((rand()&23) * crand()); p->org[2] = org[2] + k + ((rand()&23) * crand()); dir[0] = j * 8; dir[1] = i * 8; dir[2] = k * 8; VectorNormalize (dir); vel = 50 + rand()&63; VectorScale (dir, vel, p->vel); p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY; } } }
/* =============== CL_RailTrail =============== */ void CL_RailTrail (const vec3_t start, const vec3_t end) { vec3_t move, vec, right, up, dir; float len, dec, c, s; cparticle_t *p; int i; byte clr = 0x74; cdlight_t *dl; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); // add a light at the dest dl = CL_AllocDlight(0); VectorCopy(end, dl->origin); dl->radius = 100; dl->die = cl.time + 200; VectorSet(dl->color, 0.3, 0.5, 1.0); MakeNormalVectors (vec, right, up); for (i=0 ; i<len ; i++) { if(i % 3 == 0){ VectorAdd(move, vec, move); continue; } if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); Q_sincos(i * 0.1f, &s, &c); VectorScale (right, c, dir); VectorMA (dir, s, up, dir); p->alpha = 1.0f; p->alphavel = -1.0f / (1.0f+frand()*0.2f); p->color = clr + (rand()&7); p->org[0] = move[0] + dir[0]*3; p->org[1] = move[1] + dir[1]*3; p->org[2] = move[2] + dir[2]*3; p->vel[0] = dir[0]*6; p->vel[1] = dir[1]*6; p->vel[2] = dir[2]*6; VectorAdd (move, vec, move); } dec = 2.0f; VectorScale (vec, dec, vec); VectorCopy (start, move); while (len > 0) { len -= dec; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); p->alpha = 1.0f; p->alphavel = -1.0f / (0.6f+frand()*0.2f); p->color = 0x0 + (rand()&15); p->org[0] = move[0] + crand()*3; p->org[1] = move[1] + crand()*3; p->org[2] = move[2] + crand()*3; p->vel[0] = crand()*3; p->vel[1] = crand()*3; p->vel[2] = crand()*3; VectorAdd (move, vec, move); } }
/* =============== CL_DiminishingTrail =============== */ void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags) { vec3_t move; vec3_t vec; float len; int j; cparticle_t *p; float dec; float orgscale; float velscale; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); dec = 0.5; VectorScale (vec, dec, vec); if (old->trailcount > 900) { orgscale = 4; velscale = 15; } else if (old->trailcount > 800) { orgscale = 2; velscale = 10; } else { orgscale = 1; velscale = 5; } while (len > 0) { len -= dec; if (!free_particles) return; // drop less particles as it flies if ((rand()&1023) < old->trailcount) { p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; if (flags & EF_GIB) { p->alpha = 1.0; p->alphavel = -1.0 / (1+frand()*0.4); p->color = 0xe8 + (rand()&7); for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand()*orgscale; p->vel[j] = crand()*velscale; p->accel[j] = 0; } p->vel[2] -= PARTICLE_GRAVITY; } else if (flags & EF_GREENGIB) { p->alpha = 1.0; p->alphavel = -1.0 / (1+frand()*0.4); p->color = 0xdb + (rand()&7); for (j=0; j< 3; j++) { p->org[j] = move[j] + crand()*orgscale; p->vel[j] = crand()*velscale; p->accel[j] = 0; } p->vel[2] -= PARTICLE_GRAVITY; } else { p->alpha = 1.0; p->alphavel = -1.0 / (1+frand()*0.2); p->color = 4 + (rand()&7); for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand()*orgscale; p->vel[j] = crand()*velscale; } p->accel[2] = 20; } } old->trailcount -= 5; if (old->trailcount < 100) old->trailcount = 100; VectorAdd (move, vec, move); } }
uint32_t random_days(uint8_t hour, uint8_t min, uint8_t sec, uint32_t base_days) { init_crand_consistent(hour,min,sec); uint32_t random = (crand(0) * 1000) / 0x7FFF; return (uint32_t)((base_days * random) / 1000); }
/** * @brief Updates weather for the time passed; handles particle creation/removal automatically */ void Weather::update (int milliseconds) { /* Don't play the weather particles if the user doesn't want them */ if (!Cvar_GetInteger("cl_particleweather")) { /* This makes weather look very weird if it is enabled mid-battle */ /* clearParticles(); */ return; } size_t dead = 0; /* physics: check for ttl and move live particles */ for (size_t i = 0; i < Weather::MAX_PARTICLES; i++) { Weather::particle &prt = particles[i]; if (prt.ttl < 0) { dead++; continue; } else { /** @todo creates vanishing-before-impact particles at low framerates -- should improve that somehow */ int restOfLife = prt.ttl -= milliseconds; if (restOfLife < 0) { if (fabs(prt.vz) < 0.001f || splashTime < 1) { /* either no splash or is a splash particle dying */ dead++; continue; } /* convert it into splash particle */ /* technically, we should complete the last frame of movement, but with current particle types it looks good even without it */ prt.vz = 0; prt.vx = 0; prt.vy = 0; prt.ttl += splashTime; } } /* if we got so far, particle is alive and probably needs a physics update */ const int timeAfterUpdate = prt.timeout -= milliseconds; const float moveDuration = milliseconds * 0.001f; prt.x += prt.vx * moveDuration; prt.y += prt.vy * moveDuration; prt.z += prt.vz * moveDuration; if (timeAfterUpdate > 0) { /* just move linearly */ continue; } /* alter motion vector */ /** @todo */ } /* create new ones in place of dead */ if (dead) { const float windX = cos(windDirection) * (windStrength + crand() * windTurbulence); const float windY = sin(windDirection) * (windStrength + crand() * windTurbulence); AABB weatherZone; /** < extents of zone in which weather particles will be rendered */ weatherZone = cl.mapData->mapBox; weatherZone.expandXY(256); weatherZone.maxs[2] += 512; Line prtPath; if (dead > 200) dead = 200; /* avoid creating too much particles in the single frame, it could kill the low-end hardware */ int debugCreated = 0; for (size_t i = 0; dead && i < Weather::MAX_PARTICLES && i < weatherStrength * Weather::MAX_PARTICLES; i++) { Weather::particle &prt = particles[i]; if (prt.ttl >= 0) continue; prt.x = (frand() * (weatherZone.getMaxX() - weatherZone.getMinX())) + weatherZone.getMinX(); prt.y = (frand() * (weatherZone.getMaxY() - weatherZone.getMinY())) + weatherZone.getMinY(); prt.z = weatherZone.getMaxZ(); prt.vx = windX; prt.vy = windY; prt.vz = -fallingSpeed * (frand() * 0.2f + 0.9f); float lifeTime = (weatherZone.getMaxZ() - weatherZone.getMinZ()) / -prt.vz; /* default */ VectorSet(prtPath.start, prt.x, prt.y, prt.z); VectorSet(prtPath.stop, prt.x + prt.vx * lifeTime, prt.y + prt.vy * lifeTime, prt.z + prt.vz * lifeTime); trace_t trace = CL_Trace(prtPath, AABB::EMPTY, nullptr, nullptr, MASK_SOLID, cl.mapMaxLevel - 1); /* find the collision point */ lifeTime *= trace.fraction; prt.ttl = 1000 * lifeTime; /* convert to milliseconds */ prt.timeout = prt.ttl + 1000000; /** @todo proper code for physics */ debugCreated++; dead--; } } #if 0 if (debugCreated) Com_Printf("created %i weather particles\n", debugCreated); #endif }
/* =============== CL_BubbleTrail2 (lets you control the # of bubbles by setting the distance between the spawns) =============== */ void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist) { vec3_t move; vec3_t vec; float len; int i; #ifndef QMAX int j; cparticle_t *p; #endif float dec; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); dec = dist; VectorScale (vec, dec, vec); for (i=0 ; i<len ; i+=dec) { #ifdef QMAX setupParticle ( 0, 0, 0, move[0]+crand()*2, move[1]+crand()*2, move[2]+crand()*2, crand()*5, crand()*5, crand()*5+6, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0.75, -1.0 / (1 + frand() * 0.2), (frand()>0.25)? 1 : (frand()>0.5) ? 2 : (frand()>0.75) ? 3 : 4, 1, particle_bubble, PART_TRANS|PART_SHADED, NULL,0); #else if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0 / (1+frand()*0.1); p->color = 4 + (rand()&7); for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand()*2; p->vel[j] = crand()*10; } p->org[2] -= 4; // p->vel[2] += 6; p->vel[2] += 20; #endif VectorAdd (move, vec, move); } }
void CL_FlameEffects (centity_t *ent, vec3_t origin) { int n, count; int j; cparticle_t *p; count = rand() & 0xF; for(n=0;n<count;n++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0 / (1+frand()*0.2); #ifndef QMAX p->color = 226 + (rand() % 4); #endif for (j=0 ; j<3 ; j++) { p->org[j] = origin[j] + crand()*5; p->vel[j] = crand()*5; } p->vel[2] = crand() * -10; p->accel[2] = -PARTICLE_GRAVITY; } count = rand() & 0x7; for(n=0;n<count;n++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0 / (1+frand()*0.5); #ifndef QMAX p->color = 0 + (rand() % 4); #endif for (j=0 ; j<3 ; j++) { p->org[j] = origin[j] + crand()*3; } p->vel[2] = 20 + crand()*5; } }
void CL_ForceWall (vec3_t start, vec3_t end, int color8) { vec3_t move; vec3_t vec; #ifdef QMAX vec3_t color = { color8red(color8), color8green(color8), color8blue(color8)}; #else int j; cparticle_t *p; #endif float len; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); VectorScale (vec, 4, vec); // FIXME: this is a really silly way to have a loop while (len > 0) { len -= 4; if (!free_particles) return; if (frand() > 0.3) { #ifdef QMAX setupParticle ( 0, 0, 0, move[0] + crand()*3, move[1] + crand()*3, move[2] + crand()*3, 0, 0, -40 - (crand()*10), 0, 0, 0, color[0]+5, color[1]+5, color[2]+5, 0, 0, 0, 1, -1.0 / (3.0+frand()*0.5), 5, 0, particle_generic, 0, NULL,0); #else p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0 / (3.0+frand()*0.5); p->color = color8; for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand()*3; p->accel[j] = 0; } p->vel[0] = 0; p->vel[1] = 0; p->vel[2] = -40 - (crand()*10); #endif } VectorAdd (move, vec, move); } }