Commit 3f04ece0 authored by nanahira's avatar nanahira

Merge branch 'master' into raw-video

parents 21507b37 0aa6bbdb
......@@ -2,13 +2,16 @@
set -x
set -o errexit
TARGET_PLATFORM=$(arch)
TARGET_YGOPRO_BINARY_PATH=./ygopro-platforms/ygopro-platform-$TARGET_PLATFORM
export EVENT_INCLUDE_DIR=$PWD/libevent-stable/include
export EVENT_LIB_DIR=$PWD/libevent-stable/lib
export IRRLICHT_INCLUDE_DIR=$PWD/irrlicht/include
export IRRLICHT_LIB_DIR=$PWD/irrlicht
export IRRLICHT_LIB_DIR=$PWD/irrlicht/lib/$(arch)
./premake5 gmake --cc=clang --build-freetype --build-sqlite
./.ci/libevent-prebuild.sh
./premake5 gmake --cc=clang --build-freetype --build-sqlite --no-use-irrklang
cd build
make config=release -j4
......@@ -17,8 +20,8 @@ cd ..
mkdir ygopro-platforms
mv bin/release/YGOPro.app $TARGET_YGOPRO_BINARY_PATH
if [[ $TARGET_PLATFORM == "x86" ]]; then
install_name_tool -change /usr/local/lib/libirrklang.dylib @executable_path/../Frameworks/libirrklang.dylib $TARGET_YGOPRO_BINARY_PATH
fi
#if [[ $TARGET_PLATFORM == "x86" ]]; then
# install_name_tool -change /usr/local/lib/libirrklang.dylib @executable_path/../Frameworks/libirrklang.dylib $TARGET_YGOPRO_BINARY_PATH
#fi
strip $TARGET_YGOPRO_BINARY_PATH
......@@ -2,7 +2,7 @@
set -x
set -o errexit
ARCHIVE_FILES=(ygopro lib cards.cdb locales fonts sound textures strings.conf system.conf)
ARCHIVE_FILES=(ygopro lib cards.cdb locales fonts sound textures strings.conf system.conf pack)
TARGET_PLATFORM=linux
......
......@@ -2,7 +2,7 @@
set -x
set -o errexit
ARCHIVE_FILES=(ygopro LICENSE README.md lib lflist.conf strings.conf system.conf cards.cdb script textures deck single pics replay sound windbot bot bot.conf locales fonts)
ARCHIVE_FILES=(ygopro LICENSE README.md lib lflist.conf strings.conf system.conf cards.cdb script textures deck single pics replay sound windbot bot bot.conf locales fonts pack)
# TARGET_LOCALE
# ARCHIVE_SUFFIX
......
......@@ -2,7 +2,7 @@
set -x
set -o errexit
ARCHIVE_FILES=(ygopro.app cards.cdb locales fonts sound textures strings.conf system.conf)
ARCHIVE_FILES=(ygopro.app cards.cdb locales fonts textures strings.conf system.conf pack)
TARGET_PLATFORM=darwin
......
......@@ -2,7 +2,7 @@
set -x
set -o errexit
ARCHIVE_FILES=(ygopro.app LICENSE README.md lflist.conf strings.conf system.conf cards.cdb script textures deck single pics replay sound windbot bot bot.conf locales fonts)
ARCHIVE_FILES=(ygopro.app LICENSE README.md lflist.conf strings.conf system.conf cards.cdb script textures deck single pics replay windbot bot bot.conf locales fonts pack)
# TARGET_LOCALE
# ARCHIVE_SUFFIX
......
......@@ -2,7 +2,7 @@
set -x
set -o errexit
ARCHIVE_FILES=(ygopro.exe LICENSE README.md lflist.conf strings.conf system.conf cards.cdb script textures deck single pics replay sound bot.conf Bot.exe WindBot locales fonts skin)
ARCHIVE_FILES=(ygopro.exe LICENSE README.md lflist.conf strings.conf system.conf cards.cdb script textures deck single pics replay sound bot.conf Bot.exe WindBot locales fonts skin pack)
if [[ "$TARGET_LOCALE" == "zh-CN" ]]; then
ARCHIVE_FILES=("${ARCHIVE_FILES[@]}" update-koishipro)
......
......@@ -2,7 +2,7 @@
set -x
set -o errexit
ARCHIVE_FILES=(ygopro.exe cards.cdb locales fonts sound textures strings.conf system.conf skin)
ARCHIVE_FILES=(ygopro.exe cards.cdb locales fonts sound textures strings.conf system.conf skin pack)
TARGET_PLATFORM=win32
......
......@@ -2,7 +2,7 @@
set -x
set -o errexit
ARCHIVE_FILES=(ygopro.exe LICENSE README.md lflist.conf strings.conf system.conf cards.cdb script textures deck single pics replay sound bot.conf Bot.exe WindBot locales fonts skin)
ARCHIVE_FILES=(ygopro.exe LICENSE README.md lflist.conf strings.conf system.conf cards.cdb script textures deck single pics replay sound bot.conf Bot.exe WindBot locales fonts skin pack)
if [[ "$TARGET_LOCALE" == "zh-CN" && "$ARCHIVE_SUFFIX" != "zst" ]]; then
ARCHIVE_FILES=("${ARCHIVE_FILES[@]}" update-koishipro)
......
......@@ -65,6 +65,7 @@ build
/update*
/locales
/lib
/pack
# ygopro main program
/ygopro
......
......@@ -16,11 +16,11 @@ mat_common:
- linux
script:
# lua
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/lua-5.3.6.tar.gz | tar zfx -
- mv lua-5.3.6 lua
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/lua-5.4.4.tar.gz | tar zfx -
- mv lua-5.4.4 lua
# sqlite3
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/sqlite-autoconf-3360000.tar.gz | tar zfx -
- mv sqlite-autoconf-3360000 sqlite3
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/sqlite-autoconf-3390300.tar.gz | tar zfx -
- mv sqlite-autoconf-3390300 sqlite3
# freetype
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/freetype-2.11.1.tar.gz | tar zfx -
- mv freetype-2.11.1 freetype
......@@ -67,7 +67,7 @@ mat_linux:
script:
- apt update; apt -y install git wget tar
- git clone --depth=1 https://code.mycard.moe/mycard/irrlicht-new irrlicht
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/premake-5.0.0-beta1-linux.tar.gz | tar zfx -
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/premake-5.0.0-beta2-linux.tar.gz | tar zfx -
- env PROCESSOR_COUNT=$(nproc) ./.ci/libevent-prebuild.sh
artifacts:
paths:
......@@ -75,38 +75,16 @@ mat_linux:
- irrlicht
- libevent-stable
mat_macos_platform_x86:
stage: prepare
tags:
- macos
variables:
PROCESSOR_COUNT: '4'
script: ./.ci/libevent-prebuild.sh
artifacts:
paths:
- libevent-stable
mat_macos_platform_m1:
stage: prepare
tags:
- linux
script:
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/libevent-m1mac.tar.gz | tar zfx -
artifacts:
paths:
- libevent-stable
mat_macos_irrklang_patched:
stage: build
tags:
- linux
dependencies: []
script:
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/libirrklang-patched-dylib.tar.gz | tar zfx -
artifacts:
paths:
- libirrklang-patched.dylib
#mat_macos_irrklang_patched:
# stage: build
# tags:
# - linux
# dependencies: []
# script:
# - wget -O - https://cdn01.moecube.com/ygopro-build-materials/libirrklang-patched-dylib.tar.gz | tar zfx -
# artifacts:
# paths:
# - libirrklang-patched.dylib
mat_macos:
stage: prepare
......@@ -114,7 +92,8 @@ mat_macos:
- linux
script:
- apt update; apt -y install wget tar
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/premake-5.0.0-beta1-macosx.tar.gz | tar zfx -
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/premake-5.0.0-beta2-macosx.tar.gz | tar zfx -
# - wget -O - https://cdn01.moecube.com/ygopro-build-materials/libirrklang-patched-dylib.tar.gz | tar zfx -
- mkdir irrlicht
- cd irrlicht
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/irrlicht-mycard-mac.tar.gz | tar zfx -
......@@ -131,8 +110,8 @@ mat_windows:
script:
- apt update; apt -y install wget tar patch p7zip-full
# premake5.exe
- wget https://cdn01.moecube.com/ygopro-build-materials/premake-5.0.0-beta1-windows.zip
- 7z x -y premake-5.0.0-beta1-windows.zip
- wget https://cdn01.moecube.com/ygopro-build-materials/premake-5.0.0-beta2-windows.zip
- 7z x -y premake-5.0.0-beta2-windows.zip
# event
- wget -O - https://cdn01.moecube.com/ygopro-build-materials/libevent-2.0.22-stable.tar.gz | tar zfx -
- mv libevent-2.0.22-stable event
......@@ -201,8 +180,10 @@ exec_linux:
._exec_macos_platform:
extends: ._exec_build
tags:
- macos
dependencies:
- mat_macos
- mat_common
- mat_submodules
script:
- ./.ci/exec-macos-platform.sh
artifacts:
......@@ -211,27 +192,16 @@ exec_linux:
exec_macos_platform_x86:
extends: ._exec_macos_platform
dependencies:
- mat_irrklang
- mat_macos
- mat_common
- mat_macos_platform_x86
- mat_submodules
variables:
TARGET_PLATFORM: x86
BUILD_IKPMP3: '1'
tags:
- macos
exec_macos_platform_m1:
extends: ._exec_macos_platform
dependencies:
- mat_macos
- mat_common
- mat_macos_platform_m1
- mat_submodules
tags:
- macos-m1
variables:
TARGET_PLATFORM: m1
MAC_ARM: '1'
NO_USE_IRRKLANG: '1'
MAC_ARM: 1
exec_macos:
stage: combine
......@@ -240,12 +210,12 @@ exec_macos:
dependencies:
- exec_macos_platform_x86
- exec_macos_platform_m1
- mat_macos_irrklang_patched
#- mat_macos_irrklang_patched
script:
- mkdir -p ygopro.app/Contents/MacOS ygopro.app/Contents/Frameworks;
- lipo -create -output ygopro.app/Contents/MacOS/ygopro ygopro-platforms/ygopro-platform-x86 ygopro-platforms/ygopro-platform-m1;
- lipo -create -output ygopro.app/Contents/MacOS/ygopro $(ls -1 ygopro-platforms/ygopro-platform-*);
# do some special things for irrklang
- mv ./libirrklang-patched.dylib ygopro.app/Contents/Frameworks/libirrklang.dylib
#- mv ./libirrklang-patched.dylib ygopro.app/Contents/Frameworks/libirrklang.dylib
#- install_name_tool -change /usr/local/lib/libirrklang.dylib @executable_path/../Frameworks/libirrklang.dylib ygopro.app/Contents/MacOS/ygopro
#- dylibbundler -x ygopro.app/Contents/MacOS/ygopro -b -d ygopro.app/Contents/Frameworks/ -p @executable_path/../Frameworks/ -cd -i @executable_path/../Frameworks;
#- strip ygopro.app/Contents/MacOS/ygopro;
......@@ -289,6 +259,9 @@ assets:
- cd fonts
- wget -O - https://cdn01.moecube.com/ygopro-fonts.tar.gz | tar zfx -
- cd ..
# pack
- git clone --depth=1 https://code.mycard.moe/mycard/ygopro-card-list
- mv ygopro-card-list/pack .
# locales
- git clone --depth=1 https://code.mycard.moe/nanahira/ygopro-database
- mv ygopro-database/locales .
......@@ -298,6 +271,7 @@ assets:
- single
- sound
- fonts
- pack
- locales
only:
- tags
......
No preview for this file type
......@@ -753,7 +753,6 @@ void ClientField::ReplaySwap() {
mainGame->dInfo.isReplaySwapped = !mainGame->dInfo.isReplaySwapped;
std::swap(mainGame->dInfo.lp[0], mainGame->dInfo.lp[1]);
std::swap(mainGame->dInfo.strLP[0], mainGame->dInfo.strLP[1]);
std::swap(mainGame->dInfo.start_lp[0], mainGame->dInfo.start_lp[1]);
std::swap(mainGame->dInfo.hostname, mainGame->dInfo.clientname);
std::swap(mainGame->dInfo.hostname_tag, mainGame->dInfo.clientname_tag);
RefreshCardCountDisplay();
......
......@@ -148,6 +148,7 @@ public:
virtual bool OnCommonEvent(const irr::SEvent& event);
void GetHoverField(int x, int y);
void ShowMenu(int flag, int x, int y);
void HideMenu();
void UpdateChainButtons();
void ShowCancelOrFinishButton(int buttonOp);
void SetShowMark(ClientCard* pcard, bool enable);
......
......@@ -11,7 +11,6 @@ DataManager dataManager;
bool DataManager::LoadDB(const wchar_t* wfile) {
char file[256];
wchar_t strBuffer[4096];
BufferIO::EncodeUTF8(wfile, file);
#ifdef _WIN32
IReadFile* reader = FileSystem->createAndOpenFile(wfile);
......@@ -37,6 +36,7 @@ bool DataManager::LoadDB(const wchar_t* wfile) {
return Error(&db);
CardDataC cd;
CardString cs;
wchar_t strBuffer[4096];
int step = 0;
do {
step = sqlite3_step(pStmt);
......@@ -94,7 +94,7 @@ bool DataManager::LoadStrings(const char* file) {
ReadStringConfLine(linebuf);
}
fclose(fp);
for(int i = 0; i < 255; ++i)
for(int i = 0; i < 301; ++i)
myswprintf(numStrings[i], L"%d", i);
return true;
}
......
......@@ -43,7 +43,7 @@ public:
std::unordered_map<unsigned int, std::wstring> _setnameStrings;
std::unordered_map<unsigned int, std::wstring> _sysStrings;
wchar_t numStrings[256][4];
wchar_t numStrings[301][4];
wchar_t numBuffer[6];
wchar_t attBuffer[128];
wchar_t racBuffer[128];
......
......@@ -90,6 +90,7 @@ void DeckBuilder::Initialize() {
prev_deck = mainGame->cbDBDecks->getSelected();
prev_category = mainGame->cbDBCategory->getSelected();
RefreshReadonly(prev_category);
RefreshPackListScroll();
prev_operation = 0;
prev_sel = -1;
is_modified = false;
......@@ -116,6 +117,8 @@ void DeckBuilder::Terminate() {
mainGame->ClearTextures();
mainGame->showingcode = 0;
mainGame->scrFilter->setVisible(false);
mainGame->scrPackCards->setVisible(false);
mainGame->scrPackCards->setPos(0);
int catesel = mainGame->cbDBCategory->getSelected();
if(catesel >= 0)
BufferIO::CopyWStr(mainGame->cbDBCategory->getItem(catesel), mainGame->gameConf.lastcategory, 64);
......@@ -1040,7 +1043,8 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
wchar_t catepath[256];
deckManager.GetCategoryPath(catepath, mainGame->lstCategories->getSelected(), mainGame->lstCategories->getListItem(mainGame->lstCategories->getSelected()));
myswprintf(filepath, L"%ls/%ls.ydk", catepath, mainGame->lstDecks->getListItem(decksel));
deckManager.LoadDeck(filepath);
deckManager.LoadDeck(filepath, showing_pack);
RefreshPackListScroll();
prev_deck = decksel;
break;
}
......@@ -1062,6 +1066,8 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
if(hovered_pos == 0 || hovered_seq == -1)
break;
click_pos = hovered_pos;
if(readonly)
break;
dragx = event.MouseInput.X;
dragy = event.MouseInput.Y;
draging_pointer = dataManager.GetCodePointer(hovered_code);
......@@ -1143,6 +1149,8 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
if(!is_draging) {
if(hovered_pos == 0 || hovered_seq == -1)
break;
if(readonly)
break;
soundManager.PlaySoundEffect(SOUND_CARD_DROP);
if(hovered_pos == 1) {
pop_main(hovered_seq);
......@@ -1182,6 +1190,8 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
break;
if (hovered_pos == 0 || hovered_seq == -1)
break;
if (readonly)
break;
if (is_draging)
break;
auto pointer = dataManager.GetCodePointer(hovered_code);
......@@ -1265,7 +1275,33 @@ void DeckBuilder::GetHoveredCard() {
int y = pos.Y;
is_lastcard = 0;
if(x >= 314 && x <= 794) {
if(y >= 164 && y <= 435) {
if(showing_pack) {
if((x <= 772 || !mainGame->scrPackCards->isVisible()) && y >= 164 && y <= 624) {
int mainsize = deckManager.current_deck.main.size();
int lx = 10;
int dy = 68;
if(mainsize > 10 * 7)
lx = 11;
if(mainsize > 11 * 7)
lx = 12;
if(mainsize > 60)
dy = 66;
int px;
int py = (y - 164) / dy;
hovered_pos = 1;
if(x >= 750)
px = lx - 1;
else
px = (x - 314) * (lx - 1) / (mainGame->scrPackCards->isVisible() ? 414.0f : 436.0f);
hovered_seq = py * lx + px + mainGame->scrPackCards->getPos() * lx;
if(hovered_seq >= mainsize) {
hovered_seq = -1;
hovered_code = 0;
} else {
hovered_code = deckManager.current_deck.main[hovered_seq]->first;
}
}
} else if(y >= 164 && y <= 435) {
int lx = 10, px, py = (y - 164) / 68;
hovered_pos = 1;
if(deckManager.current_deck.main.size() > 40)
......@@ -1612,21 +1648,17 @@ void DeckBuilder::RefreshDeckList() {
wchar_t catepath[256];
deckManager.GetCategoryPath(catepath, lstCategories->getSelected(), lstCategories->getListItem(lstCategories->getSelected()));
lstDecks->clear();
FileSystem::TraversalDir(catepath, [lstDecks](const wchar_t* name, bool isdir) {
if(!isdir && wcsrchr(name, '.') && !mywcsncasecmp(wcsrchr(name, '.'), L".ydk", 4)) {
size_t len = wcslen(name);
wchar_t deckname[256];
wcsncpy(deckname, name, len - 4);
deckname[len - 4] = 0;
lstDecks->addItem(deckname);
}
});
mainGame->RefreshDeck(catepath, [lstDecks](const wchar_t* item) { lstDecks->addItem(item); });
}
void DeckBuilder::RefreshReadonly(int catesel) {
bool hasDeck = mainGame->cbDBDecks->getItemCount() != 0;
readonly = catesel < 2;
showing_pack = catesel == 0;
mainGame->btnSaveDeck->setEnabled(!readonly);
mainGame->btnSaveDeckAs->setEnabled(!readonly);
mainGame->btnClearDeck->setEnabled(!readonly);
mainGame->btnShuffleDeck->setEnabled(!readonly);
mainGame->btnSortDeck->setEnabled(!readonly);
mainGame->btnDeleteDeck->setEnabled(hasDeck && !readonly);
mainGame->btnRenameCategory->setEnabled(catesel > 3);
mainGame->btnDeleteCategory->setEnabled(catesel > 3);
......@@ -1636,11 +1668,26 @@ void DeckBuilder::RefreshReadonly(int catesel) {
mainGame->btnMoveDeck->setEnabled(hasDeck && !readonly);
mainGame->btnCopyDeck->setEnabled(hasDeck);
}
void DeckBuilder::RefreshPackListScroll() {
if(showing_pack) {
mainGame->scrPackCards->setPos(0);
int mainsize = deckManager.current_deck.main.size();
if(mainsize <= 7 * 12) {
mainGame->scrPackCards->setVisible(false);
} else {
mainGame->scrPackCards->setVisible(true);
mainGame->scrPackCards->setMax((int)ceil(((float)mainsize - 7 * 12) / 12.0f));
}
} else {
mainGame->scrPackCards->setVisible(false);
mainGame->scrPackCards->setPos(0);
}
}
void DeckBuilder::ChangeCategory(int catesel) {
mainGame->RefreshDeck(mainGame->cbDBCategory, mainGame->cbDBDecks);
mainGame->cbDBDecks->setSelected(0);
deckManager.LoadDeck(mainGame->cbDBCategory, mainGame->cbDBDecks);
RefreshReadonly(catesel);
deckManager.LoadDeck(mainGame->cbDBCategory, mainGame->cbDBDecks);
is_modified = false;
prev_category = catesel;
prev_deck = 0;
......@@ -1660,7 +1707,7 @@ void DeckBuilder::ShowDeckManage() {
if(isdir) {
lstCategories->addItem(name);
}
});
});
lstCategories->setSelected(prev_category);
RefreshDeckList();
RefreshReadonly(prev_category);
......
......@@ -24,6 +24,7 @@ public:
void RefreshDeckList();
void RefreshReadonly(int catesel);
void RefreshPackListScroll();
void ChangeCategory(int catesel);
void ShowDeckManage();
void ShowBigCard(int code, float zoom);
......@@ -77,11 +78,13 @@ public:
int prev_sel;
bool is_modified;
bool readonly;
bool showing_pack;
mt19937 rnd;
const std::unordered_map<int, int>* filterList;
std::vector<code_pointer> results;
wchar_t result_string[8];
std::vector<std::wstring> expansionPacks;
};
}
......
......@@ -6,6 +6,7 @@
namespace ygo {
char DeckManager::deckBuffer[0x10000];
DeckManager deckManager;
void DeckManager::LoadLFListSingle(const char* path) {
......@@ -143,7 +144,7 @@ int DeckManager::CheckDeck(Deck& deck, int lfhash, int rule) {
}
return 0;
}
int DeckManager::LoadDeck(Deck& deck, int* dbuf, int mainc, int sidec) {
int DeckManager::LoadDeck(Deck& deck, int* dbuf, int mainc, int sidec, bool is_packlist) {
deck.clear();
int code;
int errorcode = 0;
......@@ -156,6 +157,10 @@ int DeckManager::LoadDeck(Deck& deck, int* dbuf, int mainc, int sidec) {
}
if(cd.type & TYPE_TOKEN)
continue;
else if(is_packlist) {
deck.main.push_back(dataManager.GetCodePointer(code));
continue;
}
else if(cd.type & (TYPE_FUSION | TYPE_SYNCHRO | TYPE_XYZ | TYPE_LINK)) {
if(deck.extra.size() >= YGOPRO_MAX_EXTRA)
continue;
......@@ -241,7 +246,11 @@ void DeckManager::GetDeckFile(wchar_t* ret, irr::gui::IGUIComboBox* cbCategory,
bool DeckManager::LoadDeck(irr::gui::IGUIComboBox* cbCategory, irr::gui::IGUIComboBox* cbDeck) {
wchar_t filepath[256];
GetDeckFile(filepath, cbCategory, cbDeck);
return LoadDeck(filepath);
bool is_packlist = cbCategory->getSelected() == 0;
bool res = LoadDeck(filepath, is_packlist);
if(res && mainGame->is_building)
mainGame->deckBuilder.RefreshPackListScroll();
return res;
}
FILE* DeckManager::OpenDeckFile(const wchar_t* file, const char* mode) {
#ifdef WIN32
......@@ -253,20 +262,47 @@ FILE* DeckManager::OpenDeckFile(const wchar_t* file, const char* mode) {
#endif
return fp;
}
bool DeckManager::LoadDeck(const wchar_t* file) {
int sp = 0, ct = 0, mainc = 0, sidec = 0, code;
FILE* fp = OpenDeckFile(file, "r");
if(!fp) {
IReadFile* DeckManager::OpenDeckReader(const wchar_t* file) {
#ifdef WIN32
IReadFile* reader = dataManager.FileSystem->createAndOpenFile(file);
#else
char file2[256];
BufferIO::EncodeUTF8(file, file2);
IReadFile* reader = dataManager.FileSystem->createAndOpenFile(file2);
#endif
return reader;
}
bool DeckManager::LoadDeck(const wchar_t* file, bool is_packlist) {
IReadFile* reader = OpenDeckReader(file);
if(!reader) {
wchar_t localfile[64];
myswprintf(localfile, L"./deck/%ls.ydk", file);
fp = OpenDeckFile(localfile, "r");
reader = OpenDeckReader(localfile);
}
if(!fp)
if(!reader && !mywcsncasecmp(file, L"./pack", 6)) {
wchar_t zipfile[64];
myswprintf(zipfile, L"%ls", file + 2);
reader = OpenDeckReader(zipfile);
}
if(!reader)
return false;
int cardlist[128];
size_t size = reader->getSize();
if(size >= 0x20000) {
reader->drop();
return false;
}
memset(deckBuffer, 0, sizeof(deckBuffer));
reader->read(deckBuffer, size);
reader->drop();
std::istringstream deckStream(deckBuffer);
return LoadDeck(&deckStream, is_packlist);
}
bool DeckManager::LoadDeck(std::istringstream* deckStream, bool is_packlist) {
int sp = 0, ct = 0, mainc = 0, sidec = 0, code;
int cardlist[300];
bool is_side = false;
char linebuf[256];
while(fgets(linebuf, 256, fp) && ct < 128) {
std::string linebuf;
while(std::getline(*deckStream, linebuf) && ct < 300) {
if(linebuf[0] == '!') {
is_side = true;
continue;
......@@ -276,14 +312,13 @@ bool DeckManager::LoadDeck(const wchar_t* file) {
sp = 0;
while(linebuf[sp] >= '0' && linebuf[sp] <= '9') sp++;
linebuf[sp] = 0;
code = atoi(linebuf);
code = std::stoi(linebuf);
cardlist[ct++] = code;
if(is_side) sidec++;
else mainc++;
}
fclose(fp);
LoadDeck(current_deck, cardlist, mainc, sidec);
return true;
LoadDeck(current_deck, cardlist, mainc, sidec, is_packlist);
return true; // the above LoadDeck has return value but we ignore it here for now
}
bool DeckManager::SaveDeck(Deck& deck, const wchar_t* file) {
if(!FileSystem::IsDirExists(L"./deck") && !FileSystem::MakeDir(L"./deck"))
......
......@@ -5,6 +5,7 @@
#include "client_card.h"
#include <unordered_map>
#include <vector>
#include <sstream>
namespace ygo {
......@@ -35,18 +36,22 @@ public:
Deck current_deck;
std::vector<LFList> _lfList;
static char deckBuffer[0x10000];
void LoadLFListSingle(const char* path);
void LoadLFList();
const wchar_t* GetLFListName(int lfhash);
const std::unordered_map<int, int>* GetLFListContent(int lfhash);
int CheckDeck(Deck& deck, int lfhash, int rule);
int LoadDeck(Deck& deck, int* dbuf, int mainc, int sidec);
int LoadDeck(Deck& deck, int* dbuf, int mainc, int sidec, bool is_packlist = false);
bool LoadSide(Deck& deck, int* dbuf, int mainc, int sidec);
void GetCategoryPath(wchar_t* ret, int index, const wchar_t* text);
void GetDeckFile(wchar_t* ret, irr::gui::IGUIComboBox* cbCategory, irr::gui::IGUIComboBox* cbDeck);
bool LoadDeck(irr::gui::IGUIComboBox* cbCategory, irr::gui::IGUIComboBox* cbDeck);
FILE* OpenDeckFile(const wchar_t * file, const char * mode);
bool LoadDeck(const wchar_t* file);
FILE* OpenDeckFile(const wchar_t* file, const char* mode);
IReadFile* OpenDeckReader(const wchar_t* file);
bool LoadDeck(const wchar_t* file, bool is_packlist = false);
bool LoadDeck(std::istringstream* deckStream, bool is_packlist = false);
bool SaveDeck(Deck& deck, const wchar_t* file);
bool DeleteDeck(const wchar_t* file);
wchar_t DeckFormatBuffer[128];
......
This diff is collapsed.
This diff is collapsed.
......@@ -4,6 +4,7 @@
#include "config.h"
#include <vector>
#include <set>
#include <utility>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
......@@ -16,6 +17,45 @@
namespace ygo {
class HostResult {
public:
unsigned int host;
unsigned short port;
bool isValid() {
return host > 0 && port > 0;
}
HostResult() {
host = 0;
port = 0;
}
};
#ifndef _WIN32
#include <resolv.h>
#include <arpa/nameser.h>
#include <arpa/nameser_compat.h>
class RetrivedSRVRecord {
public:
bool valid;
unsigned short priority;
unsigned short weight;
unsigned short port;
char host[100];
RetrivedSRVRecord(ns_msg nsMsg, int i) {
valid = false;
ns_rr rr;
if (ns_parserr(&nsMsg, ns_s_an, i, &rr) < 0 || ns_rr_type(rr) != T_SRV)
return;
priority = ns_get16(ns_rr_rdata(rr));
weight = ns_get16(ns_rr_rdata(rr) + NS_INT16SZ);
port = ns_get16(ns_rr_rdata(rr) + 2 * NS_INT16SZ);
if (dn_expand(ns_msg_base(nsMsg), ns_msg_end(nsMsg), ns_rr_rdata(rr) + 3 * NS_INT16SZ, host, sizeof(host)) < 0)
return;
valid = true;
}
};
#endif
class DuelClient {
private:
static unsigned int connect_state;
......@@ -55,6 +95,10 @@ public:
static void SetResponseI(int respI);
static void SetResponseB(void* respB, unsigned char len);
static void SendResponse();
static unsigned int LookupHost(char *host);
static bool LookupSRV(char *hostname, HostResult* result);
static bool CheckHostnameSplitter(char *hostname, HostResult *result);
static HostResult ParseHost(char *hostname, unsigned short port);
static void SendPacketToServer(unsigned char proto) {
char* p = duel_client_write;
BufferIO::WriteInt16(p, 1);
......@@ -90,7 +134,7 @@ protected:
static bool is_refreshing;
static int match_kill;
static event* resp_event;
static std::set<unsigned int> remotes;
static std::set<std::pair<unsigned int, unsigned short>> remotes;
public:
static std::vector<HostPacket> hosts;
static std::vector<std::wstring> hosts_srvpro;
......@@ -99,7 +143,6 @@ public:
static int RefreshThread(event_base* broadev);
static void BroadcastReply(evutil_socket_t fd, short events, void* arg);
};
}
#endif //DUELCLIENT_H
......@@ -371,7 +371,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
}
case BUTTON_CMD_ACTIVATE:
case BUTTON_CMD_RESET: {
mainGame->wCmdMenu->setVisible(false);
HideMenu();
ShowCancelOrFinishButton(0);
if(!list_command) {
if(!menu_card)
......@@ -457,7 +457,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
break;
}
case BUTTON_CMD_SUMMON: {
mainGame->wCmdMenu->setVisible(false);
HideMenu();
if(!menu_card)
break;
for(size_t i = 0; i < summonable_cards.size(); ++i) {
......@@ -471,7 +471,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
break;
}
case BUTTON_CMD_SPSUMMON: {
mainGame->wCmdMenu->setVisible(false);
HideMenu();
if(!list_command) {
if(!menu_card)
break;
......@@ -514,7 +514,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
break;
}
case BUTTON_CMD_MSET: {
mainGame->wCmdMenu->setVisible(false);
HideMenu();
if(!menu_card)
break;
for(size_t i = 0; i < msetable_cards.size(); ++i) {
......@@ -535,7 +535,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
break;
}
case BUTTON_CMD_SSET: {
mainGame->wCmdMenu->setVisible(false);
HideMenu();
if(!menu_card)
break;
for(size_t i = 0; i < ssetable_cards.size(); ++i) {
......@@ -548,7 +548,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
break;
}
case BUTTON_CMD_REPOS: {
mainGame->wCmdMenu->setVisible(false);
HideMenu();
if(!menu_card)
break;
for(size_t i = 0; i < reposable_cards.size(); ++i) {
......@@ -561,7 +561,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
break;
}
case BUTTON_CMD_ATTACK: {
mainGame->wCmdMenu->setVisible(false);
HideMenu();
if(!menu_card)
break;
for(size_t i = 0; i < attackable_cards.size(); ++i) {
......@@ -574,7 +574,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
break;
}
case BUTTON_CMD_SHOWLIST: {
mainGame->wCmdMenu->setVisible(false);
HideMenu();
selectable_cards.clear();
wchar_t formatBuffer[2048];
switch(command_location) {
......@@ -1092,7 +1092,11 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
UpdateChainButtons();
}
if(mainGame->wCmdMenu->isVisible() && !mainGame->wCmdMenu->getRelativePosition().isPointInside(mousepos))
mainGame->wCmdMenu->setVisible(false);
HideMenu();
if(mainGame->btnBP->isVisible() && mainGame->btnBP->getAbsolutePosition().isPointInside(mousepos))
break;
if(mainGame->btnM2->isVisible() && mainGame->btnM2->getAbsolutePosition().isPointInside(mousepos))
break;
if(panel && panel->isVisible())
break;
GetHoverField(x, y);
......@@ -1498,7 +1502,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
UpdateChainButtons();
}
mainGame->HideElement(mainGame->wSurrender);
mainGame->wCmdMenu->setVisible(false);
HideMenu();
if(mainGame->fadingList.size())
break;
CancelOrFinish();
......@@ -1581,7 +1585,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
}
if(mcard) {
if(mcard != menu_card)
mainGame->wCmdMenu->setVisible(false);
HideMenu();
if(hovered_location == LOCATION_HAND) {
mcard->is_hovered = true;
MoveCard(mcard, 5);
......@@ -2354,7 +2358,7 @@ void ClientField::GetHoverField(int x, int y) {
}
void ClientField::ShowMenu(int flag, int x, int y) {
if(!flag) {
mainGame->wCmdMenu->setVisible(false);
HideMenu();
return;
}
menu_card = clicked_card;
......@@ -2422,11 +2426,20 @@ void ClientField::ShowMenu(int flag, int x, int y) {
} else mainGame->btnReset->setVisible(false);
panel = mainGame->wCmdMenu;
mainGame->wCmdMenu->setVisible(true);
mainGame->btnBP->setEnabled(false);
mainGame->btnM2->setEnabled(false);
mainGame->btnEP->setEnabled(false);
if(mainGame->gameConf.resize_popup_menu)
mainGame->wCmdMenu->setRelativePosition(mainGame->Resize(x - 20, y - 20, x + 80, y - 20, 0, -height, 0, 0));
else
mainGame->wCmdMenu->setRelativePosition(mainGame->Resize(x, y, x, y, -20, -(20 + height), 80, -20));
}
void ClientField::HideMenu() {
mainGame->wCmdMenu->setVisible(false);
mainGame->btnBP->setEnabled(true);
mainGame->btnM2->setEnabled(true);
mainGame->btnEP->setEnabled(true);
}
void ClientField::UpdateChainButtons() {
if(mainGame->btnChainAlways->isVisible()) {
mainGame->btnChainIgnore->setPressed(mainGame->ignore_chain);
......
......@@ -12,7 +12,7 @@
#include <sstream>
#include <regex>
unsigned short PRO_VERSION = 0x1353;
unsigned short PRO_VERSION = 0x1354;
namespace ygo {
......@@ -181,7 +181,7 @@ bool Game::Initialize() {
SetWindowsIcon();
//main menu
wchar_t strbuf[256];
myswprintf(strbuf, L"KoishiPro %X.0%X.%X Setsuna", PRO_VERSION >> 12, (PRO_VERSION >> 4) & 0xff, PRO_VERSION & 0xf);
myswprintf(strbuf, L"KoishiPro %X.0%X.%X SUPERNOVA", PRO_VERSION >> 12, (PRO_VERSION >> 4) & 0xff, PRO_VERSION & 0xf);
wMainMenu = env->addWindow(rect<s32>(370, 200, 650, 415), false, strbuf);
wMainMenu->getCloseButton()->setVisible(false);
btnLanMode = env->addButton(rect<s32>(10, 30, 270, 60), wMainMenu, BUTTON_LAN_MODE, dataManager.GetSysString(1200));
......@@ -204,7 +204,12 @@ bool Game::Initialize() {
env->addStaticText(dataManager.GetSysString(1221), rect<s32>(10, 360, 220, 380), false, false, wLanWindow);
ebJoinHost = env->addEditBox(gameConf.lasthost, rect<s32>(110, 355, 350, 380), true, wLanWindow);
ebJoinHost->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
ebJoinPort = env->addEditBox(gameConf.lastport, rect<s32>(360, 355, 420, 380), true, wLanWindow);
wchar_t lastPortText[6];
if(gameConf.lastport)
myswprintf(lastPortText, L"%d", gameConf.lastport);
else
myswprintf(lastPortText, L"");
ebJoinPort = env->addEditBox(lastPortText, rect<s32>(360, 355, 420, 380), true, wLanWindow);
ebJoinPort->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
env->addStaticText(dataManager.GetSysString(1222), rect<s32>(10, 390, 220, 410), false, false, wLanWindow);
ebJoinPass = env->addEditBox(gameConf.roompass, rect<s32>(110, 385, 420, 410), true, wLanWindow);
......@@ -393,6 +398,9 @@ bool Game::Initialize() {
chkWaitChain = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260, posY + 25), tabHelper, -1, dataManager.GetSysString(1277));
chkWaitChain->setChecked(gameConf.chkWaitChain != 0);
posY += 30;
chkDefaultShowChain = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260, posY + 25), tabHelper, -1, dataManager.GetSysString(1354));
chkDefaultShowChain->setChecked(gameConf.chkDefaultShowChain != 0);
posY += 30;
chkQuickAnimation = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260, posY + 25), tabHelper, CHECKBOX_QUICK_ANIMATION, dataManager.GetSysString(1299));
chkQuickAnimation->setChecked(gameConf.quick_animation != 0);
posY += 30;
......@@ -682,6 +690,10 @@ bool Game::Initialize() {
cbDMCategory->setMaxSelectionRows(10);
btnDMOK = env->addButton(rect<s32>(70, 80, 140, 105), wDMQuery, BUTTON_DM_OK, dataManager.GetSysString(1211));
btnDMCancel = env->addButton(rect<s32>(170, 80, 240, 105), wDMQuery, BUTTON_DM_CANCEL, dataManager.GetSysString(1212));
scrPackCards = env->addScrollBar(false, recti(775, 161, 795, 629), 0, SCROLL_FILTER);
scrPackCards->setLargeStep(1);
scrPackCards->setSmallStep(1);
scrPackCards->setVisible(false);
stDBCategory = env->addStaticText(dataManager.GetSysString(1300), rect<s32>(10, 9, 100, 29), false, false, wDeckEdit);
cbDBCategory = env->addComboBox(rect<s32>(80, 5, 220, 30), wDeckEdit, COMBOBOX_DBCATEGORY);
......@@ -1216,6 +1228,9 @@ void Game::LoadExpansions() {
#endif
dataManager.LoadStrings(reader);
}
if(wcsrchr(fname, '.') && !mywcsncasecmp(wcsrchr(fname, '.'), L".ydk", 4)) {
deckBuilder.expansionPacks.push_back(fname);
}
}
}
}
......@@ -1250,19 +1265,29 @@ void Game::RefreshCategoryDeck(irr::gui::IGUIComboBox* cbCategory, irr::gui::IGU
}
}
void Game::RefreshDeck(irr::gui::IGUIComboBox* cbCategory, irr::gui::IGUIComboBox* cbDeck) {
if(cbCategory != cbDBCategory && cbCategory->getSelected() == 0) {
// can't use pack list in duel
cbDeck->clear();
return;
}
wchar_t catepath[256];
deckManager.GetCategoryPath(catepath, cbCategory->getSelected(), cbCategory->getText());
RefreshDeck(catepath, cbDeck);
}
void Game::RefreshDeck(const wchar_t* deckpath, irr::gui::IGUIComboBox* cbDeck) {
cbDeck->clear();
FileSystem::TraversalDir(deckpath, [cbDeck](const wchar_t* name, bool isdir) {
RefreshDeck(catepath, [cbDeck](const wchar_t* item) { cbDeck->addItem(item); });
}
void Game::RefreshDeck(const wchar_t* deckpath, const std::function<void(const wchar_t*)>& additem) {
if(!mywcsncasecmp(deckpath, L"./pack", 6)) {
for(auto pack : deckBuilder.expansionPacks) {
additem(pack.substr(5, pack.size() - 9).c_str());
}
}
FileSystem::TraversalDir(deckpath, [additem](const wchar_t* name, bool isdir) {
if(!isdir && wcsrchr(name, '.') && !mywcsncasecmp(wcsrchr(name, '.'), L".ydk", 4)) {
size_t len = wcslen(name);
wchar_t deckname[256];
wcsncpy(deckname, name, len - 4);
deckname[len - 4] = 0;
cbDeck->addItem(deckname);
additem(deckname);
}
});
}
......@@ -1391,8 +1416,7 @@ bool Game::LoadConfigFromFile(const char* file) {
BufferIO::DecodeUTF8(valbuf, wstr);
BufferIO::CopyWStr(wstr, gameConf.lasthost, 100);
} else if(!strcmp(strbuf, "lastport")) {
BufferIO::DecodeUTF8(valbuf, wstr);
BufferIO::CopyWStr(wstr, gameConf.lastport, 20);
gameConf.lastport = (unsigned short)atoi(valbuf);
} else if(!strcmp(strbuf, "roompass")) {
BufferIO::DecodeUTF8(valbuf, wstr);
BufferIO::CopyWStr(wstr, gameConf.roompass, 20);
......@@ -1406,6 +1430,8 @@ bool Game::LoadConfigFromFile(const char* file) {
gameConf.chkAutoChain = atoi(valbuf);
} else if(!strcmp(strbuf, "waitchain")) {
gameConf.chkWaitChain = atoi(valbuf);
} else if(!strcmp(strbuf, "showchain")) {
gameConf.chkDefaultShowChain = atoi(valbuf);
} else if(!strcmp(strbuf, "mute_opponent")) {
gameConf.chkIgnore1 = atoi(valbuf);
} else if(!strcmp(strbuf, "mute_spectators")) {
......@@ -1514,7 +1540,7 @@ void Game::LoadConfig() {
gameConf.numfont[0] = 0;
gameConf.textfont[0] = 0;
gameConf.lasthost[0] = 0;
gameConf.lastport[0] = 0;
gameConf.lastport = 0;
gameConf.roompass[0] = 0;
//settings
gameConf.chkMAutoPos = 0;
......@@ -1522,6 +1548,7 @@ void Game::LoadConfig() {
gameConf.chkRandomPos = 0;
gameConf.chkAutoChain = 0;
gameConf.chkWaitChain = 0;
gameConf.chkDefaultShowChain = 0;
gameConf.chkIgnore1 = 0;
gameConf.chkIgnore2 = 0;
gameConf.use_lflist = 1;
......@@ -1648,14 +1675,14 @@ void Game::SaveConfig() {
fprintf(fp, "serverport = %d\n", gameConf.serverport);
BufferIO::EncodeUTF8(gameConf.lasthost, linebuf);
fprintf(fp, "lasthost = %s\n", linebuf);
BufferIO::EncodeUTF8(gameConf.lastport, linebuf);
fprintf(fp, "lastport = %s\n", linebuf);
fprintf(fp, "lastport = %d\n", gameConf.lastport);
//settings
fprintf(fp, "automonsterpos = %d\n", (chkMAutoPos->isChecked() ? 1 : 0));
fprintf(fp, "autospellpos = %d\n", (chkSTAutoPos->isChecked() ? 1 : 0));
fprintf(fp, "randompos = %d\n", (chkRandomPos->isChecked() ? 1 : 0));
fprintf(fp, "autochain = %d\n", (chkAutoChain->isChecked() ? 1 : 0));
fprintf(fp, "waitchain = %d\n", (chkWaitChain->isChecked() ? 1 : 0));
fprintf(fp, "showchain = %d\n", (chkDefaultShowChain->isChecked() ? 1 : 0));
fprintf(fp, "mute_opponent = %d\n", (chkIgnore1->isChecked() ? 1 : 0));
fprintf(fp, "mute_spectators = %d\n", (chkIgnore2->isChecked() ? 1 : 0));
fprintf(fp, "use_lflist = %d\n", gameConf.use_lflist);
......@@ -2039,6 +2066,7 @@ void Game::OnResize() {
cbDBCategory->setRelativePosition(Resize(80, 5, 220, 30));
btnManageDeck->setRelativePosition(Resize(225, 5, 290, 30));
wDeckManage->setRelativePosition(ResizeWin(310, 135, 800, 465));
scrPackCards->setRelativePosition(Resize(775, 161, 795, 629));
wSort->setRelativePosition(Resize(930, 132, 1020, 156));
cbSortType->setRelativePosition(Resize(10, 2, 85, 22));
......
......@@ -19,7 +19,7 @@ struct Config {
unsigned short serverport;
unsigned char textfontsize;
wchar_t lasthost[100];
wchar_t lastport[10];
unsigned short lastport;
wchar_t nickname[20];
wchar_t gamename[20];
wchar_t lastcategory[64];
......@@ -35,6 +35,7 @@ struct Config {
int chkRandomPos;
int chkAutoChain;
int chkWaitChain;
int chkDefaultShowChain;
int chkIgnore1;
int chkIgnore2;
int use_lflist;
......@@ -81,7 +82,7 @@ struct DuelInfo {
bool is_swapped;
bool tag_player[2];
int lp[2];
int start_lp[2];
int start_lp;
int card_count[2];
int total_attack[2];
int duel_rule;
......@@ -141,7 +142,7 @@ public:
void LoadExpansions();
void RefreshCategoryDeck(irr::gui::IGUIComboBox* cbCategory, irr::gui::IGUIComboBox* cbDeck, bool selectlastused = true);
void RefreshDeck(irr::gui::IGUIComboBox* cbCategory, irr::gui::IGUIComboBox* cbDeck);
void RefreshDeck(const wchar_t* deckpath, irr::gui::IGUIComboBox* cbDeck);
void RefreshDeck(const wchar_t* deckpath, const std::function<void(const wchar_t*)>& additem);
void RefreshReplay();
void RefreshSingleplay();
void RefreshBot();
......@@ -324,6 +325,7 @@ public:
irr::gui::IGUICheckBox* chkRandomPos;
irr::gui::IGUICheckBox* chkAutoChain;
irr::gui::IGUICheckBox* chkWaitChain;
irr::gui::IGUICheckBox* chkDefaultShowChain;
irr::gui::IGUICheckBox* chkQuickAnimation;
irr::gui::IGUICheckBox* chkAutoSaveReplay;
irr::gui::IGUICheckBox* chkDrawSingleChain;
......@@ -575,6 +577,7 @@ public:
irr::gui::IGUIComboBox* cbDMCategory;
irr::gui::IGUIButton* btnDMOK;
irr::gui::IGUIButton* btnDMCancel;
irr::gui::IGUIScrollBar* scrPackCards;
//filter
irr::gui::IGUIStaticText* wFilter;
irr::gui::IGUIScrollBar* scrFilter;
......
......@@ -81,6 +81,7 @@ int main(int argc, char* argv[]) {
bool keep_on_return = false;
bool deckCategorySpecified = false;
bool portSpecified = false;
for(int i = 1; i < wargc; ++i) {
if(wargv[i][0] == L'-' && wargv[i][1] == L'e' && wargv[i][2] != L'\0') {
ygo::dataManager.LoadDB(&wargv[i][2]);
......@@ -99,13 +100,25 @@ int main(int argc, char* argv[]) {
continue;
} else if(!wcscmp(wargv[i], L"-h")) { // Host address
++i;
if(i < wargc)
if(i < wargc) {
ygo::mainGame->ebJoinHost->setText(wargv[i]);
if(!portSpecified)
ygo::mainGame->ebJoinPort->setText(L"");
}
continue;
} else if(!wcscmp(wargv[i], L"-p")) { // host Port
++i;
if(i < wargc)
ygo::mainGame->ebJoinPort->setText(wargv[i]);
if(i < wargc) {
portSpecified = true;
auto port = _wtoi(wargv[i]);
if(port) {
wchar_t portStr[6];
myswprintf(portStr, L"%d", port);
ygo::mainGame->ebJoinPort->setText(portStr);
} else {
ygo::mainGame->ebJoinPort->setText(L"");
}
}
continue;
} else if(!wcscmp(wargv[i], L"-w")) { // host passWord
++i;
......
......@@ -65,46 +65,27 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
case BUTTON_JOIN_HOST: {
bot_mode = false;
mainGame->TrimText(mainGame->ebJoinHost);
mainGame->TrimText(mainGame->ebJoinPort);
char ip[20];
char hostname[100];
const wchar_t* pstr = mainGame->ebJoinHost->getText();
BufferIO::CopyWStr(pstr, ip, 16);
unsigned int remote_addr = htonl(inet_addr(ip));
if(remote_addr == -1) {
char hostname[100];
char port[6];
BufferIO::CopyWStr(pstr, hostname, 100);
BufferIO::CopyWStr(mainGame->ebJoinPort->getText(), port, 6);
struct evutil_addrinfo hints;
struct evutil_addrinfo *answer = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = EVUTIL_AI_ADDRCONFIG;
int status = evutil_getaddrinfo(hostname, port, &hints, &answer);
if(status != 0) {
mainGame->gMutex.lock();
soundManager.PlaySoundEffect(SOUND_INFO);
mainGame->env->addMessageBox(L"", dataManager.GetSysString(1412));
mainGame->gMutex.unlock();
if (auto_watch_mode) {
BufferIO::CopyWStr(pstr, hostname, 100);
auto port = (unsigned short)_wtoi(mainGame->ebJoinPort->getText());
HostResult remote = DuelClient::ParseHost(hostname, port);
if(!remote.isValid()) {
mainGame->gMutex.lock();
soundManager.PlaySoundEffect(SOUND_INFO);
mainGame->env->addMessageBox(L"", dataManager.GetSysString(1412));
mainGame->gMutex.unlock();
if (auto_watch_mode) {
if(!no_wait_before_exit) {
mainGame->actionSignal.Wait(2000);
}
mainGame->device->closeDevice();
}
break;
} else {
sockaddr_in * sin = ((struct sockaddr_in *)answer->ai_addr);
evutil_inet_ntop(AF_INET, &(sin->sin_addr), ip, 20);
remote_addr = htonl(inet_addr(ip));
mainGame->device->closeDevice();
}
break;
}
unsigned int remote_port = _wtoi(mainGame->ebJoinPort->getText());
BufferIO::CopyWStr(pstr, mainGame->gameConf.lasthost, 100);
BufferIO::CopyWStr(mainGame->ebJoinPort->getText(), mainGame->gameConf.lastport, 20);
if(DuelClient::StartClient(remote_addr, remote_port, false)) {
mainGame->gameConf.lastport = port;
if(DuelClient::StartClient(remote.host, remote.port, false)) {
mainGame->btnCreateHost->setEnabled(false);
mainGame->btnJoinHost->setEnabled(false);
mainGame->btnJoinCancel->setEnabled(false);
......
......@@ -42,6 +42,7 @@ bool NetServer::StartBroadcast() {
SOCKET udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
BOOL opt = TRUE;
setsockopt(udp, SOL_SOCKET, SO_BROADCAST, (const char*)&opt, sizeof(BOOL));
setsockopt(udp, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(BOOL));
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
......
......@@ -11,6 +11,10 @@ project "YGOPro"
links { "ikpmp3" }
end
if BUILD_IKPMP3 then
links { "ikpmp3" }
end
if BUILD_EVENT then
includedirs { "../event/include" }
else
......@@ -62,11 +66,11 @@ project "YGOPro"
filter {}
end
end
links { "opengl32", "ws2_32", "winmm", "gdi32", "kernel32", "user32", "imm32" }
links { "opengl32", "ws2_32", "winmm", "gdi32", "kernel32", "user32", "imm32", "Dnsapi" }
filter "not action:vs*"
buildoptions { "-std=c++14", "-fno-rtti" }
filter "not system:windows"
links { "event_pthreads", "dl", "pthread" }
links { "event_pthreads", "dl", "pthread", "resolv" }
filter "system:macosx"
links { "z" }
defines { "GL_SILENCE_DEPRECATION" }
......
......@@ -177,8 +177,7 @@ bool ReplayMode::StartDuel() {
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.start_lp[0] = start_lp;
mainGame->dInfo.start_lp[1] = start_lp;
mainGame->dInfo.start_lp = 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;
......
......@@ -488,6 +488,11 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
RefreshExtra(0);
RefreshExtra(1);
start_duel(pduel, opt);
if(host_info.time_limit) {
time_elapsed = 0;
timeval timeout = { 1, 0 };
event_add(etimer, &timeout);
}
Process();
}
void SingleDuel::Process() {
......@@ -1429,7 +1434,7 @@ void SingleDuel::GetResponse(DuelPlayer* dp, void* pdata, unsigned int len) {
if(time_limit[dp->type] >= time_elapsed)
time_limit[dp->type] -= time_elapsed;
else time_limit[dp->type] = 0;
event_del(etimer);
time_elapsed = 0;
}
Process();
}
......@@ -1446,6 +1451,7 @@ void SingleDuel::EndDuel() {
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
end_duel(pduel);
event_del(etimer);
pduel = 0;
}
void SingleDuel::WaitforResponse(int playerid) {
......@@ -1468,9 +1474,8 @@ void SingleDuel::TimeConfirm(DuelPlayer* dp) {
if(dp->type != last_response)
return;
players[last_response]->state = CTOS_RESPONSE;
time_elapsed = 0;
timeval timeout = {1, 0};
event_add(etimer, &timeout);
if(time_elapsed < 10)
time_elapsed = 0;
}
void SingleDuel::RefreshMzone(int player, int flag, int use_cache) {
char query_buffer[0x2000];
......@@ -1590,7 +1595,7 @@ int SingleDuel::MessageHandler(intptr_t fduel, int type) {
void SingleDuel::SingleTimer(evutil_socket_t fd, short events, void* arg) {
SingleDuel* sd = static_cast<SingleDuel*>(arg);
sd->time_elapsed++;
if(sd->time_elapsed >= sd->time_limit[sd->last_response]) {
if(sd->time_elapsed >= sd->time_limit[sd->last_response] || sd->time_limit[sd->last_response] <= 0) {
unsigned char wbuf[3];
uint32 player = sd->last_response;
wbuf[0] = MSG_WIN;
......@@ -1610,7 +1615,10 @@ void SingleDuel::SingleTimer(evutil_socket_t fd, short events, void* arg) {
sd->EndDuel();
sd->DuelEndProc();
event_del(sd->etimer);
return;
}
timeval timeout = { 1, 0 };
event_add(sd->etimer, &timeout);
}
}
......@@ -56,8 +56,8 @@ protected:
unsigned char duel_count;
unsigned char tp_player;
unsigned char match_result[3];
unsigned short time_limit[2];
unsigned short time_elapsed;
short time_limit[2];
short time_elapsed;
};
}
......
......@@ -46,8 +46,7 @@ int SingleMode::SinglePlayThread() {
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.start_lp[0] = start_lp;
mainGame->dInfo.start_lp[1] = start_lp;
mainGame->dInfo.start_lp = start_lp;
myswprintf(mainGame->dInfo.strLP[0], L"%d", mainGame->dInfo.lp[0]);
myswprintf(mainGame->dInfo.strLP[1], L"%d", mainGame->dInfo.lp[1]);
BufferIO::CopyWStr(mainGame->ebNickName->getText(), mainGame->dInfo.hostname, 20);
......
......@@ -484,6 +484,11 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
RefreshExtra(0);
RefreshExtra(1);
start_duel(pduel, opt);
if(host_info.time_limit) {
time_elapsed = 0;
timeval timeout = { 1, 0 };
event_add(etimer, &timeout);
}
Process();
}
void TagDuel::Process() {
......@@ -1527,7 +1532,7 @@ void TagDuel::GetResponse(DuelPlayer* dp, void* pdata, unsigned int len) {
if(time_limit[resp_type] >= time_elapsed)
time_limit[resp_type] -= time_elapsed;
else time_limit[resp_type] = 0;
event_del(etimer);
time_elapsed = 0;
}
Process();
}
......@@ -1546,6 +1551,7 @@ void TagDuel::EndDuel() {
for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit);
end_duel(pduel);
event_del(etimer);
pduel = 0;
}
void TagDuel::WaitforResponse(int playerid) {
......@@ -1572,9 +1578,8 @@ void TagDuel::TimeConfirm(DuelPlayer* dp) {
if(dp != cur_player[last_response])
return;
cur_player[last_response]->state = CTOS_RESPONSE;
time_elapsed = 0;
timeval timeout = {1, 0};
event_add(etimer, &timeout);
if(time_elapsed < 10)
time_elapsed = 0;
}
void TagDuel::RefreshMzone(int player, int flag, int use_cache) {
char query_buffer[0x4000];
......@@ -1723,7 +1728,7 @@ int TagDuel::MessageHandler(intptr_t fduel, int type) {
void TagDuel::TagTimer(evutil_socket_t fd, short events, void* arg) {
TagDuel* sd = static_cast<TagDuel*>(arg);
sd->time_elapsed++;
if(sd->time_elapsed >= sd->time_limit[sd->last_response]) {
if(sd->time_elapsed >= sd->time_limit[sd->last_response] || sd->time_limit[sd->last_response] <= 0) {
unsigned char wbuf[3];
uint32 player = sd->last_response;
wbuf[0] = MSG_WIN;
......@@ -1736,7 +1741,10 @@ void TagDuel::TagTimer(evutil_socket_t fd, short events, void* arg) {
sd->EndDuel();
sd->DuelEndProc();
event_del(sd->etimer);
return;
}
timeval timeout = { 1, 0 };
event_add(sd->etimer, &timeout);
}
}
......@@ -53,8 +53,8 @@ protected:
unsigned char last_response;
Replay last_replay;
unsigned char turn_count;
unsigned short time_limit[2];
unsigned short time_elapsed;
short time_limit[2];
short time_elapsed;
};
}
......
This diff is collapsed.
Subproject commit d71e1ea4fa0564fc49736aa9e7c19afd99210499
Subproject commit f9cd0df0186dcf4ae75b37179e9c835f11061a16
1 ICON "ygopro.ico"
1 VERSIONINFO
FILEVERSION 1, 0, 35, 3
PRODUCTVERSION 1, 0, 35, 3
FILEVERSION 1, 0, 35, 4
PRODUCTVERSION 1, 0, 35, 4
FILEOS 0x4
FILETYPE 0x1
......@@ -16,8 +16,8 @@ VALUE "InternalName", "KoishiPro"
VALUE "LegalCopyright", "Copyright (C) 2022 Nanahira"
VALUE "OriginalFilename", "ygopro.exe"
VALUE "ProductName", "KoishiPro"
VALUE "FileVersion", "Setsuna"
VALUE "ProductVersion", "Setsuna"
VALUE "FileVersion", "SUPERNOVA"
VALUE "ProductVersion", "SUPERNOVA"
END
END
BLOCK "VarFileInfo"
......
......@@ -173,7 +173,7 @@ if USE_IRRKLANG then
IRRKLANG_LIB_DIR = "../irrklang/lib/Win32-visualStudio"
elseif os.istarget("linux") then
IRRKLANG_LIB_DIR = "../irrklang/bin/linux-gcc-64"
IRRKLANG_LINK_RPATH = "-Wl,-rpath=./"
IRRKLANG_LINK_RPATH = "-Wl,-rpath=./lib/"
elseif os.istarget("macosx") then
IRRKLANG_LIB_DIR = "../irrklang/bin/macosx-gcc"
end
......@@ -196,14 +196,17 @@ BUILD_IKPMP3 = USE_IRRKLANG
if GetParam("winxp-support") and os.istarget("windows") then
WINXP_SUPPORT = true
end
if GetParam("mac-arm") and os.istarget("macosx") then
MAC_ARM = true
if os.istarget("macosx") then
MAC_ARM = false
if GetParam("mac-arm") then
MAC_ARM = true
end
end
workspace "YGOPro"
location "build"
language "C++"
objdir "obj"
objdir "obj"
configurations { "Release", "Debug" }
......@@ -252,7 +255,7 @@ workspace "YGOPro"
filter { "configurations:Release", "action:vs*" }
flags { "LinkTimeOptimization" }
staticruntime "On"
disablewarnings { "4244", "4267", "4838", "4577", "4819", "4018", "4996", "4477", "4091", "4828", "4800" }
disablewarnings { "4244", "4267", "4838", "4577", "4819", "4018", "4996", "4477", "4091", "4828", "4800", "6011", "6031", "6054", "6262" }
filter { "configurations:Release", "not action:vs*" }
symbols "On"
......@@ -262,8 +265,7 @@ workspace "YGOPro"
end
filter { "configurations:Debug", "action:vs*" }
defines { "_ITERATOR_DEBUG_LEVEL=0" }
disablewarnings { "4819", "4828" }
disablewarnings { "4819", "4828", "6011", "6031", "6054", "6262" }
filter "action:vs*"
vectorextensions "SSE2"
......
Subproject commit 8e1536d0dd8f08f0cfec0ed723aa1c999f11cac7
Subproject commit 861310196d509332bc25e20d12e492d48e4fa116
......@@ -76,8 +76,8 @@
!system 218 是否使用[%ls]的效果代替支付基本分?
!system 219 是否使用[%ls]的效果代替取除超量素材?
!system 220 是否使用[%ls]的效果代替取除指示物?
!system 221 是否在[%ls]发动[%ls]的诱发效果?
!system 222 是否要发动诱发效果?
!system 221 是否在[%ls]发动[%ls]的诱发效果?
!system 222 是否要发动诱发效果?
!system 223 稍后将询问其他可以发动的效果。
!system 224 已用正规方法特殊召唤
!system 225 叠放于[%ls](%d)下
......@@ -404,6 +404,7 @@
!system 1351 投降
!system 1352 主要信息:
!system 1353 播放起始于回合:
!system 1354 开局默认显示所有时点
!system 1355 是否确定盖放[%ls]?
!system 1356 此操作将放弃对当前卡组的修改,是否继续?
!system 1357 不提示保留对卡组的修改
......@@ -495,6 +496,7 @@
!system 1474 已存在同名分类
!system 1475 已存在同名卡组
!system 1476 删除失败
!system 1477 卡片数:
!system 1481 OCG
!system 1482 TCG
!system 1483 简体中文
......@@ -652,6 +654,9 @@
!counter 0x5f 拼图指示物
!counter 0x60 指示物(北极天熊辐射)
!counter 0x61 指示物(命运的囚人)
!counter 0x62 指示物(逐渐削减的生命)
!counter 0x1063 幻觉指示物
!counter 0x64 G石人指示物
#setnames, using tab for comment
!setname 0x1 正义盟军 AOJ
!setname 0x2 次世代 ジェネクス
......@@ -727,6 +732,7 @@
!setname 0x34 宝玉 宝玉
!setname 0x1034 宝玉兽 宝玉獣
!setname 0x2034 究极宝玉神 究極宝玉神
!setname 0x5034 高等宝玉兽 A宝玉獣
!setname 0x35 魔轰神 魔轟神
!setname 0x36 机甲 マシンナーズ
!setname 0x37 霞之谷 霞の谷
......@@ -1113,7 +1119,7 @@
!setname 0x15d 烙印
!setname 0x15e 降阶魔法 RDM
!setname 0x15f 战吼 ウォークライ
!setname 0x160 质炉 マテリアクトル
!setname 0x160 质炉 マテリアクトル
!setname 0x161 溟界
!setname 0x162 七音服 ドレミコード
!setname 0x163 北极天熊 ベアルクティ
......@@ -1130,7 +1136,7 @@
!setname 0x16d 随风旅鸟 ふわんだりぃず
!setname 0x16e 拓扑 トポロジック
!setname 0x16f 许珀里翁 ヒュペリオン
!setname 0x170 甲虫骑兵 Beetrooper
!setname 0x170 骑甲虫 ビートルーパー
!setname 0x171 朋克 P.U.N.K.
!setname 0x172 救祓少女 エクソシスター
!setname 0x173 恐啡肽狂龙 ダイノルフィア
......@@ -1140,10 +1146,27 @@
!setname 0x177 海龙神 リバイアサン
!setname 0x178 潜海 シー・ステルス
!setname 0x179 兽带斗神 セリオンズ
!setname 0x17a 肆世坏 スケアクロー
!setname 0x17a 恐吓爪牙族 スケアクロー
!setname 0x17b 野蛮人 バーバリアン
!setname 0x17c 漫读使灵 Libromancer
!setname 0x17c 漫读使灵 リブロマンサー
!setname 0x17d 群豪 ヴァリアンツ
!setname 0x17e 拉比林斯迷宫 ラビュリンス
!setname 0x117e 拉比林斯迷宫欢迎 ウェルカム・ラビュリンス
!setname 0x17f 神碑
!setname 0x180 卫星闪灵 スプライト
!setname 0x181 珠泪哀歌族 ティアラメンツ
!setname 0x182 春化精
!setname 0x183 悠悠 もけもけ
!setname 0x184 翼侠 ウィングマン
#setname 0x185 涂鸦 らくがき
!setname 0x1185 涂鸦兽 らくがきじゅう
!setname 0x2185 涂鸦本 らくがきちょう
!setname 0x186 G石人 Gゴーレム
!setname 0x187 桥梁 架け橋
!setname 0x188 深渊之兽 ビーステッド
!setname 0x189 俱舍怒威族 クシャトリラ
!setname 0x18a 魊影 Ghoti
!setname 0x18b 救援ACERACE
!setname 0x18c 纯爱妖精 ピュアリィ
!setname 0x18d 御巫
!setname 0x18e 仪水镜 儀水鏡
......@@ -2,7 +2,7 @@
#nickname & gamename should be less than 20 characters
use_d3d = 0
use_image_scale = 1
pro_version = 4947
pro_version = 4948
antialias = 2
errorlog = 3
nickname = Komeiji Koishi
......@@ -13,12 +13,13 @@ textfont = ./fonts/simhei.ttf 14
numfont = ./fonts/arial.ttf
serverport = 7911
lasthost = 127.0.0.1
lastport = 7911
lastport = 0
automonsterpos = 0
autospellpos = 0
randompos = 0
autochain = 0
waitchain = 0
showchain = 0
mute_opponent = 0
mute_spectators = 0
use_lflist = 1
......
#config file
#nickname & gamename should be less than 20 characters
use_d3d = 0
use_image_scale = 1
pro_version = 4946
antialias = 2
errorlog = 3
nickname = Nanahira
gamename = Game
lastcategory = OCG
lastdeck = wws
textfont = ./fonts/simhei.ttf 14
numfont = ./fonts/arial.ttf
serverport = 7911
lasthost = tiramisu.mycard.moe
lastport = 7911
automonsterpos = 0
autospellpos = 0
randompos = 0
autochain = 0
waitchain = 0
mute_opponent = 0
mute_spectators = 0
use_lflist = 1
default_lflist = 0
default_rule = 0
hide_setname = 0
hide_hint_button = 0
#control_mode = 0: Key A/S/D/R Chain Buttons. control_mode = 1: MouseLeft/MouseRight/NULL/F9 Without Chain Buttons
control_mode = 0
draw_field_spell = 1
separate_clear_button = 1
#auto_search_limit >= 0: Start search automatically when the user enters N chars
auto_search_limit = 2
#search_multiple_keywords = 0: Disable. 1: Search mutiple keywords with separator " ". 2: with separator "+"
search_multiple_keywords = 1
search_regex = 1
ignore_deck_changes = 0
default_ot = 1
enable_bot_mode = 1
bot_deck_path = ./windbot/Decks
quick_animation = 1
auto_save_replay = 0
draw_single_chain = 1
prefer_expansion_script = 1
ask_mset = 1
window_maximized = 0
window_width = 1402
window_height = 806
resize_popup_menu = 0
enable_sound = 1
enable_music = 0
#Volume of sound and music, between 0 and 100
sound_volume = 100
music_volume = 100
music_mode = 1
enable_pendulum_scale = 1
skin_index = -1
locale = default
textures/lp.png

967 Bytes | W: | H:

textures/lp.png

2.05 KB | W: | H:

textures/lp.png
textures/lp.png
textures/lp.png
textures/lp.png
  • 2-up
  • Swipe
  • Onion skin
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