Commit b73d8012 authored by mercury233's avatar mercury233

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

parents 12f9e87c b824c77e
Pipeline #43048 passed with stages
in 2 minutes and 40 seconds
......@@ -32,14 +32,15 @@ ClientCard::~ClientCard() {
overlayed.clear();
}
void ClientCard::SetCode(unsigned int x) {
if((location == LOCATION_HAND) && (code != x)) {
code = x;
if (code == x) {
return;
}
if (x == 0) {
chain_code = code;
}
code = x;
if (location == LOCATION_HAND) {
mainGame->dField.MoveCard(this, 5);
} else {
if (x == 0 && code != 0) {
chain_code = code;
}
code = x;
}
}
void ClientCard::UpdateInfo(unsigned char* buf) {
......
......@@ -456,17 +456,15 @@ void ClientField::ShowSelectCard(bool buttonok, bool is_continuous) {
if(mainGame->dInfo.curMsg != MSG_SORT_CARD) {
// text
wchar_t formatBuffer[2048];
if(select_continuous)
if (select_continuous)
myswprintf(formatBuffer, L"%ls", dataManager.unknown_string);
else if(cant_check_grave && selectable_cards[i]->location == LOCATION_GRAVE)
else if (cant_check_grave && selectable_cards[i]->location == LOCATION_GRAVE)
myswprintf(formatBuffer, L"%ls", dataManager.FormatLocation(selectable_cards[i]->location, 0));
else if(selectable_cards[i]->location == LOCATION_OVERLAY)
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(selectable_cards[i]->overlayTarget->location, selectable_cards[i]->overlayTarget->sequence),
selectable_cards[i]->overlayTarget->sequence + 1, selectable_cards[i]->sequence + 1);
else if (selectable_cards[i]->location == LOCATION_OVERLAY)
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(selectable_cards[i]->overlayTarget), selectable_cards[i]->overlayTarget->sequence + 1, selectable_cards[i]->sequence + 1);
else
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(selectable_cards[i]->location, selectable_cards[i]->sequence),
selectable_cards[i]->sequence + 1);
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(selectable_cards[i]), selectable_cards[i]->sequence + 1);
mainGame->stCardPos[i]->setText(formatBuffer);
// color
if (selectable_cards[i]->is_selected)
......@@ -542,8 +540,7 @@ void ClientField::ShowChainCard() {
mainGame->btnCardSelect[i]->setPressed(false);
mainGame->btnCardSelect[i]->setVisible(true);
wchar_t formatBuffer[2048];
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(selectable_cards[i]->location, selectable_cards[i]->sequence),
selectable_cards[i]->sequence + 1);
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(selectable_cards[i]), selectable_cards[i]->sequence + 1);
mainGame->stCardPos[i]->setText(formatBuffer);
if(selectable_cards[i]->location == LOCATION_OVERLAY) {
if(selectable_cards[i]->owner != selectable_cards[i]->overlayTarget->controler)
......@@ -597,13 +594,11 @@ void ClientField::ShowLocationCard() {
mainGame->btnCardDisplay[i]->setPressed(false);
mainGame->btnCardDisplay[i]->setVisible(true);
wchar_t formatBuffer[2048];
if(display_cards[i]->location == LOCATION_OVERLAY)
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(display_cards[i]->overlayTarget->location, display_cards[i]->overlayTarget->sequence),
display_cards[i]->overlayTarget->sequence + 1, display_cards[i]->sequence + 1);
if (display_cards[i]->location == LOCATION_OVERLAY)
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(display_cards[i]->overlayTarget), display_cards[i]->overlayTarget->sequence + 1, display_cards[i]->sequence + 1);
else
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(display_cards[i]->location, display_cards[i]->sequence),
display_cards[i]->sequence + 1);
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(display_cards[i]), display_cards[i]->sequence + 1);
mainGame->stDisplayPos[i]->setText(formatBuffer);
if(display_cards[i]->location == LOCATION_OVERLAY) {
if(display_cards[i]->owner != display_cards[i]->overlayTarget->controler)
......
#include "data_manager.h"
#include "game.h"
#if !defined(YGOPRO_SERVER_MODE) || defined(SERVER_ZIP_SUPPORT)
#include "client_card.h"
#include "spmemvfs/spmemvfs.h"
#endif
......@@ -245,34 +246,26 @@ const wchar_t* DataManager::GetDesc(uint32_t strCode) const {
return csit->second.desc[offset].c_str();
return unknown_string;
}
const wchar_t* DataManager::GetSysString(int code) const {
if (code < 0 || code > MAX_STRING_ID)
return unknown_string;
auto csit = _sysStrings.find(code);
if(csit == _sysStrings.end())
const wchar_t* DataManager::GetMapString(const wstring_map& table, uint32_t code) const {
auto csit = table.find(code);
if (csit == table.end())
return unknown_string;
return csit->second.c_str();
}
const wchar_t* DataManager::GetVictoryString(int code) const {
auto csit = _victoryStrings.find(code);
if(csit == _victoryStrings.end())
return unknown_string;
return csit->second.c_str();
const wchar_t* DataManager::GetSysString(uint32_t code) const {
return GetMapString(_sysStrings, code);
}
const wchar_t* DataManager::GetCounterName(int code) const {
auto csit = _counterStrings.find(code);
if(csit == _counterStrings.end())
return unknown_string;
return csit->second.c_str();
const wchar_t* DataManager::GetVictoryString(uint32_t code) const {
return GetMapString(_victoryStrings, code);
}
const wchar_t* DataManager::GetSetName(int code) const {
auto csit = _setnameStrings.find(code);
if(csit == _setnameStrings.end())
return unknown_string;
return csit->second.c_str();
const wchar_t* DataManager::GetCounterName(uint32_t code) const {
return GetMapString(_counterStrings, code);
}
const wchar_t* DataManager::GetSetName(uint32_t code) const {
return GetMapString(_setnameStrings, code);
}
std::vector<unsigned int> DataManager::GetSetCodes(std::wstring setname) const {
std::vector<unsigned int> matchingCodes;
std::vector<uint32_t> DataManager::GetSetCodes(std::wstring setname) const {
std::vector<uint32_t> matchingCodes;
for(auto csit = _setnameStrings.begin(); csit != _setnameStrings.end(); ++csit) {
auto xpos = csit->second.find_first_of(L'|');//setname|another setname or extra info
if(setname.size() < 2) {
......@@ -305,11 +298,10 @@ const wchar_t* DataManager::FormatLocation(int location, int sequence) const {
else
return GetSysString(1009);
}
int i = 1000;
int string_id = 0;
for (unsigned filter = LOCATION_DECK; filter <= LOCATION_PZONE; filter <<= 1, ++i) {
if (filter == location) {
string_id = i;
for (int i = 0; i < 10; ++i) {
if ((0x1U << i) == location) {
string_id = STRING_ID_LOCATION + i;
break;
}
}
......@@ -318,6 +310,11 @@ const wchar_t* DataManager::FormatLocation(int location, int sequence) const {
else
return unknown_string;
}
const wchar_t* DataManager::FormatLocation(ClientCard* card) const {
if (!card)
return unknown_string;
return FormatLocation(card->location, card->sequence);
}
std::wstring DataManager::FormatAttribute(unsigned int attribute) const {
std::wstring buffer;
for (int i = 0; i < ATTRIBUTES_COUNT; ++i) {
......@@ -328,7 +325,7 @@ std::wstring DataManager::FormatAttribute(unsigned int attribute) const {
}
}
if (buffer.empty())
return std::wstring(unknown_string);
buffer = unknown_string;
return buffer;
}
std::wstring DataManager::FormatRace(unsigned int race) const {
......@@ -341,7 +338,7 @@ std::wstring DataManager::FormatRace(unsigned int race) const {
}
}
if (buffer.empty())
return std::wstring(unknown_string);
buffer = unknown_string;
return buffer;
}
std::wstring DataManager::FormatType(unsigned int type) const {
......@@ -354,7 +351,7 @@ std::wstring DataManager::FormatType(unsigned int type) const {
}
}
if (buffer.empty())
return std::wstring(unknown_string);
buffer = unknown_string;
return buffer;
}
std::wstring DataManager::FormatSetName(const uint16_t setcode[]) const {
......@@ -368,7 +365,7 @@ std::wstring DataManager::FormatSetName(const uint16_t setcode[]) const {
buffer.append(setname);
}
if (buffer.empty())
return std::wstring(unknown_string);
buffer = unknown_string;
return buffer;
}
std::wstring DataManager::FormatLinkMarker(unsigned int link_marker) const {
......
......@@ -57,6 +57,9 @@ struct CardString {
};
using code_pointer = std::unordered_map<uint32_t, CardDataC>::const_iterator;
using string_pointer = std::unordered_map<uint32_t, CardString>::const_iterator;
using wstring_map = std::unordered_map<uint32_t, std::wstring>;
class ClientCard;
class DataManager {
public:
......@@ -88,23 +91,24 @@ public:
const wchar_t* GetName(uint32_t code) const;
const wchar_t* GetText(uint32_t code) const;
const wchar_t* GetDesc(uint32_t strCode) const;
const wchar_t* GetSysString(int code) const;
const wchar_t* GetVictoryString(int code) const;
const wchar_t* GetCounterName(int code) const;
const wchar_t* GetSetName(int code) const;
std::vector<unsigned int> GetSetCodes(std::wstring setname) const;
const wchar_t* GetSysString(uint32_t code) const;
const wchar_t* GetVictoryString(uint32_t code) const;
const wchar_t* GetCounterName(uint32_t code) const;
const wchar_t* GetSetName(uint32_t code) const;
std::vector<uint32_t> GetSetCodes(std::wstring setname) const;
std::wstring GetNumString(int num, bool bracket = false) const;
const wchar_t* FormatLocation(int location, int sequence) const;
const wchar_t* FormatLocation(ClientCard* card) const;
std::wstring FormatAttribute(unsigned int attribute) const;
std::wstring FormatRace(unsigned int race) const;
std::wstring FormatType(unsigned int type) const;
std::wstring FormatSetName(const uint16_t setcode[]) const;
std::wstring FormatLinkMarker(unsigned int link_marker) const;
std::unordered_map<unsigned int, std::wstring> _counterStrings;
std::unordered_map<unsigned int, std::wstring> _victoryStrings;
std::unordered_map<unsigned int, std::wstring> _setnameStrings;
std::unordered_map<unsigned int, std::wstring> _sysStrings;
wstring_map _counterStrings;
wstring_map _victoryStrings;
wstring_map _setnameStrings;
wstring_map _sysStrings;
#endif
char errmsg[512]{};
const wchar_t* unknown_string{ L"???" };
......@@ -112,9 +116,10 @@ public:
irr::io::IFileSystem* FileSystem{};
#endif
static constexpr int STRING_ID_ATTRIBUTE = 1010;
static constexpr int STRING_ID_RACE = 1020;
static constexpr int STRING_ID_TYPE = 1050;
static constexpr uint32_t STRING_ID_LOCATION = 1000;
static constexpr uint32_t STRING_ID_ATTRIBUTE = 1010;
static constexpr uint32_t STRING_ID_RACE = 1020;
static constexpr uint32_t STRING_ID_TYPE = 1050;
static constexpr int TYPES_COUNT = 27;
static unsigned char scriptBuffer[0x100000];
......@@ -136,6 +141,7 @@ public:
#endif
private:
const wchar_t* GetMapString(const wstring_map& table, uint32_t code) const;
std::unordered_map<uint32_t, CardDataC> _datas;
std::unordered_map<uint32_t, CardString> _strings;
std::unordered_map<uint32_t, std::vector<uint16_t>> extra_setcode;
......
......@@ -179,10 +179,12 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
std::sort(deckManager.current_deck.main.begin(), deckManager.current_deck.main.end(), DataManager::deck_sort_lv);
std::sort(deckManager.current_deck.extra.begin(), deckManager.current_deck.extra.end(), DataManager::deck_sort_lv);
std::sort(deckManager.current_deck.side.begin(), deckManager.current_deck.side.end(), DataManager::deck_sort_lv);
is_modified = true;
break;
}
case BUTTON_SHUFFLE_DECK: {
std::shuffle(deckManager.current_deck.main.begin(), deckManager.current_deck.main.end(), rnd);
is_modified = true;
break;
}
case BUTTON_SAVE_DECK: {
......@@ -740,6 +742,7 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
deckManager.current_deck.main.clear();
deckManager.current_deck.extra.clear();
deckManager.current_deck.side.clear();
is_modified = true;
} else if(prev_operation == BUTTON_DELETE_DECK) {
int sel = prev_sel;
mainGame->cbDBDecks->setSelected(sel);
......@@ -1083,6 +1086,7 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
is_starting_dragging = false;
irr::gui::IGUIElement* root = mainGame->env->getRootGUIElement();
if(!is_draging && !mainGame->is_siding && root->getElementFromPoint(mouse_pos) == mainGame->imgCard) {
soundManager.PlaySoundEffect(SOUND_CARD_DROP);
ShowBigCard(mainGame->showingcode, 1);
break;
}
......@@ -1112,6 +1116,7 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
case irr::EMIE_LMOUSE_DOUBLE_CLICK: {
irr::gui::IGUIElement* root = mainGame->env->getRootGUIElement();
if(!is_draging && !mainGame->is_siding && root->getElementFromPoint(mouse_pos) == root && hovered_code) {
soundManager.PlaySoundEffect(SOUND_CARD_DROP);
ShowBigCard(hovered_code, 1);
break;
}
......@@ -1371,8 +1376,6 @@ void DeckBuilder::GetHoveredCard() {
if(!is_draging && pre_code != hovered_code) {
if(hovered_code)
mainGame->ShowCardInfo(hovered_code);
if(pre_code)
imageManager.RemoveTexture(pre_code);
}
}
void DeckBuilder::StartFilter() {
......@@ -1393,7 +1396,7 @@ void DeckBuilder::FilterCards() {
results.clear();
struct element_t {
std::wstring keyword;
std::vector<unsigned int> setcodes;
std::vector<uint32_t> setcodes;
enum class type_t {
all,
name,
......
......@@ -905,17 +905,15 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
else
myswprintf(formatBuffer, L"");
} else {
if(select_continuous)
if (select_continuous)
myswprintf(formatBuffer, L"%ls", dataManager.unknown_string);
else if(cant_check_grave && selectable_cards[i]->location == LOCATION_GRAVE)
else if (cant_check_grave && selectable_cards[i]->location == LOCATION_GRAVE)
myswprintf(formatBuffer, L"%ls", dataManager.FormatLocation(selectable_cards[i]->location, 0));
else if(selectable_cards[i + pos]->location == LOCATION_OVERLAY)
else if (selectable_cards[i + pos]->location == LOCATION_OVERLAY)
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(selectable_cards[i + pos]->overlayTarget->location, selectable_cards[i + pos]->overlayTarget->sequence),
selectable_cards[i + pos]->overlayTarget->sequence + 1, selectable_cards[i + pos]->sequence + 1);
dataManager.FormatLocation(selectable_cards[i + pos]->overlayTarget), selectable_cards[i + pos]->overlayTarget->sequence + 1, selectable_cards[i + pos]->sequence + 1);
else
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(selectable_cards[i + pos]->location, selectable_cards[i + pos]->sequence),
selectable_cards[i + pos]->sequence + 1);
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(selectable_cards[i + pos]), selectable_cards[i + pos]->sequence + 1);
}
mainGame->stCardPos[i]->setText(formatBuffer);
// color
......@@ -961,13 +959,11 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
mainGame->btnCardDisplay[i]->setImage(imageManager.tCover[display_cards[i + pos]->controler + 2]);
mainGame->btnCardDisplay[i]->setRelativePosition(irr::core::rect<irr::s32>(30 + i * 125, 55, 30 + 120 + i * 125, 225));
wchar_t formatBuffer[2048];
if(display_cards[i + pos]->location == LOCATION_OVERLAY) {
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(display_cards[i + pos]->overlayTarget->location, display_cards[i + pos]->overlayTarget->sequence),
display_cards[i + pos]->overlayTarget->sequence + 1, display_cards[i + pos]->sequence + 1);
} else
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(display_cards[i + pos]->location, display_cards[i + pos]->sequence),
display_cards[i + pos]->sequence + 1);
if(display_cards[i + pos]->location == LOCATION_OVERLAY)
myswprintf(formatBuffer, L"%ls[%d](%d)",
dataManager.FormatLocation(display_cards[i + pos]->overlayTarget), display_cards[i + pos]->overlayTarget->sequence + 1, display_cards[i + pos]->sequence + 1);
else
myswprintf(formatBuffer, L"%ls[%d]", dataManager.FormatLocation(display_cards[i + pos]), display_cards[i + pos]->sequence + 1);
mainGame->stDisplayPos[i]->setText(formatBuffer);
if(display_cards[i + pos]->location == LOCATION_OVERLAY) {
if(display_cards[i + pos]->owner != display_cards[i + pos]->overlayTarget->controler)
......
......@@ -1135,16 +1135,13 @@ void Game::InitStaticText(irr::gui::IGUIStaticText* pControl, irr::u32 cWidth, i
scrCardText->setPos(0);
}
std::wstring Game::SetStaticText(irr::gui::IGUIStaticText* pControl, irr::u32 cWidth, irr::gui::CGUITTFont* font, const wchar_t* text, irr::u32 pos) {
size_t pbuffer = 0;
irr::u32 _width = 0, _height = 0;
wchar_t prev = 0;
wchar_t strBuffer[4096]{};
constexpr size_t buffer_len = sizeof strBuffer / sizeof strBuffer[0] - 1;
std::wstring result;
result.reserve(4096);
const size_t text_len = std::wcslen(text);
for(size_t i = 0; i < text_len ; ++i) {
if (pbuffer >= buffer_len)
break;
wchar_t c = text[i];
irr::u32 w = font->getCharDimension(c).Width + font->getKerningWidth(c, prev);
prev = c;
......@@ -1152,31 +1149,28 @@ std::wstring Game::SetStaticText(irr::gui::IGUIStaticText* pControl, irr::u32 cW
continue;
}
if (c == L'\n') {
strBuffer[pbuffer++] = L'\n';
result.push_back(L'\n');
_width = 0;
_height++;
prev = 0;
if (_height == pos)
pbuffer = 0;
result.clear();
continue;
}
if (_width > 0 && _width + w > cWidth) {
strBuffer[pbuffer++] = L'\n';
result.push_back(L'\n');
_width = 0;
_height++;
prev = 0;
if (_height == pos)
pbuffer = 0;
result.clear();
}
if (pbuffer >= buffer_len)
break;
_width += w;
strBuffer[pbuffer++] = c;
result.push_back(c);
}
strBuffer[pbuffer] = 0;
if (pControl)
pControl->setText(strBuffer);
return std::wstring(strBuffer);
pControl->setText(result.c_str());
return result;
}
#endif //YGOPRO_SERVER_MODE
void Game::LoadExpansions() {
......@@ -1397,8 +1391,6 @@ void Game::LoadConfig() {
gameConf.antialias = std::strtol(valbuf, nullptr, 10);
} else if(!std::strcmp(strbuf, "use_d3d")) {
gameConf.use_d3d = std::strtol(valbuf, nullptr, 10) > 0;
} else if(!std::strcmp(strbuf, "use_image_scale")) {
gameConf.use_image_scale = std::strtol(valbuf, nullptr, 10) > 0;
} else if (!std::strcmp(strbuf, "use_image_scale_multi_thread")) {
gameConf.use_image_scale_multi_thread = std::strtol(valbuf, nullptr, 10) > 0;
} else if (!std::strcmp(strbuf, "use_image_load_background_thread")) {
......@@ -1533,7 +1525,6 @@ void Game::SaveConfig() {
std::fprintf(fp, "#config file\n#nickname & gamename should be less than 20 characters\n");
char linebuf[CONFIG_LINE_SIZE];
std::fprintf(fp, "use_d3d = %d\n", gameConf.use_d3d ? 1 : 0);
std::fprintf(fp, "use_image_scale = %d\n", gameConf.use_image_scale ? 1 : 0);
std::fprintf(fp, "use_image_scale_multi_thread = %d\n", gameConf.use_image_scale_multi_thread ? 1 : 0);
std::fprintf(fp, "use_image_load_background_thread = %d\n", gameConf.use_image_load_background_thread ? 1 : 0);
std::fprintf(fp, "antialias = %d\n", gameConf.antialias);
......
......@@ -57,7 +57,6 @@ bool IsExtension(const char* filename, const char(&extension)[N]) {
#ifndef YGOPRO_SERVER_MODE
struct Config {
bool use_d3d{ false };
bool use_image_scale{ true };
bool use_image_scale_multi_thread{ true };
#ifdef _OPENMP
bool use_image_load_background_thread{ false };
......
#include "image_manager.h"
#include "image_resizer.h"
#include "game.h"
#include <thread>
#ifdef _OPENMP
#include <omp.h>
#endif
namespace ygo {
......@@ -65,6 +63,10 @@ void ImageManager::ClearTexture() {
if(tit->second && tit->second != tLoading)
driver->removeTexture(tit->second);
}
for(auto tit = tFields.begin(); tit != tFields.end(); ++tit) {
if(tit->second)
driver->removeTexture(tit->second);
}
if(tBigPicture != nullptr) {
driver->removeTexture(tBigPicture);
tBigPicture = nullptr;
......@@ -72,27 +74,13 @@ void ImageManager::ClearTexture() {
tMap[0].clear();
tMap[1].clear();
tThumb.clear();
tFields.clear();
tThumbLoadingMutex.lock();
tThumbLoading.clear();
while(!tThumbLoadingCodes.empty())
tThumbLoadingCodes.pop();
tThumbLoadingThreadRunning = false;
tThumbLoadingMutex.unlock();
tFields.clear();
}
void ImageManager::RemoveTexture(int code) {
auto tit = tMap[0].find(code);
if(tit != tMap[0].end()) {
if(tit->second)
driver->removeTexture(tit->second);
tMap[0].erase(tit);
}
tit = tMap[1].find(code);
if(tit != tMap[1].end()) {
if(tit->second)
driver->removeTexture(tit->second);
tMap[1].erase(tit);
}
}
void ImageManager::ResizeTexture() {
irr::s32 imgWidth = CARD_IMG_WIDTH * mainGame->xScale;
......@@ -129,99 +117,76 @@ void ImageManager::ResizeTexture() {
if(!tBackGround_deck)
tBackGround_deck = tBackGround;
}
// function by Warr1024, from https://github.com/minetest/minetest/issues/2419 , modified
void imageScaleNNAA(irr::video::IImage *src, irr::video::IImage *dest) {
const auto& srcDim = src->getDimension();
const auto& destDim = dest->getDimension();
// Cache scale ratios.
const double rx = (double)srcDim.Width / destDim.Width;
const double ry = (double)srcDim.Height / destDim.Height;
#pragma omp parallel if(mainGame->gameConf.use_image_scale_multi_thread)
{
double sx, sy, minsx, maxsx, minsy, maxsy, area, ra, ga, ba, aa, pw, ph, pa;
irr::video::SColor pxl, npxl;
// Walk each destination image pixel.
#pragma omp for schedule(dynamic)
for(irr::s32 dy = 0; dy < (irr::s32)destDim.Height; dy++) {
for(irr::s32 dx = 0; dx < (irr::s32)destDim.Width; dx++) {
// Calculate floating-point source rectangle bounds.
minsx = dx * rx;
maxsx = minsx + rx;
minsy = dy * ry;
maxsy = minsy + ry;
// Total area, and integral of r, g, b values over that area,
// initialized to zero, to be summed up in next loops.
area = 0;
ra = 0;
ga = 0;
ba = 0;
aa = 0;
// Loop over the integral pixel positions described by those bounds.
for(sy = floor(minsy); sy < maxsy; sy++) {
for(sx = floor(minsx); sx < maxsx; sx++) {
// Calculate width, height, then area of dest pixel
// that's covered by this source pixel.
pw = 1;
if(minsx > sx)
pw += sx - minsx;
if(maxsx < (sx + 1))
pw += maxsx - sx - 1;
ph = 1;
if(minsy > sy)
ph += sy - minsy;
if(maxsy < (sy + 1))
ph += maxsy - sy - 1;
pa = pw * ph;
// Get source pixel and add it to totals, weighted
// by covered area and alpha.
pxl = src->getPixel((irr::u32)sx, (irr::u32)sy);
area += pa;
ra += pa * pxl.getRed();
ga += pa * pxl.getGreen();
ba += pa * pxl.getBlue();
aa += pa * pxl.getAlpha();
}
}
// Set the destination image pixel to the average color.
if(area > 0) {
npxl.set((irr::u32)(aa / area + 0.5),
(irr::u32)(ra / area + 0.5),
(irr::u32)(ga / area + 0.5),
(irr::u32)(ba / area + 0.5));
} else {
npxl.set(0);
}
dest->setPixel(dx, dy, npxl);
}
void ImageManager::resizeImage(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading) {
imageResizer.resize(src, dest, use_threading);
}
/**
* Convert image to texture, resizing if needed.
* @param name Texture name (Irrlicht texture key).
* @param srcimg Source image; will be dropped by this function.
* @return Texture pointer. Remove via `driver->removeTexture` (do not `drop`).
*/
irr::video::ITexture* ImageManager::addTexture(const char* name, irr::video::IImage* srcimg, irr::s32 width, irr::s32 height) {
if(srcimg == nullptr)
return nullptr;
irr::video::ITexture* texture;
if(srcimg->getDimension() == irr::core::dimension2d<irr::u32>(width, height)) {
texture = driver->addTexture(name, srcimg);
} else {
irr::video::IImage* destimg = driver->createImage(srcimg->getColorFormat(), irr::core::dimension2d<irr::u32>(width, height));
resizeImage(srcimg, destimg, mainGame->gameConf.use_image_scale_multi_thread);
texture = driver->addTexture(name, destimg);
destimg->drop();
}
} // end of parallel region
srcimg->drop();
return texture;
}
/**
* Load image from file and convert to texture.
* @return Texture pointer. Remove via `driver->removeTexture` (do not `drop`).
*/
irr::video::ITexture* ImageManager::GetTextureFromFile(const char* file, irr::s32 width, irr::s32 height) {
if(mainGame->gameConf.use_image_scale) {
irr::video::ITexture* texture;
irr::video::IImage* srcimg = driver->createImageFromFile(file);
if(srcimg == nullptr)
return nullptr;
if(srcimg->getDimension() == irr::core::dimension2d<irr::u32>(width, height)) {
texture = driver->addTexture(file, srcimg);
} else {
irr::video::IImage *destimg = driver->createImage(srcimg->getColorFormat(), irr::core::dimension2d<irr::u32>(width, height));
imageScaleNNAA(srcimg, destimg);
texture = driver->addTexture(file, destimg);
destimg->drop();
}
srcimg->drop();
return texture;
} else {
return driver->getTexture(file);
irr::video::IImage* img = driver->createImageFromFile(file);
if(img == nullptr) {
return nullptr;
}
char name[256];
mysnprintf(name, "%s/%d_%d", file, width, height);
return addTexture(name, img, width, height);
}
/**
* Load card picture from `expansions` or `pics` folder.
* Files in the expansions directory have priority, allowing custom pictures to be loaded without modifying the original files.
* @return Image pointer. Must be dropped after use.
*/
irr::video::IImage* ImageManager::GetImage(int code) {
char file[256];
mysnprintf(file, "expansions/pics/%d.jpg", code);
irr::video::IImage* img = driver->createImageFromFile(file);
if(img == nullptr) {
mysnprintf(file, "pics/%d.jpg", code);
img = driver->createImageFromFile(file);
}
return img;
}
/**
* Load card picture.
* @return Texture pointer. Remove via `driver->removeTexture` (do not `drop`).
*/
irr::video::ITexture* ImageManager::GetTexture(int code, irr::s32 width, irr::s32 height) {
irr::video::IImage* img = GetImage(code);
if(img == nullptr) {
return nullptr;
}
char name[256];
mysnprintf(name, "pics/%d/%d_%d", code, width, height);
return addTexture(name, img, width, height);
}
/**
* Load managed card picture texture.
* @param fit Resize to fit scale if true.
* @return Texture pointer. Should NOT be removed nor dropped.
*/
irr::video::ITexture* ImageManager::GetTexture(int code, bool fit) {
if(code == 0)
return fit ? tUnknownFit : tUnknown;
......@@ -236,94 +201,67 @@ irr::video::ITexture* ImageManager::GetTexture(int code, bool fit) {
}
auto tit = tMap[fit ? 1 : 0].find(code);
if(tit == tMap[fit ? 1 : 0].end()) {
char file[256];
mysnprintf(file, "expansions/pics/%d.jpg", code);
irr::video::ITexture* img = GetTextureFromFile(file, width, height);
if(img == nullptr) {
mysnprintf(file, "pics/%d.jpg", code);
img = GetTextureFromFile(file, width, height);
}
if(img == nullptr && !mainGame->gameConf.use_image_scale) {
tMap[fit ? 1 : 0][code] = nullptr;
return GetTextureThumb(code);
}
tMap[fit ? 1 : 0][code] = img;
return (img == nullptr) ? (fit ? tUnknownFit : tUnknown) : img;
irr::video::ITexture* texture = GetTexture(code, width, height);
tMap[fit ? 1 : 0][code] = texture;
return (texture == nullptr) ? (fit ? tUnknownFit : tUnknown) : texture;
}
if(tit->second)
return tit->second;
else
return mainGame->gameConf.use_image_scale ? (fit ? tUnknownFit : tUnknown) : GetTextureThumb(code);
return fit ? tUnknownFit : tUnknown;
}
/**
* Load managed card picture texture with zoom.
* @return Texture pointer. Should NOT be removed nor dropped.
*/
irr::video::ITexture* ImageManager::GetBigPicture(int code, float zoom) {
if(code == 0)
return tUnknown;
return tUnknownFit;
if(tBigPicture != nullptr) {
driver->removeTexture(tBigPicture);
tBigPicture = nullptr;
}
irr::video::ITexture* texture;
char file[256];
mysnprintf(file, "expansions/pics/%d.jpg", code);
irr::video::IImage* srcimg = driver->createImageFromFile(file);
if(srcimg == nullptr) {
mysnprintf(file, "pics/%d.jpg", code);
srcimg = driver->createImageFromFile(file);
irr::video::IImage* img = GetImage(code);
if(img == nullptr) {
return tUnknownFit;
}
if(srcimg == nullptr) {
return tUnknown;
}
if(zoom == 1) {
texture = driver->addTexture(file, srcimg);
} else {
auto origsize = srcimg->getDimension();
irr::video::IImage* destimg = driver->createImage(srcimg->getColorFormat(), irr::core::dimension2d<irr::u32>(origsize.Width * zoom, origsize.Height * zoom));
imageScaleNNAA(srcimg, destimg);
texture = driver->addTexture(file, destimg);
destimg->drop();
}
srcimg->drop();
tBigPicture = texture;
return texture;
char name[256];
mysnprintf(name, "pics/%d/big", code);
auto origsize = img->getDimension();
tBigPicture = addTexture(name, img, origsize.Width * zoom, origsize.Height * zoom);
return tBigPicture;
}
int ImageManager::LoadThumbThread() {
while(true) {
imageManager.tThumbLoadingMutex.lock();
imageManager.tThumbLoadingThreadRunning = !imageManager.tThumbLoadingCodes.empty();
if(!imageManager.tThumbLoadingThreadRunning) {
imageManager.tThumbLoadingMutex.unlock();
break;
}
int code = imageManager.tThumbLoadingCodes.front();
imageManager.tThumbLoadingCodes.pop();
imageManager.tThumbLoadingMutex.unlock();
char file[256];
mysnprintf(file, "expansions/pics/thumbnail/%d.jpg", code);
irr::video::IImage* img = imageManager.driver->createImageFromFile(file);
if(img == nullptr) {
mysnprintf(file, "pics/thumbnail/%d.jpg", code);
img = imageManager.driver->createImageFromFile(file);
}
if(img == nullptr && mainGame->gameConf.use_image_scale) {
mysnprintf(file, "expansions/pics/%d.jpg", code);
img = imageManager.driver->createImageFromFile(file);
}
if(img == nullptr && mainGame->gameConf.use_image_scale) {
mysnprintf(file, "pics/%d.jpg", code);
img = imageManager.driver->createImageFromFile(file);
}
irr::video::IImage* img = imageManager.GetImage(code);
if(img != nullptr) {
int width = CARD_THUMB_WIDTH * mainGame->xScale;
int height = CARD_THUMB_HEIGHT * mainGame->yScale;
if(img->getDimension() == irr::core::dimension2d<irr::u32>(width, height)) {
img->grab();
imageManager.tThumbLoadingMutex.lock();
if(imageManager.tThumbLoadingThreadRunning)
imageManager.tThumbLoading[code] = img;
else
img->drop();
imageManager.tThumbLoadingMutex.unlock();
} else {
irr::video::IImage *destimg = imageManager.driver->createImage(img->getColorFormat(), irr::core::dimension2d<irr::u32>(width, height));
imageScaleNNAA(img, destimg);
imageManager.resizeImage(img, destimg, mainGame->gameConf.use_image_scale_multi_thread);
img->drop();
destimg->grab();
imageManager.tThumbLoadingMutex.lock();
if(imageManager.tThumbLoadingThreadRunning)
imageManager.tThumbLoading[code] = destimg;
else
destimg->drop();
imageManager.tThumbLoadingMutex.unlock();
}
} else {
......@@ -332,48 +270,32 @@ int ImageManager::LoadThumbThread() {
imageManager.tThumbLoading[code] = nullptr;
imageManager.tThumbLoadingMutex.unlock();
}
imageManager.tThumbLoadingMutex.lock();
imageManager.tThumbLoadingThreadRunning = !imageManager.tThumbLoadingCodes.empty();
if(!imageManager.tThumbLoadingThreadRunning)
break;
imageManager.tThumbLoadingMutex.unlock();
}
imageManager.tThumbLoadingMutex.unlock();
return 0;
}
/**
* Load managed card thumbnail texture.
* @return Texture pointer. Should NOT be removed nor dropped.
*/
irr::video::ITexture* ImageManager::GetTextureThumb(int code) {
if(code == 0)
return tUnknownThumb;
auto tit = tThumb.find(code);
if(tit == tThumb.end() && !mainGame->gameConf.use_image_load_background_thread) {
char file[256];
mysnprintf(file, "expansions/pics/thumbnail/%d.jpg", code);
int width = CARD_THUMB_WIDTH * mainGame->xScale;
int height = CARD_THUMB_HEIGHT * mainGame->yScale;
irr::video::ITexture* img = GetTextureFromFile(file, width, height);
if(img == NULL) {
mysnprintf(file, "pics/thumbnail/%d.jpg", code);
img = GetTextureFromFile(file, width, height);
}
if(img == NULL && mainGame->gameConf.use_image_scale) {
mysnprintf(file, "expansions/pics/%d.jpg", code);
img = GetTextureFromFile(file, width, height);
if(img == NULL) {
mysnprintf(file, "pics/%d.jpg", code);
img = GetTextureFromFile(file, width, height);
}
}
tThumb[code] = img;
return (img == NULL) ? tUnknownThumb : img;
irr::video::ITexture* texture = GetTexture(code, width, height);
tThumb[code] = texture;
return (texture == nullptr) ? tUnknownThumb : texture;
}
if(tit == tThumb.end() || tit->second == tLoading) {
imageManager.tThumbLoadingMutex.lock();
auto lit = tThumbLoading.find(code);
if(lit != tThumbLoading.end()) {
if(lit->second != nullptr) {
char file[256];
mysnprintf(file, "pics/thumbnail/%d.jpg", code);
irr::video::ITexture* texture = driver->addTexture(file, lit->second); // textures must be added in the main thread due to OpenGL
char textureName[256];
mysnprintf(textureName, "pics/%d/thumbnail", code);
irr::video::ITexture* texture = driver->addTexture(textureName, lit->second); // textures must be added in the main thread due to OpenGL
lit->second->drop();
tThumb[code] = texture;
} else {
......@@ -400,25 +322,31 @@ irr::video::ITexture* ImageManager::GetTextureThumb(int code) {
else
return tUnknownThumb;
}
/**
* Load managed duel field texture.
* @return Texture pointer. Should NOT be removed nor dropped.
*/
irr::video::ITexture* ImageManager::GetTextureField(int code) {
if(code == 0)
return nullptr;
auto tit = tFields.find(code);
if(tit == tFields.end()) {
irr::s32 width = 512 * mainGame->xScale;
irr::s32 height = 512 * mainGame->yScale;
char file[256];
mysnprintf(file, "expansions/pics/field/%d.png", code);
irr::video::ITexture* img = GetTextureFromFile(file, 512 * mainGame->xScale, 512 * mainGame->yScale);
irr::video::ITexture* img = GetTextureFromFile(file, width, height);
if(img == nullptr) {
mysnprintf(file, "expansions/pics/field/%d.jpg", code);
img = GetTextureFromFile(file, 512 * mainGame->xScale, 512 * mainGame->yScale);
img = GetTextureFromFile(file, width, height);
}
if(img == nullptr) {
mysnprintf(file, "pics/field/%d.png", code);
img = GetTextureFromFile(file, 512 * mainGame->xScale, 512 * mainGame->yScale);
img = GetTextureFromFile(file, width, height);
}
if(img == nullptr) {
mysnprintf(file, "pics/field/%d.jpg", code);
img = GetTextureFromFile(file, 512 * mainGame->xScale, 512 * mainGame->yScale);
img = GetTextureFromFile(file, width, height);
if(img == nullptr) {
tFields[code] = nullptr;
return nullptr;
......
......@@ -10,13 +10,17 @@
namespace ygo {
class ImageManager {
private:
void resizeImage(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading);
irr::video::ITexture* addTexture(const char* name, irr::video::IImage* srcimg, irr::s32 width, irr::s32 height);
public:
bool Initial();
void SetDevice(irr::IrrlichtDevice* dev);
void ClearTexture();
void RemoveTexture(int code);
void ResizeTexture();
irr::video::ITexture* GetTextureFromFile(const char* file, irr::s32 width, irr::s32 height);
irr::video::IImage* GetImage(int code);
irr::video::ITexture* GetTexture(int code, irr::s32 width, irr::s32 height);
irr::video::ITexture* GetTexture(int code, bool fit = false);
irr::video::ITexture* GetBigPicture(int code, float zoom);
irr::video::ITexture* GetTextureThumb(int code);
......
#include "image_resizer.h"
#include <cmath>
#ifdef _OPENMP
#include <omp.h>
#endif
#define STB_IMAGE_RESIZE2_IMPLEMENTATION
#include "stb_image_resize2.h"
namespace ygo {
ImageResizer imageResizer;
struct StbSamplerCache {
STBIR_RESIZE resize{};
int in_w = 0;
int in_h = 0;
int out_w = 0;
int out_h = 0;
stbir_pixel_layout layout = STBIR_BGRA;
bool samplers_built = false;
~StbSamplerCache() {
if(samplers_built) {
stbir_free_samplers(&resize);
samplers_built = false;
}
}
void reset_if_needed(int new_in_w, int new_in_h, int new_out_w, int new_out_h, stbir_pixel_layout new_layout) {
if(new_in_w == in_w && new_in_h == in_h && new_out_w == out_w && new_out_h == out_h && new_layout == layout)
return;
if(samplers_built) {
stbir_free_samplers(&resize);
samplers_built = false;
}
in_w = new_in_w;
in_h = new_in_h;
out_w = new_out_w;
out_h = new_out_h;
layout = new_layout;
resize = STBIR_RESIZE{};
}
};
/**
* Scale image using stb_image_resize2.
* Returns true on success, false on failure or unsupported format.
*/
bool ImageResizer::imageScaleSTB(irr::video::IImage* src, irr::video::IImage* dest) {
if(!src || !dest)
return false;
const auto srcDim = src->getDimension();
const auto destDim = dest->getDimension();
if(srcDim.Width == 0 || srcDim.Height == 0 || destDim.Width == 0 || destDim.Height == 0)
return false;
if(src->getColorFormat() != dest->getColorFormat())
return false;
stbir_pixel_layout layout = STBIR_BGRA;
// Fast-paths (8-bit per channel only):
// - ECF_A8R8G8B8: Irrlicht stores as BGRA in memory on little-endian.
// - ECF_R8G8B8: common for JPEGs (3 channels).
switch(src->getColorFormat()) {
case irr::video::ECF_A8R8G8B8:
layout = STBIR_BGRA;
break;
case irr::video::ECF_R8G8B8:
layout = STBIR_RGB;
break;
default:
return false;
}
void* srcPtr = src->lock();
if(!srcPtr)
return false;
void* destPtr = dest->lock();
if(!destPtr) {
src->unlock();
return false;
}
const int srcStride = (int)src->getPitch();
const int destStride = (int)dest->getPitch();
thread_local StbSamplerCache cache;
cache.reset_if_needed((int)srcDim.Width, (int)srcDim.Height, (int)destDim.Width, (int)destDim.Height, layout);
if(!cache.samplers_built) {
stbir_resize_init(&cache.resize,
srcPtr, (int)srcDim.Width, (int)srcDim.Height, srcStride,
destPtr, (int)destDim.Width, (int)destDim.Height, destStride,
layout, STBIR_TYPE_UINT8);
stbir_set_edgemodes(&cache.resize, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP);
// Use box filters to reduce aliasing when downscaling.
stbir_set_filters(&cache.resize, STBIR_FILTER_BOX, STBIR_FILTER_BOX);
cache.samplers_built = (stbir_build_samplers(&cache.resize) != 0);
if(!cache.samplers_built) {
dest->unlock();
src->unlock();
return false;
}
} else {
// Reuse samplers but update buffer pointers for the current images
stbir_set_buffer_ptrs(&cache.resize, srcPtr, srcStride, destPtr, destStride);
}
const int ok = stbir_resize_extended(&cache.resize);
dest->unlock();
src->unlock();
return ok != 0;
}
/**
* Scale image using nearest neighbor anti-aliasing.
* Function by Warr1024, from https://github.com/minetest/minetest/issues/2419, modified.
*/
void ImageResizer::imageScaleNNAA(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading) {
const auto& srcDim = src->getDimension();
const auto& destDim = dest->getDimension();
if (destDim.Width == 0 || destDim.Height == 0)
return;
// Cache scale ratios.
const double rx = (double)srcDim.Width / destDim.Width;
const double ry = (double)srcDim.Height / destDim.Height;
#pragma omp parallel if(use_threading)
{
// Walk each destination image pixel.
#pragma omp for schedule(dynamic)
for(irr::s32 dy = 0; dy < (irr::s32)destDim.Height; dy++) {
for(irr::s32 dx = 0; dx < (irr::s32)destDim.Width; dx++) {
// Calculate floating-point source rectangle bounds.
double minsx = dx * rx;
double maxsx = minsx + rx;
double minsy = dy * ry;
double maxsy = minsy + ry;
irr::u32 sx_begin = (irr::u32)std::floor(minsx);
irr::u32 sx_end = (irr::u32)std::ceil(maxsx);
if (sx_end > srcDim.Width)
sx_end = srcDim.Width;
irr::u32 sy_begin = (irr::u32)std::floor(minsy);
irr::u32 sy_end = (irr::u32)std::ceil(maxsy);
if (sy_end > srcDim.Height)
sy_end = srcDim.Height;
// Total area, and integral of r, g, b values over that area,
// initialized to zero, to be summed up in next loops.
double area = 0, ra = 0, ga = 0, ba = 0, aa = 0;
irr::video::SColor pxl, npxl;
// Loop over the integral pixel positions described by those bounds.
for(irr::u32 sy = sy_begin; sy < sy_end; sy++) {
for(irr::u32 sx = sx_begin; sx < sx_end; sx++) {
// Calculate width, height, then area of dest pixel
// that's covered by this source pixel.
double pw = 1;
if(minsx > sx)
pw += sx - minsx;
if(maxsx < (sx + 1))
pw += maxsx - sx - 1;
double ph = 1;
if(minsy > sy)
ph += sy - minsy;
if(maxsy < (sy + 1))
ph += maxsy - sy - 1;
double pa = pw * ph;
// Get source pixel and add it to totals, weighted
// by covered area and alpha.
pxl = src->getPixel(sx, sy);
area += pa;
ra += pa * pxl.getRed();
ga += pa * pxl.getGreen();
ba += pa * pxl.getBlue();
aa += pa * pxl.getAlpha();
}
}
// Set the destination image pixel to the average color.
if(area > 0) {
npxl.set((irr::u32)(aa / area + 0.5),
(irr::u32)(ra / area + 0.5),
(irr::u32)(ga / area + 0.5),
(irr::u32)(ba / area + 0.5));
} else {
npxl.set(0);
}
dest->setPixel(dx, dy, npxl);
}
}
} // end of parallel region
}
void ImageResizer::resize(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading) {
if(imageScaleSTB(src, dest))
return;
imageScaleNNAA(src, dest, use_threading);
}
} // namespace ygo
#ifndef IMAGE_RESIZER_H
#define IMAGE_RESIZER_H
#include <irrlicht.h>
namespace ygo {
class ImageResizer {
private:
bool imageScaleSTB(irr::video::IImage* src, irr::video::IImage* dest);
void imageScaleNNAA(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading);
public:
void resize(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading);
};
extern ImageResizer imageResizer;
} // namespace ygo
#endif // IMAGE_RESIZER_H
......@@ -8,8 +8,10 @@
#ifndef _WIN32
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <vector>
#include <algorithm>
#include <string>
#endif
#ifdef _WIN32
......@@ -182,7 +184,7 @@ public:
bool success = true;
TraversalDir(dir, [dir, &success](const char *name, bool isdir) {
char full_path[1024];
int len = mysnprintf(full_path, "%s/%s", dir, name);
int len = std::snprintf(full_path, sizeof(full_path), "%s/%s", dir, name);
if (len < 0 || len >= (int)(sizeof full_path)) {
success = false;
return;
......@@ -234,7 +236,7 @@ public:
file_unit funit;
#endif
char fname[1024];
int len = mysnprintf(fname, "%s/%s", path, dirp->d_name);
int len = std::snprintf(fname, sizeof(fname), "%s/%s", path, dirp->d_name);
if (len < 0 || len >= (int)(sizeof fname))
continue;
stat(fname, &fileStat);
......
......@@ -88,143 +88,142 @@ void SoundManager::PlaySoundEffect(int sound) {
#ifdef YGOPRO_USE_AUDIO
if(!mainGame->chkEnableSound->isChecked())
return;
char soundName[32];
std::string soundName;
switch(sound) {
case SOUND_SUMMON: {
strcpy(soundName, "summon");
soundName = "summon";
break;
}
case SOUND_SPECIAL_SUMMON: {
strcpy(soundName, "specialsummon");
soundName = "specialsummon";
break;
}
case SOUND_ACTIVATE: {
strcpy(soundName, "activate");
soundName = "activate";
break;
}
case SOUND_SET: {
strcpy(soundName, "set");
soundName = "set";
break;
}
case SOUND_FLIP: {
strcpy(soundName, "flip");
soundName = "flip";
break;
}
case SOUND_REVEAL: {
strcpy(soundName, "reveal");
soundName = "reveal";
break;
}
case SOUND_EQUIP: {
strcpy(soundName, "equip");
soundName = "equip";
break;
}
case SOUND_DESTROYED: {
strcpy(soundName, "destroyed");
soundName = "destroyed";
break;
}
case SOUND_BANISHED: {
strcpy(soundName, "banished");
soundName = "banished";
break;
}
case SOUND_TOKEN: {
strcpy(soundName, "token");
soundName = "token";
break;
}
case SOUND_NEGATE: {
strcpy(soundName, "negate");
soundName = "negate";
break;
}
case SOUND_ATTACK: {
strcpy(soundName, "attack");
soundName = "attack";
break;
}
case SOUND_DIRECT_ATTACK: {
strcpy(soundName, "directattack");
soundName = "directattack";
break;
}
case SOUND_DRAW: {
strcpy(soundName, "draw");
soundName = "draw";
break;
}
case SOUND_SHUFFLE: {
strcpy(soundName, "shuffle");
soundName = "shuffle";
break;
}
case SOUND_DAMAGE: {
strcpy(soundName, "damage");
soundName = "damage";
break;
}
case SOUND_RECOVER: {
strcpy(soundName, "gainlp");
soundName = "gainlp";
break;
}
case SOUND_COUNTER_ADD: {
strcpy(soundName, "addcounter");
soundName = "addcounter";
break;
}
case SOUND_COUNTER_REMOVE: {
strcpy(soundName, "removecounter");
soundName = "removecounter";
break;
}
case SOUND_COIN: {
strcpy(soundName, "coinflip");
soundName = "coinflip";
break;
}
case SOUND_DICE: {
strcpy(soundName, "diceroll");
soundName = "diceroll";
break;
}
case SOUND_NEXT_TURN: {
strcpy(soundName, "nextturn");
soundName = "nextturn";
break;
}
case SOUND_PHASE: {
strcpy(soundName, "phase");
soundName = "phase";
break;
}
case SOUND_MENU: {
strcpy(soundName, "menu");
soundName = "menu";
break;
}
case SOUND_BUTTON: {
strcpy(soundName, "button");
soundName = "button";
break;
}
case SOUND_INFO: {
strcpy(soundName, "info");
soundName = "info";
break;
}
case SOUND_QUESTION: {
strcpy(soundName, "question");
soundName = "question";
break;
}
case SOUND_CARD_PICK: {
strcpy(soundName, "cardpick");
soundName = "cardpick";
break;
}
case SOUND_CARD_DROP: {
strcpy(soundName, "carddrop");
soundName = "carddrop";
break;
}
case SOUND_PLAYER_ENTER: {
strcpy(soundName, "playerenter");
soundName = "playerenter";
break;
}
case SOUND_CHAT: {
strcpy(soundName, "chatmessage");
soundName = "chatmessage";
break;
}
default:
break;
return;
}
char soundPath[40];
mysnprintf(soundPath, "./sound/%s.wav", soundName);
std::string soundPath = "./sound/" + soundName + ".wav";
SetSoundVolume(mainGame->gameConf.sound_volume);
#ifdef YGOPRO_USE_MINIAUDIO
ma_engine_play_sound(&engineSound, soundPath, nullptr);
ma_engine_play_sound(&engineSound, soundPath.c_str(), nullptr);
#endif
#ifdef YGOPRO_USE_IRRKLANG
engineSound->play2D(soundPath);
engineSound->play2D(soundPath.c_str());
#endif
#endif // YGOPRO_USE_AUDIO
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
#[2026.1][2025.10 TCG][2025.10][2025.7][2025.4][2025.1][2024.10][2024.7][2024.4][2024.1][2023.10][2023.7][2023.4][2023.1][2022.10][2022.7][2022.4][2022.1][2021.10][2021.7][2021.4][2021.1][2020.10][2020.7][2020.4][2020.1][2019.10][2019.7][2019.4][2019.1][2018.10][2018.7][2018.4][2018.1][2017.10][2017.7][2017.4][2017.1][2016.10][2016.7][2016.4][2016.1][2015.10][2015.4][2015.1][2014.10][2014.7][2014.4][2014.2][2013.9][2025.9 TCG][2025.4 TCG][2024.12 TCG][2024.9 TCG][2024.4 TCG][2024.1 TCG][2023.9 TCG][2023.6 TCG][2023.2 TCG][2022.12 TCG][2022.10 TCG][2022.5 TCG][2022.2 TCG][2021.10 TCG][2021.7 TCG][2021.3 TCG][2020.12 TCG][2020.9 TCG][2020.6 TCG][2020.4 TCG][2020.1 TCG][2019.10 TCG][2019.7 TCG][2019.4 TCG][2019.1 TCG][2018.12 TCG][2018.9 TCG][2018.5 TCG][2018.2 TCG][2017.11 TCG][2017.9 TCG][2017.6 TCG][2017.3 TCG][2016.8 TCG][2016.4 TCG][2015.11 TCG][2015.7 TCG][2015.4 TCG][2015.1 TCG][2014.10 TCG][2014.7 TCG][2014.4 TCG][2014.1.1 TCG][2013.10.11 TCG][2013.3.1][2012.9.1][2012.3.1][2011.9.1]
#[2026.1][2026.2 TCG][2025.10][2025.7][2025.4][2025.1][2024.10][2024.7][2024.4][2024.1][2023.10][2023.7][2023.4][2023.1][2022.10][2022.7][2022.4][2022.1][2021.10][2021.7][2021.4][2021.1][2020.10][2020.7][2020.4][2020.1][2019.10][2019.7][2019.4][2019.1][2018.10][2018.7][2018.4][2018.1][2017.10][2017.7][2017.4][2017.1][2016.10][2016.7][2016.4][2016.1][2015.10][2015.4][2015.1][2014.10][2014.7][2014.4][2014.2][2013.9][2025.10 TCG][2025.9 TCG][2025.4 TCG][2024.12 TCG][2024.9 TCG][2024.4 TCG][2024.1 TCG][2023.9 TCG][2023.6 TCG][2023.2 TCG][2022.12 TCG][2022.10 TCG][2022.5 TCG][2022.2 TCG][2021.10 TCG][2021.7 TCG][2021.3 TCG][2020.12 TCG][2020.9 TCG][2020.6 TCG][2020.4 TCG][2020.1 TCG][2019.10 TCG][2019.7 TCG][2019.4 TCG][2019.1 TCG][2018.12 TCG][2018.9 TCG][2018.5 TCG][2018.2 TCG][2017.11 TCG][2017.9 TCG][2017.6 TCG][2017.3 TCG][2016.8 TCG][2016.4 TCG][2015.11 TCG][2015.7 TCG][2015.4 TCG][2015.1 TCG][2014.10 TCG][2014.7 TCG][2014.4 TCG][2014.1.1 TCG][2013.10.11 TCG][2013.3.1][2012.9.1][2012.3.1][2011.9.1]
!2026.1
#forbidden
20292186 0 --アーティファクト-デスサイズ
......@@ -190,7 +190,7 @@
41420027 2 --神の宣告
40366667 2 --霊王の波動
!2025.10 TCG
!2026.2 TCG
#forbidden
62320425 0 --Agido the Ancient Sentinel
06728559 0 --Archnemeses Protos
......@@ -199,6 +199,7 @@
19740112 0 --Barrier Statue of the Drought
47961808 0 --Barrier Statue of the Inferno
73356503 0 --Barrier Statue of the Stormwinds
10963799 0 --Barrier Statue of the Torrent
09929398 0 --Blackwing - Gofu the Vague Shadow
94689206 0 --Block Dragon
69015963 0 --Cyber-Stein
......@@ -237,6 +238,7 @@
03679218 0 --Knightmare Mermaid
30342076 0 --Link Decoder
85243784 0 --Linkross
95454996 0 --Maliss <Q> White Binder
44097050 0 --Mecha Phantom Beast Auroradon
71818935 0 --Moon of the Closed Heaven
25725326 0 --Prank-Kids Meow-Meow-Mu
......@@ -250,6 +252,7 @@
84815190 0 --Baronne de Fleur
27548199 0 --Borreload Savage Dragon
03040496 0 --Chaos Ruler, the Chaotic Magical Dragon
79606837 0 --Herald of the Arc Light
62242678 0 --Hot Red Dragon Archfiend King Calamity
63101919 0 --Tempest Magician
21044178 0 --Abyss Dweller
......@@ -296,6 +299,7 @@
43262273 0 --Appointer of the Red Lotus
01041278 0 --Branded Expulsion
83326048 0 --Dimensional Barrier
87639778 0 --Harpie's Feather Storm
61740673 0 --Imperial Order
28566710 0 --Last Turn
23002292 0 --Red Reboot
......@@ -315,11 +319,12 @@
76794549 1 --Astrograph Sorcerer
06637331 1 --Bystial Druiswurm
33854624 1 --Bystial Magnamhut
14536035 1 --Dark Grepher
91800273 1 --Dimension Shifter
07375867 1 --Dracotail Mululu
33396948 1 --Exodia the Forbidden One
34022970 1 --Ext Ryzeal
63542003 1 --Keldo the Sacred Protector
28642461 1 --K9-66a Jokul
32061192 1 --Maliss <P> Dormouse
36521307 1 --Mathmech Circular
38572779 1 --Miscellaneousaurus
......@@ -330,7 +335,7 @@
74078255 1 --Tearlaments Merrli
00572850 1 --Tearlaments Scheiren
91810826 1 --Tenpai Dragon Chundra
29302858 1 --Vanquish Soul Razen
93156774 1 --Vanquish Soul Hollie Sue
78872731 1 --Zoodiac Ratpier
46640168 1 --Fiendsmith's Lacrima
39512984 1 --Gem-Knight Master Diamond
......@@ -340,25 +345,24 @@
61665245 1 --Summon Sorceress
93896655 1 --Sunavalon Dryas
65563871 1 --Sunvine Healer
79606837 1 --Herald of the Arc Light
30581601 1 --YummySnatchy
13332685 1 --Ame no Habakiri no Mitsurugi
74586817 1 --PSY-Framelord Omega
90953320 1 --T.G. Hyper Librarian
00581014 1 --Daigusto Emeral
75433814 1 --Number 40: Gimmick Puppet of Strings
69170557 1 --Number C40: Gimmick Puppet of Dark Strings
34909328 1 --Ryzeal Detonator
48905153 1 --Zoodiac Drident
80181649 1 --"A Case for K9"
85106525 1 --Bonfire
07394770 1 --Brilliant Fusion
24224830 1 --Called by the Grave
72892473 1 --Card Destruction
59750328 1 --Card of Demise
91623717 1 --Chain Strike
04031928 1 --Change of Heart
99266988 1 --Chaos Space
67616300 1 --Chicken Game
65681983 1 --Crossout Designator
31552317 1 --Crystron Inclusion
15854426 1 --Divine Wind of Mist Valley
95308449 1 --Final Countdown
81439173 1 --Foolish Burial
......@@ -368,6 +372,7 @@
66957584 1 --Infernity Launcher
01845204 1 --Instant Fusion
93946239 1 --Into the Void
06153210 1 --Ketu Dracotail
71650854 1 --Magical Mid-Breaker Field
43040603 1 --Monster Gate
83764718 1 --Monster Reborn
......@@ -383,8 +388,6 @@
73468603 1 --Set Rotation
52340444 1 --Sky Striker Mecha - Hornet Drones
71344451 1 --Slash Draw
45986603 1 --Snatch Steal
54562327 1 --Stake your Soul!
73628505 1 --Terraforming
11110587 1 --That Grass Looks Greener
25311006 1 --Triple Tactics Talent
......@@ -397,12 +400,11 @@
41420027 1 --Solemn Judgment
24207889 1 --There Can Be Only One
#semi limit
61901281 2 --Black Dragon Collapserpent
94145021 2 --Droll & Lock Bird
08633261 2 --Ice Ryzeal
69272449 2 --Maliss <P> White Rabbit
35844557 2 --Sword Ryzeal
41165831 2 --Unchained Soul of Sharvara
99234526 2 --White Dragon Wyverburster
44362883 2 --Branded Fusion
68337209 2 --Maliss in Underground
55584558 2 --Purrely Delicious Memory
......@@ -8711,6 +8713,225 @@
53582587 2 --激流葬
29401950 2 --奈落の落とし穴
!2025.10 TCG
#forbidden
62320425 0 --Agido the Ancient Sentinel
06728559 0 --Archnemeses Protos
80237445 0 --Artifact Mjollnir
20292186 0 --Artifact Scythe
19740112 0 --Barrier Statue of the Drought
47961808 0 --Barrier Statue of the Inferno
73356503 0 --Barrier Statue of the Stormwinds
09929398 0 --Blackwing - Gofu the Vague Shadow
94689206 0 --Block Dragon
69015963 0 --Cyber-Stein
15341821 0 --Dandylion
08903700 0 --Djinn Releaser of Rituals
51858306 0 --Eclipse Wyvern
55623480 0 --Fairy Tail - Snow
78706415 0 --Fiber Jar
93369354 0 --Fishborg Blaster
42009836 0 --Fossil Dyna Pachycephalo
55204071 0 --Gimmick Puppet Nightmare
75732622 0 --Grinder Golem
41855169 0 --Jowgen the Spiritualist
25926710 0 --Kelbek the Ancient Vanguard
57421866 0 --Level Eater
34206604 0 --Magical Scientist
23434538 0 --Maxx "C"
96782886 0 --Mind Master
23558733 0 --Phoenixian Cluster Amaryllis
01357146 0 --Ronintoadin
91258852 0 --SPYRAL Master Plan
88071625 0 --The Tyrant Neptune
44910027 0 --Victory Dragon
17412721 0 --Elder Entity Norden
43387895 0 --Supreme King Dragon Starving Venom
92731385 0 --Tearlaments Kitkallos
04280258 0 --Apollousa, Bow of the Goddess
50588353 0 --Crystron Halqifibrax
98095162 0 --Curious, the Lightsworn Dominion
59537380 0 --Guardragon Agarpain
86148577 0 --Guardragon Elpy
24094258 0 --Heavymetalfoes Electrumite
59934749 0 --Isolde, Two Tales of the Noble Knights
39064822 0 --Knightmare Goblin
65330383 0 --Knightmare Gryphon
03679218 0 --Knightmare Mermaid
30342076 0 --Link Decoder
85243784 0 --Linkross
44097050 0 --Mecha Phantom Beast Auroradon
71818935 0 --Moon of the Closed Heaven
25725326 0 --Prank-Kids Meow-Meow-Mu
70369116 0 --Predaplant Verte Anaconda
72330894 0 --Simorgh, Bird of Sovereignty
59859086 0 --Splash Mage
27381364 0 --Spright Elf
33918636 0 --Superheavy Samurai Scarecrow
22593417 0 --Topologic Gumblar Dragon
83152482 0 --Union Carrier
84815190 0 --Baronne de Fleur
27548199 0 --Borreload Savage Dragon
03040496 0 --Chaos Ruler, the Chaotic Magical Dragon
62242678 0 --Hot Red Dragon Archfiend King Calamity
63101919 0 --Tempest Magician
21044178 0 --Abyss Dweller
00440556 0 --Bahamut Shark
27552504 0 --Beatrice, Lady of the Eternal
38273745 0 --Evilswarm Ouroboros
48626373 0 --Kashtira Arise-Heart
11398059 0 --King of the Feral Imps
34086406 0 --Lavalval Chain
04423206 0 --M-X-Saber Invoker
54719828 0 --Number 16: Shock Master
10389142 0 --Number 42: Galaxy Tomahawk
35772782 0 --Number 67: Pair-a-Dice Smasher
63504681 0 --Number 86: Heroic Champion - Rhongomyniad
95474755 0 --Number 89: Diablosis the Mind Hacker
58820923 0 --Number 95: Galaxy-Eyes Dark Matter Dragon
52653092 0 --Number S0: Utopic ZEXAL
34945480 0 --Outer Entity Azathot
88581108 0 --True King of All Calamities
81122844 0 --Wind-Up Carrier Zenmaity
85115440 0 --Zoodiac Broadbull
69243953 0 --Butterfly Dagger - Elma
57953380 0 --Card of Safe Return
60682203 0 --Cold Wave
17375316 0 --Confiscation
44763025 0 --Delinquent Duo
23557835 0 --Dimension Fusion
42703248 0 --Giant Trunade
79571449 0 --Graceful Charity
19613556 0 --Heavy Storm
35059553 0 --Kaiser Colosseum
85602018 0 --Last Will
34906152 0 --Mass Driver
46411259 0 --Metamorphosis
41482598 0 --Mirage of Nightmare
76375976 0 --Mystic Mine
89023486 0 --Original Sinful Spoils - Snake-Eye
74191942 0 --Painful Choice
55144522 0 --Pot of Greed
70828912 0 --Premature Burial
63789924 0 --Smoke Grenade of the Thief
54447022 0 --Soul Charge
42829885 0 --The Forceful Sentry
43262273 0 --Appointer of the Red Lotus
01041278 0 --Branded Expulsion
83326048 0 --Dimensional Barrier
61740673 0 --Imperial Order
28566710 0 --Last Turn
23002292 0 --Red Reboot
27174286 0 --Return from the Different Dimension
93016201 0 --Royal Oppression
57585212 0 --Self-Destruct Button
03280747 0 --Sixth Sense
23516703 0 --Summon Limit
64697231 0 --Trap Dustshoot
80604091 0 --Ultimate Offering
05851097 0 --Vanity's Emptiness
#limit
07902349 1 --Left Arm of the Forbidden One
44519536 1 --Left Leg of the Forbidden One
70903634 1 --Right Arm of the Forbidden One
08124921 1 --Right Leg of the Forbidden One
76794549 1 --Astrograph Sorcerer
06637331 1 --Bystial Druiswurm
33854624 1 --Bystial Magnamhut
14536035 1 --Dark Grepher
91800273 1 --Dimension Shifter
33396948 1 --Exodia the Forbidden One
34022970 1 --Ext Ryzeal
63542003 1 --Keldo the Sacred Protector
32061192 1 --Maliss <P> Dormouse
36521307 1 --Mathmech Circular
38572779 1 --Miscellaneousaurus
99937011 1 --Mudora the Sword Oracle
38814750 1 --PSY-Framegear Gamma
20663556 1 --Substitoad
37961969 1 --Tearlaments Havnis
74078255 1 --Tearlaments Merrli
00572850 1 --Tearlaments Scheiren
91810826 1 --Tenpai Dragon Chundra
29302858 1 --Vanquish Soul Razen
78872731 1 --Zoodiac Ratpier
46640168 1 --Fiendsmith's Lacrima
39512984 1 --Gem-Knight Master Diamond
80453041 1 --Phantom of Yubel
41999284 1 --Linkuriboh
73539069 1 --Striker Dragon
61665245 1 --Summon Sorceress
93896655 1 --Sunavalon Dryas
65563871 1 --Sunvine Healer
79606837 1 --Herald of the Arc Light
74586817 1 --PSY-Framelord Omega
90953320 1 --T.G. Hyper Librarian
00581014 1 --Daigusto Emeral
75433814 1 --Number 40: Gimmick Puppet of Strings
69170557 1 --Number C40: Gimmick Puppet of Dark Strings
34909328 1 --Ryzeal Detonator
48905153 1 --Zoodiac Drident
85106525 1 --Bonfire
07394770 1 --Brilliant Fusion
24224830 1 --Called by the Grave
72892473 1 --Card Destruction
59750328 1 --Card of Demise
91623717 1 --Chain Strike
04031928 1 --Change of Heart
99266988 1 --Chaos Space
67616300 1 --Chicken Game
65681983 1 --Crossout Designator
31552317 1 --Crystron Inclusion
15854426 1 --Divine Wind of Mist Valley
95308449 1 --Final Countdown
81439173 1 --Foolish Burial
27970830 1 --Gateway of the Six
75500286 1 --Gold Sarcophagus
18144506 1 --Harpie's Feather Duster
66957584 1 --Infernity Launcher
01845204 1 --Instant Fusion
93946239 1 --Into the Void
71650854 1 --Magical Mid-Breaker Field
43040603 1 --Monster Gate
83764718 1 --Monster Reborn
72537897 1 --Obedience Schooled
33782437 1 --One Day of Peace
02295440 1 --One for One
84211599 1 --Pot of Prosperity
58577036 1 --Reasoning
32807846 1 --Reinforcement of the Army
66730191 1 --Sangen Kaimen
30336082 1 --Sangen Summoning
24940422 1 --Sekka's Light
73468603 1 --Set Rotation
52340444 1 --Sky Striker Mecha - Hornet Drones
71344451 1 --Slash Draw
45986603 1 --Snatch Steal
54562327 1 --Stake your Soul!
73628505 1 --Terraforming
11110587 1 --That Grass Looks Greener
25311006 1 --Triple Tactics Talent
58921041 1 --Anti-Spell Fragrance
53334471 1 --Gozen Match
32723153 1 --Magical Explosion
03734202 1 --Naturia Sacred Tree
90846359 1 --Rivalry of Warlords
82732705 1 --Skill Drain
41420027 1 --Solemn Judgment
24207889 1 --There Can Be Only One
#semi limit
61901281 2 --Black Dragon Collapserpent
08633261 2 --Ice Ryzeal
69272449 2 --Maliss <P> White Rabbit
35844557 2 --Sword Ryzeal
41165831 2 --Unchained Soul of Sharvara
99234526 2 --White Dragon Wyverburster
44362883 2 --Branded Fusion
68337209 2 --Maliss in Underground
55584558 2 --Purrely Delicious Memory
21347668 2 --Purrely Sleepy Memory
92107604 2 --Runick Fountain
!2025.9 TCG
#forbidden
62320425 0 --Agido the Ancient Sentinel
......
......@@ -671,6 +671,7 @@
!counter 0x70 盘子指示物
!counter 0x71 纠罪指示物
!counter 0x1072 少女指示物
!counter 0x73 T指示物
#setnames, using tab for comment
!setname 0x1 正义盟军 AOJ
!setname 0x2 次世代 ジェネクス
......@@ -832,7 +833,7 @@
!setname 0x106e 魔导书 魔導書
!setname 0x6f 英豪 ヒロイック
!setname 0x106f 英豪挑战者 HC
#setname 0x206f 英豪冠军 H-C
!setname 0x206f 英豪冠军 HC
!setname 0x70 先史遗产 先史遺産
!setname 0x71 魔偶甜点 マドルチェ
!setname 0x72 齿轮齿轮 ギアギア
......@@ -1278,3 +1279,6 @@
!setname 0x1d8 耀圣 エルフェンノーツ
!setname 0x1d9 磁力 マグネット
!setname 0x1da 世界末日 エンド・オブ・ザ・ワールド
!setname 0x1db 妖精传姬 妖精伝姫
!setname 0x1dc 道化一座 道化の一座
!setname 0x1dd GMX
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