float target_angle (edict_t *self) { vec3_t target; float enemy_yaw; VectorSubtract (self->s.origin, self->enemy->s.origin, target); enemy_yaw = self->s.angles[YAW] - vectoyaw2(target); if (enemy_yaw < 0) enemy_yaw += 360.0; // this gets me 0 degrees = forward enemy_yaw -= 180.0; // positive is to right, negative to left return enemy_yaw; }
void carrier_start_spawn(edict_t *self) { int mytime; float enemy_yaw; vec3_t temp; if (!self) { return; } CarrierCoopCheck(self); if (!orig_yaw_speed) { orig_yaw_speed = self->yaw_speed; } if (!self->enemy) { return; } mytime = (int)((level.time - self->timestamp) / 0.5); VectorSubtract(self->enemy->s.origin, self->s.origin, temp); enemy_yaw = vectoyaw2(temp); /* note that the offsets are based on a forward of 105 from the end angle */ if (mytime == 0) { self->ideal_yaw = anglemod(enemy_yaw - 30); } else if (mytime == 1) { self->ideal_yaw = anglemod(enemy_yaw); } else if (mytime == 2) { self->ideal_yaw = anglemod(enemy_yaw + 30); } CarrierMachineGun(self); }
float target_angle(edict_t *self) { vec3_t target; float enemy_yaw; if (!self) { return 0.0; } VectorSubtract(self->s.origin, self->enemy->s.origin, target); enemy_yaw = self->s.angles[YAW] - vectoyaw2(target); if (enemy_yaw < 0) { enemy_yaw += 360.0; } enemy_yaw -= 180.0; return enemy_yaw; }
qboolean Carrier_CheckAttack(edict_t *self) { vec3_t spot1, spot2; vec3_t temp; float chance = 0; trace_t tr; qboolean enemy_infront, enemy_inback, enemy_below; int enemy_range; float enemy_yaw; if (!self) { return false; } 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->monsterinfo.monster_slots > 2)) { self->monsterinfo.attack_state = AS_BLIND; return true; } /* we want them to go ahead and shoot at info_notnulls if they can. */ if ((self->enemy->solid != SOLID_NOT) || (tr.fraction < 1.0)) { return false; } } } enemy_infront = infront(self, self->enemy); enemy_inback = inback(self, self->enemy); enemy_below = below(self, self->enemy); enemy_range = range(self, self->enemy); VectorSubtract(self->enemy->s.origin, self->s.origin, temp); enemy_yaw = vectoyaw2(temp); self->ideal_yaw = enemy_yaw; /* shoot out the back if appropriate */ if ((enemy_inback) || (!enemy_infront && enemy_below)) { /* this is using wait because the attack is supposed to be independent */ if (level.time >= self->wait) { self->wait = level.time + CARRIER_ROCKET_TIME; self->monsterinfo.attack(self); if (random() < 0.6) { self->monsterinfo.attack_state = AS_SLIDING; } else { self->monsterinfo.attack_state = AS_STRAIGHT; } return true; } } /* melee attack */ if (enemy_range == RANGE_MELEE) { self->monsterinfo.attack_state = AS_MISSILE; return true; } if (self->monsterinfo.aiflags & AI_STAND_GROUND) { chance = 0.4; } else if (enemy_range == RANGE_MELEE) { chance = 0.8; } 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; } /* go ahead and shoot every time if it's a info_notnull */ if ((random() < chance) || (self->enemy->solid == SOLID_NOT)) { self->monsterinfo.attack_state = AS_MISSILE; return true; } if (self->flags & FL_FLY) { if (random() < 0.6) { self->monsterinfo.attack_state = AS_SLIDING; } else { self->monsterinfo.attack_state = AS_STRAIGHT; } } return false; }
qboolean Widow_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; if (!self->enemy) return false; WidowPowerups(self); if (self->monsterinfo.currentmove == &widow_move_run) { // if we're in run, make sure we're in a good frame for attacking before doing anything else // frames 1,2,3,9,10,11,13 good to fire switch (self->s.frame) { case FRAME_walk04: case FRAME_walk05: case FRAME_walk06: case FRAME_walk07: case FRAME_walk08: case FRAME_walk12: { return false; } default: break; } } // give a LARGE bias to spawning things when we have room // use AI_BLOCKED as a signal to attack to spawn 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; } // PGM - we want them to go ahead and shoot at info_notnulls if they can. if(self->enemy->solid != SOLID_NOT || tr.fraction < 1.0) //PGM 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; real_enemy_range = realrange (self, self->enemy); if (real_enemy_range <= (MELEE_DISTANCE+20)) { // don't always melee 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_MELEE) { chance = 0.8; } else if (enemy_range == RANGE_NEAR) { chance = 0.7; } else if (enemy_range == RANGE_MID) { chance = 0.6; } else if (enemy_range == RANGE_FAR) { chance = 0.5; } // PGM - go ahead and shoot every time if it's a info_notnull if ((random () < chance) || (self->enemy->solid == SOLID_NOT)) { self->monsterinfo.attack_state = AS_MISSILE; return true; } return false; }
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; }