/*************************************************
 * Decompiled by Serious and Edited by SyndiShanX
 * Script: shared\clientfaceanim_shared.csc
*************************************************/

#using scripts\codescripts\struct;
#using scripts\shared\array_shared;
#using scripts\shared\callbacks_shared;
#using scripts\shared\system_shared;
#using scripts\shared\util_shared;
#namespace clientfaceanim;

function autoexec __init__sytem__() {
  system::register("clientfaceanim_shared", undefined, &main, undefined);
}

function main() {
  callback::on_spawned(&on_player_spawned);
  level._clientfaceanimonplayerspawned = &on_player_spawned;
}

function private on_player_spawned(localclientnum) {
  facialanimationsinit(localclientnum);
  self callback::on_shutdown(&on_player_shutdown);
  self thread on_player_death(localclientnum);
}

function private on_player_shutdown(localclientnum) {
  if(self isPlayer()) {
    self notify("stopfacialthread");
    corpse = self getplayercorpse();
    if(!isDefined(corpse)) {
      return;
    }
    if(isDefined(corpse.facialdeathanimstarted) && corpse.facialdeathanimstarted) {
      return;
    }
    corpse util::waittill_dobj(localclientnum);
    if(isDefined(corpse)) {
      corpse applydeathanim(localclientnum);
      corpse.facialdeathanimstarted = 1;
    }
  }
}

function private on_player_death(localclientnum) {
  self endon("entityshutdown");
  self waittill("death");
  if(self isPlayer()) {
    self notify("stopfacialthread");
    corpse = self getplayercorpse();
    if(isDefined(corpse.facialdeathanimstarted) && corpse.facialdeathanimstarted) {
      return;
    }
    corpse util::waittill_dobj(localclientnum);
    if(isDefined(corpse)) {
      corpse applydeathanim(localclientnum);
      corpse.facialdeathanimstarted = 1;
    }
  }
}

function private facialanimationsinit(localclientnum) {
  buildandvalidatefacialanimationlist(localclientnum);
  if(self isPlayer()) {
    self thread facialanimationthink(localclientnum);
  }
}

function buildandvalidatefacialanimationlist(localclientnum) {
  if(!isDefined(level.__clientfacialanimationslist)) {
    level.__clientfacialanimationslist = [];
    level.__clientfacialanimationslist["combat"] = array("ai_face_male_generic_idle_1", "ai_face_male_generic_idle_2", "ai_face_male_generic_idle_3");
    level.__clientfacialanimationslist["combat_shoot"] = array("ai_face_male_aim_fire_1", "ai_face_male_aim_fire_2", "ai_face_male_aim_fire_3");
    level.__clientfacialanimationslist["death"] = array("ai_face_male_death_1", "ai_face_male_death_2", "ai_face_male_death_3");
    level.__clientfacialanimationslist["melee"] = array("ai_face_male_melee_1");
    level.__clientfacialanimationslist["pain"] = array("ai_face_male_pain_1");
    level.__clientfacialanimationslist["swimming"] = array("mp_face_male_swim_idle_1");
    level.__clientfacialanimationslist["jumping"] = array("mp_face_male_jump_idle_1");
    level.__clientfacialanimationslist["sliding"] = array("mp_face_male_slides_1");
    level.__clientfacialanimationslist["sprinting"] = array("mp_face_male_sprint_1");
    level.__clientfacialanimationslist["wallrunning"] = array("mp_face_male_wall_run_1");
    deathanims = level.__clientfacialanimationslist["death"];
    foreach(deathanim in deathanims) {
      assert(!isanimlooping(localclientnum, deathanim), ("" + deathanim) + "");
    }
  }
}

