/*************************************************
 * Decompiled by Serious and Edited by SyndiShanX
 * Script: shared\stealth_aware.gsc
*************************************************/

#using scripts\shared\ai_shared;
#using scripts\shared\ai_sniper_shared;
#using scripts\shared\stealth;
#using scripts\shared\stealth_behavior;
#using scripts\shared\stealth_debug;
#using scripts\shared\stealth_event;
#using scripts\shared\stealth_level;
#using scripts\shared\stealth_player;
#using scripts\shared\stealth_vo;
#using scripts\shared\trigger_shared;
#using scripts\shared\util_shared;
#namespace stealth_aware;

function init() {
  assert(isDefined(self.stealth));
  self.stealth.aware_combat = [];
  self.stealth.aware_alerted = [];
  self.stealth.aware_sighted = [];
  self.stealth.debug_ignore = [];
  self set_awareness("unaware");
  self thread function_a85b6c52();
}

function enabled() {
  return isDefined(self.stealth) && isDefined(self.stealth.aware_combat);
}

function set_awareness(str_awareness) {
  assert(self enabled());
  prevawareness = self.awarenesslevelcurrent;
  if(!isDefined(prevawareness)) {
    prevawareness = "unaware";
  }
  if(isDefined(self.awarenesslevelcurrent) && self.awarenesslevelcurrent != str_awareness) {
    self.awarenesslevelprevious = self.awarenesslevelcurrent;
  }
  self.awarenesslevelcurrent = str_awareness;
  bstealthmode = self.awarenesslevelcurrent != "combat";
  parms = stealth_level::get_parms(str_awareness);
  self.fovcosine = parms.fovcosine;
  self.fovcosinez = parms.fovcosinez;
  self.maxsightdist = parms.maxsightdist;
  self.maxsightdistsqrd = self.maxsightdist * self.maxsightdist;
  self.quiet_death = bstealthmode;
  self setstealthsightawareness(self.awarenesslevelcurrent, bstealthmode);
  if(isDefined(self.patroller) && self.patroller) {
    self.stealth.was_patrolling = 1;
  } else if(!(isDefined(self.stealth.was_patrolling) && self.stealth.was_patrolling) && !isDefined(self.stealth.var_b463484b) && self.awarenesslevelcurrent != "unaware") {
    self.stealth.var_b463484b = self.origin;
  }
  switch (self.awarenesslevelcurrent) {
    case "high_alert":
    case "low_alert":
    case "unaware": {
      self set_ignore_sentient_all(1);
      break;
    }
  }
  if(str_awareness == "unaware") {
    self.stealth.aware_combat = [];
    self.stealth.aware_alerted = [];
    self.stealth.aware_sighted = [];
    self serviceeventsinradius(self.origin, -1);
    if(isactor(self)) {
      self clearenemy();
    }
    self.awarenesslevelprevious = "unaware";
    if(isDefined(self.stealth.was_patrolling) && self.stealth.was_patrolling && isDefined(self.currentgoal)) {
      self thread ai::patrol(self.currentgoal);
    } else if(isDefined(self.stealth.var_b463484b)) {
      if(isactor(self)) {
        self thread stealth_behavior::function_edba2e78(self.stealth.var_b463484b);
      }
      self.stealth.var_b463484b = undefined;
    }
  }
  if(self ai::has_behavior_attribute("stealth")) {
    self ai::set_behavior_attribute("stealth", bstealthmode);
  }
  if(self ai::has_behavior_attribute("disablearrivals")) {
    self ai::set_behavior_attribute("disablearrivals", bstealthmode);
  }
  if(self stealth_vo::enabled()) {
    self stealth_vo::set_stealth_mode(bstealthmode);
  }
  if(prevawareness != str_awareness) {
    self notify("awareness", str_awareness);
  }
  if(bstealthmode) {
    self.stealth.aware_combat = [];
  }
}

function get_awareness() {
  return self.awarenesslevelcurrent;
}

function was_alerted(entity) {
  return isDefined(self.stealth.aware_alerted[entity getentitynumber()]);
}

function change_awareness(delta) {
  assert(self enabled());
  prevaware = self.awarenesslevelcurrent;
  abs_offset = abs(delta);
  if(abs_offset > 1) {
    for(i = 0; i < abs_offset; i++) {
      if(delta > 0) {
        change_awareness(1);
        continue;
      }
      change_awareness(-1);
    }
    return prevaware != self.awarenesslevelcurrent;
  }
  if(delta > 0) {
    switch (self.awarenesslevelcurrent) {
      case "low_alert":
      case "unaware": {
        self set_awareness("high_alert");
        break;
      }
      case "high_alert": {
        self set_awareness("combat");
        break;
      }
    }
  } else {
    switch (self.awarenesslevelcurrent) {
      case "high_alert":
      case "low_alert": {
        self set_awareness("unaware");
        break;
      }
      case "combat": {
        self set_awareness("high_alert");
        break;
      }
    }
  }
  return prevaware != self.awarenesslevelcurrent;
}

