00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "ai_common.h"
00019
00020 #include "../replaymapdisplay.h"
00021 #include "../turncontrol.h"
00022 #include "../widgets/textrenderer.h"
00023 #include "../mapdisplay.h"
00024 #include "../asc-mainscreen.h"
00025 #include "../gameeventsystem.h"
00026 #include "../actions/diplomacycommand.h"
00027
00028 AI :: AI ( GameMap* _map, int _player ) : activemap ( _map ) , sections ( this )
00029 {
00030 strictChecks = false;
00031 benchMark = false;
00032
00033 player = _player;
00034
00035 _isRunning = false;
00036 fieldInformation = NULL;
00037
00038 reset();
00039 }
00040
00041 void AI :: reset ( void )
00042 {
00043 maxTrooperMove = 0;
00044 maxTransportMove = 0;
00045 maxUnitMove = 0;
00046
00047 for ( int i= 0; i < 8; i++ )
00048 maxWeapDist[i] = -1;
00049 baseThreatsCalculated = 0;
00050
00051 if ( fieldInformation )
00052 delete[] fieldInformation;
00053
00054 fieldInformation = NULL;
00055 fieldNum = 0;
00056
00057 config.wholeMapVisible = 1;
00058 config.lookIntoTransports = 1;
00059 config.lookIntoBuildings = 1;
00060 config.aggressiveness = 3;
00061 config.damageLimit = 70;
00062 config.resourceLimit = Resources ( 0, 5, 20 );
00063 config.ammoLimit= 10;
00064 config.maxCaptureTime = 15;
00065 config.maxTactTime = 10*100;
00066 config.waitForResourcePlus = 2;
00067
00068 sections.reset();
00069 }
00070
00071
00072
00073 void AI :: setup (void)
00074 {
00075 unitsWorkedInTactics.clear();
00076
00077 displaymessage2("calculating all threats ... ");
00078 calculateAllThreats ();
00079
00080 displaymessage2("calculating field threats ... ");
00081 calculateFieldInformation();
00082
00083 displaymessage2("calculating sections ... ");
00084 sections.calculate();
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 for ( int p = 0; p < 8; p++ )
00119 getMap()->player[p].existanceAtBeginOfTurn = getMap()->player[p].exist();
00120
00121
00122 for ( Player::VehicleList::iterator i = getPlayer().vehicleList.begin(); i != getPlayer().vehicleList.end(); ++i)
00123 if ( (*i)->typ->hasFunction( ContainerBaseType::MoveWithReactionFire ) )
00124 if ( (*i)->reactionfire.getStatus() == Vehicle::ReactionFire::off )
00125 (*i)->reactionfire.enable();
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 displaymessage2("setup completed ... ");
00142 }
00143
00144
00145 void AI::checkKeys ( void )
00146 {
00147 ASC_PG_App* app = &getPGApplication();
00148 if ( app )
00149 for ( int i = 0; i < 5; ++i )
00150 app->processEvent();
00151 }
00152
00153 void AI::removeDisplay()
00154 {
00155 mapDisplay = NULL;
00156 }
00157
00158
00159 typedef Loki::Functor<void> CloseScreenCallback;
00160
00161
00162 class AI_KeyboardWatcher : public SigC::Object {
00163 CloseScreenCallback callback;
00164 MapDisplayPG::LockDisplay* lock;
00165 PG_Widget* w;
00166 MainScreenWidget::StandardActionLocker menuLocker;
00167
00168 bool keyPressed( const SDL_KeyboardEvent* key )
00169 {
00170 if ( key->keysym.sym == SDLK_ESCAPE ) {
00171 callback();
00172
00173 if ( !lock )
00174 lock = new MapDisplayPG::LockDisplay;
00175
00176 return true;
00177 } else
00178 return false;
00179 }
00180
00181 public:
00182 AI_KeyboardWatcher( CloseScreenCallback callback ) : lock(NULL), w(NULL), menuLocker( mainScreenWidget, MainScreenWidget::LockOptions::Menu + MainScreenWidget::LockOptions::MapActions + MainScreenWidget::LockOptions::MapControl)
00183 {
00184
00185
00186
00187 this->callback = callback;
00188
00189 if ( PG_Application::GetApp() )
00190 PG_Application::GetApp()->sigKeyDown.connect( SigC::slot( *this, &AI_KeyboardWatcher::keyPressed ));
00191
00192 };
00193
00194 void release()
00195 {
00196 delete w;
00197 w = NULL;
00198 delete lock;
00199 lock = NULL;
00200 }
00201
00202 ~AI_KeyboardWatcher()
00203 {
00204 release();
00205 }
00206 };
00207
00208 void AI :: checkGameEvents()
00209 {
00210 while ( getMap()->player[ getMap()->actplayer ].queuedEvents )
00211 if ( !checkevents( getMap(), mapDisplay ))
00212 return ;
00213
00214 checktimedevents( getMap(), mapDisplay );
00215 }
00216
00217 class FieldMarkingSuppressor {
00218 MapDisplayInterface* mdi;
00219 public:
00220 FieldMarkingSuppressor( MapDisplayInterface* mdi ) {
00221 this->mdi = mdi;
00222 if ( mdi )
00223 mdi->setTempView( false );
00224 }
00225
00226 ~FieldMarkingSuppressor() {
00227 if ( mdi )
00228 mdi->setTempView( true );
00229 }
00230 };
00231
00232 void AI:: run ( bool benchMark, MapDisplayInterface* myMapDisplay )
00233 {
00234 AI_KeyboardWatcher kw ( CloseScreenCallback( this, &AI::removeDisplay ));
00235
00236 this->benchMark = benchMark;
00237
00238 auto_ptr<ReplayMapDisplay> rmd;
00239 if ( getMap()->getPlayerView() >= 0 && !benchMark && myMapDisplay ) {
00240 rmd.reset( new ReplayMapDisplay ( myMapDisplay ) );
00241 rmd->setCursorDelay (CGameOptions::Instance()->replayspeed + 30 );
00242
00243 mapDisplay = rmd.get();
00244 } else
00245 mapDisplay = NULL;
00246
00247 int startTime = ticker;
00248 AiResult res;
00249
00250 unitCounter = 0;
00251 _isRunning = true;
00252 _vision = visible_ago;
00253
00254 int setupTime = ticker;
00255
00256 FieldMarkingSuppressor fms( mapDisplay );
00257
00258 setup();
00259
00260
00261
00262
00263
00264 diplomacy();
00265
00266 if ( !originalUnitDistribution.calculated )
00267 originalUnitDistribution = calcUnitDistribution();
00268
00269 calcReconPositions();
00270
00271 setupTime = ticker-setupTime;
00272
00273 int serviceTime = ticker;
00274 issueServices( );
00275 executeServices();
00276
00277 checkGameEvents();
00278
00279 serviceTime = ticker-serviceTime;
00280
00281 int conquerTime = ticker;
00282 checkConquer();
00283 conquerTime = ticker - conquerTime;
00284
00285 runReconUnits ( );
00286
00287 int containerTime = ticker;
00288 buildings( 3 );
00289 transports ( 3 );
00290 containerTime = ticker-containerTime;
00291
00292 int tacticsTime = ticker;
00293 do {
00294 res = tactics();
00295 checkGameEvents();
00296 } while ( res.unitsMoved );
00297 tacticsTime = ticker - tacticsTime;
00298
00299 int strategyTime = ticker;
00300 strategy();
00301 checkGameEvents();
00302
00303 strategyTime = ticker - strategyTime;
00304
00305 buildings( 1 );
00306 transports ( 3 );
00307
00308 production();
00309
00310 checkGameEvents();
00311
00312 _isRunning = false;
00313 if ( !mapDisplay )
00314 repaintMap();
00315 int duration = ticker-startTime;
00316
00317
00318
00319
00320
00321
00322
00323
00324 if ( benchMark )
00325 displaymessage ("The AI took %.2f seconds to run\n"
00326 " setup: %d \n"
00327 " service: %d \n"
00328 " conquer: %d \n"
00329 " container: %d \n"
00330 " tactics: %d \n"
00331 " strategy: %d \n",
00332 3, float(duration)/100,
00333 setupTime / 100,
00334 serviceTime/100,
00335 conquerTime /100,
00336 containerTime/100,
00337 tacticsTime/100,
00338 strategyTime/100 );
00339
00340 displaymessage2("AI completed in %d second", duration/100);
00341
00342 checkforvictory( getMap(), false );
00343
00344 mapDisplay = NULL;
00345
00346 }
00347
00348
00349 void AI :: diplomacy ()
00350 {
00351 for ( int i = 0; i < getMap()->getPlayerCount(); ++i ) {
00352 if ( i != getPlayerNum() ) {
00353 DiplomaticStates proposal;
00354 if ( getPlayer().diplomacy.getProposal( i, &proposal )) {
00355
00356 if ( proposal > getPlayer().diplomacy.getState( i ))
00357 new Message( "Your diplomatic proposal is declined", getMap(), 1 << i, 1 << getPlayerNum() );
00358 else {
00359 auto_ptr<DiplomacyCommand> dc ( new DiplomacyCommand( getPlayer()));
00360 dc->newstate( proposal, getMap()->getPlayer(i) );
00361 ActionResult res = dc->execute( getContext() );
00362 if ( res.successful() )
00363 dc.release();
00364 }
00365 }
00366 }
00367 }
00368 }
00369
00370
00371 bool AI :: isRunning ( void )
00372 {
00373 return _isRunning;
00374 }
00375
00376
00377 VisibilityStates AI:: getVision ( void )
00378 {
00379 return _vision;
00380 }
00381
00382 void AI :: showFieldInformation ( int x, int y )
00383 {
00384 if ( !fieldInformation )
00385 calculateFieldInformation();
00386
00387 const char* fieldinfo = "#font02#Field Information (%d,%d)#font01##aeinzug20##eeinzug10##crtp10#"
00388 "threat orbit: %d\n"
00389 "threat high-level flight: %d\n"
00390 "threat flight: %d\n"
00391 "threat low-level flight: %d\n"
00392 "threat ground level: %d\n"
00393 "threat floating: %d\n"
00394 "threat submerged: %d\n"
00395 "threat deep submerged: %d\n"
00396 "controlled by %d\n";
00397
00398 char text[10000];
00399 AiThreat& threat = getFieldThreat ( x, y );
00400 sprintf(text, fieldinfo, x,y,threat.threat[7], threat.threat[6], threat.threat[5],
00401 threat.threat[4], threat.threat[3], threat.threat[2],
00402 threat.threat[1], threat.threat[0], getFieldInformation(x,y).control );
00403
00404 MapField* fld = getMap()->getField (x, y );
00405 if ( fld->vehicle && fieldvisiblenow ( fld ) && fld->vehicle->aiparam[getPlayerNum()] ) {
00406 char text2[1000];
00407 sprintf(text2, "\nunit nwid: %d ; typeid: %d", fld->vehicle->networkid, fld->vehicle->typ->id );
00408 strcat ( text, text2 );
00409 AiParameter& aip = *fld->vehicle->aiparam[getPlayerNum()];
00410
00411 if ( fld->vehicle->aiparam ) {
00412
00413 sprintf(text2, "\nunit value: %d; xtogo: %d, ytogo: %d; ztogo: %d;\njob %s ; task %s \n", aip.getValue(), aip.dest.x, aip.dest.y, aip.dest.getBitmappedHeight(), AIjobs[aip.getJob()], AItasks[aip.getTask()] );
00414 strcat ( text, text2 );
00415 }
00416
00417 if ( aip.dest.x >= 0 && aip.dest.y >= 0 ) {
00418 getMap()->cleartemps ( 1 );
00419 getMap()->getField ( aip.dest.x, aip.dest.y )->a.temp = 1;
00420 }
00421
00422
00423 }
00424
00425 for ( ReconPositions::iterator i = reconPositions.begin(); i != reconPositions.end(); i++ )
00426 getMap()->getField( i->first )->a.temp2 = 1;
00427
00428 repaintMap();
00429
00430
00431 strcat ( text, "\n#font02#Section Information#font01##aeinzug20##eeinzug10##crtp10#");
00432 string s;
00433
00434 Section& sec = sections.getForCoordinate ( x, y );
00435
00436 s += "xp = ";
00437 s += strrr ( sec.xp );
00438 s += " ; yp = ";
00439 s += strrr ( sec.yp );
00440 s += "\n";
00441 const char* threattypes[4] = { "absUnitThreat", "avgUnitThreat", "absFieldThreat", "avgFieldThreat" };
00442
00443 for ( int i = 0; i < 4; i++ ) {
00444 for ( int h = 0; h < 8; h++ ) {
00445 s += threattypes[i];
00446 s += " ";
00447 s += choehenstufen [h];
00448 s += " ";
00449 switch ( i ) {
00450 case 0: s += strrr ( sec.absUnitThreat.threat[h] );
00451 break;
00452 case 1: s += strrr ( sec.avgUnitThreat.threat[h] );
00453 break;
00454 case 2: s += strrr ( sec.absFieldThreat.threat[h] );
00455 break;
00456 case 3: s += strrr ( sec.avgFieldThreat.threat[h] );
00457 break;
00458 }
00459 s += "\n";
00460 }
00461 s += "\n";
00462 }
00463
00464 for ( int j = 0; j < aiValueTypeNum; j++ ) {
00465 s+= "\nvalue ";
00466 s+= strrr ( j );
00467 s+= " = ";
00468 s+= strrr ( sec.value[j] );
00469 }
00470
00471 strcat ( text, s.c_str() );
00472
00473 ViewFormattedText vft( "AI information", text, PG_Rect( -1, -1, 500, 550 ) );
00474 vft.Show();
00475 vft.RunModal();
00476 }
00477
00478
00479 const int currentAiStreamVersion = 104;
00480
00481 void AI :: read ( tnstream& stream )
00482 {
00483 int version = stream.readInt ( );
00484 if ( version > currentServiceOrderVersion )
00485 throw tinvalidversion ( "AI :: read", currentServiceOrderVersion, version );
00486 _isRunning = stream.readInt ();
00487 _vision = VisibilityStates(stream.readInt ( ));
00488 unitCounter = stream.readInt ( );
00489
00490 int i = stream.readInt();
00491 while ( i ) {
00492 ServiceOrder so ( this, stream );
00493 serviceOrders.push_back ( so );
00494 i = stream.readInt();
00495 }
00496
00497 for_each ( serviceOrders.begin(), serviceOrders.end(), ServiceOrder::activate );
00498
00499 i = stream.readInt();
00500 while ( i ) {
00501 MapCoordinate mc;
00502 mc.read ( stream );
00503
00504 AI::BuildingCapture bc;
00505 bc.read ( stream );
00506
00507 buildingCapture[mc] = bc;
00508
00509 i = stream.readInt();
00510 }
00511
00512 config.lookIntoTransports = stream.readInt();
00513 config.lookIntoBuildings = stream.readInt( );
00514 config.wholeMapVisible = stream.readInt( );
00515 config.aggressiveness = stream.readFloat( );
00516 config.damageLimit = stream.readInt();
00517 config.resourceLimit.read( stream );
00518 config.ammoLimit = stream.readInt();
00519 config.maxCaptureTime = stream.readInt();
00520 if ( version >= 102 )
00521 config.waitForResourcePlus = stream.readInt();
00522
00523 if ( version >= 101 )
00524 config.maxTactTime = stream.readInt();
00525
00526 if ( version >= 102 )
00527 originalUnitDistribution.read ( stream );
00528
00529 if ( version >= 103 ) {
00530 int id = stream.readInt();
00531 while ( id >= 0 ) {
00532 float enemyValue = stream.readFloat();
00533 float ownValue = stream.readFloat();
00534 unitTypeSuccess[id] = make_pair ( enemyValue, ownValue );
00535 id = stream.readInt();
00536 }
00537 }
00538
00539 if ( version >= 104 ) {
00540 int id = stream.readInt();
00541 while ( id >= 0 ) {
00542 stream.readFloat();
00543 stream.readFloat();
00544 id = stream.readInt();
00545 }
00546 }
00547
00548 int version2 = stream.readInt();
00549 if ( version != version2 )
00550 throw tinvalidversion ( "AI :: read", version, version2 );
00551
00552
00553 }
00554
00555 void AI :: write ( tnstream& stream ) const
00556 {
00557 const int version = currentAiStreamVersion;
00558 stream.writeInt ( version );
00559 stream.writeInt ( _isRunning );
00560 stream.writeInt ( _vision );
00561 stream.writeInt ( unitCounter );
00562
00563 for ( ServiceOrderContainer::const_iterator i = serviceOrders.begin(); i != serviceOrders.end(); i++) {
00564 stream.writeInt ( 1 );
00565 i->write ( stream );
00566 }
00567
00568 stream.writeInt ( 0 );
00569
00570 for ( map<MapCoordinate,BuildingCapture>::const_iterator i = buildingCapture.begin(); i != buildingCapture.end(); i++ ) {
00571 stream.writeInt ( 1 );
00572 i->first.write ( stream );
00573 i->second.write ( stream );
00574 }
00575 stream.writeInt ( 0 );
00576
00577 stream.writeInt( config.lookIntoTransports );
00578 stream.writeInt( config.lookIntoBuildings );
00579 stream.writeInt( config.wholeMapVisible );
00580 stream.writeFloat( config.aggressiveness );
00581 stream.writeInt( config.damageLimit );
00582 config.resourceLimit.write( stream );
00583 stream.writeInt( config.ammoLimit );
00584 stream.writeInt( config.maxCaptureTime );
00585 stream.writeInt( config.maxTactTime );
00586 stream.writeInt( config.waitForResourcePlus );
00587
00588 originalUnitDistribution.write( stream );
00589
00590 for ( UnitTypeSuccess::const_iterator i = unitTypeSuccess.begin(); i != unitTypeSuccess.end(); ++i ) {
00591 stream.writeInt( i->first );
00592 stream.writeFloat( i->second.first );
00593 stream.writeFloat( i->second.second );
00594 }
00595 stream.writeInt( -1 );
00596 stream.writeInt( -1 );
00597
00598 stream.writeInt ( version );
00599 }
00600
00601 Context AI :: getContext()
00602 {
00603 Context context;
00604
00605 context.gamemap = getMap();
00606 context.actingPlayer = &getPlayer();
00607 context.parentAction = NULL;
00608 context.display = mapDisplay;
00609 context.viewingPlayer = getMap()->getPlayerView();
00610 context.actionContainer = &getMap()->actions;
00611 return context;
00612 }
00613
00614 AI :: ~AI ( )
00615 {
00616 if ( fieldInformation ) {
00617 delete[] fieldInformation;
00618 fieldInformation = NULL;
00619 fieldNum = 0;
00620 }
00621 }
00622
00623