* Calculates the new target in voxel space, based on the given accuracy modifier. * @param origin Startposition of the trajectory in voxels. * @param target Endpoint of the trajectory in voxels. * @param accuracy Accuracy modifier. * @param keepRange Whether range affects accuracy. * @param targetTile Tile of target. Default = 0. * @param extendLine should this line get extended to maximum d
| 243 | * @param extendLine should this line get extended to maximum distance? |
| 244 | */ |
| 245 | void Projectile::applyAccuracy(const Position& origin, Position *target, double accuracy, bool keepRange, Tile *targetTile, bool extendLine) |
| 246 | { |
| 247 | int xdiff = origin.x - target->x; |
| 248 | int ydiff = origin.y - target->y; |
| 249 | double realDistance = sqrt((double)(xdiff*xdiff)+(double)(ydiff*ydiff)); |
| 250 | // maxRange is the maximum range a projectile shall ever travel in voxel space |
| 251 | double maxRange = keepRange?realDistance:16*1000; // 1000 tiles |
| 252 | maxRange = _action.type == BA_HIT?46:maxRange; // up to 2 tiles diagonally (as in the case of reaper v reaper) |
| 253 | RuleItem *weapon = _action.weapon->getRules(); |
| 254 | |
| 255 | if (_action.type != BA_THROW && _action.type != BA_HIT) |
| 256 | { |
| 257 | double modifier = 0.0; |
| 258 | int upperLimit = weapon->getAimRange(); |
| 259 | int lowerLimit = weapon->getMinRange(); |
| 260 | if (Options::battleUFOExtenderAccuracy) |
| 261 | { |
| 262 | if (_action.type == BA_AUTOSHOT) |
| 263 | { |
| 264 | upperLimit = weapon->getAutoRange(); |
| 265 | } |
| 266 | else if (_action.type == BA_SNAPSHOT) |
| 267 | { |
| 268 | upperLimit = weapon->getSnapRange(); |
| 269 | } |
| 270 | } |
| 271 | if (realDistance / 16 < lowerLimit) |
| 272 | { |
| 273 | modifier = (weapon->getDropoff() * (lowerLimit - realDistance / 16)) / 100; |
| 274 | } |
| 275 | else if (upperLimit < realDistance / 16) |
| 276 | { |
| 277 | modifier = (weapon->getDropoff() * (realDistance / 16 - upperLimit)) / 100; |
| 278 | } |
| 279 | accuracy = std::max(0.0, accuracy - modifier); |
| 280 | } |
| 281 | |
| 282 | int xDist = abs(origin.x - target->x); |
| 283 | int yDist = abs(origin.y - target->y); |
| 284 | int zDist = abs(origin.z - target->z); |
| 285 | int xyShift, zShift; |
| 286 | |
| 287 | if (xDist / 2 <= yDist) //yes, we need to add some x/y non-uniformity |
| 288 | xyShift = xDist / 4 + yDist; //and don't ask why, please. it's The Commandment |
| 289 | else |
| 290 | xyShift = (xDist + yDist) / 2; //that's uniform part of spreading |
| 291 | |
| 292 | if (xyShift <= zDist) //slight z deviation |
| 293 | zShift = xyShift / 2 + zDist; |
| 294 | else |
| 295 | zShift = xyShift + zDist / 2; |
| 296 | |
| 297 | int deviation = RNG::generate(0, 100) - (accuracy * 100); |
| 298 | |
| 299 | if (deviation >= 0) |
| 300 | deviation += 50; // add extra spread to "miss" cloud |
| 301 | else |
| 302 | deviation += 10; //accuracy of 109 or greater will become 1 (tightest spread) |
nothing calls this directly
no test coverage detected