00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031
00032
00033
00034
00035 #include <time.h>
00036
00037 #include "stratagus.h"
00038 #include "replay.h"
00039 #include "version.h"
00040 #include "iolib.h"
00041 #include "iocompat.h"
00042 #include "script.h"
00043 #include "unittype.h"
00044 #include "unit_manager.h"
00045 #include "settings.h"
00046 #include "commands.h"
00047 #include "player.h"
00048 #include "map.h"
00049 #include "netconnect.h"
00050 #include "network.h"
00051 #include "interface.h"
00052 #include "actions.h"
00053
00054
00055
00056
00057
00061 class LogEntry {
00062 public:
00063 LogEntry() : GameCycle(0), Flush(0), PosX(0), PosY(0), DestUnitNumber(0),
00064 Num(0), SyncRandSeed(0), Next(NULL)
00065 {
00066 UnitNumber = 0;
00067 }
00068
00069 unsigned long GameCycle;
00070 int UnitNumber;
00071 std::string UnitIdent;
00072 std::string Action;
00073 int Flush;
00074 int PosX;
00075 int PosY;
00076 int DestUnitNumber;
00077 std::string Value;
00078 int Num;
00079 unsigned SyncRandSeed;
00080 LogEntry *Next;
00081 };
00082
00086 class MPPlayer {
00087 public:
00088 MPPlayer() : Team(0), Type(0) {}
00089
00090 std::string Name;
00091 int Team;
00092 int Type;
00093 };
00094
00098 class FullReplay {
00099 public:
00100 FullReplay() :
00101 MapId(0), Type(0), LocalPlayer(0),
00102 Resource(0), NumUnits(0), Difficulty(0), NoFow(false), RevealMap(0),
00103 MapRichness(0), GameType(0), Opponents(0), Commands(NULL)
00104 {
00105 memset(Engine, 0, sizeof(Engine));
00106 memset(Network, 0, sizeof(Network));
00107 }
00108 std::string Comment1;
00109 std::string Comment2;
00110 std::string Comment3;
00111 std::string Date;
00112 std::string Map;
00113 std::string MapPath;
00114 unsigned MapId;
00115
00116 int Type;
00117 int LocalPlayer;
00118 MPPlayer Players[PlayerMax];
00119
00120 int Resource;
00121 int NumUnits;
00122 int Difficulty;
00123 bool NoFow;
00124 int RevealMap;
00125 int MapRichness;
00126 int GameType;
00127 int Opponents;
00128 int Engine[3];
00129 int Network[3];
00130 LogEntry *Commands;
00131 };
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 bool CommandLogDisabled;
00143 ReplayType ReplayGameType;
00144 static bool DisabledLog;
00145 static CFile *LogFile;
00146 static unsigned long NextLogCycle;
00147 static int InitReplay;
00148 static FullReplay *CurrentReplay;
00149 static LogEntry *ReplayStep;
00150
00151 static void AppendLog(LogEntry *log, CFile *dest);
00152
00153
00154
00155
00156
00162 static FullReplay *StartReplay(void)
00163 {
00164 FullReplay *replay;
00165 char *s;
00166 time_t now;
00167 char *s1;
00168
00169 replay = new FullReplay;
00170
00171 time(&now);
00172 s = ctime(&now);
00173 if ((s1 = strchr(s, '\n'))) {
00174 *s1 = '\0';
00175 }
00176
00177 replay->Comment1 = "Generated by Bos Wars Version " VERSION "";
00178 replay->Comment2 = "Visit http://www.boswars.org for more information";
00179 replay->Comment3 = "$Id: replay.cpp 9512 2008-03-02 22:26:50Z jim4 $";
00180
00181 if (GameSettings.NetGameType == SettingsSinglePlayerGame) {
00182 replay->Type = ReplaySinglePlayer;
00183 } else {
00184 replay->Type = ReplayMultiPlayer;
00185 }
00186
00187 for (int i = 0; i < PlayerMax; ++i) {
00188 replay->Players[i].Name = Players[i].Name;
00189 replay->Players[i].Team = GameSettings.Presets[i].Team;
00190 replay->Players[i].Type = GameSettings.Presets[i].Type;
00191 }
00192
00193 replay->LocalPlayer = ThisPlayer->Index;
00194
00195 replay->Date = s;
00196 replay->Map = Map.Info.Description;
00197 replay->MapId = (signed int)Map.Info.MapUID;
00198 replay->MapPath = CurrentMapPath;
00199 replay->Resource = GameSettings.Resources;
00200 replay->NumUnits = GameSettings.NumUnits;
00201 replay->Difficulty = GameSettings.Difficulty;
00202 replay->NoFow = GameSettings.NoFogOfWar;
00203 replay->GameType = GameSettings.GameType;
00204 replay->RevealMap = GameSettings.RevealMap;
00205 replay->MapRichness = GameSettings.MapRichness;
00206 replay->Opponents = GameSettings.Opponents;
00207
00208 replay->Engine[0] = StratagusMajorVersion;
00209 replay->Engine[1] = StratagusMinorVersion;
00210 replay->Engine[2] = StratagusPatchLevel;
00211
00212 replay->Network[0] = NetworkProtocolMajorVersion;
00213 replay->Network[1] = NetworkProtocolMinorVersion;
00214 replay->Network[2] = NetworkProtocolPatchLevel;
00215 return replay;
00216 }
00217
00221 static void ApplyReplaySettings(void)
00222 {
00223 if (CurrentReplay->Type == ReplayMultiPlayer) {
00224 ExitNetwork1();
00225 NetPlayers = 2;
00226 GameSettings.NetGameType = SettingsMultiPlayerGame;
00227
00228 ReplayGameType = ReplayMultiPlayer;
00229 NetLocalPlayerNumber = CurrentReplay->LocalPlayer;
00230 } else {
00231 GameSettings.NetGameType = SettingsSinglePlayerGame;
00232 ReplayGameType = ReplaySinglePlayer;
00233 }
00234
00235 for (int i = 0; i < PlayerMax; ++i) {
00236 GameSettings.Presets[i].Team = CurrentReplay->Players[i].Team;
00237 GameSettings.Presets[i].Type = CurrentReplay->Players[i].Type;
00238 }
00239
00240 if (strcpy_s(CurrentMapPath, sizeof(CurrentMapPath), CurrentReplay->MapPath.c_str()) != 0) {
00241 fprintf(stderr, "Replay map path is too long\n");
00242
00243 Exit(1);
00244 }
00245 GameSettings.Resources = CurrentReplay->Resource;
00246 GameSettings.NumUnits = CurrentReplay->NumUnits;
00247 GameSettings.Difficulty = CurrentReplay->Difficulty;
00248 Map.NoFogOfWar = GameSettings.NoFogOfWar = CurrentReplay->NoFow;
00249 GameSettings.GameType = CurrentReplay->GameType;
00250 FlagRevealMap = GameSettings.RevealMap = CurrentReplay->RevealMap;
00251 GameSettings.MapRichness = CurrentReplay->MapRichness;
00252 GameSettings.Opponents = CurrentReplay->Opponents;
00253
00254
00255
00256
00257 }
00258
00264 static void DeleteReplay(FullReplay *replay)
00265 {
00266 LogEntry *log;
00267 LogEntry *next;
00268
00269 log = replay->Commands;
00270 while (log) {
00271 next = log->Next;
00272 delete log;
00273 log = next;
00274 }
00275
00276 delete replay;
00277 }
00278
00279 static void PrintLogCommand(LogEntry *log, CFile *dest)
00280 {
00281 dest->printf("Log( { ");
00282 dest->printf("GameCycle = %lu, ", log->GameCycle);
00283 if (log->UnitNumber != -1) {
00284 dest->printf("UnitNumber = %d, ", log->UnitNumber);
00285 }
00286 if (!log->UnitIdent.empty()) {
00287 dest->printf("UnitIdent = \"%s\", ", log->UnitIdent.c_str());
00288 }
00289 dest->printf("Action = \"%s\", ", log->Action.c_str());
00290 dest->printf("Flush = %d, ", log->Flush);
00291 if (log->PosX != -1 || log->PosY != -1) {
00292 dest->printf("PosX = %d, PosY = %d, ", log->PosX, log->PosY);
00293 }
00294 if (log->DestUnitNumber != -1) {
00295 dest->printf("DestUnitNumber = %d, ", log->DestUnitNumber);
00296 }
00297 if (!log->Value.empty()) {
00298 dest->printf("Value = [[%s]], ", log->Value.c_str());
00299 }
00300 if (log->Num != -1) {
00301 dest->printf("Num = %d, ", log->Num);
00302 }
00303 dest->printf("SyncRandSeed = %d } )\n", (signed)log->SyncRandSeed);
00304 }
00305
00311 static void SaveFullLog(CFile *dest)
00312 {
00313 LogEntry *log;
00314 int i;
00315
00316 dest->printf("ReplayLog( {\n");
00317 dest->printf(" Comment1 = \"%s\",\n", CurrentReplay->Comment1.c_str());
00318 dest->printf(" Comment2 = \"%s\",\n", CurrentReplay->Comment2.c_str());
00319 dest->printf(" Comment3 = \"%s\",\n", CurrentReplay->Comment3.c_str());
00320 dest->printf(" Date = \"%s\",\n", CurrentReplay->Date.c_str());
00321 dest->printf(" Map = \"%s\",\n", CurrentReplay->Map.c_str());
00322 dest->printf(" MapPath = \"%s\",\n", CurrentReplay->MapPath.c_str());
00323 dest->printf(" MapId = %u,\n", CurrentReplay->MapId);
00324 dest->printf(" Type = %d,\n", CurrentReplay->Type);
00325 dest->printf(" LocalPlayer = %d,\n", CurrentReplay->LocalPlayer);
00326 dest->printf(" Players = {\n");
00327 for (i = 0; i < PlayerMax; ++i) {
00328 if (!CurrentReplay->Players[i].Name.empty()) {
00329 dest->printf("\t{ Name = \"%s\",", CurrentReplay->Players[i].Name.c_str());
00330 } else {
00331 dest->printf("\t{");
00332 }
00333 dest->printf(" Team = %d,", CurrentReplay->Players[i].Team);
00334 dest->printf(" Type = %d }%s", CurrentReplay->Players[i].Type,
00335 i != PlayerMax - 1 ? ",\n" : "\n");
00336 }
00337 dest->printf(" },\n");
00338 dest->printf(" Resource = %d,\n", CurrentReplay->Resource);
00339 dest->printf(" NumUnits = %d,\n", CurrentReplay->NumUnits);
00340 dest->printf(" Difficulty = %d,\n", CurrentReplay->Difficulty);
00341 dest->printf(" NoFow = %s,\n", CurrentReplay->NoFow ? "true" : "false");
00342 dest->printf(" RevealMap = %d,\n", CurrentReplay->RevealMap);
00343 dest->printf(" GameType = %d,\n", CurrentReplay->GameType);
00344 dest->printf(" Opponents = %d,\n", CurrentReplay->Opponents);
00345 dest->printf(" MapRichness = %d,\n", CurrentReplay->MapRichness);
00346 dest->printf(" Engine = { %d, %d, %d },\n",
00347 CurrentReplay->Engine[0], CurrentReplay->Engine[1], CurrentReplay->Engine[2]);
00348 dest->printf(" Network = { %d, %d, %d }\n",
00349 CurrentReplay->Network[0], CurrentReplay->Network[1], CurrentReplay->Network[2]);
00350 dest->printf("} )\n");
00351 log = CurrentReplay->Commands;
00352 while (log) {
00353 PrintLogCommand(log, dest);
00354 log = log->Next;
00355 }
00356 }
00357
00364 static void AppendLog(LogEntry *log, CFile *dest)
00365 {
00366 LogEntry **last;
00367
00368
00369 last = &CurrentReplay->Commands;
00370 while (*last) {
00371 last = &(*last)->Next;
00372 }
00373
00374 *last = log;
00375 log->Next = 0;
00376
00377
00378 if (!dest) {
00379 return;
00380 }
00381
00382 PrintLogCommand(log, dest);
00383 dest->flush();
00384 }
00385
00400 void CommandLog(const char *action, const CUnit *unit, int flush,
00401 int x, int y, const CUnit *dest, const char *value, int num)
00402 {
00403 LogEntry *log;
00404
00405 if (CommandLogDisabled) {
00406 return;
00407 }
00408
00409
00410
00411
00412
00413 if (!LogFile) {
00414 char buf[PATH_MAX];
00415
00416 sprintf_s(buf, sizeof(buf), "%slogs/log_of_stratagus_%d.log", UserDirectory.c_str(), ThisPlayer->Index);
00417 LogFile = new CFile;
00418 if (LogFile->open(buf, CL_OPEN_WRITE) == -1) {
00419
00420 CommandLogDisabled = false;
00421 delete LogFile;
00422 LogFile = NULL;
00423 return;
00424 }
00425
00426 if (CurrentReplay) {
00427 SaveFullLog(LogFile);
00428 }
00429 }
00430
00431 if (!CurrentReplay) {
00432 CurrentReplay = StartReplay();
00433
00434 SaveFullLog(LogFile);
00435 }
00436
00437 if (!action) {
00438 return;
00439 }
00440
00441 log = new LogEntry;
00442
00443
00444
00445
00446 log->GameCycle = GameCycle;
00447
00448 log->UnitNumber = (unit ? UnitNumber(unit) : -1);
00449 log->UnitIdent = (unit ? unit->Type->Ident.c_str() : "");
00450
00451 log->Action = action;
00452 log->Flush = flush;
00453
00454
00455
00456
00457 log->PosX = x;
00458 log->PosY = y;
00459
00460
00461
00462
00463 log->DestUnitNumber = (dest ? UnitNumber(dest) : -1);
00464
00465
00466
00467
00468 log->Value = (value ? value : "");
00469
00470
00471
00472
00473 log->Num = num;
00474
00475 log->SyncRandSeed = SyncRandSeed;
00476
00477
00478 AppendLog(log, LogFile);
00479 }
00480
00484 static int CclLog(lua_State *l)
00485 {
00486 LogEntry *log;
00487 LogEntry **last;
00488 const char *value;
00489
00490 LuaCheckArgs(l, 1);
00491 if (!lua_istable(l, 1)) {
00492 LuaError(l, "incorrect argument");
00493 }
00494
00495 Assert(CurrentReplay);
00496
00497 log = new LogEntry;
00498 log->UnitNumber = -1;
00499 log->PosX = -1;
00500 log->PosY = -1;
00501 log->DestUnitNumber = -1;
00502 log->Num = -1;
00503
00504 lua_pushnil(l);
00505 while (lua_next(l, 1)) {
00506 value = LuaToString(l, -2);
00507 if (!strcmp(value, "GameCycle")) {
00508 log->GameCycle = LuaToNumber(l, -1);
00509 } else if (!strcmp(value, "UnitNumber")) {
00510 log->UnitNumber = LuaToNumber(l, -1);
00511 } else if (!strcmp(value, "UnitIdent")) {
00512 log->UnitIdent = LuaToString(l, -1);
00513 } else if (!strcmp(value, "Action")) {
00514 log->Action = LuaToString(l, -1);
00515 } else if (!strcmp(value, "Flush")) {
00516 log->Flush = LuaToNumber(l, -1);
00517 } else if (!strcmp(value, "PosX")) {
00518 log->PosX = LuaToNumber(l, -1);
00519 } else if (!strcmp(value, "PosY")) {
00520 log->PosY = LuaToNumber(l, -1);
00521 } else if (!strcmp(value, "DestUnitNumber")) {
00522 log->DestUnitNumber = LuaToNumber(l, -1);
00523 } else if (!strcmp(value, "Value")) {
00524 log->Value = LuaToString(l, -1);
00525 } else if (!strcmp(value, "Num")) {
00526 log->Num = LuaToNumber(l, -1);
00527 } else if (!strcmp(value, "SyncRandSeed")) {
00528 log->SyncRandSeed = (unsigned)LuaToNumber(l, -1);
00529 } else {
00530 LuaError(l, "Unsupported key: %s" _C_ value);
00531 }
00532 lua_pop(l, 1);
00533 }
00534
00535
00536 last = &CurrentReplay->Commands;
00537 while (*last) {
00538 last = &(*last)->Next;
00539 }
00540
00541 *last = log;
00542
00543 return 0;
00544 }
00545
00549 static int CclReplayLog(lua_State *l)
00550 {
00551 FullReplay *replay;
00552 const char *value;
00553 int j;
00554
00555 LuaCheckArgs(l, 1);
00556 if (!lua_istable(l, 1)) {
00557 LuaError(l, "incorrect argument");
00558 }
00559
00560 Assert(CurrentReplay == NULL);
00561
00562 replay = new FullReplay;
00563
00564 lua_pushnil(l);
00565 while (lua_next(l, 1) != 0) {
00566 value = LuaToString(l, -2);
00567 if (!strcmp(value, "Comment1")) {
00568 replay->Comment1 = LuaToString(l, -1);
00569 } else if (!strcmp(value, "Comment2")) {
00570 replay->Comment2 = LuaToString(l, -1);
00571 } else if (!strcmp(value, "Comment3")) {
00572 replay->Comment3 = LuaToString(l, -1);
00573 } else if (!strcmp(value, "Date")) {
00574 replay->Date = LuaToString(l, -1);
00575 } else if (!strcmp(value, "Map")) {
00576 replay->Map = LuaToString(l, -1);
00577 } else if (!strcmp(value, "MapPath")) {
00578 replay->MapPath = LuaToString(l, -1);
00579 } else if (!strcmp(value, "MapId")) {
00580 replay->MapId = LuaToNumber(l, -1);
00581 } else if (!strcmp(value, "Type")) {
00582 replay->Type = LuaToNumber(l, -1);
00583 } else if (!strcmp(value, "LocalPlayer")) {
00584 replay->LocalPlayer = LuaToNumber(l, -1);
00585 } else if (!strcmp(value, "Players")) {
00586 if (!lua_istable(l, -1) || lua_objlen(l, -1) != PlayerMax) {
00587 LuaError(l, "incorrect argument");
00588 }
00589 for (j = 0; j < PlayerMax; ++j) {
00590 int top;
00591
00592 lua_rawgeti(l, -1, j + 1);
00593 if (!lua_istable(l, -1)) {
00594 LuaError(l, "incorrect argument");
00595 }
00596 top = lua_gettop(l);
00597 lua_pushnil(l);
00598 while (lua_next(l, top) != 0) {
00599 value = LuaToString(l, -2);
00600 if (!strcmp(value, "Name")) {
00601 replay->Players[j].Name = LuaToString(l, -1);
00602 } else if (!strcmp(value, "Team")) {
00603 replay->Players[j].Team = LuaToNumber(l, -1);
00604 } else if (!strcmp(value, "Type")) {
00605 replay->Players[j].Type = LuaToNumber(l, -1);
00606 } else {
00607 LuaError(l, "Unsupported key: %s" _C_ value);
00608 }
00609 lua_pop(l, 1);
00610 }
00611 lua_pop(l, 1);
00612 }
00613 } else if (!strcmp(value, "Resource")) {
00614 replay->Resource = LuaToNumber(l, -1);
00615 } else if (!strcmp(value, "NumUnits")) {
00616 replay->NumUnits = LuaToNumber(l, -1);
00617 } else if (!strcmp(value, "Difficulty")) {
00618 replay->Difficulty = LuaToNumber(l, -1);
00619 } else if (!strcmp(value, "NoFow")) {
00620 replay->NoFow = LuaToBoolean(l, -1);
00621 } else if (!strcmp(value, "RevealMap")) {
00622 replay->RevealMap = LuaToNumber(l, -1);
00623 } else if (!strcmp(value, "GameType")) {
00624 replay->GameType = LuaToNumber(l, -1);
00625 } else if (!strcmp(value, "Opponents")) {
00626 replay->Opponents = LuaToNumber(l, -1);
00627 } else if (!strcmp(value, "MapRichness")) {
00628 replay->MapRichness = LuaToNumber(l, -1);
00629 } else if (!strcmp(value, "Engine")) {
00630 if (!lua_istable(l, -1) || lua_objlen(l, -1) != 3) {
00631 LuaError(l, "incorrect argument");
00632 }
00633 lua_rawgeti(l, -1, 1);
00634 replay->Engine[0] = LuaToNumber(l, -1);
00635 lua_pop(l, 1);
00636 lua_rawgeti(l, -1, 2);
00637 replay->Engine[1] = LuaToNumber(l, -1);
00638 lua_pop(l, 1);
00639 lua_rawgeti(l, -1, 3);
00640 replay->Engine[2] = LuaToNumber(l, -1);
00641 lua_pop(l, 1);
00642 } else if (!strcmp(value, "Network")) {
00643 if (!lua_istable(l, -1) || lua_objlen(l, -1) != 3) {
00644 LuaError(l, "incorrect argument");
00645 }
00646 lua_rawgeti(l, -1, 1);
00647 replay->Network[0] = LuaToNumber(l, -1);
00648 lua_pop(l, 1);
00649 lua_rawgeti(l, -1, 2);
00650 replay->Network[1] = LuaToNumber(l, -1);
00651 lua_pop(l, 1);
00652 lua_rawgeti(l, -1, 3);
00653 replay->Network[2] = LuaToNumber(l, -1);
00654 lua_pop(l, 1);
00655 } else {
00656 LuaError(l, "Unsupported key: %s" _C_ value);
00657 }
00658 lua_pop(l, 1);
00659 }
00660
00661 CurrentReplay = replay;
00662
00663
00664 if (!SaveGameLoading) {
00665 ApplyReplaySettings();
00666 } else {
00667 CommandLogDisabled = false;
00668 }
00669
00670 return 0;
00671 }
00672
00676 bool IsReplayGame()
00677 {
00678 return ReplayGameType != ReplayNone;
00679 }
00680
00686 void SaveReplayList(CFile *file)
00687 {
00688 SaveFullLog(file);
00689 }
00690
00696 int LoadReplay(const std::string &name)
00697 {
00698 CleanReplayLog();
00699 ReplayGameType = ReplaySinglePlayer;
00700
00701 LuaLoadFile(name);
00702
00703 NextLogCycle = ~0UL;
00704 if (!CommandLogDisabled) {
00705 CommandLogDisabled = true;
00706 DisabledLog = true;
00707 }
00708 GameObserve = true;
00709 InitReplay = 1;
00710
00711 return 0;
00712 }
00713
00717 void EndReplayLog(void)
00718 {
00719 if (LogFile) {
00720 LogFile->close();
00721 delete LogFile;
00722 LogFile = NULL;
00723 }
00724 if (CurrentReplay) {
00725 DeleteReplay(CurrentReplay);
00726 CurrentReplay = NULL;
00727 }
00728 ReplayStep = NULL;
00729 }
00730
00734 void CleanReplayLog(void)
00735 {
00736 if (CurrentReplay) {
00737 DeleteReplay(CurrentReplay);
00738 CurrentReplay = 0;
00739 }
00740 ReplayStep = NULL;
00741
00742
00743 CommandLogDisabled = false;
00744 DisabledLog = false;
00745
00746 GameObserve = false;
00747 NetPlayers = 0;
00748 ReplayGameType = ReplayNone;
00749 }
00750
00754 static void DoNextReplay(void)
00755 {
00756 int unit;
00757 const char *action;
00758 int flags;
00759 int posx;
00760 int posy;
00761 const char *val;
00762 int num;
00763 CUnit *dunit;
00764
00765 Assert(ReplayStep != 0);
00766
00767 NextLogCycle = ReplayStep->GameCycle;
00768
00769 if (NextLogCycle != GameCycle) {
00770 return;
00771 }
00772
00773 unit = ReplayStep->UnitNumber;
00774 action = ReplayStep->Action.c_str();
00775 flags = ReplayStep->Flush;
00776 posx = ReplayStep->PosX;
00777 posy = ReplayStep->PosY;
00778 dunit = (ReplayStep->DestUnitNumber != -1 ? UnitSlots[ReplayStep->DestUnitNumber] : NoUnitP);
00779 val = ReplayStep->Value.c_str();
00780 num = ReplayStep->Num;
00781
00782 Assert(unit == -1 || ReplayStep->UnitIdent == UnitSlots[unit]->Type->Ident);
00783
00784 if (SyncRandSeed != ReplayStep->SyncRandSeed) {
00785 #ifdef DEBUG
00786 if (!ReplayStep->SyncRandSeed) {
00787
00788 ThisPlayer->Notify(NotifyYellow, -1, -1, _("No sync info for this replay !"));
00789 } else {
00790 ThisPlayer->Notify(NotifyYellow, -1, -1, _("Replay got out of sync (%lu) !"), GameCycle);
00791 DebugPrint("OUT OF SYNC %u != %u\n" _C_ SyncRandSeed _C_ ReplayStep->SyncRandSeed);
00792 DebugPrint("OUT OF SYNC GameCycle %lu \n" _C_ GameCycle);
00793 Assert(0);
00794
00795
00796
00797 }
00798 #else
00799 ThisPlayer->Notify(NotifyYellow, -1, -1, _("Replay got out of sync !"));
00800 ReplayStep = 0;
00801 NextLogCycle = ~0UL;
00802 return;
00803 #endif
00804 }
00805
00806 if (!strcmp(action, "stop")) {
00807 SendCommandStopUnit(UnitSlots[unit]);
00808 } else if (!strcmp(action, "stand-ground")) {
00809 SendCommandStandGround(UnitSlots[unit], flags);
00810 } else if (!strcmp(action, "follow")) {
00811 SendCommandFollow(UnitSlots[unit], dunit, flags);
00812 } else if (!strcmp(action, "move")) {
00813 SendCommandMove(UnitSlots[unit], posx, posy, flags);
00814 } else if (!strcmp(action, "repair")) {
00815 SendCommandRepair(UnitSlots[unit], posx, posy, dunit, flags);
00816 } else if (!strcmp(action, "auto-repair")) {
00817 SendCommandAutoRepair(UnitSlots[unit], posx);
00818 } else if (!strcmp(action, "attack")) {
00819 SendCommandAttack(UnitSlots[unit], posx, posy, dunit, flags);
00820 } else if (!strcmp(action, "attack-ground")) {
00821 SendCommandAttackGround(UnitSlots[unit], posx, posy, flags);
00822 } else if (!strcmp(action, "patrol")) {
00823 SendCommandPatrol(UnitSlots[unit], posx, posy, flags);
00824 } else if (!strcmp(action, "board")) {
00825 SendCommandBoard(UnitSlots[unit], posx, posy, dunit, flags);
00826 } else if (!strcmp(action, "unload")) {
00827 SendCommandUnload(UnitSlots[unit], posx, posy, dunit, flags);
00828 } else if (!strcmp(action, "build")) {
00829 SendCommandBuildBuilding(UnitSlots[unit], posx, posy, UnitTypeByIdent(val), flags);
00830 } else if (!strcmp(action, "dismiss")) {
00831 SendCommandDismiss(UnitSlots[unit]);
00832 } else if (!strcmp(action, "resource")) {
00833 SendCommandResource(UnitSlots[unit], dunit, flags);
00834 } else if (!strcmp(action, "train")) {
00835 SendCommandTrainUnit(UnitSlots[unit], UnitTypeByIdent(val), flags);
00836 } else if (!strcmp(action, "cancel-train")) {
00837 SendCommandCancelTraining(UnitSlots[unit], num, (val && *val) ? UnitTypeByIdent(val) : NULL);
00838 } else if (!strcmp(action, "spell-cast")) {
00839 SendCommandSpellCast(UnitSlots[unit], posx, posy, dunit, num, flags);
00840 } else if (!strcmp(action, "auto-spell-cast")) {
00841 SendCommandAutoSpellCast(UnitSlots[unit], num, posx);
00842 } else if (!strcmp(action, "diplomacy")) {
00843 int state;
00844 if (!strcmp(val, "neutral")) {
00845 state = DiplomacyNeutral;
00846 } else if (!strcmp(val, "allied")) {
00847 state = DiplomacyAllied;
00848 } else if (!strcmp(val, "enemy")) {
00849 state = DiplomacyEnemy;
00850 } else if (!strcmp(val, "crazy")) {
00851 state = DiplomacyCrazy;
00852 } else {
00853 DebugPrint("Invalid diplomacy command: %s" _C_ val);
00854 state = -1;
00855 }
00856 SendCommandDiplomacy(posx, state, posy);
00857 } else if (!strcmp(action, "shared-vision")) {
00858 bool state;
00859 state = atoi(val) ? true : false;
00860 SendCommandSharedVision(posx, state, posy);
00861 } else if (!strcmp(action, "input")) {
00862 if (val[0] == '-') {
00863 CclCommand(val + 1, false);
00864 } else {
00865 HandleCheats(val);
00866 }
00867 } else if (!strcmp(action, "quit")) {
00868 CommandQuit(posx);
00869 } else {
00870 DebugPrint("Invalid action: %s" _C_ action);
00871 }
00872
00873 ReplayStep = ReplayStep->Next;
00874 NextLogCycle = ReplayStep ? (unsigned)ReplayStep->GameCycle : ~0UL;
00875 }
00876
00880 static void ReplayEachCycle(void)
00881 {
00882 if (!CurrentReplay) {
00883 return;
00884 }
00885 if (InitReplay) {
00886 for (int i = 0; i < PlayerMax; ++i) {
00887 if (!CurrentReplay->Players[i].Name.empty()) {
00888 Players[i].SetName(CurrentReplay->Players[i].Name);
00889 }
00890 }
00891 ReplayStep = CurrentReplay->Commands;
00892 NextLogCycle = (ReplayStep ? (unsigned)ReplayStep->GameCycle : ~0UL);
00893 InitReplay = 0;
00894 }
00895
00896 if (!ReplayStep) {
00897 SetMessage(_("End of replay"));
00898 GameObserve = false;
00899 return;
00900 }
00901
00902 if (NextLogCycle != ~0UL && NextLogCycle != GameCycle) {
00903 return;
00904 }
00905
00906 do {
00907 DoNextReplay();
00908 } while (ReplayStep && (NextLogCycle == ~0UL || NextLogCycle == GameCycle));
00909
00910 if (!ReplayStep) {
00911 SetMessage(_("End of replay"));
00912 GameObserve = false;
00913 }
00914 }
00915
00919 void SinglePlayerReplayEachCycle()
00920 {
00921 if (ReplayGameType == ReplaySinglePlayer) {
00922 ReplayEachCycle();
00923 }
00924 }
00925
00929 void MultiPlayerReplayEachCycle()
00930 {
00931 if (ReplayGameType == ReplayMultiPlayer) {
00932 ReplayEachCycle();
00933 }
00934 }
00935
00939 void ReplayCclRegister(void)
00940 {
00941 lua_register(Lua, "Log", CclLog);
00942 lua_register(Lua, "ReplayLog", CclReplayLog);
00943 }
00944