void thing_think_pause(edict_t *self) { edict_t *monster; if(level.time > self->touch_debounce_time) { thing_think(self); return; } monster = self->target_ent; if(!monster || !monster->inuse) { G_FreeEdict(self); return; } if(has_valid_enemy(monster)) { vec3_t dir; vec3_t angles; if(visible(monster->enemy,monster)) { self->touch_debounce_time = 0; thing_think(self); return; } VectorSubtract(monster->enemy->s.origin,monster->s.origin,dir); VectorNormalize(dir); vectoangles(dir,angles); monster->ideal_yaw = angles[YAW]; M_ChangeYaw(monster); } self->nextthink = level.time + FRAMETIME; }
void stalker_attack_ranged(edict_t *self) { if (!self) { return; } if (!has_valid_enemy(self)) { return; } /* circle strafe stuff */ if (random() > (1.0 - (0.5 / (float)(skill->value)))) { self->monsterinfo.attack_state = AS_STRAIGHT; } else { if (random() <= 0.5) /* switch directions */ { self->monsterinfo.lefty = 1 - self->monsterinfo.lefty; } self->monsterinfo.attack_state = AS_SLIDING; } self->monsterinfo.currentmove = &stalker_move_shoot; }
void stalker_shoot_attack(edict_t *self) { vec3_t offset, start, f, r, dir; vec3_t end; float time, dist; trace_t trace; if (!self) { return; } if (!has_valid_enemy(self)) { return; } if (self->groundentity && (random() < 0.33)) { VectorSubtract(self->enemy->s.origin, self->s.origin, dir); dist = VectorLength(dir); if ((dist > 256) || (random() < 0.5)) { stalker_do_pounce(self, self->enemy->s.origin); } else { stalker_jump_straightup(self); } } AngleVectors(self->s.angles, f, r, NULL); VectorSet(offset, 24, 0, 6); G_ProjectSource(self->s.origin, offset, f, r, start); VectorSubtract(self->enemy->s.origin, start, dir); if (random() < (0.20 + 0.1 * skill->value)) { dist = VectorLength(dir); time = dist / 1000; VectorMA(self->enemy->s.origin, time, self->enemy->velocity, end); VectorSubtract(end, start, dir); } else { VectorCopy(self->enemy->s.origin, end); } trace = gi.trace(start, vec3_origin, vec3_origin, end, self, MASK_SHOT); if ((trace.ent == self->enemy) || (trace.ent == world)) { monster_fire_blaster2(self, start, dir, 15, 800, MZ2_STALKER_BLASTER, EF_BLASTER); } }
qboolean stalker_blocked (edict_t *self, float dist) { qboolean onCeiling; if(!has_valid_enemy(self)) return false; onCeiling = false; if(self->gravityVector[2] > 0) onCeiling = true; if(!onCeiling) { if(blocked_checkshot(self, 0.25 + (0.05 * skill->value) )) { return true; } if(visible (self, self->enemy)) { stalker_do_pounce(self, self->enemy->s.origin); return true; } if(blocked_checkjump (self, dist, 256, 68)) { stalker_jump (self); return true; } if(blocked_checkplat (self, dist)) return true; } else { if(blocked_checkshot(self, 0.25 + (0.05 * skill->value) )) { return true; } else if(stalker_ok_to_transition(self)) { self->gravityVector[2] = -1; self->s.angles[2] += 180.0; if(self->s.angles[2] > 360.0) self->s.angles[2] -= 360.0; self->groundentity = NULL; return true; } } return false; }
void stalker_attack_melee (edict_t *self) { if(!has_valid_enemy(self)) return; if(random() < 0.5) { self->monsterinfo.currentmove = &stalker_move_swing_l; } else { self->monsterinfo.currentmove = &stalker_move_swing_r; } }
void stalker_shoot_attack (edict_t *self) { vec3_t offset, start, f, r, dir; vec3_t end; float time, dist; trace_t trace; if(!has_valid_enemy(self)) return; if(self->groundentity && random() < 0.33) { VectorSubtract (self->enemy->s.origin, self->s.origin, dir); dist = VectorLength (dir); if((dist > 256) || (random() < 0.5)) stalker_do_pounce(self, self->enemy->s.origin); else stalker_jump_straightup (self); } // FIXME -- keep this but use a custom one // if (!infront(self, self->enemy)) // return; AngleVectors (self->s.angles, f, r, NULL); VectorSet (offset, 24, 0, 6); G_ProjectSource (self->s.origin, offset, f, r, start); VectorSubtract(self->enemy->s.origin, start, dir); if(random() < (0.20 + 0.1 * skill->value)) { dist = VectorLength(dir); time = dist / 1000; VectorMA(self->enemy->s.origin, time, self->enemy->velocity, end); VectorSubtract(end, start, dir); } else VectorCopy(self->enemy->s.origin, end); trace = gi.trace(start, vec3_origin, vec3_origin, end, self, MASK_SHOT); if(trace.ent == self->enemy || trace.ent == world) monster_fire_blaster2(self, start, dir, 15, 800, MZ2_STALKER_BLASTER, EF_BLASTER); // else // gi.dprintf("blocked by entity %s\n", trace.ent->classname); }
/* ===================== hintpath_stop Makes a monster stop following hint_paths. ===================== */ void hintpath_stop (edict_t *monster) { monster->movetarget = monster->goalentity = NULL; monster->monsterinfo.last_hint_time = level.time; monster->monsterinfo.goal_hint = NULL; monster->monsterinfo.aiflags &= ~AI_HINT_PATH; // If we don't have an enemy to get mad at, just stand around like an unactivated monster. if (!has_valid_enemy(monster)) { monster->enemy = NULL; monster->monsterinfo.pausetime = level.time + 100000000; monster->monsterinfo.stand (monster); } else if (visible(monster, monster->enemy)) // attack if we can see our foe FoundTarget (monster); else // keep pursuing HuntTarget (monster); }
void medic_StopPatrolling (edict_t *self) { self->goalentity = NULL; self->movetarget = NULL; self->monsterinfo.aiflags &= ~AI_MEDIC_PATROL; if (!(self->monsterinfo.aiflags & AI_MEDIC)) { if(medic_FindDeadMonster(self)) return; } if (has_valid_enemy(self)) { if (visible(self, self->enemy)) { FoundTarget (self); return; } HuntTarget (self); return; } if(self->monsterinfo.aiflags & AI_MEDIC) abortHeal(self,false); }
qboolean stalker_blocked (edict_t *self, float dist) { qboolean onCeiling; // gi.dprintf("stalker_blocked\n"); if(!has_valid_enemy(self)) return false; onCeiling = false; if(self->gravityVector[2] > 0) onCeiling = true; if(!onCeiling) { if(blocked_checkshot(self, 0.25 + (0.05 * skill->value) )) { // gi.dprintf("blocked: shooting\n"); return true; } if(visible (self, self->enemy)) { // gi.dprintf("blocked: jumping at player!\n"); stalker_do_pounce(self, self->enemy->s.origin); return true; } if(blocked_checkjump (self, dist, 256, 68)) { // gi.dprintf("blocked: jumping up/down\n"); stalker_jump (self); return true; } if(blocked_checkplat (self, dist)) return true; } else { if(blocked_checkshot(self, 0.25 + (0.05 * skill->value) )) { // gi.dprintf("blocked: shooting\n"); return true; } else if(stalker_ok_to_transition(self)) { self->gravityVector[2] = -1; self->s.angles[2] += 180.0; if(self->s.angles[2] > 360.0) self->s.angles[2] -= 360.0; self->groundentity = NULL; // gi.dprintf("falling off ceiling\n"); return true; } // else // gi.dprintf("Not OK to fall!\n"); } return false; }
void thing_think (edict_t *self) { vec3_t vec; vec_t dist; edict_t *monster; monster = self->target_ent; if(level.time <= self->touch_debounce_time) { if(monster && monster->inuse) { if(monster->movetarget == self) { if(monster->health > 0) { VectorSubtract(monster->s.origin,self->s.origin,vec); vec[2] = 0; dist = VectorLength(vec); if(dist >= monster->size[0]) { self->nextthink = level.time + FRAMETIME; return; } } } } } if(!monster || !monster->inuse || (monster->health <= 0)) { G_FreeEdict(self); return; } if(monster->goalentity == self) monster->goalentity = NULL; if(monster->movetarget == self) monster->movetarget = NULL; if(monster->monsterinfo.aiflags & AI_FOLLOW_LEADER) { monster->monsterinfo.leader = NULL; if(monster->monsterinfo.old_leader && monster->monsterinfo.old_leader->inuse) { monster->monsterinfo.pausetime = level.time + 2; monster->monsterinfo.stand(monster); VectorCopy(monster->monsterinfo.old_leader->s.origin,self->move_origin); self->nextthink = level.time + 2; self->think = thing_restore_leader; gi.linkentity(monster); return; } else { monster->monsterinfo.aiflags &= ~AI_FOLLOW_LEADER; } } if(monster->monsterinfo.aiflags & AI_CHICKEN) { monster->monsterinfo.stand(monster); monster->monsterinfo.aiflags |= AI_STAND_GROUND; monster->monsterinfo.pausetime = level.time + 100000; } monster->vehicle = NULL; monster->monsterinfo.aiflags &= ~(AI_CHASE_THING | AI_SEEK_COVER | AI_EVADE_GRENADE); G_FreeEdict(self); if (has_valid_enemy(monster)) { monster->monsterinfo.pausetime = 0; monster->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND); monster->goalentity = monster->enemy; if (visible(monster, monster->enemy)) { FoundTarget (monster); return; } HuntTarget (monster); return; } monster->enemy = NULL; monster->monsterinfo.pausetime = level.time + 100000000; monster->monsterinfo.stand (monster); }
void thing_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { if(self->target_ent != other) return; if(other->health <= 0) { G_FreeEdict(self); return; } self->touch = NULL; if( self->target_ent->monsterinfo.aiflags & AI_SEEK_COVER ) { edict_t *monster; // For monster/actor seeking cover after firing, // pause a random bit before resuming attack self->touch_debounce_time = level.time + random()*6.; monster = self->target_ent; monster->monsterinfo.stand(monster); monster->monsterinfo.pausetime = self->touch_debounce_time; self->think = thing_think_pause; self->think(self); return; } if( self->target_ent->monsterinfo.aiflags & AI_EVADE_GRENADE ) { edict_t *grenade = other->next_grenade; if(other->goalentity == self) other->goalentity = NULL; if(other->movetarget == self) other->movetarget = NULL; other->vehicle = NULL; if(grenade) { // make sure this is still a grenade if(grenade->inuse) { if(Q_strcasecmp(grenade->classname,"grenade") && Q_strcasecmp(grenade->classname,"hgrenade")) other->next_grenade = grenade = NULL; } else other->next_grenade = grenade = NULL; } if(grenade) { if(self->touch_debounce_time > level.time) { other->monsterinfo.pausetime = self->touch_debounce_time + 0.1; other->monsterinfo.aiflags |= AI_STAND_GROUND; other->monsterinfo.stand(other); } else other->monsterinfo.pausetime = 0; other->enemy = grenade->owner; if (has_valid_enemy(other)) { other->goalentity = other->enemy; if (visible(other, other->enemy)) FoundTarget (other); else HuntTarget (other); } else { other->enemy = NULL; other->monsterinfo.stand (other); } if(other->monsterinfo.pausetime > 0) { self->think = thing_grenade_boom; self->nextthink = other->monsterinfo.pausetime; return; } other->monsterinfo.aiflags &= ~(AI_CHASE_THING | AI_EVADE_GRENADE); } else if (has_valid_enemy(other)) { other->monsterinfo.aiflags &= ~(AI_CHASE_THING | AI_EVADE_GRENADE); other->goalentity = other->enemy; if (visible(other, other->enemy)) FoundTarget (other); else HuntTarget (other); } else { other->enemy = NULL; other->monsterinfo.pausetime = level.time + 100000000; other->monsterinfo.aiflags &= ~(AI_CHASE_THING | AI_EVADE_GRENADE); other->monsterinfo.stand (other); } G_FreeEdict(self); return; } self->touch_debounce_time = 0; thing_think(self); }