function set_ignore_sentient_all(ignore) {
  assert(self enabled());
  foreach(enemy in level.stealth.enemies[self.team]) {
    if(!isDefined(enemy)) {
      continue;
    }
    self set_ignore_sentient(enemy, ignore);
  }
}

function set_ignore_sentient(sentient, ignore) {
  assert(self enabled());
  if(issentient(self) && issentient(sentient)) {
    self setignoreent(sentient, ignore);
  }
  if(ignore) {
    self.stealth.debug_ignore[sentient getentitynumber()] = sentient;
  } else {
    self.stealth.debug_ignore[sentient getentitynumber()] = undefined;
  }
}

function function_ca6a0809(eventpackage) {
  self endon("death");
  self endon("disconnect");
  e_originator = eventpackage.parms[0];
  self notify("stealth_vo", "alert");
  if(isPlayer(e_originator)) {
    e_originator stealth_player::function_ca6a0809(self);
  }
}

function on_sighted(eventpackage) {
  e_originator = eventpackage.parms[0];
  if(!isDefined(e_originator)) {
    return;
  }
  debugreason = "";
  maxsightawareness = "unaware";
  curawareness = self get_awareness();
  var_f51f605d = e_originator getentitynumber();
  if(self stealth::is_enemy(e_originator) && isalive(e_originator)) {
    maxsightawareness = "combat";
    debugreason = "";
  } else if(e_originator enabled() && e_originator get_awareness() == "combat") {
    maxsightawareness = "high_alert";
    debugreason = "";
  }
  var_edfa68f2 = 0;
  if(stealth::awareness_delta(curawareness, maxsightawareness) < 0) {
    var_edfa68f2 = self change_awareness(1);
  }
  if(var_edfa68f2 || !isDefined(self.stealth.aware_alerted[var_f51f605d]) || !isDefined(self.stealth.aware_sighted[var_f51f605d])) {
    curawareness = self get_awareness();
    self notify("alert", curawareness, e_originator.origin + vectorscale((0, 0, 1), 20), e_originator, debugreason);
    if(var_edfa68f2 && curawareness != "combat" && issentient(e_originator)) {
      self setstealthsightvalue(e_originator, 0);
    }
  }
  if(isDefined(e_originator) && self stealth::is_enemy(e_originator)) {
    self.stealth.aware_alerted[var_f51f605d] = e_originator;
    self.stealth.aware_sighted[var_f51f605d] = e_originator;
  }
}

function on_sight_end(eventpackage) {
  self endon("death");
  self endon("disconnect");
  if(getdvarint("stealth_no_return") && self get_awareness() == "combat") {
    return;
  }
  e_originator = eventpackage.parms[0];
  sightname = "on_sight_end";
  if(isDefined(e_originator)) {
    sightname = (sightname + "_") + e_originator getentitynumber();
  }
  self notify(sightname);
  self endon(sightname);
  var_5400af02 = stealth::awareness_delta(self get_awareness(), "unaware");
  if(isDefined(self.stealth.investigating) && (self.stealth.investigating != "infinite" || var_5400af02 == 1)) {
    self waittill("investigate_stop");
  }
  maxsightvalue = 0;
  foreach(enemy in self.stealth.aware_alerted) {
    if(!isDefined(enemy)) {
      continue;
    }
    if(!issentient(enemy)) {
      continue;
    }
    maxsightvalue = max(maxsightvalue, self getstealthsightvalue(enemy));
  }
  if(maxsightvalue <= 0 && self change_awareness(-1)) {
    if(self get_awareness() != "unaware") {
      if(isDefined(e_originator)) {
        if(issentient(e_originator)) {
          self setstealthsightvalue(e_originator, 1);
        }
      } else {
        self notify("investigate", self.origin, undefined, "quick");
      }
    }
  }
}

