@Override
  public void addHealthBarToAnim(Races race) {
    //		if( Settings.yourBaseMode )
    //			return;

    if (buildingAnim != null) {
      if (getTeamName() == Teams.BLUE) {
        healthBar = new Bar(getLQ().getHealthObj());
        buildingAnim.add(healthBar, true);
        Paint nonDistOverPaint = Palette.getPaint(Align.CENTER, Color.RED, Rpg.getTextSize());
        healthBar.setBarPaint(nonDistOverPaint);
        healthBar.setTextPaint(nonDistOverPaint);
      } else {
        float yOffs = 12 * Rpg.getDp();

        Image img = getImage();
        if (img != null) yOffs = img.getHeightDiv2() + Rpg.twoDp;

        healthBar = new Bar(getLQ().getHealthObj(), -8 * Rpg.getDp(), -yOffs);
        buildingAnim.add(healthBar, true);
        Paint nonDistOverPaint = Palette.getPaint(Align.CENTER, Color.RED, Rpg.getTextSize());
        healthBar.setBarPaint(nonDistOverPaint);
      }

      healthBar.setShowCurrentAndMax(false);

      if (race == Races.UNDEAD) healthBar.setColor(Color.BLACK);
    }
  }
  @Override
  public void checkHit(@Nullable vector inDirection) {
    // System.out.println("MeleeAttack: checkHit() starting");
    if (possibleVictum != null
        && owner.loc.distanceSquared(possibleVictum.loc) < Rpg.getMeleeAttackRangeSquared()) {
      possibleVictum.takeDamage(owner.getDamage(), owner);
      return;
    }

    if (inDirection != null) {
      checkHitHere.set(inDirection);
      checkHitHere.times(Rpg.getMeleeAttackRange()).add(owner.loc);

      // Log.d( "MeleeAttack" , "checkHit(): checkHitHere = " + checkHitHere);

      inThisArea.set(weaponStrikePercArea);

      inThisArea.offset(checkHitHere.x, checkHitHere.y);

      // Log.d( "MeleeAttack" , "inThisArea=" + inThisArea);
      // System.out.println("owner.getTeam()=" + owner.getTeam());

      possibleVictum = cd.checkSingleHit(owner.getTeamName(), inThisArea);

      if (possibleVictum != null) {
        possibleVictum.takeDamage(owner.getDamage(), owner);

        if (weapon.wasDrawnThisFrame()) playHitSound(weaponType, owner.loc.x, owner.loc.y);
      } else {
        if (weapon.wasDrawnThisFrame()) playMissSound(weaponType, owner.loc.x, owner.loc.y);
      }
    }

    // System.out.println("MeleeAttack: checkHit() ending");
  }
  static {
    float dp = Rpg.getDp();
    imageFormatInfo = new ImageFormatInfo(0, 0, 0, 0, 1, 1);

    staticAttackerQualities = new AttackerQualities();

    staticAttackerQualities.setStaysAtDistanceSquared(0);
    staticAttackerQualities.setFocusRangeSquared(5000 * dp * dp);
    staticAttackerQualities.setAttackRangeSquared(Rpg.getMeleeAttackRangeSquared());
    staticAttackerQualities.setDamage(60);
    staticAttackerQualities.setdDamageAge(0);
    staticAttackerQualities.setdDamageLvl(5);
    staticAttackerQualities.setROF(1000);

    STATIC_ATTRIBUTES = new Attributes();
    STATIC_ATTRIBUTES.setRequiresBLvl(10);
    STATIC_ATTRIBUTES.setRequiresAge(Age.STEEL);
    STATIC_ATTRIBUTES.setRequiresTcLvl(16);
    STATIC_ATTRIBUTES.setLevel(1);
    STATIC_ATTRIBUTES.setFullHealth(800);
    STATIC_ATTRIBUTES.setHealth(800);
    STATIC_ATTRIBUTES.setdHealthAge(0);
    STATIC_ATTRIBUTES.setdHealthLvl(30);
    STATIC_ATTRIBUTES.setFullMana(0);
    STATIC_ATTRIBUTES.setMana(0);
    STATIC_ATTRIBUTES.setHpRegenAmount(1);
    STATIC_ATTRIBUTES.setRegenRate(1000);
    STATIC_ATTRIBUTES.setArmor(10);
    STATIC_ATTRIBUTES.setdArmorAge(0);
    STATIC_ATTRIBUTES.setdArmorLvl(2);
    STATIC_ATTRIBUTES.setSpeed(2.3f * dp);
  }
  protected List<SButton> getAllOrderButtons(List<? extends Humanoid> selectedHumanoids) {
    Game kc = Rpg.getGame();

    allOrderButtons.clear();
    orders.clear();
    orderTypes.clear();

    if (selectedHumanoids == null) return allOrderButtons;

    for (LivingThing lt : selectedHumanoids)
      if (lt.getPossibleOrders() != null) orders.addAll(lt.getPossibleOrders());

    List<? extends Humanoid> unitsOrdering = selectedHumanoids;

    OrderButton abButton;

    for (Order o : orders) {
      if (orderTypes.contains(o.getOrderType())) continue;

      abButton =
          OrderButton.getInstance(kc.getActivity(), o, null, unitsOrdering, ui.getSoldierOrders());

      allOrderButtons.add(abButton);

      orderTypes.add(o.getOrderType());
    }

    return allOrderButtons;
  }
  protected List<SButton> getAllOrderButtons(Humanoid selectedHumanoid) {
    Game kc = Rpg.getGame();

    allOrderButtons.clear();
    orders.clear();
    orderTypes.clear();

    if (selectedHumanoid != null)
      if (selectedHumanoid.getPossibleOrders() != null)
        orders.addAll(selectedHumanoid.getPossibleOrders());

    ArrayList<Humanoid> unitsOrdering = null;

    for (Order o : orders) {
      if (orderTypes.contains(o.getOrderType())) continue;

      OrderButton abButton =
          OrderButton.getInstance(
              kc.getActivity(), o, selectedHumanoid, unitsOrdering, ui.getSoldierOrders());

      allOrderButtons.add(abButton);

      orderTypes.add(o.getOrderType());
    }

    return allOrderButtons;
  }
 @Override
 public RectF getStaticPerceivedArea() {
   if (staticPerceivedArea == null) {
     float sizeDiv2 = Rpg.getDp() * 30;
     staticPerceivedArea = new RectF(-sizeDiv2, -sizeDiv2, sizeDiv2, sizeDiv2);
   }
   return staticPerceivedArea;
 }
  protected List<SButton> determineIfAndWhatToDisplay(List<? extends Humanoid> lts) {
    Game game = Rpg.getGame();
    Level level = game.getLevel();

    lt = null;
    this.lts = lts;

    if (lts == null || lts.isEmpty()) return null;

    ArrayList<SButton> buttons = new ArrayList<>();

    buttons.addAll(getAllOrderButtons(lts));
    buttons.addAll(getAllAbilityButtons(lts));

    Team team = level.getMM().getTeam(lts.get(0).getTeamName());

    return buttons;
  }
  protected List<SButton> getAllAbilityButtons(Humanoid selectedHumanoid) {
    Game kc = Rpg.getGame();
    allAbilityButtons.clear();

    abilities.clear();
    abilitiesTypes.clear();

    if (selectedHumanoid != null) abilities.addAll(selectedHumanoid.getAbilities());

    for (Ability ab : abilities) {
      if (abilitiesTypes.contains(ab.getAbility())) continue;

      AbilityButton abButton = AbilityButton.getInstance(kc.getActivity(), ab, ac);
      allAbilityButtons.add(abButton);
      abilitiesTypes.add(ab.getAbility());
    }

    return allAbilityButtons;
  }
  protected List<SButton> determineIfAndWhatToDisplay(Humanoid lt) {
    Game game = Rpg.getGame();
    Level level = game.getLevel();

    this.lt = lt;
    lts = null;

    if (lt == null) return null;

    List<SButton> buttons = new ArrayList<>();

    buttons.addAll(getAllOrderButtons(lt));
    buttons.addAll(getAllAbilityButtons(lt));

    // Team team = level.getMM().getTeam( lt.getTeamName() );

    //		if( Settings.yourBaseMode && lt instanceof Humanoid && !(lt instanceof Worker)){
    //
    //			buttons.add( AddToArmyButton.getInstance( game , (Humanoid) lt ,  team.getArmy() ,
    // team.getArmyManager() ));
    //		}

    return buttons;
  }
