private void ensureTargetVitals(Attack.TargetType targetType, String entityId, String zone) {
   if (targetType == Attack.TargetType.Character) {
     VitalsHandler.ensure(entityId, zone);
   } else if (targetType == Attack.TargetType.Object) {
     VitalsHandler.ensure(entityId, Vitals.VitalsType.Object, zone);
   } else if (targetType == Attack.TargetType.BuildObject) {
     VitalsHandler.ensure(entityId, Vitals.VitalsType.BuildObject, zone);
   } else {
     throw new RuntimeException("Invalid target type " + targetType);
   }
 }
  private void doAttack(Attack attack) {
    boolean sendToObjectGrid = false;
    boolean sendToDefaultGrid = false;

    Zone zone = PlayerService.getInstance().getZone(playerId);
    if (attack.playerSkill == null) {
      logger.warning("Attack without player skill, ignoring");
      return;
    }

    if (Strings.isNullOrEmpty(attack.attackerCharacterId)) {
      logger.warning("Attack without attackerCharacterId, ignoring");
      return;
    }

    logger.warning(
        "Attack "
            + attack.attackerCharacterId
            + " "
            + attack.targetId
            + " skill "
            + attack.playerSkill.id);

    StatusEffectTarget statusEffectTarget = new StatusEffectTarget();
    VitalsHandler.ensure(playerId, zone.name);

    statusEffectTarget.attack = attack;

    statusEffectTarget.originCharacterId = attack.attackerCharacterId;
    statusEffectTarget.originEntityId = playerId;

    if (attack.playerSkill.category == PlayerSkill.Category.SingleTarget) {
      if (Strings.isNullOrEmpty(attack.targetId)) {
        logger.warning("SingleTarget with no targetId");
        return;
      } else {
        Character character = CharacterService.instance().find(attack.targetId);

        // No character = Object/vehicle/etc..
        if (character == null) {
          if (BuildObjectHandler.exists(attack.targetId)) {
            attack.targetType = Attack.TargetType.BuildObject;
          } else {
            attack.targetType = Attack.TargetType.Object;
          }
          statusEffectTarget.targetEntityId = attack.targetId;
          sendToObjectGrid = true;
        } else {
          attack.targetType = Attack.TargetType.Character;
          statusEffectTarget.targetEntityId = character.playerId;
          sendToDefaultGrid = true;
        }

        ensureTargetVitals(attack.targetType, statusEffectTarget.targetEntityId, zone.name);
      }

    } else if (attack.playerSkill.category == PlayerSkill.Category.Self) {
      attack.targetType = Attack.TargetType.Character;
      statusEffectTarget.targetEntityId = playerId;
      ensureTargetVitals(attack.targetType, statusEffectTarget.targetEntityId, zone.name);
      sendToDefaultGrid = true;

    } else if (attack.playerSkill.category == PlayerSkill.Category.Aoe
        || attack.playerSkill.category == PlayerSkill.Category.AoeDot) {
      if (attack.targetLocation == null) {
        logger.warning("Aoe without targetLocation");
        return;
      }

      statusEffectTarget.location = attack.targetLocation;
      sendToObjectGrid = true;
      sendToDefaultGrid = true;

    } else if (attack.playerSkill.category == PlayerSkill.Category.Pbaoe) {

      Grid grid = GridService.getInstance().getGrid(zone.name, "default");

      TrackData td = grid.get(playerId);
      if (td == null) {
        logger.warning("TrackData not found for " + playerId);
        return;
      }

      statusEffectTarget.location = new GmVector3();
      statusEffectTarget.location.xi = td.x;
      statusEffectTarget.location.yi = td.y;
      statusEffectTarget.location.zi = td.z;

      sendToObjectGrid = true;
      sendToDefaultGrid = true;
    } else {
      logger.warning("Invalid damage type");
      return;
    }

    if (sendToDefaultGrid) {
      StatusEffectManager.tell("default", zone.name, statusEffectTarget.clone(), getSelf());
    }

    if (sendToObjectGrid) {
      StatusEffectManager.tell("build_objects", zone.name, statusEffectTarget.clone(), getSelf());
    }

    sendAttack(attack, zone.name);
  }