Commit bd0fe468 authored by mercury233's avatar mercury233

Merge branch 'master' of https://github.com/Fluorohydride/ygopro into server

parents 9c07d44a 6641bb30
...@@ -1271,13 +1271,6 @@ bool ClientField::check_sum(std::set<ClientCard*>::const_iterator index, std::se ...@@ -1271,13 +1271,6 @@ bool ClientField::check_sum(std::set<ClientCard*>::const_iterator index, std::se
|| check_sum(index, end, acc, count); || check_sum(index, end, acc, count);
} }
template <class T> template <class T>
static bool is_declarable(T const& cd, int declarable_type) {
if(!(cd.type & declarable_type))
return false;
return cd.code == CARD_MARINE_DOLPHIN || cd.code == CARD_TWINKLE_MOSS
|| (!cd.alias && (cd.type & (TYPE_MONSTER + TYPE_TOKEN)) != (TYPE_MONSTER + TYPE_TOKEN));
}
template <class T>
static bool is_declarable(T const& cd, const std::vector<int>& opcode) { static bool is_declarable(T const& cd, const std::vector<int>& opcode) {
std::stack<int> stack; std::stack<int> stack;
for(auto it = opcode.begin(); it != opcode.end(); ++it) { for(auto it = opcode.begin(); it != opcode.end(); ++it) {
...@@ -1418,59 +1411,12 @@ static bool is_declarable(T const& cd, const std::vector<int>& opcode) { ...@@ -1418,59 +1411,12 @@ static bool is_declarable(T const& cd, const std::vector<int>& opcode) {
return cd.code == CARD_MARINE_DOLPHIN || cd.code == CARD_TWINKLE_MOSS return cd.code == CARD_MARINE_DOLPHIN || cd.code == CARD_TWINKLE_MOSS
|| (!cd.alias && (cd.type & (TYPE_MONSTER + TYPE_TOKEN)) != (TYPE_MONSTER + TYPE_TOKEN)); || (!cd.alias && (cd.type & (TYPE_MONSTER + TYPE_TOKEN)) != (TYPE_MONSTER + TYPE_TOKEN));
} }
void ClientField::UpdateDeclarableCodeType() { void ClientField::UpdateDeclarableList() {
const wchar_t* pname = mainGame->ebANCard->getText();
int trycode = BufferIO::GetVal(pname);
CardString cstr;
CardData cd;
if(dataManager.GetString(trycode, &cstr) && dataManager.GetData(trycode, &cd) && is_declarable(cd, declarable_type)) {
mainGame->lstANCard->clear();
ancard.clear();
mainGame->lstANCard->addItem(cstr.name.c_str());
ancard.push_back(trycode);
return;
}
if(pname[0] == 0) {
std::vector<int> cache;
cache.swap(ancard);
int sel = mainGame->lstANCard->getSelected();
int selcode = (sel == -1) ? 0 : cache[sel];
mainGame->lstANCard->clear();
for(const auto& trycode : cache) {
if(dataManager.GetString(trycode, &cstr) && dataManager.GetData(trycode, &cd) && is_declarable(cd, declarable_type)) {
ancard.push_back(trycode);
mainGame->lstANCard->addItem(cstr.name.c_str());
if(trycode == selcode)
mainGame->lstANCard->setSelected(cstr.name.c_str());
}
}
if(!ancard.empty())
return;
}
mainGame->lstANCard->clear();
ancard.clear();
for(auto cit = dataManager._strings.begin(); cit != dataManager._strings.end(); ++cit) {
if(cit->second.name.find(pname) != std::wstring::npos) {
auto cp = dataManager.GetCodePointer(cit->first); //verified by _strings
//datas.alias can be double card names or alias
if(is_declarable(cp->second, declarable_type)) {
if(pname == cit->second.name) { //exact match
mainGame->lstANCard->insertItem(0, cit->second.name.c_str(), -1);
ancard.insert(ancard.begin(), cit->first);
} else {
mainGame->lstANCard->addItem(cit->second.name.c_str());
ancard.push_back(cit->first);
}
}
}
}
}
void ClientField::UpdateDeclarableCodeOpcode() {
const wchar_t* pname = mainGame->ebANCard->getText(); const wchar_t* pname = mainGame->ebANCard->getText();
int trycode = BufferIO::GetVal(pname); int trycode = BufferIO::GetVal(pname);
CardString cstr; CardString cstr;
CardData cd; CardData cd;
if(dataManager.GetString(trycode, &cstr) && dataManager.GetData(trycode, &cd) && is_declarable(cd, opcode)) { if(dataManager.GetString(trycode, &cstr) && dataManager.GetData(trycode, &cd) && is_declarable(cd, declare_opcodes)) {
mainGame->lstANCard->clear(); mainGame->lstANCard->clear();
ancard.clear(); ancard.clear();
mainGame->lstANCard->addItem(cstr.name.c_str()); mainGame->lstANCard->addItem(cstr.name.c_str());
...@@ -1484,7 +1430,7 @@ void ClientField::UpdateDeclarableCodeOpcode() { ...@@ -1484,7 +1430,7 @@ void ClientField::UpdateDeclarableCodeOpcode() {
int selcode = (sel == -1) ? 0 : cache[sel]; int selcode = (sel == -1) ? 0 : cache[sel];
mainGame->lstANCard->clear(); mainGame->lstANCard->clear();
for(const auto& trycode : cache) { for(const auto& trycode : cache) {
if(dataManager.GetString(trycode, &cstr) && dataManager.GetData(trycode, &cd) && is_declarable(cd, opcode)) { if(dataManager.GetString(trycode, &cstr) && dataManager.GetData(trycode, &cd) && is_declarable(cd, declare_opcodes)) {
ancard.push_back(trycode); ancard.push_back(trycode);
mainGame->lstANCard->addItem(cstr.name.c_str()); mainGame->lstANCard->addItem(cstr.name.c_str());
if(trycode == selcode) if(trycode == selcode)
...@@ -1500,7 +1446,7 @@ void ClientField::UpdateDeclarableCodeOpcode() { ...@@ -1500,7 +1446,7 @@ void ClientField::UpdateDeclarableCodeOpcode() {
if(cit->second.name.find(pname) != std::wstring::npos) { if(cit->second.name.find(pname) != std::wstring::npos) {
auto cp = dataManager.GetCodePointer(cit->first); //verified by _strings auto cp = dataManager.GetCodePointer(cit->first); //verified by _strings
//datas.alias can be double card names or alias //datas.alias can be double card names or alias
if(is_declarable(cp->second, opcode)) { if(is_declarable(cp->second, declare_opcodes)) {
if(pname == cit->second.name) { //exact match if(pname == cit->second.name) { //exact match
mainGame->lstANCard->insertItem(0, cit->second.name.c_str(), -1); mainGame->lstANCard->insertItem(0, cit->second.name.c_str(), -1);
ancard.insert(ancard.begin(), cit->first); ancard.insert(ancard.begin(), cit->first);
...@@ -1512,10 +1458,4 @@ void ClientField::UpdateDeclarableCodeOpcode() { ...@@ -1512,10 +1458,4 @@ void ClientField::UpdateDeclarableCodeOpcode() {
} }
} }
} }
void ClientField::UpdateDeclarableCode() {
if(opcode.size() == 0)
UpdateDeclarableCodeType();
else
UpdateDeclarableCodeOpcode();
}
} }
...@@ -60,14 +60,13 @@ public: ...@@ -60,14 +60,13 @@ public:
bool select_panalmode; bool select_panalmode;
bool select_ready; bool select_ready;
int announce_count; int announce_count;
int declarable_type;
int select_counter_count; int select_counter_count;
int select_counter_type; int select_counter_type;
std::vector<ClientCard*> selectable_cards; std::vector<ClientCard*> selectable_cards;
std::vector<ClientCard*> selected_cards; std::vector<ClientCard*> selected_cards;
std::set<ClientCard*> selectsum_cards; std::set<ClientCard*> selectsum_cards;
std::vector<ClientCard*> selectsum_all; std::vector<ClientCard*> selectsum_all;
std::vector<int> opcode; std::vector<int> declare_opcodes;
std::vector<ClientCard*> display_cards; std::vector<ClientCard*> display_cards;
std::vector<int> sort_list; std::vector<int> sort_list;
std::map<int, int> player_desc_hints[2]; std::map<int, int> player_desc_hints[2];
...@@ -112,9 +111,7 @@ public: ...@@ -112,9 +111,7 @@ public:
void check_sel_sum_t(const std::set<ClientCard*>& left, int acc); void check_sel_sum_t(const std::set<ClientCard*>& left, int acc);
bool check_sum(std::set<ClientCard*>::const_iterator index, std::set<ClientCard*>::const_iterator end, int acc, int count); bool check_sum(std::set<ClientCard*>::const_iterator index, std::set<ClientCard*>::const_iterator end, int acc, int count);
void UpdateDeclarableCodeType(); void UpdateDeclarableList();
void UpdateDeclarableCodeOpcode();
void UpdateDeclarableCode();
irr::gui::IGUIElement* panel; irr::gui::IGUIElement* panel;
std::vector<int> ancard; std::vector<int> ancard;
......
...@@ -23,6 +23,7 @@ bufferevent* DuelClient::client_bev = 0; ...@@ -23,6 +23,7 @@ bufferevent* DuelClient::client_bev = 0;
char DuelClient::duel_client_read[0x2000]; char DuelClient::duel_client_read[0x2000];
char DuelClient::duel_client_write[0x2000]; char DuelClient::duel_client_write[0x2000];
bool DuelClient::is_closing = false; bool DuelClient::is_closing = false;
bool DuelClient::is_swapping = false;
int DuelClient::select_hint = 0; int DuelClient::select_hint = 0;
int DuelClient::select_unselect_hint = 0; int DuelClient::select_unselect_hint = 0;
int DuelClient::last_select_hint = 0; int DuelClient::last_select_hint = 0;
...@@ -889,6 +890,12 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -889,6 +890,12 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
} }
if(mainGame->dInfo.time_player == 1) if(mainGame->dInfo.time_player == 1)
mainGame->dInfo.time_player = 2; mainGame->dInfo.time_player = 2;
if(is_swapping) {
mainGame->gMutex.Lock();
mainGame->dField.ReplaySwap();
mainGame->gMutex.Unlock();
is_swapping = false;
}
switch(mainGame->dInfo.curMsg) { switch(mainGame->dInfo.curMsg) {
case MSG_RETRY: { case MSG_RETRY: {
if(last_successful_msg_length) { if(last_successful_msg_length) {
...@@ -897,7 +904,6 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -897,7 +904,6 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
int err_desc = 1421; int err_desc = 1421;
switch(last_msg) { switch(last_msg) {
case MSG_ANNOUNCE_CARD: case MSG_ANNOUNCE_CARD:
case MSG_ANNOUNCE_CARD_FILTER:
err_desc = 1422; err_desc = 1422;
break; break;
case MSG_ANNOUNCE_ATTRIB: case MSG_ANNOUNCE_ATTRIB:
...@@ -2162,8 +2168,10 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -2162,8 +2168,10 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
} }
mainGame->WaitFrameSignal(11); mainGame->WaitFrameSignal(11);
} }
for (auto cit = mainGame->dField.hand[player].begin(); cit != mainGame->dField.hand[player].end(); ++cit) for(auto cit = mainGame->dField.hand[player].begin(); cit != mainGame->dField.hand[player].end(); ++cit) {
(*cit)->SetCode(BufferIO::ReadInt32(pbuf)); (*cit)->SetCode(BufferIO::ReadInt32(pbuf));
(*cit)->desc_hints.clear();
}
if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping) { if(!mainGame->dInfo.isReplay || !mainGame->dInfo.isReplaySkiping) {
for (auto cit = mainGame->dField.hand[player].begin(); cit != mainGame->dField.hand[player].end(); ++cit) { for (auto cit = mainGame->dField.hand[player].begin(); cit != mainGame->dField.hand[player].end(); ++cit) {
(*cit)->is_hovered = false; (*cit)->is_hovered = false;
...@@ -3468,8 +3476,10 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -3468,8 +3476,10 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
} }
case MSG_ANNOUNCE_CARD: { case MSG_ANNOUNCE_CARD: {
/*int player = */mainGame->LocalPlayer(BufferIO::ReadInt8(pbuf)); /*int player = */mainGame->LocalPlayer(BufferIO::ReadInt8(pbuf));
mainGame->dField.declarable_type = BufferIO::ReadInt32(pbuf); int count = BufferIO::ReadUInt8(pbuf);
mainGame->dField.opcode.clear(); mainGame->dField.declare_opcodes.clear();
for (int i = 0; i < count; ++i)
mainGame->dField.declare_opcodes.push_back(BufferIO::ReadInt32(pbuf));
if(select_hint) if(select_hint)
myswprintf(textBuffer, L"%ls", dataManager.GetDesc(select_hint)); myswprintf(textBuffer, L"%ls", dataManager.GetDesc(select_hint));
else myswprintf(textBuffer, dataManager.GetSysString(564)); else myswprintf(textBuffer, dataManager.GetSysString(564));
...@@ -3477,7 +3487,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -3477,7 +3487,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
mainGame->gMutex.Lock(); mainGame->gMutex.Lock();
mainGame->ebANCard->setText(L""); mainGame->ebANCard->setText(L"");
mainGame->wANCard->setText(textBuffer); mainGame->wANCard->setText(textBuffer);
mainGame->dField.UpdateDeclarableCode(); mainGame->dField.UpdateDeclarableList();
mainGame->PopupElement(mainGame->wANCard); mainGame->PopupElement(mainGame->wANCard);
mainGame->gMutex.Unlock(); mainGame->gMutex.Unlock();
return false; return false;
...@@ -3502,25 +3512,6 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -3502,25 +3512,6 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
mainGame->gMutex.Unlock(); mainGame->gMutex.Unlock();
return false; return false;
} }
case MSG_ANNOUNCE_CARD_FILTER: {
/*int player = */mainGame->LocalPlayer(BufferIO::ReadInt8(pbuf));
int count = BufferIO::ReadUInt8(pbuf);
mainGame->dField.declarable_type = 0;
mainGame->dField.opcode.clear();
for (int i = 0; i < count; ++i)
mainGame->dField.opcode.push_back(BufferIO::ReadInt32(pbuf));
if(select_hint)
myswprintf(textBuffer, L"%ls", dataManager.GetDesc(select_hint));
else myswprintf(textBuffer, dataManager.GetSysString(564));
select_hint = 0;
mainGame->gMutex.Lock();
mainGame->ebANCard->setText(L"");
mainGame->wANCard->setText(textBuffer);
mainGame->dField.UpdateDeclarableCode();
mainGame->PopupElement(mainGame->wANCard);
mainGame->gMutex.Unlock();
return false;
}
case MSG_CARD_HINT: { case MSG_CARD_HINT: {
int c = mainGame->LocalPlayer(BufferIO::ReadInt8(pbuf)); int c = mainGame->LocalPlayer(BufferIO::ReadInt8(pbuf));
int l = BufferIO::ReadInt8(pbuf); int l = BufferIO::ReadInt8(pbuf);
...@@ -3804,6 +3795,9 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -3804,6 +3795,9 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
} }
return true; return true;
} }
void DuelClient::SwapField() {
is_swapping = true;
}
void DuelClient::SetResponseI(int respI) { void DuelClient::SetResponseI(int respI) {
*((int*)response_buf) = respI; *((int*)response_buf) = respI;
response_len = 4; response_len = 4;
......
...@@ -29,6 +29,7 @@ private: ...@@ -29,6 +29,7 @@ private:
static char duel_client_read[0x2000]; static char duel_client_read[0x2000];
static char duel_client_write[0x2000]; static char duel_client_write[0x2000];
static bool is_closing; static bool is_closing;
static bool is_swapping;
static int select_hint; static int select_hint;
static int select_unselect_hint; static int select_unselect_hint;
static int last_select_hint; static int last_select_hint;
...@@ -45,6 +46,7 @@ public: ...@@ -45,6 +46,7 @@ public:
static int ClientThread(void* param); static int ClientThread(void* param);
static void HandleSTOCPacketLan(char* data, unsigned int len); static void HandleSTOCPacketLan(char* data, unsigned int len);
static int ClientAnalyze(char* msg, unsigned int len); static int ClientAnalyze(char* msg, unsigned int len);
static void SwapField();
static void SetResponseI(int respI); static void SetResponseI(int respI);
static void SetResponseB(void* respB, unsigned char len); static void SetResponseB(void* respB, unsigned char len);
static void SendResponse(); static void SendResponse();
......
...@@ -91,8 +91,8 @@ bool ClientField::OnEvent(const irr::SEvent& event) { ...@@ -91,8 +91,8 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
soundManager.PlaySoundEffect(SOUND_BUTTON); soundManager.PlaySoundEffect(SOUND_BUTTON);
if(mainGame->dInfo.isReplay) if(mainGame->dInfo.isReplay)
ReplayMode::SwapField(); ReplayMode::SwapField();
else if (mainGame->dInfo.player_type == 7) else if(mainGame->dInfo.player_type == 7)
mainGame->dField.ReplaySwap(); DuelClient::SwapField();
break; break;
} }
case BUTTON_REPLAY_UNDO: { case BUTTON_REPLAY_UNDO: {
...@@ -963,7 +963,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) { ...@@ -963,7 +963,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
case irr::gui::EGET_EDITBOX_CHANGED: { case irr::gui::EGET_EDITBOX_CHANGED: {
switch(id) { switch(id) {
case EDITBOX_ANCARD: { case EDITBOX_ANCARD: {
UpdateDeclarableCode(); UpdateDeclarableList();
break; break;
} }
} }
...@@ -972,7 +972,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) { ...@@ -972,7 +972,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
case irr::gui::EGET_EDITBOX_ENTER: { case irr::gui::EGET_EDITBOX_ENTER: {
switch(id) { switch(id) {
case EDITBOX_ANCARD: { case EDITBOX_ANCARD: {
UpdateDeclarableCode(); UpdateDeclarableList();
break; break;
} }
} }
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include "single_mode.h" #include "single_mode.h"
#endif //YGOPRO_SERVER_MODE #endif //YGOPRO_SERVER_MODE
const unsigned short PRO_VERSION = 0x134A; const unsigned short PRO_VERSION = 0x134B;
namespace ygo { namespace ygo {
......
...@@ -773,13 +773,8 @@ bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) { ...@@ -773,13 +773,8 @@ bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) {
pbuf += 5; pbuf += 5;
return ReadReplayResponse(); return ReadReplayResponse();
} }
case MSG_ANNOUNCE_CARD: { case MSG_ANNOUNCE_CARD:
player = BufferIO::ReadInt8(pbuf); case MSG_ANNOUNCE_NUMBER: {
pbuf += 4;
return ReadReplayResponse();
}
case MSG_ANNOUNCE_NUMBER:
case MSG_ANNOUNCE_CARD_FILTER: {
player = BufferIO::ReadInt8(pbuf); player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadUInt8(pbuf); count = BufferIO::ReadUInt8(pbuf);
pbuf += 4 * count; pbuf += 4 * count;
......
...@@ -1673,15 +1673,8 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) { ...@@ -1673,15 +1673,8 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, offset, pbuf - offset); NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, offset, pbuf - offset);
return 1; return 1;
} }
case MSG_ANNOUNCE_CARD: { case MSG_ANNOUNCE_CARD:
player = BufferIO::ReadInt8(pbuf); case MSG_ANNOUNCE_NUMBER: {
WaitforResponse(player);
pbuf += 4;
NetServer::SendBufferToPlayer(players[player], STOC_GAME_MSG, offset, pbuf - offset);
return 1;
}
case MSG_ANNOUNCE_NUMBER:
case MSG_ANNOUNCE_CARD_FILTER: {
player = BufferIO::ReadInt8(pbuf); player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadUInt8(pbuf); count = BufferIO::ReadUInt8(pbuf);
pbuf += 4 * count; pbuf += 4 * count;
......
...@@ -679,17 +679,8 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) { ...@@ -679,17 +679,8 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
} }
break; break;
} }
case MSG_ANNOUNCE_CARD: { case MSG_ANNOUNCE_CARD:
player = BufferIO::ReadInt8(pbuf); case MSG_ANNOUNCE_NUMBER: {
pbuf += 4;
if(!DuelClient::ClientAnalyze(offset, pbuf - offset)) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
}
break;
}
case MSG_ANNOUNCE_NUMBER:
case MSG_ANNOUNCE_CARD_FILTER: {
player = BufferIO::ReadInt8(pbuf); player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadUInt8(pbuf); count = BufferIO::ReadUInt8(pbuf);
pbuf += 4 * count; pbuf += 4 * count;
......
...@@ -1710,15 +1710,8 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) { ...@@ -1710,15 +1710,8 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
NetServer::SendBufferToPlayer(cur_player[player], STOC_GAME_MSG, offset, pbuf - offset); NetServer::SendBufferToPlayer(cur_player[player], STOC_GAME_MSG, offset, pbuf - offset);
return 1; return 1;
} }
case MSG_ANNOUNCE_CARD: { case MSG_ANNOUNCE_CARD:
player = BufferIO::ReadInt8(pbuf); case MSG_ANNOUNCE_NUMBER: {
pbuf += 4;
WaitforResponse(player);
NetServer::SendBufferToPlayer(cur_player[player], STOC_GAME_MSG, offset, pbuf - offset);
return 1;
}
case MSG_ANNOUNCE_NUMBER:
case MSG_ANNOUNCE_CARD_FILTER: {
player = BufferIO::ReadInt8(pbuf); player = BufferIO::ReadInt8(pbuf);
count = BufferIO::ReadUInt8(pbuf); count = BufferIO::ReadUInt8(pbuf);
pbuf += 4 * count; pbuf += 4 * count;
......
Subproject commit 79345ca980c5c933dbec08a0b0f6fb1af1a8da20 Subproject commit f79332d76d1b5774fe0105e541d34c7b40e3e54a
Subproject commit 35562e466d6ae7816bf32a2cc2b5bc37deed4aaa Subproject commit 573645ee990be70d8e7c7ae2fa8a8fad33e9d62e
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
!system 64 二重状态 !system 64 二重状态
!system 65 使用效果 !system 65 使用效果
!system 66 持续公开 !system 66 持续公开
!system 67 原本持有者为对方
!system 70 怪兽卡 !system 70 怪兽卡
!system 71 魔法卡 !system 71 魔法卡
!system 72 陷阱卡 !system 72 陷阱卡
......
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