/** ** Auto attack nearby units if possible */ static void AutoAttack(CUnit *unit, bool stand_ground) { CUnit *temp; CUnit *goal; if (unit->Wait) { unit->Wait--; return; } // Cowards don't attack unless ordered. if (unit->Type->CanAttack && !unit->Type->Coward) { // Normal units react in reaction range. if (CanMove(unit) && !unit->Removed && !stand_ground) { if ((goal = AttackUnitsInReactRange(unit))) { // Weak goal, can choose other unit, come back after attack CommandAttack(unit, goal->X, goal->Y, NULL, FlushCommands); Assert(unit->SavedOrder.Action == UnitActionStill); Assert(!unit->SavedOrder.Goal); unit->SavedOrder.Action = UnitActionAttack; unit->SavedOrder.Range = 0; unit->SavedOrder.X = unit->X; unit->SavedOrder.Y = unit->Y; unit->SavedOrder.Goal = NoUnitP; } else { unit->Wait = 15; } // Removed units can only attack in AttackRange, from bunker } else if ((goal = AttackUnitsInRange(unit))) { temp = unit->Orders[0]->Goal; if (temp && temp->Orders[0]->Action == UnitActionDie) { temp->RefsDecrease(); unit->Orders[0]->Goal = temp = NoUnitP; } if (!unit->SubAction || temp != goal) { // New target. if (temp) { temp->RefsDecrease(); } unit->Orders[0]->Goal = goal; goal->RefsIncrease(); unit->State = 0; unit->SubAction = 1; // Mark attacking. UnitHeadingFromDeltaXY(unit, goal->X + (goal->Type->TileWidth - 1) / 2 - unit->X, goal->Y + (goal->Type->TileHeight - 1) / 2 - unit->Y); } return; } } else { unit->Wait = 15; } if (unit->SubAction) { // was attacking. if ((temp = unit->Orders[0]->Goal)) { temp->RefsDecrease(); unit->Orders[0]->Goal = NoUnitP; } unit->SubAction = unit->State = 0; // No attacking, restart } Assert(!unit->Orders[0]->Goal); }
void AiForce::Insert(CUnit &unit) { Units.Insert(&unit); unit.RefsIncrease(); }
/** ** Fire missile. ** ** @param unit Unit that fires the missile. */ void FireMissile(CUnit *unit) { int x; int y; int dx; int dy; CUnit *goal; Missile *missile; // // Goal dead? // goal = unit->Orders[0]->Goal; if (goal) { // Better let the caller/action handle this. if (goal->Destroyed) { DebugPrint("destroyed unit\n"); return; } if (goal->Removed || goal->Orders[0]->Action == UnitActionDie) { return; } // FIXME: Some missile hit the field of the target and all units on it. // FIXME: goal is already dead, but missile could hit others? } // // No missile hits immediately! // if (unit->Type->Missile.Missile->Class == MissileClassNone) { // No goal, take target coordinates if (!goal) { DebugPrint("Missile-none hits no unit, shouldn't happen!\n"); return; } HitUnit(unit, goal, CalculateDamage(unit, goal)); return; } // If Firing from inside a Bunker if (unit->Container) { x = unit->Container->X * TileSizeX + TileSizeX / 2; // missile starts in tile middle y = unit->Container->Y * TileSizeY + TileSizeY / 2; } else { x = unit->X * TileSizeX + TileSizeX / 2; // missile starts in tile middle y = unit->Y * TileSizeY + TileSizeY / 2; } if (goal) { Assert(goal->Type); // Target invalid? // // Moved out of attack range? // if (MapDistanceBetweenUnits(unit, goal) < unit->Type->MinAttackRange) { DebugPrint("Missile target too near %d,%d\n" _C_ MapDistanceBetweenUnits(unit, goal) _C_ unit->Type->MinAttackRange); // FIXME: do something other? return; } // Fire to nearest point of the unit! // If Firing from inside a Bunker if (unit->Container) { NearestOfUnit(goal, unit->Container->X, unit->Container->Y, &dx, &dy); } else { NearestOfUnit(goal, unit->X, unit->Y, &dx, &dy); } } else { dx = unit->Orders[0]->X; dy = unit->Orders[0]->Y; // FIXME: Can this be too near?? } // Fire to the tile center of the destination. dx = dx * TileSizeX + TileSizeX / 2; dy = dy * TileSizeY + TileSizeY / 2; missile = MakeMissile(unit->Type->Missile.Missile, x, y, dx, dy); // // Damage of missile // if (goal) { missile->TargetUnit = goal; goal->RefsIncrease(); } missile->SourceUnit = unit; unit->RefsIncrease(); }