function on_alert_changed(eventpackage) {
  eventinterestpos = self geteventpointofinterest();
  v_origin = eventinterestpos;
  e_originator = self getcurrenteventoriginator();
  i_id = self getcurrenteventid();
  str_typename = self getcurrenteventtypename();
  str_newalert = eventpackage.parms[0];
  if(isDefined(str_typename) && str_typename == "grenade_ping") {
    str_newalert = "combat";
  }
  if(str_newalert == "low_alert") {
    str_newalert = "high_alert";
  }
  if(isDefined(eventpackage.parms[1])) {
    v_origin = eventpackage.parms[1];
  }
  if(isDefined(eventpackage.parms[2])) {
    e_originator = eventpackage.parms[2];
  }
  if(stealth::awareness_delta(str_newalert, self get_awareness()) >= 0) {
    if(isDefined(v_origin)) {
      if(!isDefined(eventinterestpos) || distancesquared(v_origin, eventinterestpos) > 0.1) {
        deltaorigin = v_origin - self.origin;
        deltaangles = vectortoangles(deltaorigin);
        self.react_yaw = absangleclamp360(self.angles[1] - deltaangles[1]);
      }
      if(isactor(self)) {
        if(str_newalert == "combat" && isDefined(e_originator)) {
          self thread react_head_look(e_originator, 0.5);
        } else {
          self thread react_head_look(v_origin, 0.5);
        }
      }
    }
    debugreason = self getcurrenteventtypename() + self getcurrenteventname();
    if(!isDefined(debugreason) || debugreason == "") {
      debugreason = "";
    }
    if(isDefined(e_originator) && iscorpse(e_originator)) {
      debugreason = "";
    }
    if(eventpackage.parms.size > 1) {
      debugreason = eventpackage.parms[eventpackage.parms.size - 1];
    }
    if(isDefined(debugreason) && isstring(debugreason)) {
      self.stealth.debug_reason = debugreason;
    }
    if(str_typename == "explosion") {
      self notify("stealth_vo", "explosion");
    } else if(isDefined(e_originator) && iscorpse(e_originator)) {
      self notify("stealth_vo", "corpse");
    }
    self set_awareness(str_newalert);
    switch (str_newalert) {
      case "high_alert":
      case "low_alert": {
        self notify("investigate", v_origin, e_originator);
        break;
      }
    }
    if(isDefined(i_id) && isDefined(e_originator) && iscorpse(e_originator)) {
      self thread delayed_service_event(8, i_id);
    }
    if(isPlayer(e_originator) && str_newalert == "combat" && level.stealth.var_e7ad9c1f == 0) {
      if(isDefined(self.blindaim) && self.blindaim) {
        e_originator stealth_vo::function_e3ae87b3("spotted_sniper", self, 2);
      } else {
        if(isvehicle(self)) {
          e_originator stealth_vo::function_e3ae87b3("spotted_drone", self, 2);
        } else {
          e_originator stealth_vo::function_e3ae87b3("spotted", self, 2);
        }
      }
    }
  }
  if(isDefined(e_originator) && self stealth::is_enemy(e_originator)) {
    self.stealth.aware_alerted[e_originator getentitynumber()] = e_originator;
    if(str_newalert == "combat") {
      self enter_combat_with(e_originator);
    }
  }
}

function function_101ac5(eventpackage) {
  e_originator = eventpackage.parms[0];
  if(!isentity(e_originator)) {
    return;
  }
  if(stealth::awareness_delta(self.awarenesslevelcurrent, self.awarenesslevelprevious) > 0) {
    self notify("alert", "combat", e_originator.origin, e_originator, "close_combat");
  }
}

function function_933965f6(eventpackage) {
  e_originator = eventpackage.parms[0];
  var_62bc230d = eventpackage.parms[1];
  if(self.awarenesslevelcurrent != "unaware") {
    return;
  }
  if(!isentity(e_originator)) {
    return;
  }
  if(!isentity(var_62bc230d)) {
    return;
  }
  if(stealth::awareness_delta(self.awarenesslevelcurrent, self.awarenesslevelprevious) > 0) {
    if(isDefined(self.stealth.var_c9b747e1) && (gettime() - self.stealth.var_c9b747e1) < 30000) {
      return;
    }
    goalpos = var_62bc230d getfinalpathpos();
    delta = goalpos - var_62bc230d.origin;
    if(lengthsquared(delta) > 250000) {
      var_fbbdb5f6 = var_62bc230d.origin + (vectornormalize(delta) * 500);
      deltaorigin = var_62bc230d.origin - self.origin;
      deltaangles = vectortoangles(deltaorigin);
      self.react_yaw = absangleclamp360(self.angles[1] - deltaangles[1]);
      self notify("investigate", var_fbbdb5f6, e_originator, "quick");
      self.stealth.var_c9b747e1 = gettime();
    }
  }
}

function alert_group(group, str_newalert, v_origin, e_originator) {
  group = getaiarray(group, "script_aigroup");
  maxdistsq = getdvarint("stealth_group_radius", 1000);
  maxdistsq = maxdistsq * maxdistsq;
  foreach(guy in group) {
    if(guy == self) {
      continue;
    }
    if(!isalive(guy)) {
      continue;
    }
    if(distancesquared(guy.origin, self.origin) > maxdistsq) {
      continue;
    }
    if(stealth::awareness_delta(str_newalert, guy get_awareness()) <= 0) {
      continue;
    }
    guy util::delay_notify(randomfloatrange(0.33, 0.66), "alert", undefined, str_newalert, v_origin, e_originator);
  }
}

