@@ -8,18 +8,110 @@ namespace ygo {
88
99DeckManager deckManager;
1010
11+ void DeckManager::LoadLFListFromLineProvider (const std::function<bool (char *, size_t )>& getLine, bool insert) {
12+ std::vector<LFList> loadedLists;
13+ auto cur = loadedLists.rend ();
14+ char linebuf[256 ]{};
15+ wchar_t strBuffer[256 ]{};
16+ if (true ) {
17+ while (getLine (linebuf, sizeof linebuf)) {
18+ if (linebuf[0 ] == ' #' )
19+ continue ;
20+ if (linebuf[0 ] == ' !' ) {
21+ auto len = std::strcspn (linebuf, " \r\n " );
22+ linebuf[len] = 0 ;
23+ BufferIO::DecodeUTF8 (&linebuf[1 ], strBuffer);
24+ LFList newlist;
25+ newlist.listName = strBuffer;
26+ newlist.hash = 0x7dfcee6a ;
27+ loadedLists.push_back (newlist);
28+ cur = loadedLists.rbegin ();
29+ continue ;
30+ }
31+ if (cur == loadedLists.rend ())
32+ continue ;
33+ if (linebuf[0 ] == ' $' ) {
34+ char * keyPos = linebuf + 1 ;
35+ keyPos += std::strspn (keyPos, " \t " );
36+ auto keyLen = std::strcspn (keyPos, " \t\r\n " );
37+ if (!keyLen)
38+ continue ;
39+ char keybuf[256 ];
40+ if (keyLen >= sizeof keybuf)
41+ keyLen = sizeof keybuf - 1 ;
42+ std::memcpy (keybuf, keyPos, keyLen);
43+ keybuf[keyLen] = 0 ;
44+ keyPos += keyLen;
45+ keyPos += std::strspn (keyPos, " \t " );
46+ errno = 0 ;
47+ char * valuePos = keyPos;
48+ auto limitValue = std::strtoul (keyPos, &keyPos, 10 );
49+ if (errno || valuePos == keyPos)
50+ continue ;
51+ BufferIO::DecodeUTF8 (keybuf, strBuffer);
52+ cur->credit_limits [strBuffer] = static_cast <uint32_t >(limitValue);
53+ continue ;
54+ }
55+ char * pos = linebuf;
56+ errno = 0 ;
57+ char * codePos = pos;
58+ auto result = std::strtoul (pos, &pos, 10 );
59+ if (errno || result > UINT32_MAX || codePos == pos)
60+ continue ;
61+ if (*pos != ' ' && *pos != ' \t ' )
62+ continue ;
63+ pos += std::strspn (pos, " \t " );
64+ uint32_t code = static_cast <uint32_t >(result);
65+ if (*pos == ' $' ) {
66+ ++pos;
67+ pos += std::strspn (pos, " \t " );
68+ auto creditKeyLen = std::strcspn (pos, " \t\r\n " );
69+ if (!creditKeyLen)
70+ continue ;
71+ char keybuf[256 ];
72+ if (creditKeyLen >= sizeof keybuf)
73+ creditKeyLen = sizeof keybuf - 1 ;
74+ std::memcpy (keybuf, pos, creditKeyLen);
75+ keybuf[creditKeyLen] = 0 ;
76+ pos += creditKeyLen;
77+ pos += std::strspn (pos, " \t " );
78+ errno = 0 ;
79+ char * creditValuePos = pos;
80+ auto creditValue = std::strtoul (pos, &pos, 10 );
81+ if (errno || creditValuePos == pos)
82+ continue ;
83+ BufferIO::DecodeUTF8 (keybuf, strBuffer);
84+ cur->credits [code][strBuffer] = static_cast <uint32_t >(creditValue);
85+ continue ;
86+ }
87+ errno = 0 ;
88+ char * countPos = pos;
89+ int count = std::strtol (pos, &pos, 10 );
90+ if (errno || countPos == pos)
91+ continue ;
92+ if (count < 0 || count > 2 )
93+ continue ;
94+ cur->content [code] = count;
95+ cur->hash = cur->hash ^ ((code << 18 ) | (code >> 14 )) ^ ((code << (27 + count)) | (code >> (5 - count)));
96+ }
97+ }
98+ if (insert)
99+ _lfList.insert (_lfList.begin (), loadedLists.begin (), loadedLists.end ());
100+ else
101+ _lfList.insert (_lfList.end (), loadedLists.begin (), loadedLists.end ());
102+ }
11103void DeckManager::LoadLFListSingle (const char * path, bool insert) {
12104 FILE* fp = myfopen (path, " r" );
13105 if (!fp) return ;
14- _LoadLFListFromLineProvider ([&](char * buf, size_t sz) {
106+ LoadLFListFromLineProvider ([&](char * buf, size_t sz) {
15107 return std::fgets (buf, sz, fp) != nullptr ;
16108 }, insert);
17109 std::fclose (fp);
18110}
19111void DeckManager::LoadLFListSingle (const wchar_t * path, bool insert) {
20112 FILE* fp = mywfopen (path, " r" );
21113 if (!fp) return ;
22- _LoadLFListFromLineProvider ([&](char * buf, size_t sz) {
114+ LoadLFListFromLineProvider ([&](char * buf, size_t sz) {
23115 return std::fgets (buf, sz, fp) != nullptr ;
24116 }, insert);
25117 std::fclose (fp);
@@ -28,7 +120,7 @@ void DeckManager::LoadLFListSingle(const wchar_t* path, bool insert) {
28120void DeckManager::LoadLFListSingle (irr::io::IReadFile* reader, bool insert) {
29121 std::string linebuf;
30122 char ch{};
31- _LoadLFListFromLineProvider ([&](char * buf, size_t sz) {
123+ LoadLFListFromLineProvider ([&](char * buf, size_t sz) {
32124 while (reader->read (&ch, 1 )) {
33125 if (ch == ' \0 ' ) break ;
34126 linebuf.push_back (ch);
@@ -97,6 +189,27 @@ unsigned int DeckManager::CheckDeck(const Deck& deck, unsigned int lfhash, int r
97189 if (!lflist)
98190 return 0 ;
99191 auto & list = lflist->content ;
192+ std::unordered_map<std::wstring, uint32_t > credit_used;
193+ auto spend_credit = [&](uint32_t code) {
194+ auto code_credit_it = lflist->credits .find (code);
195+ if (code_credit_it == lflist->credits .end ())
196+ return (uint32_t )0 ;
197+ auto code_credit = code_credit_it->second ;
198+ for (auto & credit_it : code_credit) {
199+ auto key = credit_it.first ;
200+ auto credit_limit_it = lflist->credit_limits .find (key);
201+ if (credit_limit_it == lflist->credit_limits .end ())
202+ continue ;
203+ auto credit_limit = credit_limit_it->second ;
204+ if (credit_used.find (key) == credit_used.end ())
205+ credit_used[key] = 0 ;
206+ auto credit_after = credit_used[key] + credit_it.second ;
207+ if (credit_after > credit_limit)
208+ return (DECKERROR_LFLIST << 28 ) | code;
209+ credit_used[key] = credit_after;
210+ }
211+ return (uint32_t )0 ;
212+ };
100213 const unsigned int rule_map[6 ] = { AVAIL_OCG, AVAIL_TCG, AVAIL_SC, AVAIL_CUSTOM, AVAIL_OCGTCG, 0 };
101214 unsigned int avail = 0 ;
102215 if (rule >= 0 && rule < (int )(sizeof rule_map / sizeof rule_map[0 ]))
@@ -115,6 +228,9 @@ unsigned int DeckManager::CheckDeck(const Deck& deck, unsigned int lfhash, int r
115228 auto it = list.find (code);
116229 if (it != list.end () && dc > it->second )
117230 return (DECKERROR_LFLIST << 28 ) | cit->first ;
231+ auto spend_credit_error = spend_credit (code);
232+ if (spend_credit_error)
233+ return spend_credit_error;
118234 }
119235 for (auto & cit : deck.extra ) {
120236 auto gameruleDeckError = checkAvail (cit->second .ot , avail);
@@ -130,6 +246,9 @@ unsigned int DeckManager::CheckDeck(const Deck& deck, unsigned int lfhash, int r
130246 auto it = list.find (code);
131247 if (it != list.end () && dc > it->second )
132248 return (DECKERROR_LFLIST << 28 ) | cit->first ;
249+ auto spend_credit_error = spend_credit (code);
250+ if (spend_credit_error)
251+ return spend_credit_error;
133252 }
134253 for (auto & cit : deck.side ) {
135254 auto gameruleDeckError = checkAvail (cit->second .ot , avail);
@@ -145,6 +264,9 @@ unsigned int DeckManager::CheckDeck(const Deck& deck, unsigned int lfhash, int r
145264 auto it = list.find (code);
146265 if (it != list.end () && dc > it->second )
147266 return (DECKERROR_LFLIST << 28 ) | cit->first ;
267+ auto spend_credit_error = spend_credit (code);
268+ if (spend_credit_error)
269+ return spend_credit_error;
148270 }
149271 return 0 ;
150272}
0 commit comments