void sphere_fire(edict_t *self, edict_t *enemy) { vec3_t dest; vec3_t dir; if (!self || !enemy) { return; } if ((level.time >= self->wait) || !enemy) { sphere_think_explode(self); return; } VectorCopy(enemy->s.origin, dest); self->s.effects |= EF_ROCKET; VectorSubtract(dest, self->s.origin, dir); VectorNormalize(dir); vectoangles2(dir, self->s.angles); VectorScale(dir, 1000, self->velocity); self->touch = vengeance_touch; self->think = sphere_think_explode; self->nextthink = self->wait; }
void fire_doppleganger(edict_t *ent, vec3_t start, vec3_t aimdir) { edict_t *base; edict_t *body; vec3_t dir; vec3_t forward, right, up; int number; if (!ent) { return; } vectoangles2(aimdir, dir); AngleVectors(dir, forward, right, up); base = G_Spawn(); VectorCopy(start, base->s.origin); VectorCopy(dir, base->s.angles); VectorClear(base->velocity); VectorClear(base->avelocity); base->movetype = MOVETYPE_TOSS; base->solid = SOLID_BBOX; base->s.renderfx |= RF_IR_VISIBLE; base->s.angles[PITCH] = 0; VectorSet(base->mins, -16, -16, -24); VectorSet(base->maxs, 16, 16, 32); base->s.modelindex = 0; base->teammaster = ent; base->svflags |= SVF_DAMAGEABLE; base->takedamage = DAMAGE_AIM; base->health = 30; base->pain = doppleganger_pain; base->die = doppleganger_die; base->nextthink = level.time + 30; base->think = doppleganger_timeout; base->classname = "doppleganger"; gi.linkentity(base); body = G_Spawn(); number = body->s.number; body->s = ent->s; body->s.sound = 0; body->s.event = 0; body->s.number = number; body->yaw_speed = 30; body->ideal_yaw = 0; VectorCopy(start, body->s.origin); body->s.origin[2] += 8; body->think = body_think; body->nextthink = level.time + FRAMETIME; gi.linkentity(body); base->teamchain = body; body->teammaster = base; }
/* =============== CL_TrackerTrail =============== */ void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor) { vec3_t move; vec3_t vec; vec3_t forward,right,up,angle_dir; float len; int j; cparticle_t *p; int dec; float dist; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); VectorCopy(vec, forward); vectoangles2 (forward, angle_dir); AngleVectors (angle_dir, forward, right, up); dec = 3; VectorScale (vec, 3, 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 = -2.0; #ifndef QMAX p->color = particleColor; #endif dist = DotProduct(move, forward); VectorMA(move, 8 * cos(dist), up, p->org); for (j=0 ; j<3 ; j++) { // p->org[j] = move[j] + crand(); p->vel[j] = 0; p->accel[j] = 0; } p->vel[2] = 5; VectorAdd (move, vec, move); } }
/* ===================== hintpath_start Makes a monster go towards a hintpath spot, and clears inhibiting AI flags. ===================== */ void hintpath_start (edict_t *monster, edict_t *spot) { vec3_t goDir, goAngles; VectorSubtract(spot->s.origin, monster->s.origin, goDir); vectoangles2 (goDir, goAngles); monster->monsterinfo.aiflags &= ~(AI_SOUND_TARGET | AI_PURSUIT_LAST_SEEN | AI_PURSUE_NEXT | AI_PURSUE_TEMP); monster->monsterinfo.aiflags |= AI_HINT_PATH; monster->monsterinfo.pausetime = 0; monster->ideal_yaw = goAngles[YAW]; monster->movetarget = monster->goalentity = spot; // get moovin! monster->monsterinfo.search_time = level.time; monster->monsterinfo.run (monster); }
void WidowBlaster (edict_t *self) { vec3_t forward, right, target, vec, targ_angles; vec3_t start; int flashnum; int effect; if (!self->enemy) return; shotsfired++; if (!(shotsfired % 4)) effect = EF_BLASTER; else effect = 0; AngleVectors (self->s.angles, forward, right, NULL); if ((self->s.frame >= FRAME_spawn05) && (self->s.frame <= FRAME_spawn13)) { // sweep flashnum = MZ2_WIDOW_BLASTER_SWEEP1 + self->s.frame - FRAME_spawn05; G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start); VectorSubtract (self->enemy->s.origin, start, target); vectoangles2 (target, targ_angles); VectorCopy (self->s.angles, vec); vec[PITCH] += targ_angles[PITCH]; vec[YAW] -= sweep_angles[flashnum-MZ2_WIDOW_BLASTER_SWEEP1]; AngleVectors (vec, forward, NULL, NULL); monster_fire_blaster2 (self, start, forward, BLASTER2_DAMAGE*widow_damage_multiplier, 1000, flashnum, effect); } else if ((self->s.frame >= FRAME_fired02a) && (self->s.frame <= FRAME_fired20)) { vec3_t angles; float aim_angle, target_angle; float error; self->monsterinfo.aiflags |= AI_MANUAL_STEERING; self->monsterinfo.nextframe = WidowTorso (self); if (!self->monsterinfo.nextframe) self->monsterinfo.nextframe = self->s.frame; if (self->s.frame == FRAME_fired02a) flashnum = MZ2_WIDOW_BLASTER_0; else flashnum = MZ2_WIDOW_BLASTER_100 + self->s.frame - FRAME_fired03; G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start); PredictAim (self->enemy, start, 1000, true, ((random()*0.1)-0.05), forward, NULL); // clamp it to within 10 degrees of the aiming angle (where she's facing) vectoangles2 (forward, angles); // give me 100 -> -70 aim_angle = 100 - (10*(flashnum-MZ2_WIDOW_BLASTER_100)); if (aim_angle <= 0) aim_angle += 360; target_angle = self->s.angles[YAW] - angles[YAW]; if (target_angle <= 0) target_angle += 360; error = aim_angle - target_angle; // positive error is to entity's left, aka positive direction in engine // unfortunately, I decided that for the aim_angle, positive was right. *sigh* if (error > VARIANCE) { angles[YAW] = (self->s.angles[YAW] - aim_angle) + VARIANCE; AngleVectors (angles, forward, NULL, NULL); } else if (error < -VARIANCE) { angles[YAW] = (self->s.angles[YAW] - aim_angle) - VARIANCE; AngleVectors (angles, forward, NULL, NULL); } monster_fire_blaster2 (self, start, forward, BLASTER2_DAMAGE*widow_damage_multiplier, 1000, flashnum, effect); } else if ((self->s.frame >= FRAME_run01) && (self->s.frame <= FRAME_run08)) { flashnum = MZ2_WIDOW_RUN_1 + self->s.frame - FRAME_run01; G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start); VectorSubtract (self->enemy->s.origin, start, target); target[2] += self->enemy->viewheight; monster_fire_blaster2 (self, start, target, BLASTER2_DAMAGE*widow_damage_multiplier, 1000, flashnum, effect); } }
// ==================== // ==================== int stalker_do_pounce(edict_t *self, vec3_t dest) { vec3_t forward, right; vec3_t dist; vec_t length; vec3_t jumpAngles; vec3_t jumpLZ; float velocity = 400.1; trace_t trace; int preferHighJump; // don't pounce when we're on the ceiling if(STALKER_ON_CEILING(self)) return false; if(!stalker_check_lz (self, self->enemy, dest)) return false; VectorSubtract(dest, self->s.origin, dist); // make sure we're pointing in that direction 15deg margin of error. vectoangles2 (dist, jumpAngles); if(abs(jumpAngles[YAW] - self->s.angles[YAW]) > 45) return false; // not facing the player... self->ideal_yaw = jumpAngles[YAW]; M_ChangeYaw(self); length = VectorLength(dist); if(length > 450) return false; // can't jump that far... VectorCopy(dest, jumpLZ); preferHighJump = 0; // if we're having to jump up a distance, jump a little too high to compensate. if(dist[2] >= 32.0) { preferHighJump = 1; jumpLZ[2] += 32; } trace = gi.trace (self->s.origin, vec3_origin, vec3_origin, dest, self, MASK_MONSTERSOLID); if((trace.fraction < 1) && (trace.ent != self->enemy)) { // gi.dprintf("prefer high jump angle\n"); preferHighJump = 1; } // find a valid angle/velocity combination while(velocity <= 800) { calcJumpAngle(self->s.origin, jumpLZ, velocity, jumpAngles); if((!_isnan(jumpAngles[0])) || (!_isnan(jumpAngles[1]))) break; velocity+=200; }; if(!preferHighJump && (!_isnan(jumpAngles[0])) ) { AngleVectors (self->s.angles, forward, right, NULL); VectorNormalize ( forward ) ; VectorScale( forward, velocity * cos(DEG2RAD(jumpAngles[0])), self->velocity); self->velocity[2] = velocity * sin(DEG2RAD(jumpAngles[0])) + (0.5 * sv_gravity->value * FRAMETIME); // gi.dprintf(" pouncing! %0.1f,%0.1f (%0.1f) --> %0.1f, %0.1f, %0.1f\n", // jumpAngles[0], jumpAngles[1], jumpAngles[0], // self->velocity[0], self->velocity[1], self->velocity[2]); return 1; } if(!_isnan(jumpAngles[1])) { AngleVectors (self->s.angles, forward, right, NULL); VectorNormalize ( forward ) ; VectorScale( forward, velocity * cos(DEG2RAD(jumpAngles[1])), self->velocity); self->velocity[2] = velocity * sin(DEG2RAD(jumpAngles[1])) + (0.5 * sv_gravity->value * FRAMETIME); // gi.dprintf(" pouncing! %0.1f,%0.1f (%0.1f) --> %0.1f, %0.1f, %0.1f\n", // jumpAngles[0], jumpAngles[1], jumpAngles[1], // self->velocity[0], self->velocity[1], self->velocity[2]); return 1; } // gi.dprintf(" nan\n"); return 0; }
void CL_ParseTEnt (void) { int32_t type; vec3_t pos, pos2, dir; explosion_t *ex; int32_t cnt; int32_t color; int32_t r, i; int32_t ent; int32_t magnitude; type = MSG_ReadByte (&net_message); switch (type) { case TE_BLOOD: // bullet hitting flesh MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); // Psychospaz's enhanced particle code CL_BloodHit (pos, dir); break; case TE_GUNSHOT: // bullet hitting wall case TE_SPARKS: case TE_BULLET_SPARKS: MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); // Psychospaz's enhanced particle code if (type == TE_BULLET_SPARKS) VectorScale(dir, 2, dir); { vec3_t color = { 255, 125, 10 }; CL_ParticleEffectSparks (pos, dir, color, (type == TE_GUNSHOT)? 5 : 10); } if (type != TE_SPARKS) { CL_GunSmokeEffect (pos, dir); if (type == TE_GUNSHOT || type == TE_BULLET_SPARKS) CL_ParticleBulletDecal(pos, dir, 2.5); // impact sound cnt = rand()&15; if (cnt == 1) S_StartSound (pos, 0, 0, clMedia.sfx_ric[0], 1, ATTN_NORM, 0); else if (cnt == 2) S_StartSound (pos, 0, 0, clMedia.sfx_ric[1], 1, ATTN_NORM, 0); else if (cnt == 3) S_StartSound (pos, 0, 0, clMedia.sfx_ric[2], 1, ATTN_NORM, 0); } break; case TE_SHOTGUN: // bullet hitting wall MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); // Psychospaz's enhanced particle code CL_GunSmokeEffect (pos, dir); CL_ParticleBulletDecal(pos, dir, 2.8); { vec3_t color = { 200, 100, 10 }; CL_ParticleEffectSparks (pos, dir, color, 8); } break; case TE_SCREEN_SPARKS: case TE_SHIELD_SPARKS: MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); if (type == TE_SCREEN_SPARKS) CL_ParticleEffect (pos, dir, 0xd0, 40); else CL_ParticleEffect (pos, dir, 0xb0, 40); //FIXME : replace or remove this sound S_StartSound (pos, 0, 0, clMedia.sfx_lashit, 1, ATTN_NORM, 0); break; case TE_SPLASH: // bullet hitting water cnt = MSG_ReadByte (&net_message); cnt = min(cnt, 40); // cap at 40 MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); r = MSG_ReadByte (&net_message); if (r > 6) color = 0x00; else color = splash_color[r]; // Psychospaz's enhanced particle code if (r == SPLASH_SPARKS) { CL_ParticleEffectSplashSpark (pos, dir, color, cnt); r = rand() & 3; if (r == 0) S_StartSound (pos, 0, 0, clMedia.sfx_spark[0], 1, ATTN_STATIC, 0); else if (r == 1) S_StartSound (pos, 0, 0, clMedia.sfx_spark[1], 1, ATTN_STATIC, 0); else S_StartSound (pos, 0, 0, clMedia.sfx_spark[2], 1, ATTN_STATIC, 0); } else { CL_ParticleEffectSplash (pos, dir, color, cnt); } break; case TE_LASER_SPARKS: cnt = MSG_ReadByte (&net_message); MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); color = MSG_ReadByte (&net_message); CL_ParticleEffect2 (pos, dir, color, cnt); break; case TE_RAILTRAIL: // railgun effect MSG_ReadPos (&net_message, pos); MSG_ReadPos (&net_message, pos2); CL_RailTrail (pos, pos2, false); S_StartSound (pos2, 0, 0, clMedia.sfx_railg, 1, ATTN_NORM, 0); break; // 12/23/2001 - red railgun trail case TE_RAILTRAIL2: // red railgun effect MSG_ReadPos (&net_message, pos); MSG_ReadPos (&net_message, pos2); CL_RailTrail (pos, pos2, true); S_StartSound (pos2, 0, 0, clMedia.sfx_railg, 1, ATTN_NORM, 0); break; case TE_EXPLOSION2: case TE_GRENADE_EXPLOSION: case TE_GRENADE_EXPLOSION_WATER: MSG_ReadPos (&net_message, pos); ex = CL_AllocExplosion (); VectorCopy (pos, ex->ent.origin); ex->type = ex_poly; ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW; // noshadow flag ex->start = cl.frame.servertime - 100; ex->light = 350; ex->lightcolor[0] = 1.0; ex->lightcolor[1] = 0.5; ex->lightcolor[2] = 0.5; ex->ent.model = clMedia.mod_explo; ex->frames = 19; ex->baseframe = 30; ex->ent.angles[1] = rand() % 360; CL_Explosion_Sparks (pos, 16, 128); if (type != TE_EXPLOSION2) CL_Explosion_Decal (pos, 50, particle_burnmark); if (type == TE_GRENADE_EXPLOSION_WATER) S_StartSound (pos, 0, 0, clMedia.sfx_watrexp, 1, ATTN_NORM, 0); else S_StartSound (pos, 0, 0, clMedia.sfx_grenexp, 1, ATTN_NORM, 0); break; // RAFAEL case TE_PLASMA_EXPLOSION: MSG_ReadPos (&net_message, pos); ex = CL_AllocExplosion (); VectorCopy (pos, ex->ent.origin); ex->type = ex_poly; ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW; // noshadow flag ex->start = cl.frame.servertime - 100; ex->light = 350; ex->lightcolor[0] = 1.0; ex->lightcolor[1] = 0.5; ex->lightcolor[2] = 0.5; ex->ent.angles[1] = rand() % 360; ex->ent.model = clMedia.mod_explo; if (frand() < 0.5) ex->baseframe = 15; ex->frames = 15; CL_Explosion_Sparks (pos, 16, 128); CL_Explosion_Decal (pos, 50, particle_burnmark); if (cl_plasma_explo_sound->value) S_StartSound (pos, 0, 0, clMedia.sfx_plasexp, 1, ATTN_NORM, 0); else S_StartSound (pos, 0, 0, clMedia.sfx_rockexp, 1, ATTN_NORM, 0); break; case TE_EXPLOSION1_BIG: // PMM MSG_ReadPos (&net_message, pos); ex = CL_AllocExplosion (); VectorCopy (pos, ex->ent.origin); ex->type = ex_poly; ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW; // noshadow flag ex->start = cl.frame.servertime - 100; ex->light = 350; ex->lightcolor[0] = 1.0; ex->lightcolor[1] = 0.5; ex->lightcolor[2] = 0.5; ex->ent.angles[1] = rand() % 360; ex->ent.model = clMedia.mod_explo_big; if (frand() < 0.5) ex->baseframe = 15; ex->frames = 15; CL_Explosion_Sparks (pos, 48, 128); S_StartSound (pos, 0, 0, clMedia.sfx_rockexp, 1, ATTN_NORM, 0); break; case TE_EXPLOSION1_NP: // PMM MSG_ReadPos (&net_message, pos); ex = CL_AllocExplosion (); VectorCopy (pos, ex->ent.origin); ex->type = ex_poly; ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW; // noshadow flag ex->start = cl.frame.servertime - 100; ex->light = 350; ex->lightcolor[0] = 1.0; ex->lightcolor[1] = 0.5; ex->lightcolor[2] = 0.5; ex->ent.angles[1] = rand() % 360; ex->ent.model = clMedia.mod_explo; if (frand() < 0.5) ex->baseframe = 15; ex->frames = 15; CL_Explosion_Sparks (pos, 10, 128); S_StartSound (pos, 0, 0, clMedia.sfx_grenexp, 1, ATTN_NORM, 0); break; case TE_EXPLOSION1: case TE_PLAIN_EXPLOSION: case TE_ROCKET_EXPLOSION: case TE_ROCKET_EXPLOSION_WATER: MSG_ReadPos (&net_message, pos); ex = CL_AllocExplosion (); VectorCopy (pos, ex->ent.origin); ex->type = ex_poly; ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW; // noshadow flag ex->start = cl.frame.servertime - 100; ex->light = 350; ex->lightcolor[0] = 1.0; ex->lightcolor[1] = 0.5; ex->lightcolor[2] = 0.5; ex->ent.angles[1] = rand() % 360; ex->ent.model = clMedia.mod_explo; if (frand() < 0.5) ex->baseframe = 15; ex->frames = 15; CL_Explosion_Sparks (pos, 16, 128); if (type == TE_ROCKET_EXPLOSION || type == TE_ROCKET_EXPLOSION_WATER) CL_Explosion_Decal (pos, 50, particle_burnmark); if (type == TE_ROCKET_EXPLOSION_WATER) S_StartSound (pos, 0, 0, clMedia.sfx_watrexp, 1, ATTN_NORM, 0); else S_StartSound (pos, 0, 0, clMedia.sfx_rockexp, 1, ATTN_NORM, 0); break; case TE_BFG_EXPLOSION: MSG_ReadPos (&net_message, pos); ex = CL_AllocExplosion (); VectorCopy (pos, ex->ent.origin); ex->type = ex_poly; ex->ent.flags |= RF_FULLBRIGHT; ex->start = cl.frame.servertime - 100; ex->light = 350; ex->lightcolor[0] = 0.0; ex->lightcolor[1] = 1.0; ex->lightcolor[2] = 0.0; ex->ent.model = clMedia.mod_bfg_explo; ex->ent.flags |= RF_TRANSLUCENT | RF_TRANS_ADDITIVE; ex->ent.alpha = 0.30; ex->frames = 4; break; case TE_BFG_BIGEXPLOSION: MSG_ReadPos (&net_message, pos); CL_BFGExplosionParticles (pos); CL_Explosion_Decal (pos, 75, particle_bfgmark); break; case TE_BFG_LASER: CL_ParseLaser (0xd0d1d2d3); break; case TE_BUBBLETRAIL: MSG_ReadPos (&net_message, pos); MSG_ReadPos (&net_message, pos2); CL_BubbleTrail (pos, pos2); break; case TE_PARASITE_ATTACK: case TE_MEDIC_CABLE_ATTACK: ent = CL_ParseBeam (clMedia.mod_parasite_segment); break; case TE_BOSSTPORT: // boss teleporting to station MSG_ReadPos (&net_message, pos); CL_BigTeleportParticles (pos); S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0); break; case TE_GRAPPLE_CABLE: ent = CL_ParseBeam2 (clMedia.mod_grapple_cable); break; // RAFAEL case TE_WELDING_SPARKS: cnt = MSG_ReadByte (&net_message); MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); color = MSG_ReadByte (&net_message); // Psychospaz's enhanced particle code { vec3_t sparkcolor = {color8red(color), color8green(color), color8blue(color)}; CL_ParticleEffectSparks (pos, dir, sparkcolor, 40); } ex = CL_AllocExplosion (); VectorCopy (pos, ex->ent.origin); ex->type = ex_flash; // note to self // we need a better no draw flag ex->ent.flags |= RF_BEAM; ex->start = cl.frame.servertime - 0.1; ex->light = 100 + (rand()%75); ex->lightcolor[0] = 1.0; ex->lightcolor[1] = 1.0; ex->lightcolor[2] = 0.3; ex->ent.model = clMedia.mod_flash; ex->frames = 2; break; case TE_GREENBLOOD: MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); // Psychospaz's enhanced particle code CL_GreenBloodHit (pos, dir); break; // RAFAEL case TE_TUNNEL_SPARKS: cnt = MSG_ReadByte (&net_message); MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); color = MSG_ReadByte (&net_message); CL_ParticleEffect3 (pos, dir, color, cnt); break; //============= //PGM // PMM -following code integrated for flechette (different color) case TE_BLASTER: // blaster hitting wall case TE_BLASTER2: // green blaster hitting wall case TE_BLUEHYPERBLASTER: // blue blaster hitting wall case TE_REDBLASTER: // red blaster hitting wall case TE_FLECHETTE: // flechette hitting wall MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); ex = CL_AllocExplosion (); VectorCopy (pos, ex->ent.origin); ex->ent.angles[0] = acos(dir[2])/M_PI*180; if (dir[0]) // PMM - fixed to correct for pitch of 0 ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180; else if (dir[1] > 0) ex->ent.angles[1] = 90; else if (dir[1] < 0) ex->ent.angles[1] = 270; else ex->ent.angles[1] = 0; ex->type = ex_misc; ex->ent.flags |= RF_FULLBRIGHT|RF_TRANSLUCENT|RF_NOSHADOW; // no shadow on these if (type == TE_BLASTER2) ex->ent.skinnum = 1; else if (type == TE_REDBLASTER) ex->ent.skinnum = 3; else if (type == TE_FLECHETTE || type == TE_BLUEHYPERBLASTER) ex->ent.skinnum = 2; else // TE_BLASTER ex->ent.skinnum = 0; ex->start = cl.frame.servertime - 100; ex->light = 150; if (type == TE_BLASTER2) { ex->lightcolor[0] = 0.15; ex->lightcolor[1] = 1; ex->lightcolor[2] = 0.15; } else if (type == TE_BLUEHYPERBLASTER) { ex->lightcolor[0] = 0.19; ex->lightcolor[1] = 0.41; ex->lightcolor[2] = 0.75; } else if (type == TE_REDBLASTER) { ex->lightcolor[0] = 0.75; ex->lightcolor[1] = 0.41; ex->lightcolor[2] = 0.19; } else if (type == TE_FLECHETTE) { ex->lightcolor[0] = 0.39; ex->lightcolor[1] = 0.61; ex->lightcolor[2] = 0.75; } else { // TE_BLASTER ex->lightcolor[0] = 1; ex->lightcolor[1] = 1; ex->lightcolor[2] = 0; } ex->ent.model = clMedia.mod_explode; ex->frames = 4; // Psychospaz's enhanced particle code { int32_t red, green, blue, numparts; float partsize = 4; numparts = (32 / max(cl_particle_scale->value/2, 1)); if (type == TE_BLASTER2) { CL_BlasterParticles (pos, dir, numparts, partsize, 50, 235, 50, -10, 0, -10); red=50; green=235; blue=50; } else if (type == TE_BLUEHYPERBLASTER) { CL_BlasterParticles (pos, dir, numparts, partsize, 50, 50, 235, -10, 0, -10); red=50; green=50; blue=235; } else if (type == TE_REDBLASTER) { CL_BlasterParticles (pos, dir, numparts, partsize, 235, 50, 50, 0, -90, -30); red=235; green=50; blue=50; } else if (type == TE_FLECHETTE) { CL_BlasterParticles (pos, dir, numparts, partsize, 100, 100, 195, -10, 0, -10); red=100; green=100; blue=195; } else { // TE_BLASTER CL_BlasterParticles (pos, dir, numparts, partsize, 255, 150, 50, 0, -90, -30); // was 40 red=255; green=150; blue=50; } CL_ParticleBlasterDecal(pos, dir, 10, red, green, blue); } S_StartSound (pos, 0, 0, clMedia.sfx_lashit, 1, ATTN_NORM, 0); break; // shockwave impact effect case TE_SHOCKSPLASH: MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); // Spawn 5 rings for (i = 0; i < 5; i++) { ex = CL_AllocExplosion (); VectorMA (pos, 16.0*(i+1), dir, ex->ent.origin); vectoangles2(dir, ex->ent.angles); //VectorCopy (dir, ex->ent.angles); ex->type = ex_poly2; ex->ent.flags |= RF_FULLBRIGHT|RF_TRANSLUCENT|RF_NOSHADOW; ex->start = cl.frame.servertime - 100; ex->light = 75; ex->lightcolor[0] = 0.39; ex->lightcolor[1] = 0.61; ex->lightcolor[2] = 0.75; ex->ent.model = clMedia.mod_shocksplash; ex->ent.alpha = 0.70; ex->baseframe = 4-i; ex->frames = 4+i; } S_StartSound (pos, 0, 0, clMedia.sfx_shockhit, 1, ATTN_NONE, 0); break; case TE_LIGHTNING: // Psychospaz's enhanced particle code ent = CL_ParseLightning (); S_StartSound (NULL, ent, CHAN_WEAPON, clMedia.sfx_lightning, 1, ATTN_NORM, 0); break; case TE_DEBUGTRAIL: MSG_ReadPos (&net_message, pos); MSG_ReadPos (&net_message, pos2); CL_DebugTrail (pos, pos2); break; case TE_FLASHLIGHT: MSG_ReadPos(&net_message, pos); ent = MSG_ReadShort(&net_message); CL_Flashlight(ent, pos); break; case TE_FORCEWALL: MSG_ReadPos(&net_message, pos); MSG_ReadPos(&net_message, pos2); color = MSG_ReadByte (&net_message); CL_ForceWall(pos, pos2, color); break; case TE_HEATBEAM: ent = CL_ParsePlayerBeam (clMedia.mod_heatbeam); break; case TE_MONSTER_HEATBEAM: ent = CL_ParsePlayerBeam (clMedia.mod_monster_heatbeam); break; case TE_HEATBEAM_SPARKS: cnt = 50; MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); r = 8; magnitude = 60; CL_ParticleSteamEffect (pos, dir, 240, 240, 240, -20, -20, -20, cnt, magnitude); S_StartSound (pos, 0, 0, clMedia.sfx_lashit, 1, ATTN_NORM, 0); break; case TE_HEATBEAM_STEAM: cnt = 20; MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); magnitude = 60; CL_ParticleSteamEffect (pos, dir, 255, 150, 50, 0, -90, -30, cnt, magnitude); CL_ParticlePlasmaBeamDecal (pos, dir, 10); // added burnmark S_StartSound (pos, 0, 0, clMedia.sfx_lashit, 1, ATTN_NORM, 0); break; case TE_STEAM: CL_ParseSteam(); break; case TE_BUBBLETRAIL2: cnt = 3; // was 8 MSG_ReadPos (&net_message, pos); MSG_ReadPos (&net_message, pos2); CL_BubbleTrail2 (pos, pos2, cnt); S_StartSound (pos, 0, 0, clMedia.sfx_lashit, 1, ATTN_NORM, 0); break; case TE_MOREBLOOD: MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); // Psychospaz's enhanced particle code CL_BloodHit (pos, dir); CL_BloodHit (pos, dir); break; case TE_CHAINFIST_SMOKE: dir[0]=0; dir[1]=0; dir[2]=1; MSG_ReadPos(&net_message, pos); // Psychospaz's enhanced particle code CL_ParticleSmokeEffect (pos, dir, 8); break; case TE_ELECTRIC_SPARKS: MSG_ReadPos (&net_message, pos); MSG_ReadDir (&net_message, dir); // new blue electric sparks CL_ElectricParticles (pos, dir, 40); //FIXME : replace or remove this sound S_StartSound (pos, 0, 0, clMedia.sfx_lashit, 1, ATTN_NORM, 0); break; case TE_TRACKER_EXPLOSION: MSG_ReadPos (&net_message, pos); CL_ColorFlash (pos, 0, 150, -1, -1, -1); // CL_ColorExplosionParticles (pos, 0, 1); CL_Tracker_Explode (pos); CL_Explosion_Decal (pos, 14, particle_trackermark); S_StartSound (pos, 0, 0, clMedia.sfx_disrexp, 1, ATTN_NORM, 0); break; case TE_TELEPORT_EFFECT: case TE_DBALL_GOAL: MSG_ReadPos (&net_message, pos); CL_TeleportParticles (pos); break; case TE_WIDOWBEAMOUT: CL_ParseWidow (); break; case TE_NUKEBLAST: CL_ParseNuke (); break; case TE_WIDOWSPLASH: MSG_ReadPos (&net_message, pos); CL_WidowSplash (pos); break; //PGM //============== default: Com_Error (ERR_DROP, "CL_ParseTEnt: bad type"); } }
void Widow2Beam(edict_t *self) { vec3_t forward, right, target; vec3_t start, targ_angles, vec; int flashnum; if (!self) { return; } if ((!self->enemy) || (!self->enemy->inuse)) { return; } AngleVectors(self->s.angles, forward, right, NULL); if ((self->s.frame >= FRAME_fireb05) && (self->s.frame <= FRAME_fireb09)) { /* regular beam attack */ Widow2SaveBeamTarget(self); flashnum = MZ2_WIDOW2_BEAMER_1 + self->s.frame - FRAME_fireb05; G_ProjectSource(self->s.origin, monster_flash_offset[flashnum], forward, right, start); VectorCopy(self->pos2, target); target[2] += self->enemy->viewheight - 10; VectorSubtract(target, start, forward); VectorNormalize(forward); monster_fire_heat(self, start, forward, vec3_origin, 10, 50, flashnum); } else if ((self->s.frame >= FRAME_spawn04) && (self->s.frame <= FRAME_spawn14)) { /* sweep */ flashnum = MZ2_WIDOW2_BEAM_SWEEP_1 + self->s.frame - FRAME_spawn04; G_ProjectSource(self->s.origin, monster_flash_offset[flashnum], forward, right, start); VectorSubtract(self->enemy->s.origin, start, target); vectoangles2(target, targ_angles); VectorCopy(self->s.angles, vec); vec[PITCH] += targ_angles[PITCH]; vec[YAW] -= sweep_angles[flashnum - MZ2_WIDOW2_BEAM_SWEEP_1]; AngleVectors(vec, forward, NULL, NULL); monster_fire_heat(self, start, forward, vec3_origin, 10, 50, flashnum); } else { Widow2SaveBeamTarget(self); G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_WIDOW2_BEAMER_1], forward, right, start); VectorCopy(self->pos2, target); target[2] += self->enemy->viewheight - 10; VectorSubtract(target, start, forward); VectorNormalize(forward); monster_fire_heat(self, start, forward, vec3_origin, 10, 50, 0); } }
void hunter_think(edict_t *self) { edict_t *owner; vec3_t dir, ang; if (!self) { return; } /* if we've exited the level, just remove ourselves. */ if (level.intermissiontime) { sphere_think_explode(self); return; } owner = self->owner; if (!owner && !(self->spawnflags & SPHERE_DOPPLEGANGER)) { G_FreeEdict(self); return; } if (owner) { self->ideal_yaw = owner->s.angles[YAW]; } else if (self->enemy) /* fired by doppleganger */ { VectorSubtract(self->enemy->s.origin, self->s.origin, dir); vectoangles2(dir, ang); self->ideal_yaw = ang[YAW]; } M_ChangeYaw(self); if (self->enemy) { sphere_chase(self, 0); /* deal with sam raimi cam */ if (owner && (owner->flags & FL_SAM_RAIMI)) { if (self->inuse) { owner->movetype = MOVETYPE_FLYMISSILE; LookAtKiller(owner, self, self->enemy); /* owner is flying with us, move him too */ owner->movetype = MOVETYPE_FLYMISSILE; owner->viewheight = self->s.origin[2] - owner->s.origin[2]; VectorCopy(self->s.origin, owner->s.origin); VectorCopy(self->velocity, owner->velocity); VectorClear(owner->mins); VectorClear(owner->maxs); gi.linkentity(owner); } else /* sphere timed out */ { VectorClear(owner->velocity); owner->movetype = MOVETYPE_NONE; gi.linkentity(owner); } } } else { sphere_fly(self); } if (self->inuse) { self->nextthink = level.time + 0.1; } }
void sphere_chase(edict_t *self, int stupidChase) { vec3_t dest; vec3_t dir; float dist; if (!self) { return; } if ((level.time >= self->wait) || (self->enemy && (self->enemy->health < 1))) { sphere_think_explode(self); return; } VectorCopy(self->enemy->s.origin, dest); if (self->enemy->client) { dest[2] += self->enemy->viewheight; } if (visible(self, self->enemy) || stupidChase) { /* if moving, hunter sphere uses active sound */ if (!stupidChase) { self->s.sound = gi.soundindex("spheres/h_active.wav"); } VectorSubtract(dest, self->s.origin, dir); VectorNormalize(dir); vectoangles2(dir, self->s.angles); VectorScale(dir, 500, self->velocity); VectorCopy(dest, self->monsterinfo.saved_goal); } else if (VectorCompare(self->monsterinfo.saved_goal, vec3_origin)) { VectorSubtract(self->enemy->s.origin, self->s.origin, dir); vectoangles2(dir, self->s.angles); /* if lurking, hunter sphere uses lurking sound */ self->s.sound = gi.soundindex("spheres/h_lurk.wav"); VectorClear(self->velocity); } else { VectorSubtract(self->monsterinfo.saved_goal, self->s.origin, dir); dist = VectorNormalize(dir); if (dist > 1) { vectoangles2(dir, self->s.angles); if (dist > 500) { VectorScale(dir, 500, self->velocity); } else if (dist < 20) { VectorScale(dir, (dist / FRAMETIME), self->velocity); } else { VectorScale(dir, dist, self->velocity); } /* if moving, hunter sphere uses active sound */ if (!stupidChase) { self->s.sound = gi.soundindex("spheres/h_active.wav"); } } else { VectorSubtract(self->enemy->s.origin, self->s.origin, dir); vectoangles2(dir, self->s.angles); /* if not moving, hunter sphere uses lurk sound */ if (!stupidChase) { self->s.sound = gi.soundindex("spheres/h_lurk.wav"); } VectorClear(self->velocity); } } }
void Widow2Beam (edict_t *self) { vec3_t forward, right, target; vec3_t start, targ_angles, vec; int flashnum; if ((!self->enemy) || (!self->enemy->inuse)) return; AngleVectors (self->s.angles, forward, right, NULL); if ((self->s.frame >= FRAME_fireb05) && (self->s.frame <= FRAME_fireb09)) { // regular beam attack Widow2SaveBeamTarget(self); flashnum = MZ2_WIDOW2_BEAMER_1 + self->s.frame - FRAME_fireb05; G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start); VectorCopy (self->pos2, target); target[2] += self->enemy->viewheight-10; VectorSubtract (target, start, forward); VectorNormalize (forward); monster_fire_heat (self, start, forward, vec3_origin, 10, 50, flashnum); } else if ((self->s.frame >= FRAME_spawn04) && (self->s.frame <= FRAME_spawn14)) { // sweep flashnum = MZ2_WIDOW2_BEAM_SWEEP_1 + self->s.frame - FRAME_spawn04; G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start); VectorSubtract (self->enemy->s.origin, start, target); vectoangles2 (target, targ_angles); VectorCopy (self->s.angles, vec); vec[PITCH] += targ_angles[PITCH]; vec[YAW] -= sweep_angles[flashnum-MZ2_WIDOW2_BEAM_SWEEP_1]; AngleVectors (vec, forward, NULL, NULL); monster_fire_heat (self, start, forward, vec3_origin, 10, 50, flashnum); /* if (self->s.frame == FRAME_spawn04) { VectorMA (start, 1024, forward, debugend); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_DEBUGTRAIL); gi.WritePosition (start); gi.WritePosition (debugend); gi.multicast (start, MULTICAST_ALL); drawbbox (self); self->monsterinfo.aiflags |= AI_HOLD_FRAME|AI_MANUAL_STEERING; } */ } else { // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("bad fire frame for widow2 beam -- tell me you saw this!\n"); Widow2SaveBeamTarget(self); G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_WIDOW2_BEAMER_1], forward, right, start); VectorCopy (self->pos2, target); target[2] += self->enemy->viewheight-10; VectorSubtract (target, start, forward); VectorNormalize (forward); monster_fire_heat (self, start, forward, vec3_origin, 10, 50, 0); } }
// ================= // ================= void hunter_think (edict_t *self) { edict_t *owner; vec3_t dir, ang; // if we've exited the level, just remove ourselves. if (level.intermissiontime) { sphere_think_explode(self); return; } owner = self->owner; if(!owner && !(self->spawnflags & SPHERE_DOPPLEGANGER)) { // gi.dprintf("think: no owner\n"); G_FreeEdict(self); return; } if(owner) self->ideal_yaw = owner->s.angles[YAW]; else if(self->enemy) // fired by doppleganger { VectorSubtract(self->enemy->s.origin, self->s.origin, dir); vectoangles2(dir, ang); self->ideal_yaw = ang[YAW]; } M_ChangeYaw(self); // if(level.time - self->timestamp > 1) // { // gi.sound (self, CHAN_VOICE, gi.soundindex ("powerup/hsphere.wav"), 0.5, ATTN_NORM, 0); // self->timestamp = level.time; // } if(self->enemy) { sphere_chase (self, 0); // deal with sam raimi cam if(owner && (owner->flags & FL_SAM_RAIMI)) { if(self->inuse) { owner->movetype = MOVETYPE_FLYMISSILE; // VectorCopy(self->s.angles, owner->s.angles); // VectorCopy(self->s.angles, owner->client->v_angle); LookAtKiller (owner, self, self->enemy); // owner->viewheight = 22; // owner->client->v_angle[YAW]+=5; // owner is flying with us, move him too owner->movetype = MOVETYPE_FLYMISSILE; owner->viewheight = self->s.origin[2] - owner->s.origin[2]; // VectorCopy(self->s.angles, owner->s.angles); // VectorCopy(self->s.angles, owner->client->v_angle); VectorCopy(self->s.origin, owner->s.origin); VectorCopy(self->velocity, owner->velocity); VectorClear(owner->mins); VectorClear(owner->maxs); gi.linkentity(owner); } else // sphere timed out { VectorClear(owner->velocity); owner->movetype = MOVETYPE_NONE; gi.linkentity(owner); } } } else { // self->ideal_yaw+=3; // M_ChangeYaw (self); sphere_fly (self); } if(self->inuse) self->nextthink = level.time + 0.1; }
void WidowBlaster (edict_t *self) { vec3_t forward, right, target, vec, targ_angles; vec3_t start, end; int flashnum; int effect; if (!self->enemy) return; shotsfired++; if (!(shotsfired % 4)) effect = EF_BLASTER; else effect = 0; AngleVectors (self->s.angles, forward, right, NULL); if ((self->s.frame >= FRAME_spawn05) && (self->s.frame <= FRAME_spawn13)) { // sweep flashnum = MZ2_WIDOW_BLASTER_SWEEP1 + self->s.frame - FRAME_spawn05; G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start); VectorCopy(self->enemy->s.origin, end); // Lazarus fog reduction of accuracy if(self->monsterinfo.visibility < FOG_CANSEEGOOD) { end[0] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility); end[1] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility); end[2] += crandom() * 320 * (FOG_CANSEEGOOD - self->monsterinfo.visibility); } VectorSubtract (end, start, target); vectoangles2 (target, targ_angles); VectorCopy (self->s.angles, vec); vec[PITCH] += targ_angles[PITCH]; vec[YAW] -= sweep_angles[flashnum-MZ2_WIDOW_BLASTER_SWEEP1]; AngleVectors (vec, forward, NULL, NULL); // monster_fire_blaster (self, start, forward, BLASTER2_DAMAGE*widow_damage_multiplier, 1000, flashnum, (effect!=0)?(effect|EF_TRACKER):0, BLASTER_GREEN); monster_fire_blaster2 (self, start, forward, BLASTER2_DAMAGE*widow_damage_multiplier, 1000, flashnum, effect); /* if (self->s.frame == FRAME_spawn13) { VectorMA (start, 1024, forward, debugend); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_DEBUGTRAIL); gi.WritePosition (start); gi.WritePosition (debugend); gi.multicast (start, MULTICAST_ALL); drawbbox (self); self->monsterinfo.aiflags |= AI_HOLD_FRAME|AI_MANUAL_STEERING; } */ } else if ((self->s.frame >= FRAME_fired02a) && (self->s.frame <= FRAME_fired20)) { vec3_t angles; float aim_angle, target_angle; float error; self->monsterinfo.aiflags |= AI_MANUAL_STEERING; self->monsterinfo.nextframe = WidowTorso (self); if (!self->monsterinfo.nextframe) self->monsterinfo.nextframe = self->s.frame; // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("%d\n", self->monsterinfo.nextframe); if (self->s.frame == FRAME_fired02a) flashnum = MZ2_WIDOW_BLASTER_0; else flashnum = MZ2_WIDOW_BLASTER_100 + self->s.frame - FRAME_fired03; G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start); PredictAim (self->enemy, start, 1000, true, ((random()*0.1)-0.05), forward, NULL); // clamp it to within 10 degrees of the aiming angle (where she's facing) vectoangles2 (forward, angles); // give me 100 -> -70 aim_angle = 100 - (10*(flashnum-MZ2_WIDOW_BLASTER_100)); if (aim_angle <= 0) aim_angle += 360; target_angle = self->s.angles[YAW] - angles[YAW]; if (target_angle <= 0) target_angle += 360; error = aim_angle - target_angle; // positive error is to entity's left, aka positive direction in engine // unfortunately, I decided that for the aim_angle, positive was right. *sigh* if (error > VARIANCE) { // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("angle %2.2f (really %2.2f) (%2.2f off of %2.2f) corrected to", target_angle, angles[YAW], error, aim_angle); angles[YAW] = (self->s.angles[YAW] - aim_angle) + VARIANCE; // if ((g_showlogic) && (g_showlogic->value)) // { // if (angles[YAW] <= 0) // angles[YAW] += 360; // gi.dprintf (" %2.2f\n", angles[YAW]); // } AngleVectors (angles, forward, NULL, NULL); } else if (error < -VARIANCE) { // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("angle %2.2f (really %2.2f) (%2.2f off of %2.2f) corrected to", target_angle, angles[YAW], error, aim_angle); angles[YAW] = (self->s.angles[YAW] - aim_angle) - VARIANCE; // if ((g_showlogic) && (g_showlogic->value)) // { // if (angles[YAW] <= 0) // angles[YAW] += 360; // gi.dprintf (" %2.2f\n", angles[YAW]); // } AngleVectors (angles, forward, NULL, NULL); } // gi.dprintf ("%2.2f - %2.2f - %2.2f - %2.2f\n", aim_angle, self->s.angles[YAW] - angles[YAW], target_angle, error); // gi.dprintf ("%2.2f - %2.2f - %2.2f\n", angles[YAW], aim_angle, self->s.angles[YAW]); /* if (self->s.frame == FRAME_fired20) { VectorMA (start, 512, forward, debugend); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_DEBUGTRAIL); gi.WritePosition (start); gi.WritePosition (forward); gi.multicast (start, MULTICAST_ALL); drawbbox (self); self->monsterinfo.aiflags |= AI_HOLD_FRAME; self->monsterinfo.nextframe = FRAME_fired20; self->monsterinfo.aiflags |= AI_MANUAL_STEERING; } */ /* if (!(self->plat2flags % 3)) effect = EF_HYPERBLASTER; else effect = 0; self->plat2flags ++; */ // monster_fire_blaster (self, start, forward, BLASTER2_DAMAGE*widow_damage_multiplier, 1000, flashnum, (effect!=0)?(effect|EF_TRACKER):0, BLASTER_GREEN); monster_fire_blaster2 (self, start, forward, BLASTER2_DAMAGE*widow_damage_multiplier, 1000, flashnum, effect); } else if ((self->s.frame >= FRAME_run01) && (self->s.frame <= FRAME_run08)) { flashnum = MZ2_WIDOW_RUN_1 + self->s.frame - FRAME_run01; G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start); VectorCopy(self->enemy->s.origin, end); // Lazarus fog reduction of accuracy if(self->monsterinfo.visibility < FOG_CANSEEGOOD) { end[0] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility); end[1] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility); end[2] += crandom() * 320 * (FOG_CANSEEGOOD - self->monsterinfo.visibility); } VectorSubtract (end, start, target); target[2] += self->enemy->viewheight; // monster_fire_blaster (self, start, target, BLASTER2_DAMAGE*widow_damage_multiplier, 1000, flashnum, (effect!=0)?(effect|EF_TRACKER):0, BLASTER_GREEN); monster_fire_blaster2 (self, start, target, BLASTER2_DAMAGE*widow_damage_multiplier, 1000, flashnum, effect); } // else // { // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("widow: firing on non-fire frame!\n"); // } }