void WidowExplosionLeg (edict_t *self) { // int n; vec3_t f,r,u, startpoint; vec3_t offset1 = {-31.89, -47.86, 67.02}; vec3_t offset2 = {-44.9, -82.14, 54.72}; //gi.dprintf ("Leg\n"); AngleVectors (self->s.angles, f, r, u); G_ProjectSource2 (self->s.origin, offset1, f, r, u, startpoint); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_EXPLOSION1_BIG); gi.WritePosition (startpoint); gi.multicast (self->s.origin, MULTICAST_ALL); ThrowWidowGibSized (self, "models/monsters/blackwidow2/gib2/tris.md2", 200, GIB_METALLIC, startpoint, gi.soundindex ("misc/fhit3.wav"), false); ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); G_ProjectSource2 (self->s.origin, offset2, f, r, u, startpoint); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_EXPLOSION1); gi.WritePosition (startpoint); gi.multicast (self->s.origin, MULTICAST_ALL); ThrowWidowGibSized (self, "models/monsters/blackwidow2/gib1/tris.md2", 300, GIB_METALLIC, startpoint, gi.soundindex ("misc/fhit3.wav"), false); ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); }
void spawn_out_do (edict_t *self) { vec3_t startpoint,f,r,u; AngleVectors (self->s.angles, f, r, u); G_ProjectSource2 (self->s.origin, beameffects[0], f, r, u, startpoint); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_WIDOWSPLASH); gi.WritePosition (startpoint); gi.multicast (startpoint, MULTICAST_ALL); G_ProjectSource2 (self->s.origin, beameffects[1], f, r, u, startpoint); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_WIDOWSPLASH); gi.WritePosition (startpoint); gi.multicast (startpoint, MULTICAST_ALL); VectorCopy (self->s.origin, startpoint); startpoint[2] += 36; gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BOSSTPORT); gi.WritePosition (startpoint); gi.multicast (startpoint, MULTICAST_PVS); Widowlegs_Spawn (self->s.origin, self->s.angles); G_FreeEdict (self); }
// Rocket Launcher void actorRocket (edict_t *self) { vec3_t start, target; vec3_t forward, right, up; int damage = 80; if(!self->enemy || !self->enemy->inuse) return; AngleVectors (self->s.angles, forward, right, up); if(self->monsterinfo.aiflags & AI_TWO_GUNS) { if(self->framenumbers % 2) G_ProjectSource2 (self->s.origin, self->muzzle2, forward, right, up, start); else G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); self->framenumbers++; } else G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); ActorTarget(self,target); VectorSubtract (target, start, forward); VectorNormalize (forward); fire_rocket (self, start, forward, damage, 550, damage+20, damage, ( (self->spawnflags & SF_MONSTER_SPECIAL) ? self->enemy : NULL) ); gi.positioned_sound(start,self,CHAN_WEAPON,gi.soundindex("weapons/rocklf1a.wav"),1,ATTN_NORM,0); if(developer->value) { if (!(self->monsterinfo.aiflags & AI_TWO_GUNS) || (self->framenumbers % 2)) TraceAimPoint(start,target); } }
// Railgun void actorRailGun (edict_t *self) { vec3_t start, target; vec3_t forward, right, up; if(!self->enemy || !self->enemy->inuse) return; AngleVectors (self->s.angles, forward, right, up); if(self->monsterinfo.aiflags & AI_TWO_GUNS) { if(self->framenumbers % 2) G_ProjectSource2 (self->s.origin, self->muzzle2, forward, right, up, start); else G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); self->framenumbers++; } else G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); ActorTarget(self,target); VectorSubtract (target, start, forward); VectorNormalize (forward); fire_rail (self, start, forward, 80, 100); // Do slightly less damage gi.positioned_sound(start,self,CHAN_WEAPON,gi.soundindex("weapons/railgf1a.wav"),1,ATTN_NORM,0); if(developer->value) { if (!(self->monsterinfo.aiflags & AI_TWO_GUNS) || (self->framenumbers % 2)) TraceAimPoint(start,target); } }
void spawn_out_start(edict_t *self) { vec3_t startpoint, f, r, u; if (!self) { return; } self->wait = level.time + 2.0; AngleVectors(self->s.angles, f, r, u); G_ProjectSource2(self->s.origin, beameffects[0], f, r, u, startpoint); gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_WIDOWBEAMOUT); gi.WriteShort(20001); gi.WritePosition(startpoint); gi.multicast(startpoint, MULTICAST_ALL); G_ProjectSource2(self->s.origin, beameffects[1], f, r, u, startpoint); gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_WIDOWBEAMOUT); gi.WriteShort(20002); gi.WritePosition(startpoint); gi.multicast(startpoint, MULTICAST_ALL); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/bwidowbeamout.wav"), 1, ATTN_NORM, 0); }
//Blaster void actorBlaster (edict_t *self) { vec3_t start, target; vec3_t forward, right, up; int damage; int effect, color; if(!self->enemy || !self->enemy->inuse) return; // Knightmare- select color and effect if (blaster_color->value == 2) { //green color = BLASTER_GREEN; effect = (EF_BLASTER|EF_TRACKER); } else if (blaster_color->value == 3) { //blue color = BLASTER_BLUE; #ifdef KMQUAKE2_ENGINE_MOD effect = EF_BLASTER|EF_BLUEHYPERBLASTER; #else effect = EF_BLUEHYPERBLASTER; #endif } #ifdef KMQUAKE2_ENGINE_MOD else if (blaster_color->value == 4) {//red color = BLASTER_RED; effect = EF_BLASTER|EF_IONRIPPER; } #endif else { //standard yellow color = BLASTER_ORANGE; effect = EF_BLASTER; } AngleVectors (self->s.angles, forward, right, up); G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); ActorTarget(self,target); VectorSubtract (target, start, forward); VectorNormalize (forward); if(self->monsterinfo.aiflags & AI_TWO_GUNS) damage = 5; else damage = 10; monster_fire_blaster (self, start, forward, damage, 600, MZ2_SOLDIER_BLASTER_2, effect, color); if(developer->value) TraceAimPoint(start,target); if(self->monsterinfo.aiflags & AI_TWO_GUNS) { G_ProjectSource2(self->s.origin,self->muzzle2,forward,right,up,start); VectorSubtract (target, start, forward); VectorNormalize (forward); monster_fire_blaster (self, start, forward, damage, 600, MZ2_SOLDIER_BLASTER_2, effect, color); } }
// Machinegun void actorMachineGun (edict_t *self) { vec3_t start, target; vec3_t forward, right, up; int damage; if(!self->enemy || !self->enemy->inuse) { self->monsterinfo.pausetime = 0; return; } AngleVectors (self->s.angles, forward, right, up); G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); ActorTarget(self,target); VectorSubtract (target, start, forward); VectorNormalize (forward); if(self->monsterinfo.aiflags & AI_TWO_GUNS) damage = 2; else damage = 4; fire_bullet (self, start, forward, damage, 2, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN); gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_CHAINFIST_SMOKE); gi.WritePosition(start); gi.multicast(start, MULTICAST_PVS); gi.positioned_sound(start,self,CHAN_WEAPON,gi.soundindex(va("weapons/machgf%db.wav",self->actor_gunframe % 5 + 1)),1,ATTN_NORM,0); if(self->flash) { VectorCopy(start,self->flash->s.origin); self->flash->think = muzzleflash_think; self->flash->wait = level.time + FRAMETIME; self->flash->think(self->flash); } if(developer->value) TraceAimPoint(start,target); if(self->monsterinfo.aiflags & AI_TWO_GUNS) { G_ProjectSource2 (self->s.origin, self->muzzle2, forward, right, up, start); ActorTarget(self,target); VectorSubtract (target, start, forward); VectorNormalize (forward); fire_bullet (self, start, forward, damage, 2, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN); gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_CHAINFIST_SMOKE); gi.WritePosition(start); gi.multicast(start, MULTICAST_PVS); } }
//Super Shotgun void actorSuperShotgun (edict_t *self) { vec3_t start, target; vec3_t forward, right, up; vec3_t angles; if(!self->enemy || !self->enemy->inuse) return; AngleVectors (self->s.angles, forward, right, up); if(self->monsterinfo.aiflags & AI_TWO_GUNS) { if(self->framenumbers % 2) G_ProjectSource2 (self->s.origin, self->muzzle2, forward, right, up, start); else G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); self->framenumbers++; } else G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); ActorTarget(self,target); VectorSubtract (target, start, forward); VectorNormalize (forward); vectoangles(forward,angles); angles[YAW] -= 5; AngleVectors(angles,forward,NULL,NULL); fire_shotgun (self, start, forward, 6, 12, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN); angles[YAW] += 10; AngleVectors(angles,forward,NULL,NULL); fire_shotgun (self, start, forward, 6, 12, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN); gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_CHAINFIST_SMOKE); gi.WritePosition(start); gi.multicast(start, MULTICAST_PVS); gi.positioned_sound(start,self,CHAN_WEAPON,gi.soundindex("weapons/sshotf1b.wav"),1,ATTN_NORM,0); if(self->flash) { VectorCopy(start,self->flash->s.origin); self->flash->s.frame = 0; self->flash->think = muzzleflash_think; self->flash->wait = level.time + FRAMETIME; self->flash->think(self->flash); } if(developer->value) { if (!(self->monsterinfo.aiflags & AI_TWO_GUNS) || (self->framenumbers % 2)) TraceAimPoint(start,target); } }
void widow_ready_spawn(edict_t *self) { vec3_t f, r, u, offset, startpoint, spawnpoint; int i; if (!self) { return; } WidowBlaster(self); AngleVectors(self->s.angles, f, r, u); for (i = 0; i < 2; i++) { VectorCopy(spawnpoints[i], offset); G_ProjectSource2(self->s.origin, offset, f, r, u, startpoint); if (FindSpawnPoint(startpoint, stalker_mins, stalker_maxs, spawnpoint, 64)) { SpawnGrow_Spawn(spawnpoint, 1); } } }
void ThrowArm1(edict_t *self) { int n; vec3_t f, r, u, startpoint; vec3_t offset1 = {65.76, 17.52, 7.56}; if (!self) { return; } AngleVectors(self->s.angles, f, r, u); G_ProjectSource2(self->s.origin, offset1, f, r, u, startpoint); gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_EXPLOSION1_BIG); gi.WritePosition(startpoint); gi.multicast(self->s.origin, MULTICAST_ALL); for (n = 0; n < 2; n++) { ThrowWidowGibLoc(self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); } }
void Widow2Tongue(edict_t *self) { vec3_t f, r, u; vec3_t start, end, dir; trace_t tr; if (!self) { return; } AngleVectors(self->s.angles, f, r, u); G_ProjectSource2(self->s.origin, offsets[self->s.frame - FRAME_tongs01], f, r, u, start); VectorCopy(self->enemy->s.origin, end); if (!widow2_tongue_attack_ok(start, end, 256)) { end[2] = self->enemy->s.origin[2] + self->enemy->maxs[2] - 8; if (!widow2_tongue_attack_ok(start, end, 256)) { end[2] = self->enemy->s.origin[2] + self->enemy->mins[2] + 8; if (!widow2_tongue_attack_ok(start, end, 256)) { return; } } } VectorCopy(self->enemy->s.origin, end); tr = gi.trace(start, NULL, NULL, end, self, MASK_SHOT); if (tr.ent != self->enemy) { return; } gi.sound(self, CHAN_WEAPON, sound_tentacles_retract, 1, ATTN_NORM, 0); gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_PARASITE_ATTACK); gi.WriteShort(self - g_edicts); gi.WritePosition(start); gi.WritePosition(end); gi.multicast(self->s.origin, MULTICAST_PVS); VectorSubtract(start, end, dir); T_Damage(self->enemy, self, self, dir, self->enemy->s.origin, vec3_origin, 2, 0, DAMAGE_NO_KNOCKBACK, MOD_UNKNOWN); }
void actorBFG (edict_t *self) { vec3_t start, target; vec3_t forward, right, up; if(!self->enemy || !self->enemy->inuse) { self->monsterinfo.pausetime = 0; return; } if(self->actor_gunframe == 0) gi.positioned_sound(self->s.origin,self,CHAN_WEAPON,gi.soundindex("weapons/bfg__f1y.wav"),1,ATTN_NORM,0); if(self->actor_gunframe == 10) { AngleVectors (self->s.angles, forward, right, up); if(self->monsterinfo.aiflags & AI_TWO_GUNS) { if(self->framenumbers % 2) G_ProjectSource2 (self->s.origin, self->muzzle2, forward, right, up, start); else G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); self->framenumbers++; } else G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); ActorTarget(self,target); VectorSubtract (target, start, forward); VectorNormalize (forward); fire_bfg (self, start, forward, 500, 300, 1000); self->endtime = level.time + 1; if(developer->value) { if (!(self->monsterinfo.aiflags & AI_TWO_GUNS) || (self->framenumbers % 2)) TraceAimPoint(start,target); } } self->actor_gunframe++; }
void ThrowArm2 (edict_t *self) { // int n; vec3_t f,r,u, startpoint; vec3_t offset1 = {65.76, 17.52, 7.56}; AngleVectors (self->s.angles, f, r, u); G_ProjectSource2 (self->s.origin, offset1, f, r, u, startpoint); ThrowWidowGibSized (self, "models/monsters/blackwidow2/gib4/tris.md2", 200, GIB_METALLIC, startpoint, gi.soundindex ("misc/fhit3.wav"), false); ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); }
void WidowSpawn(edict_t *self) { vec3_t f, r, u, offset, startpoint, spawnpoint; edict_t *ent, *designated_enemy; int i; if (!self) { return; } AngleVectors(self->s.angles, f, r, u); for (i = 0; i < 2; i++) { VectorCopy(spawnpoints[i], offset); G_ProjectSource2(self->s.origin, offset, f, r, u, startpoint); if (FindSpawnPoint(startpoint, stalker_mins, stalker_maxs, spawnpoint, 64)) { ent = CreateGroundMonster(spawnpoint, self->s.angles, stalker_mins, stalker_maxs, "monster_stalker", 256); if (!ent) { continue; } self->monsterinfo.monster_used++; ent->monsterinfo.commander = self; ent->nextthink = level.time; ent->think(ent); ent->monsterinfo.aiflags |= /* AI_SPAWNED_WIDOW | */ AI_DO_NOT_COUNT | AI_IGNORE_SHOTS; designated_enemy = self->enemy; if ((designated_enemy->inuse) && (designated_enemy->health > 0)) { ent->enemy = designated_enemy; FoundTarget(ent); ent->monsterinfo.attack(ent); } } } }
void Widow2TonguePull(edict_t *self) { vec3_t vec; vec3_t f, r, u; vec3_t start, end; if (!self) { return; } if ((!self->enemy) || (!self->enemy->inuse)) { self->monsterinfo.run(self); return; } AngleVectors(self->s.angles, f, r, u); G_ProjectSource2(self->s.origin, offsets[self->s.frame - FRAME_tongs01], f, r, u, start); VectorCopy(self->enemy->s.origin, end); if (!widow2_tongue_attack_ok(start, end, 256)) { return; } if (self->enemy->groundentity) { self->enemy->s.origin[2] += 1; self->enemy->groundentity = NULL; } VectorSubtract(self->s.origin, self->enemy->s.origin, vec); if (self->enemy->client) { VectorNormalize(vec); VectorMA(self->enemy->velocity, 1000, vec, self->enemy->velocity); } else { self->enemy->ideal_yaw = vectoyaw(vec); M_ChangeYaw(self->enemy); VectorScale(f, 1000, self->enemy->velocity); } }
void WidowExplosion1 (edict_t *self) { int n; vec3_t f,r,u, startpoint; vec3_t offset = {23.74, -37.67, 76.96}; // gi.dprintf ("1\n"); AngleVectors (self->s.angles, f, r, u); G_ProjectSource2 (self->s.origin, offset, f, r, u, startpoint); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_EXPLOSION1); gi.WritePosition (startpoint); gi.multicast (self->s.origin, MULTICAST_ALL); for (n= 0; n < 1; n++) ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); for (n= 0; n < 1; n++) ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); for (n= 0; n < 2; n++) ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 300, GIB_METALLIC, startpoint, false); }
void WidowExplosion7(edict_t *self) { int n; vec3_t f, r, u, startpoint; vec3_t offset = {-20.11, -1.11, 40.76}; if (!self) { return; } AngleVectors(self->s.angles, f, r, u); G_ProjectSource2(self->s.origin, offset, f, r, u, startpoint); gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_EXPLOSION1); gi.WritePosition(startpoint); gi.multicast(self->s.origin, MULTICAST_ALL); for (n = 0; n < 1; n++) { ThrowWidowGibLoc(self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); } for (n = 0; n < 1; n++) { ThrowWidowGibLoc(self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); } for (n = 0; n < 2; n++) { ThrowWidowGibLoc(self, "models/objects/gibs/sm_metal/tris.md2", 300, GIB_METALLIC, startpoint, false); } }
//========================================================================================== // // AimGrenade finds the correct aim vector to get a grenade from start to target at initial // velocity = speed. Returns false if grenade can't make it to target. // //========================================================================================== qboolean AimGrenade (edict_t *self, vec3_t start, vec3_t target, vec_t speed, vec3_t aim) { vec3_t angles, forward, right, up; vec3_t from_origin, from_muzzle; vec3_t aim_point; vec_t xo, yo; vec_t x; float cosa, t, vx, y; float drop; float last_error, v_error; int i; vec3_t last_aim; VectorCopy(target,aim_point); VectorSubtract(aim_point,self->s.origin,from_origin); VectorSubtract(aim_point, start, from_muzzle); if(self->svflags & SVF_MONSTER) { VectorCopy(from_muzzle,aim); VectorNormalize(aim); yo = from_muzzle[2]; xo = sqrt(from_muzzle[0]*from_muzzle[0] + from_muzzle[1]*from_muzzle[1]); } else { VectorCopy(from_origin,aim); VectorNormalize(aim); yo = from_origin[2]; xo = sqrt(from_origin[0]*from_origin[0] + from_origin[1]*from_origin[1]); } // If resulting aim vector is looking straight up or straight down, we're // done. Actually now that I write this down and think about it... should // probably check straight up to make sure grenade will actually reach the // target. if( (aim[2] == 1.0) || (aim[2] == -1.0)) return true; // horizontal distance to target from muzzle x = sqrt( from_muzzle[0]*from_muzzle[0] + from_muzzle[1]*from_muzzle[1]); cosa = sqrt(aim[0]*aim[0] + aim[1]*aim[1]); // constant horizontal velocity (since grenades don't have drag) vx = speed * cosa; // time to reach target x t = x/vx; // if flight time is less than one frame, no way grenade will drop much, // shoot the sucker now. if(t < FRAMETIME) return true; // in that time, grenade will drop this much: drop = 0.5*sv_gravity->value*t*t; y = speed*aim[2]*t - drop; v_error = target[2] - start[2] - y; // if we're fairly close and we'll hit target at current angle, // no need for all this, just shoot it if( (x < 128) && (fabs(v_error) < 16) ) return true; last_error = 100000.; VectorCopy(aim,last_aim); // Unfortunately there is no closed-form solution for this problem, // so we creep up on an answer and balk if it takes more than // 10 iterations to converge to the tolerance we'll accept. for(i=0; i<10 && fabs(v_error) > 4 && fabs(v_error) < fabs(last_error); i++) { last_error = v_error; aim[2] = cosa * (yo + drop)/xo; VectorNormalize(aim); if(!(self->svflags & SVF_MONSTER)) { vectoangles(aim,angles); AngleVectors(angles, forward, right, up); G_ProjectSource2(self->s.origin,self->move_origin,forward,right,up,start); VectorSubtract(aim_point,start,from_muzzle); x = sqrt(from_muzzle[0]*from_muzzle[0] + from_muzzle[1]*from_muzzle[1]); } cosa = sqrt(aim[0]*aim[0] + aim[1]*aim[1]); vx = speed * cosa; t = x/vx; drop = 0.5*sv_gravity->value*t*t; y = speed*aim[2]*t - drop; v_error = target[2] - start[2] - y; if(fabs(v_error) < fabs(last_error)) VectorCopy(aim,last_aim); } if(i >= 10 || v_error > 64) return false; if(fabs(v_error) > fabs(last_error)) { VectorCopy(last_aim,aim); if(!(self->svflags & SVF_MONSTER)) { vectoangles(aim,angles); AngleVectors(angles, forward, right, up); G_ProjectSource2(self->s.origin,self->move_origin,forward,right,up,start); VectorSubtract(aim_point,start,from_muzzle); } } // Sanity check... if launcher is at the same elevation or a bit above the // target entity, check to make sure he won't bounce grenades off the // top of a doorway or other obstruction. If he WOULD do that, then figure out // the max elevation angle that will get the grenade through the door, and // hope we get a good bounce. if( (start[2] - target[2] < 160) && (start[2] - target[2] > -16) ) { trace_t tr; vec3_t dist; tr = gi.trace(start,vec3_origin,vec3_origin,aim_point,self,MASK_SOLID); if( (tr.fraction < 1.0) && (!self->enemy || (tr.ent != self->enemy) )) { // OK... the aim vector hit a solid, but would the grenade actually hit? int contents; cosa = sqrt(aim[0]*aim[0] + aim[1]*aim[1]); vx = speed * cosa; VectorSubtract(tr.endpos,start,dist); dist[2] = 0; x = VectorLength(dist); t = x/vx; drop = 0.5*sv_gravity->value*t*(t+FRAMETIME); tr.endpos[2] -= drop; // move just a bit in the aim direction tr.endpos[0] += aim[0]; tr.endpos[1] += aim[1]; contents = gi.pointcontents(tr.endpos); while((contents & MASK_SOLID) && (aim_point[2] > target[2])) { aim_point[2] -= 8.0; VectorSubtract(aim_point,self->s.origin,from_origin); VectorCopy(from_origin,aim); VectorNormalize(aim); if(!(self->svflags & SVF_MONSTER)) { vectoangles(aim,angles); AngleVectors(angles, forward, right, up); G_ProjectSource2(self->s.origin,self->move_origin,forward,right,up,start); VectorSubtract(aim_point,start,from_muzzle); } tr = gi.trace(start,vec3_origin,vec3_origin,aim_point,self,MASK_SOLID); if(tr.fraction < 1.0) { cosa = sqrt(aim[0]*aim[0] + aim[1]*aim[1]); vx = speed * cosa; VectorSubtract(tr.endpos,start,dist); dist[2] = 0; x = VectorLength(dist); t = x/vx; drop = 0.5*sv_gravity->value*t*(t+FRAMETIME); tr.endpos[2] -= drop; tr.endpos[0] += aim[0]; tr.endpos[1] += aim[1]; contents = gi.pointcontents(tr.endpos); } } } } return true; }
void actorGrenadeLauncher (edict_t *self) { vec3_t start,target; vec3_t forward, right, up; vec3_t aim; vec3_t dist; vec_t monster_speed; if(!self->enemy || !self->enemy->inuse) return; AngleVectors (self->s.angles, forward, right, up); if(self->monsterinfo.aiflags & AI_TWO_GUNS) { if(self->framenumbers % 2) G_ProjectSource2 (self->s.origin, self->muzzle2, forward, right, up, start); else G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); self->framenumbers++; } else G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); ActorTarget(self,target); if(self->enemy->absmin[2] <= self->absmax[2]) target[2] += self->enemy->mins[2] - self->enemy->viewheight; VectorSubtract(target, start, aim); // lead target... 20, 35, 50, 65 chance of leading if( random() < (0.2 + skill->value * 0.15) ) { float dist; float time; dist = VectorLength (aim); time = dist/GRENADE_VELOCITY; // Not correct, but better than nothin' VectorMA(target, time, self->enemy->velocity, target); VectorSubtract(target, start, aim); } VectorCopy(aim,forward); VectorNormalize (aim); if(aim[2] < 1.0) { float cosa, t, x, vx, y; float drop; float last_error, last_up, v_error; int i; VectorCopy(forward,target); // save target point // horizontal distance to target x = sqrt( forward[0]*forward[0] + forward[1]*forward[1]); cosa = sqrt(aim[0]*aim[0] + aim[1]*aim[1]); // constant horizontal velocity (since grenades don't have drag) vx = GRENADE_VELOCITY * cosa; // time to reach target x t = x/vx; // in that time, grenade will drop this much: drop = 0.5*sv_gravity->value*t*(t+FRAMETIME); forward[2] = target[2] + drop; // this is a good first cut, but incorrect since angle now changes, so // horizontal speed changes VectorCopy(forward,aim); VectorNormalize(aim); cosa = sqrt(aim[0]*aim[0] + aim[1]*aim[1]); vx = GRENADE_VELOCITY * cosa; t = x/vx; y = GRENADE_VELOCITY*aim[2]*t - 0.5*sv_gravity->value*t*(t+FRAMETIME); v_error = target[2]-y; last_error = 2*v_error; for(i=0; i<10 && fabs(v_error) > 4 && fabs(v_error) < fabs(last_error); i++) { drop = 0.5*sv_gravity->value*t*(t+FRAMETIME); forward[2] = target[2] + drop; VectorCopy(forward,aim); VectorNormalize(aim); cosa = sqrt(aim[0]*aim[0] + aim[1]*aim[1]); vx = GRENADE_VELOCITY * cosa; t = x/vx; y = GRENADE_VELOCITY*aim[2]*t - 0.5*sv_gravity->value*t*(t+FRAMETIME); v_error = target[2]-y; // If error is increasing... we can't get there from here and // probably shouldn't be here in the first place. Too late now... // use last aim vector and shoot. if(fabs(v_error) < fabs(last_error)) last_up = forward[2]; } if(fabs(v_error) > fabs(last_error)) { forward[2] = last_up; VectorCopy(forward,aim); VectorNormalize(aim); } // Sanity check... if gunner is at the same elevation or a bit above the // target entity, check to make sure he won't bounce grenades off the // top of a doorway. If he WOULD do that, then figure out the max elevation // angle that will get the grenade through the door, and hope we get a // good bounce. if( (self->s.origin[2] - self->enemy->s.origin[2] < 160) && (self->s.origin[2] - self->enemy->s.origin[2] > -16) ) { trace_t tr; VectorAdd(start,forward,target); tr = gi.trace(start,vec3_origin,vec3_origin,target,self,MASK_SOLID); if(tr.fraction < 1.0) { // OK... the aim vector hit a solid, but would the grenade actually hit? int contents; cosa = sqrt(aim[0]*aim[0] + aim[1]*aim[1]); vx = GRENADE_VELOCITY * cosa; VectorSubtract(tr.endpos,start,dist); dist[2] = 0; x = VectorLength(dist); t = x/vx; drop = 0.5*sv_gravity->value*t*(t+FRAMETIME); tr.endpos[2] -= drop; // move just a bit in the aim direction tr.endpos[0] += aim[0]; tr.endpos[1] += aim[1]; contents = gi.pointcontents(tr.endpos); while((contents & MASK_SOLID) && (target[2] > self->enemy->s.origin[2])) { target[2] -= 8.0; VectorSubtract(target,start,forward); VectorCopy(forward,aim); VectorNormalize(aim); tr = gi.trace(start,vec3_origin,vec3_origin,target,self,MASK_SOLID); if(tr.fraction < 1.0) { cosa = sqrt(aim[0]*aim[0] + aim[1]*aim[1]); vx = GRENADE_VELOCITY * cosa; VectorSubtract(tr.endpos,start,dist); dist[2] = 0; x = VectorLength(dist); t = x/vx; drop = 0.5*sv_gravity->value*t*(t+FRAMETIME); tr.endpos[2] -= drop; tr.endpos[0] += aim[0]; tr.endpos[1] += aim[1]; contents = gi.pointcontents(tr.endpos); } // drop aim point another bit for insurance target[2] -= 8; VectorSubtract(target,start,forward); VectorCopy(forward,aim); VectorNormalize(aim); } } } } // DWH - take into account (sort of) Lazarus feature of adding shooter's velocity to // grenade velocity monster_speed = VectorLength(self->velocity); if(monster_speed > 0) { vec3_t v1; vec_t delta; VectorCopy(self->velocity,v1); VectorNormalize(v1); delta = -monster_speed/GRENADE_VELOCITY; VectorMA(aim,delta,v1,aim); VectorNormalize(aim); } fire_grenade (self, start, aim, 50, GRENADE_VELOCITY, 2.5, 90, false); gi.positioned_sound(start,self,CHAN_WEAPON,gi.soundindex("weapons/grenlf1a.wav"),1,ATTN_NORM,0); if(developer->value) { if (!(self->monsterinfo.aiflags & AI_TWO_GUNS) || (self->framenumbers % 2)) TraceAimPoint(start,target); } }
qboolean Widow2_CheckAttack(edict_t *self) { vec3_t spot1, spot2; vec3_t temp; float chance = 0; trace_t tr; int enemy_range; float enemy_yaw; float real_enemy_range; vec3_t f, r, u; if (!self) { return false; } if (!self->enemy) { return false; } WidowPowerups(self); if ((random() < 0.8) && (SELF_SLOTS_LEFT >= 2) && (realrange(self, self->enemy) > 150)) { self->monsterinfo.aiflags |= AI_BLOCKED; self->monsterinfo.attack_state = AS_MISSILE; return true; } if (self->enemy->health > 0) { /* see if any entities are in the way of the shot */ VectorCopy(self->s.origin, spot1); spot1[2] += self->viewheight; VectorCopy(self->enemy->s.origin, spot2); spot2[2] += self->enemy->viewheight; tr = gi.trace(spot1, NULL, NULL, spot2, self, CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_SLIME | CONTENTS_LAVA); /* do we have a clear shot? */ if (tr.ent != self->enemy) { /* go ahead and spawn stuff if we're mad a a client */ if (self->enemy->client && (SELF_SLOTS_LEFT >= 2)) { self->monsterinfo.attack_state = AS_BLIND; return true; } if ((self->enemy->solid != SOLID_NOT) || (tr.fraction < 1.0)) { return false; } } } enemy_range = range(self, self->enemy); VectorSubtract(self->enemy->s.origin, self->s.origin, temp); enemy_yaw = vectoyaw2(temp); self->ideal_yaw = enemy_yaw; /* melee attack */ if (self->timestamp < level.time) { real_enemy_range = realrange(self, self->enemy); if (real_enemy_range < 300) { AngleVectors(self->s.angles, f, r, u); G_ProjectSource2(self->s.origin, offsets[0], f, r, u, spot1); VectorCopy(self->enemy->s.origin, spot2); if (widow2_tongue_attack_ok(spot1, spot2, 256)) { /* be nice in easy mode */ if ((skill->value == 0) && (rand() & 3)) { return false; } if (self->monsterinfo.melee) { self->monsterinfo.attack_state = AS_MELEE; } else { self->monsterinfo.attack_state = AS_MISSILE; } return true; } } } if (level.time < self->monsterinfo.attack_finished) { return false; } if (self->monsterinfo.aiflags & AI_STAND_GROUND) { chance = 0.4; } else if (enemy_range == RANGE_NEAR) { chance = 0.8; } else if (enemy_range == RANGE_MID) { chance = 0.8; } else if (enemy_range == RANGE_FAR) { chance = 0.5; } if ((random() < chance) || (self->enemy->solid == SOLID_NOT)) { self->monsterinfo.attack_state = AS_MISSILE; return true; } return false; }
// Chaingun void actorChaingun (edict_t *self) { vec3_t start, target; vec3_t forward, right, up; int i; int shots; int damage; if(!self->enemy || !self->enemy->inuse) self->monsterinfo.pausetime = 0; if(level.time >= self->monsterinfo.pausetime) { self->s.sound = 0; gi.sound(self,CHAN_AUTO,gi.soundindex("weapons/chngnd1a.wav"),1,ATTN_IDLE,0); return; } if(self->actor_gunframe == 0) gi.sound(self, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0); if(self->actor_gunframe == 21 && level.time < self->monsterinfo.pausetime) self->actor_gunframe = 15; else self->actor_gunframe++; self->s.sound = gi.soundindex("weapons/chngnl1a.wav"); #ifdef LOOP_SOUND_ATTENUATION self->s.attenuation = ATTN_IDLE; #endif if(self->actor_gunframe <= 9) shots = 1; else if(self->actor_gunframe <= 14) shots = 2; else shots = 3; AngleVectors (self->s.angles, forward, right, up); G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); ActorTarget(self,target); VectorSubtract (target, start, forward); VectorNormalize (forward); if(self->monsterinfo.aiflags & AI_TWO_GUNS) damage = 2; else damage = 4; for(i=0; i<shots; i++) fire_bullet (self, start, forward, damage, 2, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN); gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_CHAINFIST_SMOKE); gi.WritePosition(start); gi.multicast(start, MULTICAST_PVS); gi.positioned_sound(start,self,CHAN_WEAPON,gi.soundindex(va("weapons/machgf%db.wav",self->actor_gunframe % 5 + 1)),1,ATTN_NORM,0); if(self->flash) { VectorCopy(start,self->flash->s.origin); self->flash->think = muzzleflash_think; self->flash->wait = level.time + FRAMETIME; self->flash->think(self->flash); } if(developer->value) TraceAimPoint(start,target); if(self->monsterinfo.aiflags & AI_TWO_GUNS) { G_ProjectSource2 (self->s.origin, self->muzzle2, forward, right, up, start); ActorTarget(self,target); VectorSubtract (target, start, forward); VectorNormalize (forward); for(i=0; i<shots; i++) fire_bullet (self, start, forward, damage, 2, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN); gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_CHAINFIST_SMOKE); gi.WritePosition(start); gi.multicast(start, MULTICAST_PVS); } }
void Widow2Spawn (edict_t *self) { vec3_t f, r, u, offset, startpoint, spawnpoint; edict_t *ent, *designated_enemy; int i; AngleVectors (self->s.angles, f, r, u); for (i=0; i < 2; i++) { VectorCopy (spawnpoints[i], offset); G_ProjectSource2 (self->s.origin, offset, f, r, u, startpoint); if (FindSpawnPoint (startpoint, stalker_mins, stalker_maxs, spawnpoint, 64)) { ent = CreateGroundMonster (spawnpoint, self->s.angles, stalker_mins, stalker_maxs, "monster_stalker", 256); if (!ent) continue; self->monsterinfo.monster_used++; ent->monsterinfo.commander = self; // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("widow: post-spawn : %d slots left\n", SELF_SLOTS_LEFT); ent->nextthink = level.time; ent->think (ent); ent->monsterinfo.aiflags |= AI_SPAWNED_WIDOW|AI_DO_NOT_COUNT|AI_IGNORE_SHOTS; if (!(coop && coop->value)) { designated_enemy = self->enemy; } else { designated_enemy = PickCoopTarget(ent); if (designated_enemy) { // try to avoid using my enemy if (designated_enemy == self->enemy) { designated_enemy = PickCoopTarget(ent); if (designated_enemy) { // if ((g_showlogic) && (g_showlogic->value)) // { // gi.dprintf ("PickCoopTarget returned a %s - ", designated_enemy->classname); // if (designated_enemy->client) // gi.dprintf ("with name %s\n", designated_enemy->client->pers.netname); // else // gi.dprintf ("NOT A CLIENT\n"); // } } else { // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("pick coop failed, using my current enemy\n"); designated_enemy = self->enemy; } } } else { // if ((g_showlogic) && (g_showlogic->value)) // gi.dprintf ("pick coop failed, using my current enemy\n"); designated_enemy = self->enemy; } } if ((designated_enemy->inuse) && (designated_enemy->health > 0)) { ent->enemy = designated_enemy; FoundTarget (ent); ent->monsterinfo.attack(ent); } } } }
void actorHyperblaster (edict_t *self) { vec3_t start, target; vec3_t forward, right, up; int damage; int effect; int color; if(!self->enemy || !self->enemy->inuse) { self->monsterinfo.pausetime = 0; self->s.sound = 0; return; } self->s.sound = gi.soundindex("weapons/hyprbl1a.wav"); #ifdef LOOP_SOUND_ATTENUATION self->s.attenuation = ATTN_IDLE; #endif if (level.time >= self->monsterinfo.pausetime) { self->actor_gunframe++; } else { // Knightmare- select color if (hyperblaster_color->value == 2) //green color = BLASTER_GREEN; else if (hyperblaster_color->value == 3) //blue color = BLASTER_BLUE; #ifdef KMQUAKE2_ENGINE_MOD else if (hyperblaster_color->value == 4) //red color = BLASTER_RED; #endif else //standard yellow color = BLASTER_ORANGE; AngleVectors (self->s.angles, forward, right, up); G_ProjectSource2 (self->s.origin, self->muzzle, forward, right, up, start); ActorTarget(self,target); VectorSubtract (target, start, forward); VectorNormalize (forward); if ((random() * 3) < 1) { if (hyperblaster_color->value == 2) //green effect = (EF_HYPERBLASTER|EF_TRACKER); else if (hyperblaster_color->value == 3) //blue effect = EF_BLUEHYPERBLASTER; #ifdef KMQUAKE2_ENGINE_MOD else if (hyperblaster_color->value == 4) //red effect = EF_HYPERBLASTER|EF_IONRIPPER; #endif else //standard yellow effect = EF_HYPERBLASTER; } else effect = 0; gi.positioned_sound(start,self,CHAN_WEAPON,gi.soundindex("weapons/hyprbf1a.wav"),1,ATTN_NORM,0); if(self->monsterinfo.aiflags & AI_TWO_GUNS) damage = 8; else damage = 15; fire_blaster (self, start, forward, damage, 1000, effect, true, color); if(developer->value) TraceAimPoint(start,target); if(self->monsterinfo.aiflags & AI_TWO_GUNS) { G_ProjectSource2 (self->s.origin, self->muzzle2, forward, right, up, start); ActorTarget(self,target); VectorSubtract (target, start, forward); VectorNormalize (forward); if ((random() * 3) < 1) { if (hyperblaster_color->value == 2) //green effect = (EF_HYPERBLASTER|EF_TRACKER); else if (hyperblaster_color->value == 3) //blue effect = EF_BLUEHYPERBLASTER; #ifdef KMQUAKE2_ENGINE_MOD else if (hyperblaster_color->value == 4) //red effect = EF_HYPERBLASTER|EF_IONRIPPER; #endif else //standard yellow effect = EF_HYPERBLASTER; } else effect = 0; fire_blaster (self, start, forward, damage, 1000, effect, true, color); } self->actor_gunframe++; if (self->actor_gunframe == 12) self->actor_gunframe = 6; } if (self->actor_gunframe == 12) { gi.sound(self, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0); self->s.sound = 0; } }