function private facialanimationthink_getwaittime(localclientnum) {
  if(!isDefined(localclientnum)) {
    return 1;
  }
  min_wait = 0.1;
  max_wait = 1;
  min_wait_distance_sq = 2500;
  max_wait_distance_sq = 640000;
  local_player = getlocalplayer(localclientnum);
  if(!isDefined(local_player)) {
    return max_wait;
  }
  if(local_player == self && !isthirdperson(localclientnum)) {
    return max_wait;
  }
  distancesq = distancesquared(local_player.origin, self.origin);
  if(distancesq > max_wait_distance_sq) {
    distance_factor = 1;
  } else {
    if(distancesq < min_wait_distance_sq) {
      distance_factor = 0;
    } else {
      distance_factor = (distancesq - min_wait_distance_sq) / (max_wait_distance_sq - min_wait_distance_sq);
    }
  }
  return ((max_wait - min_wait) * distance_factor) + min_wait;
}

function private facialanimationthink(localclientnum) {
  self endon("entityshutdown");
  self notify("stopfacialthread");
  self endon("stopfacialthread");
  if(isDefined(self.__clientfacialanimationsthinkstarted)) {
    return;
  }
  self.__clientfacialanimationsthinkstarted = 1;
  assert(self isPlayer());
  self util::waittill_dobj(localclientnum);
  while(isDefined(self)) {
    updatefacialanimforplayer(localclientnum, self);
    wait_time = self facialanimationthink_getwaittime(localclientnum);
    if(!isDefined(wait_time)) {
      wait_time = 1;
    }
    wait(wait_time);
  }
}

function private updatefacialanimforplayer(localclientnum, player) {
  if(!isDefined(player)) {
    return;
  }
  if(!isDefined(localclientnum)) {
    return;
  }
  if(!isDefined(player._currentfacestate)) {
    player._currentfacestate = "inactive";
  }
  currfacestate = player._currentfacestate;
  nextfacestate = player._currentfacestate;
  if(player isinscritpedanim()) {
    clearallfacialanims(localclientnum);
    player._currentfacestate = "inactive";
    return;
  }
  if(player isplayerdead()) {
    nextfacestate = "death";
  } else {
    if(player isplayerfiring()) {
      nextfacestate = "combat_shoot";
    } else {
      if(player isplayersliding()) {
        nextfacestate = "sliding";
      } else {
        if(player isplayerwallrunning()) {
          nextfacestate = "wallrunning";
        } else {
          if(player isplayersprinting()) {
            nextfacestate = "sprinting";
          } else {
            if(player isplayerjumping() || player isplayerdoublejumping()) {
              nextfacestate = "jumping";
            } else {
              if(player isplayerswimming()) {
                nextfacestate = "swimming";
              } else {
                nextfacestate = "combat";
              }
            }
          }
        }
      }
    }
  }
  if(player._currentfacestate == "inactive" || currfacestate != nextfacestate) {
    assert(isDefined(level.__clientfacialanimationslist[nextfacestate]));
    applynewfaceanim(localclientnum, array::random(level.__clientfacialanimationslist[nextfacestate]));
    player._currentfacestate = nextfacestate;
  }
}

function private applynewfaceanim(localclientnum, animation) {
  clearallfacialanims(localclientnum);
  if(isDefined(animation)) {
    self._currentfaceanim = animation;
    self setflaggedanimknob("ai_secondary_facial_anim", animation, 1, 0.1, 1);
  }
}

function private applydeathanim(localclientnum) {
  if(isDefined(self._currentfacestate) && self._currentfacestate == "death") {
    return;
  }
  if(isDefined(self) && isDefined(level.__clientfacialanimationslist) && isDefined(level.__clientfacialanimationslist["death"])) {
    self._currentfacestate = "death";
    applynewfaceanim(localclientnum, array::random(level.__clientfacialanimationslist["death"]));
  }
}

function private clearallfacialanims(localclientnum) {
  if(isDefined(self._currentfaceanim) && self hasdobj(localclientnum)) {
    self clearanim(self._currentfaceanim, 0.2);
  }
  self._currentfaceanim = undefined;
}