public class MeleeAttack extends Attack {

  @NonNull private final AttackAnimator weapon;

  private static final RectF weaponStrikePercArea =
      new RectF(-8 * Rpg.getDp(), -8 * Rpg.getDp(), 8 * Rpg.getDp(), 8 * Rpg.getDp());

  @NonNull private final vector checkHitHere;

  @NonNull private final RectF inThisArea;

  @Nullable private LivingThing possibleVictum;

  private final MeleeTypes weaponType;

  private final CD cd;

  public MeleeAttack(
      @NonNull MM mm, @NonNull Humanoid owner, @NonNull MeleeTypes weaponType, CD cd) {
    super(mm, owner);
    this.weaponType = weaponType;
    switch (weaponType) {
      default:
        weapon = new MeleeAnimator(owner, weaponType, this);
        break;
      case PickAxe:
        weapon = new PickAxeAnimator(owner, this);
        break;
      case Axe:
        weapon = new AxeAnimator(owner, this);
        break;
    }
    this.cd = cd;
    checkHitHere = new vector();
    inThisArea = new RectF();
  }

  public MeleeAttack(@NonNull MM mm, @NonNull Humanoid owner, CD cd) {
    super(mm, owner);

    if (Math.random() < 0.25) {
      this.weaponType = MeleeTypes.LongSword;
      weapon = new MeleeAnimator(owner, weaponType, this);
    } else if (Math.random() < 0.5) {
      this.weaponType = MeleeTypes.Sabre;
      weapon = new MeleeAnimator(owner, weaponType, this);
    } else if (Math.random() < 0.75) {
      this.weaponType = MeleeTypes.Axe;
      weapon = new AxeAnimator(owner, this);
    } else {
      this.weaponType = MeleeTypes.PickAxe;
      weapon = new PickAxeAnimator(owner, this);
    }

    this.cd = cd;
    inThisArea = new RectF();
    checkHitHere = new vector();
    // ManagerManager.getInstance().getEm().add(weapon,true);
  }

