1 Star 0 Fork 0

Alanisia/ygopro-core

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
field.cpp 116.77 KB
一键复制 编辑 原始数据 按行查看 历史
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397
/*
* field.cpp
*
* Created on: 2010-7-21
* Author: Argon
*/
#include "field.h"
#include "duel.h"
#include "card.h"
#include "group.h"
#include "effect.h"
#include "interpreter.h"
int32 field::field_used_count[32] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5};
bool chain::chain_operation_sort(const chain& c1, const chain& c2) {
return c1.triggering_effect->id < c2.triggering_effect->id;
}
void chain::set_triggering_state(card* pcard) {
triggering_controler = pcard->current.controler;
if(pcard->current.is_location(LOCATION_FZONE))
triggering_location = LOCATION_SZONE | LOCATION_FZONE;
else if(pcard->current.is_location(LOCATION_PZONE))
triggering_location = LOCATION_SZONE | LOCATION_PZONE;
else
triggering_location = pcard->current.location;
triggering_sequence = pcard->current.sequence;
triggering_position = pcard->current.position;
triggering_state.code = pcard->get_code();
triggering_state.code2 = pcard->get_another_code();
triggering_state.level = pcard->get_level();
triggering_state.rank = pcard->get_rank();
triggering_state.attribute = pcard->get_attribute();
triggering_state.race = pcard->get_race();
triggering_state.attack = pcard->get_attack();
triggering_state.defense = pcard->get_defense();
}
bool tevent::operator< (const tevent& v) const {
return std::memcmp(this, &v, sizeof(tevent)) < 0;
}
field::field(duel* pduel) {
this->pduel = pduel;
infos.field_id = 1;
infos.copy_id = 1;
infos.can_shuffle = TRUE;
infos.turn_id = 0;
infos.turn_id_by_player[0] = 0;
infos.turn_id_by_player[1] = 0;
infos.card_id = 1;
infos.phase = 0;
infos.turn_player = 0;
for (int32 i = 0; i < 2; ++i) {
//cost[i].count = 0;
//cost[i].amount = 0;
core.hint_timing[i] = 0;
player[i].lp = 8000;
player[i].start_count = 5;
player[i].draw_count = 1;
player[i].disabled_location = 0;
player[i].used_location = 0;
player[i].extra_p_count = 0;
player[i].tag_extra_p_count = 0;
player[i].list_mzone.resize(7, 0);
player[i].list_szone.resize(8, 0);
player[i].list_main.reserve(45);
player[i].list_hand.reserve(10);
player[i].list_grave.reserve(30);
player[i].list_remove.reserve(30);
player[i].list_extra.reserve(15);
core.shuffle_deck_check[i] = FALSE;
core.shuffle_hand_check[i] = FALSE;
}
core.pre_field[0] = 0;
core.pre_field[1] = 0;
core.opp_mzone.clear();
core.summoning_card = 0;
core.summon_depth = 0;
core.summon_cancelable = FALSE;
core.chain_limit.clear();
core.chain_limit_p.clear();
core.chain_solving = FALSE;
core.conti_solving = FALSE;
core.conti_player = PLAYER_NONE;
core.win_player = 5;
core.win_reason = 0;
core.reason_effect = 0;
core.reason_player = PLAYER_NONE;
core.selfdes_disabled = FALSE;
core.flip_delayed = FALSE;
core.overdraw[0] = FALSE;
core.overdraw[1] = FALSE;
core.check_level = 0;
core.limit_tuner = 0;
core.limit_syn = 0;
core.limit_syn_minc = 0;
core.limit_syn_maxc = 0;
core.limit_xyz = 0;
core.limit_xyz_minc = 0;
core.limit_xyz_maxc = 0;
core.limit_link = 0;
core.limit_link_card = 0;
core.limit_link_minc = 0;
core.limit_link_maxc = 0;
core.last_control_changed_id = 0;
core.duel_options = 0;
core.duel_rule = 0;
core.attacker = 0;
core.attack_target = 0;
core.attack_rollback = FALSE;
core.deck_reversed = FALSE;
core.remove_brainwashing = FALSE;
core.effect_damage_step = FALSE;
core.shuffle_check_disabled = FALSE;
core.global_flag = 0;
nil_event.event_code = 0;
nil_event.event_cards = 0;
nil_event.event_player = PLAYER_NONE;
nil_event.event_value = 0;
nil_event.reason = 0;
nil_event.reason_effect = 0;
nil_event.reason_player = PLAYER_NONE;
}
void field::reload_field_info() {
pduel->write_buffer8(MSG_RELOAD_FIELD);
pduel->write_buffer8(core.duel_rule);
for(int32 playerid = 0; playerid < 2; ++playerid) {
pduel->write_buffer32(player[playerid].lp);
for(auto& pcard : player[playerid].list_mzone) {
if(pcard) {
pduel->write_buffer8(1);
pduel->write_buffer8(pcard->current.position);
pduel->write_buffer8((uint8)pcard->xyz_materials.size());
} else {
pduel->write_buffer8(0);
}
}
for(auto& pcard : player[playerid].list_szone) {
if(pcard) {
pduel->write_buffer8(1);
pduel->write_buffer8(pcard->current.position);
} else {
pduel->write_buffer8(0);
}
}
pduel->write_buffer8((uint8)player[playerid].list_main.size());
pduel->write_buffer8((uint8)player[playerid].list_hand.size());
pduel->write_buffer8((uint8)player[playerid].list_grave.size());
pduel->write_buffer8((uint8)player[playerid].list_remove.size());
pduel->write_buffer8((uint8)player[playerid].list_extra.size());
pduel->write_buffer8((uint8)player[playerid].extra_p_count);
}
pduel->write_buffer8((uint8)core.current_chain.size());
for(const auto& ch : core.current_chain) {
effect* peffect = ch.triggering_effect;
pduel->write_buffer32(peffect->get_handler()->data.code);
pduel->write_buffer32(peffect->get_handler()->get_info_location());
pduel->write_buffer8(ch.triggering_controler);
pduel->write_buffer8((uint8)ch.triggering_location);
pduel->write_buffer8(ch.triggering_sequence);
pduel->write_buffer32(peffect->description);
}
}
void field::add_card(uint8 playerid, card* pcard, uint8 location, uint8 sequence, uint8 pzone) {
if (pcard->current.location != 0)
return;
if (!is_location_useable(playerid, location, sequence))
return;
if(pcard->is_extra_deck_monster() && (location & (LOCATION_HAND | LOCATION_DECK))) {
location = LOCATION_EXTRA;
pcard->sendto_param.position = POS_FACEDOWN_DEFENSE;
}
pcard->current.controler = playerid;
pcard->current.location = location;
switch (location) {
case LOCATION_MZONE: {
player[playerid].list_mzone[sequence] = pcard;
pcard->current.sequence = sequence;
break;
}
case LOCATION_SZONE: {
player[playerid].list_szone[sequence] = pcard;
pcard->current.sequence = sequence;
break;
}
case LOCATION_DECK: {
if (sequence == 0) { //deck top
player[playerid].list_main.push_back(pcard);
pcard->current.sequence = (uint8)player[playerid].list_main.size() - 1;
} else if (sequence == 1) { //deck bottom
player[playerid].list_main.insert(player[playerid].list_main.begin(), pcard);
reset_sequence(playerid, LOCATION_DECK);
} else { //deck top & shuffle
player[playerid].list_main.push_back(pcard);
pcard->current.sequence = (uint8)player[playerid].list_main.size() - 1;
if(!core.shuffle_check_disabled)
core.shuffle_deck_check[playerid] = TRUE;
}
pcard->sendto_param.position = POS_FACEDOWN;
break;
}
case LOCATION_HAND: {
player[playerid].list_hand.push_back(pcard);
pcard->current.sequence = (uint8)player[playerid].list_hand.size() - 1;
uint32 pos = pcard->is_affected_by_effect(EFFECT_PUBLIC) ? POS_FACEUP : POS_FACEDOWN;
pcard->sendto_param.position = pos;
if(!(pcard->current.reason & REASON_DRAW) && !core.shuffle_check_disabled)
core.shuffle_hand_check[playerid] = TRUE;
break;
}
case LOCATION_GRAVE: {
player[playerid].list_grave.push_back(pcard);
pcard->current.sequence = (uint8)player[playerid].list_grave.size() - 1;
break;
}
case LOCATION_REMOVED: {
player[playerid].list_remove.push_back(pcard);
pcard->current.sequence = (uint8)player[playerid].list_remove.size() - 1;
break;
}
case LOCATION_EXTRA: {
if(player[playerid].extra_p_count == 0 || (pcard->data.type & TYPE_PENDULUM) && (pcard->sendto_param.position & POS_FACEUP))
player[playerid].list_extra.push_back(pcard);
else
player[playerid].list_extra.insert(player[playerid].list_extra.end() - player[playerid].extra_p_count, pcard);
if((pcard->data.type & TYPE_PENDULUM) && (pcard->sendto_param.position & POS_FACEUP))
++player[playerid].extra_p_count;
reset_sequence(playerid, LOCATION_EXTRA);
break;
}
}
if(pzone)
pcard->current.pzone = true;
else
pcard->current.pzone = false;
pcard->apply_field_effect();
pcard->fieldid = infos.field_id++;
pcard->fieldid_r = pcard->fieldid;
pcard->turnid = infos.turn_id;
if (location == LOCATION_MZONE)
player[playerid].used_location |= 1 << sequence;
if (location == LOCATION_SZONE)
player[playerid].used_location |= 256 << sequence;
}
void field::remove_card(card* pcard) {
if (pcard->current.controler == PLAYER_NONE || pcard->current.location == 0)
return;
uint8 playerid = pcard->current.controler;
switch (pcard->current.location) {
case LOCATION_MZONE:
player[playerid].list_mzone[pcard->current.sequence] = 0;
break;
case LOCATION_SZONE:
player[playerid].list_szone[pcard->current.sequence] = 0;
break;
case LOCATION_DECK:
player[playerid].list_main.erase(player[playerid].list_main.begin() + pcard->current.sequence);
reset_sequence(playerid, LOCATION_DECK);
if(!core.shuffle_check_disabled)
core.shuffle_deck_check[playerid] = TRUE;
break;
case LOCATION_HAND:
player[playerid].list_hand.erase(player[playerid].list_hand.begin() + pcard->current.sequence);
reset_sequence(playerid, LOCATION_HAND);
break;
case LOCATION_GRAVE:
player[playerid].list_grave.erase(player[playerid].list_grave.begin() + pcard->current.sequence);
reset_sequence(playerid, LOCATION_GRAVE);
break;
case LOCATION_REMOVED:
player[playerid].list_remove.erase(player[playerid].list_remove.begin() + pcard->current.sequence);
reset_sequence(playerid, LOCATION_REMOVED);
break;
case LOCATION_EXTRA:
player[playerid].list_extra.erase(player[playerid].list_extra.begin() + pcard->current.sequence);
reset_sequence(playerid, LOCATION_EXTRA);
if((pcard->data.type & TYPE_PENDULUM) && (pcard->current.position & POS_FACEUP))
--player[playerid].extra_p_count;
break;
}
pcard->cancel_field_effect();
if (pcard->current.location == LOCATION_MZONE)
player[playerid].used_location &= ~(1 << pcard->current.sequence);
if (pcard->current.location == LOCATION_SZONE)
player[playerid].used_location &= ~(256 << pcard->current.sequence);
pcard->previous.controler = pcard->current.controler;
pcard->previous.location = pcard->current.location;
pcard->previous.sequence = pcard->current.sequence;
pcard->previous.position = pcard->current.position;
pcard->previous.pzone = pcard->current.pzone;
pcard->current.controler = PLAYER_NONE;
pcard->current.location = 0;
pcard->current.sequence = 0;
}
void field::move_card(uint8 playerid, card* pcard, uint8 location, uint8 sequence, uint8 pzone) {
if (!is_location_useable(playerid, location, sequence))
return;
uint8 preplayer = pcard->current.controler;
uint8 presequence = pcard->current.sequence;
if(pcard->is_extra_deck_monster() && (location & (LOCATION_HAND | LOCATION_DECK))) {
location = LOCATION_EXTRA;
pcard->sendto_param.position = POS_FACEDOWN_DEFENSE;
}
if (pcard->current.location) {
if (pcard->current.location == location) {
if (pcard->current.location == LOCATION_DECK) {
if(preplayer == playerid) {
pduel->write_buffer8(MSG_MOVE);
pduel->write_buffer32(pcard->data.code);
pduel->write_buffer32(pcard->get_info_location());
player[preplayer].list_main.erase(player[preplayer].list_main.begin() + pcard->current.sequence);
if (sequence == 0) { //deck top
player[playerid].list_main.push_back(pcard);
} else if (sequence == 1) {
player[playerid].list_main.insert(player[playerid].list_main.begin(), pcard);
} else {
player[playerid].list_main.push_back(pcard);
if(!core.shuffle_check_disabled)
core.shuffle_deck_check[playerid] = TRUE;
}
reset_sequence(playerid, LOCATION_DECK);
pcard->previous.controler = preplayer;
pcard->current.controler = playerid;
pduel->write_buffer32(pcard->get_info_location());
pduel->write_buffer32(pcard->current.reason);
return;
} else
remove_card(pcard);
} else if(location & LOCATION_ONFIELD) {
if (playerid == preplayer && sequence == presequence)
return;
if(location == LOCATION_MZONE) {
if(sequence >= player[playerid].list_mzone.size() || player[playerid].list_mzone[sequence])
return;
} else {
if(sequence >= player[playerid].list_szone.size() || player[playerid].list_szone[sequence])
return;
}
if(preplayer == playerid) {
pduel->write_buffer8(MSG_MOVE);
pduel->write_buffer32(pcard->data.code);
pduel->write_buffer32(pcard->get_info_location());
}
pcard->previous.controler = pcard->current.controler;
pcard->previous.location = pcard->current.location;
pcard->previous.sequence = pcard->current.sequence;
pcard->previous.position = pcard->current.position;
pcard->previous.pzone = pcard->current.pzone;
if (location == LOCATION_MZONE) {
player[preplayer].list_mzone[presequence] = 0;
player[preplayer].used_location &= ~(1 << presequence);
player[playerid].list_mzone[sequence] = pcard;
player[playerid].used_location |= 1 << sequence;
pcard->current.controler = playerid;
pcard->current.sequence = sequence;
} else {
player[preplayer].list_szone[presequence] = 0;
player[preplayer].used_location &= ~(256 << presequence);
player[playerid].list_szone[sequence] = pcard;
player[playerid].used_location |= 256 << sequence;
pcard->current.controler = playerid;
pcard->current.sequence = sequence;
}
if(preplayer == playerid) {
pduel->write_buffer32(pcard->get_info_location());
pduel->write_buffer32(pcard->current.reason);
} else
pcard->fieldid = infos.field_id++;
return;
} else if(location == LOCATION_HAND) {
if(preplayer == playerid)
return;
remove_card(pcard);
} else {
if(location == LOCATION_GRAVE) {
if(pcard->current.sequence == player[pcard->current.controler].list_grave.size() - 1)
return;
pduel->write_buffer8(MSG_MOVE);
pduel->write_buffer32(pcard->data.code);
pduel->write_buffer32(pcard->get_info_location());
player[pcard->current.controler].list_grave.erase(player[pcard->current.controler].list_grave.begin() + pcard->current.sequence);
player[pcard->current.controler].list_grave.push_back(pcard);
reset_sequence(pcard->current.controler, LOCATION_GRAVE);
pduel->write_buffer32(pcard->get_info_location());
pduel->write_buffer32(pcard->current.reason);
} else if(location == LOCATION_REMOVED) {
if(pcard->current.sequence == player[pcard->current.controler].list_remove.size() - 1)
return;
pduel->write_buffer8(MSG_MOVE);
pduel->write_buffer32(pcard->data.code);
pduel->write_buffer32(pcard->get_info_location());
player[pcard->current.controler].list_remove.erase(player[pcard->current.controler].list_remove.begin() + pcard->current.sequence);
player[pcard->current.controler].list_remove.push_back(pcard);
reset_sequence(pcard->current.controler, LOCATION_REMOVED);
pduel->write_buffer32(pcard->get_info_location());
pduel->write_buffer32(pcard->current.reason);
} else {
pduel->write_buffer8(MSG_MOVE);
pduel->write_buffer32(pcard->data.code);
pduel->write_buffer32(pcard->get_info_location());
player[pcard->current.controler].list_extra.erase(player[pcard->current.controler].list_extra.begin() + pcard->current.sequence);
player[pcard->current.controler].list_extra.push_back(pcard);
reset_sequence(pcard->current.controler, LOCATION_EXTRA);
pduel->write_buffer32(pcard->get_info_location());
pduel->write_buffer32(pcard->current.reason);
}
return;
}
} else {
if((pcard->data.type & TYPE_PENDULUM) && (location == LOCATION_GRAVE)
&& pcard->is_capable_send_to_extra(playerid)
&& (((pcard->current.location == LOCATION_MZONE) && !pcard->is_status(STATUS_SUMMON_DISABLED))
|| ((pcard->current.location == LOCATION_SZONE) && !pcard->is_status(STATUS_ACTIVATE_DISABLED)))) {
location = LOCATION_EXTRA;
pcard->sendto_param.position = POS_FACEUP_DEFENSE;
}
remove_card(pcard);
}
}
add_card(playerid, pcard, location, sequence, pzone);
}
void field::swap_card(card* pcard1, card* pcard2, uint8 new_sequence1, uint8 new_sequence2) {
uint8 p1 = pcard1->current.controler, p2 = pcard2->current.controler;
uint8 l1 = pcard1->current.location, l2 = pcard2->current.location;
uint8 s1 = pcard1->current.sequence, s2 = pcard2->current.sequence;
uint32 info1 = pcard1->get_info_location(), info2 = pcard2->get_info_location();
if(!(l1 & LOCATION_ONFIELD) || !(l2 & LOCATION_ONFIELD))
return;
if(new_sequence1 != s1 && !is_location_useable(p1, l1, new_sequence1)
|| new_sequence2 != s2 && !is_location_useable(p2, l2, new_sequence2))
return;
if(p1 == p2 && l1 == l2 && (new_sequence1 == s2 || new_sequence2 == s1))
return;
if(l1 == l2) {
pcard1->previous.controler = p1;
pcard1->previous.location = l1;
pcard1->previous.sequence = s1;
pcard1->previous.position = pcard1->current.position;
pcard1->previous.pzone = pcard1->current.pzone;
pcard1->current.controler = p2;
pcard1->current.location = l2;
pcard1->current.sequence = new_sequence2;
pcard2->previous.controler = p2;
pcard2->previous.location = l2;
pcard2->previous.sequence = s2;
pcard2->previous.position = pcard2->current.position;
pcard2->previous.pzone = pcard2->current.pzone;
pcard2->current.controler = p1;
pcard2->current.location = l1;
pcard2->current.sequence = new_sequence1;
if(p1 != p2) {
pcard1->fieldid = infos.field_id++;
pcard2->fieldid = infos.field_id++;
}
if(l1 == LOCATION_MZONE) {
player[p1].list_mzone[s1] = 0;
player[p1].used_location &= ~(1 << s1);
player[p2].list_mzone[s2] = 0;
player[p2].used_location &= ~(1 << s2);
player[p2].list_mzone[new_sequence2] = pcard1;
player[p2].used_location |= 1 << new_sequence2;
player[p1].list_mzone[new_sequence1] = pcard2;
player[p1].used_location |= 1 << new_sequence1;
} else if(l1 == LOCATION_SZONE) {
player[p1].list_szone[s1] = 0;
player[p1].used_location &= ~(256 << s1);
player[p2].list_szone[s2] = 0;
player[p2].used_location &= ~(256 << s2);
player[p2].list_szone[new_sequence2] = pcard1;
player[p2].used_location |= 256 << new_sequence2;
player[p1].list_szone[new_sequence1] = pcard2;
player[p1].used_location |= 256 << new_sequence1;
}
} else {
remove_card(pcard1);
remove_card(pcard2);
add_card(p2, pcard1, l2, new_sequence2);
add_card(p1, pcard2, l1, new_sequence1);
}
if(s1 == new_sequence1 && s2 == new_sequence2) {
pduel->write_buffer8(MSG_SWAP);
pduel->write_buffer32(pcard1->data.code);
pduel->write_buffer32(info1);
pduel->write_buffer32(pcard2->data.code);
pduel->write_buffer32(info2);
} else if(s1 == new_sequence1) {
pduel->write_buffer8(MSG_MOVE);
pduel->write_buffer32(pcard1->data.code);
pduel->write_buffer32(info1);
pduel->write_buffer32(pcard1->get_info_location());
pduel->write_buffer32(0);
pduel->write_buffer8(MSG_MOVE);
pduel->write_buffer32(pcard2->data.code);
pduel->write_buffer32(info2);
pduel->write_buffer32(pcard2->get_info_location());
pduel->write_buffer32(0);
} else {
pduel->write_buffer8(MSG_MOVE);
pduel->write_buffer32(pcard2->data.code);
pduel->write_buffer32(info2);
pduel->write_buffer32(pcard2->get_info_location());
pduel->write_buffer32(0);
pduel->write_buffer8(MSG_MOVE);
pduel->write_buffer32(pcard1->data.code);
pduel->write_buffer32(info1);
pduel->write_buffer32(pcard1->get_info_location());
pduel->write_buffer32(0);
}
}
void field::swap_card(card* pcard1, card* pcard2) {
return swap_card(pcard1, pcard2, pcard1->current.sequence, pcard2->current.sequence);
}
void field::set_control(card* pcard, uint8 playerid, uint16 reset_phase, uint8 reset_count) {
if((core.remove_brainwashing && pcard->is_affected_by_effect(EFFECT_REMOVE_BRAINWASHING)) || std::get<uint8>(pcard->refresh_control_status()) == playerid)
return;
effect* peffect = pduel->new_effect();
if(core.reason_effect)
peffect->owner = core.reason_effect->get_handler();
else
peffect->owner = pcard;
peffect->handler = pcard;
peffect->type = EFFECT_TYPE_SINGLE;
peffect->code = EFFECT_SET_CONTROL;
peffect->value = playerid;
peffect->flag[0] = EFFECT_FLAG_CANNOT_DISABLE;
peffect->reset_flag = RESET_EVENT | 0xc6c0000;
if(reset_count) {
peffect->reset_flag |= RESET_PHASE | reset_phase;
if(!(peffect->reset_flag & (RESET_SELF_TURN | RESET_OPPO_TURN)))
peffect->reset_flag |= (RESET_SELF_TURN | RESET_OPPO_TURN);
peffect->reset_count = reset_count;
}
pcard->add_effect(peffect);
pcard->current.controler = playerid;
}
card* field::get_field_card(uint32 playerid, uint32 location, uint32 sequence) {
switch(location) {
case LOCATION_MZONE: {
if(sequence < player[playerid].list_mzone.size())
return player[playerid].list_mzone[sequence];
else
return 0;
break;
}
case LOCATION_SZONE: {
if(sequence < player[playerid].list_szone.size())
return player[playerid].list_szone[sequence];
else
return 0;
break;
}
case LOCATION_FZONE: {
if(sequence == 0)
return player[playerid].list_szone[5];
else
return 0;
break;
}
case LOCATION_PZONE: {
if(sequence == 0) {
card* pcard = player[playerid].list_szone[core.duel_rule >= 4 ? 0 : 6];
return pcard && pcard->current.pzone ? pcard : 0;
} else if(sequence == 1) {
card* pcard = player[playerid].list_szone[core.duel_rule >= 4 ? 4 : 7];
return pcard && pcard->current.pzone ? pcard : 0;
} else
return 0;
break;
}
case LOCATION_DECK: {
if(sequence < player[playerid].list_main.size())
return player[playerid].list_main[sequence];
else
return 0;
break;
}
case LOCATION_HAND: {
if(sequence < player[playerid].list_hand.size())
return player[playerid].list_hand[sequence];
else
return 0;
break;
}
case LOCATION_GRAVE: {
if(sequence < player[playerid].list_grave.size())
return player[playerid].list_grave[sequence];
else
return 0;
break;
}
case LOCATION_REMOVED: {
if(sequence < player[playerid].list_remove.size())
return player[playerid].list_remove[sequence];
else
return 0;
break;
}
case LOCATION_EXTRA: {
if(sequence < player[playerid].list_extra.size())
return player[playerid].list_extra[sequence];
else
return 0;
break;
}
}
return 0;
}
int32 field::is_location_useable(uint32 playerid, uint32 location, uint32 sequence) {
uint32 flag = player[playerid].disabled_location | player[playerid].used_location;
if (location == LOCATION_MZONE) {
if(flag & (0x1u << sequence))
return FALSE;
if(sequence >= 5) {
uint32 oppo = player[1 - playerid].disabled_location | player[1 - playerid].used_location;
if(oppo & (0x1u << (11 - sequence)))
return FALSE;
}
} else if (location == LOCATION_SZONE) {
if(flag & (0x100u << sequence))
return FALSE;
} else if (location == LOCATION_FZONE) {
if(flag & (0x100u << (5 + sequence)))
return FALSE;
} else if (location == LOCATION_PZONE) {
if(core.duel_rule >= 4) {
if(flag & (0x100u << (sequence * 4)))
return FALSE;
} else {
if(flag & (0x100u << (6 + sequence)))
return FALSE;
}
}
return TRUE;
}
// uplayer: request player, PLAYER_NONE means ignoring EFFECT_MAX_MZONE, EFFECT_MAX_SZONE
// list: store local flag in list
// return: usable count of LOCATION_MZONE or real LOCATION_SZONE of playerid requested by uplayer (may be negative)
int32 field::get_useable_count(card* pcard, uint8 playerid, uint8 location, uint8 uplayer, uint32 reason, uint32 zone, uint32* list) {
if(location == LOCATION_MZONE && pcard && pcard->current.location == LOCATION_EXTRA)
return get_useable_count_fromex(pcard, playerid, uplayer, zone, list);
else
return get_useable_count_other(pcard, playerid, location, uplayer, reason, zone, list);
}
int32 field::get_useable_count_fromex(card* pcard, uint8 playerid, uint8 uplayer, uint32 zone, uint32* list) {
bool use_temp_card = false;
if(!pcard) {
use_temp_card = true;
pcard = temp_card;
pcard->current.location = LOCATION_EXTRA;
}
int32 useable_count = 0;
if(core.duel_rule >= 4)
useable_count = get_useable_count_fromex_rule4(pcard, playerid, uplayer, zone, list);
else
useable_count = get_useable_count_other(pcard, playerid, LOCATION_MZONE, uplayer, LOCATION_REASON_TOFIELD, zone, list);
if(use_temp_card)
pcard->current.location = 0;
return useable_count;
}
int32 field::get_spsummonable_count(card* pcard, uint8 playerid, uint32 zone, uint32* list) {
if(pcard->current.location == LOCATION_EXTRA)
return get_spsummonable_count_fromex(pcard, playerid, playerid, zone, list);
else
return get_tofield_count(pcard, playerid, LOCATION_MZONE, playerid, LOCATION_REASON_TOFIELD, zone, list);
}
int32 field::get_spsummonable_count_fromex(card* pcard, uint8 playerid, uint8 uplayer, uint32 zone, uint32* list) {
bool use_temp_card = false;
if(!pcard) {
use_temp_card = true;
pcard = temp_card;
pcard->current.location = LOCATION_EXTRA;
}
int32 spsummonable_count = 0;
if(core.duel_rule >= 4)
spsummonable_count = get_spsummonable_count_fromex_rule4(pcard, playerid, uplayer, zone, list);
else
spsummonable_count = get_tofield_count(pcard, playerid, LOCATION_MZONE, uplayer, LOCATION_REASON_TOFIELD, zone, list);
if(use_temp_card)
pcard->current.location = 0;
return spsummonable_count;
}
int32 field::get_useable_count_other(card* pcard, uint8 playerid, uint8 location, uint8 uplayer, uint32 reason, uint32 zone, uint32* list) {
int32 count = get_tofield_count(pcard, playerid, location, uplayer, reason, zone, list);
int32 limit;
if(location == LOCATION_MZONE)
limit = get_mzone_limit(playerid, uplayer, reason);
else
limit = get_szone_limit(playerid, uplayer, reason);
if(count > limit)
count = limit;
return count;
}
int32 field::get_tofield_count(card* pcard, uint8 playerid, uint8 location, uint32 uplayer, uint32 reason, uint32 zone, uint32* list) {
if (location != LOCATION_MZONE && location != LOCATION_SZONE)
return 0;
uint32 flag = player[playerid].disabled_location | player[playerid].used_location;
if(location == LOCATION_MZONE && (reason & LOCATION_REASON_TOFIELD)) {
filter_must_use_mzone(playerid, uplayer, reason, pcard, &flag);
}
if (location == LOCATION_MZONE)
flag = (flag | ~zone) & 0x1f;
else
flag = ((flag >> 8) | ~zone) & 0x1f;
int32 count = 5 - field_used_count[flag];
if(location == LOCATION_MZONE)
flag |= (1u << 5) | (1u << 6);
if(list)
*list = flag;
return count;
}
int32 field::get_useable_count_fromex_rule4(card* pcard, uint8 playerid, uint8 uplayer, uint32 zone, uint32* list) {
int32 count = get_spsummonable_count_fromex_rule4(pcard, playerid, uplayer, zone, list);
int32 limit = get_mzone_limit(playerid, uplayer, LOCATION_REASON_TOFIELD);
if(count > limit)
count = limit;
return count;
}
int32 field::get_spsummonable_count_fromex_rule4(card* pcard, uint8 playerid, uint8 uplayer, uint32 zone, uint32* list) {
uint32 flag = player[playerid].disabled_location | player[playerid].used_location;
filter_must_use_mzone(playerid, uplayer, LOCATION_REASON_TOFIELD, pcard, &flag);
if(player[playerid].list_mzone[5] && is_location_useable(playerid, LOCATION_MZONE, 6)
&& check_extra_link(playerid, pcard, 6)) {
flag |= 1u << 5;
} else if(player[playerid].list_mzone[6] && is_location_useable(playerid, LOCATION_MZONE, 5)
&& check_extra_link(playerid, pcard, 5)) {
flag |= 1u << 6;
} else if(player[playerid].list_mzone[5] || player[playerid].list_mzone[6]) {
flag |= (1u << 5) | (1u << 6);
} else {
if(!is_location_useable(playerid, LOCATION_MZONE, 5))
flag |= 1u << 5;
if(!is_location_useable(playerid, LOCATION_MZONE, 6))
flag |= 1u << 6;
}
uint32 rule_zone = get_rule_zone_fromex(playerid, pcard);
flag = flag | ~zone | ~rule_zone;
if(list)
*list = flag & 0x7f;
int32 count = 5 - field_used_count[flag & 0x1f];
if(~flag & ((1u << 5) | (1u << 6)))
count++;
return count;
}
int32 field::get_mzone_limit(uint8 playerid, uint8 uplayer, uint32 reason) {
uint32 used_flag = player[playerid].used_location;
used_flag = used_flag & 0x1f;
int32 max = 5;
int32 used_count = field_used_count[used_flag];
if(core.duel_rule >= 4) {
max = 7;
if(player[playerid].list_mzone[5])
used_count++;
if(player[playerid].list_mzone[6])
used_count++;
}
effect_set eset;
if(uplayer < 2)
filter_player_effect(playerid, EFFECT_MAX_MZONE, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(uplayer, PARAM_TYPE_INT);
pduel->lua->add_param(reason, PARAM_TYPE_INT);
int32 v = eset[i]->get_value(3);
if(max > v)
max = v;
}
int32 limit = max - used_count;
return limit;
}
int32 field::get_szone_limit(uint8 playerid, uint8 uplayer, uint32 reason) {
uint32 used_flag = player[playerid].used_location;
used_flag = (used_flag >> 8) & 0x1f;
effect_set eset;
if(uplayer < 2)
filter_player_effect(playerid, EFFECT_MAX_SZONE, &eset);
int32 max = 5;
for(int32 i = 0; i < eset.size(); ++i) {
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(uplayer, PARAM_TYPE_INT);
pduel->lua->add_param(reason, PARAM_TYPE_INT);
int32 v = eset[i]->get_value(3);
if(max > v)
max = v;
}
int32 limit = max - field_used_count[used_flag];
return limit;
}
uint32 field::get_linked_zone(int32 playerid) {
uint32 zones = 0;
for(auto& pcard : player[playerid].list_mzone) {
if(pcard)
zones |= pcard->get_linked_zone() & 0xff;
}
for(auto& pcard : player[1 - playerid].list_mzone) {
if(pcard)
zones |= pcard->get_linked_zone() >> 16;
}
return zones;
}
uint32 field::get_rule_zone_fromex(int32 playerid, card* pcard) {
if(core.duel_rule >= 4) {
if(core.duel_rule >= 5 && pcard && pcard->is_position(POS_FACEDOWN) && (pcard->data.type & (TYPE_FUSION | TYPE_SYNCHRO | TYPE_XYZ)))
return 0x7f;
else
return get_linked_zone(playerid) | (1u << 5) | (1u << 6);
} else {
return 0x1f;
}
}
void field::filter_must_use_mzone(uint8 playerid, uint8 uplayer, uint32 reason, card* pcard, uint32* flag) {
effect_set eset;
if(uplayer < 2)
filter_player_effect(uplayer, EFFECT_MUST_USE_MZONE, &eset);
if(pcard)
pcard->filter_effect(EFFECT_MUST_USE_MZONE, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(eset[i]->is_flag(EFFECT_FLAG_COUNT_LIMIT) && eset[i]->count_limit == 0)
continue;
uint32 value = 0x1f;
if(eset[i]->is_flag(EFFECT_FLAG_PLAYER_TARGET))
value = eset[i]->get_value();
else {
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(uplayer, PARAM_TYPE_INT);
pduel->lua->add_param(reason, PARAM_TYPE_INT);
value = eset[i]->get_value(pcard, 3);
}
if(eset[i]->get_handler_player() == playerid)
*flag |= ~value & 0x7f;
else
*flag |= ~(value >> 16) & 0x7f;
}
}
void field::get_linked_cards(uint8 self, uint8 s, uint8 o, card_set* cset) {
cset->clear();
uint8 c = s;
for(int32 p = 0; p < 2; ++p) {
if(c) {
uint32 linked_zone = get_linked_zone(self);
get_cards_in_zone(cset, linked_zone, self, LOCATION_MZONE);
}
self = 1 - self;
c = o;
}
}
int32 field::check_extra_link(int32 playerid) {
if(!player[playerid].list_mzone[5] || !player[playerid].list_mzone[6])
return FALSE;
card* pcard = player[playerid].list_mzone[5];
uint32 checked = 1u << 5;
uint32 linked_zone = pcard->get_mutual_linked_zone();
while(true) {
if((linked_zone >> 6) & 1)
return TRUE;
int32 checking = (int32)(linked_zone & ~checked);
if(!checking)
return FALSE;
int32 rightmost = checking & (-checking);
checked |= (uint32)rightmost;
if(rightmost < 0x10000) {
for(int32 i = 0; i < 7; ++i) {
if(rightmost & 1) {
pcard = player[playerid].list_mzone[i];
linked_zone |= pcard->get_mutual_linked_zone();
break;
}
rightmost >>= 1;
}
} else {
rightmost >>= 16;
for(int32 i = 0; i < 7; ++i) {
if(rightmost & 1) {
pcard = player[1 - playerid].list_mzone[i];
uint32 zone = pcard->get_mutual_linked_zone();
linked_zone |= (zone << 16) | (zone >> 16);
break;
}
rightmost >>= 1;
}
}
}
return FALSE;
}
int32 field::check_extra_link(int32 playerid, card* pcard, int32 sequence) {
if(!pcard)
return FALSE;
if(player[playerid].list_mzone[sequence])
return FALSE;
uint8 cur_controler = pcard->current.controler;
uint8 cur_location = pcard->current.location;
uint8 cur_sequence = pcard->current.sequence;
player[playerid].list_mzone[sequence] = pcard;
pcard->current.controler = playerid;
pcard->current.location = LOCATION_MZONE;
pcard->current.sequence = sequence;
int32 ret = check_extra_link(playerid);
player[playerid].list_mzone[sequence] = 0;
pcard->current.controler = cur_controler;
pcard->current.location = cur_location;
pcard->current.sequence = cur_sequence;
return ret;
}
void field::get_cards_in_zone(card_set* cset, uint32 zone, int32 playerid, int32 location) {
if(!(location & LOCATION_ONFIELD))
return;
card_vector& svector = (location == LOCATION_MZONE) ? player[playerid].list_mzone : player[playerid].list_szone;
uint32 icheck = 0x1;
for(auto& pcard : svector) {
if(zone & icheck) {
if(pcard)
cset->insert(pcard);
}
icheck <<= 1;
}
}
void field::shuffle(uint8 playerid, uint8 location) {
if(!(location & (LOCATION_HAND | LOCATION_DECK | LOCATION_EXTRA)))
return;
card_vector& svector = (location == LOCATION_HAND) ? player[playerid].list_hand : (location == LOCATION_DECK) ? player[playerid].list_main : player[playerid].list_extra;
if(svector.size() == 0)
return;
if(location == LOCATION_HAND) {
bool shuffle = false;
for(auto& pcard : svector)
if(!pcard->is_position(POS_FACEUP))
shuffle = true;
if(!shuffle) {
core.shuffle_hand_check[playerid] = FALSE;
return;
}
}
if(location == LOCATION_HAND || !(core.duel_options & DUEL_PSEUDO_SHUFFLE)) {
uint32 s = (uint32)svector.size();
if(location == LOCATION_EXTRA)
s = s - player[playerid].extra_p_count;
if(s > 1) {
uint32 i = 0, r;
for(i = 0; i < s - 1; ++i) {
r = pduel->get_next_integer(i, s - 1);
card* t = svector[i];
svector[i] = svector[r];
svector[r] = t;
}
reset_sequence(playerid, location);
}
}
if(location == LOCATION_HAND || location == LOCATION_EXTRA) {
pduel->write_buffer8((location == LOCATION_HAND) ? MSG_SHUFFLE_HAND : MSG_SHUFFLE_EXTRA);
pduel->write_buffer8(playerid);
pduel->write_buffer8((uint8)svector.size());
for(auto& pcard : svector)
pduel->write_buffer32(pcard->data.code);
if(location == LOCATION_HAND) {
core.shuffle_hand_check[playerid] = FALSE;
for(auto& pcard : svector) {
for(auto& i : pcard->indexer) {
effect* peffect = i.first;
if(peffect->is_flag(EFFECT_FLAG_CLIENT_HINT) && !peffect->is_flag(EFFECT_FLAG_PLAYER_TARGET)) {
pduel->write_buffer8(MSG_CARD_HINT);
pduel->write_buffer32(pcard->get_info_location());
pduel->write_buffer8(CHINT_DESC_ADD);
pduel->write_buffer32(peffect->description);
}
}
}
}
} else {
pduel->write_buffer8(MSG_SHUFFLE_DECK);
pduel->write_buffer8(playerid);
core.shuffle_deck_check[playerid] = FALSE;
if(core.global_flag & GLOBALFLAG_DECK_REVERSE_CHECK) {
card* ptop = svector.back();
if(core.deck_reversed || (ptop->current.position == POS_FACEUP_DEFENSE)) {
pduel->write_buffer8(MSG_DECK_TOP);
pduel->write_buffer8(playerid);
pduel->write_buffer8(0);
if(ptop->current.position != POS_FACEUP_DEFENSE)
pduel->write_buffer32(ptop->data.code);
else
pduel->write_buffer32(ptop->data.code | 0x80000000);
}
}
}
}
void field::reset_sequence(uint8 playerid, uint8 location) {
if(location & (LOCATION_ONFIELD))
return;
uint32 i = 0;
switch(location) {
case LOCATION_DECK:
for(auto& pcard : player[playerid].list_main)
pcard->current.sequence = i++;
break;
case LOCATION_HAND:
for(auto& pcard : player[playerid].list_hand)
pcard->current.sequence = i++;
break;
case LOCATION_EXTRA:
for(auto& pcard : player[playerid].list_extra)
pcard->current.sequence = i++;
break;
case LOCATION_GRAVE:
for(auto& pcard : player[playerid].list_grave)
pcard->current.sequence = i++;
break;
case LOCATION_REMOVED:
for(auto& pcard : player[playerid].list_remove)
pcard->current.sequence = i++;
break;
}
}
void field::swap_deck_and_grave(uint8 playerid) {
for(auto& pcard : player[playerid].list_grave) {
pcard->previous.location = LOCATION_GRAVE;
pcard->previous.sequence = pcard->current.sequence;
pcard->enable_field_effect(false);
pcard->cancel_field_effect();
}
for(auto& pcard : player[playerid].list_main) {
pcard->previous.location = LOCATION_DECK;
pcard->previous.sequence = pcard->current.sequence;
pcard->enable_field_effect(false);
pcard->cancel_field_effect();
}
player[playerid].list_grave.swap(player[playerid].list_main);
card_vector ex;
for(auto clit = player[playerid].list_main.begin(); clit != player[playerid].list_main.end(); ) {
if((*clit)->is_extra_deck_monster()) {
ex.push_back(*clit);
clit = player[playerid].list_main.erase(clit);
} else
++clit;
}
for(auto& pcard : player[playerid].list_grave) {
pcard->current.location = LOCATION_GRAVE;
pcard->current.reason = REASON_EFFECT;
pcard->current.reason_effect = core.reason_effect;
pcard->current.reason_player = core.reason_player;
pcard->apply_field_effect();
pcard->enable_field_effect(true);
pcard->reset(RESET_TOGRAVE, RESET_EVENT);
}
for(auto& pcard : player[playerid].list_main) {
pcard->current.location = LOCATION_DECK;
pcard->current.reason = REASON_EFFECT;
pcard->current.reason_effect = core.reason_effect;
pcard->current.reason_player = core.reason_player;
pcard->apply_field_effect();
pcard->enable_field_effect(true);
pcard->reset(RESET_TODECK, RESET_EVENT);
}
for(auto& pcard : ex) {
pcard->current.location = LOCATION_EXTRA;
pcard->current.reason = REASON_EFFECT;
pcard->current.reason_effect = core.reason_effect;
pcard->current.reason_player = core.reason_player;
pcard->apply_field_effect();
pcard->enable_field_effect(true);
pcard->reset(RESET_TODECK, RESET_EVENT);
}
player[playerid].list_extra.insert(player[playerid].list_extra.end(), ex.begin(), ex.end());
reset_sequence(playerid, LOCATION_GRAVE);
reset_sequence(playerid, LOCATION_EXTRA);
pduel->write_buffer8(MSG_SWAP_GRAVE_DECK);
pduel->write_buffer8(playerid);
shuffle(playerid, LOCATION_DECK);
}
void field::reverse_deck(uint8 playerid) {
int32 count = (int32)player[playerid].list_main.size();
if(count == 0)
return;
for(int32 i = 0; i < count / 2; ++i) {
card* tmp = player[playerid].list_main[i];
tmp->current.sequence = count - 1 - i;
player[playerid].list_main[count - 1 - i]->current.sequence = i;
player[playerid].list_main[i] = player[playerid].list_main[count - 1 - i];
player[playerid].list_main[count - 1 - i] = tmp;
}
}
void field::tag_swap(uint8 playerid) {
//main
for(auto& pcard : player[playerid].list_main) {
pcard->enable_field_effect(false);
pcard->cancel_field_effect();
}
std::swap(player[playerid].list_main, player[playerid].tag_list_main);
for(auto& pcard : player[playerid].list_main) {
pcard->apply_field_effect();
pcard->enable_field_effect(true);
}
//hand
for(auto& pcard : player[playerid].list_hand) {
pcard->enable_field_effect(false);
pcard->cancel_field_effect();
}
std::swap(player[playerid].list_hand, player[playerid].tag_list_hand);
for(auto& pcard : player[playerid].list_hand) {
pcard->apply_field_effect();
pcard->enable_field_effect(true);
}
//extra
for(auto& pcard : player[playerid].list_extra) {
pcard->enable_field_effect(false);
pcard->cancel_field_effect();
}
std::swap(player[playerid].list_extra, player[playerid].tag_list_extra);
std::swap(player[playerid].extra_p_count, player[playerid].tag_extra_p_count);
for(auto& pcard : player[playerid].list_extra) {
pcard->apply_field_effect();
pcard->enable_field_effect(true);
}
pduel->write_buffer8(MSG_TAG_SWAP);
pduel->write_buffer8(playerid);
pduel->write_buffer8((uint8)player[playerid].list_main.size());
pduel->write_buffer8((uint8)player[playerid].list_extra.size());
pduel->write_buffer8((uint8)player[playerid].extra_p_count);
pduel->write_buffer8((uint8)player[playerid].list_hand.size());
if(core.deck_reversed && player[playerid].list_main.size())
pduel->write_buffer32(player[playerid].list_main.back()->data.code);
else
pduel->write_buffer32(0);
for(auto& pcard : player[playerid].list_hand)
pduel->write_buffer32(pcard->data.code | (pcard->is_position(POS_FACEUP) ? 0x80000000 : 0));
for(auto& pcard : player[playerid].list_extra)
pduel->write_buffer32(pcard->data.code | (pcard->is_position(POS_FACEUP) ? 0x80000000 : 0));
}
void field::add_effect(effect* peffect, uint8 owner_player) {
if (!peffect->handler) {
peffect->flag[0] |= EFFECT_FLAG_FIELD_ONLY;
peffect->handler = peffect->owner;
peffect->effect_owner = owner_player;
peffect->id = infos.field_id++;
}
peffect->card_type = peffect->owner->data.type;
effect_container::iterator it;
if (!(peffect->type & EFFECT_TYPE_ACTIONS)) {
it = effects.aura_effect.emplace(peffect->code, peffect);
if(peffect->code == EFFECT_SPSUMMON_COUNT_LIMIT)
effects.spsummon_count_eff.insert(peffect);
if(peffect->type & EFFECT_TYPE_GRANT)
effects.grant_effect.emplace(peffect, field_effect::gain_effects());
} else {
if (peffect->type & EFFECT_TYPE_IGNITION)
it = effects.ignition_effect.emplace(peffect->code, peffect);
else if (peffect->type & EFFECT_TYPE_TRIGGER_O && peffect->type & EFFECT_TYPE_FIELD)
it = effects.trigger_o_effect.emplace(peffect->code, peffect);
else if (peffect->type & EFFECT_TYPE_TRIGGER_F && peffect->type & EFFECT_TYPE_FIELD)
it = effects.trigger_f_effect.emplace(peffect->code, peffect);
else if (peffect->type & EFFECT_TYPE_QUICK_O)
it = effects.quick_o_effect.emplace(peffect->code, peffect);
else if (peffect->type & EFFECT_TYPE_QUICK_F)
it = effects.quick_f_effect.emplace(peffect->code, peffect);
else if (peffect->type & EFFECT_TYPE_ACTIVATE)
it = effects.activate_effect.emplace(peffect->code, peffect);
else if (peffect->type & EFFECT_TYPE_CONTINUOUS)
it = effects.continuous_effect.emplace(peffect->code, peffect);
}
effects.indexer.emplace(peffect, it);
if(peffect->is_flag(EFFECT_FLAG_FIELD_ONLY)) {
if(peffect->is_disable_related())
update_disable_check_list(peffect);
if(peffect->is_flag(EFFECT_FLAG_OATH))
effects.oath.emplace(peffect, core.reason_effect);
if(peffect->reset_flag & RESET_PHASE)
effects.pheff.insert(peffect);
if(peffect->reset_flag & RESET_CHAIN)
effects.cheff.insert(peffect);
if(peffect->is_flag(EFFECT_FLAG_COUNT_LIMIT))
effects.rechargeable.insert(peffect);
if(peffect->is_flag(EFFECT_FLAG_PLAYER_TARGET) && peffect->is_flag(EFFECT_FLAG_CLIENT_HINT)) {
bool target_player[2] = {false, false};
if(peffect->s_range)
target_player[owner_player] = true;
if(peffect->o_range)
target_player[1 - owner_player] = true;
if(target_player[0]) {
pduel->write_buffer8(MSG_PLAYER_HINT);
pduel->write_buffer8(0);
pduel->write_buffer8(PHINT_DESC_ADD);
pduel->write_buffer32(peffect->description);
}
if(target_player[1]) {
pduel->write_buffer8(MSG_PLAYER_HINT);
pduel->write_buffer8(1);
pduel->write_buffer8(PHINT_DESC_ADD);
pduel->write_buffer32(peffect->description);
}
}
}
}
void field::remove_effect(effect* peffect) {
auto eit = effects.indexer.find(peffect);
if (eit == effects.indexer.end())
return;
auto it = eit->second;
if (!(peffect->type & EFFECT_TYPE_ACTIONS)) {
effects.aura_effect.erase(it);
if(peffect->code == EFFECT_SPSUMMON_COUNT_LIMIT)
effects.spsummon_count_eff.erase(peffect);
if(peffect->type & EFFECT_TYPE_GRANT)
erase_grant_effect(peffect);
} else {
if (peffect->type & EFFECT_TYPE_IGNITION)
effects.ignition_effect.erase(it);
else if (peffect->type & EFFECT_TYPE_TRIGGER_O)
effects.trigger_o_effect.erase(it);
else if (peffect->type & EFFECT_TYPE_TRIGGER_F)
effects.trigger_f_effect.erase(it);
else if (peffect->type & EFFECT_TYPE_QUICK_O)
effects.quick_o_effect.erase(it);
else if (peffect->type & EFFECT_TYPE_QUICK_F)
effects.quick_f_effect.erase(it);
else if (peffect->type & EFFECT_TYPE_ACTIVATE)
effects.activate_effect.erase(it);
else if (peffect->type & EFFECT_TYPE_CONTINUOUS)
effects.continuous_effect.erase(it);
}
effects.indexer.erase(peffect);
if(peffect->is_flag(EFFECT_FLAG_FIELD_ONLY)) {
if(peffect->is_disable_related())
update_disable_check_list(peffect);
if(peffect->is_flag(EFFECT_FLAG_OATH))
effects.oath.erase(peffect);
if(peffect->reset_flag & RESET_PHASE)
effects.pheff.erase(peffect);
if(peffect->reset_flag & RESET_CHAIN)
effects.cheff.erase(peffect);
if(peffect->is_flag(EFFECT_FLAG_COUNT_LIMIT))
effects.rechargeable.erase(peffect);
core.reseted_effects.insert(peffect);
if(peffect->is_flag(EFFECT_FLAG_PLAYER_TARGET) && peffect->is_flag(EFFECT_FLAG_CLIENT_HINT)) {
bool target_player[2] = {false, false};
if(peffect->s_range)
target_player[peffect->effect_owner] = true;
if(peffect->o_range)
target_player[1 - peffect->effect_owner] = true;
if(target_player[0]) {
pduel->write_buffer8(MSG_PLAYER_HINT);
pduel->write_buffer8(0);
pduel->write_buffer8(PHINT_DESC_REMOVE);
pduel->write_buffer32(peffect->description);
}
if(target_player[1]) {
pduel->write_buffer8(MSG_PLAYER_HINT);
pduel->write_buffer8(1);
pduel->write_buffer8(PHINT_DESC_REMOVE);
pduel->write_buffer32(peffect->description);
}
}
}
}
void field::remove_oath_effect(effect* reason_effect) {
for(auto oeit = effects.oath.begin(); oeit != effects.oath.end();) {
auto rm = oeit++;
if(rm->second == reason_effect) {
effect* peffect = rm->first;
effects.oath.erase(rm);
if(peffect->is_flag(EFFECT_FLAG_FIELD_ONLY))
remove_effect(peffect);
else
peffect->handler->remove_effect(peffect);
}
}
}
void field::release_oath_relation(effect* reason_effect) {
for(auto& oeit : effects.oath)
if(oeit.second == reason_effect)
oeit.second = 0;
}
void field::reset_phase(uint32 phase) {
for(auto eit = effects.pheff.begin(); eit != effects.pheff.end();) {
auto rm = eit++;
if((*rm)->reset(phase, RESET_PHASE)) {
if((*rm)->is_flag(EFFECT_FLAG_FIELD_ONLY))
remove_effect((*rm));
else
(*rm)->handler->remove_effect((*rm));
}
}
}
void field::reset_chain() {
for(auto eit = effects.cheff.begin(); eit != effects.cheff.end();) {
auto rm = eit++;
if((*rm)->is_flag(EFFECT_FLAG_FIELD_ONLY))
remove_effect((*rm));
else
(*rm)->handler->remove_effect((*rm));
}
}
void field::add_effect_code(uint32 code, uint32 playerid) {
auto& count_map = (code & EFFECT_COUNT_CODE_DUEL) ? core.effect_count_code_duel : core.effect_count_code;
count_map[code + (playerid << 30)]++;
}
uint32 field::get_effect_code(uint32 code, uint32 playerid) {
auto& count_map = (code & EFFECT_COUNT_CODE_DUEL) ? core.effect_count_code_duel : core.effect_count_code;
auto iter = count_map.find(code + (playerid << 30));
if(iter == count_map.end())
return 0;
return iter->second;
}
void field::dec_effect_code(uint32 code, uint32 playerid) {
auto& count_map = (code & EFFECT_COUNT_CODE_DUEL) ? core.effect_count_code_duel : core.effect_count_code;
auto iter = count_map.find(code + (playerid << 30));
if(iter == count_map.end())
return;
if(iter->second > 0)
iter->second--;
}
void field::filter_field_effect(uint32 code, effect_set* eset, uint8 sort) {
auto rg = effects.aura_effect.equal_range(code);
for (; rg.first != rg.second; ) {
effect* peffect = rg.first->second;
++rg.first;
if (peffect->is_available())
eset->add_item(peffect);
}
if(sort)
eset->sort();
}
void field::filter_affected_cards(effect* peffect, card_set* cset) {
if((peffect->type & EFFECT_TYPE_ACTIONS) || !(peffect->type & EFFECT_TYPE_FIELD) || peffect->is_flag(EFFECT_FLAG_PLAYER_TARGET))
return;
uint8 self = peffect->get_handler_player();
if(self == PLAYER_NONE)
return;
std::vector<card_vector*> cvec;
uint16 range = peffect->s_range;
for(uint32 p = 0; p < 2; ++p) {
if(range & LOCATION_MZONE)
cvec.push_back(&player[self].list_mzone);
if(range & LOCATION_SZONE)
cvec.push_back(&player[self].list_szone);
if(range & LOCATION_GRAVE)
cvec.push_back(&player[self].list_grave);
if(range & LOCATION_REMOVED)
cvec.push_back(&player[self].list_remove);
if(range & LOCATION_HAND)
cvec.push_back(&player[self].list_hand);
if(range & LOCATION_DECK)
cvec.push_back(&player[self].list_main);
if(range & LOCATION_EXTRA)
cvec.push_back(&player[self].list_extra);
range = peffect->o_range;
self = 1 - self;
}
for(auto& cvit : cvec) {
for(auto& pcard : *cvit) {
if(pcard && peffect->is_target(pcard))
cset->insert(pcard);
}
}
}
void field::filter_inrange_cards(effect* peffect, card_set* cset) {
if(peffect->is_flag(EFFECT_FLAG_PLAYER_TARGET))
return;
uint8 self = peffect->get_handler_player();
if(self == PLAYER_NONE)
return;
uint16 range = peffect->s_range;
std::vector<card_vector*> cvec;
for(uint32 p = 0; p < 2; ++p) {
if(range & LOCATION_MZONE)
cvec.push_back(&player[self].list_mzone);
if(range & LOCATION_SZONE)
cvec.push_back(&player[self].list_szone);
if(range & LOCATION_GRAVE)
cvec.push_back(&player[self].list_grave);
if(range & LOCATION_REMOVED)
cvec.push_back(&player[self].list_remove);
if(range & LOCATION_HAND)
cvec.push_back(&player[self].list_hand);
if(range & LOCATION_DECK)
cvec.push_back(&player[self].list_main);
if(range & LOCATION_EXTRA)
cvec.push_back(&player[self].list_extra);
range = peffect->o_range;
self = 1 - self;
}
for(auto& cvit : cvec) {
for(auto& pcard : *cvit) {
if(pcard && peffect->is_fit_target_function(pcard))
cset->insert(pcard);
}
}
}
void field::filter_player_effect(uint8 playerid, uint32 code, effect_set* eset, uint8 sort) {
auto rg = effects.aura_effect.equal_range(code);
for (; rg.first != rg.second; ++rg.first) {
effect* peffect = rg.first->second;
if (peffect->is_target_player(playerid) && peffect->is_available())
eset->add_item(peffect);
}
if(sort)
eset->sort();
}
int32 field::filter_matching_card(int32 findex, uint8 self, uint32 location1, uint32 location2, group* pgroup, card* pexception, group* pexgroup, uint32 extraargs, card** pret, int32 fcount, int32 is_target) {
if(self != 0 && self != 1)
return FALSE;
int32 count = 0;
uint32 location = location1;
for(uint32 p = 0; p < 2; ++p) {
if(location & LOCATION_MZONE) {
for(auto& pcard : player[self].list_mzone) {
if(pcard && !pcard->get_status(STATUS_SUMMONING | STATUS_SUMMON_DISABLED | STATUS_SPSUMMON_STEP)
&& pcard != pexception && !(pexgroup && pexgroup->has_card(pcard))
&& pduel->lua->check_matching(pcard, findex, extraargs)
&& (!is_target || pcard->is_capable_be_effect_target(core.reason_effect, core.reason_player))) {
if(pret) {
*pret = pcard;
return TRUE;
}
count ++;
if(fcount && count >= fcount)
return TRUE;
if(pgroup) {
pgroup->container.insert(pcard);
}
}
}
}
if(location & LOCATION_SZONE) {
for(auto& pcard : player[self].list_szone) {
if(pcard && !pcard->is_status(STATUS_ACTIVATE_DISABLED)
&& pcard != pexception && !(pexgroup && pexgroup->has_card(pcard))
&& pduel->lua->check_matching(pcard, findex, extraargs)
&& (!is_target || pcard->is_capable_be_effect_target(core.reason_effect, core.reason_player))) {
if(pret) {
*pret = pcard;
return TRUE;
}
count ++;
if(fcount && count >= fcount)
return TRUE;
if(pgroup) {
pgroup->container.insert(pcard);
}
}
}
}
if(location & LOCATION_FZONE) {
card* pcard = player[self].list_szone[5];
if(pcard && !pcard->is_status(STATUS_ACTIVATE_DISABLED)
&& pcard != pexception && !(pexgroup && pexgroup->has_card(pcard))
&& pduel->lua->check_matching(pcard, findex, extraargs)
&& (!is_target || pcard->is_capable_be_effect_target(core.reason_effect, core.reason_player))) {
if(pret) {
*pret = pcard;
return TRUE;
}
count ++;
if(fcount && count >= fcount)
return TRUE;
if(pgroup) {
pgroup->container.insert(pcard);
}
}
}
if(location & LOCATION_PZONE) {
for(int32 i = 0; i < 2; ++i) {
card* pcard = player[self].list_szone[core.duel_rule >= 4 ? i * 4 : i + 6];
if(pcard && pcard->current.pzone && !pcard->is_status(STATUS_ACTIVATE_DISABLED)
&& pcard != pexception && !(pexgroup && pexgroup->has_card(pcard))
&& pduel->lua->check_matching(pcard, findex, extraargs)
&& (!is_target || pcard->is_capable_be_effect_target(core.reason_effect, core.reason_player))) {
if(pret) {
*pret = pcard;
return TRUE;
}
count ++;
if(fcount && count >= fcount)
return TRUE;
if(pgroup) {
pgroup->container.insert(pcard);
}
}
}
}
if(location & LOCATION_DECK) {
for(auto cit = player[self].list_main.rbegin(); cit != player[self].list_main.rend(); ++cit) {
if(*cit != pexception && !(pexgroup && pexgroup->has_card(*cit))
&& pduel->lua->check_matching(*cit, findex, extraargs)
&& (!is_target || (*cit)->is_capable_be_effect_target(core.reason_effect, core.reason_player))) {
if(pret) {
*pret = *cit;
return TRUE;
}
count ++;
if(fcount && count >= fcount)
return TRUE;
if(pgroup) {
pgroup->container.insert(*cit);
}
}
}
}
if(location & LOCATION_EXTRA) {
for(auto cit = player[self].list_extra.rbegin(); cit != player[self].list_extra.rend(); ++cit) {
if(*cit != pexception && !(pexgroup && pexgroup->has_card(*cit))
&& pduel->lua->check_matching(*cit, findex, extraargs)
&& (!is_target || (*cit)->is_capable_be_effect_target(core.reason_effect, core.reason_player))) {
if(pret) {
*pret = *cit;
return TRUE;
}
count ++;
if(fcount && count >= fcount)
return TRUE;
if(pgroup) {
pgroup->container.insert(*cit);
}
}
}
}
if(location & LOCATION_HAND) {
for(auto& pcard : player[self].list_hand) {
if(pcard != pexception && !(pexgroup && pexgroup->has_card(pcard))
&& pduel->lua->check_matching(pcard, findex, extraargs)
&& (!is_target || pcard->is_capable_be_effect_target(core.reason_effect, core.reason_player))) {
if(pret) {
*pret = pcard;
return TRUE;
}
count ++;
if(fcount && count >= fcount)
return TRUE;
if(pgroup) {
pgroup->container.insert(pcard);
}
}
}
}
if(location & LOCATION_GRAVE) {
for(auto cit = player[self].list_grave.rbegin(); cit != player[self].list_grave.rend(); ++cit) {
if(*cit != pexception && !(pexgroup && pexgroup->has_card(*cit))
&& pduel->lua->check_matching(*cit, findex, extraargs)
&& (!is_target || (*cit)->is_capable_be_effect_target(core.reason_effect, core.reason_player))) {
if(pret) {
*pret = *cit;
return TRUE;
}
count ++;
if(fcount && count >= fcount)
return TRUE;
if(pgroup) {
pgroup->container.insert(*cit);
}
}
}
}
if(location & LOCATION_REMOVED) {
for(auto cit = player[self].list_remove.rbegin(); cit != player[self].list_remove.rend(); ++cit) {
if(*cit != pexception && !(pexgroup && pexgroup->has_card(*cit))
&& pduel->lua->check_matching(*cit, findex, extraargs)
&& (!is_target || (*cit)->is_capable_be_effect_target(core.reason_effect, core.reason_player))) {
if(pret) {
*pret = *cit;
return TRUE;
}
count ++;
if(fcount && count >= fcount)
return TRUE;
if(pgroup) {
pgroup->container.insert(*cit);
}
}
}
}
location = location2;
self = 1 - self;
}
return FALSE;
}
// Duel.GetFieldGroup(), Duel.GetFieldGroupCount()
int32 field::filter_field_card(uint8 self, uint32 location1, uint32 location2, group* pgroup) {
if(self != 0 && self != 1)
return 0;
uint32 location = location1;
uint32 count = 0;
for(uint32 p = 0; p < 2; ++p) {
if(location & LOCATION_MZONE) {
for(auto& pcard : player[self].list_mzone) {
if(pcard && !pcard->get_status(STATUS_SUMMONING | STATUS_SPSUMMON_STEP)) {
if(pgroup)
pgroup->container.insert(pcard);
count++;
}
}
}
if(location & LOCATION_SZONE) {
for(auto& pcard : player[self].list_szone) {
if(pcard) {
if(pgroup)
pgroup->container.insert(pcard);
count++;
}
}
}
if(location & LOCATION_FZONE) {
card* pcard = player[self].list_szone[5];
if(pcard) {
if(pgroup)
pgroup->container.insert(pcard);
count++;
}
}
if(location & LOCATION_PZONE) {
for(int32 i = 0; i < 2; ++i) {
card* pcard = player[self].list_szone[core.duel_rule >= 4 ? i * 4 : i + 6];
if(pcard && pcard->current.pzone) {
if(pgroup)
pgroup->container.insert(pcard);
count++;
}
}
}
if(location & LOCATION_HAND) {
if(pgroup)
pgroup->container.insert(player[self].list_hand.begin(), player[self].list_hand.end());
count += (uint32)player[self].list_hand.size();
}
if(location & LOCATION_DECK) {
if(pgroup)
pgroup->container.insert(player[self].list_main.rbegin(), player[self].list_main.rend());
count += (uint32)player[self].list_main.size();
}
if(location & LOCATION_EXTRA) {
if(pgroup)
pgroup->container.insert(player[self].list_extra.rbegin(), player[self].list_extra.rend());
count += (uint32)player[self].list_extra.size();
}
if(location & LOCATION_GRAVE) {
if(pgroup)
pgroup->container.insert(player[self].list_grave.rbegin(), player[self].list_grave.rend());
count += (uint32)player[self].list_grave.size();
}
if(location & LOCATION_REMOVED) {
if(pgroup)
pgroup->container.insert(player[self].list_remove.rbegin(), player[self].list_remove.rend());
count += (uint32)player[self].list_remove.size();
}
location = location2;
self = 1 - self;
}
return count;
}
effect* field::is_player_affected_by_effect(uint8 playerid, uint32 code) {
auto rg = effects.aura_effect.equal_range(code);
for (; rg.first != rg.second; ++rg.first) {
effect* peffect = rg.first->second;
if (peffect->is_target_player(playerid) && peffect->is_available())
return peffect;
}
return 0;
}
int32 field::get_release_list(uint8 playerid, card_set* release_list, card_set* ex_list, card_set* ex_list_oneof, int32 use_con, int32 use_hand, int32 fun, int32 exarg, card* exc, group* exg) {
uint32 rcount = 0;
for(auto& pcard : player[playerid].list_mzone) {
if(pcard && pcard != exc && !(exg && exg->has_card(pcard)) && pcard->is_releasable_by_nonsummon(playerid)
&& (!use_con || pduel->lua->check_matching(pcard, fun, exarg))) {
if(release_list)
release_list->insert(pcard);
pcard->release_param = 1;
rcount++;
}
}
if(use_hand) {
for(auto& pcard : player[playerid].list_hand) {
if(pcard && pcard != exc && !(exg && exg->has_card(pcard)) && pcard->is_releasable_by_nonsummon(playerid)
&& (!use_con || pduel->lua->check_matching(pcard, fun, exarg))) {
if(release_list)
release_list->insert(pcard);
pcard->release_param = 1;
rcount++;
}
}
}
int32 ex_oneof_max = 0;
for(auto& pcard : player[1 - playerid].list_mzone) {
if(pcard && pcard != exc && !(exg && exg->has_card(pcard)) && (pcard->is_position(POS_FACEUP) || !use_con)
&& pcard->is_releasable_by_nonsummon(playerid) && (!use_con || pduel->lua->check_matching(pcard, fun, exarg))) {
pcard->release_param = 1;
if(pcard->is_affected_by_effect(EFFECT_EXTRA_RELEASE)) {
if(ex_list)
ex_list->insert(pcard);
rcount++;
} else {
effect* peffect = pcard->is_affected_by_effect(EFFECT_EXTRA_RELEASE_NONSUM);
if(!peffect || (peffect->is_flag(EFFECT_FLAG_COUNT_LIMIT) && peffect->count_limit == 0))
continue;
pduel->lua->add_param(core.reason_effect, PARAM_TYPE_EFFECT);
pduel->lua->add_param(REASON_COST, PARAM_TYPE_INT);
pduel->lua->add_param(core.reason_player, PARAM_TYPE_INT);
if(!peffect->check_value_condition(3))
continue;
if(ex_list_oneof)
ex_list_oneof->insert(pcard);
ex_oneof_max = 1;
}
}
}
return rcount + ex_oneof_max;
}
int32 field::check_release_list(uint8 playerid, int32 count, int32 use_con, int32 use_hand, int32 fun, int32 exarg, card* exc, group* exg) {
card_set relcard;
card_set relcard_oneof;
get_release_list(playerid, &relcard, &relcard, &relcard_oneof, use_con, use_hand, fun, exarg, exc, exg);
bool has_oneof = false;
for(auto& pcard : core.must_select_cards) {
auto it = relcard.find(pcard);
if(it != relcard.end())
relcard.erase(it);
else if(!has_oneof && relcard_oneof.find(pcard) != relcard_oneof.end())
has_oneof = true;
else
return FALSE;
}
int32 rcount = (int32)relcard.size();
if(!has_oneof && !relcard_oneof.empty())
rcount++;
return (rcount >= count) ? TRUE : FALSE;
}
// return: the max release count of mg or all monsters on field
int32 field::get_summon_release_list(card* target, card_set* release_list, card_set* ex_list, card_set* ex_list_oneof, group* mg, uint32 ex, uint32 releasable, uint32 pos) {
uint8 p = target->current.controler;
card_set ex_tribute;
effect_set eset;
target->filter_effect(EFFECT_ADD_EXTRA_TRIBUTE, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(eset[i]->get_value() & pos)
filter_inrange_cards(eset[i], &ex_tribute);
}
uint32 rcount = 0;
for(auto& pcard : player[p].list_mzone) {
if(pcard && ((releasable >> pcard->current.sequence) & 1) && pcard->is_releasable_by_summon(p, target)) {
if(mg && !mg->has_card(pcard))
continue;
if(release_list)
release_list->insert(pcard);
if(pcard->is_affected_by_effect(EFFECT_DOUBLE_TRIBUTE, target))
pcard->release_param = 2;
else
pcard->release_param = 1;
rcount += pcard->release_param;
}
}
uint32 ex_oneof_max = 0;
for(auto& pcard : player[1 - p].list_mzone) {
if(!pcard || !((releasable >> (pcard->current.sequence + 16)) & 1) || !pcard->is_releasable_by_summon(p, target))
continue;
if(mg && !mg->has_card(pcard))
continue;
if(pcard->is_affected_by_effect(EFFECT_DOUBLE_TRIBUTE, target))
pcard->release_param = 2;
else
pcard->release_param = 1;
if(ex || ex_tribute.find(pcard) != ex_tribute.end()) {
if(release_list)
release_list->insert(pcard);
rcount += pcard->release_param;
} else if(pcard->is_affected_by_effect(EFFECT_EXTRA_RELEASE)) {
if(ex_list)
ex_list->insert(pcard);
rcount += pcard->release_param;
} else {
effect* peffect = pcard->is_affected_by_effect(EFFECT_EXTRA_RELEASE_SUM);
if(!peffect || (peffect->is_flag(EFFECT_FLAG_COUNT_LIMIT) && peffect->count_limit == 0))
continue;
if(ex_list_oneof)
ex_list_oneof->insert(pcard);
if(ex_oneof_max < pcard->release_param)
ex_oneof_max = pcard->release_param;
}
}
for(auto& pcard : ex_tribute) {
if(pcard->current.location == LOCATION_MZONE || !pcard->is_releasable_by_summon(p, target))
continue;
if(release_list)
release_list->insert(pcard);
if(pcard->is_affected_by_effect(EFFECT_DOUBLE_TRIBUTE, target))
pcard->release_param = 2;
else
pcard->release_param = 1;
rcount += pcard->release_param;
}
return rcount + ex_oneof_max;
}
int32 field::get_summon_count_limit(uint8 playerid) {
effect_set eset;
filter_player_effect(playerid, EFFECT_SET_SUMMON_COUNT_LIMIT, &eset);
int32 count = 1;
for(int32 i = 0; i < eset.size(); ++i) {
int32 c = eset[i]->get_value();
if(c > count)
count = c;
}
return count;
}
int32 field::get_draw_count(uint8 playerid) {
effect_set eset;
filter_player_effect(infos.turn_player, EFFECT_DRAW_COUNT, &eset);
int32 count = player[playerid].draw_count;
if(eset.size())
count = eset.get_last()->get_value();
return count;
}
void field::get_ritual_material(uint8 playerid, effect* peffect, card_set* material) {
for(auto& pcard : player[playerid].list_mzone) {
if(pcard && pcard->get_level() && pcard->is_affect_by_effect(peffect)
&& pcard->is_releasable_by_nonsummon(playerid) && pcard->is_releasable_by_effect(playerid, peffect))
material->insert(pcard);
}
for(auto& pcard : player[1 - playerid].list_mzone) {
if(pcard && pcard->get_level() && pcard->is_affect_by_effect(peffect)
&& pcard->is_affected_by_effect(EFFECT_EXTRA_RELEASE)
&& pcard->is_releasable_by_nonsummon(playerid) && pcard->is_releasable_by_effect(playerid, peffect))
material->insert(pcard);
}
for(auto& pcard : player[playerid].list_hand)
if((pcard->data.type & TYPE_MONSTER) && pcard->is_releasable_by_nonsummon(playerid))
material->insert(pcard);
for(auto& pcard : player[playerid].list_grave)
if((pcard->data.type & TYPE_MONSTER) && pcard->is_affected_by_effect(EFFECT_EXTRA_RITUAL_MATERIAL) && pcard->is_removeable(playerid, POS_FACEUP, REASON_EFFECT))
material->insert(pcard);
}
void field::get_fusion_material(uint8 playerid, card_set* material) {
for(auto& pcard : player[playerid].list_mzone) {
if(pcard)
material->insert(pcard);
}
for(auto& pcard : player[playerid].list_szone) {
if(pcard && pcard->is_affected_by_effect(EFFECT_EXTRA_FUSION_MATERIAL))
material->insert(pcard);
}
for(auto& pcard : player[playerid].list_hand)
if(pcard->data.type & TYPE_MONSTER)
material->insert(pcard);
}
void field::ritual_release(card_set* material) {
card_set rel;
card_set rem;
for(auto& pcard : *material) {
if(pcard->current.location == LOCATION_GRAVE)
rem.insert(pcard);
else
rel.insert(pcard);
}
release(&rel, core.reason_effect, REASON_RITUAL + REASON_EFFECT + REASON_MATERIAL, core.reason_player);
send_to(&rem, core.reason_effect, REASON_RITUAL + REASON_EFFECT + REASON_MATERIAL, core.reason_player, PLAYER_NONE, LOCATION_REMOVED, 0, POS_FACEUP);
}
void field::get_xyz_material(card* scard, int32 findex, uint32 lv, int32 maxc, group* mg) {
core.xmaterial_lst.clear();
uint32 xyz_level;
if(mg) {
for (auto& pcard : mg->container) {
if(pcard->is_can_be_xyz_material(scard) && (xyz_level = pcard->check_xyz_level(scard, lv))
&& (findex == 0 || pduel->lua->check_matching(pcard, findex, 0)))
core.xmaterial_lst.emplace((xyz_level >> 12) & 0xf, pcard);
}
} else {
int32 playerid = scard->current.controler;
for(auto& pcard : player[playerid].list_mzone) {
if(pcard && pcard->is_position(POS_FACEUP) && pcard->is_can_be_xyz_material(scard) && (xyz_level = pcard->check_xyz_level(scard, lv))
&& (findex == 0 || pduel->lua->check_matching(pcard, findex, 0)))
core.xmaterial_lst.emplace((xyz_level >> 12) & 0xf, pcard);
}
for(auto& pcard : player[1 - playerid].list_mzone) {
if(pcard && pcard->is_position(POS_FACEUP) && pcard->is_can_be_xyz_material(scard) && (xyz_level = pcard->check_xyz_level(scard, lv))
&& pcard->is_affected_by_effect(EFFECT_XYZ_MATERIAL) && (findex == 0 || pduel->lua->check_matching(pcard, findex, 0)))
core.xmaterial_lst.emplace((xyz_level >> 12) & 0xf, pcard);
}
}
if(core.global_flag & GLOBALFLAG_XMAT_COUNT_LIMIT) {
if(maxc > (int32)core.xmaterial_lst.size())
maxc = (int32)core.xmaterial_lst.size();
auto iter = core.xmaterial_lst.lower_bound(maxc);
core.xmaterial_lst.erase(core.xmaterial_lst.begin(), iter);
}
}
void field::get_overlay_group(uint8 self, uint8 s, uint8 o, card_set* pset) {
uint8 c = s;
for(int32 p = 0; p < 2; ++p) {
if(c) {
for(auto& pcard : player[self].list_mzone) {
if(pcard && !pcard->get_status(STATUS_SUMMONING | STATUS_SPSUMMON_STEP) && pcard->xyz_materials.size())
pset->insert(pcard->xyz_materials.begin(), pcard->xyz_materials.end());
}
}
self = 1 - self;
c = o;
}
}
int32 field::get_overlay_count(uint8 self, uint8 s, uint8 o) {
uint8 c = s;
uint32 count = 0;
for(int32 p = 0; p < 2; ++p) {
if(c) {
for(auto& pcard : player[self].list_mzone) {
if(pcard && !pcard->get_status(STATUS_SUMMONING | STATUS_SPSUMMON_STEP))
count += (uint32)pcard->xyz_materials.size();
}
}
self = 1 - self;
c = o;
}
return count;
}
// put all cards in the target of peffect into effects.disable_check_list
void field::update_disable_check_list(effect* peffect) {
card_set cset;
filter_affected_cards(peffect, &cset);
for (auto& pcard : cset)
add_to_disable_check_list(pcard);
}
void field::add_to_disable_check_list(card* pcard) {
auto result=effects.disable_check_set.insert(pcard);
if(!result.second)
return;
effects.disable_check_list.push_back(pcard);
}
void field::adjust_disable_check_list() {
card* checking;
int32 pre_disable, new_disable;
if (!effects.disable_check_list.size())
return;
card_set checked;
do {
checked.clear();
while (effects.disable_check_list.size()) {
checking = effects.disable_check_list.front();
effects.disable_check_list.pop_front();
effects.disable_check_set.erase(checking);
checked.insert(checking);
if (checking->is_status(STATUS_TO_ENABLE | STATUS_TO_DISABLE))
continue;
pre_disable = checking->get_status(STATUS_DISABLED | STATUS_FORBIDDEN);
checking->refresh_disable_status();
new_disable = checking->get_status(STATUS_DISABLED | STATUS_FORBIDDEN);
if (pre_disable != new_disable && checking->is_status(STATUS_EFFECT_ENABLED)) {
checking->filter_disable_related_cards();
if (pre_disable)
checking->set_status(STATUS_TO_ENABLE, TRUE);
else
checking->set_status(STATUS_TO_DISABLE, TRUE);
}
}
for (auto& pcard : checked) {
if(pcard->is_status(STATUS_DISABLED) && pcard->is_status(STATUS_TO_DISABLE) && !pcard->is_status(STATUS_TO_ENABLE))
pcard->reset(RESET_DISABLE, RESET_EVENT);
pcard->set_status(STATUS_TO_ENABLE | STATUS_TO_DISABLE, FALSE);
}
} while(effects.disable_check_list.size());
}
// adjust SetUniqueOnField(), EFFECT_SELF_DESTROY, EFFECT_SELF_TOGRAVE
void field::adjust_self_destroy_set() {
if(core.selfdes_disabled || !core.unique_destroy_set.empty() || !core.self_destroy_set.empty() || !core.self_tograve_set.empty())
return;
int32 p = infos.turn_player;
for(int32 p1 = 0; p1 < 2; ++p1) {
std::vector<card*> uniq_set;
for(auto& ucard : core.unique_cards[p]) {
if(ucard->is_position(POS_FACEUP) && ucard->get_status(STATUS_EFFECT_ENABLED)
&& !ucard->get_status(STATUS_DISABLED | STATUS_FORBIDDEN)) {
card_set cset;
ucard->get_unique_target(&cset, p);
if(cset.size() == 0)
ucard->unique_fieldid = 0;
else if(cset.size() == 1) {
auto cit = cset.begin();
ucard->unique_fieldid = (*cit)->fieldid;
} else
uniq_set.push_back(ucard);
}
}
std::sort(uniq_set.begin(), uniq_set.end(), [](card* lhs, card* rhs) { return lhs->fieldid < rhs->fieldid; });
for(auto& pcard : uniq_set) {
add_process(PROCESSOR_SELF_DESTROY, 0, 0, 0, p, 0, 0, 0, pcard);
core.unique_destroy_set.insert(pcard);
}
p = 1 - p;
}
card_set cset;
for(uint8 p = 0; p < 2; ++p) {
for(auto& pcard : player[p].list_mzone) {
if(pcard && pcard->is_position(POS_FACEUP) && !pcard->is_status(STATUS_BATTLE_DESTROYED))
cset.insert(pcard);
}
for(auto& pcard : player[p].list_szone) {
if(pcard && pcard->is_position(POS_FACEUP))
cset.insert(pcard);
}
}
for(auto& pcard : cset) {
effect* peffect = pcard->is_affected_by_effect(EFFECT_SELF_DESTROY);
if(peffect) {
core.self_destroy_set.insert(pcard);
}
}
if(core.global_flag & GLOBALFLAG_SELF_TOGRAVE) {
for(auto& pcard : cset) {
effect* peffect = pcard->is_affected_by_effect(EFFECT_SELF_TOGRAVE);
if(peffect) {
core.self_tograve_set.insert(pcard);
}
}
}
if(!core.self_destroy_set.empty())
add_process(PROCESSOR_SELF_DESTROY, 10, 0, 0, 0, 0);
if(!core.self_tograve_set.empty())
add_process(PROCESSOR_SELF_DESTROY, 20, 0, 0, 0, 0);
}
void field::erase_grant_effect(effect* peffect) {
auto eit = effects.grant_effect.find(peffect);
for(auto& it : eit->second)
it.first->remove_effect(it.second);
effects.grant_effect.erase(eit);
}
int32 field::adjust_grant_effect() {
int32 adjusted = FALSE;
for(auto& eit : effects.grant_effect) {
effect* peffect = eit.first;
if(!peffect->label_object)
continue;
card_set cset;
if(peffect->is_available())
filter_affected_cards(peffect, &cset);
card_set add_set;
for(auto& pcard : cset) {
if(pcard->is_affect_by_effect(peffect) && !eit.second.count(pcard))
add_set.insert(pcard);
}
card_set remove_set;
for(auto& cit : eit.second) {
card* pcard = cit.first;
if(!pcard->is_affect_by_effect(peffect) || !cset.count(pcard))
remove_set.insert(pcard);
}
for(auto& pcard : add_set) {
effect* geffect = (effect*)peffect->get_label_object();
effect* ceffect = geffect->clone();
ceffect->owner = pcard;
pcard->add_effect(ceffect);
eit.second.emplace(pcard, ceffect);
}
for(auto& pcard : remove_set) {
auto it = eit.second.find(pcard);
pcard->remove_effect(it->second);
eit.second.erase(it);
}
if(!add_set.empty() || !remove_set.empty())
adjusted = TRUE;
}
return adjusted;
}
void field::add_unique_card(card* pcard) {
uint8 con = pcard->current.controler;
if(pcard->unique_pos[0])
core.unique_cards[con].insert(pcard);
if(pcard->unique_pos[1])
core.unique_cards[1 - con].insert(pcard);
pcard->unique_fieldid = 0;
}
void field::remove_unique_card(card* pcard) {
uint8 con = pcard->current.controler;
if(con == PLAYER_NONE)
return;
if(pcard->unique_pos[0])
core.unique_cards[con].erase(pcard);
if(pcard->unique_pos[1])
core.unique_cards[1 - con].erase(pcard);
}
// return: pcard->unique_effect or 0
effect* field::check_unique_onfield(card* pcard, uint8 controler, uint8 location, card* icard) {
for(auto& ucard : core.unique_cards[controler]) {
if((ucard != pcard) && (ucard != icard) && ucard->is_position(POS_FACEUP) && ucard->get_status(STATUS_EFFECT_ENABLED)
&& !ucard->get_status(STATUS_DISABLED | STATUS_FORBIDDEN)
&& ucard->unique_fieldid && ucard->check_unique_code(pcard) && (ucard->unique_location & location))
return ucard->unique_effect;
}
if(!pcard->unique_code || !(pcard->unique_location & location) || pcard->get_status(STATUS_DISABLED | STATUS_FORBIDDEN))
return 0;
card_set cset;
pcard->get_unique_target(&cset, controler, icard);
if(pcard->check_unique_code(pcard))
cset.insert(pcard);
if(cset.size() >= 2)
return pcard->unique_effect;
return 0;
}
int32 field::check_spsummon_once(card* pcard, uint8 playerid) {
if(pcard->spsummon_code == 0)
return TRUE;
auto iter = core.spsummon_once_map[playerid].find(pcard->spsummon_code);
return (iter == core.spsummon_once_map[playerid].end()) || (iter->second == 0);
}
// increase the binary custom counter 1~5
void field::check_card_counter(card* pcard, int32 counter_type, int32 playerid) {
auto& counter_map = (counter_type == 1) ? core.summon_counter :
(counter_type == 2) ? core.normalsummon_counter :
(counter_type == 3) ? core.spsummon_counter :
(counter_type == 4) ? core.flipsummon_counter : core.attack_counter;
for(auto& iter : counter_map) {
auto& info = iter.second;
if((playerid == 0) && (info.second & 0xffff) != 0)
continue;
if((playerid == 1) && (info.second & 0xffff0000) != 0)
continue;
if(info.first) {
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
if(!pduel->lua->check_condition(info.first, 1)) {
if(playerid == 0)
info.second += 0x1;
else
info.second += 0x10000;
}
}
}
}
void field::check_card_counter(group* pgroup, int32 counter_type, int32 playerid) {
auto& counter_map = (counter_type == 1) ? core.summon_counter :
(counter_type == 2) ? core.normalsummon_counter :
(counter_type == 3) ? core.spsummon_counter :
(counter_type == 4) ? core.flipsummon_counter : core.attack_counter;
for(auto& iter : counter_map) {
auto& info = iter.second;
if((playerid == 0) && (info.second & 0xffff) != 0)
continue;
if((playerid == 1) && (info.second & 0xffff0000) != 0)
continue;
if(info.first) {
for(auto& pcard : pgroup->container) {
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
if(!pduel->lua->check_condition(info.first, 1)) {
if(playerid == 0)
info.second += 0x1;
else
info.second += 0x10000;
break;
}
}
}
}
}
void field::check_chain_counter(effect* peffect, int32 playerid, int32 chainid, bool cancel) {
for(auto& iter : core.chain_counter) {
auto& info = iter.second;
if(info.first) {
pduel->lua->add_param(peffect, PARAM_TYPE_EFFECT);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(chainid, PARAM_TYPE_INT);
if(!pduel->lua->check_condition(info.first, 3)) {
if(playerid == 0) {
if(!cancel)
info.second += 0x1;
else if(info.second & 0xffff)
info.second -= 0x1;
} else {
if(!cancel)
info.second += 0x10000;
else if(info.second & 0xffff0000)
info.second -= 0x10000;
}
}
}
}
}
void field::set_spsummon_counter(uint8 playerid) {
core.spsummon_state_count[playerid]++;
if(core.global_flag & GLOBALFLAG_SPSUMMON_COUNT) {
for(auto& peffect : effects.spsummon_count_eff) {
card* pcard = peffect->get_handler();
if(peffect->is_available()) {
if(((playerid == pcard->current.controler) && peffect->s_range) || ((playerid != pcard->current.controler) && peffect->o_range)) {
pcard->spsummon_counter[playerid]++;
}
}
}
}
}
int32 field::check_spsummon_counter(uint8 playerid, uint8 ct) {
if(core.global_flag & GLOBALFLAG_SPSUMMON_COUNT) {
for(auto& peffect : effects.spsummon_count_eff) {
card* pcard = peffect->get_handler();
uint16 val = (uint16)peffect->value;
if(peffect->is_available()) {
if(pcard->spsummon_counter[playerid] + ct > val)
return FALSE;
}
}
}
return TRUE;
}
int32 field::check_lp_cost(uint8 playerid, uint32 lp) {
effect_set eset;
int32 val = lp;
filter_player_effect(playerid, EFFECT_LPCOST_CHANGE, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
pduel->lua->add_param(core.reason_effect, PARAM_TYPE_EFFECT);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(val, PARAM_TYPE_INT);
val = eset[i]->get_value(3);
}
if(val <= 0)
return TRUE;
tevent e;
e.event_cards = 0;
e.event_player = playerid;
e.event_value = lp;
e.reason = 0;
e.reason_effect = core.reason_effect;
e.reason_player = playerid;
if(effect_replace_check(EFFECT_LPCOST_REPLACE, e))
return TRUE;
//cost[playerid].amount += val;
if(val <= player[playerid].lp)
return TRUE;
return FALSE;
}
/*
void field::save_lp_cost() {
for(uint8 playerid = 0; playerid < 2; ++playerid) {
if(cost[playerid].count < 8)
cost[playerid].lpstack[cost[playerid].count] = cost[playerid].amount;
cost[playerid].count++;
}
}
void field::restore_lp_cost() {
for(uint8 playerid = 0; playerid < 2; ++playerid) {
cost[playerid].count--;
if(cost[playerid].count < 8)
cost[playerid].amount = cost[playerid].lpstack[cost[playerid].count];
}
}
*/
uint32 field::get_field_counter(uint8 self, uint8 s, uint8 o, uint16 countertype) {
uint8 c = s;
uint32 count = 0;
for(int32 p = 0; p < 2; ++p) {
if(c) {
for(auto& pcard : player[self].list_mzone) {
if(pcard)
count += pcard->get_counter(countertype);
}
for(auto& pcard : player[self].list_szone) {
if(pcard)
count += pcard->get_counter(countertype);
}
}
self = 1 - self;
c = o;
}
return count;
}
int32 field::effect_replace_check(uint32 code, const tevent& e) {
auto pr = effects.continuous_effect.equal_range(code);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
if(peffect->is_activateable(peffect->get_handler_player(), e))
return TRUE;
}
return FALSE;
}
int32 field::get_attack_target(card* pcard, card_vector* v, uint8 chain_attack, bool select_target) {
pcard->direct_attackable = 0;
uint8 p = pcard->current.controler;
card_vector auto_attack, only_attack, must_attack;
for(auto& atarget : player[1 - p].list_mzone) {
if(atarget) {
if(atarget->is_affected_by_effect(EFFECT_ONLY_BE_ATTACKED))
auto_attack.push_back(atarget);
if(pcard->is_affected_by_effect(EFFECT_ONLY_ATTACK_MONSTER, atarget))
only_attack.push_back(atarget);
if(pcard->is_affected_by_effect(EFFECT_MUST_ATTACK_MONSTER, atarget))
must_attack.push_back(atarget);
}
}
card_vector* pv = nullptr;
int32 atype = 0;
if(auto_attack.size()) {
atype = 1;
if(auto_attack.size() == 1)
pv = &auto_attack;
else
return atype;
} else if(pcard->is_affected_by_effect(EFFECT_ONLY_ATTACK_MONSTER)) {
atype = 2;
if(only_attack.size() == 1)
pv = &only_attack;
else
return atype;
} else if(pcard->is_affected_by_effect(EFFECT_MUST_ATTACK_MONSTER)) {
atype = 3;
if(must_attack.size())
pv = &must_attack;
else
return atype;
} else {
atype = 4;
pv = &player[1 - p].list_mzone;
}
int32 extra_count = 0;
effect_set eset;
pcard->filter_effect(EFFECT_EXTRA_ATTACK, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
int32 val = eset[i]->get_value(pcard);
if(val > extra_count)
extra_count = val;
}
int32 extra_count_m = 0;
eset.clear();
pcard->filter_effect(EFFECT_EXTRA_ATTACK_MONSTER, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
int32 val = eset[i]->get_value(pcard);
if(val > extra_count_m)
extra_count_m = val;
}
if(!chain_attack && pcard->announce_count > extra_count
&& (!extra_count_m || pcard->announce_count > extra_count_m || pcard->announced_cards.findcard(0))) {
effect* peffect;
if((peffect = pcard->is_affected_by_effect(EFFECT_ATTACK_ALL)) && pcard->attack_all_target) {
for(auto& atarget : *pv) {
if(!atarget)
continue;
pduel->lua->add_param(atarget, PARAM_TYPE_CARD);
if(!peffect->check_value_condition(1))
continue;
if(pcard->announced_cards.findcard(atarget) >= (uint32)peffect->get_value(atarget))
continue;
if(atype >= 2 && atarget->is_affected_by_effect(EFFECT_IGNORE_BATTLE_TARGET))
continue;
if(select_target && (atype == 2 || atype == 4)) {
if(atarget->is_affected_by_effect(EFFECT_CANNOT_BE_BATTLE_TARGET, pcard))
continue;
if(pcard->is_affected_by_effect(EFFECT_CANNOT_SELECT_BATTLE_TARGET, atarget))
continue;
}
v->push_back(atarget);
}
}
return atype;
}
//chain attack or announce count check passed
uint32 mcount = 0;
for(auto& atarget : *pv) {
if(!atarget)
continue;
if(atype >= 2 && atarget->is_affected_by_effect(EFFECT_IGNORE_BATTLE_TARGET))
continue;
mcount++;
if(chain_attack && core.chain_attack_target && atarget != core.chain_attack_target)
continue;
if(select_target && (atype == 2 || atype == 4)) {
if(atarget->is_affected_by_effect(EFFECT_CANNOT_BE_BATTLE_TARGET, pcard))
continue;
if(pcard->is_affected_by_effect(EFFECT_CANNOT_SELECT_BATTLE_TARGET, atarget))
continue;
}
v->push_back(atarget);
}
if(atype <= 3)
return atype;
if((mcount == 0 || pcard->is_affected_by_effect(EFFECT_DIRECT_ATTACK) || core.attack_player)
&& !pcard->is_affected_by_effect(EFFECT_CANNOT_DIRECT_ATTACK)
&& !(extra_count_m && pcard->announce_count > extra_count)
&& !(chain_attack && core.chain_attack_target))
pcard->direct_attackable = 1;
return atype;
}
bool field::confirm_attack_target() {
card_vector cv;
get_attack_target(core.attacker, &cv, core.chain_attack, false);
return core.attack_target && std::find(cv.begin(), cv.end(), core.attack_target) != cv.end()
|| !core.attack_target && core.attacker->direct_attackable;
}
// update the validity for EFFECT_ATTACK_ALL (approximate solution)
void field::attack_all_target_check() {
if(!core.attacker)
return;
if(!core.attack_target) {
core.attacker->attack_all_target = FALSE;
return;
}
effect* peffect = core.attacker->is_affected_by_effect(EFFECT_ATTACK_ALL);
if(!peffect)
return;
if(!peffect->get_value(core.attack_target))
core.attacker->attack_all_target = FALSE;
}
int32 field::check_synchro_material(card* pcard, int32 findex1, int32 findex2, int32 min, int32 max, card* smat, group* mg) {
if(core.global_flag & GLOBALFLAG_MUST_BE_SMATERIAL) {
effect_set eset;
filter_player_effect(pcard->current.controler, EFFECT_MUST_BE_SMATERIAL, &eset);
if(eset.size())
return check_tuner_material(pcard, eset[0]->handler, findex1, findex2, min, max, smat, mg);
}
if(mg) {
for(auto& tuner : mg->container) {
if(check_tuner_material(pcard, tuner, findex1, findex2, min, max, smat, mg))
return TRUE;
}
} else {
for(uint8 p = 0; p < 2; ++p) {
for(auto& tuner : player[p].list_mzone) {
if(check_tuner_material(pcard, tuner, findex1, findex2, min, max, smat, mg))
return TRUE;
}
}
}
return FALSE;
}
int32 field::check_tuner_material(card* pcard, card* tuner, int32 findex1, int32 findex2, int32 min, int32 max, card* smat, group* mg) {
if(!tuner || (tuner->current.location == LOCATION_MZONE && !tuner->is_position(POS_FACEUP)) || !(tuner->get_synchro_type() & TYPE_TUNER) || !tuner->is_can_be_synchro_material(pcard))
return FALSE;
effect* pcheck = tuner->is_affected_by_effect(EFFECT_SYNCHRO_CHECK);
if(pcheck)
pcheck->get_value(tuner);
if((mg && !mg->has_card(tuner)) || !pduel->lua->check_matching(tuner, findex1, 0)) {
pduel->restore_assumes();
return FALSE;
}
effect* pcustom = tuner->is_affected_by_effect(EFFECT_SYNCHRO_MATERIAL_CUSTOM, pcard);
if(pcustom) {
if(!pcustom->target) {
pduel->restore_assumes();
return FALSE;
}
pduel->lua->add_param(pcustom, PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(findex2, PARAM_TYPE_INDEX);
pduel->lua->add_param(min, PARAM_TYPE_INT);
pduel->lua->add_param(max, PARAM_TYPE_INT);
if(pduel->lua->check_condition(pcustom->target, 5)) {
pduel->restore_assumes();
return TRUE;
}
pduel->restore_assumes();
return FALSE;
}
int32 playerid = pcard->current.controler;
int32 ct = get_spsummonable_count(pcard, playerid);
card_set handover_zone_cards;
if(ct <= 0) {
uint32 must_use_zone_flag = 0;
filter_must_use_mzone(playerid, playerid, LOCATION_REASON_TOFIELD, pcard, &must_use_zone_flag);
uint32 handover_zone = get_rule_zone_fromex(playerid, pcard) & ~must_use_zone_flag;
get_cards_in_zone(&handover_zone_cards, handover_zone, playerid, LOCATION_MZONE);
if(handover_zone_cards.find(tuner) != handover_zone_cards.end())
ct++;
}
int32 location = LOCATION_MZONE;
effect* ptuner = tuner->is_affected_by_effect(EFFECT_TUNER_MATERIAL_LIMIT);
if(ptuner) {
if(ptuner->value)
location = ptuner->value;
if(ptuner->s_range && ptuner->s_range > min)
min = ptuner->s_range;
if(ptuner->o_range && ptuner->o_range < max)
max = ptuner->o_range;
if(min > max) {
pduel->restore_assumes();
return FALSE;
}
}
int32 mzone_limit = get_mzone_limit(playerid, playerid, LOCATION_REASON_TOFIELD);
if(mzone_limit < 0) {
if(location == LOCATION_HAND) {
pduel->restore_assumes();
return FALSE;
}
int32 ft = -mzone_limit;
if(ft > min)
min = ft;
if(min > max) {
pduel->restore_assumes();
return FALSE;
}
}
int32 lv = pcard->get_level();
card_vector nsyn;
int32 mcount = 1;
nsyn.push_back(tuner);
tuner->sum_param = tuner->get_synchro_level(pcard);
if(smat) {
if(pcheck)
pcheck->get_value(smat);
if(!smat->is_position(POS_FACEUP) || !smat->is_can_be_synchro_material(pcard, tuner) || !pduel->lua->check_matching(smat, findex2, 1)) {
pduel->restore_assumes();
return FALSE;
}
if(ptuner && ptuner->target) {
pduel->lua->add_param(ptuner, PARAM_TYPE_EFFECT);
pduel->lua->add_param(smat, PARAM_TYPE_CARD);
if(!pduel->lua->get_function_value(ptuner->target, 2)) {
pduel->restore_assumes();
return FALSE;
}
}
min--;
max--;
nsyn.push_back(smat);
smat->sum_param = smat->get_synchro_level(pcard);
mcount++;
if(ct <= 0) {
if(handover_zone_cards.find(smat) != handover_zone_cards.end())
ct++;
}
if(min == 0) {
if(ct > 0 && check_with_sum_limit_m(nsyn, lv, 0, 0, 0, 2)) {
pduel->restore_assumes();
return TRUE;
}
if(max == 0) {
pduel->restore_assumes();
return FALSE;
}
}
}
if(mg) {
for(auto& pm : mg->container) {
if(pm == tuner || pm == smat || !pm->is_can_be_synchro_material(pcard, tuner))
continue;
if(ptuner && ptuner->target) {
pduel->lua->add_param(ptuner, PARAM_TYPE_EFFECT);
pduel->lua->add_param(pm, PARAM_TYPE_CARD);
if(!pduel->lua->get_function_value(ptuner->target, 2))
continue;
}
if(pcheck)
pcheck->get_value(pm);
if(pm->current.location == LOCATION_MZONE && !pm->is_position(POS_FACEUP))
continue;
if(!pduel->lua->check_matching(pm, findex2, 1))
continue;
nsyn.push_back(pm);
pm->sum_param = pm->get_synchro_level(pcard);
}
} else {
card_vector cv;
if(location & LOCATION_MZONE) {
cv.insert(cv.end(), player[0].list_mzone.begin(), player[0].list_mzone.end());
cv.insert(cv.end(), player[1].list_mzone.begin(), player[1].list_mzone.end());
}
if(location & LOCATION_HAND)
cv.insert(cv.end(), player[playerid].list_hand.begin(), player[playerid].list_hand.end());
for(auto& pm : cv) {
if(!pm || pm == tuner || pm == smat || !pm->is_can_be_synchro_material(pcard, tuner))
continue;
if(ptuner && ptuner->target) {
pduel->lua->add_param(ptuner, PARAM_TYPE_EFFECT);
pduel->lua->add_param(pm, PARAM_TYPE_CARD);
if(!pduel->lua->get_function_value(ptuner->target, 2))
continue;
}
if(pcheck)
pcheck->get_value(pm);
if(pm->current.location == LOCATION_MZONE && !pm->is_position(POS_FACEUP))
continue;
if(!pduel->lua->check_matching(pm, findex2, 1))
continue;
nsyn.push_back(pm);
pm->sum_param = pm->get_synchro_level(pcard);
}
}
if(ct > 0) {
int32 ret = check_other_synchro_material(nsyn, lv, min, max, mcount);
pduel->restore_assumes();
return ret;
}
auto start = nsyn.begin() + mcount;
for(auto cit = start; cit != nsyn.end(); ++cit) {
card* pm = *cit;
if(handover_zone_cards.find(pm) == handover_zone_cards.end())
continue;
if(start != cit)
std::iter_swap(start, cit);
if(check_other_synchro_material(nsyn, lv, min - 1, max - 1, mcount + 1)) {
pduel->restore_assumes();
return TRUE;
}
if(start != cit)
std::iter_swap(start, cit);
}
pduel->restore_assumes();
return FALSE;
}
int32 field::check_other_synchro_material(const card_vector& nsyn, int32 lv, int32 min, int32 max, int32 mcount) {
if(!(core.global_flag & GLOBALFLAG_SCRAP_CHIMERA)) {
if(check_with_sum_limit_m(nsyn, lv, 0, min, max, mcount)) {
return TRUE;
}
return FALSE;
}
effect* pscrap = 0;
for(auto& pm : nsyn) {
pscrap = pm->is_affected_by_effect(EFFECT_SCRAP_CHIMERA);
if(pscrap)
break;
}
if(!pscrap) {
if(check_with_sum_limit_m(nsyn, lv, 0, min, max, mcount)) {
return TRUE;
}
return FALSE;
}
card_vector nsyn_filtered;
for(auto& pm : nsyn) {
if(!pscrap->get_value(pm))
nsyn_filtered.push_back(pm);
}
if(nsyn_filtered.size() == nsyn.size()) {
if(check_with_sum_limit_m(nsyn, lv, 0, min, max, mcount)) {
return TRUE;
}
} else {
bool mfiltered = true;
for(int32 i = 0; i < mcount; ++i) {
if(pscrap->get_value(nsyn[i]))
mfiltered = false;
}
if(mfiltered && check_with_sum_limit_m(nsyn_filtered, lv, 0, min, max, mcount)) {
return TRUE;
}
for(int32 i = 0; i < mcount; ++i) {
if(nsyn[i]->is_affected_by_effect(EFFECT_SCRAP_CHIMERA)) {
return FALSE;
}
}
card_vector nsyn_removed;
for(auto& pm : nsyn) {
if(!pm->is_affected_by_effect(EFFECT_SCRAP_CHIMERA))
nsyn_removed.push_back(pm);
}
if(check_with_sum_limit_m(nsyn_removed, lv, 0, min, max, mcount)) {
return TRUE;
}
}
return FALSE;
}
int32 field::check_tribute(card* pcard, int32 min, int32 max, group* mg, uint8 toplayer, uint32 zone, uint32 releasable, uint32 pos) {
int32 ex = FALSE;
uint32 sumplayer = pcard->current.controler;
if(toplayer == 1 - sumplayer)
ex = TRUE;
card_set release_list, ex_list;
int32 m = get_summon_release_list(pcard, &release_list, &ex_list, 0, mg, ex, releasable, pos);
if(max > m)
max = m;
if(min > max)
return FALSE;
zone &= 0x1f;
int32 s = 0;
int32 ct = get_tofield_count(pcard, toplayer, LOCATION_MZONE, sumplayer, LOCATION_REASON_TOFIELD, zone);
if(ct <= 0 && max <= 0)
return FALSE;
for(auto& pcard : release_list) {
if(pcard->current.location == LOCATION_MZONE && pcard->current.controler == toplayer) {
s++;
if((zone >> pcard->current.sequence) & 1)
ct++;
}
}
if(ct <= 0)
return FALSE;
max -= (int32)ex_list.size();
int32 fcount = get_mzone_limit(toplayer, sumplayer, LOCATION_REASON_TOFIELD);
if(s < -fcount + 1)
return FALSE;
if(max < 0)
max = 0;
if(max < -fcount + 1)
return FALSE;
return TRUE;
}
int32 field::check_with_sum_limit(const card_vector& mats, int32 acc, int32 index, int32 count, int32 min, int32 max) {
if(count > max)
return FALSE;
while(index < (int32)mats.size()) {
int32 op1 = mats[index]->sum_param & 0xffff;
int32 op2 = (mats[index]->sum_param >> 16) & 0xffff;
if((op1 == acc || op2 == acc) && count >= min)
return TRUE;
index++;
if(acc > op1 && check_with_sum_limit(mats, acc - op1, index, count + 1, min, max))
return TRUE;
if(op2 && acc > op2 && check_with_sum_limit(mats, acc - op2, index, count + 1, min, max))
return TRUE;
}
return FALSE;
}
int32 field::check_with_sum_limit_m(const card_vector& mats, int32 acc, int32 index, int32 min, int32 max, int32 must_count) {
if(acc == 0)
return index == must_count && 0 >= min && 0 <= max;
if(index == must_count)
return check_with_sum_limit(mats, acc, index, 1, min, max);
if(index >= (int32)mats.size())
return FALSE;
int32 op1 = mats[index]->sum_param & 0xffff;
int32 op2 = (mats[index]->sum_param >> 16) & 0xffff;
if(acc >= op1 && check_with_sum_limit_m(mats, acc - op1, index + 1, min, max, must_count))
return TRUE;
if(op2 && acc >= op2 && check_with_sum_limit_m(mats, acc - op2, index + 1, min, max, must_count))
return TRUE;
return FALSE;
}
int32 field::check_with_sum_greater_limit(const card_vector& mats, int32 acc, int32 index, int32 opmin) {
while(index < (int32)mats.size()) {
int32 op1 = mats[index]->sum_param & 0xffff;
int32 op2 = (mats[index]->sum_param >> 16) & 0xffff;
if((acc <= op1 && acc + opmin > op1) || (op2 && acc <= op2 && acc + opmin > op2))
return TRUE;
index++;
if(check_with_sum_greater_limit(mats, acc - op1, index, std::min(opmin, op1)))
return TRUE;
if(op2 && check_with_sum_greater_limit(mats, acc - op2, index, std::min(opmin, op2)))
return TRUE;
}
return FALSE;
}
int32 field::check_with_sum_greater_limit_m(const card_vector& mats, int32 acc, int32 index, int32 opmin, int32 must_count) {
if(acc <= 0)
return index == must_count && acc + opmin > 0;
if(index == must_count)
return check_with_sum_greater_limit(mats, acc, index, opmin);
if(index >= (int32)mats.size())
return FALSE;
int32 op1 = mats[index]->sum_param & 0xffff;
int32 op2 = (mats[index]->sum_param >> 16) & 0xffff;
if(check_with_sum_greater_limit_m(mats, acc - op1, index + 1, std::min(opmin, op1), must_count))
return TRUE;
if(op2 && check_with_sum_greater_limit_m(mats, acc - op2, index + 1, std::min(opmin, op2), must_count))
return TRUE;
return FALSE;
}
int32 field::check_xyz_material(card* scard, int32 findex, int32 lv, int32 min, int32 max, group* mg) {
get_xyz_material(scard, findex, lv, max, mg);
int32 playerid = scard->current.controler;
int32 ct = get_spsummonable_count(scard, playerid);
card_set handover_zone_cards;
if(ct <= 0) {
int32 ft = ct;
uint32 must_use_zone_flag = 0;
filter_must_use_mzone(playerid, playerid, LOCATION_REASON_TOFIELD, scard, &must_use_zone_flag);
uint32 handover_zone = get_rule_zone_fromex(playerid, scard) & ~must_use_zone_flag;
get_cards_in_zone(&handover_zone_cards, handover_zone, playerid, LOCATION_MZONE);
for(auto cit = core.xmaterial_lst.begin(); cit != core.xmaterial_lst.end(); ++cit) {
card* pcard = cit->second;
if(handover_zone_cards.find(pcard) != handover_zone_cards.end())
ft++;
}
if(ft <= 0)
return FALSE;
}
effect_set eset;
filter_player_effect(playerid, EFFECT_MUST_BE_XMATERIAL, &eset);
card_set mcset;
for(int32 i = 0; i < eset.size(); ++i)
mcset.insert(eset[i]->handler);
int32 mct = (int32)mcset.size();
if(mct > 0) {
if(ct == 0 && std::none_of(mcset.begin(), mcset.end(),
[=](card* pcard) { return handover_zone_cards.find(pcard) != handover_zone_cards.end(); }))
mct++;
if(mct > max)
return FALSE;
}
if(!(core.global_flag & GLOBALFLAG_TUNE_MAGICIAN)) {
if(std::any_of(mcset.begin(), mcset.end(),
[=](card* pcard) { return std::find_if(core.xmaterial_lst.begin(), core.xmaterial_lst.end(),
[=](const std::pair<int32, card*>& v) { return v.second == pcard; }) == core.xmaterial_lst.end(); }))
return FALSE;
return (int32)core.xmaterial_lst.size() >= min;
}
for(auto& pcard : mcset) {
effect* peffect = pcard->is_affected_by_effect(EFFECT_TUNE_MAGICIAN_X);
if(peffect) {
for(auto cit = core.xmaterial_lst.begin(); cit != core.xmaterial_lst.end();) {
if(pcard != cit->second && peffect->get_value(cit->second))
cit = core.xmaterial_lst.erase(cit);
else
++cit;
}
}
}
for(auto& pcard : mcset) {
auto it = std::find_if(core.xmaterial_lst.begin(), core.xmaterial_lst.end(),
[=](const std::pair<int32, card*>& v) { return v.second == pcard; });
if(it == core.xmaterial_lst.end())
return FALSE;
if(min < it->first)
min = it->first;
core.xmaterial_lst.erase(it);
}
for(auto cit = core.xmaterial_lst.begin(); cit != core.xmaterial_lst.end(); ++cit)
cit->second->sum_param = 0;
int32 digit = 1;
for(auto cit = core.xmaterial_lst.begin(); cit != core.xmaterial_lst.end();) {
card* pcard = cit->second;
effect* peffect = pcard->is_affected_by_effect(EFFECT_TUNE_MAGICIAN_X);
if(peffect) {
if(std::any_of(mcset.begin(), mcset.end(),
[=](card* mcard) { return !!peffect->get_value(mcard); })) {
cit = core.xmaterial_lst.erase(cit);
continue;
}
digit <<= 1;
for(auto mit = core.xmaterial_lst.begin(); mit != core.xmaterial_lst.end(); ++mit) {
if(!peffect->get_value(mit->second))
mit->second->sum_param |= digit;
}
pcard->sum_param |= digit;
} else
pcard->sum_param |= 1;
++cit;
}
ct += (int32)std::count_if(mcset.begin(), mcset.end(),
[=](card* pcard) { return handover_zone_cards.find(pcard) != handover_zone_cards.end(); });
std::multimap<int32, card*, std::greater<int32>> mat;
for(int32 icheck = 1; icheck <= digit; icheck <<= 1) {
mat.clear();
for(auto cit = core.xmaterial_lst.begin(); cit != core.xmaterial_lst.end(); ++cit) {
if(cit->second->sum_param & icheck)
mat.insert(*cit);
}
if(core.global_flag & GLOBALFLAG_XMAT_COUNT_LIMIT) {
int32 maxc = std::min(max, (int32)mat.size() + mct);
auto iter = mat.lower_bound(maxc);
mat.erase(mat.begin(), iter);
}
if(ct <= 0) {
int32 ft = ct;
for(auto cit = mat.begin(); cit != mat.end(); ++cit) {
card* pcard = cit->second;
if(handover_zone_cards.find(pcard) != handover_zone_cards.end())
ft++;
}
if(ft <= 0)
continue;
}
if((int32)mat.size() + mct >= min)
return TRUE;
}
return FALSE;
}
int32 field::is_player_can_draw(uint8 playerid) {
return !is_player_affected_by_effect(playerid, EFFECT_CANNOT_DRAW);
}
int32 field::is_player_can_discard_deck(uint8 playerid, int32 count) {
if(player[playerid].list_main.size() < (uint32)count)
return FALSE;
return !is_player_affected_by_effect(playerid, EFFECT_CANNOT_DISCARD_DECK);
}
int32 field::is_player_can_discard_deck_as_cost(uint8 playerid, int32 count) {
if(player[playerid].list_main.size() < (uint32)count)
return FALSE;
if(is_player_affected_by_effect(playerid, EFFECT_CANNOT_DISCARD_DECK))
return FALSE;
if((count == 1) && core.deck_reversed)
return player[playerid].list_main.back()->is_capable_cost_to_grave(playerid);
effect_set eset;
filter_field_effect(EFFECT_TO_GRAVE_REDIRECT, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
uint32 redirect = eset[i]->get_value();
if((redirect & LOCATION_REMOVED) && player[playerid].list_main.back()->is_affected_by_effect(EFFECT_CANNOT_REMOVE))
continue;
uint8 p = eset[i]->get_handler_player();
if((p == playerid && eset[i]->s_range & LOCATION_DECK) || (p != playerid && eset[i]->o_range & LOCATION_DECK))
return FALSE;
}
return TRUE;
}
int32 field::is_player_can_discard_hand(uint8 playerid, card * pcard, effect * reason_effect, uint32 reason) {
if(pcard->current.location != LOCATION_HAND)
return FALSE;
effect_set eset;
filter_player_effect(playerid, EFFECT_CANNOT_DISCARD_HAND, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(reason_effect, PARAM_TYPE_EFFECT);
pduel->lua->add_param(reason, PARAM_TYPE_INT);
if (pduel->lua->check_condition(eset[i]->target, 4))
return FALSE;
}
return TRUE;
}
int32 field::is_player_can_action(uint8 playerid, uint32 actionlimit) {
effect_set eset;
filter_player_effect(playerid, actionlimit, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
}
return TRUE;
}
int32 field::is_player_can_summon(uint32 sumtype, uint8 playerid, card * pcard, uint8 toplayer) {
effect_set eset;
sumtype |= SUMMON_TYPE_NORMAL;
filter_player_effect(playerid, EFFECT_CANNOT_SUMMON, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(sumtype, PARAM_TYPE_INT);
pduel->lua->add_param(POS_FACEUP, PARAM_TYPE_INT);
pduel->lua->add_param(toplayer, PARAM_TYPE_INT);
if(pduel->lua->check_condition(eset[i]->target, 6))
return FALSE;
}
return TRUE;
}
int32 field::is_player_can_mset(uint32 sumtype, uint8 playerid, card * pcard, uint8 toplayer) {
effect_set eset;
sumtype |= SUMMON_TYPE_NORMAL;
filter_player_effect(playerid, EFFECT_CANNOT_MSET, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(sumtype, PARAM_TYPE_INT);
pduel->lua->add_param(POS_FACEDOWN, PARAM_TYPE_INT);
pduel->lua->add_param(toplayer, PARAM_TYPE_INT);
if (pduel->lua->check_condition(eset[i]->target, 6))
return FALSE;
}
return TRUE;
}
int32 field::is_player_can_sset(uint8 playerid, card * pcard) {
effect_set eset;
filter_player_effect(playerid, EFFECT_CANNOT_SSET, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
if (pduel->lua->check_condition(eset[i]->target, 3))
return FALSE;
}
return TRUE;
}
// check player-effect EFFECT_CANNOT_SPECIAL_SUMMON without target
int32 field::is_player_can_spsummon(uint8 playerid) {
effect_set eset;
filter_player_effect(playerid, EFFECT_CANNOT_SPECIAL_SUMMON, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
}
return is_player_can_spsummon_count(playerid, 1);
}
int32 field::is_player_can_spsummon(effect* reason_effect, uint32 sumtype, uint8 sumpos, uint8 playerid, uint8 toplayer, card* pcard) {
if(pcard->is_affected_by_effect(EFFECT_CANNOT_SPECIAL_SUMMON))
return FALSE;
if(pcard->is_status(STATUS_FORBIDDEN))
return FALSE;
if((pcard->data.type & TYPE_TOKEN) && (pcard->current.location & LOCATION_ONFIELD))
return FALSE;
if(pcard->data.type & TYPE_LINK)
sumpos &= POS_FACEUP_ATTACK;
if(sumpos == 0)
return FALSE;
sumtype |= SUMMON_TYPE_SPECIAL;
save_lp_cost();
if(!pcard->check_cost_condition(EFFECT_SPSUMMON_COST, playerid, sumtype)) {
restore_lp_cost();
return FALSE;
}
restore_lp_cost();
if(sumpos & POS_FACEDOWN && is_player_affected_by_effect(playerid, EFFECT_DEVINE_LIGHT))
sumpos = (sumpos & POS_FACEUP) | ((sumpos & POS_FACEDOWN) >> 1);
effect_set eset;
filter_player_effect(playerid, EFFECT_CANNOT_SPECIAL_SUMMON, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(sumtype, PARAM_TYPE_INT);
pduel->lua->add_param(sumpos, PARAM_TYPE_INT);
pduel->lua->add_param(toplayer, PARAM_TYPE_INT);
pduel->lua->add_param(reason_effect, PARAM_TYPE_EFFECT);
if (pduel->lua->check_condition(eset[i]->target, 7))
return FALSE;
}
if(!check_spsummon_once(pcard, playerid))
return FALSE;
if(!check_spsummon_counter(playerid))
return FALSE;
return TRUE;
}
int32 field::is_player_can_flipsummon(uint8 playerid, card * pcard) {
effect_set eset;
filter_player_effect(playerid, EFFECT_CANNOT_FLIP_SUMMON, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
if (pduel->lua->check_condition(eset[i]->target, 3))
return FALSE;
}
return TRUE;
}
int32 field::is_player_can_spsummon_monster(uint8 playerid, uint8 toplayer, uint8 sumpos, uint32 sumtype, card_data* pdata) {
temp_card->data = *pdata;
int32 result = is_player_can_spsummon(core.reason_effect, sumtype, sumpos, playerid, toplayer, temp_card);
temp_card->data.clear();
return result;
}
int32 field::is_player_can_release(uint8 playerid, card * pcard) {
effect_set eset;
filter_player_effect(playerid, EFFECT_CANNOT_RELEASE, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
if (pduel->lua->check_condition(eset[i]->target, 3))
return FALSE;
}
return TRUE;
}
int32 field::is_player_can_spsummon_count(uint8 playerid, uint32 count) {
effect_set eset;
filter_player_effect(playerid, EFFECT_LEFT_SPSUMMON_COUNT, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
pduel->lua->add_param(core.reason_effect, PARAM_TYPE_EFFECT);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
int32 v = eset[i]->get_value(2);
if(v < (int32)count)
return FALSE;
}
return check_spsummon_counter(playerid, count);
}
int32 field::is_player_can_place_counter(uint8 playerid, card * pcard, uint16 countertype, uint16 count) {
effect_set eset;
filter_player_effect(playerid, EFFECT_CANNOT_PLACE_COUNTER, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
if (pduel->lua->check_condition(eset[i]->target, 3))
return FALSE;
}
return TRUE;
}
int32 field::is_player_can_remove_counter(uint8 playerid, card * pcard, uint8 s, uint8 o, uint16 countertype, uint16 count, uint32 reason) {
if((pcard && pcard->get_counter(countertype) >= count) || (!pcard && get_field_counter(playerid, s, o, countertype) >= count))
return TRUE;
auto pr = effects.continuous_effect.equal_range(EFFECT_RCOUNTER_REPLACE + countertype);
tevent e;
e.event_cards = 0;
e.event_player = playerid;
e.event_value = count;
e.reason = reason;
e.reason_effect = core.reason_effect;
e.reason_player = playerid;
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
if(peffect->is_activateable(peffect->get_handler_player(), e))
return TRUE;
}
return FALSE;
}
int32 field::is_player_can_remove_overlay_card(uint8 playerid, card * pcard, uint8 s, uint8 o, uint16 min, uint32 reason) {
if((pcard && pcard->xyz_materials.size() >= min) || (!pcard && get_overlay_count(playerid, s, o) >= min))
return TRUE;
auto pr = effects.continuous_effect.equal_range(EFFECT_OVERLAY_REMOVE_REPLACE);
tevent e;
e.event_cards = 0;
e.event_player = playerid;
e.event_value = min;
e.reason = reason;
e.reason_effect = core.reason_effect;
e.reason_player = playerid;
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
if(peffect->is_activateable(peffect->get_handler_player(), e))
return TRUE;
}
return FALSE;
}
int32 field::is_player_can_send_to_grave(uint8 playerid, card * pcard) {
effect_set eset;
filter_player_effect(playerid, EFFECT_CANNOT_TO_GRAVE, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
if (pduel->lua->check_condition(eset[i]->target, 3))
return FALSE;
}
return TRUE;
}
int32 field::is_player_can_send_to_hand(uint8 playerid, card * pcard) {
effect_set eset;
filter_player_effect(playerid, EFFECT_CANNOT_TO_HAND, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(core.reason_effect, PARAM_TYPE_EFFECT);
if (pduel->lua->check_condition(eset[i]->target, 4))
return FALSE;
}
if(pcard->is_extra_deck_monster() && !is_player_can_send_to_deck(playerid, pcard))
return FALSE;
return TRUE;
}
int32 field::is_player_can_send_to_deck(uint8 playerid, card * pcard) {
effect_set eset;
filter_player_effect(playerid, EFFECT_CANNOT_TO_DECK, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
if (pduel->lua->check_condition(eset[i]->target, 3))
return FALSE;
}
return TRUE;
}
int32 field::is_player_can_remove(uint8 playerid, card * pcard, uint32 reason) {
effect_set eset;
filter_player_effect(playerid, EFFECT_CANNOT_REMOVE, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(!eset[i]->target)
return FALSE;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(reason, PARAM_TYPE_INT);
pduel->lua->add_param(core.reason_effect, PARAM_TYPE_EFFECT);
if(pduel->lua->check_condition(eset[i]->target, 5))
return FALSE;
}
return TRUE;
}
int32 field::is_chain_negatable(uint8 chaincount) {
effect_set eset;
if(chaincount < 0 || chaincount > core.current_chain.size())
return FALSE;
effect* peffect;
if(chaincount == 0)
peffect = core.current_chain.back().triggering_effect;
else
peffect = core.current_chain[chaincount - 1].triggering_effect;
if(peffect->is_flag(EFFECT_FLAG_CANNOT_INACTIVATE))
return FALSE;
filter_field_effect(EFFECT_CANNOT_INACTIVATE, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
pduel->lua->add_param(chaincount, PARAM_TYPE_INT);
if(eset[i]->check_value_condition(1))
return FALSE;
}
return TRUE;
}
int32 field::is_chain_disablable(uint8 chaincount) {
effect_set eset;
if(chaincount < 0 || chaincount > core.current_chain.size())
return FALSE;
effect* peffect;
if(chaincount == 0)
peffect = core.current_chain.back().triggering_effect;
else
peffect = core.current_chain[chaincount - 1].triggering_effect;
if(!peffect->get_handler()->get_status(STATUS_FORBIDDEN)) {
if(peffect->is_flag(EFFECT_FLAG_CANNOT_DISABLE))
return FALSE;
filter_field_effect(EFFECT_CANNOT_DISEFFECT, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
pduel->lua->add_param(chaincount, PARAM_TYPE_INT);
if(eset[i]->check_value_condition(1))
return FALSE;
}
}
return TRUE;
}
int32 field::is_chain_disabled(uint8 chaincount) {
if(chaincount < 0 || chaincount > core.current_chain.size())
return FALSE;
chain* pchain;
if(chaincount == 0)
pchain = &core.current_chain.back();
else
pchain = &core.current_chain[chaincount - 1];
if(pchain->flag & CHAIN_DISABLE_EFFECT)
return TRUE;
card* pcard = pchain->triggering_effect->get_handler();
auto rg = pcard->single_effect.equal_range(EFFECT_DISABLE_CHAIN);
for(; rg.first != rg.second; ++rg.first) {
effect* peffect = rg.first->second;
if(peffect->get_value() == pchain->chain_id) {
peffect->reset_flag |= RESET_CHAIN;
return TRUE;
}
}
return FALSE;
}
int32 field::check_chain_target(uint8 chaincount, card * pcard) {
if(chaincount < 0 || chaincount > core.current_chain.size())
return FALSE;
chain* pchain;
if(chaincount == 0)
pchain = &core.current_chain.back();
else
pchain = &core.current_chain[chaincount - 1];
effect* peffect = pchain->triggering_effect;
uint8 tp = pchain->triggering_player;
if(!peffect->is_flag(EFFECT_FLAG_CARD_TARGET) || !peffect->target)
return FALSE;
pduel->lua->add_param(peffect, PARAM_TYPE_EFFECT);
pduel->lua->add_param(tp, PARAM_TYPE_INT);
pduel->lua->add_param(pchain->evt.event_cards , PARAM_TYPE_GROUP);
pduel->lua->add_param(pchain->evt.event_player, PARAM_TYPE_INT);
pduel->lua->add_param(pchain->evt.event_value, PARAM_TYPE_INT);
pduel->lua->add_param(pchain->evt.reason_effect , PARAM_TYPE_EFFECT);
pduel->lua->add_param(pchain->evt.reason, PARAM_TYPE_INT);
pduel->lua->add_param(pchain->evt.reason_player, PARAM_TYPE_INT);
pduel->lua->add_param((ptr)0, PARAM_TYPE_INT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
return pduel->lua->check_condition(peffect->target, 10);
}
chain* field::get_chain(uint32 chaincount) {
if(chaincount == 0 && core.continuous_chain.size() && (core.reason_effect->type & EFFECT_TYPE_CONTINUOUS))
return &core.continuous_chain.back();
if(chaincount == 0 || chaincount > core.current_chain.size()) {
chaincount = (uint32)core.current_chain.size();
if(chaincount == 0)
return 0;
}
return &core.current_chain[chaincount - 1];
}
int32 field::get_cteffect(effect* peffect, int32 playerid, int32 store) {
card* phandler = peffect->get_handler();
if(phandler->data.type != (TYPE_TRAP | TYPE_CONTINUOUS))
return FALSE;
if(!(peffect->type & EFFECT_TYPE_ACTIVATE))
return FALSE;
if(peffect->code != EVENT_FREE_CHAIN)
return FALSE;
if(peffect->cost || peffect->target || peffect->operation)
return FALSE;
if(store) {
core.select_chains.clear();
core.select_options.clear();
}
for(auto& efit : phandler->field_effect) {
effect* feffect = efit.second;
if(!(feffect->type & (EFFECT_TYPE_TRIGGER_F | EFFECT_TYPE_TRIGGER_O | EFFECT_TYPE_QUICK_O)))
continue;
if(!feffect->in_range(phandler))
continue;
uint32 code = efit.first;
if(code == EVENT_FREE_CHAIN || code == EVENT_PHASE + infos.phase) {
nil_event.event_code = code;
if(get_cteffect_evt(feffect, playerid, nil_event, store) && !store)
return TRUE;
} else {
for(const auto& ev : core.point_event) {
if(code != ev.event_code)
continue;
if(get_cteffect_evt(feffect, playerid, ev, store) && !store)
return TRUE;
}
for(const auto& ev : core.instant_event) {
if(code != ev.event_code)
continue;
if(get_cteffect_evt(feffect, playerid, ev, store) && !store)
return TRUE;
}
}
}
return (store && !core.select_chains.empty()) ? TRUE : FALSE;
}
int32 field::get_cteffect_evt(effect* feffect, int32 playerid, const tevent& e, int32 store) {
if(!feffect->is_activateable(playerid, e, FALSE, FALSE, FALSE, FALSE, TRUE))
return FALSE;
if(store) {
chain newchain;
newchain.evt = e;
newchain.triggering_effect = feffect;
core.select_chains.push_back(newchain);
core.select_options.push_back(feffect->description);
}
return TRUE;
}
int32 field::check_cteffect_hint(effect* peffect, uint8 playerid) {
card* phandler = peffect->get_handler();
if(phandler->data.type != (TYPE_TRAP | TYPE_CONTINUOUS))
return FALSE;
if(!(peffect->type & EFFECT_TYPE_ACTIVATE))
return FALSE;
if(peffect->code != EVENT_FREE_CHAIN)
return FALSE;
if(peffect->cost || peffect->target || peffect->operation)
return FALSE;
for(auto& efit : phandler->field_effect) {
effect* feffect = efit.second;
if(!(feffect->type & (EFFECT_TYPE_TRIGGER_F | EFFECT_TYPE_TRIGGER_O | EFFECT_TYPE_QUICK_O)))
continue;
if(!feffect->in_range(phandler))
continue;
uint32 code = efit.first;
if(code == EVENT_FREE_CHAIN || code == EVENT_PHASE + infos.phase) {
nil_event.event_code = code;
if(get_cteffect_evt(feffect, playerid, nil_event, FALSE)
&& (code != EVENT_FREE_CHAIN || check_hint_timing(feffect)))
return TRUE;
} else {
for(const auto& ev : core.point_event) {
if(code != ev.event_code)
continue;
if(get_cteffect_evt(feffect, playerid, ev, FALSE))
return TRUE;
}
for(const auto& ev : core.instant_event) {
if(code != ev.event_code)
continue;
if(get_cteffect_evt(feffect, playerid, ev, FALSE))
return TRUE;
}
}
}
return FALSE;
}
int32 field::check_nonpublic_trigger(chain& ch) {
effect* peffect = ch.triggering_effect;
card* phandler = peffect->get_handler();
if(!peffect->is_flag(EFFECT_FLAG_FIELD_ONLY)
&& ((peffect->type & EFFECT_TYPE_SINGLE) && !peffect->is_flag(EFFECT_FLAG_SINGLE_RANGE)
&& phandler->is_has_relation(ch) && (ch.triggering_location & (LOCATION_HAND | LOCATION_DECK))
|| (peffect->range & (LOCATION_HAND | LOCATION_DECK)))) {
ch.flag |= CHAIN_HAND_TRIGGER;
core.new_ochain_h.push_back(ch);
if(ch.triggering_location == LOCATION_HAND && phandler->is_position(POS_FACEDOWN)
|| ch.triggering_location == LOCATION_DECK
|| peffect->range && !peffect->in_range(ch))
return FALSE;
}
return TRUE;
}
int32 field::check_trigger_effect(const chain& ch) const {
effect* peffect = ch.triggering_effect;
card* phandler = peffect->get_handler();
if(core.duel_rule >= 5)
return phandler->is_has_relation(ch);
else {
if(peffect->type & EFFECT_TYPE_FIELD)
return phandler->is_has_relation(ch);
else {
if((ch.triggering_location & (LOCATION_DECK | LOCATION_HAND | LOCATION_EXTRA))
&& (ch.triggering_position & POS_FACEDOWN))
return TRUE;
if(!(phandler->current.location & (LOCATION_DECK | LOCATION_HAND | LOCATION_EXTRA))
|| phandler->is_position(POS_FACEUP))
return TRUE;
return FALSE;
}
}
}
int32 field::check_spself_from_hand_trigger(const chain& ch) const {
effect* peffect = ch.triggering_effect;
uint8 tp = ch.triggering_player;
if((peffect->status & EFFECT_STATUS_SPSELF) && (ch.flag & CHAIN_HAND_TRIGGER)) {
return std::none_of(core.current_chain.begin(), core.current_chain.end(), [tp](chain ch) {
return ch.triggering_player == tp
&& (ch.triggering_effect->status & EFFECT_STATUS_SPSELF) && (ch.flag & CHAIN_HAND_TRIGGER);
});
}
return TRUE;
}
int32 field::is_able_to_enter_bp() {
return ((core.duel_options & DUEL_ATTACK_FIRST_TURN) || infos.turn_id != 1)
&& infos.phase < PHASE_BATTLE_START
&& !is_player_affected_by_effect(infos.turn_player, EFFECT_CANNOT_BP);
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/alanisia/ygopro-core.git
git@gitee.com:alanisia/ygopro-core.git
alanisia
ygopro-core
ygopro-core
master

搜索帮助