Commit 5e749d4b authored by wind2009's avatar wind2009

Merge branch 'server' of https://github.com/purerosefallen/ygopro into 2pick

parents 80d79bdf 9822c235
No preview for this file type
...@@ -132,7 +132,7 @@ void ClientField::Initial(int player, int deckc, int extrac) { ...@@ -132,7 +132,7 @@ void ClientField::Initial(int player, int deckc, int extrac) {
} }
ClientCard* ClientField::GetCard(int controler, int location, int sequence, int sub_seq) { ClientCard* ClientField::GetCard(int controler, int location, int sequence, int sub_seq) {
std::vector<ClientCard*>* lst = 0; std::vector<ClientCard*>* lst = 0;
bool is_xyz = (location & 0x80) != 0; bool is_xyz = (location & LOCATION_OVERLAY) != 0;
location &= 0x7f; location &= 0x7f;
switch(location) { switch(location) {
case LOCATION_DECK: case LOCATION_DECK:
......
...@@ -1946,10 +1946,10 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -1946,10 +1946,10 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
respbuf[0] = mainGame->LocalPlayer(0); respbuf[0] = mainGame->LocalPlayer(0);
respbuf[1] = LOCATION_MZONE; respbuf[1] = LOCATION_MZONE;
filter = mainGame->dField.selectable_field & 0x7f; filter = mainGame->dField.selectable_field & 0x7f;
} else if (mainGame->dField.selectable_field & 0x1f00) { } else if (mainGame->dField.selectable_field & 0x3f00) {
respbuf[0] = mainGame->LocalPlayer(0); respbuf[0] = mainGame->LocalPlayer(0);
respbuf[1] = LOCATION_SZONE; respbuf[1] = LOCATION_SZONE;
filter = (mainGame->dField.selectable_field >> 8) & 0x1f; filter = (mainGame->dField.selectable_field >> 8) & 0x3f;
} else if (mainGame->dField.selectable_field & 0xc000) { } else if (mainGame->dField.selectable_field & 0xc000) {
respbuf[0] = mainGame->LocalPlayer(0); respbuf[0] = mainGame->LocalPlayer(0);
respbuf[1] = LOCATION_SZONE; respbuf[1] = LOCATION_SZONE;
...@@ -1959,10 +1959,10 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -1959,10 +1959,10 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
respbuf[0] = mainGame->LocalPlayer(1); respbuf[0] = mainGame->LocalPlayer(1);
respbuf[1] = LOCATION_MZONE; respbuf[1] = LOCATION_MZONE;
filter = (mainGame->dField.selectable_field >> 16) & 0x7f; filter = (mainGame->dField.selectable_field >> 16) & 0x7f;
} else if (mainGame->dField.selectable_field & 0x1f000000) { } else if (mainGame->dField.selectable_field & 0x3f000000) {
respbuf[0] = mainGame->LocalPlayer(1); respbuf[0] = mainGame->LocalPlayer(1);
respbuf[1] = LOCATION_SZONE; respbuf[1] = LOCATION_SZONE;
filter = (mainGame->dField.selectable_field >> 24) & 0x1f; filter = (mainGame->dField.selectable_field >> 24) & 0x3f;
} else { } else {
respbuf[0] = mainGame->LocalPlayer(1); respbuf[0] = mainGame->LocalPlayer(1);
respbuf[1] = LOCATION_SZONE; respbuf[1] = LOCATION_SZONE;
...@@ -2741,6 +2741,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -2741,6 +2741,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
else if(reason & REASON_DESTROY && pl != cl) else if(reason & REASON_DESTROY && pl != cl)
soundManager.PlaySoundEffect(SOUND_DESTROYED); soundManager.PlaySoundEffect(SOUND_DESTROYED);
} }
int appear = mainGame->gameConf.quick_animation ? 12 : 20;
if (pl == 0) { if (pl == 0) {
ClientCard* pcard = new ClientCard(); ClientCard* pcard = new ClientCard();
pcard->position = cp; pcard->position = cp;
...@@ -2751,8 +2752,8 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -2751,8 +2752,8 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
mainGame->gMutex.unlock(); mainGame->gMutex.unlock();
mainGame->dField.GetCardLocation(pcard, &pcard->curPos, &pcard->curRot, true); mainGame->dField.GetCardLocation(pcard, &pcard->curPos, &pcard->curRot, true);
pcard->curAlpha = 5; pcard->curAlpha = 5;
mainGame->dField.FadeCard(pcard, 255, 20); mainGame->dField.FadeCard(pcard, 255, appear);
mainGame->WaitFrameSignal(20); mainGame->WaitFrameSignal(appear);
} else } else
mainGame->dField.AddCard(pcard, cc, cl, cs); mainGame->dField.AddCard(pcard, cc, cl, cs);
} else if (cl == 0) { } else if (cl == 0) {
...@@ -2763,8 +2764,8 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -2763,8 +2764,8 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
for(auto eqit = pcard->equipped.begin(); eqit != pcard->equipped.end(); ++eqit) for(auto eqit = pcard->equipped.begin(); eqit != pcard->equipped.end(); ++eqit)
(*eqit)->equipTarget = 0; (*eqit)->equipTarget = 0;
if(!mainGame->dInfo.isReplaySkiping) { if(!mainGame->dInfo.isReplaySkiping) {
mainGame->dField.FadeCard(pcard, 5, 20); mainGame->dField.FadeCard(pcard, 5, appear);
mainGame->WaitFrameSignal(20); mainGame->WaitFrameSignal(appear);
mainGame->gMutex.lock(); mainGame->gMutex.lock();
mainGame->dField.RemoveCard(pc, pl, ps); mainGame->dField.RemoveCard(pc, pl, ps);
mainGame->gMutex.unlock(); mainGame->gMutex.unlock();
...@@ -2774,7 +2775,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -2774,7 +2775,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
mainGame->dField.RemoveCard(pc, pl, ps); mainGame->dField.RemoveCard(pc, pl, ps);
delete pcard; delete pcard;
} else { } else {
if (!(pl & 0x80) && !(cl & 0x80)) { if (!(pl & LOCATION_OVERLAY) && !(cl & LOCATION_OVERLAY)) {
ClientCard* pcard = mainGame->dField.GetCard(pc, pl, ps); ClientCard* pcard = mainGame->dField.GetCard(pc, pl, ps);
if (pcard->code != code && (code != 0 || cl == 0x40)) if (pcard->code != code && (code != 0 || cl == 0x40))
pcard->SetCode(code); pcard->SetCode(code);
...@@ -2837,7 +2838,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -2837,7 +2838,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
mainGame->WaitFrameSignal(5); mainGame->WaitFrameSignal(5);
} }
} }
} else if (!(pl & 0x80)) { } else if (!(pl & LOCATION_OVERLAY)) {
ClientCard* pcard = mainGame->dField.GetCard(pc, pl, ps); ClientCard* pcard = mainGame->dField.GetCard(pc, pl, ps);
if (code != 0 && pcard->code != code) if (code != 0 && pcard->code != code)
pcard->SetCode(code); pcard->SetCode(code);
...@@ -2857,7 +2858,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -2857,7 +2858,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
olcard->overlayed.push_back(pcard); olcard->overlayed.push_back(pcard);
mainGame->dField.overlay_cards.insert(pcard); mainGame->dField.overlay_cards.insert(pcard);
pcard->overlayTarget = olcard; pcard->overlayTarget = olcard;
pcard->location = 0x80; pcard->location = LOCATION_OVERLAY;
pcard->sequence = olcard->overlayed.size() - 1; pcard->sequence = olcard->overlayed.size() - 1;
} else { } else {
mainGame->gMutex.lock(); mainGame->gMutex.lock();
...@@ -2866,7 +2867,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -2866,7 +2867,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
mainGame->dField.overlay_cards.insert(pcard); mainGame->dField.overlay_cards.insert(pcard);
mainGame->gMutex.unlock(); mainGame->gMutex.unlock();
pcard->overlayTarget = olcard; pcard->overlayTarget = olcard;
pcard->location = 0x80; pcard->location = LOCATION_OVERLAY;
pcard->sequence = olcard->overlayed.size() - 1; pcard->sequence = olcard->overlayed.size() - 1;
if (olcard->location & 0x0c) { if (olcard->location & 0x0c) {
mainGame->gMutex.lock(); mainGame->gMutex.lock();
...@@ -2878,7 +2879,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -2878,7 +2879,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
mainGame->WaitFrameSignal(5); mainGame->WaitFrameSignal(5);
} }
} }
} else if (!(cl & 0x80)) { } else if (!(cl & LOCATION_OVERLAY)) {
ClientCard* olcard = mainGame->dField.GetCard(pc, pl & 0x7f, ps); ClientCard* olcard = mainGame->dField.GetCard(pc, pl & 0x7f, ps);
ClientCard* pcard = olcard->overlayed[pp]; ClientCard* pcard = olcard->overlayed[pp];
if(mainGame->dInfo.isReplaySkiping) { if(mainGame->dInfo.isReplaySkiping) {
...@@ -2915,7 +2916,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -2915,7 +2916,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
olcard1->overlayed.erase(olcard1->overlayed.begin() + pcard->sequence); olcard1->overlayed.erase(olcard1->overlayed.begin() + pcard->sequence);
olcard2->overlayed.push_back(pcard); olcard2->overlayed.push_back(pcard);
pcard->sequence = olcard2->overlayed.size() - 1; pcard->sequence = olcard2->overlayed.size() - 1;
pcard->location = 0x80; pcard->location = LOCATION_OVERLAY;
pcard->overlayTarget = olcard2; pcard->overlayTarget = olcard2;
for (size_t i = 0; i < olcard1->overlayed.size(); ++i) { for (size_t i = 0; i < olcard1->overlayed.size(); ++i) {
olcard1->overlayed[i]->sequence = i; olcard1->overlayed[i]->sequence = i;
...@@ -2925,7 +2926,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -2925,7 +2926,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
olcard1->overlayed.erase(olcard1->overlayed.begin() + pcard->sequence); olcard1->overlayed.erase(olcard1->overlayed.begin() + pcard->sequence);
olcard2->overlayed.push_back(pcard); olcard2->overlayed.push_back(pcard);
pcard->sequence = olcard2->overlayed.size() - 1; pcard->sequence = olcard2->overlayed.size() - 1;
pcard->location = 0x80; pcard->location = LOCATION_OVERLAY;
pcard->overlayTarget = olcard2; pcard->overlayTarget = olcard2;
for (size_t i = 0; i < olcard1->overlayed.size(); ++i) { for (size_t i = 0; i < olcard1->overlayed.size(); ++i) {
olcard1->overlayed[i]->sequence = i; olcard1->overlayed[i]->sequence = i;
...@@ -3239,7 +3240,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -3239,7 +3240,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
int l = BufferIO::ReadInt8(pbuf); int l = BufferIO::ReadInt8(pbuf);
int s = BufferIO::ReadInt8(pbuf); int s = BufferIO::ReadInt8(pbuf);
int ss = BufferIO::ReadInt8(pbuf); int ss = BufferIO::ReadInt8(pbuf);
if ((l & 0x80) > 0) if ((l & LOCATION_OVERLAY) > 0)
pcards[i] = mainGame->dField.GetCard(c, l & 0x7f, s)->overlayed[ss]; pcards[i] = mainGame->dField.GetCard(c, l & 0x7f, s)->overlayed[ss];
else else
pcards[i] = mainGame->dField.GetCard(c, l, s); pcards[i] = mainGame->dField.GetCard(c, l, s);
...@@ -4091,7 +4092,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) { ...@@ -4091,7 +4092,7 @@ int DuelClient::ClientAnalyze(char * msg, unsigned int len) {
ccard->overlayed.push_back(xcard); ccard->overlayed.push_back(xcard);
mainGame->dField.overlay_cards.insert(xcard); mainGame->dField.overlay_cards.insert(xcard);
xcard->overlayTarget = ccard; xcard->overlayTarget = ccard;
xcard->location = 0x80; xcard->location = LOCATION_OVERLAY;
xcard->sequence = ccard->overlayed.size() - 1; xcard->sequence = ccard->overlayed.size() - 1;
xcard->owner = p; xcard->owner = p;
xcard->controler = p; xcard->controler = p;
......
...@@ -1683,6 +1683,13 @@ bool ClientField::OnEvent(const irr::SEvent& event) { ...@@ -1683,6 +1683,13 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
myswprintf(formatBuffer, L"\n*%ls", dataManager.GetDesc(iter->first)); myswprintf(formatBuffer, L"\n*%ls", dataManager.GetDesc(iter->first));
str.append(formatBuffer); str.append(formatBuffer);
} }
if(mainGame->dInfo.turn == 1) {
if(mplayer == 0 && mainGame->dInfo.isFirst || mplayer != 0 && !mainGame->dInfo.isFirst)
myswprintf(formatBuffer, L"\n*%ls", dataManager.GetSysString(100));
else
myswprintf(formatBuffer, L"\n*%ls", dataManager.GetSysString(101));
str.append(formatBuffer);
}
should_show_tip = true; should_show_tip = true;
irr::core::dimension2d<unsigned int> dtip = mainGame->guiFont->getDimension(str.c_str()) + irr::core::dimension2d<unsigned int>(10, 10); irr::core::dimension2d<unsigned int> dtip = mainGame->guiFont->getDimension(str.c_str()) + irr::core::dimension2d<unsigned int>(10, 10);
mainGame->stTip->setRelativePosition(recti(mousepos.X - 10 - dtip.Width, mousepos.Y + 10, mousepos.X - 10, mousepos.Y + 10 + dtip.Height)); mainGame->stTip->setRelativePosition(recti(mousepos.X - 10 - dtip.Width, mousepos.Y + 10, mousepos.X - 10, mousepos.Y + 10 + dtip.Height));
......
...@@ -42,15 +42,15 @@ HostInfo game_info; ...@@ -42,15 +42,15 @@ HostInfo game_info;
void Game::MainServerLoop() { void Game::MainServerLoop() {
#ifdef SERVER_ZIP_SUPPORT #ifdef SERVER_ZIP_SUPPORT
dataManager.FileSystem = new irr::io::CFileSystem(); dataManager.FileSystem = new irr::io::CFileSystem();
#endif
#ifdef SERVER_PRO2_SUPPORT
dataManager.FileSystem->addFileArchive("data/script.zip");
#endif #endif
initUtils(); initUtils();
deckManager.LoadLFList(); deckManager.LoadLFList();
dataManager.LoadDB(L"cards.cdb"); dataManager.LoadDB(L"cards.cdb");
LoadExpansions(); LoadExpansions();
#ifdef SERVER_PRO2_SUPPORT
dataManager.FileSystem->addFileArchive("data/script.zip", true, false, EFAT_ZIP);
#endif
server_port = NetServer::StartServer(server_port); server_port = NetServer::StartServer(server_port);
NetServer::InitDuel(); NetServer::InitDuel();
printf("%u\n", server_port); printf("%u\n", server_port);
...@@ -229,7 +229,7 @@ bool Game::Initialize() { ...@@ -229,7 +229,7 @@ bool Game::Initialize() {
SetWindowsIcon(); SetWindowsIcon();
//main menu //main menu
wchar_t strbuf[256]; wchar_t strbuf[256];
myswprintf(strbuf, L"KoishiPro %X.0%X.%X Paranoia", PRO_VERSION >> 12, (PRO_VERSION >> 4) & 0xff, PRO_VERSION & 0xf); myswprintf(strbuf, L"KoishiPro %X.0%X.%X ChimiMoryo", PRO_VERSION >> 12, (PRO_VERSION >> 4) & 0xff, PRO_VERSION & 0xf);
wMainMenu = env->addWindow(rect<s32>(370, 200, 650, 415), false, strbuf); wMainMenu = env->addWindow(rect<s32>(370, 200, 650, 415), false, strbuf);
wMainMenu->getCloseButton()->setVisible(false); wMainMenu->getCloseButton()->setVisible(false);
btnLanMode = env->addButton(rect<s32>(10, 30, 270, 60), wMainMenu, BUTTON_LAN_MODE, dataManager.GetSysString(1200)); btnLanMode = env->addButton(rect<s32>(10, 30, 270, 60), wMainMenu, BUTTON_LAN_MODE, dataManager.GetSysString(1200));
......
...@@ -20,6 +20,7 @@ namespace ygo { ...@@ -20,6 +20,7 @@ namespace ygo {
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
#define REPLAY_MODE_SAVE_IN_SERVER 0x1 #define REPLAY_MODE_SAVE_IN_SERVER 0x1
#define REPLAY_MODE_WATCHER_NO_SEND 0x2 #define REPLAY_MODE_WATCHER_NO_SEND 0x2
#define REPLAY_MODE_INCLUDE_CHAT 0x4
#endif // YGOPRO_SERVER_MODE #endif // YGOPRO_SERVER_MODE
struct ReplayHeader { struct ReplayHeader {
......
...@@ -562,7 +562,7 @@ bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) { ...@@ -562,7 +562,7 @@ bool ReplayMode::ReplayAnalyze(char* msg, unsigned int len) {
/*int cp = pbuf[11];*/ /*int cp = pbuf[11];*/
pbuf += 16; pbuf += 16;
DuelClient::ClientAnalyze(offset, pbuf - offset); DuelClient::ClientAnalyze(offset, pbuf - offset);
if(cl && !(cl & 0x80) && (pl != cl || pc != cc)) if(cl && !(cl & LOCATION_OVERLAY) && (pl != cl || pc != cc))
ReplayRefreshSingle(cc, cl, cs); ReplayRefreshSingle(cc, cl, cs);
else if(pl == cl && cl == LOCATION_DECK) else if(pl == cl && cl == LOCATION_DECK)
ReplayRefreshDeck(cc); ReplayRefreshDeck(cc);
......
...@@ -43,6 +43,8 @@ void SingleDuel::Chat(DuelPlayer* dp, void* pdata, int len) { ...@@ -43,6 +43,8 @@ void SingleDuel::Chat(DuelPlayer* dp, void* pdata, int len) {
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
if(cache_recorder) if(cache_recorder)
NetServer::ReSendToPlayer(cache_recorder); NetServer::ReSendToPlayer(cache_recorder);
if(replay_recorder && replay_mode & REPLAY_MODE_INCLUDE_CHAT)
NetServer::ReSendToPlayer(replay_recorder);
#endif #endif
} }
void SingleDuel::JoinGame(DuelPlayer* dp, void* pdata, bool is_creater) { void SingleDuel::JoinGame(DuelPlayer* dp, void* pdata, bool is_creater) {
...@@ -1268,7 +1270,7 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) { ...@@ -1268,7 +1270,7 @@ int SingleDuel::Analyze(char* msgbuffer, unsigned int len) {
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
NetServer::ReSendToPlayers(cache_recorder, replay_recorder); NetServer::ReSendToPlayers(cache_recorder, replay_recorder);
#endif #endif
if (cl != 0 && (cl & 0x80) == 0 && (cl != pl || pc != cc)) if (cl != 0 && (cl & LOCATION_OVERLAY) == 0 && (cl != pl || pc != cc))
RefreshSingle(cc, cl, cs); RefreshSingle(cc, cl, cs);
break; break;
} }
......
...@@ -452,7 +452,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) { ...@@ -452,7 +452,7 @@ bool SingleMode::SinglePlayAnalyze(char* msg, unsigned int len) {
/*int cp = pbuf[11];*/ /*int cp = pbuf[11];*/
pbuf += 16; pbuf += 16;
DuelClient::ClientAnalyze(offset, pbuf - offset); DuelClient::ClientAnalyze(offset, pbuf - offset);
if(cl && !(cl & 0x80) && (pl != cl || pc != cc)) if(cl && !(cl & LOCATION_OVERLAY) && (pl != cl || pc != cc))
SinglePlayRefreshSingle(cc, cl, cs); SinglePlayRefreshSingle(cc, cl, cs);
break; break;
} }
......
...@@ -34,6 +34,8 @@ void TagDuel::Chat(DuelPlayer* dp, void* pdata, int len) { ...@@ -34,6 +34,8 @@ void TagDuel::Chat(DuelPlayer* dp, void* pdata, int len) {
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
if(cache_recorder) if(cache_recorder)
NetServer::ReSendToPlayer(cache_recorder); NetServer::ReSendToPlayer(cache_recorder);
if(replay_recorder && replay_mode & REPLAY_MODE_INCLUDE_CHAT)
NetServer::ReSendToPlayer(replay_recorder);
#endif #endif
} }
void TagDuel::JoinGame(DuelPlayer* dp, void* pdata, bool is_creater) { void TagDuel::JoinGame(DuelPlayer* dp, void* pdata, bool is_creater) {
...@@ -1198,7 +1200,7 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) { ...@@ -1198,7 +1200,7 @@ int TagDuel::Analyze(char* msgbuffer, unsigned int len) {
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
NetServer::ReSendToPlayers(cache_recorder, replay_recorder); NetServer::ReSendToPlayers(cache_recorder, replay_recorder);
#endif #endif
if (cl != 0 && (cl & 0x80) == 0 && (cl != pl || pc != cc)) if (cl != 0 && (cl & LOCATION_OVERLAY) == 0 && (cl != pl || pc != cc))
RefreshSingle(cc, cl, cs); RefreshSingle(cc, cl, cs);
break; break;
} }
......
Subproject commit 796a37ef44a50b8ce1770157be197315f37664ca Subproject commit 9a18abac5d3b8cbe987a8fe4ae5b101b0ec3a8c0
Subproject commit 9e44cd9296c16ad8331f82cb80c1ddddb3f946d6 Subproject commit f3e8cf5a04950491a3b16b0750edffaf287a8abd
...@@ -1169,3 +1169,4 @@ ...@@ -1169,3 +1169,4 @@
!setname 0x18b 救援ACERACE !setname 0x18b 救援ACERACE
!setname 0x18c 纯爱妖精 ピュアリィ !setname 0x18c 纯爱妖精 ピュアリィ
!setname 0x18d 御巫 !setname 0x18d 御巫
!setname 0x18e 仪水镜 儀水鏡
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