00001
00002
00003
00004
00005
00006
00007
00008
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdarg.h>
00026 #include "replay.h"
00027 #include "typen.h"
00028 #include "buildingtype.h"
00029 #include "vehicletype.h"
00030 #include "spfst.h"
00031 #include "controls.h"
00032 #include "dialog.h"
00033 #include "gameoptions.h"
00034 #include "viewcalculation.h"
00035 #include "itemrepository.h"
00036 #include "containercontrols.h"
00037 #include "resourcenet.h"
00038 #include "guiiconhandler.h"
00039 #include "guifunctions.h"
00040 #include "cannedmessages.h"
00041 #include "spfst-legacy.h"
00042 #include "replaymapdisplay.h"
00043 #include "asc-mainscreen.h"
00044 #include "loaders.h"
00045 #include "turncontrol.h"
00046 #include "widgets/textrenderer.h"
00047 #include "actions/jumpdrivecommand.h"
00048 #include "reactionfire.h"
00049 #include "gameeventsystem.h"
00050 #include "sdl/graphicsqueue.h"
00051 #include "video/videorecorder.h"
00052 #include "iconrepository.h"
00053 #include "dialogs/replayrecorder.h"
00054 #include "sg.h"
00055 #include "actions/action.h"
00056 #include "actions/cargomovecommand.h"
00057 #include "actions/constructbuildingcommand.h"
00058 #include "actions/destructbuildingcommand.h"
00059 #include "actions/destructunitcommand.h"
00060 #include "actions/recycleunitcommand.h"
00061 #include "actions/trainunitcommand.h"
00062 #include "actions/moveunitcommand.h"
00063 #include "actions/consumeammo.h"
00064 #include "actions/consumeresource.h"
00065 #include "actions/buildproductionlinecommand.h"
00066 #include "actions/removeproductionlinecommand.h"
00067 #include "actions/cancelresearchcommand.h"
00068 #include "researchexecution.h"
00069
00070 trunreplay runreplay;
00071
00072 int startreplaylate = 0;
00073
00074
00075 enum trpl_actions { rpl_attack,
00076 rpl_move,
00077 rpl_changeheight,
00078 rpl_convert,
00079 rpl_remobj,
00080 rpl_buildobj,
00081 rpl_putbuilding,
00082 rpl_removebuilding,
00083 rpl_putmine,
00084 rpl_removemine,
00085 rpl_produceunit,
00086 rpl_removeunit,
00087 rpl_trainunit,
00088 rpl_reactionfire,
00089 rpl_finished,
00090 rpl_shareviewchange,
00091 rpl_alliancechange,
00092 rpl_move2,
00093 rpl_buildtnk,
00094 rpl_refuel,
00095 rpl_bldrefuel,
00096 rpl_move3,
00097 rpl_changeheight2,
00098 rpl_buildtnk2,
00099 rpl_moveUnitUpDown,
00100 rpl_move4,
00101 rpl_productionResourceUsage,
00102 rpl_buildtnk3,
00103 rpl_refuel2,
00104 rpl_buildobj2,
00105 rpl_remobj2,
00106 rpl_repairUnit,
00107 rpl_repairUnit2,
00108 rpl_refuel3,
00109 rpl_produceAmmo,
00110 rpl_buildtnk4,
00111 rpl_buildProdLine,
00112 rpl_removeProdLine,
00113 rpl_setResearch,
00114 rpl_techResearched,
00115 rpl_putbuilding2,
00116 rpl_setGeneratorStatus,
00117 rpl_cutFromGame,
00118 rpl_removebuilding2,
00119 rpl_setResourceProcessingAmount,
00120 rpl_removebuilding3,
00121 rpl_netcontrol,
00122 rpl_move5,
00123 rpl_alliancechange2,
00124 rpl_moveUnitUp,
00125 rpl_jump,
00126 rpl_repairBuilding,
00127 rpl_recycleUnit,
00128 rpl_convert2,
00129 rpl_putmine2,
00130 rpl_repairUnit3,
00131 rpl_transferTribute,
00132 rpl_reactionFireOn,
00133 rpl_reactionFireOff,
00134 rpl_selfdestruct,
00135 rpl_cancelResearch,
00136 rpl_runCommandAction };
00137
00138
00139
00140 class ReplayRecorder;
00141
00142 class ReplayRecorderWatcherGlobal {
00143 ReplayRecorder* recorder;
00144 public:
00145 ReplayRecorderWatcherGlobal() : recorder( NULL ) {};
00146 void set( ReplayRecorder* rec ) {
00147 recorder = rec;
00148 }
00149
00150 ~ReplayRecorderWatcherGlobal() ;
00151 } replayRecorderWatcherGlobal;
00152
00153
00154 class ReplayRecorder : public SigC::Object {
00155
00156 VideoRecorder* rec;
00157 SigC::Connection connection;
00158 bool movieModeStorage;
00159 ASCString lastFilename;
00160
00161 public:
00162 ReplayRecorder() : rec (NULL)
00163 {
00164 movieModeStorage = CGameOptions::Instance()->replayMovieMode;
00165 replayRecorderWatcherGlobal.set( this );
00166 }
00167
00168 void start( const ASCString& filename, bool append, int framerate, int ascFramerateLimit, int quality )
00169 {
00170 lastFilename = filename;
00171 movieModeStorage = CGameOptions::Instance()->replayMovieMode;
00172 CGameOptions::Instance()->replayMovieMode = true;
00173 ASCString newFilename = constructFileName( 0, "", filename );
00174 if ( !rec || !append || newFilename != rec->getFilename() ) {
00175 delete rec;
00176 rec = new VideoRecorder( newFilename, PG_Application::GetScreen(), framerate, ascFramerateLimit, quality );
00177 }
00178
00179 if ( !connection.connected() )
00180 connection = postScreenUpdate.connect( SigC::slot( *this, &ReplayRecorder::screenUpdate ));
00181 }
00182
00183 void pause()
00184 {
00185 if ( connection.connected() )
00186 connection.disconnect();
00187 CGameOptions::Instance()->replayMovieMode = movieModeStorage;
00188 }
00189
00190 void close()
00191 {
00192 pause();
00193 delete rec;
00194 rec = NULL;
00195 }
00196
00197 bool isRunning()
00198 {
00199 return connection.connected() && rec;
00200 }
00201
00202 bool isOpen()
00203 {
00204 return rec != NULL;
00205 }
00206
00207 ASCString getLastFilename()
00208 {
00209 return lastFilename;
00210 }
00211
00212 private:
00213 void screenUpdate( const SDL_Surface* surf )
00214 {
00215 if ( rec )
00216 rec->storeFrame( surf );
00217 }
00218 };
00219
00220 class ReplayRecorderWatcherLocal {
00221 ReplayRecorder* recorder;
00222 public:
00223 ReplayRecorderWatcherLocal( ReplayRecorder* rec ) : recorder( rec ) {};
00224 ~ReplayRecorderWatcherLocal()
00225 {
00226 if ( recorder )
00227 recorder->pause();
00228 }
00229 };
00230
00231
00232 ReplayRecorderWatcherGlobal::~ReplayRecorderWatcherGlobal()
00233 {
00234 if ( recorder )
00235 recorder->pause();
00236 }
00237
00238
00239 ReplayRecorder* replayRecorder = NULL;
00240
00241
00242
00243 namespace ReplayGuiFunctions {
00244
00245 class ReplayPlay : public GuiFunction
00246 {
00247 public:
00248 bool available( const MapCoordinate& pos, ContainerBase* subject, int num )
00249 {
00250 if ( runreplay.status == 1 )
00251 return true;
00252
00253 return false;
00254 };
00255
00256 void execute( const MapCoordinate& pos, ContainerBase* subject, int num )
00257 {
00258 runreplay.status = 2;
00259 updateFieldInfo();
00260 }
00261
00262 Surface& getImage( const MapCoordinate& pos, ContainerBase* subject, int num )
00263 {
00264 return IconRepository::getIcon("replay-play.png");
00265 };
00266
00267 ASCString getName( const MapCoordinate& pos, ContainerBase* subject, int num )
00268 {
00269 return "start re~p~lay";
00270 };
00271
00272 bool checkForKey( const SDL_KeyboardEvent* key, int modifier, int num )
00273 {
00274 return ( key->keysym.unicode == 'p' );
00275 };
00276
00277 };
00278
00279
00280 class ReplayPause : public GuiFunction
00281 {
00282 public:
00283 bool available( const MapCoordinate& pos, ContainerBase* subject, int num )
00284 {
00285 if ( runreplay.status == 2 )
00286 return true;
00287
00288 return false;
00289 };
00290
00291 void execute( const MapCoordinate& pos, ContainerBase* subject, int num )
00292 {
00293 runreplay.status = 1;
00294 updateFieldInfo();
00295 }
00296
00297 Surface& getImage( const MapCoordinate& pos, ContainerBase* subject, int num )
00298 {
00299 return IconRepository::getIcon("replay-pause.png");
00300 };
00301
00302 ASCString getName( const MapCoordinate& pos, ContainerBase* subject, int num )
00303 {
00304 return "~p~ause replay";
00305 };
00306
00307 bool checkForKey( const SDL_KeyboardEvent* key, int modifier, int num )
00308 {
00309 return ( key->keysym.unicode == 'p' );
00310 };
00311
00312 };
00313
00314
00315
00316 class ReplayFaster : public GuiFunction
00317 {
00318 public:
00319 bool available( const MapCoordinate& pos, ContainerBase* subject, int num )
00320 {
00321 if ( runreplay.status == 2 )
00322 if ( CGameOptions::Instance()->replayspeed > 0 )
00323 return true;
00324
00325 return false;
00326 };
00327
00328 void execute( const MapCoordinate& pos, ContainerBase* subject, int num )
00329 {
00330 if ( CGameOptions::Instance()->replayspeed > 20 )
00331 CGameOptions::Instance()->replayspeed -= 20;
00332 else
00333 CGameOptions::Instance()->replayspeed = 0;
00334
00335 CGameOptions::Instance()->setChanged ( 1 );
00336 displaymessage2 ( "delay set to %d / 100 sec", CGameOptions::Instance()->replayspeed );
00337 updateFieldInfo();
00338 }
00339
00340 Surface& getImage( const MapCoordinate& pos, ContainerBase* subject, int num )
00341 {
00342 return IconRepository::getIcon("replay-faster.png");
00343 };
00344
00345 ASCString getName( const MapCoordinate& pos, ContainerBase* subject, int num )
00346 {
00347 return "increase replay speed (~+~)";
00348 };
00349
00350 bool checkForKey( const SDL_KeyboardEvent* key, int modifier, int num )
00351 {
00352 return ( key->keysym.unicode == '+' || key->keysym.sym == SDLK_KP_PLUS);
00353 };
00354
00355 };
00356
00357
00358 class ReplaySlower : public GuiFunction
00359 {
00360 public:
00361 bool available( const MapCoordinate& pos, ContainerBase* subject, int num )
00362 {
00363 if ( runreplay.status == 2 )
00364 return true;
00365
00366 return false;
00367 };
00368
00369 void execute( const MapCoordinate& pos, ContainerBase* subject, int num )
00370 {
00371 CGameOptions::Instance()->replayspeed += 20;
00372 CGameOptions::Instance()->setChanged ( 1 );
00373 displaymessage2 ( "delay set to %d / 100 sec", CGameOptions::Instance()->replayspeed );
00374 updateFieldInfo();
00375 }
00376
00377 Surface& getImage( const MapCoordinate& pos, ContainerBase* subject, int num )
00378 {
00379 return IconRepository::getIcon("replay-slow.png");
00380 };
00381
00382 ASCString getName( const MapCoordinate& pos, ContainerBase* subject, int num )
00383 {
00384 return "decrease replay speed (~-~)";
00385 };
00386
00387 bool checkForKey( const SDL_KeyboardEvent* key, int modifier, int num )
00388 {
00389 return ( key->keysym.unicode == '-' || key->keysym.sym == SDLK_KP_MINUS);
00390 };
00391
00392 };
00393
00394
00395 class ReplayRewind : public GuiFunction
00396 {
00397 public:
00398 bool available( const MapCoordinate& pos, ContainerBase* subject, int num )
00399 {
00400 if ( runreplay.status == 1 || runreplay.status == 10 )
00401 return true;
00402
00403 return false;
00404 };
00405
00406 void execute( const MapCoordinate& pos, ContainerBase* subject, int num )
00407 {
00408 runreplay.status = 101;
00409 updateFieldInfo();
00410 }
00411
00412 Surface& getImage( const MapCoordinate& pos, ContainerBase* subject, int num )
00413 {
00414 return IconRepository::getIcon("replay-back.png");
00415 };
00416
00417 ASCString getName( const MapCoordinate& pos, ContainerBase* subject, int num )
00418 {
00419 return "~r~estart replay";
00420 };
00421
00422 bool checkForKey( const SDL_KeyboardEvent* key, int modifier, int num )
00423 {
00424 return ( key->keysym.unicode == 'r' );
00425 };
00426
00427 };
00428
00429
00430 class ReplayExit : public GuiFunction
00431 {
00432 public:
00433 bool available( const MapCoordinate& pos, ContainerBase* subject, int num )
00434 {
00435 if ( runreplay.status == 1 || runreplay.status == 10 || runreplay.status == 11 )
00436 return true;
00437
00438 return false;
00439 };
00440
00441 void execute( const MapCoordinate& pos, ContainerBase* subject, int num )
00442 {
00443 runreplay.status = 100;
00444 updateFieldInfo();
00445 }
00446
00447 Surface& getImage( const MapCoordinate& pos, ContainerBase* subject, int num )
00448 {
00449 return IconRepository::getIcon("replay-exit.png");
00450 };
00451
00452 ASCString getName( const MapCoordinate& pos, ContainerBase* subject, int num )
00453 {
00454 return "e~x~it replay";
00455 };
00456
00457 bool checkForKey( const SDL_KeyboardEvent* key, int modifier, int num )
00458 {
00459 return ( key->keysym.unicode == 'x' );
00460 };
00461
00462 };
00463
00464 class ReplayRecord : public GuiFunction
00465 {
00466 public:
00467 bool available( const MapCoordinate& pos, ContainerBase* subject, int num )
00468 {
00469 if ( runreplay.status == 1 )
00470 return true;
00471
00472 return false;
00473 };
00474
00475 void execute( const MapCoordinate& pos, ContainerBase* subject, int num )
00476 {
00477 ASCString filename;
00478 bool open = false;
00479 if ( replayRecorder ) {
00480 filename = replayRecorder->getLastFilename();
00481 open = replayRecorder->isOpen();
00482 }
00483
00484 ReplayRecorderDialog rrd( filename, open );
00485 rrd.Show();
00486 rrd.RunModal();
00487 rrd.Hide();
00488
00489 if ( !replayRecorder )
00490 replayRecorder = new ReplayRecorder();
00491 replayRecorder->start( rrd.getFilename(), rrd.getAppend(), rrd.getFramerate(), rrd.getASCFramerateLimit(), rrd.getQuality() );
00492
00493 runreplay.status = 2;
00494 updateFieldInfo();
00495 }
00496
00497 Surface& getImage( const MapCoordinate& pos, ContainerBase* subject, int num )
00498 {
00499 return IconRepository::getIcon("replay-record.png");
00500 };
00501
00502 ASCString getName( const MapCoordinate& pos, ContainerBase* subject, int num )
00503 {
00504 return "record to ~v~ideo";
00505 };
00506
00507 bool checkForKey( const SDL_KeyboardEvent* key, int modifier, int num )
00508 {
00509 return ( key->keysym.unicode == 'v' );
00510 };
00511
00512 };
00513
00514 class ReplayRecordExit : public GuiFunction
00515 {
00516 public:
00517 bool available( const MapCoordinate& pos, ContainerBase* subject, int num )
00518 {
00519 if ( replayRecorder && replayRecorder->isOpen() && (runreplay.status == 1 || runreplay.status == 10 || runreplay.status == 11) )
00520 return true;
00521
00522 return false;
00523 };
00524
00525 void execute( const MapCoordinate& pos, ContainerBase* subject, int num )
00526 {
00527 replayRecorder->close();
00528 runreplay.status = 100;
00529 updateFieldInfo();
00530 }
00531
00532 Surface& getImage( const MapCoordinate& pos, ContainerBase* subject, int num )
00533 {
00534 return IconRepository::getIcon("replay-record-stop.png");
00535 };
00536
00537 ASCString getName( const MapCoordinate& pos, ContainerBase* subject, int num )
00538 {
00539 return "exit replay and ~c~lose recording";
00540 };
00541
00542 bool checkForKey( const SDL_KeyboardEvent* key, int modifier, int num )
00543 {
00544 return ( key->keysym.unicode == 'c' );
00545 };
00546
00547 };
00548
00549
00550 }
00551
00552 void registerReplayGuiFunctions( GuiIconHandler& handler )
00553 {
00554 handler.registerUserFunction( new ReplayGuiFunctions::ReplayPlay() );
00555 #ifdef XVIDEXPORT
00556 handler.registerUserFunction( new ReplayGuiFunctions::ReplayRecord() );
00557 #endif
00558 handler.registerUserFunction( new ReplayGuiFunctions::ReplayPause() );
00559 handler.registerUserFunction( new ReplayGuiFunctions::ReplayFaster() );
00560 handler.registerUserFunction( new ReplayGuiFunctions::ReplaySlower() );
00561 handler.registerUserFunction( new ReplayGuiFunctions::ReplayRewind() );
00562 #ifdef XVIDEXPORT
00563 handler.registerUserFunction( new ReplayGuiFunctions::ReplayRecordExit() );
00564 #endif
00565 handler.registerUserFunction( new ReplayGuiFunctions::ReplayExit() );
00566 }
00567
00568
00569
00570 class ReplayGuiIconHandleHandler {
00571 static GuiIconHandler* replayIconHandler;
00572 bool active;
00573 public:
00574 ReplayGuiIconHandleHandler()
00575 {
00576 if ( !replayIconHandler ) {
00577 replayIconHandler = new GuiIconHandler();
00578 registerReplayGuiFunctions( *replayIconHandler );
00579 }
00580
00581 if ( NewGuiHost::getIconHandler() != replayIconHandler ) {
00582 active = true;
00583 NewGuiHost::pushIconHandler( replayIconHandler );
00584 } else
00585 active = false;
00586 };
00587
00588 ~ReplayGuiIconHandleHandler()
00589 {
00590 if ( active )
00591 NewGuiHost::popIconHandler();
00592 };
00593 };
00594 GuiIconHandler* ReplayGuiIconHandleHandler::replayIconHandler = NULL;
00595
00596
00597
00598
00599
00600 void runSpecificReplay( int player, int viewingplayer, bool performEndTurnOperations )
00601 {
00602 if ( actmap->replayinfo->map[player] && actmap->replayinfo->guidata[player] ) {
00603 try {
00604 int t;
00605 do {
00606 t = runreplay.run ( player, viewingplayer, performEndTurnOperations );
00607 } while ( t );
00608 }
00609
00610 catch ( ActionResult res ) {
00611
00612 delete actmap;
00613 actmap = NULL;
00614 throw NoMapLoaded();
00615 }
00616
00617 #ifndef ASC_DEBUG
00618 catch ( ... ) {
00619 #else
00620 catch ( GameMap m ) {
00621 #endif
00622 errorMessage("An unrecognized error occured during the replay");
00623 delete actmap;
00624 actmap = NULL;
00625 throw NoMapLoaded();
00626 }
00627 }
00628 }
00629
00630 void viewOwnReplay( Player& player )
00631 {
00632 if ( player.stat == Player::human || player.stat == Player::supervisor )
00633 if ( CGameOptions::Instance()->debugReplay && player.getParentMap()->replayinfo )
00634 if (choice_dlg("run replay of your turn ?","~y~es","~n~o") == 1) {
00635
00636 runSpecificReplay ( player.getPosition(), player.getPosition(), false );
00637 }
00638 }
00639
00640
00641 void checkforreplay ( void )
00642 {
00643 if ( !actmap->replayinfo )
00644 return;
00645
00646 int rpnum = 0;
00647 int s = actmap->actplayer + 1;
00648 if ( s >= 8 )
00649 s = 0;
00650 while ( s != actmap->actplayer ) {
00651 if ( actmap->replayinfo->map[s] && actmap->replayinfo->guidata[s] )
00652 rpnum++;
00653
00654 if ( s < 7 )
00655 s++;
00656 else
00657 s = 0;
00658 }
00659
00660
00661 if ( actmap->replayinfo && rpnum && (actmap->player[ actmap->actplayer ].stat == Player::human || actmap->player[ actmap->actplayer ].stat == Player::supervisor) )
00662 if (choice_dlg("run replay of last turn ?","~y~es","~n~o") == 1) {
00663
00664 MainScreenWidget::StandardActionLocker locker( mainScreenWidget, MainScreenWidget::LockOptions::Menu );
00665 ReplayGuiIconHandleHandler guiIconHandler;
00666
00667 int s = actmap->actplayer + 1;
00668 if ( s >= 8 )
00669 s = 0;
00670 while ( s != actmap->actplayer ) {
00671 if ( s >= 8 )
00672 s = 0;
00673
00674 runSpecificReplay(s, actmap->actplayer );
00675
00676 if ( s < 7 )
00677 s++;
00678 else
00679 s = 0;
00680 }
00681
00682
00683 }
00684 }
00685
00686
00687 void initReplayLogging( Player& player )
00688 {
00689 GameMap* gamemap = player.getParentMap();
00690
00691 if ( startreplaylate ) {
00692 gamemap->replayinfo = new GameMap::ReplayInfo;
00693 startreplaylate = 0;
00694 }
00695
00696 if ( gamemap->replayinfo && player.stat != Player::off ) {
00697 if ( gamemap->replayinfo->actmemstream )
00698 fatalError( "actmemstream already open at begin of turn " );
00699
00700 if ( gamemap->replayinfo->guidata[ player.getPosition() ] ) {
00701 delete gamemap->replayinfo->guidata[ player.getPosition() ];
00702 gamemap->replayinfo->guidata[ player.getPosition() ] = NULL;
00703 }
00704
00705 savereplay ( gamemap, player.getPosition() );
00706
00707 gamemap->replayinfo->guidata[ player.getPosition() ] = new MemoryStreamStorage;
00708 gamemap->replayinfo->actmemstream = new MemoryStream ( gamemap->replayinfo->guidata[ player.getPosition() ], tnstream::writing );
00709 }
00710 }
00711
00712
00713 LockReplayRecording::LockReplayRecording( GameMap::ReplayInfo& _ri )
00714 : ri ( _ri )
00715 {
00716 ri.stopRecordingActions++;
00717 }
00718
00719 LockReplayRecording::~LockReplayRecording()
00720 {
00721 ri.stopRecordingActions--;
00722 }
00723
00724
00725 Resources getUnitResourceCargo ( Vehicle* veh )
00726 {
00727 Resources res = veh->getTank();
00728 for ( ContainerBase::Cargo::const_iterator i = veh->getCargo().begin(); i != veh->getCargo().end(); ++i )
00729 if ( *i )
00730 res += getUnitResourceCargo ( *i );
00731 return res;
00732 }
00733
00734 class LogActionIntoReplayInfo {
00735 GameMap* gamemap;
00736 public:
00737 LogActionIntoReplayInfo( GameMap* map ) : gamemap( map ) {
00738
00739 };
00740
00741 void saveCommand( const Command& cmd )
00742 {
00743 if ( gamemap->replayinfo && gamemap->replayinfo->actmemstream && !gamemap->replayinfo->stopRecordingActions) {
00744 tnstream* stream = gamemap->replayinfo->actmemstream;
00745
00746 stream->writeChar( rpl_runCommandAction );
00747
00748 MemoryStreamStorage buff;
00749 {
00750 MemoryStream stream2( &buff, tnstream::writing );
00751 cmd.write( stream2 );
00752 }
00753
00754
00755 int size = (buff.getSize()+3)/4;
00756 stream->writeInt( size + 1 );
00757
00758 int padding = size*4 - buff.getSize();
00759 stream->writeInt( padding );
00760
00761 buff.writetostream( stream );
00762 for ( int i = 0; i < padding;++i )
00763 stream->writeChar( 255-i );
00764 }
00765 }
00766 };
00767
00768 static void logActionToReplay( GameMap* map, Command& command)
00769 {
00770 LogActionIntoReplayInfo lairi( map );
00771 lairi.saveCommand( command );
00772 }
00773
00774
00775 Context trunreplay::createReplayContext()
00776 {
00777 Context context;
00778
00779 context.gamemap = actmap;
00780 context.actingPlayer = &actmap->getPlayer( actmap->actplayer );
00781 context.parentAction = NULL;
00782
00783 if ( !replayMapDisplay )
00784 replayMapDisplay = new ReplayMapDisplay( &getDefaultMapDisplay() );
00785
00786 context.display = replayMapDisplay;
00787 context.viewingPlayer = actmap->getPlayerView();
00788 context.actionContainer = &actmap->actions;
00789 return context;
00790 }
00791
00792
00793
00794
00795 trunreplay :: trunreplay ()
00796 {
00797 replayMapDisplay = NULL;
00798 status = -1;
00799 movenum = 0;
00800 }
00801
00802 trunreplay :: ~trunreplay()
00803 {
00804 delete replayMapDisplay;
00805 }
00806
00807 void trunreplay::error( const ActionResult& res )
00808 {
00809 error( ASCString(getmessage(res.getCode() )) + res.getMessage() );
00810 }
00811
00812 void trunreplay::error( const MapCoordinate& pos, const ASCString& message )
00813 {
00814 error( message );
00815 }
00816
00817
00818 void trunreplay::error( const MapCoordinate& pos, const char* message, ... )
00819 {
00820 if ( CGameOptions::Instance()->replayMovieMode )
00821 return;
00822
00823 va_list paramlist;
00824 va_start ( paramlist, message );
00825 char tempbuf[1000];
00826 int lng = vsprintf( tempbuf, message, paramlist );
00827
00828 assert(lng < 1000);
00829 error( tempbuf );
00830
00831 }
00832
00833 void trunreplay::error( const char* message, ... )
00834 {
00835 if ( CGameOptions::Instance()->replayMovieMode )
00836 return;
00837
00838 if ( message != lastErrorMessage ) {
00839 va_list paramlist;
00840 va_start ( paramlist, message );
00841
00842 char tempbuf[1000];
00843
00844 int lng = vsprintf( tempbuf, message, paramlist );
00845 if ( lng >= 1000 )
00846 displaymessage ( "trunreplay::error: String to long !\nPlease report this error", 1 );
00847
00848 va_end ( paramlist );
00849
00850 displaymessage(tempbuf, 1 );
00851 lastErrorMessage = message;
00852 }
00853 }
00854
00855 void trunreplay::error( const ASCString& message )
00856 {
00857 if ( CGameOptions::Instance()->replayMovieMode )
00858 return;
00859
00860 if ( message != lastErrorMessage ) {
00861 displaymessage(message.c_str(), 1 );
00862 lastErrorMessage = message;
00863 }
00864 }
00865
00866
00867
00868
00869 void trunreplay :: wait ( int t )
00870 {
00871
00872 while ( ticker < t + CGameOptions::Instance()->replayspeed && !keypress()) {
00873
00874
00875
00876
00877
00878
00879
00880 releasetimeslice();
00881 }
00882 }
00883
00884 void trunreplay :: wait ( MapCoordinate pos, int t )
00885 {
00886 if ( fieldvisiblenow ( actmap->getField ( pos ), actmap->getPlayerView() ))
00887 wait();
00888 }
00889
00890 void trunreplay :: wait ( MapCoordinate pos1, MapCoordinate pos2, int t )
00891 {
00892 if ( fieldvisiblenow ( actmap->getField ( pos1 ), actmap->getPlayerView() ) || fieldvisiblenow ( actmap->getField ( pos2 ), actmap->getPlayerView() ))
00893 wait();
00894 }
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910 void trunreplay :: displayActionCursor ( int x1, int y1, int x2, int y2, int secondWait )
00911 {
00912 ReplayMapDisplay rmd( &getDefaultMapDisplay() );
00913 rmd.setCursorDelay ( CGameOptions::Instance()->replayspeed );
00914 rmd.displayActionCursor ( x1, y1, x2, y2, secondWait );
00915 }
00916
00917 void trunreplay :: removeActionCursor ( void )
00918 {
00919 ReplayMapDisplay rmd( &getDefaultMapDisplay() );
00920 rmd.removeActionCursor ( );
00921 }
00922
00923
00924 void trunreplay :: execnextreplaymove ( void )
00925 {
00926
00927 static int lastTicker = ticker;
00928
00929 if ( lastTicker + 10 < ticker ) {
00930 displayLogMessage( 8, "executing replay move %d\n", movenum );
00931 lastTicker = ticker;
00932 }
00933
00934 if ( !replayRecorder || !replayRecorder->isRunning())
00935 displaymessage2("executing replay move %d\n", movenum );
00936
00937 movenum++;
00938 int actaction = nextaction;
00939 if ( nextaction != rpl_finished ) {
00940 switch ( nextaction ) {
00941 case rpl_move: {
00942 stream->readInt();
00943 int x1 = stream->readInt();
00944 int y1 = stream->readInt();
00945 int x2 = stream->readInt();
00946 int y2 = stream->readInt();
00947 int nwid = stream->readInt();
00948 readnextaction();
00949
00950 Vehicle* eht = actmap->getUnit ( x1, y1, nwid );
00951 if ( eht ) {
00952 ReplayMapDisplay rmd ( &getDefaultMapDisplay() );
00953
00954
00955 auto_ptr<MoveUnitCommand> muc ( new MoveUnitCommand( eht ));
00956 muc->setDestination( MapCoordinate(x2,y2) );
00957
00958 int t = ticker;
00959 wait( MapCoordinate(x1,y1), MapCoordinate(x2,y2), t );
00960
00961 ActionResult res = muc->execute( createReplayContext() );
00962 if ( res.successful() )
00963 muc.release();
00964 else
00965 error("severe replay inconsistency:\nerror for move1 command at " + MapCoordinate(x1,y1).toString() );
00966 }
00967
00968 if ( !eht )
00969 error("severe replay inconsistency:\nno vehicle for move1 command at " + MapCoordinate(x1,y1).toString() );
00970 }
00971 break;
00972 case rpl_move5:
00973 case rpl_move4:
00974 case rpl_move3:
00975 case rpl_move2: {
00976 stream->readInt();
00977 int x1 = stream->readInt();
00978 int y1 = stream->readInt();
00979 int x2 = stream->readInt();
00980 int y2 = stream->readInt();
00981 int nwid = stream->readInt();
00982 int height = stream->readInt();
00983 int noInterrupt;
00984 if ( nextaction == rpl_move3 || nextaction == rpl_move4 || nextaction == rpl_move5 )
00985 noInterrupt = stream->readInt();
00986 else
00987 noInterrupt = -1;
00988
00989 int destDamage;
00990 if ( nextaction == rpl_move5 )
00991 destDamage = stream->readInt();
00992 else
00993 destDamage = -1;
00994
00995 readnextaction();
00996
00997 Vehicle* eht = actmap->getUnit ( x1, y1, nwid );
00998 if ( eht ) {
00999 auto_ptr<MoveUnitCommand> muc ( new MoveUnitCommand( eht ));
01000
01001 int t = ticker;
01002 wait( MapCoordinate(x1,y1), MapCoordinate(x2,y2), t );
01003
01004 MapCoordinate3D dest ( x2,y2, 0 );
01005 dest.setNumericalHeight(height);
01006 muc->setDestination( dest );
01007
01008 ActionResult res = muc->execute( createReplayContext());
01009 if ( res.successful() )
01010 muc.release();
01011 else {
01012 if ( CGameOptions::Instance()->replayMovieMode ) {
01013
01014 MapField* fld = eht->getMap()->getField(x1,y1);
01015 if ( fld->vehicle == eht ) {
01016 fld->vehicle = NULL;
01017 } else {
01018 if ( fld->getContainer() )
01019 fld->getContainer()->removeUnitFromCargo( eht, true );
01020 }
01021
01022 if ( eht->isViewing() )
01023 eht->removeview();
01024
01025
01026 eht->setnewposition(x2,y2);
01027 if ( height >= 0 )
01028 eht->height = 1 << height;
01029
01030 MapField* fld2 = eht->getMap()->getField(x2,y2);
01031 if ( !fld2->getContainer() ) {
01032 fld2->vehicle = eht;
01033 eht->addview();
01034 } else
01035 fld2->getContainer()->addToCargo( eht );
01036 }
01037 eht = NULL;
01038
01039 }
01040
01041 if ( destDamage >= 0 ) {
01042 int realDamage;
01043 Vehicle* veh = actmap->getUnit( nwid );
01044 if ( veh )
01045 realDamage = veh->damage;
01046 else
01047 realDamage = 100;
01048
01049 if ( destDamage != realDamage )
01050 error( MapCoordinate(x1,y1), "severe replay inconsistency:\ndamage after movement differs: recorded=%d, actual=%d", destDamage, realDamage );
01051 }
01052 }
01053
01054 if ( !eht )
01055 error("severe replay inconsistency:\nno vehicle for move2 command at " + MapCoordinate(x1,y1).toString() );
01056 }
01057 break;
01058 case rpl_attack: {
01059 stream->readInt();
01060 int x1 = stream->readInt();
01061 int y1 = stream->readInt();
01062 int x2 = stream->readInt();
01063 int y2 = stream->readInt();
01064 int ad1 = stream->readInt();
01065 int ad2 = stream->readInt();
01066 int dd1 = stream->readInt();
01067 int dd2 = stream->readInt();
01068 int wpnum = stream->readInt();
01069 readnextaction();
01070
01071 MapField* fld = getfield ( x1, y1 );
01072 MapField* targ = getfield ( x2, y2 );
01073 int attackvisible = fieldvisiblenow ( fld, actmap->getPlayerView() ) || fieldvisiblenow ( targ, actmap->getPlayerView() );
01074 if ( fld && targ && fld->vehicle ) {
01075 if ( fieldvisiblenow ( targ, fld->vehicle->getOwner() )) {
01076 if ( targ->vehicle ) {
01077 tunitattacksunit battle ( fld->vehicle, targ->vehicle, 1, wpnum );
01078 battle.av.damage = ad1;
01079 battle.dv.damage = dd1;
01080 if ( attackvisible ) {
01081 displayActionCursor ( x1, y1, x2, y2, 0 );
01082 ReplayMapDisplay rmd( &getDefaultMapDisplay() );
01083 rmd.showBattle( battle );
01084 removeActionCursor();
01085 } else {
01086 battle.calc ();
01087 }
01088 if ( battle.av.damage < ad2 || battle.dv.damage > dd2 )
01089 error(MapCoordinate(x2,y2), "severe replay inconsistency:\nresult of attack differ !\nexpected target damage: %d ; recorded target damage: %d\nexpected attacker damage: %d ; recorded attacker damage: %d", battle.av.damage,ad2 ,battle.dv.damage, dd2);
01090 battle.setresult( createReplayContext() );
01091
01092 if ( battle.av.damage >= 100 || battle.dv.damage >= 100 )
01093 computeview( actmap );
01094
01095 updateFieldInfo();
01096
01097 } else
01098 if ( targ->building ) {
01099 tunitattacksbuilding battle ( fld->vehicle, x2, y2 , wpnum );
01100 battle.av.damage = ad1;
01101 battle.dv.damage = dd1;
01102 if ( attackvisible ) {
01103 displayActionCursor ( x1, y1, x2, y2, 0 );
01104 ReplayMapDisplay rmd( &getDefaultMapDisplay() );
01105 rmd.showBattle( battle );
01106 removeActionCursor();
01107 } else {
01108 battle.calc ();
01109
01110
01111 }
01112 if ( battle.av.damage != ad2 || battle.dv.damage != dd2 )
01113 error(MapCoordinate(x2,y2), "severe replay inconsistency:\nresult of attack differ !\nexpected target damage: %d ; recorded target damage: %d\nexpected attacker damage: %d ; recorded attacker damage: %d", battle.av.damage,ad2 ,battle.dv.damage, dd2);
01114 battle.setresult( createReplayContext() );
01115
01116 if ( battle.av.damage >= 100 || battle.dv.damage >= 100 )
01117 computeview( actmap );
01118 updateFieldInfo();
01119 } else
01120 if ( !targ->objects.empty() ) {
01121 tunitattacksobject battle ( fld->vehicle, x2, y2, wpnum );
01122 if ( attackvisible ) {
01123 displayActionCursor ( x1, y1, x2, y2, 0 );
01124 ReplayMapDisplay rmd( &getDefaultMapDisplay() );
01125 rmd.showBattle( battle );
01126 removeActionCursor();
01127 } else {
01128 battle.calc ();
01129
01130
01131 }
01132 if ( battle.av.damage != ad2 || battle.dv.damage != dd2 )
01133 error(MapCoordinate(x2,y2), "severe replay inconsistency:\nresult of attack differ !\nexpected target damage: %d ; recorded target damage: %d\nexpected attacker damage: %d ; recorded attacker damage: %d", battle.av.damage,ad2 ,battle.dv.damage, dd2);
01134 battle.setresult( createReplayContext() );
01135
01136 if ( battle.av.damage >= 100 || battle.dv.damage >= 100 )
01137 computeview( actmap );
01138
01139 updateFieldInfo();
01140 }
01141 displaymap();
01142 } else
01143 error(MapCoordinate(x2,y2), "severe replay inconsistency:\nthe attacking unit can't view the target field!" );
01144
01145 } else
01146 error(MapCoordinate(x1,y1), "severe replay inconsistency:\nno vehicle for attack command !" );
01147
01148 }
01149 break;
01150 case rpl_changeheight2:
01151 case rpl_changeheight: {
01152 stream->readInt();
01153 int x1 = stream->readInt();
01154 int y1 = stream->readInt();
01155 int x2 = stream->readInt();
01156 int y2 = stream->readInt();
01157 int nwid = stream->readInt();
01158 stream->readInt();
01159 int newheight = stream->readInt();
01160 int noInterrupt = -1;
01161
01162 if ( nextaction == rpl_changeheight2 )
01163 noInterrupt = stream->readInt();
01164
01165
01166 readnextaction();
01167
01168 Vehicle* eht = actmap->getUnit ( x1, y1, nwid );
01169 if ( eht ) {
01170 ReplayMapDisplay rmd( &getDefaultMapDisplay() );
01171
01172 auto_ptr<MoveUnitCommand> muc ( new MoveUnitCommand( eht ));
01173 muc->setDestination( MapCoordinate3D( x2,y2, newheight ));
01174
01175 wait( MapCoordinate(x1,y1), MapCoordinate(x2,y2) );
01176
01177 ActionResult res = muc->execute( createReplayContext() );
01178
01179 if ( res.successful() )
01180 muc.release();
01181 else
01182 eht = NULL;
01183
01184 }
01185
01186 if ( !eht )
01187 error(MapCoordinate(x1,y1), "severe replay inconsistency:\nno vehicle for changeheight command !");
01188
01189
01190 }
01191 break;
01192 case rpl_convert:
01193 case rpl_convert2: {
01194 stream->readInt();
01195 int x = stream->readInt();
01196 int y = stream->readInt();
01197 int col = stream->readInt();
01198 if ( nextaction == rpl_convert2 ) {
01199 int nwid = stream->readInt();
01200 readnextaction();
01201
01202 Vehicle* veh = actmap->getUnit( x,y, nwid );
01203 if ( veh )
01204 veh->convert(col);
01205 else
01206 error(MapCoordinate(x,y), "severe replay inconsistency:\nno vehicle for convert command !");
01207 } else {
01208 readnextaction();
01209
01210 MapField* fld = getfield ( x, y );
01211 if ( fld ) {
01212 displayActionCursor ( x, y );
01213 if ( fld->vehicle )
01214 fld->vehicle->convert ( col );
01215 else
01216 if ( fld->building )
01217 fld->building->convert ( col );
01218
01219 computeview( actmap );
01220 displaymap();
01221 wait( MapCoordinate(x,y) );
01222 removeActionCursor();
01223 } else
01224 error(MapCoordinate(x,y), "severe replay inconsistency:\nno vehicle for convert command !");
01225 }
01226 }
01227 break;
01228 case rpl_remobj:
01229 case rpl_buildobj:
01230 case rpl_remobj2:
01231 case rpl_buildobj2: {
01232 stream->readInt();
01233 int x = stream->readInt();
01234 int y = stream->readInt();
01235 int id = stream->readInt();
01236 int unit = -1;
01237 if ( actaction == rpl_remobj2 || actaction == rpl_buildobj2 )
01238 unit = stream->readInt();
01239
01240 readnextaction();
01241
01242 ObjectType* obj = objectTypeRepository.getObject_byID ( id );
01243
01244 MapField* fld = getfield ( x, y );
01245 if ( obj && fld ) {
01246 displayActionCursor ( x, y );
01247
01248 Resources cost;
01249 int movecost;
01250
01251 RecalculateAreaView rav ( actmap, MapCoordinate(x,y), maxViewRange / maxmalq + 1, NULL );
01252
01253 bool objectAffectsVisibility = obj->basicjamming_plus || obj->viewbonus_plus || obj->viewbonus_abs != -1 || obj->basicjamming_abs != -1;
01254 if ( objectAffectsVisibility )
01255 rav.removeView();
01256
01257
01258 if ( actaction == rpl_remobj || actaction == rpl_remobj2 ) {
01259 cost = obj->removecost;
01260 fld->removeObject ( obj );
01261 movecost = obj->remove_movecost;
01262 } else {
01263 cost = obj->buildcost;
01264 fld->addobject ( obj );
01265 movecost = obj->build_movecost;
01266 }
01267
01268 if ( objectAffectsVisibility )
01269 rav.addView();
01270
01271
01272 if ( unit > 0 ) {
01273 Vehicle* veh = actmap->getUnit(unit);
01274 if ( veh ) {
01275 if ( veh->getMovement() < movecost )
01276 error(MapCoordinate(x,y), "not enough movement to construct/remove object !");
01277 veh->decreaseMovement( movecost );
01278 Resources res2 = static_cast<ContainerBase*>(veh)->getResource( cost, 0, 1 );
01279 for ( int r = 0; r < 3; r++ )
01280 if ( res2.resource(r) < cost.resource(r) && cost.resource(r) > 0 )
01281 error("Resource mismatch: not enough resources to construct/remove object !\nPosition: " + MapCoordinate(x,y).toString());
01282
01283 } else
01284 error(MapCoordinate(x,y), "replay inconsistency:\nCannot find Unit to build/remove Object !");
01285 }
01286
01287 if ( fieldvisiblenow ( fld, actmap->getPlayerView() ))
01288 displaymap();
01289
01290 wait(MapCoordinate(x,y));
01291 removeActionCursor();
01292 } else
01293 error(MapCoordinate(x,y), "severe replay inconsistency:\nCannot find Object to build/remove !");
01294
01295 }
01296 break;
01297 case rpl_buildtnk:
01298 case rpl_buildtnk2:
01299 case rpl_buildtnk3:
01300 case rpl_buildtnk4: {
01301 stream->readInt();
01302 int x = stream->readInt();
01303 int y = stream->readInt();
01304 int id = stream->readInt();
01305 int col = stream->readInt();
01306 int nwid = -1;
01307 int constx = -1;
01308 int consty = -1;
01309 int height = -1;
01310 if ( nextaction == rpl_buildtnk2 )
01311 nwid = stream->readInt();
01312
01313 if ( nextaction == rpl_buildtnk3 || nextaction == rpl_buildtnk4 ) {
01314 constx = stream->readInt();
01315 consty = stream->readInt();
01316 if ( nextaction == rpl_buildtnk4 )
01317 height = stream->readInt();
01318 }
01319
01320 readnextaction();
01321
01322 MapField* fld = getfield ( x, y );
01323
01324 VehicleType* tnk = vehicleTypeRepository.getObject_byID ( id );
01325
01326 if ( fld && tnk && !fld->vehicle ) {
01327 displayActionCursor ( x, y );
01328 Vehicle* v = new Vehicle ( tnk, actmap, col );
01329 v->xpos = x;
01330 v->ypos = y;
01331 fld->vehicle = v;
01332 if ( height >= 0 )
01333 v->height = height;
01334
01335 if ( constx >= 0 && consty >= 0 ) {
01336 MapField* constructorField = getfield(constx, consty );
01337 if ( constructorField->vehicle ) {
01338 Resources r ( 0, tnk->productionCost.material, tnk->productionCost.energy );
01339 Resources rr = constructorField->getContainer()->getResource( r, 0 );
01340 if ( rr < r ) {
01341 displayActionCursor ( x, y );
01342 error(MapCoordinate(x,y), "severe replay inconsistency: \nNot enough resources to produce unit %s !\nRequired: %d/%d/%d ; Available: %d/%d/%d", v->typ->description.c_str(), r.energy, r.material, r.fuel, rr.energy, rr.material, rr.fuel);
01343 }
01344 } else
01345 error(MapCoordinate(x,y), "severe replay inconsistency: could not find constructor !");
01346
01347 }
01348
01349 computeview( actmap );
01350 displaymap();
01351 wait(MapCoordinate(x,y) );
01352 removeActionCursor();
01353 } else
01354 error(MapCoordinate(x,y), "severe replay inconsistency:\nCannot find Vehicle to build !");
01355
01356 }
01357 break;
01358 case rpl_putbuilding2:
01359 case rpl_putbuilding : {
01360 int size = stream->readInt();
01361 int x = stream->readInt();
01362 int y = stream->readInt();
01363 int id = stream->readInt();
01364 stream->readInt();
01365 int networkid = 0;
01366 if ( size == 5 )
01367 networkid = stream->readInt();
01368
01369 readnextaction();
01370
01371 MapField* fld = getfield ( x, y );
01372
01373 BuildingType* bld = buildingTypeRepository.getObject_byID ( id );
01374
01375 if ( bld && fld && networkid && actmap->getUnit( networkid ) ) {
01376 displayActionCursor ( x, y );
01377 auto_ptr<ConstructBuildingCommand> cbc ( new ConstructBuildingCommand( actmap->getUnit( networkid ) ));
01378 cbc->setBuildingType( bld );
01379 cbc->setTargetPosition( MapCoordinate(x,y));
01380 ActionResult res = cbc->execute( createReplayContext());
01381 if ( res.successful() )
01382 cbc.release();
01383 else
01384 error( MapCoordinate(x,y), "severe replay inconsistency, could not construct building; Code=" + ASCString::toString( res.getCode() ));
01385
01386 wait(MapCoordinate(x,y));
01387 removeActionCursor();
01388 } else
01389 error(MapCoordinate(x,y), "severe replay inconsistency:\nCannot find building to build/remove building!" );
01390 }
01391 break;
01392 case rpl_putmine:
01393 case rpl_putmine2: {
01394 stream->readInt();
01395 int x = stream->readInt();
01396 int y = stream->readInt();
01397 int col = stream->readInt();
01398 int typ = stream->readInt();
01399 int strength = stream->readInt();
01400 int nwid = -1;
01401 if ( nextaction == rpl_putmine2)
01402 nwid = stream->readInt();
01403
01404 readnextaction();
01405
01406 MapField* fld = getfield ( x, y );
01407 if ( fld ) {
01408 displayActionCursor ( x, y );
01409 fld -> putmine ( col, MineTypes(typ), strength );
01410 if ( nwid >= 0 ) {
01411 Vehicle* veh = actmap->getUnit( nwid );
01412 if ( veh ) {
01413 ConsumeAmmo ca ( veh, cwminen, -1, 1 );
01414 ActionResult res = ca.execute( createReplayContext());
01415 if ( !res.successful() )
01416 error(MapCoordinate(x,y), "could not obtain ammo for mine placement");
01417
01418 } else
01419 error(MapCoordinate(x,y), "could not find unit for mine placement");
01420 }
01421 computeview( actmap );
01422 if ( fieldvisiblenow ( actmap->getField(x,y), actmap->getPlayerView() )) {
01423 displaymap();
01424 wait();
01425 }
01426 removeActionCursor();
01427 } else
01428 error(MapCoordinate(x,y), "severe replay inconsistency:\nno field for putmine command !");
01429
01430 }
01431 break;
01432 case rpl_removemine: {
01433 stream->readInt();
01434 int x = stream->readInt();
01435 int y = stream->readInt();
01436 readnextaction();
01437
01438 MapField* fld = getfield ( x, y );
01439 if ( fld ) {
01440 displayActionCursor ( x, y );
01441 fld -> removemine ( -1 );
01442 computeview( actmap );
01443 if ( fieldvisiblenow ( actmap->getField(x,y), actmap->getPlayerView() )) {
01444 displaymap();
01445 wait();
01446 }
01447 removeActionCursor ( );
01448 } else
01449 error(MapCoordinate(x,y), "severe replay inconsistency:\nno field for remove mine command !");
01450
01451 }
01452 break;
01453 case rpl_removebuilding2:
01454 case rpl_removebuilding3:
01455 case rpl_removebuilding: {
01456 stream->readInt();
01457 int x = stream->readInt();
01458 int y = stream->readInt();
01459 int nwid = -1;
01460 if ( nextaction == rpl_removebuilding2 || nextaction == rpl_removebuilding3 )
01461 nwid = stream->readInt();
01462
01463 Resources res;
01464 if ( nextaction == rpl_removebuilding3 ) {
01465 res.energy = stream->readInt();
01466 res.material = stream->readInt();
01467 res.fuel = stream->readInt();
01468 }
01469
01470 readnextaction();
01471
01472 MapField* fld = getfield ( x, y );
01473 if ( fld && fld->building ) {
01474 displayActionCursor ( x, y );
01475 if ( nwid >= 0 ) {
01476 Vehicle* veh = actmap->getUnit( nwid );
01477 if ( veh ) {
01478 DestructBuildingCommand* dbc = new DestructBuildingCommand( veh );
01479 dbc->setTargetPosition( MapCoordinate( x,y ));
01480 dbc->execute( createReplayContext());
01481
01482 } else
01483 error(MapCoordinate(x,y), "severe replay inconsistency:\nfailed to obtain vehicle for removebuilding command !");
01484 } else
01485 error(MapCoordinate(x,y), "no vehicle for removebuilding command !");
01486
01487 computeview( actmap );
01488 displaymap();
01489 wait();
01490 removeActionCursor();
01491 } else
01492 error(MapCoordinate(x,y), "severe replay inconsistency:\nno building for removebuilding command !");
01493
01494 }
01495 break;
01496 case rpl_produceunit : {
01497 stream->readInt();
01498 int id = stream->readInt();
01499 int col = stream->readInt();
01500 int x = stream->readInt();
01501 int y = stream->readInt();
01502 stream->readInt();
01503 int nwid = stream->readInt();
01504 readnextaction();
01505
01506 MapField* fld = getfield ( x, y );
01507
01508 VehicleType* tnk = vehicleTypeRepository.getObject_byID ( id );
01509 if ( tnk && fld) {
01510
01511 #if 0
01512 printf("produced unit: pos %d / %d; nwid %d; typ id %d; typ %s \n", x,y,nwid,id,tnk->description.c_str() );
01513 #endif
01514
01515 Vehicle* eht = new Vehicle ( tnk, actmap, col / 8 );
01516 eht->xpos = x;
01517 eht->ypos = y;
01518 eht->networkid = nwid;
01519
01520 if ( fld->building ) {
01521 Resources cost = fld->building->getProductionCost(tnk);
01522 Resources r = fld->building->getResource( cost, 0 );
01523 if ( r < cost ) {
01524 displayActionCursor ( x, y );
01525 error(MapCoordinate(x,y), "severe replay inconsistency: \nNot enough resources to produce unit %s !\nRequired: %d/%d/%d ; Available: %d/%d/%d", eht->typ->description.c_str(), cost.energy, cost.material, cost.fuel, r.energy, r.material, r.fuel);
01526 }
01527 fld->building->addToCargo( eht );
01528 } else {
01529 displayActionCursor ( x, y );
01530 fld->vehicle = eht;
01531 computeview( actmap );
01532 displaymap();
01533 wait( MapCoordinate(x,y) );
01534 removeActionCursor();
01535 }
01536 } else
01537 error(MapCoordinate(x,y), "severe replay inconsistency:\nCannot find vehicle to build/remove !");
01538
01539 }
01540 break;
01541 case rpl_removeunit : {
01542 stream->readInt();
01543 int x = stream->readInt();
01544 int y = stream->readInt();
01545 int nwid = stream->readInt();
01546 readnextaction();
01547 MapField* fld = getfield(x,y);
01548 if ( (!fld->vehicle || fld->vehicle->networkid != nwid) && fld->building ) {
01549 auto_ptr<RecycleUnitCommand> ruc ( new RecycleUnitCommand( fld->building ));
01550 ruc->setUnit( actmap->getUnit( nwid ) );
01551 ActionResult res = ruc->execute( createReplayContext());
01552 if ( res.successful() )
01553 ruc.release();
01554 else
01555 displayActionError(res);
01556 } else
01557 if ( !fld->getContainer() || !fld->getContainer()->removeUnitFromCargo ( nwid, true ))
01558 displaymessage ( "severe replay inconsistency:\nCould not remove unit %d!", 1, nwid );
01559 }
01560 break;
01561 case rpl_trainunit:{
01562 stream->readInt();
01563 int x = stream->readInt();
01564 int y = stream->readInt();
01565 stream->readInt();
01566 int nwid = stream->readInt();
01567 readnextaction();
01568
01569 Vehicle* eht = actmap->getUnit ( x, y, nwid );
01570 Building* bld = actmap->getField ( x, y )->building;
01571 if ( eht && bld ) {
01572 auto_ptr<TrainUnitCommand> tuc ( new TrainUnitCommand( bld ));
01573 tuc->setUnit( eht );
01574 ActionResult res = tuc->execute( createReplayContext());
01575 if ( res.successful())
01576 tuc.release();
01577 else
01578 displayActionError(res);
01579 } else
01580 error(MapCoordinate(x,y), "severe replay inconsistency:\nno vehicle for trainunit command !");
01581
01582
01583 }
01584 break;
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611 case rpl_alliancechange2: {
01612 stream->readInt();
01613 int actingPlayer = stream->readInt();
01614 int targetPlayer = stream->readInt();
01615 int state = stream->readInt();
01616 actmap->player[actingPlayer].diplomacy.setState( targetPlayer, DiplomaticStates( state ));
01617
01618 readnextaction();
01619 }
01620 break;
01621 case rpl_refuel :
01622 case rpl_refuel2 : {
01623 stream->readInt();
01624 int x = stream->readInt();
01625 int y = stream->readInt();
01626 int nwid = stream->readInt();
01627 int pos = stream->readInt();
01628 int amnt = stream->readInt();
01629 int old = -2;
01630 if ( nextaction == rpl_refuel2 )
01631 old = stream->readInt();
01632
01633 readnextaction();
01634
01635 Vehicle* eht = actmap->getUnit ( x, y, nwid );
01636 if ( eht ) {
01637 if ( pos < 16 ) {
01638 if ( old >= 0 && old != eht->ammo[pos] )
01639 error(MapCoordinate(x,y), "severe replay inconsistency:\nthe ammo of unit not matching. \nrecorded: %d , expected: %d !", old, eht->ammo[pos] );
01640 eht->ammo[pos] = amnt;
01641 } else {
01642 int res = pos - 1000;
01643 int avl = eht->getTank().resource(res);
01644 if ( avl != old && old >= 0 )
01645 error(MapCoordinate(x,y), "severe replay inconsistency:\nthe resources of unit not matching. \nrecorded: %d , expected: %d !", old, avl);
01646 eht->getResource ( avl - amnt, res, false );
01647 }
01648 } else
01649 error(MapCoordinate(x,y), "severe replay inconsistency:\nno vehicle for refuel-unit command !");
01650 }
01651 break;
01652 case rpl_refuel3 : {
01653 stream->readInt();
01654 int id = stream->readInt();
01655 int type = stream->readInt();
01656 int delta = stream->readInt();
01657 readnextaction();
01658
01659 ContainerBase* cb = actmap->getContainer ( id );
01660 if ( cb ) {
01661 if ( type >= 1000 ) {
01662 Resources res;
01663 res.resource(type-1000) = delta;
01664 ConsumeResource cr ( cb, res );
01665 ActionResult result = cr.execute( createReplayContext() );
01666 if ( !result.successful())
01667 error("severe replay inconsistency:\nthe resources of container not matching. ");
01668
01669 } else {
01670 ConsumeAmmo ca ( cb, type, -1, delta );
01671 ActionResult result = ca.execute( createReplayContext() );
01672 if ( !result.successful())
01673 error("severe replay inconsistency:\nthe resources of container not matching. ");
01674 }
01675 } else
01676 error("severe replay inconsistency:\nno vehicle for refuel3 command !");
01677 }
01678 break;
01679 case rpl_bldrefuel : {
01680 stream->readInt();
01681 int x = stream->readInt();
01682 int y = stream->readInt();
01683 int pos = stream->readInt();
01684 int amnt = stream->readInt();
01685 readnextaction();
01686
01687 Building* bld = actmap->getField(x,y)->building;
01688 if ( bld ) {
01689 if ( pos < 16 )
01690 bld->ammo[pos] = amnt;
01691 else
01692 bld->getResource ( amnt, pos-1000, 0 );
01693 } else
01694 error(MapCoordinate(x,y), "severe replay inconsistency:\nno building for refuel-unit command !");
01695 }
01696 break;
01697 case rpl_moveUnitUpDown: {
01698 stream->readInt();
01699 int x = stream->readInt();
01700 int y = stream->readInt();
01701 stream->readInt();
01702 int nwid_to = stream->readInt();
01703 int nwid_moving = stream->readInt();
01704
01705 readnextaction();
01706
01707 ContainerBase* b = actmap->getField(x,y)->getContainer();
01708 if ( b ) {
01709 b->removeUnitFromCargo( nwid_moving, true );
01710
01711 Vehicle* veh_targ = actmap->getUnit( nwid_to );
01712 Vehicle* veh_moving = actmap->getUnit( nwid_moving );
01713 if ( veh_targ && veh_moving )
01714 veh_targ->addToCargo( veh_moving );
01715 else
01716 error ( MapCoordinate(x,y), "Could not locate unit for MoveToInnerTransport");
01717 } else
01718 error( MapCoordinate(x,y), "severe replay inconsistency in MoveUnitUp !");
01719
01720 }
01721 break;
01722 case rpl_moveUnitUp: {
01723 stream->readInt();
01724 int x = stream->readInt();
01725 int y = stream->readInt();
01726 int nwid = stream->readInt();
01727
01728 readnextaction();
01729
01730 Vehicle* eht = actmap->getUnit ( x, y, nwid );
01731 if ( eht ) {
01732 CargoMoveCommand* cmc = new CargoMoveCommand( eht );
01733 cmc->setMode( CargoMoveCommand::moveOutwards );
01734 ActionResult res = cmc->execute( createReplayContext() );
01735 if ( !res.successful())
01736 error(MapCoordinate(x,y), "severe replay inconsistency in MoveUnitUp !");
01737 } else
01738 error(MapCoordinate(x,y), "Unit not found for MoveUnitUp !");
01739
01740 }
01741 break;
01742 case rpl_repairUnit : {
01743 stream->readInt();
01744 int nwid = stream->readInt();
01745 int destnwid = stream->readInt();
01746 int amount = stream->readInt();
01747 int matremain = stream->readInt();
01748 int fuelremain = stream->readInt();
01749
01750 readnextaction();
01751
01752 Vehicle* eht = actmap->getUnit ( nwid );
01753 Vehicle* dest = actmap->getUnit ( destnwid );
01754 if ( eht && dest ) {
01755 eht->repairItem ( dest, amount );
01756 if ( eht->getTank().fuel != fuelremain || eht->getTank().material != matremain )
01757 error("severe replay inconsistency:\nthe resources of unit not matching for repair operation!");
01758 } else
01759 error("severe replay inconsistency:\nno vehicle for repair-unit command !");
01760 }
01761 break;
01762 case rpl_repairUnit2 : {
01763 stream->readInt();
01764 int x = stream->readInt();
01765 int y = stream->readInt();
01766 int destnwid = stream->readInt();
01767 int amount = stream->readInt();
01768
01769 readnextaction();
01770
01771 ContainerBase* bld = getfield(x,y)->getContainer();
01772 Vehicle* dest = actmap->getUnit ( destnwid );
01773 if ( bld && dest ) {
01774 bld->repairItem ( dest, amount );
01775 } else
01776 error(MapCoordinate(x,y), "severe replay inconsistency:\nno vehicle for repair-unit command !");
01777 }
01778 break;
01779 case rpl_repairUnit3 : {
01780 stream->readInt();
01781 int serviceNWID = stream->readInt();
01782 int destnwid = stream->readInt();
01783 int amount = stream->readInt();
01784
01785 readnextaction();
01786
01787 ContainerBase* bld = actmap->getContainer( serviceNWID );
01788 Vehicle* dest = actmap->getUnit ( destnwid );
01789 if ( bld && dest ) {
01790 bld->repairItem ( dest, amount );
01791 } else
01792 error("severe replay inconsistency:\nno vehicle for repair-unit command !");
01793 }
01794 break;
01795 case rpl_repairBuilding : {
01796 stream->readInt();
01797 int x = stream->readInt();
01798 int y = stream->readInt();
01799 stream->readInt();
01800 int amount = stream->readInt();
01801
01802 readnextaction();
01803
01804 ContainerBase* bld = getfield(x,y)->getContainer();
01805 if ( bld ) {
01806 bld->repairItem ( bld, amount );
01807 } else
01808 error(MapCoordinate(x,y), "severe replay inconsistency:\nno building for repair-building command !");
01809 }
01810 break;
01811 case rpl_produceAmmo : {
01812 stream->readInt();
01813 int x = stream->readInt();
01814 int y = stream->readInt();
01815 int weaptype = stream->readInt();
01816 int n = stream->readInt();
01817 readnextaction();
01818 Building* bld = getfield(x,y)->building;
01819 if ( bld ) {
01820
01821 bld->getResource ( Resources( ammoProductionCost[weaptype][0] * n, ammoProductionCost[weaptype][1] * n, ammoProductionCost[weaptype][2] * n ), false );
01822 bld->putAmmo ( weaptype, n, false );
01823
01824 } else
01825 error(MapCoordinate(x,y), "severe replay inconsistency:\nno building for produce ammo command !");
01826
01827 }
01828 break;
01829 case rpl_buildProdLine : {
01830 stream->readInt();
01831 int building = stream->readInt();
01832 int vehicleid = stream->readInt();
01833 readnextaction();
01834 Building* bld = dynamic_cast<Building*>( actmap->getContainer(building));
01835 VehicleType* veh = actmap->getvehicletype_byid ( vehicleid );
01836 if ( bld && veh ) {
01837 if ( veh->techDependency.available( actmap->player[ bld->getOwner()].research )) {
01838 auto_ptr<BuildProductionLineCommand> bplc ( new BuildProductionLineCommand( bld ));
01839 bplc->setProduction( veh );
01840 ActionResult res = bplc->execute( createReplayContext() );
01841 if ( res.successful() )
01842 bplc.release();
01843 else
01844 error("severe replay inconsistency:\ncould not build production line!");
01845 } else
01846 error("severe replay inconsistency:\ntechnology for building production line not available!");
01847
01848 } else
01849 error("severe replay inconsistency:\nno building for build production line command !");
01850
01851 }
01852 break;
01853 case rpl_removeProdLine : {
01854 stream->readInt();
01855 int building = stream->readInt();
01856 int vehicleid = stream->readInt();
01857 readnextaction();
01858 Building* bld = dynamic_cast<Building*>( actmap->getContainer(building));
01859 VehicleType* veh = actmap->getvehicletype_byid ( vehicleid );
01860 if ( bld && veh ) {
01861 auto_ptr<RemoveProductionLineCommand> rplc ( new RemoveProductionLineCommand( bld ));
01862 rplc->setRemoval( veh );
01863 ActionResult res = rplc->execute( createReplayContext());
01864 if ( res.successful())
01865 rplc.release();
01866 else
01867 error("severe replay inconsistency:\ncould not remove production line!");
01868
01869 } else
01870 error("severe replay inconsistency:\nno building for remove production line command !");
01871
01872 }
01873 break;
01874 case rpl_setResearch : {
01875 stream->readInt();
01876 int building = stream->readInt();
01877 int amount = stream->readInt();
01878 readnextaction();
01879 Building* bld = dynamic_cast<Building*>( actmap->getContainer(building));
01880 if ( bld )
01881 bld->researchpoints = amount;
01882 else
01883 error("severe replay inconsistency:\nno building for set research command !");
01884
01885 }
01886 break;
01887 case rpl_techResearched: {
01888 stream->readInt();
01889 int techID = stream->readInt();
01890 int player = stream->readInt();
01891 readnextaction();
01892 Technology* tech = technologyRepository.getObject_byID( techID );
01893 if ( tech ) {
01894 actmap->player[player].research.addanytechnology( tech );
01895 actmap->player[player].research.progress -= tech->researchpoints;
01896 } else
01897 error("severe replay inconsistency:\nno technology for tech researched command !");
01898 }
01899 break;
01900 case rpl_setGeneratorStatus : {
01901 stream->readInt();
01902 int nwid = stream->readInt();
01903 int status = stream->readInt();
01904
01905 readnextaction();
01906
01907 Vehicle* eht = actmap->getUnit ( nwid );
01908 if ( eht )
01909 eht->setGeneratorStatus( status );
01910 else
01911 error("severe replay inconsistency:\nvehicle for generator switching not found !");
01912 }
01913
01914
01915 break;
01916 case rpl_cutFromGame: {
01917 stream->readInt();
01918 int vehid = stream->readInt();
01919 Vehicle* veh = actmap->getUnit ( vehid );
01920 Resources res;
01921 res.energy = stream->readInt();
01922 res.material = stream->readInt();
01923 res.fuel = stream->readInt();
01924
01925 readnextaction();
01926
01927 if ( veh && res == getUnitResourceCargo ( veh )) {
01928 veh->prepareForCleanRemove();
01929 delete veh;
01930 computeview( actmap );
01931 displaymap();
01932 } else
01933 error ( "resource mismatch at cut unit operation! ");
01934 }
01935 break;
01936 case rpl_setResourceProcessingAmount: {
01937 stream->readInt();
01938 int x = stream->readInt();
01939 int y = stream->readInt();
01940 Resources p;
01941 p.energy = stream->readInt();
01942 p.material = stream->readInt();
01943 p.fuel = stream->readInt();
01944 readnextaction();
01945 Building* bld = actmap->getField(x,y)->building;
01946 if ( bld ) {
01947 for ( int r = 0; r< 3; ++r )
01948 if ( abs(p.resource(r)) > abs(bld->typ->maxplus.resource(r)) )
01949 error (MapCoordinate(x,y), "Building can not produ ");
01950 bld->plus = p;
01951 } else
01952 error (MapCoordinate(x,y), "Building not found on for rpl_setResourceProcessingAmount ");
01953 }
01954 break;
01955 case rpl_netcontrol: {
01956 stream->readInt();
01957 int x = stream->readInt();
01958 int y = stream->readInt();
01959 stream->readInt();
01960 stream->readInt();
01961 readnextaction();
01962
01963 Building* bld = actmap->getField(x,y)->building;
01964 if ( bld ) {
01965
01966
01967
01968
01969
01970
01971
01972 } else
01973 error (MapCoordinate(x,y), "Building not found on for rpl_setResourceProcessingAmount ");
01974 }
01975 break;
01976 case rpl_jump: {
01977 stream->readInt();
01978 int nwid = stream->readInt();
01979 int x = stream->readInt();
01980 int y = stream->readInt();
01981 readnextaction();
01982
01983 Vehicle* veh = actmap->getUnit(nwid);
01984 if ( veh ) {
01985 if ( JumpDriveCommand::available( veh ).ready()) {
01986 auto_ptr<JumpDriveCommand> jd( new JumpDriveCommand(veh) );
01987 displayActionCursor ( veh->getPosition().x , veh->getPosition().x, x, y, 0 );
01988 jd->setDestination( MapCoordinate(x,y));
01989 ActionResult res = jd->execute( createReplayContext() );
01990 if ( !res.successful() )
01991 error(MapCoordinate(x,y), "Unit cannot jump to this position");
01992 else
01993 jd.release();
01994
01995 } else
01996 error(MapCoordinate(x,y), "Unit cannot jump");
01997 } else
01998 error (MapCoordinate(x,y), "Unit not found for Jump ");
01999
02000
02001 }
02002 break;
02003 case rpl_recycleUnit : {
02004 stream->readInt();
02005 int building = stream->readInt();
02006 int vehicleid = stream->readInt();
02007 readnextaction();
02008 Building* bld = dynamic_cast<Building*>( actmap->getContainer(building));
02009 Vehicle* veh = actmap->getUnit ( vehicleid );
02010 if ( bld && veh ) {
02011 auto_ptr<RecycleUnitCommand> ruc ( new RecycleUnitCommand( bld ));
02012 ruc->setUnit( veh );
02013 ActionResult res = ruc->execute( createReplayContext() );
02014 if ( res.successful() )
02015 ruc.release();
02016 else
02017 displayActionError(res);
02018 } else
02019 error("severe replay inconsistency:\nno unit for recycle command !");
02020 }
02021 break;
02022 case rpl_transferTribute: {
02023 stream->readInt();
02024 int player = stream->readInt();
02025 readnextaction();
02026 transfer_all_outstanding_tribute( actmap->getPlayer( player ) );
02027 }
02028 break;
02029
02030 case rpl_reactionFireOn:
02031 case rpl_reactionFireOff: {
02032 stream->readInt();
02033 int nwid = stream->readInt();
02034 readnextaction();
02035 Vehicle* v = actmap->getUnit( nwid );
02036 if ( v ) {
02037 if ( actaction == rpl_reactionFireOn ) {
02038 int res = v->reactionfire.enable();
02039 if ( res < 0 )
02040 error("severe enabling reactionfire for unit !");
02041 } else
02042 v->reactionfire.disable();
02043 } else
02044 error("severe replay inconsistency:\nno unit for reactionfire command !");
02045 }
02046 break;
02047 case rpl_selfdestruct: {
02048 stream->readInt();
02049 int nwid = stream->readInt();
02050 readnextaction();
02051 ContainerBase* c = actmap->getContainer( nwid );
02052 if ( DestructUnitCommand::avail( c )) {
02053 auto_ptr<DestructUnitCommand> duc ( new DestructUnitCommand( c ));
02054 ActionResult res = duc->execute( createReplayContext() );
02055 if ( !res.successful() )
02056 error("severe replay inconsistency:\nno container for selfdestruct command !");
02057 else
02058 duc.release();
02059 } else
02060 error("severe replay inconsistency:\nno container for selfdestruct command !");
02061 }
02062 break;
02063 case rpl_cancelResearch :
02064 {
02065 stream->readInt();
02066 readnextaction();
02067
02068 auto_ptr<CancelResearchCommand> crc ( new CancelResearchCommand( actmap ));
02069 crc->setPlayer( actmap->player[actmap->actplayer] );
02070 ActionResult res = crc->execute( createReplayContext() );
02071 if ( res.successful() )
02072 crc.release();
02073 else
02074 error( res );
02075 }
02076 break;
02077
02078 case rpl_runCommandAction:
02079 {
02080 stream->readInt();
02081 int padding = stream->readInt();
02082 MemoryStreamStorage buffer;
02083 buffer.readfromstream( stream );
02084
02085 MemoryStream memstream( &buffer, tnstream::reading );
02086
02087 auto_ptr<GameAction> readaction ( GameAction::readFromStream( memstream, actmap ));
02088
02089 Command* a = dynamic_cast<Command*> ( readaction.get() );
02090
02091 for ( int i = 0; i < padding;++i ) {
02092 char c = stream->readChar();
02093 if ( c != 255-i )
02094 error("invalid padding bytes in command action storage buffer");
02095 }
02096 readnextaction();
02097
02098 if ( a ) {
02099 try {
02100 ActionResult res = a->redo( createReplayContext() );
02101 if ( !res.successful() )
02102 error("action " + a->getDescription() + " failed\n" + getmessage(res.getCode()));
02103 } catch ( ActionResult res ) {
02104 error("action " + a->getDescription() + " failed\n" + getmessage(res.getCode()));
02105 throw res;
02106 }
02107
02108 } else
02109 error("could not read Command action from replay stream" );
02110 }
02111 break;
02112
02113 default:{
02114 int size = stream->readInt();
02115 for ( int i = 0; i< size; i++ )
02116 stream->readInt();
02117
02118 readnextaction();
02119
02120 }
02121 break;
02122 }
02123
02124 } else {
02125 status = 10;
02126 updateFieldInfo();
02127 }
02128
02129 }
02130
02131 void trunreplay :: readnextaction ( void )
02132 {
02133 if ( stream->dataavail () )
02134 nextaction = stream->readChar();
02135 else
02136 nextaction = rpl_finished;
02137 }
02138
02139
02140
02141 int trunreplay :: run ( int player, int viewingplayer, bool performEndTurnOperations )
02142 {
02143 ReplayRecorderWatcherLocal rrw( replayRecorder );
02144
02145 if ( status < 0 )
02146 firstinit ( );
02147
02148 lastErrorMessage = "";
02149
02150 movenum = 0;
02151
02152 actplayer = actmap->actplayer;
02153
02154 orgmap = actmap;
02155 actmap = loadreplay ( orgmap->replayinfo->map[player] );
02156 if ( !actmap ) {
02157 displaymessage("error loading replay", 1 );
02158 actmap = orgmap;
02159 return 0;
02160 }
02161 actmap->state = GameMap::Replay;
02162
02163 actmap->setPlayerView ( viewingplayer );
02164 actmap->getCursor() = orgmap->getCursor();
02165
02166 SuppressTechPresentation stp;
02167 actmap->sigPlayerTurnBegins( actmap->getPlayer( player ));
02168
02169 MemoryStream guidatastream ( orgmap->replayinfo->guidata [ player ], tnstream::reading );
02170 stream = &guidatastream;
02171
02172 if ( stream->dataavail () )
02173 nextaction = stream->readChar();
02174 else
02175 nextaction = rpl_finished;
02176
02177
02178
02179
02180 ReplayGuiIconHandleHandler guiIconHandler;
02181
02182 if ( stream->dataavail () ) {
02183 if ( CGameOptions::Instance()->replayMovieMode )
02184 status = 2;
02185 else
02186 status = 1;
02187 } else
02188 status = 11;
02189
02190
02191 actmap->overviewMapHolder.getOverviewMap( );
02192
02193 computeview( actmap );
02194 displaymap ();
02195
02196 updateFieldInfo();
02197
02198 MainScreenWidget::StandardActionLocker locker( mainScreenWidget, MainScreenWidget::LockOptions::Menu );
02199
02200
02201
02202
02203
02204 bool resourcesCompared = false;
02205 do {
02206 if ( status == 2 ) {
02207 execnextreplaymove ( );
02208 checktimedevents( actmap, &getDefaultMapDisplay() );
02209
02210
02211
02212
02213 } else {
02214 PG_Application::GetApp()->sigAppIdle( PG_Application::GetApp() );
02215 releasetimeslice();
02216 }
02217
02218 if (nextaction == rpl_finished || status != 2 ) {
02219 if ( CGameOptions::Instance()->replayMovieMode && status != 1 && !(replayRecorder && replayRecorder->isRunning()) )
02220 status = 100;
02221 else {
02222 if ( nextaction == rpl_finished && !resourcesCompared ) {
02223
02224 if ( replayRecorder )
02225 replayRecorder->pause();
02226
02227 displaymessage2("running final comparison" );
02228
02229 int replayedplayer = actmap->actplayer;
02230 actmap->endTurn();
02231 int nextplayer = findNextPlayer( actmap );
02232 if ( nextplayer < actmap->actplayer && performEndTurnOperations )
02233 actmap->endRound();
02234
02235 actmap->getCursor() = orgmap->getCursor();
02236
02237 resourcesCompared = true;
02238 ASCString resourceComparisonResult;
02239 GameMap* comparisonMap = NULL;
02240 GameMap* nextPlayerMap = NULL;
02241
02242 if ( replayedplayer == orgmap->actplayer )
02243 comparisonMap = orgmap;
02244 else
02245 comparisonMap = nextPlayerMap = loadreplay ( orgmap->replayinfo->map[nextplayer] );
02246
02247 if ( !CGameOptions::Instance()->replayMovieMode ) {
02248 if ( comparisonMap ) {
02249 if ( compareMapResources( comparisonMap, actmap, player, &resourceComparisonResult)) {
02250 ViewFormattedText vft( "warning", resourceComparisonResult, PG_Rect( -1, -1, 500, 550 ) );
02251 vft.Show();
02252 vft.RunModal();
02253 }
02254
02255 } else
02256 error("Replay: no map to compare to!");
02257 }
02258
02259 delete nextPlayerMap;
02260 }
02261 }
02262 }
02263
02264 for ( int i = 0; i < 5; ++i )
02265 getPGApplication().processEvent();
02266
02267 } while ( status > 0 && status < 100 ) ;
02268
02269 delete actmap;
02270 actmap = orgmap;
02271
02272 int st = status;
02273 status = 0;
02274
02275 updateFieldInfo();
02276
02277 if ( st == 101 )
02278 return 1;
02279 else
02280 return 0;
02281 }
02282
02283 void trunreplay :: firstinit ( void )
02284 {
02285 status = 0;
02286 }
02287
02288
02289 void hookReplayToSystem()
02290 {
02291 ActionContainer::commitCommand.connect( SigC::slot( &logActionToReplay ));
02292 }