/** ** 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; }
/** ** Death-Coil class. Damages organic units and gives to the caster. ** ** @todo do it configurable. */ void MissileDeathCoil::Action() { this->Wait = this->Type->Sleep; if (PointToPointMissile(*this)) { Assert(this->SourceUnit != NULL); CUnit &source = *this->SourceUnit; if (source.Destroyed) { return; } // source unit still exists // // Target unit still exists and casted on a special target // if (this->TargetUnit && !this->TargetUnit->Destroyed && this->TargetUnit->CurrentAction() == UnitActionDie) { HitUnit(&source, *this->TargetUnit, this->Damage); if (source.CurrentAction() != UnitActionDie) { source.Variable[HP_INDEX].Value += this->Damage; if (source.Variable[HP_INDEX].Value > source.Variable[HP_INDEX].Max) { source.Variable[HP_INDEX].Value = source.Variable[HP_INDEX].Max; } } } else { // // No target unit -- try enemies in range 5x5 // Must be parametrable // std::vector<CUnit *> table; const Vec2i destPos = Map.MapPixelPosToTilePos(this->destination); const Vec2i range(2, 2); Select(destPos - range, destPos + range, table, IsEnemyWith(*source.Player)); if (table.empty()) { return; } const size_t n = table.size(); // enemy count const int damage = std::min<int>(1, this->Damage / n); // disperse damage between them for (size_t i = 0; i != n; ++i) { HitUnit(&source, *table[i], damage); } if (source.CurrentAction() != UnitActionDie) { source.Variable[HP_INDEX].Value += this->Damage; if (source.Variable[HP_INDEX].Value > source.Variable[HP_INDEX].Max) { source.Variable[HP_INDEX].Value = source.Variable[HP_INDEX].Max; } } } this->TTL = 0; } }