00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "ai_common.h"
00020
00021
00022
00023 bool AI :: runUnitTask ( Vehicle* veh )
00024 {
00025 if ( veh->aiparam[getPlayerNum()]->getTask() == AiParameter::tsk_move || veh->aiparam[getPlayerNum()]->getTask() == AiParameter::tsk_serviceRetreat ) {
00026 bool moveIntoBuildings = false;
00027 if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer ||
00028 veh->aiparam[getPlayerNum()]->getTask() == AiParameter::tsk_serviceRetreat ||
00029 veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_script )
00030 moveIntoBuildings = true;
00031
00032 int nwid = veh->networkid;
00033 moveUnit ( veh, veh->aiparam[getPlayerNum()]->dest, moveIntoBuildings );
00034 if ( getMap()->getUnit( nwid ))
00035 if ( veh->getPosition() == veh->aiparam[getPlayerNum()]->dest ) {
00036 veh->aiparam[getPlayerNum()]->resetTask ();
00037 return true;
00038 }
00039 }
00040
00041 return false;
00042 }
00043
00044
00045
00046 int AI :: getBestHeight ( Vehicle* veh )
00047 {
00048 int heightNum = 0;
00049 for ( int i = 0; i < 8; i++ )
00050 if ( veh->typ->height & ( 1 << i ))
00051 heightNum++;
00052 if ( heightNum == 1 )
00053 return veh->typ->height;
00054
00055 int bestHeight = -1;
00056 float bestHeightValue = minfloat;
00057
00058 float maxAvgFieldThreat = minfloat;
00059 float minAvgFieldThreat = maxfloat;
00060 float secminAvgFieldThreat = maxfloat;
00061
00062
00063 for ( int k = 0; k < 8; k++ )
00064 if ( veh->typ->height & ( 1 << k )) {
00065 float t = sections.getForCoordinate( veh->xpos, veh->ypos ).avgFieldThreat.threat[ veh->getValueType(1<<k) ];
00066
00067 if ( maxAvgFieldThreat < t )
00068 maxAvgFieldThreat = t;
00069
00070 if ( minAvgFieldThreat > t )
00071 minAvgFieldThreat = t;
00072
00073 if ( t )
00074 if ( secminAvgFieldThreat > t )
00075 secminAvgFieldThreat = t;
00076 }
00077
00078
00079 for ( int j = 0; j < 8; j++ )
00080 if ( veh->typ->height & ( 1 << j )) {
00081
00082 TemporaryContainerStorage tus (veh);
00083 veh->height = 1<<j;
00084
00085
00086 calculateThreat ( veh );
00087 Section& sec = sections.getForCoordinate( veh->xpos, veh->ypos );
00088
00089 float value = veh->aiparam[getPlayerNum()]->getValue();
00090 if ( veh->typ->movement[j] )
00091 value *= log( double(veh->typ->movement[j]) );
00092
00093 float threat = sec.avgFieldThreat.threat[ veh->aiparam[getPlayerNum()]->valueType ];
00094 if ( minAvgFieldThreat > 0 ) {
00095 if ( threat && threat != 1 )
00096 value *= ( log ( minAvgFieldThreat ) / log ( threat ) );
00097 } else {
00098 if ( secminAvgFieldThreat < maxfloat)
00099 if ( threat && threat != 1 )
00100 value *= ( log ( secminAvgFieldThreat ) / log ( threat ) );
00101 else
00102 value *= 1.5;
00103 }
00104
00105 if ( value > bestHeightValue ) {
00106 bestHeightValue = value;
00107 bestHeight = 1 << j;
00108 }
00109 tus.restore();
00110 }
00111
00112 return bestHeight;
00113 }
00114
00115
00116
00117 class SaveUnitMovement {
00118 int m;
00119 Vehicle* unit;
00120 public:
00121 SaveUnitMovement ( Vehicle* veh ) {
00122 unit = veh;
00123 npush ( unit->xpos );
00124 npush ( unit->ypos );
00125 npush ( unit->height );
00126 m = unit->getMovement();
00127 npush ( unit->attacked );
00128 };
00129 ~SaveUnitMovement ( ) {
00130 npop ( unit->attacked );
00131 unit->setMovement ( m, 0 );
00132 npop ( unit->height );
00133 npop ( unit->ypos );
00134 npop ( unit->xpos );
00135 };
00136 };
00137
00138
00139
00140 void AI::RefuelConstraint::findPath()
00141 {
00142 if ( !ast ) {
00143
00144 int dist;
00145 if ( maxMove == -1 ) {
00146 if ( veh->typ->fuelConsumption )
00147 dist = veh->getResource(maxint, 2, true) / veh->typ->fuelConsumption * maxmalq;
00148 else
00149 dist = maxint;
00150
00151 dist = min( dist, veh->maxMovement() * 5);
00152 } else
00153 dist = maxMove;
00154
00155 ast = new AStar3D ( ai.getMap(), veh, true, dist );
00156 ast->findAllAccessibleFields ( );
00157
00158 }
00159 }
00160
00161 MapCoordinate3D AI::RefuelConstraint::getNearestRefuellingPosition ( bool buildingRequired, bool refuel, bool repair )
00162 {
00163 findPath();
00164
00165 int fuel = veh->getResource(maxint, 2, true);
00166 int x1,y1,x2,y2;
00167 x1 = max(veh->xpos - fuel / veh->typ->fuelConsumption, 0 );
00168 y1 = max(veh->ypos - fuel / veh->typ->fuelConsumption, 0 );
00169 x2 = min(veh->xpos + fuel / veh->typ->fuelConsumption, actmap->xsize );
00170 y2 = min(veh->ypos + fuel / veh->typ->fuelConsumption, actmap->ysize );
00171
00172 for ( AStar3D::Container::iterator i = ast->visited.begin(); i != ast->visited.end(); i++ ) {
00173 int dist = int(i->gval );
00174 if ( i->h.getNumericalHeight() == -1 ) {
00175 tfield* fld = getfield( i->h.x, i->h.y );
00176 if ( fld->building && fld->building->color == veh->color )
00177 reachableBuildings[ dist ] = fld->building;
00178 }
00179
00180
00181
00182
00183
00184
00185 if ((veh->height > chfahrend) && (i->h.getNumericalHeight() == chfahrend) ) {
00186
00187 FieldInformation& fi = ai.getFieldInformation ( i->h.x, i->h.y );
00188 if ( fi.control == -1 || !actmap->player[fi.control].diplomacy.isHostile( ai.getPlayerNum() ) )
00189 landingPositions[dist] = i->h;
00190 }
00191 }
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223 if ( buildingRequired ) {
00224 for ( ReachableBuildings::iterator rb = reachableBuildings.begin(); rb != reachableBuildings.end(); rb++ ) {
00225 if ( !repair || (rb->second->typ->hasFunction( ContainerBaseType::InternalUnitRepair )))
00226 return rb->second->getPosition3D();
00227 }
00228 }
00229 if ( !reachableBuildings.empty() && !landingPositions.empty()) {
00230 if ( reachableBuildings.begin()->first < landingPositions.begin()->first )
00231 return reachableBuildings.begin()->second->getPosition3D();
00232 else
00233 return landingPositions.begin()->second;
00234 }
00235
00236 if ( !landingPositions.empty() )
00237 return landingPositions.begin()->second;
00238 else
00239 return MapCoordinate3D();
00240 }
00241
00242 bool AI::RefuelConstraint::returnFromPositionPossible ( const MapCoordinate3D& pos, int theoreticalFuel )
00243 {
00244 if ( !veh->typ->fuelConsumption )
00245 return true;
00246
00247 if ( theoreticalFuel < 0 )
00248 theoreticalFuel = veh->getResource(maxint, 2, true );
00249
00250 findPath();
00251 if ( !positionsCalculated ) {
00252 getNearestRefuellingPosition ( true, true, false );
00253 positionsCalculated = true;
00254 }
00255
00256 if ( !ast->fieldVisited(pos) )
00257 return false;
00258
00259 int dist = int( ast->fieldVisited(pos)->gval );
00260 int dist2;
00261 if ( !reachableBuildings.empty() ) {
00262 ReachableBuildings::iterator rb = reachableBuildings.begin();
00263 dist2 = beeline ( pos, rb->second->getPosition() );
00264 rb++;
00265 while ( rb != reachableBuildings.end() ) {
00266 int d = beeline ( pos, rb->second->getPosition() );
00267 if ( d < dist2 ) {
00268 dist2 = d;
00269 }
00270 rb++;
00271 }
00272 } else {
00273 if ( !landingPositions.empty() ) {
00274 LandingPositions::iterator lp = landingPositions.begin();
00275 dist2 = beeline ( pos, lp->second );
00276 MapCoordinate3D dest = lp->second;
00277 lp++;
00278 while ( lp != landingPositions.end() ) {
00279 int d = beeline ( pos, lp->second );
00280 if ( d < dist2 ) {
00281 dist2 = d;
00282 dest = lp->second;
00283 }
00284 lp++;
00285 }
00286 } else
00287
00288
00289
00290 return true;
00291 }
00292
00293 if ( theoreticalFuel - (dist + dist2) / maxmalq * veh->typ->fuelConsumption > 0.2 * veh->getStorageCapacity().fuel )
00294 return true;
00295 else
00296 return false;
00297
00298 }
00299
00300 bool AI::RefuelConstraint::necessary (const Vehicle* veh, AI& ai )
00301 {
00302 if ( !veh->typ->fuelConsumption )
00303 return false;
00304 if ( !(veh->height & (chtieffliegend | chfliegend | chhochfliegend))) {
00305 ServiceOrder so ( &ai, VehicleService::srv_resource, veh->networkid, 2 );
00306 if ( so.serviceUnitExists() )
00307 return false;
00308 else
00309 return true;
00310 }
00311
00312 return true;
00313 }
00314
00315
00316 AI::VehicleTypeEfficiencyCalculator::VehicleTypeEfficiencyCalculator( AI& _ai, Vehicle* _attacker, Vehicle* _target )
00317 : ai ( _ai ), attacker( _attacker ), target( _target)
00318 {
00319 ownValue = attacker->aiparam[ai.getPlayerNum()]->getValue();
00320 ownTypeID = attacker->typ->id;
00321 enemyValue = target->aiparam[ai.getPlayerNum()]->getValue();
00322 orgOwnDamage = attacker->damage;
00323 orgEnemyDamage = target->damage;
00324 enemyID = target->networkid;
00325 ownID = attacker->networkid;
00326 }
00327
00328
00329 void AI::VehicleTypeEfficiencyCalculator::calc()
00330 {
00331 int newOwnDamage;
00332 if ( ai.getMap()->getUnit(ownID) )
00333 newOwnDamage = attacker->damage;
00334 else
00335 newOwnDamage = 100;
00336
00337 int newEnemyDamage;
00338 if ( ai.getMap()->getUnit(enemyID) )
00339 newEnemyDamage = target->damage;
00340 else
00341 newEnemyDamage = 100;
00342
00343 ai.unitTypeSuccess[ownTypeID].first += enemyValue * (newEnemyDamage - orgEnemyDamage) * 0.01;
00344 ai.unitTypeSuccess[ownTypeID].second += ownValue * (newOwnDamage - orgOwnDamage ) * 0.01;
00345 }
00346
00347 AI::AiResult AI :: container ( ContainerBase* cb )
00348 {
00349 ContainerControls cc( cb );
00350 AiResult result;
00351
00352
00353 std::vector<Vehicle*> idleUnits;
00354 for ( vector<Vehicle*>::const_iterator j = cb->getCargo().begin(); j != cb->getCargo().end(); ++j ) {
00355 Vehicle* veh = *j;
00356 if ( veh )
00357 if ( veh->canMove() && veh->getOwner() == getPlayerNum() )
00358 if ( veh->aiparam[ getPlayerNum() ]->getTask() == AiParameter::tsk_nothing
00359 || veh->aiparam[ getPlayerNum() ]->getJob() == AiParameter::job_script )
00360 idleUnits.push_back ( veh );
00361 }
00362
00363
00364 sort ( idleUnits.begin(), idleUnits.end(), vehicleValueComp );
00365
00366 for ( std::vector<Vehicle*>::iterator i = idleUnits.begin(); i != idleUnits.end(); i++ ) {
00367
00368 checkKeys();
00369
00370
00371
00372 int preferredHeight = getBestHeight ( *i );
00373
00374 VehicleMovement* vm = ContainerControls::movement ( *i );
00375
00376 if ( vm ) {
00377 vm->registerMapDisplay ( mapDisplay );
00378 auto_ptr<VehicleMovement> avm ( vm );
00379
00380 VehicleAttack va ( NULL, NULL );
00381 int moved = 0;
00382 if ( va.available ( *i )) {
00383 TargetVector tv;
00384
00385
00386 AStar3D ast ( getMap(), *i, false, (*i)->getMovement() );
00387 ast.findAllAccessibleFields ();
00388
00389 getAttacks ( ast, *i, tv, 0 );
00390
00391 if ( tv.size() ) {
00392 AiResult res = executeMoveAttack ( *i, tv );
00393 result += res;
00394 if ( !res.unitsDestroyed )
00395 (*i)->aiparam[ getPlayerNum() ]->setTask( AiParameter::tsk_tactics );
00396
00397 moved = 1;
00398 } else {
00399 AStar3D ast ( getMap(), *i, false, (*i)->maxMovement()*3 );
00400 ast.findAllAccessibleFields ();
00401
00402 getAttacks ( ast, *i, tv, 0 );
00403
00404 if ( tv.size() ) {
00405 MoveVariant* mv = *max_element( tv.begin(), tv.end(), moveVariantComp );
00406 if ( moveUnit ( *i, mv->movePos ) )
00407 moved = 1;
00408 }
00409 }
00410
00411 }
00412 if ( !moved ) {
00413 AiResult res = moveToSavePlace ( *i, *vm, preferredHeight );
00414 result += res;
00415 if ( !res.unitsDestroyed )
00416 (*i)->aiparam[ getPlayerNum() ]->resetTask();
00417 }
00418 }
00419 }
00420 return result;
00421 }
00422
00423
00424 AI::AiResult AI::buildings( int process )
00425 {
00426 AiResult result;
00427
00428 displaymessage2("checking buildings ... ");
00429
00430 int buildingCounter = 0;
00431 for ( Player::BuildingList::iterator bi = getPlayer().buildingList.begin(); bi != getPlayer().buildingList.end(); bi++ ) {
00432 buildingCounter++;
00433 displaymessage2("processing building %d", buildingCounter );
00434
00435 ContainerControls bc( *bi );
00436
00437 int unitCounter = 0;
00438 for ( vector<Vehicle*>::const_iterator j= (*bi)->getCargo().begin(); j != (*bi)->getCargo().end(); j++ ) {
00439 Vehicle* veh = *j;
00440 if ( veh ) {
00441 ++unitCounter;
00442 displaymessage2("processing building %d (unit %d)", buildingCounter, unitCounter );
00443 if ( veh->aiparam[ getPlayerNum() ]->getJob() != AiParameter::job_supply )
00444 bc.fillResource( veh, Resources::Fuel, maxint );
00445 else
00446 bc.refilleverything( veh );
00447 }
00448 }
00449
00450 result += container ( *bi );
00451
00452 checkKeys();
00453 }
00454
00455 displaymessage2("building check completed... ");
00456 return result;
00457 }
00458
00459
00460 AI::AiResult AI::transports( int process )
00461 {
00462 AiResult result;
00463
00464 displaymessage2("checking transports ... ");
00465
00466 int transportCounter = 0;
00467 for ( Player::VehicleList::iterator vi = getPlayer().vehicleList.begin(); vi != getPlayer().vehicleList.end(); vi++ ) {
00468 Vehicle* veh = *vi;
00469 transportCounter++;
00470 displaymessage2("processing unit %d for transportation ", transportCounter );
00471
00472 result += container ( veh );
00473
00474 checkKeys();
00475 }
00476
00477 displaymessage2("transport check completed... ");
00478 return result;
00479 }
00480
00481
00482
00483 bool AI :: moveUnit ( Vehicle* veh, const MapCoordinate3D& destination, bool intoBuildings, bool intoTransports )
00484 {
00485
00486
00487 #if 0
00488 if ( destination.getNumericalHeight() == -1 ) {
00489
00490 VehicleMovement vm ( mapDisplay, NULL );
00491 vm.execute ( veh, -1, -1, 0, -1, -1 );
00492
00493 std::vector<MapCoordinate> path;
00494 AStar* ast = NULL;
00495 if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer )
00496 ast = new HiddenAStar ( this, veh );
00497 else
00498 ast = new StratAStar ( this, veh );
00499
00500 auto_ptr<AStar> ap ( ast );
00501
00502 ast->findPath ( AStar::HexCoord ( veh->xpos, veh->ypos ), AStar::HexCoord ( destination.x, destination.y ), path );
00503
00504 int xtogo = veh->xpos;
00505 int ytogo = veh->ypos;
00506
00507 for ( unsigned int i = 0; i < path.size(); i++ ) {
00508 int x = path[i].x;
00509 int y = path[i].y;
00510
00511 tfield* fld = getfield ( x, y );
00512 if ( !fld)
00513 break;
00514
00515
00516 if ( vm.reachableFields.isMember ( x, y )
00517 && fieldaccessible ( fld, veh ) == 2
00518 && (!fld->building || intoBuildings)
00519 && (!fld->vehicle || intoTransports )) {
00520 xtogo = x;
00521 ytogo = y;
00522 }
00523 }
00524
00525 if ( xtogo != veh->xpos || ytogo != veh->ypos ) {
00526 if ( getfield ( xtogo, ytogo )->building )
00527 if ( checkReConquer ( getfield ( xtogo, ytogo )->building, veh ))
00528 return false;
00529
00530 int nwid = veh->networkid;
00531 vm.execute ( NULL, xtogo, ytogo, 2, -1, -1 );
00532 if ( vm.getStatus() != 3 )
00533 displaymessage ( "AI :: moveUnit \n error in movement step 2 with unit %d", 1, veh->networkid );
00534
00535 vm.execute ( NULL, xtogo, ytogo, 3, -1, 1 );
00536 if ( vm.getStatus() != 1000 )
00537 displaymessage ( "AI :: moveUnit \n error in movement step 3 with unit %d", 1, veh->networkid );
00538
00539 if ( getMap()->getUnit(nwid) )
00540 if ( destination.x == xtogo && destination.y == ytogo )
00541 if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer )
00542 if ( getfield ( xtogo, ytogo)->building )
00543 veh->aiparam[getPlayerNum()]->clearJobs();
00544
00545
00546 return true;
00547 }
00548 return false;
00549 } else {
00550 #endif
00551 if ( veh->getPosition3D() == destination )
00552 return true;
00553
00554 AStar3D* ast = NULL;
00555 if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer )
00556 ast = new HiddenAStar3D ( this, veh );
00557 else
00558 if ( beeline ( veh->getPosition(), destination) > veh->maxMovement() )
00559 ast = new StratAStar3D ( this, veh );
00560 else
00561 ast = new AStar3D ( getMap(), veh );
00562
00563 auto_ptr<AStar3D> ap ( ast );
00564
00565 AStar3D::Path path;
00566 ast->findPath ( path, destination );
00567
00568 return moveUnit ( veh, path, intoBuildings, intoTransports ) == 1 ;
00569
00570 }
00571
00572 int AI::moveUnit ( Vehicle* veh, const AStar3D::Path& path, bool intoBuildings, bool intoTransports )
00573 {
00574 AStar3D::Path::const_iterator pi = path.begin();
00575 if ( pi == path.end() )
00576 return 0;
00577
00578 int nwid = veh->networkid;
00579
00580 AStar3D::Path::const_iterator lastmatch = pi;
00581 while ( pi != path.end() ) {
00582 tfield* fld = getfield ( pi->x, pi->y );
00583 bool ok = true;
00584 if ( fld->getContainer() ) {
00585 if ( pi+1 !=path.end() )
00586 ok = false;
00587 else {
00588 if ( fld->building && !intoBuildings )
00589 ok = false;
00590 if ( fld->vehicle && !intoTransports )
00591 ok = false;
00592 }
00593 }
00594
00595 if ( ok )
00596
00597 if ( pi->dist <= veh->getMovement() )
00598 lastmatch = pi;
00599
00600 ++pi;
00601 }
00602
00603 if ( getfield ( lastmatch->x, lastmatch->y )->building )
00604 if ( checkReConquer ( getfield ( lastmatch->x, lastmatch->y )->building, veh ))
00605 return false;
00606
00607 if ( lastmatch == path.begin() )
00608 return 0;
00609
00610 BaseVehicleMovement vm ( vat_move, NULL, mapDisplay );
00611 vm.execute ( veh, lastmatch->x, lastmatch->y, 0, lastmatch->getNumericalHeight(), 1 );
00612
00613 if ( vm.getStatus() != 3 ) {
00614 displaymessage ( "AI :: moveUnit (path) \n error in movement step 3 with unit %d", 1, veh->networkid );
00615 return -1;
00616 }
00617
00618 vm.execute ( NULL, lastmatch->x, lastmatch->y, 3, -1, 1 );
00619 if ( vm.getStatus() != 1000 ) {
00620 displaymessage ( "AI :: moveUnit (path) \n error in movement step 3 with unit %d", 1, veh->networkid );
00621 return -1;
00622 }
00623
00624
00626 if ( ! getMap()->getUnit ( nwid ))
00627 return 1;
00628
00629 if ( pi == path.end() )
00630 if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer )
00631 if ( getMap()->getField ( veh->getPosition() )->building )
00632 veh->aiparam[getPlayerNum()]->clearJobs();
00633
00634 return 1;
00635 }
00636
00637
00638
00639
00640
00641 AI:: CheckFieldRecon :: CheckFieldRecon ( AI* _ai ) : SearchFields ( _ai->getMap() ), player(_ai->getPlayerNum()), ai ( _ai )
00642 {
00643 for( int i = 0; i < 3; i++ ) {
00644 ownFields[i] = 0;
00645 enemyFields[i] = 0;
00646 }
00647 }
00648
00649 int AI:: CheckFieldRecon :: run ( int x, int y)
00650 {
00651 initsearch ( MapCoordinate(x, y), 1 , 2 );
00652 startsearch();
00653 if ( ownFields[1] && !enemyFields[1] ) {
00654 if ( enemyFields[2] > ownFields[2] )
00655 return 0;
00656 else
00657 if ( enemyFields[2] )
00658 return 1;
00659 }
00660 return -1;
00661 }
00662
00663 void AI::CheckFieldRecon :: testfield ( const MapCoordinate& mc )
00664 {
00665 FieldInformation& fi = ai->getFieldInformation ( mc.x, mc.y );
00666 if( fi.control != -1 )
00667 if ( !actmap->player[player].diplomacy.isHostile( fi.control ) )
00668 ownFields[dist]++;
00669 else
00670 enemyFields[dist]++;
00671 }
00672
00673 void AI :: calcReconPositions()
00674 {
00675 displaymessage2("calculating reconnaissance positions ... ");
00676 for ( int y = 0; y < getMap()->ysize; y++ )
00677 for ( int x = 0; x < getMap()->xsize; x++ ) {
00678 FieldInformation& fi = getFieldInformation ( x, y );
00679 tfield* fld = getMap()->getField(x,y);
00680 if ( fi.control == getPlayerNum() && !fld->building && ( !fld->vehicle || fld->vehicle->aiparam[getPlayerNum()]->getJob() == AiParameter::job_recon )) {
00681 CheckFieldRecon cfr ( this );
00682 int qual = cfr.run(x,y);
00683 if ( qual>= 0 )
00684 reconPositions[MapCoordinate ( x, y )] = qual;
00685
00686 }
00687 }
00688 }
00689
00690 void AI :: runReconUnits ( )
00691 {
00692 Player::VehicleList::iterator nvi;
00693 for ( Player::VehicleList::iterator vi = getPlayer().vehicleList.begin(); vi != getPlayer().vehicleList.end(); ) {
00694 nvi = vi;
00695 ++nvi;
00696
00697 Vehicle* veh = *vi;
00698
00699 int maxUnitMovement = veh->typ->maxSpeed();
00700
00701
00702 if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_recon ) {
00703 if ( reconPositions.find ( veh->getPosition()) == reconPositions.end()) {
00704
00705 int mindist = maxint;
00706 MapCoordinate mc;
00707 for ( ReconPositions::iterator i = reconPositions.begin(); i != reconPositions.end(); i++ ) {
00708 tfield* fld = getMap()->getField( i->first );
00709 if ( !fld->vehicle && !fld->building ) {
00710 AStar ast ( getMap(), veh );
00711 ast.findAllAccessibleFields( maxUnitMovement );
00712 if ( fld->a.temp ) {
00713 int vdist = beeline ( veh->getPosition(), i->first )*(1+i->second/2);
00714 if( vdist < mindist ) {
00715 mindist = vdist;
00716 mc = i->first;
00717 }
00718 }
00719 }
00720 }
00721 if( mindist < maxint ) {
00722 veh->aiparam[getPlayerNum()]->dest = MapCoordinate3D(mc, veh->height);
00723 veh->aiparam[getPlayerNum()]->setTask( AiParameter::tsk_move );
00724 runUnitTask ( veh );
00725 }
00726 }
00727 }
00728 vi = nvi;
00729 }
00730 }
00731
00732 AI::UnitDistribution::Group AI::getUnitDistributionGroup ( Vehicletype* vt )
00733 {
00734 switch ( chooseJob ( vt ).front() ) {
00735 case AiParameter::job_supply : return UnitDistribution::service;
00736 case AiParameter::job_recon : return UnitDistribution::recon;
00737 case AiParameter::job_conquer: return UnitDistribution::conquer;
00738 case AiParameter::job_fight:
00739 case AiParameter::job_guard: {
00740 bool range = false;
00741 for ( int w = 0; w < vt->weapons.count; w++ )
00742 if ( vt->weapons.weapon[w].offensive() )
00743 if ( vt->weapons.weapon[w].maxdistance >= 2 * minmalq )
00744 range = true;
00745 if ( range )
00746 return UnitDistribution::rangeattack;
00747 else
00748 return UnitDistribution::attack;
00749 }
00750 default:;
00751 }
00752 return UnitDistribution::other;
00753 }
00754
00755
00756 AI::UnitDistribution::Group AI::getUnitDistributionGroup ( Vehicle* veh )
00757 {
00758 switch ( veh->aiparam[getPlayerNum()]->getJob() ) {
00759 case AiParameter::job_supply : return UnitDistribution::service;
00760 case AiParameter::job_recon : return UnitDistribution::recon;
00761 case AiParameter::job_conquer: return UnitDistribution::conquer;
00762 case AiParameter::job_fight:
00763 case AiParameter::job_guard: {
00764 bool range = false;
00765 for ( int w = 0; w < veh->typ->weapons.count; w++ )
00766 if ( veh->typ->weapons.weapon[w].offensive() )
00767 if ( veh->typ->weapons.weapon[w].maxdistance >= 2 * minmalq )
00768 range = true;
00769 if ( range )
00770 return UnitDistribution::rangeattack;
00771 else
00772 return UnitDistribution::attack;
00773 }
00774 default:;
00775 }
00776 return UnitDistribution::other;
00777 }
00778
00779 void AI::UnitDistribution::read ( tnstream& stream )
00780 {
00781 int version = stream.readInt();
00782 if ( version == 15000 ) {
00783 int gc = stream.readInt();
00784 calculated = stream.readInt();
00785 for ( int i = 0; i< gc; i++ )
00786 group[i] = stream.readFloat();
00787
00788 for ( int i = gc; i < groupCount; i++ )
00789 group[i] = 0;
00790 }
00791 }
00792
00793 void AI::UnitDistribution::write ( tnstream& stream ) const
00794 {
00795 stream.writeInt ( 15000 );
00796 stream.writeInt ( groupCount );
00797 stream.writeInt ( calculated );
00798 for ( int i = 0; i < groupCount; i++ )
00799 stream.writeFloat ( group[i] );
00800 }
00801
00802
00803 AI::UnitDistribution AI::calcUnitDistribution ()
00804 {
00805 UnitDistribution unitDistribution;
00806 int unitCount = getPlayer().vehicleList.size();
00807 if ( unitCount ) {
00808 float inc = float(1) / float(unitCount);
00809 for ( Player::VehicleList::iterator i = getPlayer().vehicleList.begin(); i != getPlayer().vehicleList.end(); i++ )
00810 unitDistribution.group[ getUnitDistributionGroup ( *i )] += inc;
00811
00812 }
00813 unitDistribution.calculated = true;
00814 return unitDistribution;
00815 }
00816
00817
00818 void AI::production()
00819 {
00820 float inc;
00821 int unitCount = getPlayer().vehicleList.size();
00822 if ( unitCount )
00823 inc = float(1) / float(unitCount);
00824 else
00825 inc = 1;
00826
00827 UnitDistribution currentUnitDistribution = calcUnitDistribution();
00828
00829
00830 currentUnitDistribution.group[ UnitDistribution::attack ] = 0;
00831
00832 displaymessage2("producing units ... ");
00833
00834 AiThreat enemyThreat;
00835 float enemyValue[aiValueTypeNum];
00836 for ( int i = 0; i < aiValueTypeNum; i++ )
00837 enemyValue[i] = 0;
00838
00839 for ( int p = 0; p < 8; p++ )
00840 if ( actmap->player[p].diplomacy.isHostile( getPlayerNum() ) )
00841 for ( Player::VehicleList::iterator vli = getMap()->player[p].vehicleList.begin(); vli != getMap()->player[p].vehicleList.end(); vli++ ) {
00842 enemyThreat += (*vli)->aiparam[getPlayerNum()]->threat;
00843 enemyValue[(*vli)->aiparam[getPlayerNum()]->valueType] += (*vli)->aiparam[getPlayerNum()]->getValue();
00844 }
00845
00846
00847 int emptyCount = 0;
00848 for ( int i = 0; i < aiValueTypeNum; i++ )
00849 if ( enemyValue[i] == 0)
00850 emptyCount++;
00851
00852
00853 if ( emptyCount == aiValueTypeNum )
00854 return ;
00855
00856
00857
00858 typedef multimap<float,ProductionRating> Produceable;
00859 Produceable produceable;
00860
00861 for ( Player::BuildingList::iterator bli = getPlayer().buildingList.begin(); bli != getPlayer().buildingList.end(); bli ++ ) {
00862 Building* bld = *bli;
00863 for ( int i = 0; i < bld->getProduction().size(); i++ )
00864 if ( bld->getProduction()[i] && bld->vehicleUnloadable ( bld->getProduction()[i] )) {
00865 const Vehicletype* typ = bld->getProduction()[i];
00866 float rating = 0;
00867 for ( int j = 0; j < aiValueTypeNum; j++ )
00868 rating += enemyValue[j] * typ->aiparam[getPlayerNum()]->threat.threat[j];
00869
00870 int danger = 1;
00871 if ( typ->aiparam[getPlayerNum()]->getValue() ) {
00872 if ( typ->aiparam[getPlayerNum()]->getValue() < enemyThreat.threat[ typ->aiparam[getPlayerNum()]->valueType] )
00873 danger = enemyThreat.threat[ typ->aiparam[getPlayerNum()]->valueType] / typ->aiparam[getPlayerNum()]->getValue();
00874 }
00875
00876 rating /= 1 + log ( double(danger) );
00877
00878 UnitTypeSuccess::iterator uts = unitTypeSuccess.find ( bld->getProduction()[i]->id );
00879 if ( uts != unitTypeSuccess.end() ) {
00880 if ( uts->second.second >= 1 )
00881 rating *= uts->second.first / uts->second.second;
00882 }
00883
00884
00885 int cost = 0;
00886 for ( int j = 0; j < resourceTypeNum; j++ )
00887 cost += typ->productionCost.resource(j);
00888
00889 if ( cost )
00890 rating /= cost;
00891
00892 ProductionRating pr = { typ, bld, rating };
00893 produceable.insert ( make_pair(rating, pr));
00894 }
00895 }
00896
00897 for ( Produceable::iterator i = produceable.begin(); i != produceable.end(); ++i ) {
00898 float f = i->first;
00899 const char* d = i->second.vt->description.c_str();
00900 printf(" typ: %s ; rating: %e \n", d, f );
00901 }
00902
00903 if ( !produceable.empty() ) {
00904
00905 GetConnectedBuildings::BuildingContainer lockedBuildings;
00906
00907 bool produced;
00908 do {
00909 produced = false;
00910
00911
00912 for ( Produceable::reverse_iterator p = produceable.rbegin(); p != produceable.rend(); p++ ) {
00913
00914 ProductionRating& pr = p->second;
00915
00916 if ( find ( lockedBuildings.begin(), lockedBuildings.end(), pr.bld ) == lockedBuildings.end()) {
00917 ContainerControls bc( pr.bld );
00918 int lack = bc.unitProductionPrerequisites( pr.vt );
00919 if ( !lack && pr.bld->vehicleUnloadSystem ( pr.vt, 255 ) ) {
00920 Vehicle* veh = bc.produceUnit( pr.vt, true, true );
00921 if ( veh ) {
00922 calculateThreat ( veh );
00923 container ( pr.bld );
00924
00925 produced = true;
00926 break;
00927 }
00928 } else {
00929
00930
00931 if ( !(lack & ( 1<<10 ))) {
00932 if ( pr.bld->getResource ( pr.vt->productionCost, 1 ) + pr.bld->netResourcePlus( ) * config.waitForResourcePlus >= pr.vt->productionCost )
00933 for ( int r = 0; r < resourceTypeNum; r++ )
00934 if ( lack & (1 << r )) {
00935 GetConnectedBuildings gcb ( lockedBuildings, getMap(), r );
00936 gcb.start ( pr.bld->getEntry().x, pr.bld->getEntry().y );
00937 }
00938 sort ( lockedBuildings.begin(), lockedBuildings.end());
00939 unique( lockedBuildings.begin(), lockedBuildings.end());
00940 }
00941 }
00942 }
00943
00944
00945 }
00946
00947
00948 } while ( produced );
00949 }
00950
00951 }
00952
00953