#pragma once
#include "dark-info.hpp"
#include "enity/particle/prt.hpp"
#include "enity/bullet/blt.hpp"
#define info_cast(dst) auto dst = rcast(const Dark_info*, p_info)
//! чёрный бумер
class Plr_dark: public Plr {
public:
  Plr_dark() = default;
  ~Plr_dark() { free(); }
  Counter shoot_cldwn = {}; ///< таймер задержки обычного выстрела
  Counter shoot_side_cldwn = {}; ///< задержка выстрелов по сторонам
  Counter shoot_back_cldwn = {}; ///< задержка выстрелов назад
  Vec camera_old = {}; ///< сейв камеры сцены для эффекта тряски
  bool left_side = false; ///< определяет, с какой стороны будет следующий выстрел
  void init() override {
    Plr::init();
    info_cast(info);
    en = Bar(info->en, info->en);
    reset();
  }
  void reset() override {
    Plr::reset();
    info_cast(info);
    hp = info->hp;
    en.val = en.size;
    shoot_cldwn.set_count(info->SHOOT_CLDWN);
    shoot_side_cldwn.set_count(info->SHOOT_SIDE_CLDWN);
    shoot_back_cldwn.set_count(info->SHOOT_BACK_CLDWN);
    smoke.init(smoke_bank::big_plr, {0, 12}); // дым чуть назад от игрока
  }
private:
  nocopy(Plr_dark);
  void free() {}
  bool draw(Image& dst, CN(Vec) offset) const override
    { return Plr::draw(dst, offset); }
  bool update(float dt, uint update_idx) override {
    update_jolt(dt);
    if ( !update_physic(dt, update_idx))
      return false;
    update_input(dt);
    update_shoot(dt);
    update_lines();
    update_smoke();
    info_cast(info);
    en.add(info->en_reg * dt); // реген маны
    return true;
  } // updste
protected:
  void update_input(float dt); ///< обновляет управление и движение
  void left(float dt);
  void right(float dt);
  void up(float dt);
  void down(float dt);
  void update_shoot(float dt);
  void update_main_shoot(float dt); ///< выстрел пряимо
  //! быстрые пули игрока
  void make_main_shoot(float dist = 0, float deg_add = 0);
  void make_main_shoot_ext(); ///< усиленные выстрелы прямо
  void update_side_shoot(float dt); ///< выстрел в стороны
  void update_back_shoot(float dt); ///< выстрел выстрел назад
  //! создаёт линии от скорости
  void update_lines() const {
    info_cast(info);
    if ((Game::status & GF_INAIR) and phys.spd >= info->LINES_SPEED) {
      if (Prt* p = add_prt(PRT_SPEED_LINES); p) {
        p->phys.pos = phys.pos;
        p->phys.deg = phys.deg;
        p->flags |= EF_NO_MOVE | EF_R_FRAME_ANY | EF_NO_OFFSET | EF_KILL_TIMER;
        p->blend_mode = BM::blink;
      }
    }
  } // update_lines
  void update_jolt(float dt) {
    info_cast(info);
    plr_shake_offset = make_jolt(Game::game_time);
    plr_jolt = std::clamp(plr_jolt - info->JOLT_DECREASE * dt, 0.0f, 9.0f);
  }
  //! получить вектор тряски
  Vec make_jolt(float game_time) const {
    info_cast(info);
    float len = 0; // смещение от тряски
  // тряска от скорости
    len += std::max(0.f, phys.spd - info->JOLTING_THRESOLD)
      * info->JOLT_RATIO;
    game_time *= 11.0f;
  // тряска от врзывов
    len += plr_jolt * info->JOLT_POWER;
    game_time *= 1.0f + plr_jolt; // ускорение тряски
    len = std::min(len, 36.0f);
  // создание вектора тряски
    float jolt_x = (
      a83::sin(game_time * a83::PI * 0.66666f) +
      a83::sin(game_time * a83::PI * 1.8f) +
      a83::sin(game_time * a83::PI * 2.5f)) * 0.3333333f;
    game_time += 12.34f;
    float jolt_y = (
      a83::cos(game_time * a83::PI * 0.66666f) +
      a83::cos(game_time * a83::PI * 1.8f) +
      a83::cos(game_time * a83::PI * 2.5f)) * 0.3333333f;
    return Vec(jolt_x * len, jolt_y * len);
  } // make_jolt
  //! 1, если есть энергия на мощный выстрел
  bool check_ext() const { 
    info_cast(info);
    return en.val > info->en_ext;
  }
  //! создаёт дым, когда мало hp
  void update_smoke() override {
    info_cast(info);
    if (hp > info->smoke_hp)
      return;
    smoke(phys);
  } // make_smoke
}; // Plr_dark
#include "dark-load.cpp"
#include "dark-input.cpp"
#include "dark-shoot.cpp"
#undef info_cast