void DoTargetedCommand(int x, int y, Unit *target, int fow_unit) { if (!*bw::is_targeting) return; EndTargeting(); int16_t order, error = -1; bool can_attack = false, can_cast_spell = false, has_energy = false; if (target) order = *bw::unit_order_id; else if (fow_unit != Unit::None) order = *bw::obscured_unit_order_id; else order = *bw::ground_order_id; int targeting_weapon = orders_dat_targeting_weapon[order]; int weapon_targeting = orders_dat_use_weapon_targeting[order]; int energy = 0, tech = orders_dat_energy_tech[order]; if (tech != Tech::None) energy = techdata_dat_energy_cost[tech] * 256; if (orders_dat_obscured[order] == Order::None) fow_unit = Unit::None; for (unsigned i = 0; i < Limits::Selection; i++) { Unit *unit = bw::client_selection_group[i]; if (!unit) break; if (unit->IsDisabled()) continue; if (weapon_targeting) { if (targeting_weapon == Weapon::None) { if (!target) { if (unit->unit_id == Unit::InfestedTerran || unit->CanAttackFowUnit(fow_unit)) can_attack = true; } else { if (unit->GetRClickAction() == RightClickAction::Attack) // sieged tank, towerit, etc { if (IsOutOfRange(unit, target)) { error = String::Error_OutOfRange; continue; } else if (IsTooClose(unit, target)) { error = String::Error_TooClose; continue; } } can_attack |= unit->CanAttackUnit(target, true); } } else { if (!CanHitUnit(target, unit, targeting_weapon) && (fow_unit != Unit::None || units_dat_flags[fow_unit] & UnitFlags::Invincible)) { continue; } if (!NeedsMoreEnergy(unit, energy)) has_energy = true; can_attack = true; } } else if (tech != Tech::None) { if (CanTargetSpell(unit, x, y, &error, tech, target, fow_unit)) { if (!NeedsMoreEnergy(unit, energy)) has_energy = true; can_cast_spell = true; } } else if (fow_unit == Unit::None) { CanTargetOrder(unit, target, order, &error); // Not checking anything, just to get error } else { CanTargetOrderOnFowUnit(unit, fow_unit, order, &error); // Same } } Unit *unit = *bw::selection_rank_order; if (weapon_targeting) { if (!can_attack || error != -1) { GetAttackErrorMessage(target, targeting_weapon, &error); ShowInfoMessage(error, Sound::Error_Zerg + unit->GetRace(), unit->player); if (targeting_weapon == Weapon::None) SendTargetedOrderCommand(order, x, y, target, fow_unit, *bw::is_queuing_command); // So it'll move there anyways return; } else if (energy && !has_energy) { int race = unit->GetRace(); ShowInfoMessage(String::NotEnoughEnergy + race, Sound::NotEnoughEnergy + race, unit->player); return; } } else if (energy) { if (!can_cast_spell) { if (error == -1) error = String::Error_InvalidTarget; ShowErrorMessage((*bw::stat_txt_tbl)->GetTblString(error), *bw::command_user, unit); return; } else if (/*energy && */!has_energy) { int race = unit->GetRace(); ShowInfoMessage(String::NotEnoughEnergy + race, Sound::NotEnoughEnergy + race, unit->player); return; } } if (error != -1) { ShowErrorMessage((*bw::stat_txt_tbl)->GetTblString(error), unit->player, unit); } else { PlayYesSoundAnim(bw::selection_rank_order[0]); SendTargetedOrderCommand(order, x, y, target, fow_unit, *bw::is_queuing_command); } }