#include "main.h"


void cheat_actor_teleport(struct actor_info *info, const float pos[3], int interior_id)
{
   if(info == NULL)
      return;
   vect3_copy(pos, &info->base.matrix[4*3]);
   gta_interior_id_set(interior_id);
}


void cheat_handle_actor_autoaim(struct actor_info *info, float time_diff)
{
   static int prev_id;


   if(KEY_PRESSED(set.key_autoaim))
   {
      cheat_state->actor.autoaim ^= 1;
      prev_id = -1;
   }

   if(cheat_state->actor.autoaim)
   {
      static float adj_rx, adj_rz, prev_rx, prev_rz;
      float rx = *(float *)0x00B6F248;
      float rz = *(float *)0x00B6F258;

      int nearest_id = actor_find_nearest(ACTOR_ALIVE);
      struct actor_info *nearest;
      float vect[3], ax, az;


      if(nearest_id == -1)
      {
         cheat_state_text("No players found; auto aim disabled.");
         cheat_state->actor.autoaim = 0;
         return;
      }

      if(nearest_id == prev_id)
      {
         adj_rx += rx - prev_rx;
         adj_rz += rz - prev_rz;
      }
      prev_id = nearest_id;

      if((nearest = actor_info_get(nearest_id, ACTOR_ALIVE)) == NULL)
         return;  /* won't happen */

      /*cheat_state_text("%.3f %.3f %d %d", adj_rx, adj_rz, nearest->state, nearest->state_running);*/

      /* calculate distance vector */
      vect3_vect3_sub(&nearest->base.matrix[4*3], &info->base.matrix[4*3], vect);

      /* z angle */
      az = atan2f(vect[0], vect[1]);
      /* rotate around z axis */
      vect[1] = sinf(az) * vect[0] + cosf(az) * vect[1];
      /* x angle */
      ax = atan2f(vect[1], vect[2]);

      ax = -ax + M_PI / 2.0f + adj_rx;
      az = -az - M_PI / 2.0f + adj_rz;

      if(ax < -M_PI)
         ax = -M_PI;
      else if(ax > M_PI)
         ax = M_PI;

      /* XXX make function */
      prev_rx = *(float *)0x00B6F248 = ax;
      prev_rz = *(float *)0x00B6F258 = az;
   }
}


void cheat_handle_actor_air_brake(struct actor_info *info, float time_diff)
{
   static float orig_pos[3];
   static float fall_speed_mult;
   static int was_enabled;


   if(set.air_brake_toggle)
   {
      if(KEY_PRESSED(set.key_air_brake_foot_mod))
         cheat_state->actor.air_brake ^= 1;

      if(KEY_PRESSED(set.key_air_brake_mod2) && cheat_state->actor.air_brake)
         cheat_state->actor.air_brake_slowmo ^= 1;
   }
   else
   {
      if(KEY_PRESSED(set.key_air_brake_foot_mod))
         cheat_state->actor.air_brake = 1;
      else if(KEY_RELEASED(set.key_air_brake_foot_mod))
         cheat_state->actor.air_brake = 0;

      if(KEY_PRESSED(set.key_air_brake_mod2) && cheat_state->actor.air_brake)
         cheat_state->actor.air_brake_slowmo = 1;
      else if(KEY_RELEASED(set.key_air_brake_mod2) && cheat_state->actor.air_brake)
         cheat_state->actor.air_brake_slowmo = 0;
   }

   if(!was_enabled && cheat_state->actor.air_brake)
   {
      vect3_copy(&info->base.matrix[4*3], orig_pos);
      fall_speed_mult = 1.0f;
      was_enabled = 1;
   }

   if(!cheat_state->actor.air_brake)
      was_enabled = 0;


   #define PARACHUTE_ACTIVE (info->weapon_slot == 11 && info->weapon[11].id == 46)

   if(cheat_state->actor.air_brake)
   {
      /* prevent movement */
      if(!PARACHUTE_ACTIVE)
      {
         vect3_copy(orig_pos, &info->base.matrix[4*3]);
         vect3_zero(info->speed);
         if(samp_get_version() == SAMP_VERSION_1)
         {
            info->animation_state1 = 0x03;
            info->animation_state2 = 0x20;
         }
      }
   }
   else
   {
      cheat_state->actor.air_brake = 0;
      cheat_state->actor.air_brake_slowmo = 0;
   }

   if(cheat_state->actor.air_brake)
   {
      float *matrix = info->base.matrix;

      if(!PARACHUTE_ACTIVE)
      {
         static uint32_t time_start;
         float d[4] = { 0.0f, 0.0f, 0.0f, time_diff * set.air_brake_speed };

         if(cheat_state->actor.air_brake_slowmo)
            d[3] /= 10.0f;

         if(KEY_DOWN(set.key_air_brake_forward))   d[0] += 1.0f;
         if(KEY_DOWN(set.key_air_brake_backward))  d[0] -= 1.0f;
         if(KEY_DOWN(set.key_air_brake_left))      d[1] += 1.0f;
         if(KEY_DOWN(set.key_air_brake_right))     d[1] -= 1.0f;
         if(KEY_DOWN(set.key_air_brake_up))        d[2] += 1.0f;
         if(KEY_DOWN(set.key_air_brake_down))      d[2] -= 1.0f;

         if(!near_zero(set.air_brake_accel_time))
         {
            if(!vect3_near_zero(d))
               time_start = (time_start == 0) ? time_get() : time_start;
            else
               time_start = 0;   /* no keys pressed */

            /* acceleration */
            if(time_start != 0)
            {
               float t = TIME_TO_FLOAT(time_get() - time_start);
               if(t < set.air_brake_accel_time)
                  d[3] *= t / set.air_brake_accel_time;
            }
         }

         if(!vect3_near_zero(d))
         {
            float vect[4] = { -d[1], d[0], d[2], 0.0f };
            float out[4];

            /* out = matrix * norm(d) */
            vect3_normalize(vect, vect);
            matrix_vect4_mult(matrix, vect, out);

            matrix[4*3+0] += out[0] * d[3];
            matrix[4*3+1] += out[1] * d[3];
            matrix[4*3+2] += out[2] * d[3];
         }
      }
      else /* PARACHUTE_ACTIVE */
      {
         if(KEY_DOWN(set.key_air_brake_up))   fall_speed_mult += time_diff / 2.0f;
         if(KEY_DOWN(set.key_air_brake_down)) fall_speed_mult -= time_diff / 2.0f;

         if(fall_speed_mult < 0.0f)
            fall_speed_mult = 0.0f;
         else if(fall_speed_mult > 2.0f)
            fall_speed_mult = 2.0f;

         matrix[4*3+0] += info->speed[0] * time_diff * set.air_brake_speed;
         matrix[4*3+1] += info->speed[1] * time_diff * set.air_brake_speed;
         matrix[4*3+2] -= (matrix[4*3+2] - orig_pos[2]) * fall_speed_mult;
      }

      vect3_copy(&matrix[4*3], orig_pos);
   }
}