function react_head_look(lookat, delay) {
  self notify("react_head_look");
  self endon("react_head_look");
  ent = lookat;
  if(!isentity(lookat)) {
    if(!isDefined(self.stealth_head_look_ent)) {
      self.stealth_head_look_ent = spawn("script_model", lookat);
    }
    ent = self.stealth_head_look_ent;
  } else if(isDefined(self.stealth_head_look_ent)) {
    self.stealth_head_look_ent delete();
    self.stealth_head_look_ent = undefined;
  }
  starttime = gettime();
  delayms = delay * 1000;
  wait(0.2);
  while(isalive(self) && (isDefined(self.stealth_reacting) && self.stealth_reacting)) {
    if((gettime() - starttime) >= delayms) {
      self lookatentity(ent);
      if(stealth_debug::enabled()) {
        line(self getEye(), ent.origin + vectorscale((0, 0, 1), 20), (0, 0, 1), 1, 1, 1);
        debugstar(ent.origin + vectorscale((0, 0, 1), 20), 1, (0, 0, 1));
      }
    }
    wait(0.05);
  }
  if(isDefined(self)) {
    self lookatentity();
    if(isDefined(self.stealth_head_look_ent)) {
      self.stealth_head_look_ent delete();
      self.stealth_head_look_ent = undefined;
    }
  }
}

function delayed_service_event(delay, id) {
  self endon("death");
  wait(delay);
  self serviceevent(id);
}

function on_witness_combat(eventpackage) {
  self endon("death");
  e_attacker = eventpackage.parms[0];
  debugreason = eventpackage.parms[1];
  if(isDefined(e_attacker)) {
    if(stealth::awareness_delta(self get_awareness(), "high_alert") < 0) {
      self notify("alert", "high_alert", e_attacker.origin, e_attacker, debugreason);
    }
  }
}

function combat_alert_event(e_attacker) {
  self endon("death");
  if(isDefined(e_attacker) && self enabled()) {
    wait(randomfloatrange(0.25, 0.75));
    self enter_combat_with(e_attacker);
  }
}

function enter_combat_with(enemy) {
  if(!self enabled()) {
    return;
  }
  if(!isDefined(enemy) || !self stealth::is_enemy(enemy)) {
    return;
  }
  self stealth_behavior::investigate_stop();
  self stopanimscripted();
  enemyentnum = enemy getentitynumber();
  self set_awareness("combat");
  self set_ignore_sentient(enemy, 0);
  if(!isDefined(self.stealth.aware_combat[enemyentnum])) {
    self.stealth.aware_combat[enemyentnum] = enemy;
    self.stealth.aware_alerted[enemyentnum] = enemy;
    self thread combat_spread_thread(enemy);
    self notify("stealth_vo", "enemy");
  }
  if(issentient(enemy)) {
    self setstealthsightvalue(enemy, 1);
  }
  self ai_sniper::actor_lase_stop();
  if(isPlayer(enemy) && getdvarint("stealth_all_aware")) {
    foreach(player in level.activeplayers) {
      if(player == enemy) {
        continue;
      }
      playerentnum = player getentitynumber();
      if(!isDefined(self.stealth.aware_combat[playerentnum])) {
        enter_combat_with(player);
      }
    }
  }
}

function combat_spread_thread(enemy) {
  self notify("combat_spread_thread_" + enemy getentitynumber());
  self endon("combat_spread_thread_" + enemy getentitynumber());
  self endon("death");
  idletime = 0;
  while(true) {
    wait(0.5);
    if(!isDefined(enemy) || enemy.health <= 0 || self get_awareness() != "combat" || (isDefined(self.silenced) && self.silenced)) {
      break;
    }
    self stealth_event::broadcast_to_team(self.team, self.origin, 200, 100, 0, "combat_spread", "combat", enemy, self);
    self stealth_event::broadcast_to_team(self.team, self.origin, 400, 300, 1, "combat_interest", enemy, self);
    if(!isDefined(self.enemy) || !self stealth::can_see(self.enemy)) {
      self setstealthsightawareness(self.awarenesslevelcurrent, 1);
    } else {
      self setstealthsightawareness(self.awarenesslevelcurrent, 0);
    }
  }
  self setstealthsightawareness(self.awarenesslevelcurrent, 1);
}

function function_a85b6c52() {
  self endon("death");
  while(true) {
    self waittill("enemy");
    while(isDefined(self.enemy) && isalive(self.enemy)) {
      if(isDefined(self.enemy.civilian) && self.enemy.civilian || (isDefined(self.enemy.lase_override) && (isDefined(self.enemy.lase_override.civilian) && self.enemy.lase_override.civilian))) {
        self.avoid_cover = 1;
        self.silentshot = 1;
      } else {
        self.avoid_cover = undefined;
        self.silentshot = 0;
      }
      wait(0.05);
    }
    self notify("stealth_sight_end", self.enemy);
  }
}