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