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