| 395 | } |
| 396 | |
| 397 | void EntityAI::PositionPilot(float& speedWanted, float& headChange, float& turnPredict, Vector3Par pos, Vector3Par dir, |
| 398 | float precision) |
| 399 | { |
| 400 | AIUnit* unit = PilotUnit(); |
| 401 | |
| 402 | // control vehicle to get to given position |
| 403 | // default: no speed limit |
| 404 | _limitSpeed = GetType()->GetMaxSpeedMs() * 1.5; |
| 405 | float dist2 = pos.Distance2(Position()); |
| 406 | |
| 407 | saturateMin(precision, floatMax(4, GetPrecision())); |
| 408 | float limit = precision; |
| 409 | if (!_inFormation) |
| 410 | { |
| 411 | limit *= 0.5; |
| 412 | } |
| 413 | else |
| 414 | { |
| 415 | limit *= 2; |
| 416 | } |
| 417 | |
| 418 | if (dist2 < Square(limit)) |
| 419 | { |
| 420 | // in position - turn to direction |
| 421 | _inFormation = true; |
| 422 | speedWanted = 0; |
| 423 | if (_fire._fireTarget) |
| 424 | { |
| 425 | Vector3Val tgtDir = PositionWorldToModel(_fire._fireTarget->AimingPosition()); |
| 426 | headChange = atan2(tgtDir.X(), tgtDir.Z()); |
| 427 | } |
| 428 | else |
| 429 | { |
| 430 | Vector3Val relMoveDir = DirectionWorldToModel(dir); |
| 431 | headChange = atan2(relMoveDir.X(), relMoveDir.Z()); |
| 432 | if (fabs(headChange) < 0.05 && GetStopped()) |
| 433 | { |
| 434 | EngineOff(); |
| 435 | } |
| 436 | } |
| 437 | } |
| 438 | else |
| 439 | { |
| 440 | // out of position |
| 441 | _inFormation = false; |
| 442 | // check if trivial solution is good enough |
| 443 | |
| 444 | // check if we are already there |
| 445 | // find nearest empry position |
| 446 | Vector3 freePos = pos; |
| 447 | unit->FindNearestEmpty(freePos); |
| 448 | |
| 449 | dist2 = freePos.Distance2(Position()); |
| 450 | |
| 451 | if (dist2 < Square(limit)) |
| 452 | { |
| 453 | // we cannot be in formation - in-formation position is not free |
| 454 | _inFormation = true; |
nothing calls this directly
no test coverage detected