00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <tankai/TankAICurrentMove.h>
00022 #include <tankai/TankAIAimGuesser.h>
00023 #include <tankai/TankAISniperGuesser.h>
00024 #include <coms/ComsPlayedMoveMessage.h>
00025 #include <coms/ComsDefenseMessage.h>
00026 #include <common/Logger.h>
00027 #include <server/ServerShotHolder.h>
00028 #include <server/ServerDefenseHandler.h>
00029 #include <server/ScorchedServer.h>
00030 #include <tank/Tank.h>
00031 #include <tank/TankLib.h>
00032 #include <tank/TankPosition.h>
00033 #include <tank/TankAccessories.h>
00034 #include <target/TargetLife.h>
00035 #include <target/TargetShield.h>
00036 #include <target/TargetParachute.h>
00037 #include <landscapemap/LandscapeMaps.h>
00038 #include <landscapemap/MovementMap.h>
00039 #include <landscapemap/GroundMaps.h>
00040 #include <weapons/AccessoryStore.h>
00041 #include <weapons/Shield.h>
00042 #include <weapons/WeaponMoveTank.h>
00043 #include <XML/XMLNode.h>
00044
00045 TankAICurrentMove::TankAICurrentMove() :
00046 useResign_(true), useFuel_(true),
00047 totalDamageBeforeMove_(0.0f),
00048 movementDamage_(300.0f), movementDamageChance_(0.3f), movementLife_(75.0f),
00049 movementRandom_(10.0f), movementCloseness_(15.0f),
00050 groupShotSize_(2), groupShotChance_(0.7f), groupTargetDistance_(25.0f),
00051 resignLife_(10.0f),
00052 largeWeaponUseDistance_(10.0f),
00053 sniperUseDistance_(80.0f),
00054 sniperStartDistance_(10.0f), sniperEndDistance_(0.0f),
00055 sniperMinDecrement_(2.0f), sniperMaxDecrement_(5.0f),
00056 sniperMovementFactor_(4.0f),
00057 projectileStartDistance_(10.0f), projectileEndDistance_(5.0f),
00058 projectileMinDecrement_(1.0f), projectileMaxDecrement_(4.0f),
00059 projectileMovementFactor_(10.0f), projectileMinDistance_(10.0f)
00060 {
00061 }
00062
00063 TankAICurrentMove::~TankAICurrentMove()
00064 {
00065 }
00066
00067 bool TankAICurrentMove::parseConfig(XMLNode *node)
00068 {
00069 {
00070 XMLNode *targets = 0;
00071 if (!node->getNamedChild("targets", targets)) return false;
00072 if (!targets_.parseConfig(targets)) return false;
00073 }
00074 {
00075 XMLNode *resign = 0;
00076 if (!node->getNamedChild("resign", resign)) return false;
00077 if (!resign->getNamedChild("useresign", useResign_)) return false;
00078 if (!resign->getNamedChild("resignlife", resignLife_)) return false;
00079 if (!resign->failChildren()) return false;
00080 }
00081 {
00082 XMLNode *movement = 0;
00083 if (!node->getNamedChild("movement", movement)) return false;
00084 if (!movement->getNamedChild("usefuel", useFuel_)) return false;
00085 if (!movement->getNamedChild("movementdamage", movementDamage_)) return false;
00086 if (!movement->getNamedChild("movementdamagechance", movementDamageChance_)) return false;
00087 if (!movement->getNamedChild("movementlife", movementLife_)) return false;
00088 if (!movement->getNamedChild("movementrandom", movementRandom_)) return false;
00089 if (!movement->getNamedChild("movementcloseness", movementCloseness_)) return false;
00090 if (!movement->failChildren()) return false;
00091 }
00092 {
00093 XMLNode *groupshot = 0;
00094 if (!node->getNamedChild("groupshot", groupshot)) return false;
00095 if (!groupshot->getNamedChild("groupshotsize", groupShotSize_)) return false;
00096 if (!groupshot->getNamedChild("groupshotchance", groupShotChance_)) return false;
00097 if (!groupshot->getNamedChild("grouptargetdistance", groupTargetDistance_)) return false;
00098 if (!groupshot->failChildren()) return false;
00099 }
00100 {
00101 XMLNode *sniper = 0;
00102 if (!node->getNamedChild("sniper", sniper)) return false;
00103 if (!sniper->getNamedChild("snipermovementfactor", sniperMovementFactor_)) return false;
00104 if (!sniper->getNamedChild("sniperusedistance", sniperUseDistance_)) return false;
00105 if (!sniper->getNamedChild("sniperstartdistance", sniperStartDistance_)) return false;
00106 if (!sniper->getNamedChild("sniperenddistance", sniperEndDistance_)) return false;
00107 if (!sniper->getNamedChild("snipermindecrement", sniperMinDecrement_)) return false;
00108 if (!sniper->getNamedChild("snipermaxdecrement", sniperMaxDecrement_)) return false;
00109 if (!sniper->failChildren()) return false;
00110 }
00111 {
00112 XMLNode *projectile = 0;
00113 if (!node->getNamedChild("projectile", projectile)) return false;
00114 if (!projectile->getNamedChild("projectilemindistance", projectileMinDistance_)) return false;
00115 if (!projectile->getNamedChild("projectilemovementfactor", projectileMovementFactor_)) return false;
00116 if (!projectile->getNamedChild("projectilestartdistance", projectileStartDistance_)) return false;
00117 if (!projectile->getNamedChild("projectileenddistance", projectileEndDistance_)) return false;
00118 if (!projectile->getNamedChild("projectilemindecrement", projectileMinDecrement_)) return false;
00119 if (!projectile->getNamedChild("projectilemaxdecrement", projectileMaxDecrement_)) return false;
00120 if (!projectile->getNamedChild("largeweaponusedistance", largeWeaponUseDistance_)) return false;
00121 if (!projectile->failChildren()) return false;
00122 }
00123
00124 return node->failChildren();
00125 }
00126
00127 void TankAICurrentMove::clear()
00128 {
00129 totalDamageBeforeMove_ = 0.0f;
00130 shotRecords_.clear();
00131 }
00132
00133 void TankAICurrentMove::playMove(Tank *tank,
00134 TankAIWeaponSets::WeaponSet *weapons, bool useBatteries)
00135 {
00136 std::list<Tank *> sortedTanks;
00137
00138
00139
00140 targets_.getTargets(tank, sortedTanks);
00141
00142
00143 float totalDamage =
00144 targets_.getTotalDamageTaken() - totalDamageBeforeMove_;
00145 if (totalDamage > movementDamage_ &&
00146 RAND <= movementDamageChance_)
00147 {
00148
00149 if (useBatteries)
00150 {
00151 useAvailableBatteries(tank);
00152 }
00153
00154 if (tank->getLife().getLife().asFloat() > movementLife_)
00155 {
00156
00157 if (makeMoveShot(tank, weapons, sortedTanks)) return;
00158 }
00159 }
00160
00161
00162 if (RAND <= groupShotChance_)
00163 {
00164 if (makeGroupShot(tank, weapons, sortedTanks)) return;
00165 }
00166
00167
00168 while (!sortedTanks.empty())
00169 {
00170
00171 Tank *targetTank = sortedTanks.front();
00172 sortedTanks.pop_front();
00173
00174
00175 TankAICurrentMoveWeapons moveWeapons(tank, targetTank, weapons);
00176
00177
00178 if (shootAtTank(tank, targetTank, moveWeapons)) return;
00179
00180
00181
00182
00183
00184
00185 if (useBatteries &&
00186 tank->getLife().getLife() < tank->getLife().getMaxLife())
00187 {
00188
00189 if (useAvailableBatteries(tank))
00190 {
00191
00192 sortedTanks.push_front(targetTank);
00193 }
00194 }
00195 }
00196
00197
00198
00199 if (tank->getLife().getLife().asFloat() > movementLife_)
00200 {
00201 targets_.getTargets(tank, sortedTanks);
00202 if (makeMoveShot(tank, weapons, sortedTanks)) return;
00203 }
00204
00205
00206
00207 if (useResign_ &&
00208 tank->getLife().getLife().asFloat() < resignLife_)
00209 {
00210 resign(tank);
00211 return;
00212 }
00213
00214
00215
00216 skipMove(tank);
00217 }
00218
00219 bool TankAICurrentMove::shootAtTank(Tank *tank, Tank *targetTank,
00220 TankAICurrentMoveWeapons &weapons)
00221 {
00222
00223 if (makeSniperShot(tank, targetTank, weapons)) return true;
00224
00225
00226 if (makeLaserSniperShot(tank, targetTank, weapons)) return true;
00227
00228
00229 if (makeProjectileShot(tank, targetTank, weapons)) return true;
00230
00231
00232 if (makeBurriedShot(tank, targetTank, weapons)) return true;
00233
00234 return false;
00235 }
00236
00237 bool TankAICurrentMove::makeProjectileShot(Tank *tank, Tank *targetTank,
00238 TankAICurrentMoveWeapons &weapons)
00239 {
00240
00241 if (!weapons.roller &&
00242 !weapons.digger &&
00243 !weapons.napalm &&
00244 !weapons.large &&
00245 !weapons.small) return false;
00246
00247
00248 Vector directTarget = targetTank->getPosition().getTankPosition().asVector();
00249
00250
00251 bool inhole = false;
00252 if (weapons.roller &&
00253 inHole(directTarget))
00254 {
00255 inhole = true;
00256
00257
00258 if (weapons.shield &&
00259 (weapons.shield->getShieldType() == Shield::ShieldTypeRoundReflective ||
00260 weapons.shield->getShieldType() == Shield::ShieldTypeSquareReflective))
00261 {
00262
00263
00264 directTarget = lowestHighest(weapons, directTarget, false);
00265 }
00266 }
00267 else
00268 {
00269
00270 if (weapons.shield &&
00271 (weapons.shield->getShieldType() == Shield::ShieldTypeRoundReflective ||
00272 weapons.shield->getShieldType() == Shield::ShieldTypeSquareReflective))
00273 {
00274
00275
00276 directTarget = lowestHighest(weapons, directTarget, true);
00277 }
00278 }
00279
00280
00281 float tankAimDistance = getShotDistance(targetTank, true);
00282 tankAimDistance -= 5.0f;
00283 if (tankAimDistance < 0.0f) tankAimDistance = 0.0f;
00284
00285
00286
00287 Vector aimPosition = directTarget;
00288 float a = RAND * 3.14f * 2.0f;
00289 aimPosition[0] += sinf(a) * tankAimDistance;
00290 aimPosition[1] += cosf(a) * tankAimDistance;
00291 float aimDistance = MIN(tankAimDistance + 5.0f, 15.0f);
00292
00293
00294 for (float degs=45.0f; degs<=85.0f; degs+=8.0f)
00295 {
00296
00297 Vector actualPosition;
00298 TankAIAimGuesser aimGuesser;
00299 if (aimGuesser.guess(tank, aimPosition, degs, aimDistance, actualPosition))
00300 {
00301
00302 float distanceFromTarget =
00303 (actualPosition - directTarget).Magnitude();
00304 float distanceFromUs =
00305 (actualPosition - tank->getPosition().getTankPosition().asVector()).Magnitude();
00306 if (distanceFromUs < projectileMinDistance_) continue;
00307
00308
00309
00310
00311 if (distanceFromTarget < largeWeaponUseDistance_)
00312 {
00313
00314 if (inhole)
00315 {
00316 setWeapon(tank, weapons.roller);
00317 }
00318 else
00319 {
00320
00321
00322 if (weapons.shield)
00323 {
00324
00325 if (weapons.digger) setWeapon(tank, weapons.digger);
00326 else if (weapons.napalm) setWeapon(tank, weapons.napalm);
00327 else if (weapons.large) setWeapon(tank, weapons.large);
00328 else return false;
00329 }
00330 else
00331 {
00332
00333
00334 if (weapons.digger) setWeapon(tank, weapons.digger);
00335 else if (weapons.large) setWeapon(tank, weapons.large);
00336 else if (weapons.small) setWeapon(tank, weapons.small);
00337 else return false;
00338 }
00339 }
00340 }
00341 else
00342 {
00343
00344 if (weapons.small) setWeapon(tank, weapons.small);
00345 else if (weapons.large) setWeapon(tank, weapons.large);
00346 else return false;
00347 }
00348
00349
00350 shotAtTank(targetTank, true, distanceFromTarget);
00351 fireShot(tank);
00352 return true;
00353 }
00354 }
00355
00356 return false;
00357 }
00358
00359 bool TankAICurrentMove::makeSniperShot(Tank *tank, Tank *targetTank,
00360 TankAICurrentMoveWeapons &weapons)
00361 {
00362
00363 if (!weapons.digger &&
00364 !weapons.laser &&
00365 !weapons.large &&
00366 !weapons.small) return false;
00367
00368
00369 Vector directTarget = targetTank->getPosition().getTankPosition().asVector();
00370
00371
00372
00373 float offset = getShotDistance(targetTank, false);
00374 TankAISniperGuesser sniperGuesser;
00375 if (sniperGuesser.guess(tank, directTarget, sniperUseDistance_, true, offset))
00376 {
00377
00378
00379
00380 if (!weapons.shield ||
00381 (weapons.shield->getShieldType() != Shield::ShieldTypeRoundReflective &&
00382 weapons.shield->getShieldType() != Shield::ShieldTypeSquareReflective))
00383 {
00384
00385 if (weapons.shield)
00386 {
00387
00388 if (weapons.digger) setWeapon(tank, weapons.digger);
00389 else if (weapons.laser) setWeapon(tank, weapons.laser);
00390 else if (weapons.large) setWeapon(tank, weapons.large);
00391 else return false;
00392 }
00393 else
00394 {
00395
00396 if (weapons.digger) setWeapon(tank, weapons.digger);
00397 else if (weapons.large) setWeapon(tank, weapons.large);
00398 else if (weapons.small) setWeapon(tank, weapons.small);
00399 else return false;
00400 }
00401
00402
00403 shotAtTank(targetTank, false, 0.0f);
00404 fireShot(tank);
00405 return true;
00406 }
00407 else if (weapons.laser)
00408 {
00409
00410
00411 shotAtTank(targetTank, false, 0.0f);
00412 fireShot(tank);
00413 return true;
00414 }
00415 }
00416
00417 return false;
00418 }
00419
00420 bool TankAICurrentMove::makeLaserSniperShot(Tank *tank, Tank *targetTank,
00421 TankAICurrentMoveWeapons &weapons)
00422 {
00423
00424 if (!weapons.laser) return false;
00425
00426
00427 Vector directTarget = targetTank->getPosition().getTankPosition().asVector();
00428
00429
00430
00431 float offset = getShotDistance(targetTank, false);
00432 TankAISniperGuesser sniperGuesser;
00433 if (sniperGuesser.guess(tank, directTarget, sniperUseDistance_, false, offset))
00434 {
00435 if (weapons.laser)
00436 {
00437
00438 shotAtTank(targetTank, false, 0.0f);
00439 setWeapon(tank, weapons.laser);
00440 fireShot(tank);
00441 return true;
00442 }
00443 }
00444
00445 return false;
00446 }
00447
00448 bool TankAICurrentMove::makeBurriedShot(Tank *tank, Tank *targetTank,
00449 TankAICurrentMoveWeapons &weapons)
00450 {
00451
00452 if (!weapons.uncover) return false;
00453
00454
00455 fixed xy, yz, power;
00456 TankLib::getSniperShotTowardsPosition(
00457 ScorchedServer::instance()->getContext(),
00458 tank->getPosition().getTankPosition(), targetTank->getPosition().getTankPosition(),
00459 100000, xy, yz, power);
00460
00461
00462 if (TankLib::intersection(
00463 ScorchedServer::instance()->getContext(),
00464 tank->getPosition().getTankGunPosition(),
00465 xy, yz, power, 2))
00466 {
00467
00468 if (weapons.uncover)
00469 {
00470 tank->getPosition().rotateGunXY(xy, false);
00471 tank->getPosition().rotateGunYZ(yz, false);
00472 tank->getPosition().changePower(power, false);
00473
00474 setWeapon(tank, weapons.uncover);
00475 fireShot(tank);
00476 return true;
00477 }
00478 }
00479
00480 return false;
00481 }
00482
00483 bool TankAICurrentMove::inHole(Vector &position)
00484 {
00485
00486 Vector pos = position;
00487 for (;;)
00488 {
00489 Vector lowest = pos;
00490 for (float a=0.0f; a<360.0f; a+=45.0f)
00491 {
00492 float offSetX = sinf(a / 180.0f * PI) * 1.25f;
00493 float offSetY = cosf(a / 180.0f * PI) * 1.25f;
00494
00495 Vector newPos(
00496 pos[0] + offSetX,
00497 pos[1] + offSetY);
00498 newPos[2] =
00499 ScorchedServer::instance()->getLandscapeMaps().
00500 getGroundMaps().getInterpHeight(
00501 fixed::fromFloat(newPos[0]),
00502 fixed::fromFloat(newPos[1])).asFloat();
00503 if (newPos[2] < lowest[2]) lowest = newPos;
00504 }
00505
00506 if (lowest[2] < pos[2])
00507 {
00508 pos = lowest;
00509 Vector direction = pos - position;
00510 float dist =
00511 float(sqrt(direction[0]*direction[0] + direction[1]*direction[1]));
00512 if (dist > 6.0f) return false;
00513 }
00514 else
00515 {
00516 break;
00517 }
00518 }
00519
00520
00521 for (float a=0.0f; a<360.0f; a+=22.5f)
00522 {
00523 bool ok = false;
00524 for (float radius=2.0f; radius<10.0f; radius+=1.0f)
00525 {
00526 float offSetX = sinf(a / 180.0f * PI) * radius;
00527 float offSetY = cosf(a / 180.0f * PI) * radius;
00528
00529 Vector newPos(
00530 pos[0] + offSetX,
00531 pos[1] + offSetY);
00532 newPos[2] =
00533 ScorchedServer::instance()->getLandscapeMaps().
00534 getGroundMaps().getInterpHeight(
00535 fixed::fromFloat(newPos[0]),
00536 fixed::fromFloat(newPos[1])).asFloat();
00537
00538 float heightDiff = newPos[2] - pos[2];
00539 if (heightDiff < -2.0f)
00540 {
00541 return false;
00542 }
00543 if (heightDiff > 2.0f)
00544 {
00545 ok = true;
00546 break;
00547 }
00548 }
00549 if (!ok) return false;
00550 }
00551
00552 return true;
00553 }
00554
00555 bool TankAICurrentMove::makeMoveShot(Tank *tank,
00556 TankAIWeaponSets::WeaponSet *weapons,
00557 std::list<Tank *> &sortedTanks)
00558 {
00559 if (!useFuel_) return false;
00560 if (sortedTanks.empty()) return false;
00561
00562 Accessory *fuel = weapons->getTankAccessoryByType(tank, "fuel");
00563 if (!fuel) return false;
00564
00565 ScorchedContext &context = ScorchedServer::instance()->getContext();
00566 WeaponMoveTank *moveWeapon = (WeaponMoveTank *)
00567 context.getAccessoryStore().findAccessoryPartByAccessoryId(
00568 fuel->getAccessoryId(), "WeaponMoveTank");
00569 if (moveWeapon)
00570 {
00571
00572
00573 Tank *target = sortedTanks.front();
00574 Vector targetPos = target->getPosition().getTankPosition().asVector();
00575 Vector tankPos = tank->getPosition().getTankPosition().asVector();
00576 float totalDistance = MAX(100.0f, MIN(500.0f, (targetPos - tankPos).Magnitude() * 2.0f));
00577
00578
00579 MovementMap mmap(
00580 tank,
00581 context);
00582 if (!mmap.calculatePosition(FixedVector::fromVector(targetPos),
00583 fixed::fromFloat(totalDistance))) return false;
00584 float totalFuel = mmap.getFuel(moveWeapon).asFloat();
00585 if (totalFuel <= 5) return false;
00586
00587
00588 MovementMap::MovementMapEntry entry =
00589 mmap.getEntry((int) targetPos[0], (int) targetPos[1]);
00590 if (entry.type != MovementMap::eMovement) return false;
00591
00592
00593
00594 while (entry.srcEntry)
00595 {
00596 unsigned int pt = entry.srcEntry;
00597 unsigned int x = pt >> 16;
00598 unsigned int y = pt & 0xffff;
00599
00600 Vector position((float) x, (float) y,
00601 ScorchedServer::instance()->getLandscapeMaps().getGroundMaps().getHeight(
00602 (int) x, (int) y).asFloat());
00603 float distance = (position - targetPos).Magnitude();
00604 if (distance > movementCloseness_)
00605 {
00606 if (entry.dist.asFloat() < totalFuel)
00607 {
00608
00609 totalDamageBeforeMove_ = targets_.getTotalDamageTaken();
00610
00611
00612 tank->getPosition().setSelectPosition((int) x, (int) y);
00613 setWeapon(tank, fuel);
00614 fireShot(tank);
00615
00616 return true;
00617 }
00618 }
00619
00620 entry = mmap.getEntry(x, y);
00621 }
00622 }
00623
00624 return false;
00625 }
00626
00627 struct GroupingEntry
00628 {
00629 Vector position;
00630 std::list<Tank *> targets;
00631 float totalDistance;
00632 };
00633
00634 bool TankAICurrentMove::makeGroupShot(Tank *tank,
00635 TankAIWeaponSets::WeaponSet *weapons,
00636 std::list<Tank *> &sortedTanks)
00637 {
00638 if (groupShotSize_ == 0) return false;
00639 Accessory *explosionhuge = weapons->getTankAccessoryByType(tank, "explosionhuge");
00640 if (!explosionhuge) return false;
00641
00642 std::list<GroupingEntry> foundEntries;
00643 HeightMap &map =
00644 ScorchedServer::instance()->getLandscapeMaps().getGroundMaps().getHeightMap();
00645
00646 int arenaX = ScorchedServer::instance()->getLandscapeMaps().
00647 getGroundMaps().getArenaX();
00648 int arenaY = ScorchedServer::instance()->getLandscapeMaps().
00649 getGroundMaps().getArenaY();
00650 int arenaWidth = ScorchedServer::instance()->getLandscapeMaps().
00651 getGroundMaps().getArenaWidth();
00652 int arenaHeight = ScorchedServer::instance()->getLandscapeMaps().
00653 getGroundMaps().getArenaHeight();
00654
00655
00656
00657 for (int y=arenaY; y<arenaY + arenaHeight; y+=4)
00658 {
00659 for (int x=arenaX; x<arenaX + arenaWidth; x+=4)
00660 {
00661 GroupingEntry entry;
00662 entry.position = Vector(float(x), float(y), map.getHeight(x, y).asFloat());
00663 entry.totalDistance = 0.0f;
00664
00665
00666 float distance =
00667 (tank->getPosition().getTankPosition().asVector() -
00668 entry.position).Magnitude();
00669 if (distance < groupTargetDistance_ * 2.0f) continue;
00670
00671
00672 std::list<Tank *>::iterator toItor;
00673 for (toItor = sortedTanks.begin();
00674 toItor != sortedTanks.end();
00675 toItor++)
00676 {
00677 Tank *to = *toItor;
00678
00679 distance =
00680 (to->getPosition().getTankPosition().asVector() -
00681 entry.position).Magnitude();
00682 if (distance < groupTargetDistance_)
00683 {
00684 entry.totalDistance += distance;
00685 entry.targets.push_back(to);
00686 }
00687 }
00688
00689
00690 if (entry.targets.size() >= (unsigned int) groupShotSize_)
00691 {
00692 foundEntries.push_back(entry);
00693 }
00694 }
00695 }
00696
00697
00698 if (!foundEntries.empty())
00699 {
00700 GroupingEntry *current = 0;
00701 std::list<GroupingEntry>::iterator itor;
00702 for (itor = foundEntries.begin();
00703 itor != foundEntries.end();
00704 itor++)
00705 {
00706 GroupingEntry &entry = *itor;
00707 if (!current ||
00708 entry.targets.size() > current->targets.size() ||
00709 (entry.targets.size() == current->targets.size() &&
00710 entry.totalDistance < current->totalDistance))
00711 {
00712 current = &entry;
00713 }
00714 }
00715
00716 if (current)
00717 {
00718
00719 for (float degs=85.0f; degs>=45.0f; degs-=8.0f)
00720 {
00721
00722 Vector actualPosition;
00723 TankAIAimGuesser aimGuesser;
00724 if (aimGuesser.guess(tank, current->position,
00725 degs, 15.0f, actualPosition))
00726 {
00727 setWeapon(tank, explosionhuge);
00728 fireShot(tank);
00729 return true;
00730 }
00731 }
00732 }
00733 }
00734
00735 return false;
00736 }
00737
00738 bool TankAICurrentMove::useAvailableBatteries(Tank *tank)
00739 {
00740
00741 bool result = false;
00742 while (tank->getLife().getLife() <
00743 tank->getLife().getMaxLife() &&
00744 tank->getAccessories().getBatteries().canUse())
00745 {
00746 std::list<Accessory *> &entries =
00747 tank->getAccessories().getAllAccessoriesByType(
00748 AccessoryPart::AccessoryBattery);
00749 if (!entries.empty())
00750 {
00751 useBattery(tank, entries.front()->getAccessoryId());
00752 result = true;
00753 }
00754 }
00755 return result;
00756 }
00757
00758 Vector TankAICurrentMove::lowestHighest(TankAICurrentMoveWeapons &weapons,
00759 Vector &directTarget, bool highest)
00760 {
00761 float radius = weapons.shield->getBoundingSize().asFloat() + 2.0f;
00762 Vector bestPos = directTarget;
00763 bestPos[1] += radius;
00764 bestPos[2] =
00765 ScorchedServer::instance()->getLandscapeMaps().
00766 getGroundMaps().getInterpHeight(
00767 fixed::fromFloat(bestPos[0]), fixed::fromFloat(bestPos[1])).asFloat();
00768 for (float a=0.0f; a<360.0f; a+=22.5f)
00769 {
00770 float offSetX = sinf(a / 180.0f * PI) * radius;
00771 float offSetY = cosf(a / 180.0f * PI) * radius;
00772
00773 Vector newPos(
00774 directTarget[0] + offSetX,
00775 directTarget[1] + offSetY);
00776 newPos[2] =
00777 ScorchedServer::instance()->getLandscapeMaps().
00778 getGroundMaps().getInterpHeight(
00779 fixed::fromFloat(newPos[0]), fixed::fromFloat(newPos[1])).asFloat();
00780
00781 if (highest)
00782 {
00783 if (newPos[2] > bestPos[2]) bestPos = newPos;
00784 }
00785 else
00786 {
00787 if (newPos[2] < bestPos[2]) bestPos = newPos;
00788 }
00789 }
00790 return bestPos;
00791 }
00792
00793 float TankAICurrentMove::getShotDistance(Tank *tank, bool projectile)
00794 {
00795
00796 std::map<Tank *, ShotRecord>::iterator itor =
00797 shotRecords_.find(tank);
00798 if (itor == shotRecords_.end())
00799 {
00800 if (projectile) return projectileStartDistance_;
00801 else return sniperStartDistance_;
00802 }
00803 else
00804 {
00805 if (projectile) return itor->second.projectileCurrentDistance;
00806 else return itor->second.sniperCurrentDistance;
00807 }
00808 }
00809
00810 void TankAICurrentMove::shotAtTank(Tank *tank, bool projectile, float newDistance)
00811 {
00812 targets_.shotAt(tank);
00813
00814
00815 std::map<Tank *, ShotRecord>::iterator itor =
00816 shotRecords_.find(tank);
00817 if (itor == shotRecords_.end())
00818 {
00819
00820 ShotRecord record;
00821 record.projectileCurrentDistance = projectileStartDistance_;
00822 record.sniperCurrentDistance = sniperStartDistance_;
00823 record.position = tank->getPosition().getTankPosition().asVector();
00824 shotRecords_[tank] = record;
00825 }
00826
00827
00828 ShotRecord &record = shotRecords_[tank];
00829 float distance = (record.position - tank->getPosition().getTankPosition().asVector()).Magnitude();
00830 float distanceDec = 0.0f;
00831 if (distance > 5.0f)
00832 {
00833 distanceDec = MIN(distance - 5.0f, 20.0f) / 20.0f;
00834 }
00835
00836 record.position = tank->getPosition().getTankPosition().asVector();
00837 if (projectile)
00838 {
00839 record.projectileCurrentDistance = newDistance;
00840
00841 float decrement =
00842 projectileMinDecrement_ +
00843 RAND * (projectileMaxDecrement_ - projectileMinDecrement_);
00844 record.projectileCurrentDistance =
00845 MAX(projectileEndDistance_, record.projectileCurrentDistance - decrement);
00846
00847 distanceDec *= projectileMovementFactor_;
00848 record.projectileCurrentDistance =
00849 MIN(projectileStartDistance_, record.projectileCurrentDistance + distanceDec);
00850 }
00851 else
00852 {
00853 float decrement =
00854 sniperMinDecrement_ +
00855 RAND * (sniperMaxDecrement_ - sniperMinDecrement_);
00856 record.sniperCurrentDistance =
00857 MAX(sniperEndDistance_, record.sniperCurrentDistance - decrement);
00858
00859 distanceDec *= sniperMovementFactor_;
00860 record.sniperCurrentDistance =
00861 MIN(sniperStartDistance_, record.sniperCurrentDistance + distanceDec);
00862 }
00863 }
00864
00865 void TankAICurrentMove::setWeapon(Tank *tank, Accessory *accessory)
00866 {
00867 tank->getAccessories().getWeapons().setWeapon(accessory);
00868 }
00869
00870 void TankAICurrentMove::skipMove(Tank *tank)
00871 {
00872 ComsPlayedMoveMessage *message =
00873 new ComsPlayedMoveMessage(tank->getPlayerId(), ComsPlayedMoveMessage::eSkip);
00874 ServerShotHolder::instance()->addShot(tank->getPlayerId(), message);
00875 }
00876
00877 void TankAICurrentMove::resign(Tank *tank)
00878 {
00879 ComsPlayedMoveMessage *message =
00880 new ComsPlayedMoveMessage(tank->getPlayerId(), ComsPlayedMoveMessage::eResign);
00881 ServerShotHolder::instance()->addShot(tank->getPlayerId(), message);
00882 }
00883
00884 void TankAICurrentMove::fireShot(Tank *tank)
00885 {
00886 Accessory *currentWeapon =
00887 tank->getAccessories().getWeapons().getCurrent();
00888 if (currentWeapon)
00889 {
00890 ComsPlayedMoveMessage *message =
00891 new ComsPlayedMoveMessage(tank->getPlayerId(), ComsPlayedMoveMessage::eShot);
00892 message->setShot(
00893 currentWeapon->getAccessoryId(),
00894 tank->getPosition().getRotationGunXY(),
00895 tank->getPosition().getRotationGunYZ(),
00896 tank->getPosition().getPower(),
00897 tank->getPosition().getSelectPositionX(),
00898 tank->getPosition().getSelectPositionY());
00899
00900 if (!ServerShotHolder::instance()->addShot(tank->getPlayerId(), message))
00901 {
00902 Logger::log(S3D::formatStringBuffer("AI %u failed to make a shot, shot refused",
00903 tank->getPlayerId()));
00904 skipMove(tank);
00905 }
00906 }
00907 }
00908
00909 void TankAICurrentMove::useBattery(Tank *tank, unsigned int batteryId)
00910 {
00911 ComsDefenseMessage defenseMessage(
00912 tank->getPlayerId(),
00913 ComsDefenseMessage::eBatteryUse,
00914 batteryId);
00915
00916 ServerDefenseHandler::instance()->processDefenseMessage(defenseMessage, tank);
00917 }