  @Override
  public void attack(vector inDirection) {
    weapon.attack(inDirection);
    doAttackAt = GameTime.getTime() + weapon.getTimeFromAttackStartTillDoAttack();
  }

  @Override
  public void attackFromUnitVector(vector unitVector) {
    weapon.attackFromUnitVector(unitVector);
  }

  @Override
  public boolean attack(LivingThing target) {
    possibleVictum = target;
    weapon.attack();
    doAttackAt = GameTime.getTime() + weapon.getTimeFromAttackStartTillDoAttack();
    return true;
  }

  @Override
  public void checkHit(@Nullable vector inDirection) {
    // System.out.println("MeleeAttack: checkHit() starting");
    if (possibleVictum != null
        && owner.loc.distanceSquared(possibleVictum.loc) < Rpg.getMeleeAttackRangeSquared()) {
      possibleVictum.takeDamage(owner.getDamage(), owner);
      return;
    }

    if (inDirection != null) {
      checkHitHere.set(inDirection);
      checkHitHere.times(Rpg.getMeleeAttackRange()).add(owner.loc);

      // Log.d( "MeleeAttack" , "checkHit(): checkHitHere = " + checkHitHere);

      inThisArea.set(weaponStrikePercArea);

      inThisArea.offset(checkHitHere.x, checkHitHere.y);

      // Log.d( "MeleeAttack" , "inThisArea=" + inThisArea);
      // System.out.println("owner.getTeam()=" + owner.getTeam());

      possibleVictum = cd.checkSingleHit(owner.getTeamName(), inThisArea);

      if (possibleVictum != null) {
        possibleVictum.takeDamage(owner.getDamage(), owner);

        if (weapon.wasDrawnThisFrame()) playHitSound(weaponType, owner.loc.x, owner.loc.y);
      } else {
        if (weapon.wasDrawnThisFrame()) playMissSound(weaponType, owner.loc.x, owner.loc.y);
      }
    }

    // System.out.println("MeleeAttack: checkHit() ending");
  }

  public void checkHit(@Nullable LivingThing target) {
    if (target == null) return;

    if (owner.loc.distanceSquared(target.loc) < owner.getAQ().getAttackRangeSquared())
      target.takeDamage(owner.getDamage(), owner);
  }

  @Override
  public void removeAnim() {
    weapon.setOver(true);
  }

  @NonNull
  @Override
  public Anim getAnimator() {
    return weapon;
  }

  private long doAttackAt;

  @Override
  public void act() {
    if (doAttackAt < GameTime.getTime()) {
      doAttack();
      doAttackAt = Long.MAX_VALUE;
    }
  }

  private void doAttack() {
    checkHit(weapon.getAttackingInDirectionUnitVector());
  }

  private static void playHitSound(@Nullable MeleeTypes weaponType, float x, float y) {
    if (weaponType == null) return;

    switch (weaponType) {
      case Mace:
      case Sabre:
      case LongSword:
        SpecialEffects.playHitSound(x, y);
        return;

      case Hammer:
        SpecialEffects.playHammerSound(x, y);
        return;

      case Axe:
        SpecialEffects.playAxeSound(x, y);
        return;

      case Hoe:
        return;

      case PickAxe:
        SpecialEffects.playPickaxeSound(x, y);
        return;

      default:
        return;
    }
  }

  private static void playMissSound(@Nullable MeleeTypes weaponType, float x, float y) {
    if (weaponType == null) return;

    switch (weaponType) {
      case Mace:
      case Sabre:
      case LongSword:
        SpecialEffects.playMissSound(x, y);
        return;

      case Hammer:
        SpecialEffects.playHammerSound(x, y);
        return;

      case Axe:
        SpecialEffects.playAxeSound(x, y);
        return;

      case Hoe:
        return;

      case PickAxe:
        SpecialEffects.playPickaxeSound(x, y);
        return;

      default:
        return;
    }
  }
}
 @Override
 public RectF getStaticPerceivedArea() {
   return Rpg.getNormalPerceivedArea();
 }