Commit 3516ba98 authored by edo9300's avatar edo9300

Merge remote-tracking branch 'refs/remotes/origin/new-replay-system'

parents 80ffa24b 38ff205e
......@@ -53,7 +53,8 @@ ClientCard::ClientCard() {
void ClientCard::SetCode(int code) {
if((location == LOCATION_HAND) && (this->code != (unsigned int)code)) {
this->code = code;
mainGame->dField.MoveCard(this, 5);
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->dField.MoveCard(this, 5);
} else
this->code = code;
}
......@@ -66,7 +67,8 @@ void ClientCard::UpdateInfo(char* buf) {
pdata = BufferIO::ReadInt32(buf);
if((location == LOCATION_HAND) && ((unsigned int)pdata != code)) {
code = pdata;
mainGame->dField.MoveCard(this, 5);
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->dField.MoveCard(this, 5);
} else
code = pdata;
}
......
......@@ -26,6 +26,10 @@ u64 DuelClient::select_hint = 0;
wchar_t DuelClient::event_string[256];
mtrandom DuelClient::rnd;
std::vector<ReplayPacket> DuelClient::replay_stream;
Replay DuelClient::last_replay;
bool DuelClient::old_replay = true;
bool DuelClient::is_refreshing = false;
int DuelClient::match_kill = 0;
std::vector<HostPacket> DuelClient::hosts;
......@@ -693,43 +697,7 @@ void DuelClient::HandleSTOCPacketLan(char* data, unsigned int len) {
mainGame->btnSideReload->setVisible(false);
mainGame->wChat->setVisible(true);
mainGame->device->setEventReceiver(&mainGame->dField);
// reset master rule 4 phase button position
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 310, 855, 330));
if(mainGame->dInfo.extraval & 0x1) {
if(mainGame->dInfo.duel_field >= 4) {
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 290, 855, 350));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnEP->setRelativePosition(mainGame->Resize(310, 0, 360, 20));
} else {
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnDP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
mainGame->btnEP->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
} else {
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
if(mainGame->dInfo.duel_field >= 4) {
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
} else {
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
mainGame->btnEP->setRelativePosition(mainGame->Resize(320, 0, 370, 20));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
}
mainGame->SetPhaseButtons();
if(!mainGame->dInfo.isTag) {
if(selftype > 1) {
mainGame->dInfo.player_type = 7;
......@@ -767,6 +735,8 @@ void DuelClient::HandleSTOCPacketLan(char* data, unsigned int len) {
}
mainGame->gMutex.Unlock();
match_kill = 0;
replay_stream.clear();
old_replay = true;
break;
}
case STOC_DUEL_END: {
......@@ -803,6 +773,7 @@ void DuelClient::HandleSTOCPacketLan(char* data, unsigned int len) {
break;
}
case STOC_REPLAY: {
if (!old_replay) break;
mainGame->gMutex.Lock();
mainGame->wPhase->setVisible(false);
if(mainGame->dInfo.player_type < 7)
......@@ -823,16 +794,28 @@ void DuelClient::HandleSTOCPacketLan(char* data, unsigned int len) {
mainGame->gMutex.Unlock();
mainGame->replaySignal.Reset();
mainGame->replaySignal.Wait();
if(mainGame->actionParam || !is_host) {
if(mainGame->saveReplay || !is_host) {
char* prep = pdata;
Replay new_replay;
memcpy(&new_replay.pheader, prep, sizeof(ReplayHeader));
prep += sizeof(ReplayHeader);
memcpy(new_replay.comp_data, prep, len - sizeof(ReplayHeader) - 1);
new_replay.comp_size = len - sizeof(ReplayHeader) - 1;
if(mainGame->actionParam)
new_replay.SaveReplay(mainGame->ebRSName->getText());
else new_replay.SaveReplay(L"_LastReplay");
ReplayHeader pheader;
memcpy(&pheader, prep, sizeof(ReplayHeader));
replay_stream.push_back(ReplayPacket(OLD_REPLAY_MODE, prep, len - 1));
if(mainGame->saveReplay) {
last_replay.BeginRecord(false);
last_replay.WriteHeader(pheader);
last_replay.pheader.id = 0x58707279;
last_replay.WriteData(mainGame->dInfo.hostname, 40, false);
last_replay.WriteData(mainGame->dInfo.clientname, 40, false);
if (last_replay.pheader.flag & REPLAY_TAG) {
last_replay.WriteData(mainGame->dInfo.hostname_tag, 40, false);
last_replay.WriteData(mainGame->dInfo.clientname_tag, 40, false);
}
last_replay.WriteInt32(mainGame->dInfo.duel_field | mainGame->dInfo.extraval >> 8);
last_replay.WriteStream(replay_stream);
last_replay.EndRecord();
}
if (mainGame->saveReplay)
last_replay.SaveReplay(mainGame->ebRSName->getText());
else last_replay.SaveReplay(L"_LastReplay");
}
break;
}
......@@ -975,12 +958,56 @@ void DuelClient::HandleSTOCPacketLan(char* data, unsigned int len) {
mainGame->gMutex.Unlock();
break;
}
case STOC_NEW_REPLAY: {
old_replay = false;
mainGame->gMutex.Lock();
mainGame->wPhase->setVisible(false);
if(mainGame->dInfo.player_type < 7)
mainGame->btnLeaveGame->setVisible(false);
mainGame->btnChainIgnore->setVisible(false);
mainGame->btnChainAlways->setVisible(false);
mainGame->btnChainWhenAvail->setVisible(false);
mainGame->btnCancelOrFinish->setVisible(false);
time_t nowtime = time(NULL);
struct tm *localedtime = localtime(&nowtime);
char timebuf[40];
strftime(timebuf, 40, "%Y-%m-%d %H-%M-%S", localedtime);
size_t size = strlen(timebuf) + 1;
wchar_t timetext[80];
mbstowcs(timetext, timebuf, size);
mainGame->ebRSName->setText(timetext);
mainGame->PopupElement(mainGame->wReplaySave);
mainGame->gMutex.Unlock();
mainGame->replaySignal.Reset();
mainGame->replaySignal.Wait();
if(mainGame->saveReplay || !is_host) {
char* prep = pdata;
Replay new_replay;
memcpy(&new_replay.pheader, prep, sizeof(ReplayHeader));
prep += sizeof(ReplayHeader);
memcpy(new_replay.comp_data, prep, len - sizeof(ReplayHeader) - 1);
new_replay.comp_size = len - sizeof(ReplayHeader) - 1;
if(mainGame->saveReplay)
new_replay.SaveReplay(mainGame->ebRSName->getText());
else new_replay.SaveReplay(L"_LastReplay");
}
break;
}
}
}
int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
char* pbuf = msg;
wchar_t textBuffer[256];
mainGame->dInfo.curMsg = BufferIO::ReadUInt8(pbuf);
if(!mainGame->dInfo.isReplay || mainGame->dInfo.isOldReplay) {
mainGame->dInfo.curMsg = BufferIO::ReadUInt8(pbuf);
if(mainGame->dInfo.curMsg != MSG_WAITING) {
ReplayPacket p;
p.message = mainGame->dInfo.curMsg;
p.length = len - 1;
memcpy(p.data, pbuf, p.length);
replay_stream.push_back(p);
}
}
mainGame->wCmdMenu->setVisible(false);
if(!mainGame->dInfo.isReplay && mainGame->dInfo.curMsg != MSG_WAITING && mainGame->dInfo.curMsg != MSG_CARD_SELECTED) {
mainGame->waitFrame = -1;
......@@ -1164,15 +1191,17 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
return true;
}
case MSG_START: {
mainGame->showcardcode = 11;
mainGame->showcarddif = 30;
mainGame->showcardp = 0;
mainGame->showcard = 101;
mainGame->WaitFrameSignal(40);
mainGame->showcard = 0;
mainGame->gMutex.Lock();
int playertype = BufferIO::ReadInt8(pbuf);
mainGame->dInfo.isFirst = (playertype & 0xf) ? false : true;
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping) {
mainGame->showcardcode = 11;
mainGame->showcarddif = 30;
mainGame->showcardp = 0;
mainGame->showcard = 101;
mainGame->WaitFrameSignal(40);
mainGame->showcard = 0;
mainGame->gMutex.Lock();
mainGame->dInfo.isFirst = (playertype & 0xf) ? false : true;
}
if(playertype & 0xf0)
mainGame->dInfo.player_type = 7;
if(mainGame->dInfo.isTag) {
......@@ -1197,24 +1226,29 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
mainGame->dField.Initial(mainGame->LocalPlayer(1), deckc, extrac);
mainGame->dInfo.turn = 0;
mainGame->dInfo.is_shuffling = false;
mainGame->gMutex.Unlock();
if (!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Unlock();
return true;
}
case MSG_UPDATE_DATA: {
int player = mainGame->LocalPlayer(BufferIO::ReadInt8(pbuf));
int location = BufferIO::ReadInt8(pbuf);
mainGame->gMutex.Lock();
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Lock();
mainGame->dField.UpdateFieldCard(player, location, pbuf);
mainGame->gMutex.Unlock();
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Unlock();
return true;
}
case MSG_UPDATE_CARD: {
int player = mainGame->LocalPlayer(BufferIO::ReadInt8(pbuf));
int loc = BufferIO::ReadInt8(pbuf);
int seq = BufferIO::ReadInt8(pbuf);
mainGame->gMutex.Lock();
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Lock();
mainGame->dField.UpdateCard(player, loc, seq, pbuf);
mainGame->gMutex.Unlock();
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Unlock();
break;
}
case MSG_SELECT_BATTLECMD: {
......@@ -3729,11 +3763,13 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
break;
}
case MSG_RELOAD_FIELD: {
mainGame->gMutex.Lock();
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Lock();
mainGame->dField.Clear();
int field = BufferIO::ReadInt8(pbuf);
mainGame->dInfo.duel_field = field & 0xf;
mainGame->dInfo.extraval = field >> 4;
mainGame->SetPhaseButtons();
int val = 0;
for(int i = 0; i < 2; ++i) {
int p = mainGame->LocalPlayer(i);
......@@ -3848,7 +3884,8 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
myswprintf(event_string, dataManager.GetSysString(1609), dataManager.GetName(mainGame->dField.current_chain.code));
mainGame->dField.last_chain = true;
}
mainGame->gMutex.Unlock();
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Unlock();
break;
}
}
......@@ -3914,10 +3951,11 @@ void DuelClient::SendResponse() {
break;
}
}
replay_stream.pop_back();
if(mainGame->dInfo.isSingleMode) {
SingleMode::SetResponse(response_buf, response_len);
mainGame->singleSignal.Set();
} else {
} else if (!mainGame->dInfo.isReplay) {
mainGame->dInfo.time_player = 2;
SendBufferToServer(CTOS_RESPONSE, response_buf, response_len);
}
......
......@@ -13,6 +13,7 @@
#include "data_manager.h"
#include "deck_manager.h"
#include "../ocgcore/mtrandom.h"
#include "replay.h"
namespace ygo {
......@@ -45,6 +46,9 @@ public:
static void ClientEvent(bufferevent *bev, short events, void *ctx);
static int ClientThread(void* param);
static void HandleSTOCPacketLan(char* data, unsigned int len);
static std::vector<ReplayPacket> replay_stream;
static Replay last_replay;
static bool old_replay;
static int ClientAnalyze(char* msg, unsigned int len);
static void SetResponseI(int respI);
static void SetResponseB(void* respB, unsigned char len);
......
......@@ -95,13 +95,13 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
case BUTTON_REPLAY_SAVE: {
if(mainGame->ebRSName->getText()[0] == 0)
break;
mainGame->actionParam = 1;
mainGame->saveReplay = 1;
mainGame->HideElement(mainGame->wReplaySave);
mainGame->replaySignal.Set();
break;
}
case BUTTON_REPLAY_CANCEL: {
mainGame->actionParam = 0;
mainGame->saveReplay = 0;
mainGame->HideElement(mainGame->wReplaySave);
mainGame->replaySignal.Set();
break;
......
......@@ -617,6 +617,7 @@ bool Game::Initialize() {
btnReplayCancel = env->addButton(rect<s32>(460, 385, 570, 410), wReplay, BUTTON_CANCEL_REPLAY, dataManager.GetSysString(1347));
env->addStaticText(dataManager.GetSysString(1349), rect<s32>(360, 30, 570, 50), false, true, wReplay);
stReplayInfo = env->addStaticText(L"", rect<s32>(360, 60, 570, 350), false, true, wReplay);
chkYrp = env->addCheckBox(false, recti(360, 250, 560, 270), wReplay, -1, dataManager.GetSysString(1999));
env->addStaticText(dataManager.GetSysString(1353), rect<s32>(360, 275, 570, 295), false, true, wReplay);
ebRepStartTurn = env->addEditBox(L"", rect<s32>(360, 300, 460, 320), true, wReplay, -1);
ebRepStartTurn->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
......@@ -1228,7 +1229,7 @@ bool Game::PlayChant(unsigned int code) {
return false;
}
void Game::PlaySoundEffect(char* sound) {
if(chkEnableSound->isChecked()) {
if(chkEnableSound->isChecked() && (!dInfo.isReplay || !dInfo.isReplaySkiping)) {
engineSound->play2D(sound);
engineSound->setSoundVolume(gameConf.volume);
}
......@@ -1563,8 +1564,46 @@ int Game::GetMasterRule(uint32 param, uint32 forbiddentypes, int* truerule) {
}
}
}
void Game::OnResize()
{
void Game::SetPhaseButtons() {
// reset master rule 4 phase button position
wPhase->setRelativePosition(Resize(480, 310, 855, 330));
if (dInfo.extraval & 0x1) {
if (dInfo.duel_field >= 4) {
wPhase->setRelativePosition(Resize(480, 290, 855, 350));
btnShuffle->setRelativePosition(Resize(0, 40, 50, 60));
btnDP->setRelativePosition(Resize(0, 40, 50, 60));
btnSP->setRelativePosition(Resize(0, 40, 50, 60));
btnM1->setRelativePosition(Resize(160, 20, 210, 40));
btnBP->setRelativePosition(Resize(160, 20, 210, 40));
btnM2->setRelativePosition(Resize(160, 20, 210, 40));
btnEP->setRelativePosition(Resize(310, 0, 360, 20));
} else {
btnShuffle->setRelativePosition(Resize(65, 0, 115, 20));
btnDP->setRelativePosition(Resize(65, 0, 115, 20));
btnSP->setRelativePosition(Resize(65, 0, 115, 20));
btnM1->setRelativePosition(Resize(130, 0, 180, 20));
btnBP->setRelativePosition(Resize(195, 0, 245, 20));
btnM2->setRelativePosition(Resize(260, 0, 310, 20));
btnEP->setRelativePosition(Resize(260, 0, 310, 20));
}
} else {
btnDP->setRelativePosition(Resize(0, 0, 50, 20));
if (dInfo.duel_field >= 4) {
btnSP->setRelativePosition(Resize(0, 0, 50, 20));
btnM1->setRelativePosition(Resize(160, 0, 210, 20));
btnBP->setRelativePosition(Resize(160, 0, 210, 20));
btnM2->setRelativePosition(Resize(160, 0, 210, 20));
} else {
btnSP->setRelativePosition(Resize(65, 0, 115, 20));
btnM1->setRelativePosition(Resize(130, 0, 180, 20));
btnBP->setRelativePosition(Resize(195, 0, 245, 20));
btnM2->setRelativePosition(Resize(260, 0, 310, 20));
}
btnEP->setRelativePosition(Resize(320, 0, 370, 20));
btnShuffle->setRelativePosition(Resize(0, 0, 50, 20));
}
}
void Game::OnResize() {
wMainMenu->setRelativePosition(ResizeWin(370, 200, 650, 415));
wDeckEdit->setRelativePosition(Resize(309, 8, 605, 130));
cbDBLFList->setRelativePosition(Resize(80, 5, 220, 30));
......@@ -1662,42 +1701,7 @@ void Game::OnResize()
btnReplaySwap->setRelativePosition(Resize(5, 30, 85, 50));
btnReplayExit->setRelativePosition(Resize(5, 105, 85, 125));
wPhase->setRelativePosition(Resize(480, 310, 855, 330));
if(dInfo.extraval & 0x1) {
if(dInfo.duel_field >= 4) {
wPhase->setRelativePosition(Resize(480, 290, 855, 350));
btnShuffle->setRelativePosition(Resize(0, 40, 50, 60));
btnDP->setRelativePosition(Resize(0, 40, 50, 60));
btnSP->setRelativePosition(Resize(0, 40, 50, 60));
btnM1->setRelativePosition(Resize(160, 20, 210, 40));
btnBP->setRelativePosition(Resize(160, 20, 210, 40));
btnM2->setRelativePosition(Resize(160, 20, 210, 40));
btnEP->setRelativePosition(Resize(310, 0, 360, 20));
} else {
btnShuffle->setRelativePosition(Resize(65, 0, 115, 20));
btnDP->setRelativePosition(Resize(65, 0, 115, 20));
btnSP->setRelativePosition(Resize(65, 0, 115, 20));
btnM1->setRelativePosition(Resize(130, 0, 180, 20));
btnBP->setRelativePosition(Resize(195, 0, 245, 20));
btnM2->setRelativePosition(Resize(260, 0, 310, 20));
btnEP->setRelativePosition(Resize(260, 0, 310, 20));
}
} else {
btnDP->setRelativePosition(Resize(0, 0, 50, 20));
if(dInfo.duel_field >= 4) {
btnSP->setRelativePosition(Resize(0, 0, 50, 20));
btnM1->setRelativePosition(Resize(160, 0, 210, 20));
btnBP->setRelativePosition(Resize(160, 0, 210, 20));
btnM2->setRelativePosition(Resize(160, 0, 210, 20));
} else {
btnSP->setRelativePosition(Resize(65, 0, 115, 20));
btnM1->setRelativePosition(Resize(130, 0, 180, 20));
btnBP->setRelativePosition(Resize(195, 0, 245, 20));
btnM2->setRelativePosition(Resize(260, 0, 310, 20));
}
btnEP->setRelativePosition(Resize(320, 0, 370, 20));
btnShuffle->setRelativePosition(Resize(0, 0, 50, 20));
}
SetPhaseButtons();
btnSpectatorSwap->setRelativePosition(Resize(205, 100, 295, 135));
btnChainAlways->setRelativePosition(Resize(205, 140, 295, 175));
btnChainIgnore->setRelativePosition(Resize(205, 100, 295, 135));
......
......@@ -48,6 +48,7 @@ struct Config {
struct DuelInfo {
bool isStarted;
bool isReplay;
bool isOldReplay;
bool isReplaySkiping;
bool isFirst;
bool isTag;
......@@ -134,6 +135,7 @@ public:
const wchar_t* LocalName(int local_player);
void UpdateDuelParam();
int GetMasterRule(uint32 param, uint32 forbidden, int* truerule = 0);
void SetPhaseButtons();
bool HasFocus(EGUI_ELEMENT_TYPE type) const {
irr::gui::IGUIElement* focus = env->getFocus();
......@@ -170,7 +172,7 @@ public:
unsigned short linePattern;
int waitFrame;
int signalFrame;
int actionParam;
int saveReplay;
const wchar_t* showingtext;
int showcard;
int showcardcode;
......@@ -309,6 +311,7 @@ public:
irr::gui::IGUIWindow* wReplay;
irr::gui::IGUIListBox* lstReplayList;
irr::gui::IGUIStaticText* stReplayInfo;
irr::gui::IGUICheckBox* chkYrp;
irr::gui::IGUIButton* btnLoadReplay;
irr::gui::IGUIButton* btnReplayCancel;
irr::gui::IGUIEditBox* ebRepStartTurn;
......
......@@ -274,6 +274,8 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
if(!ReplayMode::cur_replay.OpenReplay(mainGame->lstReplayList->getListItem(mainGame->lstReplayList->getSelected())))
break;
}
if(mainGame->chkYrp->isChecked() && !ReplayMode::cur_replay.LoadYrp())
break;
mainGame->imgCard->setImage(imageManager.tCover[0]);
mainGame->wCardImg->setVisible(true);
mainGame->wInfos->setVisible(true);
......@@ -393,6 +395,11 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
repinfo.append(infobuf);
mainGame->ebRepStartTurn->setText(L"1");
mainGame->SetStaticText(mainGame->stReplayInfo, 180, mainGame->guiFont, (wchar_t*)repinfo.c_str());
if(ReplayMode::cur_replay.pheader.id == 0x31707279) {
mainGame->chkYrp->setChecked(false);
mainGame->chkYrp->setEnabled(false);
} else
mainGame->chkYrp->setEnabled(true);
break;
}
}
......
......@@ -215,6 +215,9 @@ public:
#define STOC_HS_PLAYER_CHANGE 0x21
#define STOC_HS_WATCH_CHANGE 0x22
#define STOC_NEW_REPLAY 0x30
#define PLAYERCHANGE_OBSERVE 0x8
#define PLAYERCHANGE_READY 0x9
#define PLAYERCHANGE_NOTREADY 0xa
......
#include "replay_mode.h"
#include "duelclient.h"
#include "game.h"
#include "single_mode.h"
#include "../ocgcore/duel.h"
#include "../ocgcore/field.h"
#include "../ocgcore/mtrandom.h"
namespace ygo {
bool ReplayMode::ReadReplayResponse() {
unsigned char resp[64];
bool result = cur_replay.ReadNextResponse(resp);
if (result)
set_responseb(pduel, resp);
return result;
}
int ReplayMode::OldReplayThread(void* param) {
const ReplayHeader& rh = cur_replay.pheader;
mainGame->dInfo.isFirst = true;
mainGame->dInfo.isTag = !!(rh.flag & REPLAY_TAG);
mainGame->dInfo.isSingleMode = !!(rh.flag & REPLAY_SINGLE_MODE);
mainGame->dInfo.lua64 = true;
mainGame->dInfo.tag_player[0] = false;
mainGame->dInfo.tag_player[1] = false;
if (mainGame->dInfo.isSingleMode) {
set_script_reader((script_reader)SingleMode::ScriptReader);
set_card_reader((card_reader)DataManager::CardReader);
set_message_handler((message_handler)MessageHandler);
}
else {
set_script_reader(default_script_reader);
set_card_reader((card_reader)DataManager::CardReader);
set_message_handler((message_handler)MessageHandler);
}
if (!StartDuel()) {
EndDuel();
return 0;
}
mainGame->dInfo.isStarted = true;
mainGame->dInfo.isReplay = true;
mainGame->dInfo.isOldReplay = true;
mainGame->dInfo.isReplaySkiping = (skip_turn > 0);
char engineBuffer[0x1000];
is_continuing = true;
skip_step = 0;
if (mainGame->dInfo.isSingleMode) {
int len = get_message(pduel, (byte*)engineBuffer);
if (len > 0)
is_continuing = ReplayAnalyze(engineBuffer, len);
}
else {
ReplayRefreshDeck(0);
ReplayRefreshDeck(1);
ReplayRefreshExtra(0);
ReplayRefreshExtra(1);
}
exit_pending = false;
current_step = 0;
if (mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Lock();
while (is_continuing && !exit_pending) {
int result = process(pduel);
int len = result & 0xffff;
/*int flag = result >> 16;*/
if (len > 0) {
get_message(pduel, (byte*)engineBuffer);
is_continuing = ReplayAnalyze(engineBuffer, len);
if (is_restarting) {
is_restarting = false;
int step = current_step - 1;
if (step < 0)
step = 0;
if (mainGame->dInfo.isSingleMode) {
is_continuing = true;
skip_step = 0;
int len = get_message(pduel, (byte*)engineBuffer);
if (len > 0) {
mainGame->gMutex.Unlock();
is_continuing = ReplayAnalyze(engineBuffer, len);
mainGame->gMutex.Lock();
}
}
if (step == 0) {
Pause(true, false);
mainGame->dInfo.isStarted = true;
mainGame->dInfo.isReplaySkiping = false;
mainGame->dField.RefreshAllCards();
mainGame->gMutex.Unlock();
}
skip_step = step;
current_step = 0;
}
}
}
if (mainGame->dInfo.isReplaySkiping) {
mainGame->dInfo.isReplaySkiping = false;
mainGame->dField.RefreshAllCards();
mainGame->gMutex.Unlock();
}
EndDuel();
return 0;
}
bool ReplayMode::StartDuel() {
const ReplayHeader& rh = cur_replay.pheader;
mtrandom rnd;
int seed = rh.seed;
rnd.reset(seed);
if (mainGame->dInfo.isTag) {
cur_replay.ReadName(mainGame->dInfo.hostname);
cur_replay.ReadName(mainGame->dInfo.hostname_tag);
cur_replay.ReadName(mainGame->dInfo.clientname_tag);
cur_replay.ReadName(mainGame->dInfo.clientname);
}
else {
cur_replay.ReadName(mainGame->dInfo.hostname);
cur_replay.ReadName(mainGame->dInfo.clientname);
}
pduel = create_duel(rnd.rand());
int start_lp = cur_replay.ReadInt32();
int start_hand = cur_replay.ReadInt32();
int draw_count = cur_replay.ReadInt32();
int opt = cur_replay.ReadInt32();
int duel_rule = opt >> 16;
int rule = opt >> 16; //backwards compatibility with master rule replays
if (rule)
switch (rule) {
case 1: {
opt |= MASTER_RULE_1;
break;
}
case 2: {
opt |= MASTER_RULE_2;
break;
}
case 3: {
opt |= MASTER_RULE_3;
break;
}
case 4: {
opt |= MASTER_RULE_4;
break;
}
}
//pre mr4 replay compatibility
if (opt & DUEL_OBSOLETE_RULING) {
opt &= ~DUEL_OBSOLETE_RULING;
opt |= MASTER_RULE_1;
}
else if (!(opt & 0xff80))
opt |= MASTER_RULE_3;
mainGame->dInfo.duel_field = 2;
if ((opt & DUEL_PZONE) && (opt & DUEL_SEPARATE_PZONE) && (opt & DUEL_EMZONE))
mainGame->dInfo.duel_field = 5;
else if (opt & DUEL_EMZONE)
mainGame->dInfo.duel_field = 4;
else if (opt & DUEL_PZONE)
mainGame->dInfo.duel_field = 3;
mainGame->dInfo.extraval = !!(opt & SPEED_DUEL);
// reset master rule 4 phase button position
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 310, 855, 330));
if (mainGame->dInfo.extraval) {
if (mainGame->dInfo.duel_field >= 4) {
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 290, 855, 350));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnEP->setRelativePosition(mainGame->Resize(310, 0, 360, 20));
}
else {
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnDP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
mainGame->btnEP->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
}
else {
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
if (mainGame->dInfo.duel_field >= 4) {
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
}
else {
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
mainGame->btnEP->setRelativePosition(mainGame->Resize(320, 0, 370, 20));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
}
set_player_info(pduel, 0, start_lp, start_hand, draw_count);
set_player_info(pduel, 1, start_lp, start_hand, draw_count);
mainGame->dInfo.lp[0] = start_lp;
mainGame->dInfo.lp[1] = start_lp;
mainGame->dInfo.startlp = start_lp;
myswprintf(mainGame->dInfo.strLP[0], L"%d", mainGame->dInfo.lp[0]);
myswprintf(mainGame->dInfo.strLP[1], L"%d", mainGame->dInfo.lp[1]);
mainGame->dInfo.turn = 0;
if (!mainGame->dInfo.isSingleMode) {
if (!(opt & DUEL_TAG_MODE)) {
int main = cur_replay.ReadInt32();
for (int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
int extra = cur_replay.ReadInt32();
for (int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(0, main, extra);
main = cur_replay.ReadInt32();
for (int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
extra = cur_replay.ReadInt32();
for (int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(1, main, extra);
}
else {
int main = cur_replay.ReadInt32();
for (int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
int extra = cur_replay.ReadInt32();
for (int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(0, main, extra);
main = cur_replay.ReadInt32();
for (int i = 0; i < main; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 0, LOCATION_DECK);
extra = cur_replay.ReadInt32();
for (int i = 0; i < extra; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 0, LOCATION_EXTRA);
main = cur_replay.ReadInt32();
for (int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
extra = cur_replay.ReadInt32();
for (int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(1, main, extra);
main = cur_replay.ReadInt32();
for (int i = 0; i < main; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 1, LOCATION_DECK);
extra = cur_replay.ReadInt32();
for (int i = 0; i < extra; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 1, LOCATION_EXTRA);
}
}
else {
char filename[256];
size_t slen = cur_replay.ReadInt16();
cur_replay.ReadData(filename, slen);
filename[slen] = 0;
if (!preload_script(pduel, filename, slen)) {
return false;
}
}
start_duel(pduel, opt);
return true;
}
bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) {
char* pbuf = msg;
int player, count;
is_restarting = false;
while (pbuf - msg < (int)len) {
if (is_closing)
return false;
if (is_restarting) {
//is_restarting = false;
return true;
}
if (is_swapping) {
mainGame->gMutex.Lock();
mainGame->dField.ReplaySwap();
mainGame->gMutex.Unlock();
is_swapping = false;
}
char* offset = pbuf;
bool pauseable = true;
mainGame->dInfo.curMsg = BufferIO::ReadUInt8(pbuf);
switch (mainGame->dInfo.curMsg) {
case MSG_RETRY: {
if (mainGame->dInfo.isReplaySkiping) {
mainGame->dInfo.isReplaySkiping = false;
mainGame->dField.RefreshAllCards();
mainGame->gMutex.Unlock();
}
mainGame->gMutex.Lock();
mainGame->stMessage->setText(L"Error occurs.");
mainGame->PopupElement(mainGame->wMessage);
mainGame->gMutex.Unlock();
mainGame->actionSignal.Reset();
mainGame->actionSignal.Wait();
return false;
}
case MSG_HINT: {
pbuf += (mainGame->dInfo.lua64) ? 10 : 6;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_WIN: {
if (mainGame->dInfo.isReplaySkiping) {
mainGame->dInfo.isReplaySkiping = false;
mainGame->dField.RefreshAllCards();
mainGame->gMutex.Unlock();
}
pbuf += 2;
DuelClient::ClientAnalyze(offset, pbuf - offset);
return false;
}
case MSG_SELECT_BATTLECMD: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * (mainGame->dInfo.lua64) ? 15 : 11;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8 + 2;
ReplayRefresh();
return ReadReplayResponse();
}
case MSG_SELECT_IDLECMD: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * (mainGame->dInfo.lua64) ? 15 : 11 + 3;
ReplayRefresh();
return ReadReplayResponse();
}
case MSG_SELECT_EFFECTYN: {
player = BufferIO::ReadInt8(pbuf);
pbuf += (mainGame->dInfo.lua64) ? 16 : 12;
return ReadReplayResponse();
}
case MSG_SELECT_YESNO: {
player = BufferIO::ReadInt8(pbuf);
pbuf += (mainGame->dInfo.lua64) ? 8 : 4;
return ReadReplayResponse();
}
case MSG_SELECT_OPTION: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * (mainGame->dInfo.lua64) ? 8 : 4;
return ReadReplayResponse();
}
case MSG_SELECT_CARD:
case MSG_SELECT_TRIBUTE: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 3;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8;
return ReadReplayResponse();
}
case MSG_SELECT_UNSELECT_CARD: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 4;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8;
return ReadReplayResponse();
}
case MSG_SELECT_CHAIN: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += 10 + count * (mainGame->dInfo.lua64) ? 17 : 13;
return ReadReplayResponse();
}
case MSG_SELECT_PLACE:
case MSG_SELECT_DISFIELD: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 5;
return ReadReplayResponse();
}
case MSG_SELECT_POSITION: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 5;
return ReadReplayResponse();
}
case MSG_SELECT_COUNTER: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 4;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 9;
return ReadReplayResponse();
}
case MSG_SELECT_SUM: {
pbuf++;
player = BufferIO::ReadInt8(pbuf);
pbuf += 6;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 11;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 11;
return ReadReplayResponse();
}
case MSG_SORT_CARD:
case MSG_SORT_CHAIN: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
return ReadReplayResponse();
}
case MSG_CONFIRM_DECKTOP: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CONFIRM_EXTRATOP: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CONFIRM_CARDS: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SHUFFLE_DECK: {
player = BufferIO::ReadInt8(pbuf);
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefreshDeck(player);
break;
}
case MSG_SHUFFLE_HAND: {
/*int oplayer = */BufferIO::ReadInt8(pbuf);
int count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SHUFFLE_EXTRA: {
/*int oplayer = */BufferIO::ReadInt8(pbuf);
int count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_REFRESH_DECK: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SWAP_GRAVE_DECK: {
player = BufferIO::ReadInt8(pbuf);
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefreshGrave(player);
break;
}
case MSG_REVERSE_DECK: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefreshDeck(0);
ReplayRefreshDeck(1);
break;
}
case MSG_DECK_TOP: {
pbuf += 6;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SHUFFLE_SET_CARD: {
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_NEW_TURN: {
if (skip_turn) {
skip_turn--;
if (skip_turn == 0) {
mainGame->dInfo.isReplaySkiping = false;
mainGame->dField.RefreshAllCards();
mainGame->gMutex.Unlock();
}
}
player = BufferIO::ReadInt8(pbuf);
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_NEW_PHASE: {
pbuf += 2;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_MOVE: {
int pc = pbuf[4];
int pl = pbuf[5];
/*int ps = pbuf[6];*/
/*int pp = pbuf[7];*/
int cc = pbuf[8];
int cl = pbuf[9];
int cs = pbuf[10];
/*int cp = pbuf[11];*/
pbuf += 16;
DuelClient::ClientAnalyze(offset, pbuf - offset);
if (cl && !(cl & 0x80) && (pl != cl || pc != cc))
ReplayRefreshSingle(cc, cl, cs);
break;
}
case MSG_POS_CHANGE: {
pbuf += 9;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SET: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_SWAP: {
pbuf += 16;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_FIELD_DISABLED: {
pbuf += 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_SUMMONING: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_SUMMONED: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_SPSUMMONING: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_SPSUMMONED: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_FLIPSUMMONING: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_FLIPSUMMONED: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_CHAINING: {
pbuf += (mainGame->dInfo.lua64) ? 20 : 16;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CHAINED: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_CHAIN_SOLVING: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_CHAIN_SOLVED: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
pauseable = false;
break;
}
case MSG_CHAIN_END: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
pauseable = false;
break;
}
case MSG_CHAIN_NEGATED: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CHAIN_DISABLED: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CARD_SELECTED:
case MSG_RANDOM_SELECTED: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_BECOME_TARGET: {
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_DRAW: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_DAMAGE: {
pbuf += 5;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_RECOVER: {
pbuf += 5;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_EQUIP: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_LPUPDATE: {
pbuf += 5;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_UNEQUIP: {
pbuf += 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_CARD_TARGET: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_CANCEL_TARGET: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_PAY_LPCOST: {
pbuf += 5;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_ADD_COUNTER: {
pbuf += 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_REMOVE_COUNTER: {
pbuf += 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_ATTACK: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_BATTLE: {
pbuf += 26;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_ATTACK_DISABLED: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_DAMAGE_STEP_START: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
pauseable = false;
break;
}
case MSG_DAMAGE_STEP_END: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
pauseable = false;
break;
}
case MSG_MISSED_EFFECT: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_TOSS_COIN: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_TOSS_DICE: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_ROCK_PAPER_SCISSORS: {
player = BufferIO::ReadInt8(pbuf);
return ReadReplayResponse();
}
case MSG_HAND_RES: {
pbuf += 1;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_ANNOUNCE_RACE: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 5;
return ReadReplayResponse();
}
case MSG_ANNOUNCE_ATTRIB: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 5;
return ReadReplayResponse();
}
case MSG_ANNOUNCE_CARD: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 4;
return ReadReplayResponse();
}
case MSG_ANNOUNCE_NUMBER:
case MSG_ANNOUNCE_CARD_FILTER: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += (mainGame->dInfo.lua64) ? 8 : 4 * count;
return ReadReplayResponse();
}
case MSG_CARD_HINT: {
pbuf += (mainGame->dInfo.lua64) ? 13 : 9;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_PLAYER_HINT: {
pbuf += (mainGame->dInfo.lua64) ? 10 : 6;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_MATCH_KILL: {
pbuf += 4;
break;
}
case MSG_TAG_SWAP: {
player = pbuf[0];
pbuf += pbuf[2] * 4 + pbuf[4] * 4 + 9;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefreshDeck(player);
ReplayRefreshExtra(player);
break;
}
case MSG_RELOAD_FIELD: {
pbuf++;
for (int p = 0; p < 2; ++p) {
pbuf += 4;
for (int seq = 0; seq < 7; ++seq) {
int val = BufferIO::ReadInt8(pbuf);
if (val)
pbuf += 2;
}
for (int seq = 0; seq < 8; ++seq) {
int val = BufferIO::ReadInt8(pbuf);
if (val)
pbuf++;
}
pbuf += 6;
}
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayReload();
mainGame->dField.RefreshAllCards();
break;
}
case MSG_AI_NAME: {
int len = BufferIO::ReadInt16(pbuf);
pbuf += len + 1;
break;
}
case MSG_SHOW_HINT: {
int len = BufferIO::ReadInt16(pbuf);
pbuf += len + 1;
break;
}
}
if (pauseable) {
current_step++;
if (skip_step) {
skip_step--;
if (skip_step == 0) {
Pause(true, false);
mainGame->dInfo.isStarted = true;
mainGame->dInfo.isReplaySkiping = false;
mainGame->dField.RefreshAllCards();
mainGame->gMutex.Unlock();
}
}
if (is_pausing) {
is_paused = true;
mainGame->actionSignal.Reset();
mainGame->actionSignal.Wait();
is_paused = false;
}
}
}
return true;
}
void ReplayMode::ReplayRefresh(int flag) {
unsigned char queryBuffer[0x4000];
/*int len = */query_field_card(pduel, 0, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_HAND, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshHand(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_HAND, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshGrave(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_GRAVE, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshDeck(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_DECK, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshExtra(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_EXTRA, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshSingle(int player, int location, int sequence, int flag) {
unsigned char queryBuffer[0x4000];
/*int len = */query_card(pduel, player, location, sequence, flag, queryBuffer, 0);
mainGame->dField.UpdateCard(mainGame->LocalPlayer(player), location, sequence, (char*)queryBuffer);
}
void ReplayMode::ReplayReload() {
unsigned char queryBuffer[0x4000];
unsigned int flag = 0xffdfff;
/*int len = */query_field_card(pduel, 0, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_DECK, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_DECK, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_EXTRA, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_EXTRA, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_GRAVE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_GRAVE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_REMOVED, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_REMOVED, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_REMOVED, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_REMOVED, (char*)queryBuffer);
}
int ReplayMode::MessageHandler(long fduel, int type) {
if (!enable_log)
return 0;
char msgbuf[1024];
get_log_message(fduel, (byte*)msgbuf);
mainGame->AddDebugMsg(msgbuf);
return 0;
}
}
\ No newline at end of file
#include "replay.h"
#include "../ocgcore/ocgapi.h"
#include "../ocgcore/card.h"
#include "../ocgcore/field.h"
#include <algorithm>
#include "lzma/LzmaLib.h"
namespace ygo {
ReplayPacket::ReplayPacket(char * buf, int len) {
message = BufferIO::ReadInt8(buf);
length = len;
memcpy(data, buf, length);
}
ReplayPacket::ReplayPacket(int msg, char * buf, int len) {
message = msg;
length = len;
memcpy(data, buf, length);
}
void ReplayPacket::Set(int msg, char * buf, int len) {
message = msg;
length = len;
memcpy(data, buf, length);
}
Replay::Replay() {
is_recording = false;
is_replaying = false;
......@@ -16,25 +33,42 @@ Replay::~Replay() {
delete[] replay_data;
delete[] comp_data;
}
void Replay::BeginRecord() {
void Replay::BeginRecord(bool write) {
#ifdef _WIN32
if(is_recording)
if(is_recording && is_writing)
CloseHandle(recording_fp);
recording_fp = CreateFileW(L"./replay/_LastReplay.yrp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
if(recording_fp == INVALID_HANDLE_VALUE)
return;
is_writing = write;
if(is_writing) {
recording_fp = CreateFileW(L"./replay/_LastReplay.yrpX", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
if(recording_fp == INVALID_HANDLE_VALUE)
return;
}
#else
if(is_recording)
if(is_recording && is_writing)
fclose(fp);
fp = fopen("./replay/_LastReplay.yrp", "wb");
if(!fp)
return;
is_writing = write;
if(is_writing) {
fp = fopen("./replay/_LastReplay.yrpX", "wb");
if(!fp)
return;
}
#endif
pdata = replay_data;
is_recording = true;
}
void Replay::WritePacket(ReplayPacket p) {
WriteInt8(p.message, false);
WriteInt32(p.length, false);
WriteData((char*)p.data, p.length);
}
void Replay::WriteStream(std::vector<ReplayPacket> stream) {
if(stream.size())
for(auto it = stream.begin(); it != stream.end(); it++)
WritePacket((*it));
}
void Replay::WriteHeader(ReplayHeader& header) {
pheader = header;
if(!is_writing) return;
#ifdef _WIN32
DWORD size;
WriteFile(recording_fp, &header, sizeof(header), &size, NULL);
......@@ -48,6 +82,7 @@ void Replay::WriteData(const void* data, unsigned int length, bool flush) {
return;
memcpy(pdata, data, length);
pdata += length;
if(!is_writing) return;
#ifdef _WIN32
DWORD size;
WriteFile(recording_fp, data, length, &size, NULL);
......@@ -62,6 +97,7 @@ void Replay::WriteInt32(int data, bool flush) {
return;
*((int*)(pdata)) = data;
pdata += 4;
if(!is_writing) return;
#ifdef _WIN32
DWORD size;
WriteFile(recording_fp, &data, sizeof(int), &size, NULL);
......@@ -76,6 +112,7 @@ void Replay::WriteInt16(short data, bool flush) {
return;
*((short*)(pdata)) = data;
pdata += 2;
if(!is_writing) return;
#ifdef _WIN32
DWORD size;
WriteFile(recording_fp, &data, sizeof(short), &size, NULL);
......@@ -90,6 +127,7 @@ void Replay::WriteInt8(char data, bool flush) {
return;
*pdata = data;
pdata++;
if(!is_writing) return;
#ifdef _WIN32
DWORD size;
WriteFile(recording_fp, &data, sizeof(char), &size, NULL);
......@@ -102,14 +140,16 @@ void Replay::WriteInt8(char data, bool flush) {
void Replay::Flush() {
if(!is_recording)
return;
if(!is_writing) return;
#ifdef _WIN32
#else
fflush(fp);
#endif
}
void Replay::EndRecord() {
void Replay::EndRecord(size_t size) {
if(!is_recording)
return;
if(is_writing)
#ifdef _WIN32
CloseHandle(recording_fp);
#else
......@@ -118,13 +158,13 @@ void Replay::EndRecord() {
pheader.datasize = pdata - replay_data;
pheader.flag |= REPLAY_COMPRESSED;
size_t propsize = 5;
comp_size = 0x1000;
comp_size = size;
LzmaCompress(comp_data, &comp_size, replay_data, pdata - replay_data, pheader.props, &propsize, 5, 1 << 24, 3, 0, 2, 32, 1);
is_recording = false;
}
void Replay::SaveReplay(const wchar_t* name) {
wchar_t fname[256];
myswprintf(fname, L"./replay/%ls.yrp", name);
myswprintf(fname, L"./replay/%ls.yrpX", name);
#ifdef WIN32
fp = _wfopen(fname, L"wb");
#else
......@@ -161,7 +201,7 @@ bool Replay::OpenReplay(const wchar_t* name) {
return false;
fread(&pheader, sizeof(pheader), 1, fp);
if(pheader.flag & REPLAY_COMPRESSED) {
comp_size = fread(comp_data, 1, 0x1000, fp);
comp_size = fread(comp_data, 1, 0x20000, fp);
fclose(fp);
replay_size = pheader.datasize;
if(LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.props, 5) != SZ_OK)
......@@ -190,7 +230,23 @@ bool Replay::CheckReplay(const wchar_t* name) {
ReplayHeader rheader;
fread(&rheader, sizeof(ReplayHeader), 1, rfp);
fclose(rfp);
return rheader.id == 0x31707279 && rheader.version >= 0x12d0;
return (rheader.id == 0x31707279 || rheader.id == 0x58707279) && rheader.version >= 0x12d0;
}
bool Replay::ReadNextPacket(ReplayPacket* packet) {
if (pdata - replay_data >= (int)replay_size)
return false;
packet->message = *pdata++;
packet->length = ReadInt32();
ReadData((char*)&packet->data, packet->length);
return true;
}
bool Replay::ReadStream(std::vector<ReplayPacket>* stream) {
stream->clear();
ReplayPacket p;
while (ReadNextPacket(&p)) {
stream->push_back(p);
}
return !!stream->size();
}
bool Replay::ReadNextResponse(unsigned char resp[64]) {
if(pdata - replay_data >= (int)replay_size)
......@@ -238,4 +294,31 @@ void Replay::Rewind() {
pdata = replay_data;
}
bool Replay::LoadYrp() {
if (pheader.flag & REPLAY_NEWREPLAY) {
pdata += (4 + ((pheader.flag & REPLAY_TAG) ? 160 : 80));
ReplayPacket p;
while (ReadNextPacket(&p))
if (p.message == OLD_REPLAY_MODE) {
char* prep = (char*)p.data;
memcpy(&pheader, prep, sizeof(ReplayHeader));
prep += sizeof(ReplayHeader);
if(pheader.flag & REPLAY_COMPRESSED) {
comp_size = (size_t)(p.length - sizeof(ReplayHeader));
replay_size = pheader.datasize;
if (LzmaUncompress(replay_data, &replay_size, (unsigned char*)prep, &comp_size, pheader.props, 5) != SZ_OK)
return false;
} else {
comp_size = fread(replay_data, 1, 0x20000, fp);
fclose(fp);
replay_size = comp_size;
}
pdata = replay_data;
is_replaying = true;
return true;
}
}
return !(pheader.flag & REPLAY_NEWREPLAY);
}
}
......@@ -11,6 +11,7 @@ namespace ygo {
#define REPLAY_DECODED 0x4
#define REPLAY_SINGLE_MODE 0x8
#define REPLAY_LUA64 0x10
#define REPLAY_NEWREPLAY 0x20
struct ReplayHeader {
unsigned int id;
......@@ -22,29 +23,44 @@ struct ReplayHeader {
unsigned char props[8];
};
class ReplayPacket {
public:
int message;
int length;
unsigned char data[0x2000];
ReplayPacket() {}
ReplayPacket(char * buf, int len);
ReplayPacket(int msg, char * buf, int len);
void Set(int msg, char * buf, int len);
};
class Replay {
public:
Replay();
~Replay();
void BeginRecord();
void BeginRecord(bool write = true);
void WriteStream(std::vector<ReplayPacket> stream);
void WritePacket(ReplayPacket p);
void WriteHeader(ReplayHeader& header);
void WriteData(const void* data, unsigned int length, bool flush = true);
void WriteInt32(int data, bool flush = true);
void WriteInt16(short data, bool flush = true);
void WriteInt8(char data, bool flush = true);
void Flush();
void EndRecord();
void EndRecord(size_t size = 0x20000);
void SaveReplay(const wchar_t* name);
bool OpenReplay(const wchar_t* name);
static bool CheckReplay(const wchar_t* name);
bool ReadNextPacket(ReplayPacket* packet);
bool ReadStream(std::vector<ReplayPacket>* stream);
bool ReadNextResponse(unsigned char resp[64]);
void ReadName(wchar_t* data);
void ReadHeader(ReplayHeader& header);
void ReadData(void* data, unsigned int length);
int ReadInt32();
short ReadInt16();
char ReadInt8();
void Rewind();
bool LoadYrp();
FILE* fp;
ReplayHeader pheader;
......@@ -57,6 +73,7 @@ public:
size_t replay_size;
size_t comp_size;
bool is_recording;
bool is_writing;
bool is_replaying;
};
......
......@@ -9,12 +9,14 @@
namespace ygo {
long ReplayMode::pduel = 0;
bool ReplayMode::yrp = false;
Replay ReplayMode::cur_replay;
std::vector<ReplayPacket> ReplayMode::current_stream;
bool ReplayMode::is_continuing = true;
bool ReplayMode::is_closing = false;
bool ReplayMode::is_pausing = false;
bool ReplayMode::is_paused = false;
bool ReplayMode::is_swaping = false;
bool ReplayMode::is_swapping = false;
bool ReplayMode::is_restarting = false;
bool ReplayMode::exit_pending = false;
int ReplayMode::skip_turn = 0;
......@@ -24,8 +26,12 @@ int ReplayMode::skip_step = 0;
bool ReplayMode::StartReplay(int skipturn) {
skip_turn = skipturn;
if(skip_turn < 0)
skip_turn = 0;
Thread::NewThread(ReplayThread, 0);
skip_turn = 0;
yrp = cur_replay.pheader.id == 0x31707279;
if(yrp)
Thread::NewThread(OldReplayThread, 0);
else
Thread::NewThread(ReplayThread, 0);
return true;
}
void ReplayMode::StopReplay(bool is_exiting) {
......@@ -39,7 +45,7 @@ void ReplayMode::SwapField() {
if(is_paused)
mainGame->dField.ReplaySwap();
else
is_swaping = true;
is_swapping = true;
}
void ReplayMode::Pause(bool is_pause, bool is_step) {
if(is_pause)
......@@ -50,13 +56,6 @@ void ReplayMode::Pause(bool is_pause, bool is_step) {
mainGame->actionSignal.Set();
}
}
bool ReplayMode::ReadReplayResponse() {
unsigned char resp[64];
bool result = cur_replay.ReadNextResponse(resp);
if(result)
set_responseb(pduel, resp);
return result;
}
int ReplayMode::ReplayThread(void* param) {
const ReplayHeader& rh = cur_replay.pheader;
mainGame->dInfo.isFirst = true;
......@@ -65,72 +64,53 @@ int ReplayMode::ReplayThread(void* param) {
mainGame->dInfo.lua64 = !!(rh.flag & REPLAY_LUA64);
mainGame->dInfo.tag_player[0] = false;
mainGame->dInfo.tag_player[1] = false;
if(mainGame->dInfo.isSingleMode) {
set_script_reader((script_reader)SingleMode::ScriptReader);
set_card_reader((card_reader)DataManager::CardReader);
set_message_handler((message_handler)MessageHandler);
} else {
set_script_reader(default_script_reader);
set_card_reader((card_reader)DataManager::CardReader);
set_message_handler((message_handler)MessageHandler);
if (mainGame->dInfo.isTag) {
cur_replay.ReadName(mainGame->dInfo.hostname);
cur_replay.ReadName(mainGame->dInfo.hostname_tag);
cur_replay.ReadName(mainGame->dInfo.clientname_tag);
cur_replay.ReadName(mainGame->dInfo.clientname);
}
if(!StartDuel()) {
else {
cur_replay.ReadName(mainGame->dInfo.hostname);
cur_replay.ReadName(mainGame->dInfo.clientname);
}
int opt = cur_replay.ReadInt32();
mainGame->dInfo.duel_field = opt & 0xff;
mainGame->dInfo.extraval = (opt >> 8);
mainGame->SetPhaseButtons();
if(!cur_replay.ReadStream(&current_stream)) {
EndDuel();
return 0;
}
mainGame->dInfo.isStarted = true;
mainGame->dInfo.isReplay = true;
mainGame->dInfo.turn = 0;
mainGame->dInfo.isReplaySkiping = (skip_turn > 0);
char engineBuffer[0x1000];
is_continuing = true;
skip_step = 0;
if(mainGame->dInfo.isSingleMode) {
int len = get_message(pduel, (byte*)engineBuffer);
if (len > 0)
is_continuing = ReplayAnalyze(engineBuffer, len);
} else {
ReplayRefreshDeck(0);
ReplayRefreshDeck(1);
ReplayRefreshExtra(0);
ReplayRefreshExtra(1);
}
exit_pending = false;
current_step = 0;
if(mainGame->dInfo.isReplaySkiping)
mainGame->gMutex.Lock();
while (is_continuing && !exit_pending) {
int result = process(pduel);
int len = result & 0xffff;
/*int flag = result >> 16;*/
if (len > 0) {
get_message(pduel, (byte*)engineBuffer);
is_continuing = ReplayAnalyze(engineBuffer, len);
if(is_restarting) {
is_restarting = false;
int step = current_step - 1;
if(step < 0)
step = 0;
if(mainGame->dInfo.isSingleMode) {
is_continuing = true;
skip_step = 0;
int len = get_message(pduel, (byte*)engineBuffer);
if (len > 0) {
mainGame->gMutex.Unlock();
is_continuing = ReplayAnalyze(engineBuffer, len);
mainGame->gMutex.Lock();
}
}
if(step == 0) {
Pause(true, false);
mainGame->dInfo.isStarted = true;
mainGame->dInfo.isReplaySkiping = false;
mainGame->dField.RefreshAllCards();
mainGame->gMutex.Unlock();
}
skip_step = step;
current_step = 0;
for(auto it = current_stream.begin(); is_continuing && !exit_pending && it != current_stream.end();) {
is_continuing = ReplayAnalyze((*it));
if(is_restarting) {
it = current_stream.begin();
is_restarting = false;
int step = current_step - 1;
if (step < 0)
step = 0;
if (step == 0) {
Pause(true, false);
mainGame->dInfo.isStarted = true;
mainGame->dInfo.isReplaySkiping = false;
mainGame->dField.RefreshAllCards();
mainGame->gMutex.Unlock();
}
}
skip_step = step;
current_step = 0;
} else
it++;
}
if(mainGame->dInfo.isReplaySkiping) {
mainGame->dInfo.isReplaySkiping = false;
......@@ -140,163 +120,9 @@ int ReplayMode::ReplayThread(void* param) {
EndDuel();
return 0;
}
bool ReplayMode::StartDuel() {
const ReplayHeader& rh = cur_replay.pheader;
mtrandom rnd;
int seed = rh.seed;
rnd.reset(seed);
if(mainGame->dInfo.isTag) {
cur_replay.ReadName(mainGame->dInfo.hostname);
cur_replay.ReadName(mainGame->dInfo.hostname_tag);
cur_replay.ReadName(mainGame->dInfo.clientname_tag);
cur_replay.ReadName(mainGame->dInfo.clientname);
} else {
cur_replay.ReadName(mainGame->dInfo.hostname);
cur_replay.ReadName(mainGame->dInfo.clientname);
}
pduel = create_duel(rnd.rand());
int start_lp = cur_replay.ReadInt32();
int start_hand = cur_replay.ReadInt32();
int draw_count = cur_replay.ReadInt32();
int opt = cur_replay.ReadInt32();
int duel_rule = opt >> 16;
int rule = opt >> 16; //backwards compatibility with master rule replays
if(rule)
switch (rule) {
case 1: {
opt |= MASTER_RULE_1;
break;
}
case 2: {
opt |= MASTER_RULE_2;
break;
}
case 3: {
opt |= MASTER_RULE_3;
break;
}
case 4: {
opt |= MASTER_RULE_4;
break;
}
}
//pre mr4 replay compatibility
if(opt & DUEL_OBSOLETE_RULING) {
opt &= ~DUEL_OBSOLETE_RULING;
opt |= MASTER_RULE_1;
} else if (!(opt & 0xff80))
opt |= MASTER_RULE_3;
mainGame->dInfo.duel_field = 2;
if ((opt & DUEL_PZONE) && (opt & DUEL_SEPARATE_PZONE) && (opt & DUEL_EMZONE))
mainGame->dInfo.duel_field = 5;
else if (opt & DUEL_EMZONE)
mainGame->dInfo.duel_field = 4;
else if(opt & DUEL_PZONE)
mainGame->dInfo.duel_field = 3;
mainGame->dInfo.extraval = !!(opt & SPEED_DUEL);
// reset master rule 4 phase button position
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 310, 855, 330));
if(mainGame->dInfo.extraval) {
if(mainGame->dInfo.duel_field >= 4) {
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 290, 855, 350));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnEP->setRelativePosition(mainGame->Resize(310, 0, 360, 20));
} else {
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnDP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
mainGame->btnEP->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
} else {
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
if(mainGame->dInfo.duel_field >= 4) {
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
} else {
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
mainGame->btnEP->setRelativePosition(mainGame->Resize(320, 0, 370, 20));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
}
set_player_info(pduel, 0, start_lp, start_hand, draw_count);
set_player_info(pduel, 1, start_lp, start_hand, draw_count);
mainGame->dInfo.lp[0] = start_lp;
mainGame->dInfo.lp[1] = start_lp;
mainGame->dInfo.startlp = start_lp;
myswprintf(mainGame->dInfo.strLP[0], L"%d", mainGame->dInfo.lp[0]);
myswprintf(mainGame->dInfo.strLP[1], L"%d", mainGame->dInfo.lp[1]);
mainGame->dInfo.turn = 0;
if(!mainGame->dInfo.isSingleMode) {
if(!(opt & DUEL_TAG_MODE)) {
int main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
int extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(0, main, extra);
main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(1, main, extra);
} else {
int main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
int extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(0, main, extra);
main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 0, LOCATION_DECK);
extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 0, LOCATION_EXTRA);
main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(1, main, extra);
main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 1, LOCATION_DECK);
extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 1, LOCATION_EXTRA);
}
} else {
char filename[256];
size_t slen = cur_replay.ReadInt16();
cur_replay.ReadData(filename, slen);
filename[slen] = 0;
if(!preload_script(pduel, filename, slen)) {
return false;
}
}
start_duel(pduel, opt);
return true;
}
void ReplayMode::EndDuel() {
end_duel(pduel);
if(yrp)
end_duel(pduel);
if(!is_closing) {
mainGame->actionSignal.Reset();
mainGame->gMutex.Lock();
......@@ -309,6 +135,7 @@ void ReplayMode::EndDuel() {
mainGame->gMutex.Lock();
mainGame->dInfo.isStarted = false;
mainGame->dInfo.isReplay = false;
mainGame->dInfo.isOldReplay = false;
mainGame->gMutex.Unlock();
mainGame->closeDoneSignal.Reset();
mainGame->closeSignal.Set();
......@@ -323,21 +150,21 @@ void ReplayMode::EndDuel() {
}
}
void ReplayMode::Restart(bool refresh) {
end_duel(pduel);
if(yrp) {
end_duel(pduel);
cur_replay.Rewind();
}
mainGame->dInfo.isStarted = false;
mainGame->dInfo.turn = 0;
mainGame->dField.Clear();
//mainGame->device->setEventReceiver(&mainGame->dField);
cur_replay.Rewind();
//mainGame->dInfo.isFirst = true;
mainGame->dInfo.tag_player[0] = false;
mainGame->dInfo.tag_player[1] = false;
if(!StartDuel()) {
if (yrp && !StartDuel()) {
EndDuel();
}
if(refresh) {
mainGame->dField.RefreshAllCards();
mainGame->dInfo.isStarted = true;
//mainGame->dInfo.isReplay = true;
}
skip_turn = 0;
is_restarting = true;
......@@ -350,26 +177,21 @@ void ReplayMode::Undo() {
mainGame->gMutex.Lock();
Pause(false, false);
}
bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) {
char* pbuf = msg;
int player, count;
bool ReplayMode::ReplayAnalyze(ReplayPacket p) {
is_restarting = false;
while (pbuf - msg < (int)len) {
while(true) {
if(is_closing)
return false;
if(is_restarting) {
//is_restarting = false;
return true;
}
if(is_swaping) {
if(is_restarting)
break;
if(is_swapping) {
mainGame->gMutex.Lock();
mainGame->dField.ReplaySwap();
mainGame->gMutex.Unlock();
is_swaping = false;
is_swapping = false;
}
char* offset = pbuf;
bool pauseable = true;
mainGame->dInfo.curMsg = BufferIO::ReadUInt8(pbuf);
mainGame->dInfo.curMsg = p.message;
switch (mainGame->dInfo.curMsg) {
case MSG_RETRY: {
if(mainGame->dInfo.isReplaySkiping) {
......@@ -385,188 +207,40 @@ bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) {
mainGame->actionSignal.Wait();
return false;
}
case MSG_HINT: {
pbuf += (mainGame->dInfo.lua64) ? 10 : 6;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_WIN: {
if(mainGame->dInfo.isReplaySkiping) {
if (mainGame->dInfo.isReplaySkiping) {
mainGame->dInfo.isReplaySkiping = false;
mainGame->dField.RefreshAllCards();
mainGame->gMutex.Unlock();
}
pbuf += 2;
DuelClient::ClientAnalyze(offset, pbuf - offset);
DuelClient::ClientAnalyze((char*)p.data, p.length);
return false;
}
case MSG_SELECT_BATTLECMD: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * (mainGame->dInfo.lua64) ? 15 : 11;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8 + 2;
ReplayRefresh();
return ReadReplayResponse();
}
case MSG_SELECT_IDLECMD: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * (mainGame->dInfo.lua64) ? 15 : 11 + 3;
ReplayRefresh();
return ReadReplayResponse();
}
case MSG_SELECT_EFFECTYN: {
player = BufferIO::ReadInt8(pbuf);
pbuf += (mainGame->dInfo.lua64) ? 16 : 12;
return ReadReplayResponse();
}
case MSG_SELECT_YESNO: {
player = BufferIO::ReadInt8(pbuf);
pbuf += (mainGame->dInfo.lua64) ? 8 : 4;
return ReadReplayResponse();
}
case MSG_SELECT_OPTION: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * (mainGame->dInfo.lua64) ? 8 : 4;
return ReadReplayResponse();
}
case MSG_SELECT_CARD:
case MSG_SELECT_TRIBUTE: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 3;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8;
return ReadReplayResponse();
}
case MSG_SELECT_UNSELECT_CARD: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 4;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8;
return ReadReplayResponse();
}
case MSG_SELECT_CHAIN: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += 10 + count * (mainGame->dInfo.lua64) ? 17 : 13;
return ReadReplayResponse();
}
case MSG_SELECT_PLACE:
case MSG_SELECT_DISFIELD: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 5;
return ReadReplayResponse();
}
case MSG_SELECT_POSITION: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 5;
return ReadReplayResponse();
}
case MSG_SELECT_COUNTER: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 4;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 9;
return ReadReplayResponse();
}
case MSG_SELECT_SUM: {
pbuf++;
player = BufferIO::ReadInt8(pbuf);
pbuf += 6;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 11;
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 11;
return ReadReplayResponse();
}
case MSG_SORT_CARD:
case MSG_SORT_CHAIN: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
return ReadReplayResponse();
}
case MSG_CONFIRM_DECKTOP: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CONFIRM_EXTRATOP: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CONFIRM_CARDS: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SHUFFLE_DECK: {
player = BufferIO::ReadInt8(pbuf);
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefreshDeck(player);
break;
}
case MSG_SHUFFLE_HAND: {
/*int oplayer = */BufferIO::ReadInt8(pbuf);
int count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SHUFFLE_EXTRA: {
/*int oplayer = */BufferIO::ReadInt8(pbuf);
int count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_REFRESH_DECK: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SWAP_GRAVE_DECK: {
player = BufferIO::ReadInt8(pbuf);
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefreshGrave(player);
break;
}
case MSG_REVERSE_DECK: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefreshDeck(0);
ReplayRefreshDeck(1);
break;
}
case MSG_DECK_TOP: {
pbuf += 6;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SHUFFLE_SET_CARD: {
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
case MSG_START:
case MSG_UPDATE_DATA:
case MSG_UPDATE_CARD:
case MSG_SET:
case MSG_SWAP:
case MSG_FIELD_DISABLED:
case MSG_SUMMONING:
case MSG_SPSUMMONING:
case MSG_FLIPSUMMONING:
case MSG_CHAIN_SOLVING:
case MSG_CHAIN_SOLVED:
case MSG_CHAIN_END:
case MSG_CARD_SELECTED:
case MSG_RANDOM_SELECTED:
case MSG_EQUIP:
case MSG_UNEQUIP:
case MSG_CARD_TARGET:
case MSG_CANCEL_TARGET:
case MSG_BATTLE:
case MSG_ATTACK_DISABLED:
case MSG_DAMAGE_STEP_START:
case MSG_DAMAGE_STEP_END:
case MSG_TAG_SWAP:
case MSG_RELOAD_FIELD: {
pauseable = false;
break;
}
case MSG_NEW_TURN: {
......@@ -578,335 +252,24 @@ bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) {
mainGame->gMutex.Unlock();
}
}
player = BufferIO::ReadInt8(pbuf);
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_NEW_PHASE: {
pbuf += 2;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_MOVE: {
int pc = pbuf[4];
int pl = pbuf[5];
/*int ps = pbuf[6];*/
/*int pp = pbuf[7];*/
int cc = pbuf[8];
int cl = pbuf[9];
int cs = pbuf[10];
/*int cp = pbuf[11];*/
pbuf += 16;
DuelClient::ClientAnalyze(offset, pbuf - offset);
if(cl && !(cl & 0x80) && (pl != cl || pc != cc))
ReplayRefreshSingle(cc, cl, cs);
break;
}
case MSG_POS_CHANGE: {
pbuf += 9;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_SET: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_SWAP: {
pbuf += 16;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_FIELD_DISABLED: {
pbuf += 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_SUMMONING: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_SUMMONED: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_SPSUMMONING: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_SPSUMMONED: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_FLIPSUMMONING: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_FLIPSUMMONED: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_CHAINING: {
pbuf += (mainGame->dInfo.lua64) ? 20 : 16;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CHAINED: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
break;
}
case MSG_CHAIN_SOLVING: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_CHAIN_SOLVED: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
pauseable = false;
break;
}
case MSG_CHAIN_END: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
pauseable = false;
break;
}
case MSG_CHAIN_NEGATED: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CHAIN_DISABLED: {
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_CARD_SELECTED:
case MSG_RANDOM_SELECTED: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_BECOME_TARGET: {
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_DRAW: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count * 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_DAMAGE: {
pbuf += 5;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_RECOVER: {
pbuf += 5;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_EQUIP: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_LPUPDATE: {
pbuf += 5;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_UNEQUIP: {
pbuf += 4;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_CARD_TARGET: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_CANCEL_TARGET: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_PAY_LPCOST: {
pbuf += 5;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_ADD_COUNTER: {
pbuf += 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_REMOVE_COUNTER: {
pbuf += 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_ATTACK: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_BATTLE: {
pbuf += 26;
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_ATTACK_DISABLED: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
pauseable = false;
break;
}
case MSG_DAMAGE_STEP_START: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
pauseable = false;
break;
}
case MSG_DAMAGE_STEP_END: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefresh();
pauseable = false;
break;
}
case MSG_MISSED_EFFECT: {
pbuf += 8;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_TOSS_COIN: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_TOSS_DICE: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += count;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_ROCK_PAPER_SCISSORS: {
player = BufferIO::ReadInt8(pbuf);
return ReadReplayResponse();
}
case MSG_HAND_RES: {
pbuf += 1;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_ANNOUNCE_RACE: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 5;
return ReadReplayResponse();
}
case MSG_ANNOUNCE_ATTRIB: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 5;
return ReadReplayResponse();
}
case MSG_ANNOUNCE_CARD: {
player = BufferIO::ReadInt8(pbuf);
pbuf += 4;
return ReadReplayResponse();
}
case MSG_ANNOUNCE_NUMBER:
case MSG_ANNOUNCE_CARD_FILTER: {
player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadInt8(pbuf);
pbuf += (mainGame->dInfo.lua64) ? 8 : 4 * count;
return ReadReplayResponse();
}
case MSG_CARD_HINT: {
pbuf += (mainGame->dInfo.lua64) ? 13 : 9;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_PLAYER_HINT: {
pbuf += (mainGame->dInfo.lua64) ? 10 : 6;
DuelClient::ClientAnalyze(offset, pbuf - offset);
break;
}
case MSG_MATCH_KILL: {
pbuf += 4;
break;
}
case MSG_TAG_SWAP: {
player = pbuf[0];
pbuf += pbuf[2] * 4 + pbuf[4] * 4 + 9;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayRefreshDeck(player);
ReplayRefreshExtra(player);
break;
}
case MSG_RELOAD_FIELD: {
pbuf++;
for(int p = 0; p < 2; ++p) {
pbuf += 4;
for(int seq = 0; seq < 7; ++seq) {
int val = BufferIO::ReadInt8(pbuf);
if(val)
pbuf += 2;
}
for(int seq = 0; seq < 8; ++seq) {
int val = BufferIO::ReadInt8(pbuf);
if(val)
pbuf++;
}
pbuf += 6;
}
pbuf++;
DuelClient::ClientAnalyze(offset, pbuf - offset);
ReplayReload();
mainGame->dField.RefreshAllCards();
break;
}
case MSG_AI_NAME: {
char* pbuf =(char*) p.data;
char namebuf[128];
wchar_t wname[128];
int len = BufferIO::ReadInt16(pbuf);
char* begin = pbuf;
pbuf += len + 1;
break;
}
case MSG_SHOW_HINT: {
int len = BufferIO::ReadInt16(pbuf);
pbuf += len + 1;
break;
memcpy(namebuf, begin, len + 1);
BufferIO::DecodeUTF8(namebuf, wname);
BufferIO::CopyWStr(wname, mainGame->dInfo.clientname, 20);
return true;
}
case OLD_REPLAY_MODE:
return true;
}
DuelClient::ClientAnalyze((char*)p.data, p.length);
if(pauseable) {
current_step++;
if(skip_step) {
......@@ -926,88 +289,9 @@ bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) {
is_paused = false;
}
}
break;
}
return true;
}
void ReplayMode::ReplayRefresh(int flag) {
unsigned char queryBuffer[0x4000];
/*int len = */query_field_card(pduel, 0, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_HAND, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshHand(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_HAND, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshGrave(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_GRAVE, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshDeck(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_DECK, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshExtra(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_EXTRA, (char*)queryBuffer);
}
void ReplayMode::ReplayRefreshSingle(int player, int location, int sequence, int flag) {
unsigned char queryBuffer[0x4000];
/*int len = */query_card(pduel, player, location, sequence, flag, queryBuffer, 0);
mainGame->dField.UpdateCard(mainGame->LocalPlayer(player), location, sequence, (char*)queryBuffer);
}
void ReplayMode::ReplayReload() {
unsigned char queryBuffer[0x4000];
unsigned int flag = 0xffdfff;
/*int len = */query_field_card(pduel, 0, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_DECK, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_DECK, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_EXTRA, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_EXTRA, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_GRAVE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_GRAVE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_REMOVED, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_REMOVED, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_REMOVED, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_REMOVED, (char*)queryBuffer);
}
int ReplayMode::MessageHandler(long fduel, int type) {
if(!enable_log)
return 0;
char msgbuf[1024];
get_log_message(fduel, (byte*)msgbuf);
mainGame->AddDebugMsg(msgbuf);
return 0;
}
}
......@@ -12,12 +12,14 @@ namespace ygo {
class ReplayMode {
private:
static long pduel;
static bool yrp;
static bool is_continuing;
static bool is_closing;
static bool is_pausing;
static bool is_paused;
static bool is_swaping;
static bool is_swapping;
static bool is_restarting;
static bool undo;
static bool exit_pending;
static int skip_turn;
static int current_step;
......@@ -25,6 +27,7 @@ private:
public:
static Replay cur_replay;
static std::vector<ReplayPacket> ReplayMode::current_stream;
public:
static bool StartReplay(int skipturn);
......@@ -33,12 +36,14 @@ public:
static void Pause(bool is_pause, bool is_step);
static bool ReadReplayResponse();
static int ReplayThread(void* param);
static int OldReplayThread(void* param);
static bool StartDuel();
static void EndDuel();
static void Restart(bool refresh);
static void Undo();
static bool ReplayAnalyze(ReplayPacket p);
static bool ReplayAnalyze(char* msg, unsigned int len);
static void ReplayRefresh(int flag = 0xf81fff);
static void ReplayRefreshHand(int player, int flag = 0x781fff);
static void ReplayRefreshGrave(int player, int flag = 0x181fff);
......
......@@ -9,6 +9,8 @@
namespace ygo {
std::vector<ReplayPacket> SingleDuel::replay_stream;
SingleDuel::SingleDuel(bool is_match) {
game_started = false;
match_mode = is_match;
......@@ -187,6 +189,8 @@ void SingleDuel::LeaveGame(DuelPlayer* dp) {
NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
ReplayPacket p((char*)wbuf, 3);
replay_stream.push_back(p);
EndDuel();
NetServer::SendPacketToPlayer(players[0], STOC_DUEL_END);
NetServer::ReSendToPlayer(players[1]);
......@@ -398,11 +402,19 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
rh.flag = REPLAY_LUA64;
time_t seed = time(0);
rh.seed = seed;
last_replay.BeginRecord();
last_replay.BeginRecord(false);
last_replay.WriteHeader(rh);
rnd.reset(seed);
last_replay.WriteData(players[0]->name, 40, false);
last_replay.WriteData(players[1]->name, 40, false);
//records the replay with the new system
new_replay.BeginRecord();
rh.id = 0x58707279;
rh.flag |= REPLAY_NEWREPLAY;
new_replay.WriteHeader(rh);
new_replay.WriteData(players[0]->name, 40, false);
new_replay.WriteData(players[1]->name, 40);
replay_stream.clear();
if(!host_info.no_shuffle_deck) {
for(size_t i = pdeck[0].main.size() - 1; i > 0; --i) {
int swap = rnd.real() * (i + 1);
......@@ -427,6 +439,7 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
opt |= DUEL_PSEUDO_SHUFFLE;
if(host_info.speed)
opt |= SPEED_DUEL;
new_replay.WriteInt32((mainGame->GetMasterRule(opt, 0)) | (opt & SPEED_DUEL) << 8);
last_replay.WriteInt32(host_info.start_lp, false);
last_replay.WriteInt32(host_info.start_hand, false);
last_replay.WriteInt32(host_info.draw_count, false);
......@@ -518,8 +531,14 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
else startbuf[1] = 0x11;
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::SendBufferToPlayer(*oit, STOC_GAME_MSG, startbuf, 18);
startbuf[1] = 0;
ReplayPacket p((char*)startbuf, 17);
replay_stream.push_back(p);
PseudoRefreshDeck(0);
PseudoRefreshDeck(1);
RefreshExtra(0);
RefreshExtra(1);
new_replay.WriteStream(replay_stream);
start_duel(pduel, opt);
Process();
}
......@@ -594,6 +613,8 @@ void SingleDuel::Surrender(DuelPlayer* dp) {
NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
ReplayPacket p((char*)wbuf, 3);
replay_stream.push_back(p);
if(players[player] == pplayer[player]) {
match_result[duel_count++] = 1 - player;
tp_player = player;
......@@ -609,12 +630,19 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
char* offset, *pbufw, *pbuf = msgbuffer;
int player, count, type;
while (pbuf - msgbuffer < (int)len) {
replay_stream.clear();
bool record = true;
ReplayPacket p;
offset = pbuf;
unsigned char engType = BufferIO::ReadUInt8(pbuf);
p.message = engType;
p.length = len - 1;
memcpy(p.data, pbuf, p.length);
switch (engType) {
case MSG_RETRY: {
WaitforResponse(last_response);
NetServer::SendBufferToPlayer(players[last_response], STOC_GAME_MSG, offset, pbuf - offset);
replay_stream.push_back(p);
return 1;
}
case MSG_HINT: {
......@@ -627,6 +655,7 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
case 3:
case 5: {
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, offset, pbuf - offset);
record = false;
break;
}
case 4:
......@@ -666,6 +695,7 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
match_result[duel_count++] = 1 - player;
tp_player = player;
}
replay_stream.push_back(p);
EndDuel();
return 2;
}
......@@ -872,6 +902,7 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
PseudoRefreshDeck(player);
break;
}
case MSG_SHUFFLE_HAND: {
......@@ -920,6 +951,8 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
PseudoRefreshDeck(0);
PseudoRefreshDeck(1);
break;
}
case MSG_DECK_TOP: {
......@@ -1432,6 +1465,12 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
break;
}
}
//setting the length again in case of multiple messages in a row,
//when the packet will be written in the replay, the extra data registered previously will be discarded
p.length = (pbuf - offset) - 1;
if (record)
replay_stream.insert(replay_stream.begin(), p);
new_replay.WriteStream(replay_stream);
}
return 0;
}
......@@ -1453,11 +1492,28 @@ void SingleDuel::GetResponse(DuelPlayer* dp, void* pdata, unsigned int len) {
void SingleDuel::EndDuel() {
if(!pduel)
return;
last_replay.EndRecord();
last_replay.EndRecord(0x1000);
char replaybuf[0x2000], *pbuf = replaybuf;
memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader));
pbuf += sizeof(ReplayHeader);
memcpy(pbuf, last_replay.comp_data, last_replay.comp_size);
replay_stream.push_back(ReplayPacket(OLD_REPLAY_MODE, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size));
//in case of remaining packets, e.g. MSG_WIN
new_replay.WriteStream(replay_stream);
new_replay.EndRecord();
char nreplaybuf[0x2000], *npbuf = nreplaybuf;
memcpy(npbuf, &new_replay.pheader, sizeof(ReplayHeader));
npbuf += sizeof(ReplayHeader);
memcpy(npbuf, new_replay.comp_data, new_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_NEW_REPLAY, nreplaybuf, sizeof(ReplayHeader) + new_replay.comp_size);
NetServer::ReSendToPlayer(players[1]);
for (auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size);
NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
......@@ -1497,8 +1553,10 @@ void SingleDuel::RefreshMzone(int player, int flag, int use_cache) {
BufferIO::WriteInt8(qbuf, LOCATION_MZONE);
int len = query_field_card(pduel, player, LOCATION_MZONE, flag, (unsigned char*)qbuf, use_cache);
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, query_buffer, len + 3);
ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
int qlen = 0;
while(qlen < len) {
while (qlen < len) {
int clen = BufferIO::ReadInt32(qbuf);
qlen += clen;
if (clen == 4)
......@@ -1519,8 +1577,10 @@ void SingleDuel::RefreshSzone(int player, int flag, int use_cache) {
BufferIO::WriteInt8(qbuf, LOCATION_SZONE);
int len = query_field_card(pduel, player, LOCATION_SZONE, flag, (unsigned char*)qbuf, use_cache);
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, query_buffer, len + 3);
ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
int qlen = 0;
while(qlen < len) {
while (qlen < len) {
int clen = BufferIO::ReadInt32(qbuf);
qlen += clen;
if (clen == 4)
......@@ -1558,6 +1618,8 @@ void SingleDuel::RefreshHand(int player, int flag, int use_cache) {
NetServer::SendBufferToPlayer(players[1 - player], STOC_GAME_MSG, query_buffer, len + 3);
for(auto pit = observers.begin(); pit != observers.end(); ++pit)
NetServer::ReSendToPlayer(*pit);
ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
void SingleDuel::RefreshGrave(int player, int flag, int use_cache) {
char query_buffer[0x2000];
......@@ -1570,6 +1632,8 @@ void SingleDuel::RefreshGrave(int player, int flag, int use_cache) {
NetServer::ReSendToPlayer(players[1]);
for(auto pit = observers.begin(); pit != observers.end(); ++pit)
NetServer::ReSendToPlayer(*pit);
ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
void SingleDuel::RefreshExtra(int player, int flag, int use_cache) {
char query_buffer[0x2000];
......@@ -1579,6 +1643,8 @@ void SingleDuel::RefreshExtra(int player, int flag, int use_cache) {
BufferIO::WriteInt8(qbuf, LOCATION_EXTRA);
int len = query_field_card(pduel, player, LOCATION_EXTRA, flag, (unsigned char*)qbuf, use_cache);
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, query_buffer, len + 3);
ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
void SingleDuel::RefreshSingle(int player, int location, int sequence, int flag) {
char query_buffer[0x2000];
......@@ -1589,6 +1655,8 @@ void SingleDuel::RefreshSingle(int player, int location, int sequence, int flag)
BufferIO::WriteInt8(qbuf, sequence);
int len = query_card(pduel, player, location, sequence, flag, (unsigned char*)qbuf, 0);
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, query_buffer, len + 4);
ReplayPacket p((char*)query_buffer, len + 3);
replay_stream.push_back(p);
if(location == LOCATION_REMOVED && (qbuf[15] & POS_FACEDOWN))
return;
if ((location & 0x90) || ((location & 0x2c) && (qbuf[15] & POS_FACEUP))) {
......@@ -1597,6 +1665,16 @@ void SingleDuel::RefreshSingle(int player, int location, int sequence, int flag)
NetServer::ReSendToPlayer(*pit);
}
}
void SingleDuel::PseudoRefreshDeck(int player, int flag) {
char query_buffer[0x2000];
char* qbuf = query_buffer;
BufferIO::WriteInt8(qbuf, MSG_UPDATE_DATA);
BufferIO::WriteInt8(qbuf, player);
BufferIO::WriteInt8(qbuf, LOCATION_DECK);
int len = query_field_card(pduel, player, LOCATION_DECK, flag, (unsigned char*)qbuf, 0);
ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
int SingleDuel::MessageHandler(long fduel, int type) {
if(!enable_log)
return 0;
......@@ -1618,6 +1696,8 @@ void SingleDuel::SingleTimer(evutil_socket_t fd, short events, void* arg) {
NetServer::ReSendToPlayer(sd->players[1]);
for(auto oit = sd->observers.begin(); oit != sd->observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
ReplayPacket p((char*)wbuf, 3);
sd->replay_stream.push_back(p);
if(sd->players[player] == sd->pplayer[player]) {
sd->match_result[sd->duel_count++] = 1 - player;
sd->tp_player = player;
......
......@@ -40,6 +40,9 @@ public:
static int MessageHandler(long fduel, int type);
static void SingleTimer(evutil_socket_t fd, short events, void* arg);
void PseudoRefreshDeck(int player, int flag = 0x181fff);
static std::vector<ReplayPacket> replay_stream;
protected:
DuelPlayer* players[2];
......@@ -51,6 +54,7 @@ protected:
unsigned char last_response;
std::set<DuelPlayer*> observers;
Replay last_replay;
Replay new_replay;
bool match_mode;
int match_kill;
bool game_started;
......
......@@ -11,6 +11,8 @@ long SingleMode::pduel = 0;
bool SingleMode::is_closing = false;
bool SingleMode::is_continuing = false;
Replay SingleMode::last_replay;
Replay SingleMode::new_replay;
std::vector<ReplayPacket> SingleMode::replay_stream;
static byte buffer[0x20000];
......@@ -106,16 +108,21 @@ int SingleMode::SinglePlayThread(void* param) {
char engineBuffer[0x1000];
is_closing = false;
is_continuing = true;
int len = get_message(pduel, (byte*)engineBuffer);
if (len > 0)
is_continuing = SinglePlayAnalyze(engineBuffer, len);
last_replay.BeginRecord();
last_replay.BeginRecord(false);
last_replay.WriteHeader(rh);
//records the replay with the new system
new_replay.BeginRecord();
rh.id = 0x58707279;
rh.flag |= REPLAY_NEWREPLAY;
new_replay.WriteHeader(rh);
replay_stream.clear();
unsigned short buffer[20];
BufferIO::CopyWStr(mainGame->dInfo.hostname, buffer, 20);
last_replay.WriteData(buffer, 40, false);
new_replay.WriteData(buffer, 40, false);
BufferIO::CopyWStr(mainGame->dInfo.clientname, buffer, 20);
last_replay.WriteData(buffer, 40, false);
new_replay.WriteData(buffer, 40, false);
last_replay.WriteInt32(start_lp, false);
last_replay.WriteInt32(start_hand, false);
last_replay.WriteInt32(draw_count, false);
......@@ -123,6 +130,11 @@ int SingleMode::SinglePlayThread(void* param) {
last_replay.WriteInt16(slen, false);
last_replay.WriteData(filename, slen, false);
last_replay.Flush();
new_replay.WriteInt32((mainGame->GetMasterRule(opt, 0)) | (opt & SPEED_DUEL) << 8);
int len = get_message(pduel, (byte*)engineBuffer);
if (len > 0){
is_continuing = SinglePlayAnalyze(engineBuffer, len);
}
start_duel(pduel, opt);
while (is_continuing) {
int result = process(pduel);
......@@ -133,7 +145,15 @@ int SingleMode::SinglePlayThread(void* param) {
is_continuing = SinglePlayAnalyze(engineBuffer, len);
}
}
last_replay.EndRecord();
last_replay.EndRecord(0x1000);
char replaybuf[0x2000], *pbuf = replaybuf;
memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader));
pbuf += sizeof(ReplayHeader);
memcpy(pbuf, last_replay.comp_data, last_replay.comp_size);
new_replay.WritePacket(ReplayPacket(OLD_REPLAY_MODE, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size));
new_replay.EndRecord();
time_t nowtime = time(NULL);
struct tm *localedtime = localtime(&nowtime);
char timebuf[40];
......@@ -146,8 +166,8 @@ int SingleMode::SinglePlayThread(void* param) {
mainGame->gMutex.Unlock();
mainGame->replaySignal.Reset();
mainGame->replaySignal.Wait();
if(mainGame->actionParam)
last_replay.SaveReplay(mainGame->ebRSName->getText());
if(mainGame->saveReplay)
new_replay.SaveReplay(mainGame->ebRSName->getText());
end_duel(pduel);
if(!is_closing) {
mainGame->gMutex.Lock();
......@@ -171,10 +191,16 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
char* offset, *pbuf = msg;
int player, count;
while (pbuf - msg < (int)len) {
replay_stream.clear();
bool record = true;
if(is_closing || !is_continuing)
return false;
offset = pbuf;
ReplayPacket p;
mainGame->dInfo.curMsg = BufferIO::ReadUInt8(pbuf);
p.message = mainGame->dInfo.curMsg;
p.length = len - 1;
memcpy(p.data, pbuf, p.length);
switch (mainGame->dInfo.curMsg) {
case MSG_RETRY: {
mainGame->gMutex.Lock();
......@@ -186,16 +212,19 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
return false;
}
case MSG_HINT: {
/*int type = */BufferIO::ReadInt8(pbuf);
int type = BufferIO::ReadInt8(pbuf);
int player = BufferIO::ReadInt8(pbuf);
/*int data = */BufferIO::ReadInt64(pbuf);
if(player == 0)
DuelClient::ClientAnalyze(offset, pbuf - offset);
if (type > 0 && type < 6 && type != 4)
record = false;
break;
}
case MSG_WIN: {
pbuf += 2;
DuelClient::ClientAnalyze(offset, pbuf - offset);
replay_stream.push_back(p);
return false;
}
case MSG_SELECT_BATTLECMD: {
......@@ -209,6 +238,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_IDLECMD: {
......@@ -230,6 +260,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_EFFECTYN: {
......@@ -240,6 +271,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_YESNO: {
......@@ -249,6 +281,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_OPTION: {
......@@ -259,6 +292,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_CARD:
......@@ -271,6 +305,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_UNSELECT_CARD: {
......@@ -284,6 +319,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_CHAIN: {
......@@ -294,6 +330,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_PLACE:
......@@ -304,6 +341,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_POSITION: {
......@@ -313,6 +351,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_COUNTER: {
......@@ -324,6 +363,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SELECT_SUM: {
......@@ -338,6 +378,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_SORT_CARD:
......@@ -349,6 +390,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_CONFIRM_DECKTOP: {
......@@ -375,7 +417,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
case MSG_SHUFFLE_DECK: {
player = BufferIO::ReadInt8(pbuf);
DuelClient::ClientAnalyze(offset, pbuf - offset);
SinglePlayRefreshDeck(player);
SinglePlayRefresh(player, LOCATION_DECK, 0x181fff);
break;
}
case MSG_SHUFFLE_HAND: {
......@@ -400,13 +442,13 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
case MSG_SWAP_GRAVE_DECK: {
player = BufferIO::ReadInt8(pbuf);
DuelClient::ClientAnalyze(offset, pbuf - offset);
SinglePlayRefreshGrave(player);
SinglePlayRefresh(player, LOCATION_GRAVE, 0x181fff);
break;
}
case MSG_REVERSE_DECK: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
SinglePlayRefreshDeck(0);
SinglePlayRefreshDeck(1);
SinglePlayRefresh(0, LOCATION_DECK, 0x181fff);
SinglePlayRefresh(1, LOCATION_DECK, 0x181fff);
break;
}
case MSG_DECK_TOP: {
......@@ -521,8 +563,8 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
case MSG_CHAIN_END: {
DuelClient::ClientAnalyze(offset, pbuf - offset);
SinglePlayRefresh();
SinglePlayRefreshDeck(0);
SinglePlayRefreshDeck(1);
SinglePlayRefresh(0, LOCATION_DECK, 0x181fff);
SinglePlayRefresh(1, LOCATION_DECK, 0x181fff);
break;
}
case MSG_CHAIN_NEGATED: {
......@@ -655,6 +697,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_HAND_RES: {
......@@ -669,6 +712,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_ANNOUNCE_ATTRIB: {
......@@ -678,6 +722,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_ANNOUNCE_CARD: {
......@@ -687,6 +732,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_ANNOUNCE_NUMBER:
......@@ -698,6 +744,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
record = false;
break;
}
case MSG_CARD_HINT: {
......@@ -714,8 +761,8 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
player = pbuf[0];
pbuf += pbuf[2] * 4 + pbuf[4] * 4 + 9;
DuelClient::ClientAnalyze(offset, pbuf - offset);
SinglePlayRefreshDeck(player);
SinglePlayRefreshExtra(player);
SinglePlayRefresh(player, LOCATION_DECK, 0x181fff);
SinglePlayRefresh(player, LOCATION_EXTRA, 0x181fff);
break;
}
case MSG_MATCH_KILL: {
......@@ -728,43 +775,6 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
int rule = BufferIO::ReadInt8(pbuf);
mainGame->dInfo.duel_field = rule & 0xf;
mainGame->dInfo.extraval = rule >> 4;
// reset master rule 4 phase button position
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 310, 855, 330));
if(mainGame->dInfo.extraval) {
if(mainGame->dInfo.duel_field >= 4) {
mainGame->wPhase->setRelativePosition(mainGame->Resize(480, 290, 855, 350));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 40, 50, 60));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 20, 210, 40));
mainGame->btnEP->setRelativePosition(mainGame->Resize(310, 0, 360, 20));
} else {
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnDP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
mainGame->btnEP->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
} else {
mainGame->btnDP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
if(mainGame->dInfo.duel_field >= 4) {
mainGame->btnSP->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(160, 0, 210, 20));
} else {
mainGame->btnSP->setRelativePosition(mainGame->Resize(65, 0, 115, 20));
mainGame->btnM1->setRelativePosition(mainGame->Resize(130, 0, 180, 20));
mainGame->btnBP->setRelativePosition(mainGame->Resize(195, 0, 245, 20));
mainGame->btnM2->setRelativePosition(mainGame->Resize(260, 0, 310, 20));
}
mainGame->btnEP->setRelativePosition(mainGame->Resize(320, 0, 370, 20));
mainGame->btnShuffle->setRelativePosition(mainGame->Resize(0, 0, 50, 20));
}
int val = 0;
for(int p = 0; p < 2; ++p) {
mainGame->dInfo.lp[p] = BufferIO::ReadInt32(pbuf);
......@@ -858,80 +868,64 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
break;
}
}
//setting the length again in case of multiple messages in a row,
//when the packet will be written in the replay, the extra data registered previously will be discarded
p.length = (pbuf - offset) - 1;
if (record)
replay_stream.insert(replay_stream.begin(), p);
new_replay.WriteStream(replay_stream);
}
return is_continuing;
}
void SingleMode::SinglePlayRefresh(int flag) {
void SingleMode::SinglePlayRefresh(int player, int location, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, 0, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_HAND, (char*)queryBuffer);
}
void SingleMode::SinglePlayRefreshHand(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_HAND, (char*)queryBuffer);
}
void SingleMode::SinglePlayRefreshGrave(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_GRAVE, (char*)queryBuffer);
}
void SingleMode::SinglePlayRefreshDeck(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_DECK, (char*)queryBuffer);
}
void SingleMode::SinglePlayRefreshExtra(int player, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_field_card(pduel, player, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), LOCATION_EXTRA, (char*)queryBuffer);
char queryBuffer2[0x2000];
char* qbuf = queryBuffer2;
ReplayPacket p;
int len = query_field_card(pduel, player, location, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(player), location, (char*)queryBuffer);
BufferIO::WriteInt8(qbuf, player);
BufferIO::WriteInt8(qbuf, location);
memcpy(qbuf, (char*)queryBuffer, len);
replay_stream.push_back(ReplayPacket(MSG_UPDATE_DATA, queryBuffer2, len + 2));
}
void SingleMode::SinglePlayRefreshSingle(int player, int location, int sequence, int flag) {
unsigned char queryBuffer[0x2000];
/*int len = */query_card(pduel, player, location, sequence, flag, queryBuffer, 0);
char queryBuffer2[0x2000];
char* qbuf = queryBuffer2;
int len = query_card(pduel, player, location, sequence, flag, queryBuffer, 0);
mainGame->dField.UpdateCard(mainGame->LocalPlayer(player), location, sequence, (char*)queryBuffer);
BufferIO::WriteInt8(qbuf, player);
BufferIO::WriteInt8(qbuf, location);
BufferIO::WriteInt8(qbuf, sequence);
memcpy(qbuf, (char*)queryBuffer, len);
ReplayPacket p(MSG_UPDATE_CARD, queryBuffer2, len + 3);
replay_stream.push_back(p);
}
void SingleMode::SinglePlayRefresh(int flag) {
SinglePlayRefresh(0, LOCATION_MZONE, flag);
SinglePlayRefresh(1, LOCATION_MZONE, flag);
SinglePlayRefresh(0, LOCATION_SZONE, flag);
SinglePlayRefresh(1, LOCATION_SZONE, flag);
SinglePlayRefresh(0, LOCATION_HAND, flag);
SinglePlayRefresh(1, LOCATION_HAND, flag);
}
void SingleMode::SinglePlayReload() {
unsigned char queryBuffer[0x2000];
unsigned int flag = 0xffdfff;
/*int len = */query_field_card(pduel, 0, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_MZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_MZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_SZONE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_SZONE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_HAND, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_HAND, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_DECK, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_DECK, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_DECK, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_EXTRA, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_EXTRA, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_EXTRA, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_GRAVE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_GRAVE, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_GRAVE, (char*)queryBuffer);
/*len = */query_field_card(pduel, 0, LOCATION_REMOVED, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(0), LOCATION_REMOVED, (char*)queryBuffer);
/*len = */query_field_card(pduel, 1, LOCATION_REMOVED, flag, queryBuffer, 0);
mainGame->dField.UpdateFieldCard(mainGame->LocalPlayer(1), LOCATION_REMOVED, (char*)queryBuffer);
SinglePlayRefresh(0, LOCATION_MZONE, flag);
SinglePlayRefresh(1, LOCATION_MZONE, flag);
SinglePlayRefresh(0, LOCATION_SZONE, flag);
SinglePlayRefresh(1, LOCATION_SZONE, flag);
SinglePlayRefresh(0, LOCATION_HAND, flag);
SinglePlayRefresh(1, LOCATION_HAND, flag);
SinglePlayRefresh(0, LOCATION_DECK, flag);
SinglePlayRefresh(1, LOCATION_DECK, flag);
SinglePlayRefresh(0, LOCATION_EXTRA, flag);
SinglePlayRefresh(1, LOCATION_EXTRA, flag);
SinglePlayRefresh(0, LOCATION_GRAVE, flag);
SinglePlayRefresh(1, LOCATION_GRAVE, flag);
SinglePlayRefresh(0, LOCATION_REMOVED, flag);
SinglePlayRefresh(1, LOCATION_REMOVED, flag);
}
byte* SingleMode::ScriptReader(const char* script_name, int* slen) {
FILE *fp;
......@@ -960,4 +954,4 @@ int SingleMode::MessageHandler(long fduel, int type) {
return 0;
}
}
}
\ No newline at end of file
......@@ -18,11 +18,8 @@ public:
static int SinglePlayThread(void* param);
static bool SinglePlayAnalyze(char* msg, unsigned int len);
static void SinglePlayRefresh(int player, int location, int flag = 0xf81fff);
static void SinglePlayRefresh(int flag = 0xf81fff);
static void SinglePlayRefreshHand(int player, int flag = 0x781fff);
static void SinglePlayRefreshGrave(int player, int flag = 0x181fff);
static void SinglePlayRefreshDeck(int player, int flag = 0x181fff);
static void SinglePlayRefreshExtra(int player, int flag = 0x181fff);
static void SinglePlayRefreshSingle(int player, int location, int sequence, int flag = 0xf81fff);
static void SinglePlayReload();
......@@ -31,6 +28,8 @@ public:
protected:
static Replay last_replay;
static Replay new_replay;
static std::vector<ReplayPacket> replay_stream;
};
}
......
......@@ -9,6 +9,8 @@
namespace ygo {
std::vector<ReplayPacket> TagDuel::replay_stream;
TagDuel::TagDuel() {
game_started = false;
for(int i = 0; i < 4; ++i) {
......@@ -355,13 +357,23 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
rh.flag = REPLAY_TAG + REPLAY_LUA64;
time_t seed = time(0);
rh.seed = seed;
last_replay.BeginRecord();
last_replay.BeginRecord(false);
last_replay.WriteHeader(rh);
rnd.reset(seed);
last_replay.WriteData(players[0]->name, 40, false);
last_replay.WriteData(players[1]->name, 40, false);
last_replay.WriteData(players[2]->name, 40, false);
last_replay.WriteData(players[3]->name, 40, false);
//records the replay with the new system
new_replay.BeginRecord();
rh.id = 0x58707279;
rh.flag |= REPLAY_NEWREPLAY;
new_replay.WriteHeader(rh);
new_replay.WriteData(players[0]->name, 40, false);
new_replay.WriteData(players[1]->name, 40, false);
new_replay.WriteData(players[2]->name, 40, false);
new_replay.WriteData(players[3]->name, 40);
replay_stream.clear();
if(!host_info.no_shuffle_deck) {
for(size_t i = pdeck[0].main.size() - 1; i > 0; --i) {
int swap = rnd.real() * (i + 1);
......@@ -395,6 +407,7 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
if(host_info.speed)
opt |= SPEED_DUEL;
opt |= DUEL_TAG_MODE;
new_replay.WriteInt32((mainGame->GetMasterRule(opt, 0)) | (opt & SPEED_DUEL) << 8);
last_replay.WriteInt32(host_info.start_lp, false);
last_replay.WriteInt32(host_info.start_hand, false);
last_replay.WriteInt32(host_info.draw_count, false);
......@@ -519,8 +532,14 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
else startbuf[1] = 0x11;
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::SendBufferToPlayer(*oit, STOC_GAME_MSG, startbuf, 18);
startbuf[1] = 0;
ReplayPacket p((char*)startbuf, 17);
replay_stream.push_back(p);
PseudoRefreshDeck(0);
PseudoRefreshDeck(1);
RefreshExtra(0);
RefreshExtra(1);
new_replay.WriteStream(replay_stream);
start_duel(pduel, opt);
Process();
}
......@@ -558,12 +577,19 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
char* offset, *pbufw, *pbuf = msgbuffer;
int player, count, type;
while (pbuf - msgbuffer < (int)len) {
replay_stream.clear();
bool record = true;
ReplayPacket p;
offset = pbuf;
unsigned char engType = BufferIO::ReadUInt8(pbuf);
p.message = engType;
p.length = len - 1;
memcpy(p.data, pbuf, p.length);
switch (engType) {
case MSG_RETRY: {
WaitforResponse(last_response);
NetServer::SendBufferToPlayer(cur_player[last_response], STOC_GAME_MSG, offset, pbuf - offset);
replay_stream.push_back(p);
return 1;
}
case MSG_HINT: {
......@@ -577,6 +603,7 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
case 5:
case 10: {
NetServer::SendBufferToPlayer(cur_player[player], STOC_GAME_MSG, offset, pbuf - offset);
record = false;
break;
}
case 4:
......@@ -603,6 +630,7 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::ReSendToPlayer(players[3]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
replay_stream.push_back(p);
EndDuel();
return 2;
}
......@@ -817,6 +845,7 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::ReSendToPlayer(players[3]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
PseudoRefreshDeck(player);
break;
}
case MSG_SHUFFLE_HAND: {
......@@ -875,6 +904,8 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::ReSendToPlayer(players[3]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
PseudoRefreshDeck(0);
PseudoRefreshDeck(1);
break;
}
case MSG_DECK_TOP: {
......@@ -1499,6 +1530,7 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::SendBufferToPlayer(players[p], STOC_GAME_MSG, offset, pbuf - offset);
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
PseudoRefreshDeck(player);
RefreshExtra(player);
RefreshMzone(0, 0x81fff, 0);
RefreshMzone(1, 0x81fff, 0);
......@@ -1513,6 +1545,12 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
break;
}
}
//setting the length again in case of multiple messages in a row,
//when the packet will be written in the replay, the extra data registered previously will be discarded
p.length = (pbuf - offset) - 1;
if (record)
replay_stream.insert(replay_stream.begin(), p);
new_replay.WriteStream(replay_stream);
}
return 0;
}
......@@ -1535,11 +1573,29 @@ void TagDuel::GetResponse(DuelPlayer* dp, void* pdata, unsigned int len) {
void TagDuel::EndDuel() {
if(!pduel)
return;
last_replay.EndRecord();
last_replay.EndRecord(0x1000);
char replaybuf[0x2000], *pbuf = replaybuf;
memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader));
pbuf += sizeof(ReplayHeader);
memcpy(pbuf, last_replay.comp_data, last_replay.comp_size);
replay_stream.push_back(ReplayPacket(OLD_REPLAY_MODE, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size));
//in case of remaining packets, e.g. MSG_WIN
new_replay.WriteStream(replay_stream);
new_replay.EndRecord();
char nreplaybuf[0x2000], *npbuf = nreplaybuf;
memcpy(npbuf, &new_replay.pheader, sizeof(ReplayHeader));
npbuf += sizeof(ReplayHeader);
memcpy(npbuf, new_replay.comp_data, new_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_NEW_REPLAY, nreplaybuf, sizeof(ReplayHeader) + new_replay.comp_size);
NetServer::ReSendToPlayer(players[1]);
NetServer::ReSendToPlayer(players[2]);
NetServer::ReSendToPlayer(players[3]);
for (auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size);
NetServer::ReSendToPlayer(players[1]);
NetServer::ReSendToPlayer(players[2]);
......@@ -1586,6 +1642,8 @@ void TagDuel::RefreshMzone(int player, int flag, int use_cache) {
int len = query_field_card(pduel, player, LOCATION_MZONE, flag, (unsigned char*)qbuf, use_cache);
int pid = (player == 0) ? 0 : 2;
NetServer::SendBufferToPlayer(players[pid], STOC_GAME_MSG, query_buffer, len + 3);
ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
NetServer::ReSendToPlayer(players[pid + 1]);
int qlen = 0;
while(qlen < len) {
......@@ -1612,6 +1670,8 @@ void TagDuel::RefreshSzone(int player, int flag, int use_cache) {
int len = query_field_card(pduel, player, LOCATION_SZONE, flag, (unsigned char*)qbuf, use_cache);
int pid = (player == 0) ? 0 : 2;
NetServer::SendBufferToPlayer(players[pid], STOC_GAME_MSG, query_buffer, len + 3);
ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
NetServer::ReSendToPlayer(players[pid + 1]);
int qlen = 0;
while(qlen < len) {
......@@ -1637,6 +1697,8 @@ void TagDuel::RefreshHand(int player, int flag, int use_cache) {
BufferIO::WriteInt8(qbuf, LOCATION_HAND);
int len = query_field_card(pduel, player, LOCATION_HAND, flag | QUERY_IS_PUBLIC, (unsigned char*)qbuf, use_cache);
NetServer::SendBufferToPlayer(cur_player[player], STOC_GAME_MSG, query_buffer, len + 3);
ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
int qlen = 0;
while(qlen < len) {
int slen = BufferIO::ReadInt32(qbuf);
......@@ -1670,6 +1732,8 @@ void TagDuel::RefreshGrave(int player, int flag, int use_cache) {
NetServer::ReSendToPlayer(players[3]);
for(auto pit = observers.begin(); pit != observers.end(); ++pit)
NetServer::ReSendToPlayer(*pit);
ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
void TagDuel::RefreshExtra(int player, int flag, int use_cache) {
char query_buffer[0x2000];
......@@ -1679,6 +1743,8 @@ void TagDuel::RefreshExtra(int player, int flag, int use_cache) {
BufferIO::WriteInt8(qbuf, LOCATION_EXTRA);
int len = query_field_card(pduel, player, LOCATION_EXTRA, flag, (unsigned char*)qbuf, use_cache);
NetServer::SendBufferToPlayer(cur_player[player], STOC_GAME_MSG, query_buffer, len + 3);
ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
void TagDuel::RefreshSingle(int player, int location, int sequence, int flag) {
char query_buffer[0x2000];
......@@ -1688,6 +1754,8 @@ void TagDuel::RefreshSingle(int player, int location, int sequence, int flag) {
BufferIO::WriteInt8(qbuf, location);
BufferIO::WriteInt8(qbuf, sequence);
int len = query_card(pduel, player, location, sequence, flag, (unsigned char*)qbuf, 0);
ReplayPacket p((char*)query_buffer, len + 3);
replay_stream.push_back(p);
if(location & LOCATION_ONFIELD) {
int pid = (player == 0) ? 0 : 2;
NetServer::SendBufferToPlayer(players[pid], STOC_GAME_MSG, query_buffer, len + 4);
......@@ -1714,6 +1782,16 @@ void TagDuel::RefreshSingle(int player, int location, int sequence, int flag) {
}
}
}
void TagDuel::PseudoRefreshDeck(int player, int flag) {
char query_buffer[0x2000];
char* qbuf = query_buffer;
BufferIO::WriteInt8(qbuf, MSG_UPDATE_DATA);
BufferIO::WriteInt8(qbuf, player);
BufferIO::WriteInt8(qbuf, LOCATION_DECK);
int len = query_field_card(pduel, player, LOCATION_DECK, flag, (unsigned char*)qbuf, 0);
ReplayPacket p((char*)query_buffer, len + 2);
replay_stream.push_back(p);
}
int TagDuel::MessageHandler(long fduel, int type) {
if(!enable_log)
return 0;
......@@ -1735,6 +1813,8 @@ void TagDuel::TagTimer(evutil_socket_t fd, short events, void* arg) {
NetServer::ReSendToPlayer(sd->players[1]);
NetServer::ReSendToPlayer(sd->players[2]);
NetServer::ReSendToPlayer(sd->players[3]);
ReplayPacket p((char*)wbuf, 3);
sd->replay_stream.push_back(p);
sd->EndDuel();
sd->DuelEndProc();
event_del(sd->etimer);
......
......@@ -40,6 +40,9 @@ public:
static int MessageHandler(long fduel, int type);
static void TagTimer(evutil_socket_t fd, short events, void* arg);
void PseudoRefreshDeck(int player, int flag = 0x181fff);
static std::vector<ReplayPacket> replay_stream;
protected:
DuelPlayer* players[4];
......@@ -52,6 +55,7 @@ protected:
unsigned char hand_result[2];
unsigned char last_response;
Replay last_replay;
Replay new_replay;
bool game_started;
unsigned char turn_count;
unsigned short time_limit[2];
......
Subproject commit cbcff83c4001fb4208a530f580ad7ce0ac1fdfb2
Subproject commit 2a37a9fad5e84d06998e16eb530c0c2acdbb4e81
#The first line is used for comment
#line doesn't start with '!' is also neglected
#called by DataManager::GetSysString(), DataManager::GetDesc()
#system
!system 1 Normal Summon
!system 2 Special Summon
......@@ -375,6 +375,7 @@
!system 1353 Start at turn
!system 1354 Hide Set Names 
!system 1355 Hide Chain Buttons
!system 1356 Old Replay Mode
!system 1360 Previous
!system 1370 Level
!system 1371 Attack
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment