gcc_pure NearestAirspace NearestAirspace::FindHorizontal(const MoreData &basic, const ProtectedAirspaceWarningManager &airspace_warnings, const Airspaces &airspace_database) { if (!basic.location_available) /* can't check for airspaces without a GPS fix */ return NearestAirspace(); /* find the nearest airspace */ //consider only active airspaces const auto outside_and_active = MakeAndPredicate(ActiveAirspacePredicate(&airspace_warnings), OutsideAirspacePredicate(AGeoPoint(basic.location, 0))); //if altitude is available, filter airspaces in same height as airplane if (basic.NavAltitudeAvailable()) { /* check altitude; hard-coded margin of 50m (for now) */ const auto outside_and_active_and_height = MakeAndPredicate(outside_and_active, AirspacePredicateHeightRange(basic.nav_altitude - 50, basic.nav_altitude + 50)); const auto predicate = WrapAirspacePredicate(outside_and_active_and_height); return ::FindHorizontal(basic.location, airspace_database, predicate); } else { /* only filter outside and active */ const auto predicate = WrapAirspacePredicate(outside_and_active); return ::FindHorizontal(basic.location, airspace_database, predicate); } }
void AirspaceRoute::Synchronise(const Airspaces &master, const AirspacePredicate &_condition, const AGeoPoint &origin, const AGeoPoint &destination) { // @todo: also synchronise with AirspaceWarningManager to filter out items that are // acknowledged. h_min = std::min((int)origin.altitude, std::min((int)destination.altitude, h_min)); h_max = std::max((int)origin.altitude, std::max((int)destination.altitude, h_max)); // @todo: have margin for h_max to allow for climb AirspacePredicateHeightRangeExcludeTwo h_condition(h_min, h_max, origin, destination); const auto and_condition = MakeAndPredicate(h_condition, AirspacePredicateRef(_condition)); const auto predicate = WrapAirspacePredicate(and_condition); if (m_airspaces.SynchroniseInRange(master, origin.Middle(destination), 0.5 * origin.Distance(destination), predicate)) { if (!m_airspaces.IsEmpty()) dirty = true; } }
/** ** Check if the unit's container has an adjacent unit owned by another non-neutral player ** ** @return true if the unit is now sheltered (or if exited a shelter), false otherwise */ static bool LeaveShelter(CUnit &unit) { if ( !unit.Container || (unit.Container->Type->BoolFlag[ATTACKFROMTRANSPORTER_INDEX].value && unit.Type->BoolFlag[ATTACKFROMTRANSPORTER_INDEX].value) || (!unit.Player->AiEnabled && !(unit.Type->BoolFlag[FAUNA_INDEX].value && unit.Player->Type == PlayerNeutral)) || unit.Container->CanMove() //is a transporter, not a shelter || !unit.Container->Type->CanTransport() //is not a garrisonable building || (unit.Container->Type->BoolFlag[RECRUITHEROES_INDEX].value && unit.Character && unit.Player->Type == PlayerNeutral) //if is a hireable hero in a hero recruitment building, don't leave it ) { return false; } std::vector<CUnit *> table; if (unit.Type->BoolFlag[FAUNA_INDEX].value) { SelectAroundUnit(*unit.Container, 1, table, HasNotSamePlayerAs(*unit.Player)); } else { SelectAroundUnit(*unit.Container, unit.CurrentSightRange, table, MakeAndPredicate(IsEnemyWith(*unit.Player), HasNotSamePlayerAs(Players[PlayerNumNeutral]))); } if (table.size() > 0) { CommandUnload(*unit.Container, unit.Container->tilePos, &unit, FlushCommands, unit.Container->MapLayer->ID); return true; } return false; }
/** ** Attack units in distance. ** ** If the unit can attack must be handled by caller. ** Choose the best target, that can be attacked. ** ** @param unit Find in distance for this unit. ** @param range Distance range to look. ** @param onlyBuildings Search only buildings (useful when attacking with AI force) ** ** @return Unit to be attacked. */ CUnit *AttackUnitsInDistance(const CUnit &unit, int range, CUnitFilter pred) { // if necessary, take possible damage on allied units into account... if (unit.Type->Missile.Missile->Range > 1 && (range + unit.Type->Missile.Missile->Range < 15)) { // If catapult, count units near the target... // FIXME : make it configurable int missile_range = unit.Type->Missile.Missile->Range + range - 1; Assert(2 * missile_range + 1 < 32); // If unit is removed, use containers x and y const CUnit *firstContainer = unit.Container ? unit.Container : &unit; std::vector<CUnit *> table; SelectAroundUnit(*firstContainer, missile_range, table, MakeAndPredicate(HasNotSamePlayerAs(Players[PlayerNumNeutral]), pred)); if (table.empty() == false) { return BestRangeTargetFinder(unit, range).Find(table); } return NULL; } else { // If unit is removed, use containers x and y const CUnit *firstContainer = unit.Container ? unit.Container : &unit; std::vector<CUnit *> table; SelectAroundUnit(*firstContainer, range, table, MakeAndPredicate(HasNotSamePlayerAs(Players[PlayerNumNeutral]), pred)); const int n = static_cast<int>(table.size()); if (range > 25 && table.size() > 9) { std::sort(table.begin(), table.begin() + n, CompareUnitDistance(unit)); } // Find the best unit to attack return BestTargetFinder(unit).Find(table); } }
/** ** Cast capture. ** ** @param caster Unit that casts the spell ** @param spell Spell-type pointer ** @param target Target unit that spell is addressed to ** @param goalPos coord of target spot when/if target does not exist ** ** @return =!0 if spell should be repeated, 0 if not */ /* virtual */ int Spell_Capture::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &/*goalPos*/) { if (!target || caster.Player == target->Player) { return 0; } if (this->DamagePercent) { if ((100 * target->Variable[HP_INDEX].Value) / target->Variable[HP_INDEX].Max > this->DamagePercent && target->Variable[HP_INDEX].Value > this->Damage) { HitUnit(&caster, *target, this->Damage); if (this->SacrificeEnable) { // No corpse. caster.Remove(NULL); caster.Release(); } return 1; } } caster.Player->Score += target->Variable[POINTS_INDEX].Value; if (caster.IsEnemy(*target)) { if (target->Type->Building) { caster.Player->TotalRazings++; } else { caster.Player->TotalKills++; } //Wyrmgus start caster.Player->UnitTypeKills[target->Type->Slot]++; /* if (UseHPForXp) { caster.Variable[XP_INDEX].Max += target->Variable[HP_INDEX].Value; } else { caster.Variable[XP_INDEX].Max += target->Variable[POINTS_INDEX].Value; } caster.Variable[XP_INDEX].Value = caster.Variable[XP_INDEX].Max; */ //distribute experience between nearby units belonging to the same player if (!target->Type->BoolFlag[BUILDING_INDEX].value) { std::vector<CUnit *> table; SelectAroundUnit(caster, 6, table, MakeAndPredicate(HasSamePlayerAs(*caster.Player), IsNotBuildingType())); if (UseHPForXp) { caster.Variable[XP_INDEX].Max += target->Variable[HP_INDEX].Value / (table.size() + 1); } else { caster.Variable[XP_INDEX].Max += target->Variable[POINTS_INDEX].Value / (table.size() + 1); } caster.Variable[XP_INDEX].Value = caster.Variable[XP_INDEX].Max; caster.XPChanged(); for (size_t i = 0; i != table.size(); ++i) { if (UseHPForXp) { table[i]->Variable[XP_INDEX].Max += target->Variable[HP_INDEX].Value / (table.size() + 1); } else { table[i]->Variable[XP_INDEX].Max += target->Variable[POINTS_INDEX].Value / (table.size() + 1); } table[i]->Variable[XP_INDEX].Value = table[i]->Variable[XP_INDEX].Max; table[i]->XPChanged(); } } //Wyrmgus end caster.Variable[KILL_INDEX].Value++; caster.Variable[KILL_INDEX].Max++; caster.Variable[KILL_INDEX].Enable = 1; } target->ChangeOwner(*caster.Player); UnitClearOrders(*target); if (this->JoinToAIForce && caster.Player->AiEnabled) { int force = caster.Player->Ai->Force.GetForce(caster); if (force != -1) { caster.Player->Ai->Force[force].Insert(*target); target->GroupId = caster.GroupId; CommandDefend(*target, caster, FlushCommands); } } if (this->SacrificeEnable) { // No corpse. caster.Remove(NULL); caster.Release(); } else { caster.Variable[MANA_INDEX].Value -= spell.ManaCost; } return 0; }