dep-ygopro-core/processor.cpp

5686 lines
No EOL
198 KiB
C++

/*
* processor.cpp
*
* Created on: 2010-8-3
* Author: Argon
*/
#include "field.h"
#include "duel.h"
#include "card.h"
#include "group.h"
#include "effect.h"
#include "interpreter.h"
#include <iterator>
void field::add_process(uint16 type, uint16 step, effect* peffect, group* target, int64 arg1, int64 arg2, int64 arg3, int64 arg4, void* ptr1, void* ptr2) {
processor_unit new_unit;
new_unit.type = type;
new_unit.step = step;
new_unit.peffect = peffect;
new_unit.ptarget = target;
new_unit.arg1 = arg1;
new_unit.arg2 = arg2;
new_unit.arg3 = arg3;
new_unit.arg4 = arg4;
new_unit.ptr1 = ptr1;
new_unit.ptr2 = ptr2;
core.subunits.push_back(new_unit);
}
int32 field::process() {
if (core.subunits.size())
core.units.splice(core.units.begin(), core.subunits);
if (core.units.size() == 0)
return PROCESSOR_FLAG_END;
auto it = core.units.begin();
switch (it->type) {
case PROCESSOR_ADJUST: {
if (adjust_step(it->step))
core.units.pop_front();
else {
it->step++;
}
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_TURN: {
if (process_turn(it->step, it->arg1))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_REFRESH_LOC: {
if (refresh_location_info(it->step))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_STARTUP: {
if (startup(it->step))
core.units.pop_front();
else {
it->step++;
}
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SELECT_BATTLECMD: {
if (select_battle_command(it->step, it->arg1)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_IDLECMD: {
if (select_idle_command(it->step, it->arg1)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_EFFECTYN: {
if (select_effect_yes_no(it->step, it->arg1, it->arg2, (card*)it->ptarget)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_YESNO: {
if (select_yes_no(it->step, it->arg1, it->arg2)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_OPTION: {
if (select_option(it->step, it->arg1)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_CARD: {
if (select_card(it->step, it->arg1 & 0xff, (it->arg1 >> 16) & 0xff, (it->arg2) & 0xff, (it->arg2 >> 16) & 0xff, (it->arg3) & 0xff)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_UNSELECT_CARD: {
if (select_unselect_card(it->step, it->arg1 & 0xff, (it->arg1 >> 16) & 0xff, (it->arg2) & 0xff, (it->arg2 >> 16) & 0xff, (it->arg3) & 0xff)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_CHAIN: {
if (select_chain(it->step, it->arg1, (it->arg2 & 0xffff), it->arg2 >> 16)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_DISFIELD:
case PROCESSOR_SELECT_PLACE: {
if(select_place(it->step, it->arg1, it->arg2, it->arg3)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_POSITION: {
if (select_position(it->step, it->arg1 & 0xffff, it->arg2, (it->arg1 >> 16) & 0xffff)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_TRIBUTE_P: {
if (select_tribute(it->step, it->arg1 & 0xff, (it->arg1 >> 16) & 0xff, (it->arg2) & 0xff, (it->arg2 >> 16) & 0xff)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SORT_CHAIN: {
if(sort_chain(it->step, it->arg1)) {
core.units.pop_front();
} else {
it->step++;
}
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SELECT_COUNTER: {
if (select_counter(it->step, it->arg1, it->arg2, it->arg3, it->arg4 >> 8, it->arg4 & 0xff)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_SUM: {
if (select_with_sum_limit(it->step, it->arg2 & 0xffff, it->arg1, (it->arg2 >> 16) & 0xff, (it->arg2 >> 24) & 0xff)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SORT_CARD: {
if (sort_card(it->step, it->arg1, it->arg2)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step = 1;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_RELEASE: {
if (select_release_cards(it->step, it->arg1 & 0xff, (it->arg1 >> 16) & 0xff, (it->arg2) & 0xff, (it->arg2 >> 16) & 0xff, it->arg3 & 0xff, (card*)it->ptarget, (it->arg3 >> 8) & 0xff, (it->arg3 >> 16) & 0xff))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SELECT_TRIBUTE: {
if (select_tribute_cards(it->step, (card*)it->ptarget, it->arg1 & 0xff, (it->arg1 >> 16) & 0xff, (it->arg2) & 0xff, (it->arg2 >> 16) & 0xff, it->arg3, it->arg4))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_POINT_EVENT: {
if(process_point_event(it->step, it->arg1 & 0xff, (it->arg1 >> 8) & 0xff, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_QUICK_EFFECT: {
if(process_quick_effect(it->step, it->arg1, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_IDLE_COMMAND: {
if(process_idle_command(it->step))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_PHASE_EVENT: {
if(process_phase_event(it->step, it->arg1))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_BATTLE_COMMAND: {
if(process_battle_command(it->step))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_DAMAGE_STEP: {
if(process_damage_step(it->step, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_FORCED_BATTLE: {
if(process_forced_battle(it->step))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_ADD_CHAIN: {
if (add_chain(it->step))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SOLVE_CHAIN: {
if (solve_chain(it->step, it->arg1, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SOLVE_CONTINUOUS: {
if (solve_continuous(it->step))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_EXECUTE_COST: {
if (execute_cost(it->step, it->peffect, it->arg1)) {
core.units.pop_front();
core.solving_event.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_EXECUTE_OPERATION: {
if (execute_operation(it->step, it->peffect, it->arg1)) {
core.units.pop_front();
core.solving_event.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_EXECUTE_TARGET: {
if (execute_target(it->step, it->peffect, it->arg1)) {
core.units.pop_front();
core.solving_event.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_DESTROY: {
if (destroy(it->step, it->ptarget, it->peffect, it->arg1, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_RELEASE: {
if (release(it->step, it->ptarget, it->peffect, it->arg1, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SENDTO: {
if (send_to(it->step, it->ptarget, it->peffect, it->arg1, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_DESTROY_REPLACE: {
if(destroy_replace(it->step, it->ptarget, (card*)it->ptr1, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_RELEASE_REPLACE: {
if (release_replace(it->step, it->ptarget, (card*)it->ptr1))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SENDTO_REPLACE: {
if (send_replace(it->step, it->ptarget, (card*)it->ptr1))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_MOVETOFIELD: {
if (move_to_field(it->step, (card*)it->ptarget, it->arg1 & 0xff, (it->arg1 >> 8) & 0xff, (it->arg1 >> 16) & 0xff, (it->arg1 >> 24) & 0xff, it->arg2 & 0xff, (it->arg2 >> 8) & 0xff, (it->arg2 >> 16) & 0xff))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_CHANGEPOS: {
if (change_position(it->step, it->ptarget, it->peffect, it->arg1, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_OPERATION_REPLACE: {
if (operation_replace(it->step, it->peffect, it->ptarget, (card*)it->ptr1, it->arg1))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_ACTIVATE_EFFECT: {
if (activate_effect(it->step, it->peffect))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SUMMON_RULE: {
if (summon(it->step, it->arg1 & 0xff, (card*)it->ptarget, it->peffect, (it->arg1 >> 8) & 0xff, (it->arg1 >> 16) & 0xff, (it->arg1 >> 24) & 0xff))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SPSUMMON_RULE: {
if (special_summon_rule(it->step, it->arg1, (card*)it->ptarget, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SPSUMMON: {
if (special_summon(it->step, it->peffect, it->arg1, it->ptarget, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_FLIP_SUMMON: {
if (flip_summon(it->step, it->arg1, (card*)(it->ptarget)))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_MSET: {
if (mset(it->step, it->arg1 & 0xff, (card*)it->ptarget, it->peffect, (it->arg1 >> 8) & 0xff, (it->arg1 >> 16) & 0xff, (it->arg1 >> 24) & 0xff))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SSET: {
if (sset(it->step, it->arg1, it->arg2, (card*)(it->ptarget), it->peffect))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SPSUMMON_STEP: {
if (special_summon_step(it->step, it->ptarget, (card*)(it->ptr1), it->arg1))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SSET_G: {
if (sset_g(it->step, it->arg1, it->arg2, it->ptarget, it->arg3, it->peffect)) {
core.units.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SPSUMMON_RULE_G: {
if (special_summon_rule_group(it->step, it->arg1, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_DRAW : {
if (draw(it->step, it->peffect, it->arg1, (it->arg2 >> 28) & 0xf, (it->arg2 >> 24) & 0xf, it->arg2 & 0xffffff))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_DAMAGE: {
int32 reason = it->arg1;
effect* reason_effect = 0;
card* reason_card = 0;
if(reason & REASON_BATTLE)
reason_card = (card*)it->peffect;
else
reason_effect = it->peffect;
if (damage(it->step, reason_effect, reason, (it->arg2 >> 26) & 0x3, reason_card, (it->arg2 >> 24) & 0x3, it->arg2 & 0xffffff, (it->arg2 >> 28) & 0x1)) {
if(it->step == 9) {
it->step = 1;
core.recover_damage_reserve.splice(core.recover_damage_reserve.end(), core.units, it);
} else
core.units.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_RECOVER: {
if (recover(it->step, it->peffect, it->arg1, (it->arg2 >> 26) & 0x3, (it->arg2 >> 24) & 0x3, it->arg2 & 0xffffff, (it->arg2 >> 28) & 0x1)) {
if(it->step == 9) {
it->step = 1;
core.recover_damage_reserve.splice(core.recover_damage_reserve.end(), core.units, it);
} else
core.units.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_EQUIP: {
if (equip(it->step, it->arg2 & 0xffff, (card*)it->ptr1, (card*)it->ptarget, (it->arg2 >> 16) & 0xff, (it->arg2 >> 24) & 0xff))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_GET_CONTROL: {
if (get_control(it->step, it->peffect, (it->arg2 >> 28) & 0xf, it->ptarget, (it->arg2 >> 24) & 0xf, (it->arg2 >> 8) & 0x3ff, it->arg2 & 0xff, it->arg3)) {
core.units.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SWAP_CONTROL: {
if (swap_control(it->step, it->peffect, it->arg1, it->ptarget, (group*)it->ptr1, it->arg2, it->arg3)) {
core.units.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_CONTROL_ADJUST: {
if (control_adjust(it->step)) {
core.units.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SELF_DESTROY: {
if (self_destroy(it->step, (card*)it->ptr1, it->arg1)) {
core.units.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_TRAP_MONSTER_ADJUST: {
if (trap_monster_adjust(it->step))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_PAY_LPCOST: {
if (pay_lp_cost(it->step, it->arg1, it->arg2))
core.units.pop_front();
else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_REMOVE_COUNTER: {
if (remove_counter(it->step, it->arg4, (card*)it->ptarget, (it->arg1 >> 16) & 0xff, (it->arg1 >> 8) & 0xff, it->arg1 & 0xff, it->arg2, it->arg3)) {
core.units.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_ATTACK_DISABLE: {
if(it->step == 0) {
card* attacker = core.attacker;
if(!attacker
|| core.effect_damage_step != 0
|| (attacker->fieldid_r != core.pre_field[0])
|| (attacker->current.location != LOCATION_MZONE)
|| !attacker->is_capable_attack()
|| !attacker->is_affect_by_effect(core.reason_effect)
|| attacker->is_affected_by_effect(EFFECT_UNSTOPPABLE_ATTACK)) {
returns.at<int32>(0) = 0;
core.units.pop_front();
} else {
effect* peffect = pduel->new_effect();
peffect->code = EFFECT_ATTACK_DISABLED;
peffect->type = EFFECT_TYPE_SINGLE;
attacker->add_effect(peffect);
attacker->set_status(STATUS_ATTACK_CANCELED, TRUE);
raise_event(attacker, EVENT_ATTACK_DISABLED, core.reason_effect, 0, core.reason_player, PLAYER_NONE, 0);
process_instant_event();
it->step++;
}
} else {
returns.at<int32>(0) = 1;
core.units.pop_front();
}
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_ANNOUNCE_RACE: {
if(announce_race(it->step, it->arg1 & 0xffff, it->arg1 >> 16, it->arg2)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step++;
}
return PROCESSOR_FLAG_WAITING;
}
case PROCESSOR_ANNOUNCE_ATTRIB: {
if(announce_attribute(it->step, it->arg1 & 0xffff, it->arg1 >> 16, it->arg2)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step++;
}
return PROCESSOR_FLAG_WAITING;
}
case PROCESSOR_ANNOUNCE_CARD: {
if(announce_card(it->step, it->arg1)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
if(it->step == 0)
it->step++;
}
return PROCESSOR_FLAG_WAITING;
}
case PROCESSOR_ANNOUNCE_NUMBER: {
if(announce_number(it->step, it->arg1)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step++;
}
return PROCESSOR_FLAG_WAITING;
}
case PROCESSOR_TOSS_DICE: {
if(toss_dice(it->step, it->peffect, it->arg1 >> 16, it->arg1 & 0xff, it->arg2 & 0xff, it->arg2 >> 16)) {
core.units.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_TOSS_COIN: {
if (toss_coin(it->step, it->peffect, (it->arg1 >> 16), it->arg1 & 0xff, it->arg2)) {
core.units.pop_front();
} else
it->step++;
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_ROCK_PAPER_SCISSORS: {
if (rock_paper_scissors(it->step, it->arg1)) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
} else {
it->step++;
return PROCESSOR_FLAG_WAITING;
}
}
case PROCESSOR_SELECT_FUSION: {
if(it->step == 0) {
effect_set eset;
card* pcard = (card*)it->ptr2;
pcard->fusion_filter_valid(it->ptarget, (group*)it->ptr1, it->arg1>>16, &eset);
core.select_effects.clear();
core.select_options.clear();
if(eset.size() < 1) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
}
for(const auto& peff : eset) {
core.select_effects.push_back(peff);
core.select_options.push_back(peff->description);
}
if (core.select_options.size() == 1)
returns.at<int32>(0) = 0;
else
add_process(PROCESSOR_SELECT_OPTION, 0, 0, 0, it->arg1, 0);
it->step++;
} else if(it->step==1){
tevent e;
e.event_cards = it->ptarget;
e.reason_effect = core.select_effects[returns.at<int32>(0)];
e.reason_player = it->arg1;
core.fusion_materials.clear();
if(!core.select_effects[returns.at<int32>(0)]) {
core.units.pop_front();
return PROCESSOR_FLAG_CONTINUE;
}
core.sub_solving_event.push_back(e);
pduel->lua->add_param(it->ptr1, PARAM_TYPE_GROUP);
pduel->lua->add_param(it->arg1 >> 16, PARAM_TYPE_INT);
add_process(PROCESSOR_EXECUTE_OPERATION, 0, core.select_effects[returns.at<int32>(0)], 0, it->arg1 & 0xffff, 0);
it->step++;
} else {
core.units.pop_front();
}
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_DISCARD_HAND: {
if(it->step == 0) {
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_SELECTMSG);
message->write<uint8>(it->arg1);
if(it->arg3 & REASON_DISCARD)
message->write<uint64>(501);
else
message->write<uint64>(504);
add_process(PROCESSOR_SELECT_CARD, 0, 0, 0, it->arg1, it->arg2);
it->step++;
} else if(it->step == 1) {
card_set cset(return_cards.list.begin(), return_cards.list.end());
if(cset.size())
send_to(&cset, core.reason_effect, it->arg3, core.reason_player, PLAYER_NONE, LOCATION_GRAVE, 0, POS_FACEUP);
else
returns.at<int32>(0) = 0;
it->step++;
} else {
core.units.pop_front();
}
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_DISCARD_DECK: {
if(discard_deck(it->step, it->arg1 & 0xff, it->arg1 >> 16, it->arg2)) {
core.units.pop_front();
} else {
it->step++;
}
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_SORT_DECK: {
uint8 sort_player = it->arg1 & 0xffff;
uint8 target_player = it->arg1 >> 16;
uint32 count = it->arg2, i = 0;
bool bottom = it->arg3;
auto& list = player[target_player].list_main;
if(count > list.size())
count = list.size();
if(it->step == 0) {
core.select_cards.clear();
if(bottom) {
for(auto clit = list.begin(); i < count; ++i, ++clit)
core.select_cards.push_back(*clit);
} else {
for(auto clit = list.rbegin(); i < count; ++i, ++clit)
core.select_cards.push_back(*clit);
}
add_process(PROCESSOR_SORT_CARD, 0, 0, 0, sort_player, 0);
it->step++;
} else {
if(returns.at<int8>(0) != -1) {
card* tc[64];
for(i = 0; i < count; ++i)
tc[returns.at<uint8>(i)] = core.select_cards[i];
for(i = 0; i < count; ++i) {
card* pcard = nullptr;
if(bottom)
pcard = tc[i];
else
pcard = tc[count - i - 1];
auto message = pduel->new_message(MSG_MOVE);
message->write<uint32>(0);
message->write(pcard->get_info_location());
list.erase(list.begin() + pcard->current.sequence);
if(bottom)
list.insert(list.begin(), pcard);
else
list.push_back(pcard);
reset_sequence(target_player, LOCATION_DECK);
message->write(pcard->get_info_location());
message->write<uint32>(pcard->current.reason);
}
if(count > 0) {
if(core.global_flag & GLOBALFLAG_DECK_REVERSE_CHECK) {
card* ptop = list.back();
if(core.deck_reversed || (ptop->current.position == POS_FACEUP_DEFENSE)) {
auto message = pduel->new_message(MSG_DECK_TOP);
message->write<uint8>(target_player);
message->write<uint32>(0);
message->write<uint32>(ptop->data.code);
message->write<uint32>(ptop->current.position);
}
}
}
}
core.units.pop_front();
}
return PROCESSOR_FLAG_CONTINUE;
}
case PROCESSOR_REMOVE_OVERLAY: {
if(remove_overlay_card(it->step, it->arg3, it->ptarget, it->arg1 >> 16,
(it->arg1 >> 8) & 0xff, it->arg1 & 0xff, it->arg2 & 0xffff, it->arg2 >> 16)) {
core.units.pop_front();
} else {
it->step++;
}
return PROCESSOR_FLAG_CONTINUE;
}
}
return PROCESSOR_FLAG_CONTINUE;
}
int32 field::execute_cost(uint16 step, effect* triggering_effect, uint8 triggering_player) {
if(!triggering_effect->cost) {
core.solving_event.splice(core.solving_event.begin(), core.sub_solving_event);
pduel->lua->params.clear();
return TRUE;
}
if (step == 0) {
core.solving_event.splice(core.solving_event.begin(), core.sub_solving_event);
const tevent& e = core.solving_event.front();
pduel->lua->add_param(1, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.reason_player, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.reason, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.reason_effect , PARAM_TYPE_EFFECT, true);
pduel->lua->add_param(e.event_value, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.event_player, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.event_cards , PARAM_TYPE_GROUP, true);
pduel->lua->add_param(triggering_player, PARAM_TYPE_INT, true);
pduel->lua->add_param(triggering_effect, PARAM_TYPE_EFFECT, true);
if(core.check_level == 0) {
core.shuffle_deck_check[0] = FALSE;
core.shuffle_deck_check[1] = FALSE;
core.shuffle_hand_check[0] = FALSE;
core.shuffle_hand_check[1] = FALSE;
}
core.units.begin()->arg2 = core.shuffle_check_disabled;
core.shuffle_check_disabled = FALSE;
core.check_level++;
}
core.reason_effect = triggering_effect;
core.reason_player = triggering_player;
uint32 count = pduel->lua->params.size();
uint32 yield_value = 0;
int32 result = pduel->lua->call_coroutine(triggering_effect->cost, count, &yield_value, step);
returns.at<int32>(0) = yield_value;
if (result != COROUTINE_YIELD) {
core.reason_effect = 0;
core.reason_player = PLAYER_NONE;
core.check_level--;
if(core.check_level == 0) {
if(core.shuffle_hand_check[0])
shuffle(0, LOCATION_HAND);
if(core.shuffle_hand_check[1])
shuffle(1, LOCATION_HAND);
if(core.shuffle_deck_check[0])
shuffle(0, LOCATION_DECK);
if(core.shuffle_deck_check[1])
shuffle(1, LOCATION_DECK);
}
core.shuffle_check_disabled = core.units.begin()->arg2;
return TRUE;
}
return FALSE;
}
int32 field::execute_operation(uint16 step, effect* triggering_effect, uint8 triggering_player) {
if(!triggering_effect->operation) {
core.solving_event.splice(core.solving_event.begin(), core.sub_solving_event);
pduel->lua->params.clear();
return TRUE;
}
if (step == 0) {
core.solving_event.splice(core.solving_event.begin(), core.sub_solving_event);
const tevent& e = core.solving_event.front();
pduel->lua->add_param(e.reason_player, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.reason, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.reason_effect , PARAM_TYPE_EFFECT, true);
pduel->lua->add_param(e.event_value, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.event_player, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.event_cards , PARAM_TYPE_GROUP, true);
pduel->lua->add_param(triggering_player, PARAM_TYPE_INT, true);
pduel->lua->add_param(triggering_effect, PARAM_TYPE_EFFECT, true);
if(core.check_level == 0) {
core.shuffle_deck_check[0] = FALSE;
core.shuffle_deck_check[1] = FALSE;
core.shuffle_hand_check[0] = FALSE;
core.shuffle_hand_check[1] = FALSE;
}
core.units.begin()->arg2 = core.shuffle_check_disabled;
core.shuffle_check_disabled = FALSE;
core.check_level++;
}
core.reason_effect = triggering_effect;
core.reason_player = triggering_player;
uint32 count = pduel->lua->params.size();
uint32 yield_value = 0;
int32 result = pduel->lua->call_coroutine(triggering_effect->operation, count, &yield_value, step);
returns.at<int32>(0) = yield_value;
if (result != COROUTINE_YIELD) {
core.reason_effect = 0;
core.reason_player = PLAYER_NONE;
core.check_level--;
if(core.check_level == 0) {
if(core.shuffle_hand_check[0])
shuffle(0, LOCATION_HAND);
if(core.shuffle_hand_check[1])
shuffle(1, LOCATION_HAND);
if(core.shuffle_deck_check[0])
shuffle(0, LOCATION_DECK);
if(core.shuffle_deck_check[1])
shuffle(1, LOCATION_DECK);
//cost[0].count = 0;
//cost[1].count = 0;
//cost[0].amount = 0;
//cost[1].amount = 0;
}
core.shuffle_check_disabled = core.units.begin()->arg2;
return TRUE;
}
return FALSE;
}
int32 field::execute_target(uint16 step, effect* triggering_effect, uint8 triggering_player) {
if(!triggering_effect->target) {
core.solving_event.splice(core.solving_event.begin(), core.sub_solving_event);
pduel->lua->params.clear();
return TRUE;
}
if (step == 0) {
core.solving_event.splice(core.solving_event.begin(), core.sub_solving_event);
const tevent& e = core.solving_event.front();
pduel->lua->add_param(1, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.reason_player, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.reason, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.reason_effect , PARAM_TYPE_EFFECT, true);
pduel->lua->add_param(e.event_value, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.event_player, PARAM_TYPE_INT, true);
pduel->lua->add_param(e.event_cards , PARAM_TYPE_GROUP, true);
pduel->lua->add_param(triggering_player, PARAM_TYPE_INT, true);
pduel->lua->add_param(triggering_effect, PARAM_TYPE_EFFECT, true);
if(core.check_level == 0) {
core.shuffle_deck_check[0] = FALSE;
core.shuffle_deck_check[1] = FALSE;
core.shuffle_hand_check[0] = FALSE;
core.shuffle_hand_check[1] = FALSE;
}
core.units.begin()->arg2 = core.shuffle_check_disabled;
core.shuffle_check_disabled = FALSE;
core.check_level++;
}
core.reason_effect = triggering_effect;
core.reason_player = triggering_player;
uint32 count = pduel->lua->params.size();
uint32 yield_value = 0;
int32 result = pduel->lua->call_coroutine(triggering_effect->target, count, &yield_value, step);
returns.at<int32>(0) = yield_value;
if (result != COROUTINE_YIELD) {
core.reason_effect = 0;
core.reason_player = PLAYER_NONE;
core.check_level--;
if(core.check_level == 0) {
if(core.shuffle_hand_check[0])
shuffle(0, LOCATION_HAND);
if(core.shuffle_hand_check[1])
shuffle(1, LOCATION_HAND);
if(core.shuffle_deck_check[0])
shuffle(0, LOCATION_DECK);
if(core.shuffle_deck_check[1])
shuffle(1, LOCATION_DECK);
}
core.shuffle_check_disabled = core.units.begin()->arg2;
return TRUE;
}
return FALSE;
}
void field::raise_event(card* event_card, uint32 event_code, effect* reason_effect, uint32 reason, uint8 reason_player, uint8 event_player, uint32 event_value) {
tevent new_event;
new_event.trigger_card = 0;
if (event_card) {
group* pgroup = pduel->new_group(event_card);
pgroup->is_readonly = TRUE;
new_event.event_cards = pgroup;
} else
new_event.event_cards = 0;
new_event.event_code = event_code;
new_event.reason_effect = reason_effect;
new_event.reason = reason;
new_event.reason_player = reason_player;
new_event.event_player = event_player;
new_event.event_value = event_value;
new_event.global_id = infos.event_id;
core.queue_event.push_back(new_event);
}
void field::raise_event(card_set* event_cards, uint32 event_code, effect* reason_effect, uint32 reason, uint8 reason_player, uint8 event_player, uint32 event_value) {
tevent new_event;
new_event.trigger_card = 0;
if (event_cards) {
group* pgroup = pduel->new_group(*event_cards);
pgroup->is_readonly = TRUE;
new_event.event_cards = pgroup;
} else
new_event.event_cards = 0;
new_event.event_code = event_code;
new_event.reason_effect = reason_effect;
new_event.reason = reason;
new_event.reason_player = reason_player;
new_event.event_player = event_player;
new_event.event_value = event_value;
new_event.global_id = infos.event_id;
core.queue_event.push_back(new_event);
}
void field::raise_single_event(card* trigger_card, card_set* event_cards, uint32 event_code, effect* reason_effect, uint32 reason, uint8 reason_player, uint8 event_player, uint32 event_value) {
tevent new_event;
new_event.trigger_card = trigger_card;
if (event_cards) {
group* pgroup = pduel->new_group(*event_cards);
pgroup->is_readonly = TRUE;
new_event.event_cards = pgroup;
} else
new_event.event_cards = 0;
new_event.event_code = event_code;
new_event.reason_effect = reason_effect;
new_event.reason = reason;
new_event.reason_player = reason_player;
new_event.event_player = event_player;
new_event.event_value = event_value;
new_event.global_id = infos.event_id;
core.single_event.push_back(new_event);
}
int32 field::check_event(uint32 code, tevent* pe) {
for(const auto& ev : core.point_event) {
if(ev.event_code == code) {
if(pe)
*pe = ev;
return TRUE;
}
}
for(const auto& ev : core.instant_event) {
if(ev.event_code == code) {
if(pe)
*pe = ev;
return TRUE;
}
}
return FALSE;
}
int32 field::check_event_c(effect* peffect, uint8 playerid, int32 neglect_con, int32 neglect_cost, int32 copy_info, tevent* pe) {
if(peffect->code == EVENT_FREE_CHAIN) {
return peffect->is_activate_ready(core.reason_effect, playerid, nil_event, neglect_con, neglect_cost, FALSE);
}
for(const auto& ev : core.point_event) {
if(ev.event_code == peffect->code &&
peffect->is_activate_ready(core.reason_effect, playerid, ev, neglect_con, neglect_cost, FALSE)) {
if(pe)
*pe = ev;
if(copy_info && !pduel->lua->no_action && core.current_chain.size()) {
core.current_chain.back().evt = ev;
}
return TRUE;
}
}
for(const auto& ev : core.instant_event) {
if(ev.event_code == peffect->code &&
peffect->is_activate_ready(core.reason_effect, playerid, ev, neglect_con, neglect_cost, FALSE)) {
if(pe)
*pe = ev;
if(copy_info && !pduel->lua->no_action && core.current_chain.size()) {
core.current_chain.back().evt = ev;
}
return TRUE;
}
}
return FALSE;
}
int32 field::check_hint_timing(effect* peffect) {
int32 p = peffect->get_handler_player();
if(p == 0)
return (peffect->hint_timing[0] & core.hint_timing[0]) || (peffect->hint_timing[1] & core.hint_timing[1]);
else
return (peffect->hint_timing[0] & core.hint_timing[1]) || (peffect->hint_timing[1] & core.hint_timing[0]);
}
// core.spe_effect[p]: # of optional trigger effects, activate/quick effect with hints
int32 field::process_phase_event(int16 step, int32 phase) {
switch(step) {
case 0: {
if((phase == PHASE_DRAW && (core.force_turn_end || is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_DP)))
|| (phase == PHASE_STANDBY && (core.force_turn_end || is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_SP)))
|| (phase == PHASE_BATTLE_START && (core.force_turn_end || is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_BP)))
|| (phase == PHASE_BATTLE && (core.force_turn_end || is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_BP)))
|| (phase == PHASE_END && (core.force_turn_end || is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_EP)))) {
core.units.begin()->step = 24;
return FALSE;
}
int32 phase_event = EVENT_PHASE + phase;
nil_event.event_code = phase_event;
nil_event.event_player = infos.turn_player;
int32 check_player = infos.turn_player;
if(core.units.begin()->arg2 & 0x2)
check_player = 1 - infos.turn_player;
chain newchain;
core.select_chains.clear();
int32 tf_count = 0, to_count = 0, fc_count = 0, cn_count = 0;
auto pr = effects.trigger_f_effect.equal_range(phase_event);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
peffect->set_activate_location();
if(!peffect->is_activateable(check_player, nil_event))
continue;
peffect->id = infos.field_id++;
newchain.triggering_effect = peffect;
core.select_chains.push_back(newchain);
tf_count++;
}
pr = effects.continuous_effect.equal_range(phase_event);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
//effects.continuous_effect may be changed in is_activateable (e.g. Rescue Cat)
if(peffect->get_handler_player() != check_player || !peffect->is_activateable(check_player, nil_event))
continue;
peffect->id = infos.field_id++;
newchain.triggering_effect = peffect;
core.select_chains.push_back(newchain);
cn_count++;
}
//all effects taking control non-permanently are only until End Phase, not until Turn end
for(auto* peffect : effects.pheff) {
if(peffect->code != EFFECT_SET_CONTROL)
continue;
if(!(peffect->reset_flag & phase))
continue;
uint8 pid = peffect->get_handler_player();
if(pid != check_player)
continue;
uint8 tp = infos.turn_player;
if(!(((peffect->reset_flag & RESET_SELF_TURN) && pid == tp) || ((peffect->reset_flag & RESET_OPPO_TURN) && pid != tp)))
continue;
if(peffect->reset_count != 1)
continue;
card* phandler = peffect->get_handler();
if(peffect->get_value(phandler) != phandler->current.controler)
continue;
newchain.triggering_effect = peffect;
core.select_chains.push_back(newchain);
cn_count++;
}
core.spe_effect[check_player] = 0;
if(!core.hand_adjusted) {
pr = effects.trigger_o_effect.equal_range(phase_event);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
peffect->set_activate_location();
if(!peffect->is_activateable(check_player, nil_event))
continue;
peffect->id = infos.field_id++;
newchain.triggering_effect = peffect;
core.select_chains.push_back(newchain);
to_count++;
core.spe_effect[check_player]++;
}
if(phase == PHASE_DRAW)
core.hint_timing[infos.turn_player] = TIMING_DRAW_PHASE;
else if(phase == PHASE_STANDBY)
core.hint_timing[infos.turn_player] = TIMING_STANDBY_PHASE;
else if(phase == PHASE_BATTLE_START)
core.hint_timing[infos.turn_player] = TIMING_BATTLE_START;
else if(phase == PHASE_BATTLE)
core.hint_timing[infos.turn_player] = TIMING_BATTLE_END;
else
core.hint_timing[infos.turn_player] = TIMING_END_PHASE;
pr = effects.activate_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
peffect->set_activate_location();
if(!peffect->is_chainable(check_player) || !peffect->is_activateable(check_player, nil_event))
continue;
peffect->id = infos.field_id++;
newchain.triggering_effect = peffect;
if(check_hint_timing(peffect) || check_cteffect_hint(peffect, check_player))
core.spe_effect[check_player]++;
core.select_chains.push_back(newchain);
fc_count++;
}
pr = effects.quick_o_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
peffect->set_activate_location();
if(!peffect->is_chainable(check_player) || !peffect->is_activateable(check_player, nil_event))
continue;
peffect->id = infos.field_id++;
newchain.triggering_effect = peffect;
if(check_hint_timing(peffect))
core.spe_effect[check_player]++;
core.select_chains.push_back(newchain);
fc_count++;
}
pr = effects.continuous_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
if(peffect->get_handler_player() != check_player || !peffect->is_activateable(check_player, nil_event))
continue;
peffect->id = infos.field_id++;
newchain.triggering_effect = peffect;
core.select_chains.push_back(newchain);
fc_count++;
}
}
if(core.select_chains.size() == 0) {
returns.at<int32>(0) = -1;
core.units.begin()->step = 1;
return FALSE;
} else if(tf_count == 0 && cn_count == 1 && to_count == 0 && fc_count == 0) {
returns.at<int32>(0) = 0;
core.units.begin()->step = 1;
return FALSE;
} else {
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(check_player);
if(infos.phase == PHASE_DRAW)
message->write<uint64>(20);
else if(infos.phase == PHASE_STANDBY)
message->write<uint64>(21);
else if(infos.phase == PHASE_BATTLE_START)
message->write<uint64>(28);
else if(infos.phase == PHASE_BATTLE)
message->write<uint64>(25);
else
message->write<uint64>(26);
if(tf_count == 0 && to_count == 1 && fc_count == 0 && cn_count == 0) {
add_process(PROCESSOR_SELECT_EFFECTYN, 0, 0, (group*)core.select_chains[0].triggering_effect->get_handler(), check_player, 0);
return FALSE;
} else {
add_process(PROCESSOR_SELECT_CHAIN, 0, 0, 0, check_player, core.spe_effect[check_player] | (tf_count + cn_count ? 0x10000 : 0));
core.units.begin()->step = 1;
return FALSE;
}
}
return FALSE;
}
case 1: {
returns.at<int32>(0)--;
return FALSE;
}
case 2: {
int32 priority_passed = core.units.begin()->arg2 & 0x1;
int32 is_opponent = core.units.begin()->arg2 & 0x2;
if(returns.at<int32>(0) == -1) {
if(priority_passed)
core.units.begin()->step = 19;
else {
priority_passed = 1;
is_opponent ^= 0x2;
core.units.begin()->arg2 = is_opponent | priority_passed;
core.units.begin()->step = -1;
}
return FALSE;
}
priority_passed = 0;
core.units.begin()->arg2 = is_opponent | priority_passed;
chain newchain = core.select_chains[returns.at<int32>(0)];
effect* peffect = newchain.triggering_effect;
card* phandler = peffect->get_handler();
if(!(peffect->type & EFFECT_TYPE_ACTIONS)) {
if(peffect->is_flag(EFFECT_FLAG_FIELD_ONLY))
remove_effect(peffect);
else
peffect->handler->remove_effect(peffect);
adjust_all();
core.units.begin()->step = 3;
} else if(!(peffect->type & EFFECT_TYPE_CONTINUOUS)) {
int32 check_player = infos.turn_player;
if(is_opponent)
check_player = 1 - infos.turn_player;
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.evt = nil_event;
newchain.set_triggering_state(phandler);
newchain.triggering_player = check_player;
core.new_chains.push_back(newchain);
phandler->set_status(STATUS_CHAINING, TRUE);
peffect->dec_count(check_player);
core.select_chains.clear();
add_process(PROCESSOR_ADD_CHAIN, 0, 0, 0, 0, 0);
if(is_flag(DUEL_INVERTED_QUICK_PRIORITY))
add_process(PROCESSOR_QUICK_EFFECT, 0, 0, 0, FALSE, check_player);
else
add_process(PROCESSOR_QUICK_EFFECT, 0, 0, 0, FALSE, 1 - check_player);
infos.priorities[0] = 0;
infos.priorities[1] = 0;
} else {
core.select_chains.clear();
solve_continuous(peffect->get_handler_player(), peffect, nil_event);
core.units.begin()->step = 3;
}
return FALSE;
}
case 3: {
core.chain_limit.clear();
for(auto& ch : core.current_chain)
ch.triggering_effect->get_handler()->set_status(STATUS_CHAINING, FALSE);
add_process(PROCESSOR_SOLVE_CHAIN, 0, 0, 0, FALSE, 0);
core.units.begin()->step = -1;
return FALSE;
}
case 4: {
adjust_instant();
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, 0);
core.units.begin()->step = -1;
return FALSE;
}
case 20: {
if(phase != PHASE_END) {
core.units.begin()->step = 24;
return FALSE;
}
int32 limit = 6;
effect_set eset;
filter_player_effect(infos.turn_player, EFFECT_HAND_LIMIT, &eset);
if(eset.size())
limit = eset.back()->get_value();
int32 hd = player[infos.turn_player].list_hand.size();
if(hd <= limit || is_flag(DUEL_NO_HAND_LIMIT)) {
core.units.begin()->step = 24;
return FALSE;
}
core.select_cards.clear();
for(auto& pcard : player[infos.turn_player].list_hand)
core.select_cards.push_back(pcard);
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_SELECTMSG);
message->write<uint8>(infos.turn_player);
message->write<uint64>(501);
add_process(PROCESSOR_SELECT_CARD, 0, 0, 0, infos.turn_player, hd - limit + ((hd - limit) << 16));
return FALSE;
}
case 21: {
card_set cset(return_cards.list.begin(), return_cards.list.end());
send_to(&cset, 0, REASON_RULE + REASON_DISCARD + REASON_ADJUST, infos.turn_player, PLAYER_NONE, LOCATION_GRAVE, 0, POS_FACEUP);
return FALSE;
}
case 22: {
core.hand_adjusted = TRUE;
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, 0);
core.units.begin()->step = -1;
core.units.begin()->arg2 = 0;
return FALSE;
}
case 25: {
core.hint_timing[infos.turn_player] = 0;
reset_phase(phase);
adjust_all();
return FALSE;
}
case 26: {
core.quick_f_chain.clear();
core.instant_event.clear();
core.point_event.clear();
core.delayed_activate_event.clear();
core.full_event.clear();
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
}
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
// core.ignition_priority_chains: used in step 8 (obsolete ignition effect ruling)
int32 field::process_point_event(int16 step, int32 skip_trigger, int32 skip_freechain, int32 skip_new) {
switch(step) {
case 0: {
core.select_chains.clear();
core.point_event.splice(core.point_event.end(), core.instant_event);
if(skip_trigger) {
core.units.begin()->step = 7;
return FALSE;
}
core.new_fchain_s.splice(core.new_fchain_s.begin(), core.new_fchain);
core.new_ochain_s.splice(core.new_ochain_s.begin(), core.new_ochain);
core.full_event.splice(core.full_event.end(), core.delayed_activate_event);
core.delayed_quick.clear();
core.delayed_quick_tmp.swap(core.delayed_quick);
core.current_player = infos.turn_player;
core.units.begin()->step = 1;
return FALSE;
}
case 1: {
return FALSE;
}
case 2: {
//forced trigger
core.select_chains.clear();
for (auto clit = core.new_fchain_s.begin(); clit != core.new_fchain_s.end(); ) {
effect* peffect = clit->triggering_effect;
card* phandler = peffect->get_handler();
if(phandler->is_has_relation(*clit)) //work around: position and control should be refreshed before raising event
clit->set_triggering_state(phandler);
uint8 tp = clit->triggering_player;
if((!clit->was_just_sent || phandler->current.location == LOCATION_HAND)
&& check_trigger_effect(*clit)
&& peffect->is_chainable(tp)
&& peffect->is_activateable(tp, clit->evt, TRUE, FALSE, FALSE, is_flag(DUEL_TRIGGER_WHEN_PRIVATE_KNOWLEDGE), is_flag(DUEL_TRIGGER_WHEN_PRIVATE_KNOWLEDGE))) {
if(tp == core.current_player)
core.select_chains.push_back(*clit);
} else {
peffect->active_type = 0;
core.new_fchain_s.erase(clit++);
continue;
}
++clit;
}
//TCG SEGOC
if(core.select_chains.size() == 0) {
returns.at<int32>(0) = -1;
} else {
if(is_flag(DUEL_TCG_SEGOC_FIRSTTRIGGER)) { //tcg segoc
std::sort(core.select_chains.begin(), core.select_chains.end(), [](const chain& c1, const chain& c2) {return c1.event_id < c2.event_id; });
auto pred = [id = core.select_chains.front().event_id](const chain& ch) {
return ch.event_id == id;
};
auto endit = std::find_if_not(core.select_chains.begin(), core.select_chains.end(), pred);
core.select_chains.erase(endit, core.select_chains.end());
}
if(core.select_chains.size() == 1) {
returns.at<int32>(0) = 0;
} else {
add_process(PROCESSOR_SELECT_CHAIN, 0, 0, 0, core.current_player, 0x7f | 0x10000);
}
}
return FALSE;
}
case 3: {
if(returns.at<int32>(0) == -1) {
if(core.new_fchain_s.size()) {
core.current_player = 1 - infos.turn_player;
core.units.begin()->step = 1;
} else {
core.current_player = infos.turn_player;
}
return FALSE;
}
chain newchain = core.select_chains[returns.at<int32>(0)];
effect* peffect = newchain.triggering_effect;
uint8 tp = newchain.triggering_player;
peffect->get_handler()->set_status(STATUS_CHAINING, TRUE);
peffect->dec_count(tp);
core.new_chains.push_back(newchain);
add_process(PROCESSOR_ADD_CHAIN, 0, 0, 0, 0, 0);
core.new_fchain_s.remove_if([chain_id = newchain.chain_id](chain ch) { return ch.chain_id == chain_id; });
core.units.begin()->step = 1;
return FALSE;
}
case 4: {
//optional trigger
core.select_chains.clear();
for (auto clit = core.new_ochain_s.begin(); clit != core.new_ochain_s.end(); ) {
effect* peffect = clit->triggering_effect;
card* phandler = peffect->get_handler();
if(phandler->is_has_relation(*clit)) //work around: position and control should be refreshed before raising event
clit->set_triggering_state(phandler);
if(!peffect->is_flag(EFFECT_FLAG_FIELD_ONLY) && (peffect->type & EFFECT_TYPE_FIELD)
&& (peffect->range & LOCATION_HAND) && phandler->current.location == LOCATION_HAND) {
if(!phandler->is_has_relation(*clit) && peffect->is_condition_check(phandler->current.controler, clit->evt))
phandler->create_relation(*clit);
peffect->set_activate_location();
clit->triggering_player = phandler->current.controler;
clit->set_triggering_state(phandler);
}
uint8 tp = clit->triggering_player;
if((!clit->was_just_sent || phandler->current.location == LOCATION_HAND)
&& (is_flag(DUEL_TRIGGER_WHEN_PRIVATE_KNOWLEDGE) || check_nonpublic_trigger(*clit))
&& check_trigger_effect(*clit)
&& peffect->is_chainable(tp)
&& peffect->is_activateable(tp, clit->evt, TRUE, FALSE, FALSE, is_flag(DUEL_TRIGGER_WHEN_PRIVATE_KNOWLEDGE), is_flag(DUEL_TRIGGER_WHEN_PRIVATE_KNOWLEDGE))
&& check_spself_from_hand_trigger(*clit)) {
if(tp == core.current_player)
core.select_chains.push_back(*clit);
} else {
peffect->active_type = 0;
core.new_ochain_s.erase(clit++);
continue;
}
++clit;
}
//TCG SEGOC
if(core.select_chains.size() == 0) {
returns.at<int32>(0) = -2;
core.units.begin()->step = 5;
return FALSE;
} else {
if(is_flag(DUEL_TCG_SEGOC_NONPUBLIC))
core.new_ochain_h.clear();
//tcg segoc
if(is_flag(DUEL_TCG_SEGOC_FIRSTTRIGGER)) {
std::sort(core.select_chains.begin(), core.select_chains.end(), [](const chain& c1, const chain& c2) {return c1.event_id < c2.event_id; });
auto pred = [id = core.select_chains.front().event_id](const chain& ch) {
return ch.event_id == id;
};
auto endit = std::find_if_not(core.select_chains.begin(), core.select_chains.end(), pred);
core.select_chains.erase(endit, core.select_chains.end());
}
if(core.select_chains.size() == 1 && !core.current_chain.size()) {
add_process(PROCESSOR_SELECT_EFFECTYN, 0, 0, (group*)core.select_chains[0].triggering_effect->get_handler(), core.current_player, 221);
return FALSE;
} else {
add_process(PROCESSOR_SELECT_CHAIN, 0, 0, 0, core.current_player, 0x7f);
core.units.begin()->step = 5;
return FALSE;
}
}
return FALSE;
}
case 5: {
returns.at<int32>(0)--;
return FALSE;
}
case 6: {
if(returns.at<int32>(0) == -2 || (returns.at<int32>(0) == -1 && !is_flag(DUEL_TCG_SEGOC_FIRSTTRIGGER))) {
for(const auto& ch : core.select_chains) {
ch.triggering_effect->active_type = 0;
core.new_ochain_s.remove_if([chain_id = ch.chain_id](chain ch) { return ch.chain_id == chain_id; });
}
if(core.new_ochain_s.size()) {
core.current_player = 1 - infos.turn_player;
core.units.begin()->step = 3;
} else {
core.current_player = infos.turn_player;
core.units.begin()->step = 6;
}
return FALSE;
} else if(returns.at<int32>(0) == -1) {
//TCG SEGOC
chain discardedchain = core.select_chains[0];
core.new_ochain_s.remove_if([event_id = discardedchain.event_id](chain ch) { return ch.event_id == event_id; });
core.units.begin()->step = 3;
return FALSE;
}
chain newchain = core.select_chains[returns.at<int32>(0)];
effect* peffect = newchain.triggering_effect;
uint8 tp = newchain.triggering_player;
peffect->get_handler()->set_status(STATUS_CHAINING, TRUE);
peffect->dec_count(tp);
core.new_chains.push_back(newchain);
add_process(PROCESSOR_ADD_CHAIN, 0, 0, 0, 0, 0);
core.new_ochain_s.remove_if([chain_id = newchain.chain_id](chain ch) { return ch.chain_id == chain_id; });
core.new_ochain_h.remove_if([chain_id = newchain.chain_id](chain ch) { return ch.chain_id == chain_id; });
core.units.begin()->step = 3;
return FALSE;
}
case 7: {
core.select_chains.clear();
return FALSE;
}
case 8: {
if(!is_flag(DUEL_OBSOLETE_IGNITION) || (infos.phase != PHASE_MAIN1 && infos.phase != PHASE_MAIN2))
return FALSE;
// Obsolete ignition effect ruling
tevent _e;
if(core.current_chain.size() == 0 &&
(check_event(EVENT_SUMMON_SUCCESS, &_e) || check_event(EVENT_SPSUMMON_SUCCESS, &_e) || check_event(EVENT_FLIP_SUMMON_SUCCESS, &_e)
|| check_event(EVENT_CHAIN_END, &_e)) && _e.reason_player == infos.turn_player) {
chain newchain;
tevent e;
e.event_cards = 0;
e.event_value = 0;
e.event_player = PLAYER_NONE;
e.reason_effect = 0;
e.reason = 0;
e.reason_player = PLAYER_NONE;
for(auto eit = effects.ignition_effect.begin(); eit != effects.ignition_effect.end();) {
effect* peffect = eit->second;
++eit;
card* phandler = peffect->get_handler();
e.event_code = peffect->code;
if(phandler->current.location == LOCATION_MZONE && peffect->is_chainable(infos.turn_player)
&& peffect->is_activateable(infos.turn_player, e)) {
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.evt = e;
newchain.triggering_effect = peffect;
newchain.set_triggering_state(phandler);
newchain.triggering_player = infos.turn_player;
core.ignition_priority_chains.push_back(newchain);
}
}
}
return FALSE;
}
case 9: {
infos.priorities[0] = 0;
infos.priorities[1] = 0;
if(core.current_chain.size() == 0) {
if(!core.hand_adjusted) {
if(is_flag(DUEL_INVERTED_QUICK_PRIORITY))
add_process(PROCESSOR_QUICK_EFFECT, 0, 0, 0, skip_freechain, 1 - infos.turn_player);
else
add_process(PROCESSOR_QUICK_EFFECT, 0, 0, 0, skip_freechain, infos.turn_player);
}
} else
add_process(PROCESSOR_QUICK_EFFECT, 0, 0, 0, skip_freechain, 1 - core.current_chain.back().triggering_player);
return FALSE;
}
case 10: {
core.new_ochain_h.clear();
core.full_event.clear();
core.delayed_quick.clear();
core.chain_limit.clear();
if(core.current_chain.size()) {
for(auto& ch : core.current_chain)
ch.triggering_effect->get_handler()->set_status(STATUS_CHAINING, FALSE);
add_process(PROCESSOR_SOLVE_CHAIN, 0, 0, 0, skip_trigger | ((skip_freechain | skip_new) << 8), skip_new);
} else {
core.used_event.splice(core.used_event.end(), core.point_event);
core.chain_limit_p.clear();
reset_chain();
returns.at<int32>(0) = FALSE;
}
if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}
return TRUE;
}
case 30: {
int32 check_player = infos.turn_player;
nil_event.event_code = EVENT_FREE_CHAIN;
chain newchain;
core.select_chains.clear();
core.spe_effect[check_player] = 0;
auto pr = effects.continuous_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
newchain.triggering_effect = peffect;
if(peffect->get_handler_player() == check_player && peffect->is_activateable(check_player, nil_event)) {
core.select_chains.push_back(newchain);
core.spe_effect[check_player]++;
}
}
if(!core.select_chains.empty())
add_process(PROCESSOR_SELECT_CHAIN, 0, 0, 0, check_player, core.spe_effect[check_player]);
else
core.units.begin()->step = 31;
return FALSE;
}
case 31: {
if(returns.at<int32>(0) == -1)
return FALSE;
const chain& newchain = core.select_chains[returns.at<int32>(0)];
effect* peffect = newchain.triggering_effect;
core.select_chains.clear();
solve_continuous(peffect->get_handler_player(), peffect, nil_event);
core.units.begin()->step = 29;
return FALSE;
}
case 32: {
int32 check_player = 1 - infos.turn_player;
nil_event.event_code = EVENT_FREE_CHAIN;
chain newchain;
core.select_chains.clear();
core.spe_effect[check_player] = 0;
auto pr = effects.continuous_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
newchain.triggering_effect = peffect;
if(peffect->get_handler_player() == check_player && peffect->is_activateable(check_player, nil_event)) {
core.select_chains.push_back(newchain);
core.spe_effect[check_player]++;
}
}
if(!core.select_chains.empty())
add_process(PROCESSOR_SELECT_CHAIN, 0, 0, 0, check_player, core.spe_effect[check_player]);
else
core.units.begin()->step = -1;
return FALSE;
}
case 33: {
if(returns.at<int32>(0) == -1) {
core.units.begin()->step = -1;
return FALSE;
}
const chain& newchain = core.select_chains[returns.at<int32>(0)];
effect* peffect = newchain.triggering_effect;
core.select_chains.clear();
solve_continuous(peffect->get_handler_player(), peffect, nil_event);
core.units.begin()->step = 31;
return FALSE;
}
}
if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}
return TRUE;
}
int32 field::process_quick_effect(int16 step, int32 skip_freechain, uint8 priority) {
switch(step) {
case 0: {
uint8 check_player = infos.turn_player;
if(core.units.begin()->arg3)
check_player = 1 - infos.turn_player;
core.select_chains.clear();
for(auto ifit = core.quick_f_chain.begin(); ifit != core.quick_f_chain.end(); ) {
effect* peffect = ifit->first;
card* phandler = peffect->get_handler();
if(peffect->is_chainable(ifit->second.triggering_player) && peffect->check_count_limit(ifit->second.triggering_player)
&& phandler->is_has_relation(ifit->second)) {
if(ifit->second.triggering_player == check_player)
core.select_chains.push_back(ifit->second);
} else {
core.quick_f_chain.erase(ifit++);
continue;
}
++ifit;
}
if(core.select_chains.size() == 0)
returns.at<int32>(0) = -1;
else if(core.select_chains.size() == 1)
returns.at<int32>(0) = 0;
else
add_process(PROCESSOR_SELECT_CHAIN, 0, 0, 0, check_player, 0x10000);
return FALSE;
}
case 1: {
if(returns.at<int32>(0) == -1) {
if(core.quick_f_chain.size()) {
core.units.begin()->arg3 = TRUE;
core.units.begin()->step = -1;
} else if(core.new_chains.size()) {
add_process(PROCESSOR_ADD_CHAIN, 0, 0, 0, 0, 0);
add_process(PROCESSOR_QUICK_EFFECT, 0, 0, 0, FALSE, 1 - core.new_chains.back().triggering_player);
infos.priorities[0] = 0;
infos.priorities[1] = 0;
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
return FALSE;
}
chain newchain = core.select_chains[returns.at<int32>(0)];
effect* peffect = newchain.triggering_effect;
uint8 tp = newchain.triggering_player;
peffect->get_handler()->set_status(STATUS_CHAINING, TRUE);
peffect->dec_count(tp);
core.new_chains.push_back(newchain);
core.quick_f_chain.erase(peffect);
core.units.begin()->step = -1;
return FALSE;
}
case 2: {
chain newchain;
if(core.ignition_priority_chains.size())
core.select_chains.swap(core.ignition_priority_chains);
for(auto& event : { &core.point_event , &core.instant_event }) {
for(auto evit = event->begin(); evit != event->end(); ++evit) {
auto pr = effects.activate_effect.equal_range(evit->event_code);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
peffect->set_activate_location();
if(!peffect->is_flag(EFFECT_FLAG_DELAY) && peffect->is_chainable(priority) && peffect->is_activateable(priority, *evit)) {
card* phandler = peffect->get_handler();
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.evt = *evit;
newchain.triggering_effect = peffect;
newchain.set_triggering_state(phandler);
newchain.triggering_player = priority;
core.select_chains.push_back(newchain);
}
}
pr = effects.quick_o_effect.equal_range(evit->event_code);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
peffect->set_activate_location();
if(!peffect->is_flag(EFFECT_FLAG_DELAY) && peffect->is_chainable(priority) && peffect->is_activateable(priority, *evit)) {
card* phandler = peffect->get_handler();
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.evt = *evit;
newchain.triggering_effect = peffect;
newchain.set_triggering_state(phandler);
newchain.triggering_player = priority;
core.select_chains.push_back(newchain);
}
}
}
}
for(auto& ch : core.new_ochain_h) {
effect* peffect = ch.triggering_effect;
card* phandler = peffect->get_handler();
if(!peffect->is_flag(EFFECT_FLAG_FIELD_ONLY) && (peffect->type & EFFECT_TYPE_FIELD)
&& (peffect->range & LOCATION_HAND) && phandler->current.location == LOCATION_HAND) {
if(!phandler->is_has_relation(ch) && peffect->is_condition_check(phandler->current.controler, ch.evt))
phandler->create_relation(ch);
peffect->set_activate_location();
ch.triggering_player = phandler->current.controler;
ch.set_triggering_state(phandler);
}
if(ch.triggering_player == priority && !phandler->is_status(STATUS_CHAINING)
&& ((ch.triggering_location == LOCATION_HAND && phandler->is_position(POS_FACEDOWN)) || ch.triggering_location == LOCATION_DECK)
&& phandler->is_has_relation(ch) && peffect->is_chainable(priority) && peffect->is_activateable(priority, ch.evt, TRUE)
&& check_spself_from_hand_trigger(ch))
core.select_chains.push_back(ch);
}
//delayed activate
for(const auto& ev : core.full_event) {
auto pr = effects.activate_effect.equal_range(ev.event_code);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
peffect->set_activate_location();
if(peffect->is_flag(EFFECT_FLAG_DELAY) && peffect->is_chainable(priority) && peffect->is_activateable(priority, ev)) {
card* phandler = peffect->get_handler();
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.evt = ev;
newchain.triggering_effect = peffect;
newchain.set_triggering_state(phandler);
newchain.triggering_player = priority;
core.select_chains.push_back(newchain);
}
}
}
// delayed quick
for(auto eit = core.delayed_quick.begin(); eit != core.delayed_quick.end();) {
effect* peffect = eit->first;
const tevent& evt = eit->second;
++eit;
peffect->set_activate_location();
if(peffect->is_chainable(priority) && peffect->is_activateable(priority, evt, TRUE, FALSE, FALSE)) {
card* phandler = peffect->get_handler();
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.evt = evt;
newchain.triggering_effect = peffect;
newchain.set_triggering_state(phandler);
newchain.triggering_player = priority;
core.select_chains.push_back(newchain);
}
}
core.spe_effect[priority] = core.select_chains.size();
if(!skip_freechain) {
nil_event.event_code = EVENT_FREE_CHAIN;
auto pr = effects.activate_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
peffect->set_activate_location();
if(peffect->is_chainable(priority) && peffect->is_activateable(priority, nil_event)) {
card* phandler = peffect->get_handler();
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.evt = nil_event;
newchain.triggering_effect = peffect;
newchain.set_triggering_state(phandler);
newchain.triggering_player = priority;
core.select_chains.push_back(newchain);
if(check_hint_timing(peffect) || check_cteffect_hint(peffect, priority))
core.spe_effect[priority]++;
}
}
pr = effects.quick_o_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
peffect->set_activate_location();
if(peffect->is_chainable(priority) && peffect->is_activateable(priority, nil_event)) {
card* phandler = peffect->get_handler();
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.evt = nil_event;
newchain.triggering_effect = peffect;
newchain.set_triggering_state(phandler);
newchain.triggering_player = priority;
core.select_chains.push_back(newchain);
if(check_hint_timing(peffect))
core.spe_effect[priority]++;
}
}
}
if(core.current_chain.size() || (core.hint_timing[0] & TIMING_ATTACK) || (core.hint_timing[1] & TIMING_ATTACK))
core.spe_effect[priority] = core.select_chains.size();
add_process(PROCESSOR_SELECT_CHAIN, 0, 0, 0, priority, core.spe_effect[priority]);
return FALSE;
}
case 3: {
if(core.select_chains.size() && returns.at<int32>(0) != -1) {
chain newchain = core.select_chains[returns.at<int32>(0)];
core.new_chains.push_back(newchain);
effect* peffect = newchain.triggering_effect;
core.delayed_quick.erase(std::make_pair(peffect, newchain.evt));
peffect->get_handler()->set_status(STATUS_CHAINING, TRUE);
peffect->dec_count(priority);
add_process(PROCESSOR_ADD_CHAIN, 0, 0, 0, 0, 0);
add_process(PROCESSOR_QUICK_EFFECT, 0, 0, 0, FALSE, 1 - priority);
infos.priorities[0] = 0;
infos.priorities[1] = 0;
} else {
infos.priorities[priority] = 1;
if(!infos.priorities[0] || !infos.priorities[1])
add_process(PROCESSOR_QUICK_EFFECT, 1, 0, 0, skip_freechain, 1 - priority);
else {
core.hint_timing[0] &= TIMING_DAMAGE_STEP | TIMING_DAMAGE_CAL;
core.hint_timing[1] &= TIMING_DAMAGE_STEP | TIMING_DAMAGE_CAL;
}
}
core.select_chains.clear();
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
}
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
int32 field::process_instant_event() {
auto check_simul = [&just_sent=core.just_sent_cards](effect* peffect, card* phandler) {
return (peffect->flag[1] & EFFECT_FLAG2_CHECK_SIMULTANEOUS) != 0 && just_sent.find(phandler) != just_sent.end();
};
if(core.queue_event.size() == 0) {
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return TRUE;
}
chain newchain;
chain_list tp;
chain_list ntp;
for(const auto& ev : core.queue_event) {
//continuous events
auto pr = effects.continuous_effect.equal_range(ev.event_code);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
uint8 owner_player = peffect->get_handler_player();
if(peffect->is_flag(EFFECT_FLAG_EVENT_PLAYER) && (ev.event_player == 0 || ev.event_player == 1))
owner_player = ev.event_player;
if(peffect->is_activateable(owner_player, ev)) {
newchain.chain_id = 0;
newchain.chain_count = 0;
newchain.triggering_effect = peffect;
newchain.triggering_player = owner_player;
newchain.evt = ev;
newchain.target_cards = 0;
newchain.target_player = PLAYER_NONE;
newchain.target_param = 0;
newchain.disable_player = PLAYER_NONE;
newchain.disable_reason = 0;
newchain.flag = 0;
if(peffect->is_flag(EFFECT_FLAG_DELAY) && (core.chain_solving || core.conti_solving)) {
if(owner_player == infos.turn_player)
core.delayed_continuous_tp.push_back(newchain);
else
core.delayed_continuous_ntp.push_back(newchain);
} else {
if(owner_player == infos.turn_player)
tp.push_back(newchain);
else
ntp.push_back(newchain);
}
}
}
if(ev.event_code == EVENT_ADJUST || ev.event_code == EVENT_BREAK_EFFECT || ((ev.event_code & 0xf000) == EVENT_PHASE_START))
continue;
//triggers
pr = effects.trigger_f_effect.equal_range(ev.event_code);
for(auto eit = pr.first; eit != pr.second;) {
newchain.was_just_sent = false;
effect* peffect = eit->second;
++eit;
card* phandler = peffect->get_handler();
if(!phandler->is_status(STATUS_EFFECT_ENABLED) || !peffect->is_condition_check(phandler->current.controler, ev))
continue;
if((newchain.was_just_sent = check_simul(peffect, phandler)) == true && (peffect->range & LOCATION_HAND) == 0)
continue;
peffect->set_activate_location();
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.event_id = ev.global_id;
newchain.evt = ev;
newchain.triggering_effect = peffect;
newchain.set_triggering_state(phandler);
if(peffect->is_flag(EFFECT_FLAG_EVENT_PLAYER) && (ev.event_player == 0 || ev.event_player == 1))
newchain.triggering_player = ev.event_player;
else
newchain.triggering_player = phandler->current.controler;
core.new_fchain.push_back(newchain);
phandler->create_relation(newchain);
}
pr = effects.trigger_o_effect.equal_range(ev.event_code);
for(auto eit = pr.first; eit != pr.second;) {
newchain.was_just_sent = false;
effect* peffect = eit->second;
++eit;
card* phandler = peffect->get_handler();
bool act = phandler->is_status(STATUS_EFFECT_ENABLED) && peffect->is_condition_check(phandler->current.controler, ev);
if((newchain.was_just_sent = check_simul(peffect, phandler)) == true && (peffect->range & LOCATION_HAND) == 0)
continue;
if((peffect->range & LOCATION_HAND) == 0 && !act)
continue;
peffect->set_activate_location();
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.event_id = ev.global_id;
newchain.evt = ev;
newchain.triggering_effect = peffect;
newchain.set_triggering_state(phandler);
if(peffect->is_flag(EFFECT_FLAG_EVENT_PLAYER) && (ev.event_player == 0 || ev.event_player == 1))
newchain.triggering_player = ev.event_player;
else
newchain.triggering_player = phandler->current.controler;
core.new_ochain.push_back(newchain);
if(peffect->is_flag(EFFECT_FLAG_FIELD_ONLY)
|| !(peffect->range & LOCATION_HAND)
|| ((peffect->range & phandler->current.location) && act))
phandler->create_relation(newchain);
}
//instant_f
pr = effects.quick_f_effect.equal_range(ev.event_code);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
card* phandler = peffect->get_handler();
peffect->set_activate_location();
if(peffect->is_activateable(phandler->current.controler, ev)) {
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.evt = ev;
newchain.triggering_effect = peffect;
newchain.set_triggering_state(phandler);
if(peffect->is_flag(EFFECT_FLAG_EVENT_PLAYER) && (ev.event_player == 0 || ev.event_player == 1))
newchain.triggering_player = ev.event_player;
else
newchain.triggering_player = phandler->current.controler;
core.quick_f_chain[peffect] = newchain;
phandler->create_relation(newchain);
}
}
// delayed activate effect
core.delayed_activate_event.push_back(ev);
// delayed quick effect
pr = effects.quick_o_effect.equal_range(ev.event_code);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
if(peffect->is_flag(EFFECT_FLAG_DELAY) && peffect->is_condition_check(peffect->get_handler()->current.controler, ev))
core.delayed_quick_tmp.emplace(peffect, ev);
}
}
while(tp.size()) {
core.sub_solving_continuous.splice(core.sub_solving_continuous.end(), tp, tp.begin());
add_process(PROCESSOR_SOLVE_CONTINUOUS, 0, 0, 0, 0, 0);
}
while(ntp.size()) {
core.sub_solving_continuous.splice(core.sub_solving_continuous.end(), ntp, ntp.begin());
add_process(PROCESSOR_SOLVE_CONTINUOUS, 0, 0, 0, 0, 0);
}
core.instant_event.splice(core.instant_event.end(), core.queue_event);
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
int32 field::process_single_event() {
if(core.single_event.size() == 0) {
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
chain_list tp;
chain_list ntp;
for(const auto& ev : core.single_event) {
card* starget = ev.trigger_card;
auto pr = starget->single_effect.equal_range(ev.event_code);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
process_single_event(peffect, ev, tp, ntp);
}
for(auto& pcard : starget->xyz_materials) {
pr = pcard->xmaterial_effect.equal_range(ev.event_code);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
if(peffect->type & EFFECT_TYPE_FIELD)
continue;
process_single_event(peffect, ev, tp, ntp);
}
}
}
while(tp.size()) {
core.sub_solving_continuous.splice(core.sub_solving_continuous.end(), tp, tp.begin());
add_process(PROCESSOR_SOLVE_CONTINUOUS, 0, 0, 0, 0, 0);
}
while(ntp.size()) {
core.sub_solving_continuous.splice(core.sub_solving_continuous.end(), ntp, ntp.begin());
add_process(PROCESSOR_SOLVE_CONTINUOUS, 0, 0, 0, 0, 0);
}
core.single_event.clear();
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
int32 field::process_single_event(effect* peffect, const tevent& e, chain_list& tp, chain_list& ntp) {
if(!(peffect->type & EFFECT_TYPE_ACTIONS))
return FALSE;
if((peffect->type & EFFECT_TYPE_FLIP) && (e.event_value & (NO_FLIP_EFFECT >> 16)))
return FALSE;
//continuous & trigger (single)
if(peffect->type & EFFECT_TYPE_CONTINUOUS) {
uint8 owner_player = peffect->get_handler_player();
if(peffect->is_flag(EFFECT_FLAG_EVENT_PLAYER) && (e.event_player == 0 || e.event_player == 1))
owner_player = e.event_player;
if(peffect->is_activateable(owner_player, e)) {
chain newchain;
newchain.chain_id = 0;
newchain.chain_count = 0;
newchain.triggering_effect = peffect;
newchain.triggering_player = owner_player;
newchain.evt = e;
newchain.target_cards = 0;
newchain.target_player = PLAYER_NONE;
newchain.target_param = 0;
newchain.disable_player = PLAYER_NONE;
newchain.disable_reason = 0;
newchain.flag = 0;
if(peffect->is_flag(EFFECT_FLAG_DELAY) && (core.chain_solving || core.conti_solving)) {
if(owner_player == infos.turn_player)
core.delayed_continuous_tp.push_back(newchain);
else
core.delayed_continuous_ntp.push_back(newchain);
} else {
if(owner_player == infos.turn_player)
tp.push_back(newchain);
else
ntp.push_back(newchain);
}
}
} else {
card* phandler = peffect->get_handler();
if(!peffect->is_condition_check(phandler->current.controler, e))
return FALSE;
peffect->set_activate_location();
chain newchain;
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.event_id = e.global_id;
newchain.evt = e;
newchain.triggering_effect = peffect;
newchain.set_triggering_state(phandler);
if(peffect->is_flag(EFFECT_FLAG_EVENT_PLAYER) && (e.event_player == 0 || e.event_player == 1))
newchain.triggering_player = e.event_player;
else {
if(phandler->current.reason & REASON_TEMPORARY)
newchain.triggering_player = phandler->previous.controler;
else
newchain.triggering_player = newchain.triggering_controler;
}
if(core.flip_delayed && e.event_code == EVENT_FLIP) {
if (peffect->type & EFFECT_TYPE_TRIGGER_O)
core.new_ochain_b.push_back(newchain);
else
core.new_fchain_b.push_back(newchain);
} else {
if (peffect->type & EFFECT_TYPE_TRIGGER_O)
core.new_ochain.push_back(newchain);
else
core.new_fchain.push_back(newchain);
}
peffect->set_active_type();
phandler->create_relation(newchain);
effect* deffect;
if((deffect = phandler->is_affected_by_effect(EFFECT_DISABLE_EFFECT)) != nullptr) {
effect* negeff = pduel->new_effect();
negeff->owner = deffect->owner;
negeff->type = EFFECT_TYPE_SINGLE;
negeff->code = EFFECT_DISABLE_CHAIN;
negeff->value = newchain.chain_id;
negeff->reset_flag = RESET_EVENT | deffect->get_value();
phandler->add_effect(negeff);
}
}
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
int32 field::process_idle_command(uint16 step) {
switch(step) {
case 0: {
bool must_attack = false;
core.select_chains.clear();
chain newchain;
nil_event.event_code = EVENT_FREE_CHAIN;
if(core.set_forced_attack) {
core.set_forced_attack = false;
core.units.begin()->step = -1;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
return FALSE;
}
core.to_bp = TRUE;
core.to_ep = TRUE;
if((!is_flag(DUEL_ATTACK_FIRST_TURN) && infos.turn_id == 1 && !(is_player_affected_by_effect(infos.turn_player, EFFECT_BP_FIRST_TURN))) || infos.phase == PHASE_MAIN2 || is_player_affected_by_effect(infos.turn_player, EFFECT_CANNOT_BP) || core.force_turn_end)
core.to_bp = FALSE;
if(infos.phase == PHASE_MAIN1) {
for(auto& pcard : player[infos.turn_player].list_mzone) {
if(pcard && pcard->is_capable_attack() && pcard->is_affected_by_effect(EFFECT_MUST_ATTACK)) {
must_attack = true;
break;
}
}
if(core.to_bp && (must_attack || is_player_affected_by_effect(infos.turn_player, EFFECT_CANNOT_EP)))
core.to_ep = FALSE;
}
if((infos.phase == PHASE_MAIN1 && is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_M1))
|| (infos.phase == PHASE_MAIN2 && is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_M2)) || core.force_turn_end) {
if(core.to_bp && core.to_ep) {
core.select_options.clear();
core.select_options.push_back(80);
core.select_options.push_back(81);
add_process(PROCESSOR_SELECT_OPTION, 0, 0, 0, infos.turn_player, 0);
core.units.begin()->step = 11;
} else if(core.to_bp) {
core.units.begin()->arg1 = 6;
core.units.begin()->step = 10;
reset_phase(infos.phase);
adjust_all();
} else {
core.units.begin()->arg1 = 7;
core.units.begin()->step = 10;
reset_phase(infos.phase);
adjust_all();
}
return FALSE;
}
if((infos.phase == PHASE_MAIN2) && core.skip_m2) {
core.skip_m2 = FALSE;
returns.at<int32>(0) = 7;
return FALSE;
}
auto pr = effects.activate_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second; eit++) {
effect* peffect = eit->second;
peffect->set_activate_location();
newchain.triggering_effect = peffect;
if(peffect->is_activateable(infos.turn_player, nil_event))
core.select_chains.push_back(newchain);
}
pr = effects.quick_o_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second; eit++) {
effect* peffect = eit->second;
peffect->set_activate_location();
newchain.triggering_effect = peffect;
if(peffect->is_activateable(infos.turn_player, nil_event))
core.select_chains.push_back(newchain);
}
pr = effects.continuous_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second; eit++) {
effect* peffect = eit->second;
newchain.triggering_effect = peffect;
if(peffect->get_handler_player() == infos.turn_player && peffect->is_activateable(infos.turn_player, nil_event))
core.select_chains.push_back(newchain);
}
for(auto& eit : effects.ignition_effect) {
effect* peffect = eit.second;
peffect->set_activate_location();
newchain.triggering_effect = peffect;
if(peffect->is_activateable(infos.turn_player, nil_event))
core.select_chains.push_back(newchain);
}
core.summonable_cards.clear();
for(auto& pcard : player[infos.turn_player].list_hand)
if(pcard->is_can_be_summoned(infos.turn_player, FALSE, 0, 0))
core.summonable_cards.push_back(pcard);
for(auto& pcard : player[infos.turn_player].list_mzone) {
if(pcard && pcard->is_can_be_summoned(infos.turn_player, FALSE, 0, 0))
core.summonable_cards.push_back(pcard);
}
core.spsummonable_cards.clear();
effect_set eset;
filter_field_effect(EFFECT_SPSUMMON_PROC, &eset);
for(const auto& peff : eset) {
card* pcard = peff->get_handler();
if(!peff->check_count_limit(pcard->current.controler))
continue;
if(pcard->current.controler == infos.turn_player && pcard->is_special_summonable(infos.turn_player, 0))
core.spsummonable_cards.push_back(pcard);
}
eset.clear();
filter_field_effect(EFFECT_SPSUMMON_PROC_G, &eset);
for(const auto& peff : eset) {
card* pcard = peff->get_handler();
if(!peff->check_count_limit(infos.turn_player))
continue;
if(pcard->current.controler != infos.turn_player && !peff->is_flag(EFFECT_FLAG_BOTH_SIDE))
continue;
effect* oreason = core.reason_effect;
uint8 op = core.reason_player;
core.reason_effect = peff;
core.reason_player = pcard->current.controler;
save_lp_cost();
pduel->lua->add_param(peff, PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
if(pduel->lua->check_condition(peff->condition, 2))
core.spsummonable_cards.push_back(pcard);
restore_lp_cost();
core.reason_effect = oreason;
core.reason_player = op;
}
core.repositionable_cards.clear();
for(auto& pcard : player[infos.turn_player].list_mzone) {
if(pcard && ((pcard->is_position(POS_FACEUP | POS_FACEDOWN_ATTACK) && pcard->is_capable_change_position(infos.turn_player))
|| (pcard->is_position(POS_FACEDOWN) && pcard->is_can_be_flip_summoned(infos.turn_player))))
core.repositionable_cards.push_back(pcard);
}
core.msetable_cards.clear();
core.ssetable_cards.clear();
for(auto& pcard : player[infos.turn_player].list_hand) {
if(pcard->is_setable_mzone(infos.turn_player, FALSE, 0, 0))
core.msetable_cards.push_back(pcard);
if(pcard->is_setable_szone(infos.turn_player))
core.ssetable_cards.push_back(pcard);
}
add_process(PROCESSOR_SELECT_IDLECMD, 0, 0, 0, infos.turn_player, 0);
return FALSE;
}
case 1: {
uint32 ctype = returns.at<int32>(0) & 0xffff;
uint32 sel = returns.at<int32>(0) >> 16;
if(ctype == 5) {
chain newchain = core.select_chains[sel];
effect* peffect = newchain.triggering_effect;
if(peffect->type & EFFECT_TYPE_CONTINUOUS) {
core.select_chains.clear();
solve_continuous(peffect->get_handler_player(), peffect, nil_event);
core.units.begin()->step = 2;
return FALSE;
}
card* phandler = peffect->get_handler();
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.evt.event_code = peffect->code;
newchain.evt.event_player = PLAYER_NONE;
newchain.evt.event_value = 0;
newchain.evt.event_cards = 0;
newchain.evt.reason = 0;
newchain.evt.reason_effect = 0;
newchain.evt.reason_player = PLAYER_NONE;
newchain.set_triggering_state(phandler);
newchain.triggering_player = infos.turn_player;
core.new_chains.push_back(newchain);
phandler->set_status(STATUS_CHAINING, TRUE);
peffect->dec_count(infos.turn_player);
core.select_chains.clear();
add_process(PROCESSOR_ADD_CHAIN, 0, 0, 0, 0, 0);
add_process(PROCESSOR_QUICK_EFFECT, 0, 0, 0, FALSE, 1 - infos.turn_player);
infos.priorities[0] = 0;
infos.priorities[1] = 0;
core.select_chains.clear();
return FALSE;
} else if(ctype == 0) {
core.units.begin()->step = 4;
return FALSE;
} else if(ctype == 1) {
core.units.begin()->step = 5;
return FALSE;
} else if(ctype == 2) {
core.units.begin()->step = 6;
return FALSE;
} else if(ctype == 3) {
core.units.begin()->step = 7;
return FALSE;
} else if(ctype == 4) {
core.units.begin()->step = 8;
return FALSE;
} else if (ctype == 8) {
core.units.begin()->step = -1;
shuffle(infos.turn_player, LOCATION_HAND);
infos.can_shuffle = FALSE;
return FALSE;
} else {
core.units.begin()->step = 9;
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(1 - infos.turn_player);
message->write<uint64>(23);
core.select_chains.clear();
core.hint_timing[infos.turn_player] = TIMING_MAIN_END;
add_process(PROCESSOR_QUICK_EFFECT, 0, 0, 0, FALSE, 1 - infos.turn_player);
infos.priorities[infos.turn_player] = 1;
infos.priorities[1 - infos.turn_player] = 0;
core.units.begin()->arg1 = ctype;
return FALSE;
}
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
case 2: {
core.chain_limit.clear();
for(auto& ch : core.current_chain)
ch.triggering_effect->get_handler()->set_status(STATUS_CHAINING, FALSE);
add_process(PROCESSOR_SOLVE_CHAIN, 0, 0, 0, FALSE, 0);
core.units.begin()->step = -1;
return FALSE;
}
case 3: {
adjust_instant();
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, 0);
core.units.begin()->step = -1;
return FALSE;
}
case 5: {
card* target = core.summonable_cards[returns.at<int32>(0) >> 16];
core.summon_cancelable = TRUE;
summon(infos.turn_player, target, 0, FALSE, 0);
core.units.begin()->step = -1;
return FALSE;
}
case 6: {
card* target = core.spsummonable_cards[returns.at<int32>(0) >> 16];
core.summon_cancelable = TRUE;
special_summon_rule(infos.turn_player, target, 0);
core.units.begin()->step = -1;
return FALSE;
}
case 7: {
card* target = core.repositionable_cards[returns.at<int32>(0) >> 16];
if(target->is_position(POS_FACEUP_ATTACK)) {
core.phase_action = TRUE;
change_position(target, 0, infos.turn_player, POS_FACEUP_DEFENSE, FALSE);
adjust_all();
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, FALSE, 0);
} else if(target->is_position(POS_FACEUP_DEFENSE)) {
core.phase_action = TRUE;
change_position(target, 0, infos.turn_player, POS_FACEUP_ATTACK, FALSE);
adjust_all();
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, FALSE, 0);
} else if(target->is_position(POS_FACEDOWN_ATTACK)) {
core.units.begin()->ptarget = (group*)target;
int32 positions = 0;
if(target->is_capable_change_position(infos.turn_player))
positions |= POS_FACEDOWN_DEFENSE;
if(target->is_can_be_flip_summoned(infos.turn_player))
positions |= POS_FACEUP_ATTACK;
add_process(PROCESSOR_SELECT_POSITION, 0, 0, 0, infos.turn_player + (positions << 16), target->data.code);
core.units.begin()->step = 12;
return FALSE;
} else
add_process(PROCESSOR_FLIP_SUMMON, 0, 0, (group*)target, target->current.controler, 0);
target->set_status(STATUS_FORM_CHANGED, TRUE);
core.units.begin()->step = -1;
return FALSE;
}
case 8: {
card* target = core.msetable_cards[returns.at<int32>(0) >> 16];
core.summon_cancelable = TRUE;
mset(target->current.controler, target, 0, FALSE, 0);
core.units.begin()->step = -1;
return FALSE;
}
case 9: {
card* target = core.ssetable_cards[returns.at<int32>(0) >> 16];
add_process(PROCESSOR_SSET, 0, 0, (group*)target, target->current.controler, target->current.controler);
core.units.begin()->step = -1;
return FALSE;
}
case 10: {
//end announce
core.chain_limit.clear();
if(core.current_chain.size()) {
for(auto& ch : core.current_chain)
ch.triggering_effect->get_handler()->set_status(STATUS_CHAINING, FALSE);
add_process(PROCESSOR_SOLVE_CHAIN, 0, 0, 0, FALSE, 0);
core.units.begin()->step = -1;
return FALSE;
}
reset_phase(infos.phase);
adjust_all();
return FALSE;
}
case 11: {
returns.at<int32>(0) = core.units.begin()->arg1;
infos.can_shuffle = TRUE;
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
case 12: {
if(returns.at<int32>(0) == 0)
core.units.begin()->arg1 = 6;
else
core.units.begin()->arg1 = 7;
reset_phase(infos.phase);
adjust_all();
core.units.begin()->step = 10;
return FALSE;
}
case 13: {
card* target = (card*)core.units.begin()->ptarget;
if(returns.at<int32>(0) == POS_FACEUP_ATTACK)
add_process(PROCESSOR_FLIP_SUMMON, 0, 0, (group*)target, target->current.controler, 0);
else {
core.phase_action = TRUE;
change_position(target, 0, infos.turn_player, POS_FACEDOWN_DEFENSE, FALSE);
adjust_all();
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, FALSE, 0);
}
target->set_status(STATUS_FORM_CHANGED, TRUE);
core.units.begin()->step = -1;
return FALSE;
}
}
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
int32 field::process_battle_command(uint16 step) {
switch(step) {
case 0: {
effect* peffect = 0;
core.select_chains.clear();
chain newchain;
nil_event.event_code = EVENT_FREE_CHAIN;
if(!core.chain_attack) {
core.chain_attacker_id = 0;
core.chain_attack_target = 0;
}
core.attack_player = FALSE;
core.attacker = 0;
core.attack_target = 0;
if((peffect = is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_BP)) != nullptr || core.force_turn_end) {
core.units.begin()->step = 41;
core.units.begin()->arg1 = 2;
if(is_player_affected_by_effect(infos.turn_player, EFFECT_BP_TWICE))
core.units.begin()->arg2 = 1;
else core.units.begin()->arg2 = 0;
if(core.force_turn_end || peffect->value.Empty()) {
reset_phase(PHASE_BATTLE_STEP);
adjust_all();
infos.phase = PHASE_BATTLE;
add_process(PROCESSOR_PHASE_EVENT, 0, 0, 0, PHASE_BATTLE, 0);
} else {
core.hint_timing[infos.turn_player] = 0;
reset_phase(PHASE_BATTLE);
adjust_all();
}
return FALSE;
}
auto pr = effects.activate_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second; eit++) {
peffect = eit->second;
peffect->set_activate_location();
newchain.triggering_effect = peffect;
if(peffect->is_activateable(infos.turn_player, nil_event) && peffect->get_speed() > 1)
core.select_chains.push_back(newchain);
}
pr = effects.quick_o_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second; eit++) {
peffect = eit->second;
peffect->set_activate_location();
newchain.triggering_effect = peffect;
if(peffect->is_activateable(infos.turn_player, nil_event))
core.select_chains.push_back(newchain);
}
pr = effects.continuous_effect.equal_range(EVENT_FREE_CHAIN);
for(auto eit = pr.first; eit != pr.second; eit++) {
peffect = eit->second;
newchain.triggering_effect = peffect;
if(peffect->get_handler_player() == infos.turn_player && peffect->is_activateable(infos.turn_player, nil_event))
core.select_chains.push_back(newchain);
}
core.attackable_cards.clear();
card_vector first_attack;
card_vector must_attack;
if(!is_player_affected_by_effect(infos.turn_player, EFFECT_CANNOT_ATTACK_ANNOUNCE)) {
for(auto& pcard : player[infos.turn_player].list_mzone) {
if(!pcard)
continue;
if(!pcard->is_capable_attack_announce(infos.turn_player))
continue;
uint8 chain_attack = FALSE;
if(core.chain_attack && core.chain_attacker_id == pcard->fieldid)
chain_attack = TRUE;
card_vector cv;
get_attack_target(pcard, &cv, chain_attack);
if(cv.size() == 0 && pcard->direct_attackable == 0)
continue;
core.attackable_cards.push_back(pcard);
if(pcard->is_affected_by_effect(EFFECT_FIRST_ATTACK))
first_attack.push_back(pcard);
if(pcard->is_affected_by_effect(EFFECT_MUST_ATTACK))
must_attack.push_back(pcard);
}
if(first_attack.size())
core.attackable_cards = first_attack;
}
core.to_m2 = is_flag(DUEL_NO_MAIN_PHASE_2) ? FALSE : TRUE;
core.to_ep = TRUE;
if(must_attack.size() || is_player_affected_by_effect(infos.turn_player, EFFECT_CANNOT_M2) || core.force_turn_end)
core.to_m2 = FALSE;
if(must_attack.size())
core.to_ep = FALSE;
core.attack_cancelable = TRUE;
core.attack_cost_paid = FALSE;
add_process(PROCESSOR_SELECT_BATTLECMD, 0, 0, 0, infos.turn_player, 0);
return FALSE;
}
case 1: {
int32 ctype = returns.at<int32>(0) & 0xffff;
int32 sel = returns.at<int32>(0) >> 16;
if(ctype == 0) {
chain newchain = core.select_chains[sel];
effect* peffect = newchain.triggering_effect;
if(peffect->type & EFFECT_TYPE_CONTINUOUS) {
core.select_chains.clear();
solve_continuous(peffect->get_handler_player(), peffect, nil_event);
core.units.begin()->step = 14;
return FALSE;
}
card* phandler = peffect->get_handler();
newchain.flag = 0;
newchain.chain_id = infos.field_id++;
newchain.evt.event_code = peffect->code;
newchain.evt.event_player = PLAYER_NONE;
newchain.evt.event_value = 0;
newchain.evt.event_cards = 0;
newchain.evt.reason = 0;
newchain.evt.reason_effect = 0;
newchain.evt.reason_player = PLAYER_NONE;
newchain.set_triggering_state(phandler);
newchain.triggering_player = infos.turn_player;
core.new_chains.push_back(newchain);
phandler->set_status(STATUS_CHAINING, TRUE);
peffect->dec_count(infos.turn_player);
core.select_chains.clear();
add_process(PROCESSOR_ADD_CHAIN, 0, 0, 0, 0, 0);
add_process(PROCESSOR_QUICK_EFFECT, 0, 0, 0, FALSE, 1 - infos.turn_player);
infos.priorities[0] = 0;
infos.priorities[1] = 0;
core.select_chains.clear();
return FALSE;
} else if(ctype == 1) {
core.units.begin()->step = 2;
core.units.begin()->arg3 = FALSE;
if(!core.forced_attack)
core.attacker = core.attackable_cards[sel];
core.attacker->set_status(STATUS_ATTACK_CANCELED, FALSE);
core.attacker->attack_controler = core.attacker->current.controler;
core.pre_field[0] = core.attacker->fieldid_r;
if(core.chain_attack && core.chain_attacker_id != core.attacker->fieldid) {
core.chain_attack = FALSE;
core.chain_attacker_id = 0;
}
effect_set eset;
core.tpchain.clear();
chain newchain;
filter_player_effect(infos.turn_player, EFFECT_ATTACK_COST, &eset, FALSE);
core.attacker->filter_effect(EFFECT_ATTACK_COST, &eset);
for(const auto& peff : eset) {
if(peff->operation) {
newchain.triggering_effect = peff;
core.tpchain.push_back(newchain);
core.attack_cancelable = FALSE;
}
}
if(core.tpchain.size() > 1) {
add_process(PROCESSOR_SORT_CHAIN, 0, 0, 0, 1, infos.turn_player);
core.units.begin()->step = 13;
}
else if(core.tpchain.size() == 1){
core.sub_solving_event.push_back(nil_event);
add_process(PROCESSOR_EXECUTE_OPERATION, 0, core.tpchain.begin()->triggering_effect, 0, infos.turn_player, 0);
adjust_all();
}
return FALSE;
} else {
core.units.begin()->step = 39;
core.units.begin()->arg1 = ctype;
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(1 - infos.turn_player);
message->write<uint64>(29);
core.select_chains.clear();
core.hint_timing[infos.turn_player] = TIMING_BATTLE_STEP_END;
add_process(PROCESSOR_QUICK_EFFECT, 0, 0, 0, FALSE, 1 - infos.turn_player);
infos.priorities[infos.turn_player] = 1;
infos.priorities[1 - infos.turn_player] = 0;
return FALSE;
}
/*if(core.set_forced_attack) {
core.set_forced_attack = false;
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);
}*/
return TRUE;
}
case 2: {
core.chain_limit.clear();
for(auto& ch : core.current_chain)
ch.triggering_effect->get_handler()->set_status(STATUS_CHAINING, FALSE);
add_process(PROCESSOR_SOLVE_CHAIN, 0, 0, 0, FALSE, 0);
core.units.begin()->step = -1;
return FALSE;
}
case 3: {
core.units.begin()->arg1 = FALSE;
if(core.attacker->is_status(STATUS_ATTACK_CANCELED)) {
core.units.begin()->arg3 = TRUE;
core.units.begin()->step = 6;
return FALSE;
}
//Cancel the attack cost
if(core.attack_cost_paid != 1 && !core.attack_cancelable) {
if(core.forced_attack) {
returns.at<int32>(0) = 2;
core.units.begin()->step = 0;
} else
core.units.begin()->step = -1;
return FALSE;
}
if(core.forced_attack)
core.units.begin()->step = 6;
return FALSE;
}
case 4: {
// select attack target(replay start point)
core.attack_player = FALSE;
core.select_cards.clear();
return_cards.clear();
auto atype = get_attack_target(core.attacker, &core.select_cards, core.chain_attack);
// only self targets aviable
if (core.select_cards.size() && core.attacker->direct_attackable) {
add_process(PROCESSOR_SELECT_YESNO, 0, 0, 0, infos.turn_player, 31);
return FALSE;
}
// direct attack
if(core.attacker->direct_attackable) {
if(core.select_cards.size() == 0) {
returns.at<int32>(0) = -2;
core.units.begin()->step = 5;
return FALSE;
}
if(is_player_affected_by_effect(infos.turn_player, EFFECT_PATRICIAN_OF_DARKNESS)) {
add_process(PROCESSOR_SELECT_EFFECTYN, 0, 0, (group*)core.attacker, 1 - infos.turn_player, 31);
}
else {
add_process(PROCESSOR_SELECT_YESNO, 0, 0, 0, infos.turn_player, 31);
}
return FALSE;
}
// no target and not direct attackable
if(core.select_cards.size() == 0) {
core.units.begin()->arg3 = TRUE;
core.units.begin()->step = 6;
return FALSE;
}
// must attack monster
if(atype == 3 || is_player_affected_by_effect(infos.turn_player, EFFECT_PATRICIAN_OF_DARKNESS)) {
if(core.select_cards.size() == 1)
return_cards.list.push_back(core.select_cards.front());
else {
auto message = pduel->new_message(MSG_BECOME_TARGET);
message->write<uint32>(1);
message->write(core.attacker->get_info_location());
message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_SELECTMSG);
message->write<uint8>(1 - infos.turn_player);
message->write<uint64>(549);
add_process(PROCESSOR_SELECT_CARD, 0, 0, 0, 1 - infos.turn_player, 0x10001);
}
} else {
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_SELECTMSG);
message->write<uint8>(infos.turn_player);
message->write<uint64>(549);
add_process(PROCESSOR_SELECT_CARD, 0, 0, 0, infos.turn_player + (core.attack_cancelable ? 0x20000 : 0), 0x10001);
}
core.units.begin()->step = 5;
return FALSE;
}
case 5: {
// the answer of "direct attack or not"
if(returns.at<int32>(0)) {
returns.at<int32>(0) = -2;
} else {
if(core.select_cards.size()) {
auto opposel = !!is_player_affected_by_effect(infos.turn_player, EFFECT_PATRICIAN_OF_DARKNESS);
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_SELECTMSG);
message->write<uint8>(opposel ? 1 - infos.turn_player : infos.turn_player);
message->write<uint64>(549);
add_process(PROCESSOR_SELECT_CARD, 0, 0, 0, (opposel ? 1 - infos.turn_player : infos.turn_player) + (core.attack_cancelable ? 0x20000 : 0), 0x10001);
} else {
core.units.begin()->arg3 = TRUE;
core.units.begin()->step = 6;
}
}
return FALSE;
}
case 6: {
if(return_cards.canceled) {//cancel attack manually
if(core.units.begin()->arg1) {
core.units.begin()->step = 12;
return FALSE;
}
if(core.forced_attack) {
returns.at<int32>(0) = 2;
core.units.begin()->step = 0;
} else
core.units.begin()->step = -1;
return FALSE;
}
if(returns.at<int32>(0) == -2)
core.attack_target = 0;
else
core.attack_target = return_cards.list[0];
if(core.attack_target)
core.pre_field[1] = core.attack_target->fieldid_r;
else
core.pre_field[1] = 0;
return FALSE;
}
case 7: {
if(!core.units.begin()->arg1) {
core.phase_action = TRUE;
core.attack_state_count[infos.turn_player]++;
check_card_counter(core.attacker, 5, infos.turn_player);
core.attacker->attack_announce_count++;
}
if(core.units.begin()->arg3) {//attack announce failed
core.attacker->announce_count++;
core.chain_attack = FALSE;
if(core.forced_attack) {
returns.at<int32>(0) = 2;
core.units.begin()->step = 0;
} else
core.units.begin()->step = -1;
}
return FALSE;
}
case 8: {
core.attack_cancelable = TRUE;
auto message = pduel->new_message(MSG_ATTACK);
message->write(core.attacker->get_info_location());
if(core.attack_target) {
raise_single_event(core.attack_target, 0, EVENT_BE_BATTLE_TARGET, 0, 0, 0, 1 - infos.turn_player, 0);
raise_event(core.attack_target, EVENT_BE_BATTLE_TARGET, 0, 0, 0, 1 - infos.turn_player, 0);
message->write(core.attack_target->get_info_location());
} else {
message->write(loc_info{});
}
core.attack_rollback = FALSE;
core.opp_mzone.clear();
for(auto& pcard : player[1 - infos.turn_player].list_mzone) {
if(pcard)
core.opp_mzone.insert(pcard->fieldid_r);
}
//core.units.begin()->arg1 ---> is rollbacked
if(!core.units.begin()->arg1) {
raise_single_event(core.attacker, 0, EVENT_ATTACK_ANNOUNCE, 0, 0, 0, infos.turn_player, 0);
raise_event(core.attacker, EVENT_ATTACK_ANNOUNCE, 0, 0, 0, infos.turn_player, 0);
}
core.attacker->attack_controler = core.attacker->current.controler;
core.pre_field[0] = core.attacker->fieldid_r;
process_single_event();
process_instant_event();
core.hint_timing[infos.turn_player] = TIMING_ATTACK;
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, 0);
return FALSE;
}
case 9: {
if(is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_BP)
|| core.attacker->is_status(STATUS_ATTACK_CANCELED) || core.attack_rollback) {
core.units.begin()->step = 10;
return FALSE;
}
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(0);
message->write<uint64>(24);
message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(1);
message->write<uint64>(24);
core.hint_timing[0] = TIMING_BATTLE_PHASE;
core.hint_timing[1] = TIMING_BATTLE_PHASE;
add_process(PROCESSOR_POINT_EVENT, 30, 0, 0, 0, 0);
return FALSE;
}
case 10: {
if(returns.at<int32>(0))
core.units.begin()->step = 8;
else
adjust_all();
return FALSE;
}
case 11: {
if(core.attacker->is_affected_by_effect(EFFECT_ATTACK_DISABLED)) {
core.attacker->reset(EFFECT_ATTACK_DISABLED, RESET_CODE);
pduel->new_message(MSG_ATTACK_DISABLED);
core.attacker->set_status(STATUS_ATTACK_CANCELED, TRUE);
}
if(is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_BP)
|| core.attacker->is_status(STATUS_ATTACK_CANCELED)) {
core.units.begin()->step = 12;
return FALSE;
}
// go to damage step
if(!core.attack_rollback) {
core.attacker->announce_count++;
core.attacker->announced_cards.addcard(core.attack_target);
attack_all_target_check();
core.units.begin()->step = 18;
return FALSE;
}
card_vector cv;
get_attack_target(core.attacker, &cv, core.chain_attack);
if(!cv.size() && !core.attacker->direct_attackable) {
core.units.begin()->step = 12;
return FALSE;
}
// replay
if(is_flag(DUEL_STORE_ATTACK_REPLAYS)) {
returns.at<int32>(0) = FALSE;
} else if(!core.attacker->is_affected_by_effect(EFFECT_MUST_ATTACK))
add_process(PROCESSOR_SELECT_YESNO, 0, 0, 0, infos.turn_player, 30);
else {
returns.at<int32>(0) = TRUE;
core.attack_cancelable = FALSE;
}
return FALSE;
}
case 12: {
// answer of "replay or not"
if(returns.at<int32>(0)) {
core.units.begin()->arg1 = TRUE;
core.units.begin()->arg3 = FALSE;
core.units.begin()->step = 3;
}
return FALSE;
}
case 13: {
if(core.attacker->fieldid_r == core.pre_field[0] && (!is_flag(DUEL_STORE_ATTACK_REPLAYS) || core.attacker->is_status(STATUS_ATTACK_CANCELED))) {
core.attacker->announce_count++;
core.attacker->announced_cards.addcard(core.attack_target);
attack_all_target_check();
}
core.chain_attack = FALSE;
if(core.forced_attack) {
returns.at<int32>(0) = 2;
core.units.begin()->step = 0;
} else
core.units.begin()->step = -1;
reset_phase(PHASE_DAMAGE);
adjust_all();
return FALSE;
}
case 14: {
for(auto clit = core.tpchain.begin(); clit != core.tpchain.end(); ++clit) {
core.sub_solving_event.push_back(nil_event);
add_process(PROCESSOR_EXECUTE_OPERATION, 0, clit->triggering_effect, 0, infos.turn_player, 0);
adjust_all();
}
core.tpchain.clear();
core.units.begin()->step = 2;
return FALSE;
}
case 15: {
adjust_instant();
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, 0);
core.units.begin()->step = -1;
return FALSE;
}
case 19: {
infos.phase = PHASE_DAMAGE;
core.chain_attack = FALSE;
core.units.begin()->arg1 = FALSE;
core.damage_calculated = FALSE;
core.selfdes_disabled = TRUE;
core.flip_delayed = TRUE;
core.attacker->attack_controler = core.attacker->current.controler;
core.pre_field[0] = core.attacker->fieldid_r;
if(core.attack_target) {
core.attack_target->attack_controler = core.attack_target->current.controler;
core.pre_field[1] = core.attack_target->fieldid_r;
} else
core.pre_field[1] = 0;
core.attacker->attacked_count++;
core.attacker->attacked_cards.addcard(core.attack_target);
core.battled_count[infos.turn_player]++;
adjust_all();
return FALSE;
}
case 20: {
// start of PHASE_DAMAGE;
auto message = pduel->new_message(MSG_DAMAGE_STEP_START);
raise_single_event(core.attacker, 0, EVENT_BATTLE_START, 0, 0, 0, 0, 0);
if(core.attack_target) {
raise_single_event(core.attack_target, 0, EVENT_BATTLE_START, 0, 0, 0, 0, 1);
}
raise_event((card*)0, EVENT_BATTLE_START, 0, 0, 0, 0, 0);
process_single_event();
process_instant_event();
if(!is_flag(DUEL_6_STEP_BATLLE_STEP) || (core.new_fchain.size() || core.new_ochain.size())) {
core.units.begin()->arg4 = core.new_fchain.size() || core.new_ochain.size();
message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(0);
message->write<uint64>(40);
message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(1);
message->write<uint64>(40);
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, is_flag(DUEL_SINGLE_CHAIN_IN_DAMAGE_SUBSTEP));
}
return FALSE;
}
case 21: {
if(core.attacker->is_status(STATUS_ATTACK_CANCELED)) {
core.units.begin()->step = 33;
return FALSE;
}
if(!core.attack_target) {
return FALSE;
}
core.attacker->temp.position = core.attacker->current.position;
core.attack_target->temp.position = core.attack_target->current.position;
if(core.attack_target->is_position(POS_FACEDOWN)) {
change_position(core.attack_target, 0, PLAYER_NONE, core.attack_target->current.position >> 1, 0, TRUE);
adjust_all();
}
return FALSE;
}
case 22: {
raise_single_event(core.attacker, 0, EVENT_BATTLE_CONFIRM, 0, 0, 0, 0, 0);
if(core.attack_target) {
if(core.attack_target->temp.position & POS_FACEDOWN)
core.pre_field[1] = core.attack_target->fieldid_r;
raise_single_event(core.attack_target, 0, EVENT_BATTLE_CONFIRM, 0, 0, 0, 0, 1);
}
raise_event((card*)0, EVENT_BATTLE_CONFIRM, 0, 0, 0, 0, 0);
process_single_event();
process_instant_event();
if(!is_flag(DUEL_6_STEP_BATLLE_STEP) || !core.units.begin()->arg4 || core.new_fchain.size() || core.new_ochain.size()) {
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(0);
message->write<uint64>(41);
message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(1);
message->write<uint64>(41);
core.hint_timing[infos.turn_player] = TIMING_DAMAGE_STEP;
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, is_flag(DUEL_SINGLE_CHAIN_IN_DAMAGE_SUBSTEP));
}
return FALSE;
}
case 23: {
if(core.attacker->is_status(STATUS_ATTACK_CANCELED)) {
core.units.begin()->step = 33;
return FALSE;
}
infos.phase = PHASE_DAMAGE_CAL;
adjust_all();
return FALSE;
}
case 24: {
// PHASE_DAMAGE_CAL;
calculate_battle_damage(0, 0, 0);
raise_single_event(core.attacker, 0, EVENT_PRE_DAMAGE_CALCULATE, 0, 0, 0, 0, 0);
if(core.attack_target)
raise_single_event(core.attack_target, 0, EVENT_PRE_DAMAGE_CALCULATE, 0, 0, 0, 0, 1);
raise_event((card*)0, EVENT_PRE_DAMAGE_CALCULATE, 0, 0, 0, 0, 0);
process_single_event();
process_instant_event();
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(0);
message->write<uint64>(42);
message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(1);
message->write<uint64>(42);
core.hint_timing[infos.turn_player] = TIMING_DAMAGE_CAL;
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, is_flag(DUEL_SINGLE_CHAIN_IN_DAMAGE_SUBSTEP));
return FALSE;
}
case 25: {
if(core.attacker->is_status(STATUS_ATTACK_CANCELED)) {
reset_phase(PHASE_DAMAGE_CAL);
adjust_all();
infos.phase = PHASE_DAMAGE;
core.units.begin()->step = 33;
return FALSE;
}
return FALSE;
}
case 26: {
// Duel.CalculateDamage() goes here
uint32 aa = core.attacker->get_attack(), ad = core.attacker->get_defense();
uint32 da = 0, dd = 0;
uint8 pa = core.attacker->current.controler, pd;
core.attacker->set_status(STATUS_BATTLE_RESULT, FALSE);
core.attacker->set_status(STATUS_BATTLE_DESTROYED, FALSE);
if(core.attack_target) {
da = core.attack_target->get_attack();
dd = core.attack_target->get_defense();
core.attack_target->set_status(STATUS_BATTLE_RESULT, FALSE);
core.attack_target->set_status(STATUS_BATTLE_DESTROYED, FALSE);
pd = core.attack_target->current.controler;
if(pa != pd) {
core.attacker->set_status(STATUS_OPPO_BATTLE, TRUE);
core.attack_target->set_status(STATUS_OPPO_BATTLE, TRUE);
}
}
effect* damchange = 0;
card* reason_card = 0;
uint8 bd[2];
calculate_battle_damage(&damchange, &reason_card, bd);
if(bd[0]) {
effect* indestructable_effect = core.attacker->is_affected_by_effect(EFFECT_INDESTRUCTABLE_BATTLE, core.attack_target);
if(indestructable_effect) {
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_CARD);
message->write<uint8>(0);
message->write<uint64>(indestructable_effect->owner->data.code);
bd[0] = FALSE;
} else
core.attacker->set_status(STATUS_BATTLE_RESULT, TRUE);
}
if(bd[1]) {
effect* indestructable_effect = core.attack_target->is_affected_by_effect(EFFECT_INDESTRUCTABLE_BATTLE, core.attacker);
if(indestructable_effect) {
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_CARD);
message->write<uint8>(0);
message->write<uint64>(indestructable_effect->owner->data.code);
bd[1] = FALSE;
} else
core.attack_target->set_status(STATUS_BATTLE_RESULT, TRUE);
}
auto message = pduel->new_message(MSG_BATTLE);
message->write(core.attacker->get_info_location());
message->write<uint32>(aa);
message->write<uint32>(ad);
message->write<uint8>(bd[0]);
if(core.attack_target) {
message->write(core.attack_target->get_info_location());
message->write<uint32>(da);
message->write<uint32>(dd);
message->write<uint8>(bd[1]);
} else {
message->write(loc_info{});
message->write<uint32>(0);
message->write<uint32>(0);
message->write<uint8>(0);
}
core.units.begin()->peffect = damchange;
if(reason_card)
core.temp_var[0] = reason_card->current.controler;
if(!reason_card)
core.temp_var[1] = 0;
else if(reason_card == core.attacker)
core.temp_var[1] = 1;
else core.temp_var[1] = 2;
if(!damchange) {
if(core.battle_damage[infos.turn_player]) {
raise_single_event(core.attacker, 0, EVENT_PRE_BATTLE_DAMAGE, 0, 0, reason_card->current.controler, infos.turn_player, core.battle_damage[infos.turn_player]);
if(core.attack_target)
raise_single_event(core.attack_target, 0, EVENT_PRE_BATTLE_DAMAGE, 0, 0, reason_card->current.controler, infos.turn_player, core.battle_damage[infos.turn_player]);
raise_event(reason_card, EVENT_PRE_BATTLE_DAMAGE, 0, 0, reason_card->current.controler, infos.turn_player, core.battle_damage[infos.turn_player]);
}
if(core.battle_damage[1 - infos.turn_player]) {
raise_single_event(core.attacker, 0, EVENT_PRE_BATTLE_DAMAGE, 0, 0, reason_card->current.controler, 1 - infos.turn_player, core.battle_damage[1 - infos.turn_player]);
if(core.attack_target)
raise_single_event(core.attack_target, 0, EVENT_PRE_BATTLE_DAMAGE, 0, 0, reason_card->current.controler, 1 - infos.turn_player, core.battle_damage[1 - infos.turn_player]);
raise_event(reason_card, EVENT_PRE_BATTLE_DAMAGE, 0, 0, reason_card->current.controler, 1 - infos.turn_player, core.battle_damage[1 - infos.turn_player]);
}
}
process_single_event();
process_instant_event();
core.damage_calculated = TRUE;
return FALSE;
}
case 27: {
infos.phase = PHASE_DAMAGE;
core.hint_timing[infos.turn_player] = 0;
core.chain_attack = FALSE;
core.attacker->battled_cards.addcard(core.attack_target);
if(core.attack_target)
core.attack_target->battled_cards.addcard(core.attacker);
uint8 reason_player = core.temp_var[0];
card* reason_card = 0;
if(core.temp_var[1] == 1)
reason_card = core.attacker;
else if(core.temp_var[1] == 2)
reason_card = core.attack_target;
effect* damchange = core.units.begin()->peffect;
if(!damchange) {
if(core.battle_damage[0])
damage(0, REASON_BATTLE, reason_player, reason_card, 0, core.battle_damage[0]);
if(core.battle_damage[1])
damage(0, REASON_BATTLE, reason_player, reason_card, 1, core.battle_damage[1]);
} else {
if(core.battle_damage[0])
damage(damchange, REASON_EFFECT, reason_player, reason_card, 0, core.battle_damage[0]);
if(core.battle_damage[1])
damage(damchange, REASON_EFFECT, reason_player, reason_card, 1, core.battle_damage[1]);
}
reset_phase(PHASE_DAMAGE_CAL);
adjust_all();
return FALSE;
}
case 28: {
card_set des;
effect* peffect;
if(core.attacker->is_status(STATUS_BATTLE_RESULT)
&& core.attacker->current.location == LOCATION_MZONE && core.attacker->fieldid_r == core.pre_field[0]) {
des.insert(core.attacker);
core.attacker->temp.reason = core.attacker->current.reason;
core.attacker->temp.reason_card = core.attacker->current.reason_card;
core.attacker->temp.reason_effect = core.attacker->current.reason_effect;
core.attacker->temp.reason_player = core.attacker->current.reason_player;
core.attacker->current.reason_effect = 0;
core.attacker->current.reason = REASON_BATTLE;
core.attacker->current.reason_card = core.attack_target;
core.attacker->current.reason_player = core.attack_target->current.controler;
uint32 dest = LOCATION_GRAVE;
uint32 seq = 0;
if((peffect = core.attack_target->is_affected_by_effect(EFFECT_BATTLE_DESTROY_REDIRECT)) != nullptr && (core.attacker->data.type & TYPE_MONSTER)) {
dest = peffect->get_value(core.attacker);
seq = dest >> 16;
dest &= 0xffff;
}
core.attacker->sendto_param.set(core.attacker->owner, POS_FACEUP, dest, seq);
core.attacker->set_status(STATUS_DESTROY_CONFIRMED, TRUE);
}
if(core.attack_target && core.attack_target->is_status(STATUS_BATTLE_RESULT)
&& core.attack_target->current.location == LOCATION_MZONE && core.attack_target->fieldid_r == core.pre_field[1]) {
des.insert(core.attack_target);
core.attack_target->temp.reason = core.attack_target->current.reason;
core.attack_target->temp.reason_card = core.attack_target->current.reason_card;
core.attack_target->temp.reason_effect = core.attack_target->current.reason_effect;
core.attack_target->temp.reason_player = core.attack_target->current.reason_player;
core.attack_target->current.reason_effect = 0;
core.attack_target->current.reason = REASON_BATTLE;
core.attack_target->current.reason_card = core.attacker;
core.attack_target->current.reason_player = core.attacker->current.controler;
uint32 dest = LOCATION_GRAVE;
uint32 seq = 0;
if((peffect = core.attacker->is_affected_by_effect(EFFECT_BATTLE_DESTROY_REDIRECT)) != nullptr && (core.attack_target->data.type & TYPE_MONSTER)) {
dest = peffect->get_value(core.attack_target);
seq = dest >> 16;
dest &= 0xffff;
}
core.attack_target->sendto_param.set(core.attack_target->owner, POS_FACEUP, dest, seq);
core.attack_target->set_status(STATUS_DESTROY_CONFIRMED, TRUE);
}
core.attacker->set_status(STATUS_BATTLE_RESULT, FALSE);
if(core.attack_target)
core.attack_target->set_status(STATUS_BATTLE_RESULT, FALSE);
core.battle_destroy_rep.clear();
core.desrep_chain.clear();
if(des.size()) {
group* ng = pduel->new_group();
ng->container.swap(des);
ng->is_readonly = TRUE;
add_process(PROCESSOR_DESTROY, 10, 0, ng, REASON_BATTLE, PLAYER_NONE);
core.units.begin()->ptarget = ng;
}
return FALSE;
}
case 29: {
if(core.battle_destroy_rep.size())
destroy(&core.battle_destroy_rep, 0, REASON_EFFECT | REASON_REPLACE, PLAYER_NONE);
if(core.desrep_chain.size())
add_process(PROCESSOR_OPERATION_REPLACE, 15, NULL, NULL, 0, 0);
adjust_all();
return FALSE;
}
case 30: {
group* des = core.units.begin()->ptarget;
if(des && des->container.size()) {
for(auto& pcard : des->container) {
pcard->set_status(STATUS_BATTLE_DESTROYED, TRUE);
pcard->set_status(STATUS_DESTROY_CONFIRMED, FALSE);
pcard->filter_disable_related_cards();
}
}
core.selfdes_disabled = FALSE;
adjust_all();
if(is_flag(DUEL_6_STEP_BATLLE_STEP)) {
//EVENT_BATTLE_END was here, but this timing does not exist in Master Rule 3+
if(!core.effect_damage_step) {
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(0);
message->write<uint64>(45);
message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(1);
message->write<uint64>(45);
core.hint_timing[infos.turn_player] = TIMING_DAMAGE_CAL;
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, is_flag(DUEL_SINGLE_CHAIN_IN_DAMAGE_SUBSTEP));
} else {
break_effect();
}
}
return FALSE;
}
case 31: {
core.flip_delayed = FALSE;
core.new_fchain.splice(core.new_fchain.begin(), core.new_fchain_b);
core.new_ochain.splice(core.new_ochain.begin(), core.new_ochain_b);
raise_single_event(core.attacker, 0, EVENT_BATTLED, 0, 0, PLAYER_NONE, 0, 0);
if(core.attack_target)
raise_single_event(core.attack_target, 0, EVENT_BATTLED, 0, 0, PLAYER_NONE, 0, 1);
raise_event((card*)0, EVENT_BATTLED, 0, 0, PLAYER_NONE, 0, 0);
process_single_event();
process_instant_event();
if(core.effect_damage_step) {
core.reserved.ptr1 = core.units.begin()->ptarget;
return TRUE;
}
core.units.begin()->step = 32;
}
// fall through
case 32: {
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(0);
message->write<uint64>(43);
message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(1);
message->write<uint64>(43);
core.hint_timing[0] |= TIMING_BATTLED;
core.hint_timing[1] |= TIMING_BATTLED;
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, is_flag(DUEL_SINGLE_CHAIN_IN_DAMAGE_SUBSTEP));
return FALSE;
}
case 33: {
group* des = core.units.begin()->ptarget;
if(des) {
for(auto cit = des->container.begin(); cit != des->container.end();) {
auto rm = cit++;
if((*rm)->current.location != LOCATION_MZONE || ((*rm)->fieldid_r != core.pre_field[0] && (*rm)->fieldid_r != core.pre_field[1]))
des->container.erase(rm);
}
add_process(PROCESSOR_DESTROY, 3, 0, des, REASON_BATTLE, PLAYER_NONE);
}
adjust_all();
return FALSE;
}
case 34: {
core.units.begin()->ptarget = 0;
// for unexpected end of damage step
core.damage_calculated = TRUE;
core.selfdes_disabled = FALSE;
core.flip_delayed = FALSE;
core.new_fchain.splice(core.new_fchain.begin(), core.new_fchain_b);
core.new_ochain.splice(core.new_ochain.begin(), core.new_ochain_b);
card_set ing;
card_set ed;
if(core.attacker->is_status(STATUS_BATTLE_DESTROYED) && (core.attacker->current.reason & REASON_BATTLE)) {
raise_single_event(core.attack_target, 0, EVENT_BATTLE_DESTROYING, 0, core.attacker->current.reason, core.attack_target->current.controler, 0, 1);
raise_single_event(core.attacker, 0, EVENT_BATTLE_DESTROYED, 0, core.attacker->current.reason, core.attack_target->current.controler, 0, 0);
raise_single_event(core.attacker, 0, EVENT_DESTROYED, 0, core.attacker->current.reason, core.attack_target->current.controler, 0, 0);
ing.insert(core.attack_target);
ed.insert(core.attacker);
}
if(core.attack_target && core.attack_target->is_status(STATUS_BATTLE_DESTROYED) && (core.attack_target->current.reason & REASON_BATTLE)) {
raise_single_event(core.attacker, 0, EVENT_BATTLE_DESTROYING, 0, core.attack_target->current.reason, core.attacker->current.controler, 0, 0);
raise_single_event(core.attack_target, 0, EVENT_BATTLE_DESTROYED, 0, core.attack_target->current.reason, core.attacker->current.controler, 0, 1);
raise_single_event(core.attack_target, 0, EVENT_DESTROYED, 0, core.attack_target->current.reason, core.attacker->current.controler, 0, 1);
ing.insert(core.attacker);
ed.insert(core.attack_target);
}
if(ing.size())
raise_event(&ing, EVENT_BATTLE_DESTROYING, 0, 0, 0, 0, 0);
if(ed.size()) {
raise_event(&ed, EVENT_BATTLE_DESTROYED, 0, 0, 0, 0, 0);
raise_event(&ed, EVENT_DESTROYED, 0, 0, 0, 0, 0);
}
raise_single_event(core.attacker, 0, EVENT_DAMAGE_STEP_END, 0, 0, 0, 0, 0);
if(core.attack_target)
raise_single_event(core.attack_target, 0, EVENT_DAMAGE_STEP_END, 0, 0, 0, 0, 1);
raise_event((card*)0, EVENT_DAMAGE_STEP_END, 0, 0, 0, 0, 0);
core.attacker->set_status(STATUS_BATTLE_DESTROYED, FALSE);
if(core.attack_target)
core.attack_target->set_status(STATUS_BATTLE_DESTROYED, FALSE);
process_single_event();
process_instant_event();
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(0);
message->write<uint64>(44);
message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(1);
message->write<uint64>(44);
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, TRUE);
core.units.begin()->step = 38;
return FALSE;
}
case 38: {
return FALSE;
}
case 39: {
//end of damage step
core.attacker->set_status(STATUS_OPPO_BATTLE, FALSE);
if(core.attack_target)
core.attack_target->set_status(STATUS_OPPO_BATTLE, FALSE);
if(core.forced_attack) {
returns.at<int32>(0) = 2;
core.units.begin()->step = 0;
} else
core.units.begin()->step = -1;
infos.phase = PHASE_BATTLE_STEP;
pduel->new_message(MSG_DAMAGE_STEP_END);
reset_phase(PHASE_DAMAGE);
adjust_all();
if(core.effect_damage_step)
return TRUE;
return FALSE;
}
case 40: {
core.chain_limit.clear();
if(core.current_chain.size()) {
for(auto& ch : core.current_chain)
ch.triggering_effect->get_handler()->set_status(STATUS_CHAINING, FALSE);
add_process(PROCESSOR_SOLVE_CHAIN, 0, 0, 0, FALSE, 0);
if(!core.forced_attack)
core.units.begin()->step = -1;
return FALSE;
}
reset_phase(PHASE_BATTLE_STEP);
adjust_all();
return FALSE;
}
case 41: {
// normal end of battle step
if(is_player_affected_by_effect(infos.turn_player, EFFECT_BP_TWICE))
core.units.begin()->arg2 = 1;
else
core.units.begin()->arg2 = 0;
infos.phase = PHASE_BATTLE;
add_process(PROCESSOR_PHASE_EVENT, 0, 0, 0, PHASE_BATTLE, 0);
adjust_all();
return FALSE;
}
case 42: {
core.attacker = 0;
core.attack_target = 0;
returns.at<int32>(0) = core.units.begin()->arg1;
returns.at<int32>(1) = core.units.begin()->arg2;
return TRUE;
}
}
return TRUE;
}
int32 field::process_forced_battle(uint16 step) {
switch(step) {
case 0: {
if (is_player_affected_by_effect(infos.turn_player, EFFECT_CANNOT_BP))
return TRUE;
core.battle_phase_count[infos.turn_player]++;
if (is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_BP) || core.force_turn_end) {
auto message = pduel->new_message(MSG_NEW_PHASE);
message->write<uint16>(PHASE_BATTLE_START);
reset_phase(PHASE_BATTLE_START);
reset_phase(PHASE_BATTLE_STEP);
reset_phase(PHASE_BATTLE);
adjust_all();
message = pduel->new_message(MSG_NEW_PHASE);
message->write<uint16>(infos.phase);
return TRUE;
}
core.units.begin()->arg1 = infos.phase;
auto tmp_attacker = core.forced_attacker;
auto tmp_attack_target = core.forced_attack_target;
if(!tmp_attacker->is_capable_attack_announce(infos.turn_player))
return TRUE;
card_vector cv;
get_attack_target(tmp_attacker, &cv);
if((cv.size() == 0 && tmp_attacker->direct_attackable == 0) || (tmp_attack_target && std::find(cv.begin(), cv.end(), tmp_attack_target)==cv.end()))
return TRUE;
core.attacker = tmp_attacker;
core.attack_target = tmp_attack_target;
for(uint8 p = 0; p < 2; ++p) {
for(auto& pcard : player[p].list_mzone) {
if(!pcard)
continue;
pcard->attack_announce_count = 0;
pcard->announce_count = 0;
pcard->attacked_count = 0;
pcard->announced_cards.clear();
pcard->attacked_cards.clear();
pcard->battled_cards.clear();
}
}
core.forced_attack = true;
core.attack_cancelable = TRUE;
core.attack_cost_paid = FALSE;
core.chain_attacker_id = 0;
core.chain_attack_target = 0;
returns.at<int32>(0) = 1;
reset_phase(infos.phase);
reset_phase(PHASE_BATTLE_START);
infos.phase = PHASE_BATTLE_STEP;
core.new_fchain.clear();
core.new_ochain.clear();
core.quick_f_chain.clear();
core.delayed_quick_tmp.clear();
auto message = pduel->new_message(MSG_NEW_PHASE);
message->write<uint16>(PHASE_BATTLE_START);
add_process(PROCESSOR_BATTLE_COMMAND, 1, 0, 0, 0, 0);
return FALSE;
}
case 1: {
reset_phase(infos.phase);
core.forced_attack = false;
infos.phase = core.units.begin()->arg1;
core.new_fchain.clear();
core.new_ochain.clear();
core.quick_f_chain.clear();
core.delayed_quick_tmp.clear();
for(uint8 p = 0; p < 2; ++p) {
for(auto& pcard : player[p].list_mzone) {
if(!pcard)
continue;
pcard->attack_announce_count = 0;
pcard->announce_count = 0;
pcard->attacked_count = 0;
pcard->announced_cards.clear();
pcard->attacked_cards.clear();
pcard->battled_cards.clear();
}
}
core.attacker = 0;
core.attack_target = 0;
auto message = pduel->new_message(MSG_NEW_PHASE);
message->write<uint16>(infos.phase);
return TRUE;
}
}
return TRUE;
}
int32 field::process_damage_step(uint16 step, uint32 new_attack) {
switch(step) {
case 0: {
if(core.effect_damage_step && !new_attack)
return TRUE;
core.effect_damage_step = 1;
card* tmp = core.attacker;
core.attacker = (card*)core.units.begin()->peffect;
core.units.begin()->peffect = (effect*)tmp;
tmp = core.attack_target;
core.attack_target = (card*)core.units.begin()->ptarget;
core.units.begin()->ptarget = (group*)tmp;
core.units.begin()->arg1 = infos.phase;
if(core.attacker->current.location != LOCATION_MZONE || (core.attack_target && core.attack_target->current.location != LOCATION_MZONE)) {
core.units.begin()->step = 2;
return FALSE;
}
if(new_attack) {
core.attack_state_count[infos.turn_player]++;
core.battled_count[infos.turn_player]++;
check_card_counter(core.attacker, 5, infos.turn_player);
}
core.attacker->announced_cards.addcard(core.attack_target);
attack_all_target_check();
auto message = pduel->new_message(MSG_ATTACK);
message->write(core.attacker->get_info_location());
if(core.attack_target) {
message->write(core.attack_target->get_info_location());
} else {
message->write(loc_info{});
}
infos.phase = PHASE_DAMAGE;
message = pduel->new_message(MSG_DAMAGE_STEP_START);
core.pre_field[0] = core.attacker->fieldid_r;
core.attacker->attacked_count++;
if(core.attack_target) {
core.pre_field[1] = core.attack_target->fieldid_r;
if(core.attack_target->is_position(POS_FACEDOWN)) {
change_position(core.attack_target, 0, PLAYER_NONE, core.attack_target->current.position >> 1, 0, TRUE);
adjust_all();
}
} else
core.pre_field[1] = 0;
return FALSE;
}
case 1: {
infos.phase = PHASE_DAMAGE_CAL;
add_process(PROCESSOR_BATTLE_COMMAND, 26, 0, 0, 0, 0);
core.units.begin()->step = 2;
core.reserved = core.units.front();
return TRUE;
}
case 2: {
core.effect_damage_step = 2;
add_process(PROCESSOR_BATTLE_COMMAND, 32, 0, (group*)core.units.begin()->ptr1, 0, 0);
return FALSE;
}
case 3: {
core.attacker = (card*)core.units.begin()->peffect;
core.attack_target = (card*)core.units.begin()->ptarget;
if(core.attacker)
core.attacker->set_status(STATUS_ATTACK_CANCELED, TRUE);
if(core.attack_target)
core.attack_target->set_status(STATUS_ATTACK_CANCELED, TRUE);
core.effect_damage_step = 0;
infos.phase = core.units.begin()->arg1;
return TRUE;
}
}
return TRUE;
}
void field::calculate_battle_damage(effect** pdamchange, card** preason_card, uint8* battle_destroyed) {
uint32 aa = core.attacker->get_attack(), ad = core.attacker->get_defense();
uint32 da = 0, dd = 0, a = aa, d;
uint8 pa = core.attacker->current.controler, pd;
uint8 damp = 0;
effect* damchange = 0;
card* reason_card = 0;
uint8 bd[2] = {FALSE, FALSE};
bool pierce = false;
core.battle_damage[0] = core.battle_damage[1] = 0;
if(core.attacker->is_position(POS_FACEUP_DEFENSE)) {
effect* defattack = core.attacker->is_affected_by_effect(EFFECT_DEFENSE_ATTACK);
if(defattack && defattack->get_value(core.attacker))
a = ad;
}
effect* battstat = core.attacker->is_affected_by_effect(EFFECT_CHANGE_BATTLE_STAT);
if(battstat)
a = battstat->get_value(core.attacker);
if(core.attack_target) {
da = core.attack_target->get_attack();
dd = core.attack_target->get_defense();
pd = core.attack_target->current.controler;
battstat = core.attack_target->is_affected_by_effect(EFFECT_CHANGE_BATTLE_STAT);
if(battstat)
d = battstat->get_value(core.attack_target);
else if (core.attack_target->is_position(POS_ATTACK))
d = da;
else
d = dd;
if(core.attack_target->is_position(POS_ATTACK)) {
if(a > d) {
damp = pd;
core.battle_damage[damp] = a - d;
reason_card = core.attacker;
bd[1] = TRUE;
} else if(a < d) {
damp = pa;
core.battle_damage[damp] = d - a;
reason_card = core.attack_target;
bd[0] = TRUE;
} else {
if(a != 0 || is_flag(DUEL_0_ATK_DESTROYED)) {
bd[0] = TRUE;
bd[1] = TRUE;
}
}
} else {
if(a > d) {
effect_set eset;
core.attacker->filter_effect(EFFECT_PIERCE, &eset);
if(eset.size()) {
pierce = true;
uint8 dp[2] = {};
for(const auto& peff : eset)
dp[1 - peff->get_handler_player()] = 1;
if(dp[0])
core.battle_damage[0] = a - d;
if(dp[1])
core.battle_damage[1] = a - d;
bool double_damage = false;
//bool half_damage = false;
for(const auto& peff : eset) {
if(peff->get_value() == static_cast<int32>(DOUBLE_DAMAGE))
double_damage = true;
//if(peff->get_value() == HALF_DAMAGE)
// half_damage = true;
}
//if(double_damage && half_damage) {
// double_damage = false;
// half_damage = false;
//}
if(double_damage) {
if(dp[0])
core.battle_damage[0] *= 2;
if(dp[1])
core.battle_damage[1] *= 2;
}
//if(half_damage) {
// if(dp[0])
// core.battle_damage[0] /= 2;
// if(dp[1])
// core.battle_damage[1] /= 2;
//}
bool both = dp[0] && dp[1];
if(!both) {
damp = dp[0] ? 0 : 1;
if(core.attacker->is_affected_by_effect(EFFECT_BOTH_BATTLE_DAMAGE)
|| core.attack_target->is_affected_by_effect(EFFECT_BOTH_BATTLE_DAMAGE)) {
core.battle_damage[1 - damp] = core.battle_damage[damp];
both = true;
}
}
effect* reflect[2] = {};
if((reflect[pd] = core.attack_target->is_affected_by_effect(EFFECT_REFLECT_BATTLE_DAMAGE, core.attacker)) == nullptr)
reflect[pd] = is_player_affected_by_effect(pd, EFFECT_REFLECT_BATTLE_DAMAGE);
if((reflect[1 - pd] = core.attacker->is_affected_by_effect(EFFECT_REFLECT_BATTLE_DAMAGE, core.attack_target)) == nullptr)
reflect[1 - pd] = is_player_affected_by_effect(1 - pd, EFFECT_REFLECT_BATTLE_DAMAGE);
bool also[2] = { false, false };
if(!both
&& (core.attack_target->is_affected_by_effect(EFFECT_ALSO_BATTLE_DAMAGE)
|| is_player_affected_by_effect(pd, EFFECT_ALSO_BATTLE_DAMAGE)))
also[pd] = true;
if(!both
&& (core.attacker->is_affected_by_effect(EFFECT_ALSO_BATTLE_DAMAGE)
|| is_player_affected_by_effect(1 - pd, EFFECT_ALSO_BATTLE_DAMAGE)))
also[1 - pd] = true;
if(both) {
//turn player's effect applies first
if(reflect[pa] && reflect[pa]->get_handler_player() == pa) {
core.battle_damage[1 - pa] += core.battle_damage[pa];
core.battle_damage[pa] = 0;
} else if(reflect[1 - pa] && reflect[1 - pa]->get_handler_player() == pa) {
core.battle_damage[pa] += core.battle_damage[1 - pa];
core.battle_damage[1 - pa] = 0;
} else if(reflect[pa] && reflect[pa]->get_handler_player() == 1 - pa) {
core.battle_damage[1 - pa] += core.battle_damage[pa];
core.battle_damage[pa] = 0;
} else if(reflect[1 - pa] && reflect[1 - pa]->get_handler_player() == 1 - pa) {
core.battle_damage[pa] += core.battle_damage[1 - pa];
core.battle_damage[1 - pa] = 0;
}
} else {
if(reflect[damp]) {
if(!also[1 - damp]) {
core.battle_damage[1 - damp] += core.battle_damage[damp];
core.battle_damage[damp] = 0;
} else {
core.battle_damage[1 - damp] += core.battle_damage[damp];
core.battle_damage[damp] = core.battle_damage[1 - damp];
}
} else if(also[damp]) {
if(!reflect[1 - damp]) {
core.battle_damage[1 - damp] += core.battle_damage[damp];
} else {
core.battle_damage[1 - damp] += core.battle_damage[damp];
core.battle_damage[damp] += core.battle_damage[1 - damp];
core.battle_damage[1 - damp] = 0;
}
}
}
eset.clear();
core.attacker->filter_effect(EFFECT_CHANGE_BATTLE_DAMAGE, &eset, FALSE);
core.attack_target->filter_effect(EFFECT_CHANGE_BATTLE_DAMAGE, &eset, FALSE);
filter_player_effect(pa, EFFECT_CHANGE_BATTLE_DAMAGE, &eset, FALSE);
filter_player_effect(1 - pa, EFFECT_CHANGE_BATTLE_DAMAGE, &eset, FALSE);
std::sort(eset.begin(), eset.end(), effect_sort_id);
for(uint8 p = 0; p < 2; ++p) {
bool double_dam = false;
bool half_dam = false;
int32 dam_value = -1;
for(const auto& peff : eset) {
int32 val = -1;
if(!peff->is_flag(EFFECT_FLAG_PLAYER_TARGET)) {
pduel->lua->add_param(p, PARAM_TYPE_INT);
pduel->lua->add_param(core.attacker, PARAM_TYPE_CARD);
val = peff->get_value(2);
} else if(peff->is_target_player(p)) {
pduel->lua->add_param(core.attacker, PARAM_TYPE_CARD);
val = peff->get_value(1);
}
if(val == 0) {
dam_value = 0;
break;
} else if(val > 0)
dam_value = val;
else if(val == static_cast<int32>(DOUBLE_DAMAGE))
double_dam = true;
else if(val == static_cast<int32>(HALF_DAMAGE))
half_dam = true;
}
if(double_dam && half_dam) {
double_dam = false;
half_dam = false;
}
if(double_dam)
core.battle_damage[p] *= 2;
if(half_dam)
core.battle_damage[p] /= 2;
if(dam_value >= 0 && core.battle_damage[p] > 0)
core.battle_damage[p] = dam_value;
}
if(core.attacker->is_affected_by_effect(EFFECT_NO_BATTLE_DAMAGE)
|| core.attack_target->is_affected_by_effect(EFFECT_AVOID_BATTLE_DAMAGE, core.attacker)
|| is_player_affected_by_effect(pd, EFFECT_AVOID_BATTLE_DAMAGE))
core.battle_damage[pd] = 0;
if(core.attack_target->is_affected_by_effect(EFFECT_NO_BATTLE_DAMAGE)
|| core.attacker->is_affected_by_effect(EFFECT_AVOID_BATTLE_DAMAGE, core.attack_target)
|| is_player_affected_by_effect(1 - pd, EFFECT_AVOID_BATTLE_DAMAGE))
core.battle_damage[1 - pd] = 0;
reason_card = core.attacker;
}
bd[1] = TRUE;
} else if(a < d) {
damp = pa;
core.battle_damage[damp] = d - a;
reason_card = core.attack_target;
}
}
} else {
if(a != 0) {
damp = 1 - pa;
core.battle_damage[damp] = a;
reason_card = core.attacker;
}
}
if(reason_card && !pierce
&& (damchange = reason_card->is_affected_by_effect(EFFECT_BATTLE_DAMAGE_TO_EFFECT)) == nullptr) {
card* dam_card = (reason_card == core.attacker) ? core.attack_target : core.attacker;
bool both = false;
if(reason_card->is_affected_by_effect(EFFECT_BOTH_BATTLE_DAMAGE)
|| (dam_card && dam_card->is_affected_by_effect(EFFECT_BOTH_BATTLE_DAMAGE))) {
core.battle_damage[1 - damp] = core.battle_damage[damp];
both = true;
}
effect* reflect[2] = {};
if(!dam_card || (reflect[damp] = dam_card->is_affected_by_effect(EFFECT_REFLECT_BATTLE_DAMAGE, reason_card)) == nullptr)
reflect[damp] = is_player_affected_by_effect(damp, EFFECT_REFLECT_BATTLE_DAMAGE);
if((reflect[1 - damp] = reason_card->is_affected_by_effect(EFFECT_REFLECT_BATTLE_DAMAGE, dam_card)) == nullptr)
reflect[1 - damp] = is_player_affected_by_effect(1 - damp, EFFECT_REFLECT_BATTLE_DAMAGE);
bool also[2] = { false, false };
if(!both
&& ((dam_card && dam_card->is_affected_by_effect(EFFECT_ALSO_BATTLE_DAMAGE))
|| is_player_affected_by_effect(damp, EFFECT_ALSO_BATTLE_DAMAGE)))
also[damp] = true;
if(!both
&& (reason_card->is_affected_by_effect(EFFECT_ALSO_BATTLE_DAMAGE)
|| is_player_affected_by_effect(1 - damp, EFFECT_ALSO_BATTLE_DAMAGE)))
also[1 - damp] = true;
if(both) {
//turn player's effect applies first
if(reflect[pa] && reflect[pa]->get_handler_player() == pa) {
core.battle_damage[1 - pa] += core.battle_damage[pa];
core.battle_damage[pa] = 0;
} else if(reflect[1 - pa] && reflect[1 - pa]->get_handler_player() == pa) {
core.battle_damage[pa] += core.battle_damage[1 - pa];
core.battle_damage[1 - pa] = 0;
} else if(reflect[pa] && reflect[pa]->get_handler_player() == 1 - pa) {
core.battle_damage[1 - pa] += core.battle_damage[pa];
core.battle_damage[pa] = 0;
} else if(reflect[1 - pa] && reflect[1 - pa]->get_handler_player() == 1 - pa) {
core.battle_damage[pa] += core.battle_damage[1 - pa];
core.battle_damage[1 - pa] = 0;
}
} else {
if(reflect[damp]) {
if(!also[1 - damp]) {
core.battle_damage[1 - damp] += core.battle_damage[damp];
core.battle_damage[damp] = 0;
} else {
core.battle_damage[1 - damp] += core.battle_damage[damp];
core.battle_damage[damp] = core.battle_damage[1 - damp];
}
} else if(also[damp]) {
if(!reflect[1 - damp]) {
core.battle_damage[1 - damp] += core.battle_damage[damp];
} else {
core.battle_damage[1 - damp] += core.battle_damage[damp];
core.battle_damage[damp] += core.battle_damage[1 - damp];
core.battle_damage[1 - damp] = 0;
}
}
}
effect_set eset;
reason_card->filter_effect(EFFECT_CHANGE_BATTLE_DAMAGE, &eset, FALSE);
if(dam_card)
dam_card->filter_effect(EFFECT_CHANGE_BATTLE_DAMAGE, &eset, FALSE);
filter_player_effect(damp, EFFECT_CHANGE_BATTLE_DAMAGE, &eset, FALSE);
filter_player_effect(1 - damp, EFFECT_CHANGE_BATTLE_DAMAGE, &eset, FALSE);
std::sort(eset.begin(), eset.end(), effect_sort_id);
for(uint8 p = 0; p < 2; ++p) {
bool double_dam = false;
bool half_dam = false;
int32 dam_value = -1;
for(const auto& peff : eset) {
int32 val = -1;
if(!peff->is_flag(EFFECT_FLAG_PLAYER_TARGET)) {
pduel->lua->add_param(p, PARAM_TYPE_INT);
pduel->lua->add_param(reason_card, PARAM_TYPE_CARD);
val = peff->get_value(2);
} else if(peff->is_target_player(p)) {
pduel->lua->add_param(reason_card, PARAM_TYPE_CARD);
val = peff->get_value(1);
}
if(val == 0) {
dam_value = 0;
break;
} else if(val > 0)
dam_value = val;
else if(val == static_cast<int32>(DOUBLE_DAMAGE))
double_dam = true;
else if(val == static_cast<int32>(HALF_DAMAGE))
half_dam = true;
}
if(double_dam && half_dam) {
double_dam = false;
half_dam = false;
}
if(double_dam)
core.battle_damage[p] *= 2;
if(half_dam)
core.battle_damage[p] /= 2;
if(dam_value >= 0 && core.battle_damage[p] > 0)
core.battle_damage[p] = dam_value;
}
if(reason_card->is_affected_by_effect(EFFECT_NO_BATTLE_DAMAGE)
|| (dam_card && dam_card->is_affected_by_effect(EFFECT_AVOID_BATTLE_DAMAGE, reason_card))
|| is_player_affected_by_effect(damp, EFFECT_AVOID_BATTLE_DAMAGE))
core.battle_damage[damp] = 0;
if((dam_card && dam_card->is_affected_by_effect(EFFECT_NO_BATTLE_DAMAGE))
|| reason_card->is_affected_by_effect(EFFECT_AVOID_BATTLE_DAMAGE, dam_card)
|| is_player_affected_by_effect(1 - damp, EFFECT_AVOID_BATTLE_DAMAGE))
core.battle_damage[1 - damp] = 0;
}
if(!core.battle_damage[damp] && !core.battle_damage[1 - damp])
reason_card = 0;
if(pdamchange)
*pdamchange = damchange;
if(preason_card)
*preason_card = reason_card;
if(battle_destroyed) {
battle_destroyed[0] = bd[0];
battle_destroyed[1] = bd[1];
}
}
int32 field::process_turn(uint16 step, uint8 turn_player) {
switch(step) {
case 0: {
//Pre Draw
for(const auto& ev : core.used_event) {
if(ev.event_cards)
pduel->delete_group(ev.event_cards);
}
core.used_event.clear();
for(auto& peffect : core.reseted_effects) {
pduel->delete_effect(peffect);
}
core.reseted_effects.clear();
core.effect_count_code.clear();
for(uint8 p = 0; p < 2; ++p) {
for(auto& pcard : player[p].list_mzone) {
if(!pcard)
continue;
pcard->set_status(STATUS_SUMMON_TURN, FALSE);
pcard->set_status(STATUS_FLIP_SUMMON_TURN, FALSE);
pcard->set_status(STATUS_SPSUMMON_TURN, FALSE);
pcard->set_status(STATUS_SET_TURN, FALSE);
pcard->set_status(STATUS_FORM_CHANGED, FALSE);
pcard->indestructable_effects.clear();
pcard->attack_announce_count = 0;
pcard->announce_count = 0;
pcard->attacked_count = 0;
pcard->announced_cards.clear();
pcard->attacked_cards.clear();
pcard->battled_cards.clear();
pcard->attack_all_target = TRUE;
}
for(auto& pcard : player[p].list_szone) {
if(!pcard)
continue;
pcard->set_status(STATUS_SET_TURN, FALSE);
pcard->indestructable_effects.clear();
}
core.summon_state_count[p] = 0;
core.normalsummon_state_count[p] = 0;
core.flipsummon_state_count[p] = 0;
core.spsummon_state_count[p] = 0;
core.spsummon_state_count_rst[p] = 0;
core.attack_state_count[p] = 0;
core.battle_phase_count[p] = 0;
core.battled_count[p] = 0;
core.summon_count[p] = 0;
core.extra_summon[p] = 0;
core.spsummon_once_map[p].clear();
core.spsummon_once_map_rst[p].clear();
if (player[p].recharge)
next_player(p);
}
core.force_turn_end = false;
core.spsummon_rst = false;
for(auto& peffect : effects.rechargeable)
if(!peffect->is_flag(EFFECT_FLAG_NO_TURN_RESET))
peffect->recharge();
for(auto& iter : core.summon_counter)
iter.second.second = 0;
for(auto& iter : core.normalsummon_counter)
iter.second.second = 0;
for(auto& iter : core.spsummon_counter)
iter.second.second = 0;
for(auto& iter : core.flipsummon_counter)
iter.second.second = 0;
for(auto& iter : core.attack_counter)
iter.second.second = 0;
for(auto& iter : core.chain_counter)
iter.second.second = 0;
if(core.global_flag & GLOBALFLAG_SPSUMMON_COUNT) {
for(auto& peffect : effects.spsummon_count_eff) {
card* pcard = peffect->get_handler();
if(!peffect->is_flag(EFFECT_FLAG_NO_TURN_RESET)) {
pcard->spsummon_counter[0] = pcard->spsummon_counter[1] = 0;
pcard->spsummon_counter_rst[0] = pcard->spsummon_counter_rst[1] = 0;
}
}
}
infos.turn_id++;
infos.turn_id_by_player[turn_player]++;
infos.turn_player = turn_player;
auto message = pduel->new_message(MSG_NEW_TURN);
message->write<uint8>(turn_player);
if(!is_flag(DUEL_RELAY) && infos.turn_id != 1)
tag_swap(turn_player);
if(is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_TURN)) {
core.units.begin()->step = 17;
reset_phase(PHASE_DRAW);
reset_phase(PHASE_STANDBY);
reset_phase(PHASE_END);
adjust_all();
return FALSE;
}
infos.phase = PHASE_DRAW;
core.phase_action = FALSE;
core.hand_adjusted = FALSE;
raise_event((card*)0, EVENT_PHASE_START + PHASE_DRAW, 0, 0, 0, turn_player, 0);
process_instant_event();
adjust_all();
return FALSE;
}
case 1: {
core.new_fchain.clear();
core.new_ochain.clear();
core.quick_f_chain.clear();
core.delayed_quick_tmp.clear();
if(is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_DP) || core.force_turn_end) {
core.units.begin()->step = 2;
reset_phase(PHASE_DRAW);
adjust_all();
return FALSE;
}
auto message = pduel->new_message(MSG_NEW_PHASE);
message->write<uint16>(infos.phase);
raise_event((card*)0, EVENT_PREDRAW, 0, 0, 0, turn_player, 0);
process_instant_event();
message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_EVENT);
message->write<uint8>(turn_player);
message->write<uint64>(27);
if(core.new_fchain.size() || core.new_ochain.size())
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, 0);
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 2: {
// Draw, new ruling
if(is_flag(DUEL_1ST_TURN_DRAW) || (infos.turn_id > 1)) {
int32 count = get_draw_count(infos.turn_player);
if(count > 0 && is_flag(DUEL_DRAW_UNTIL_5)) {
count = std::max<int>(5 - player[turn_player].list_hand.size(), 1);
}
if(count > 0) {
draw(0, REASON_RULE, turn_player, turn_player, count);
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, 0);
}
}
add_process(PROCESSOR_PHASE_EVENT, 0, 0, 0, PHASE_DRAW, 0);
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 3: {
// EVENT_PHASE_PRESTART is removed
return FALSE;
}
case 4: {
//Standby Phase
infos.phase = PHASE_STANDBY;
core.phase_action = FALSE;
core.new_fchain.clear();
core.new_ochain.clear();
core.quick_f_chain.clear();
core.delayed_quick_tmp.clear();
if(is_flag(DUEL_NO_STANDBY_PHASE) || is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_SP) || core.force_turn_end) {
core.units.begin()->step = 5;
reset_phase(PHASE_STANDBY);
adjust_all();
return FALSE;
}
auto message = pduel->new_message(MSG_NEW_PHASE);
message->write<uint16>(infos.phase);
raise_event((card*)0, EVENT_PHASE_START + PHASE_STANDBY, 0, 0, 0, turn_player, 0);
process_instant_event();
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 5: {
// EVENT_PHASE_START + PHASE_STANDBY is a special case(c89642993)
if(core.new_fchain.size() || core.new_ochain.size() || core.instant_event.back().event_code != EVENT_PHASE_START + PHASE_STANDBY)
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, 0);
add_process(PROCESSOR_PHASE_EVENT, 0, 0, 0, PHASE_STANDBY, 0);
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 6: {
//Main1
infos.phase = PHASE_MAIN1;
core.phase_action = FALSE;
raise_event((card*)0, EVENT_PHASE_START + PHASE_MAIN1, 0, 0, 0, turn_player, 0);
process_instant_event();
adjust_all();
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 7: {
return FALSE;
}
case 8: {
core.new_fchain.clear();
core.new_ochain.clear();
core.quick_f_chain.clear();
core.delayed_quick_tmp.clear();
auto message = pduel->new_message(MSG_NEW_PHASE);
message->write<uint16>(infos.phase);
add_process(PROCESSOR_IDLE_COMMAND, 0, 0, 0, 0, 0);
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 9: {
if(returns.at<int32>(0) == 7) { // End Phase
core.units.begin()->step = 14;
return FALSE;
}
infos.phase = PHASE_BATTLE_START;
core.new_fchain.clear();
core.new_ochain.clear();
core.quick_f_chain.clear();
core.delayed_quick_tmp.clear();
core.phase_action = FALSE;
core.battle_phase_count[infos.turn_player]++;
auto message = pduel->new_message(MSG_NEW_PHASE);
message->write<uint16>(infos.phase);
// Show the texts to indicate that BP is entered and skipped
if(is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_BP) || core.force_turn_end) {
core.units.begin()->step = 14;
reset_phase(PHASE_BATTLE_START);
reset_phase(PHASE_BATTLE_STEP);
reset_phase(PHASE_BATTLE);
adjust_all();
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
raise_event((card*)0, EVENT_PHASE_START + PHASE_BATTLE_START, 0, 0, 0, turn_player, 0);
process_instant_event();
adjust_all();
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 10: {
add_process(PROCESSOR_PHASE_EVENT, 0, 0, 0, PHASE_BATTLE_START, 0);
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 11: {
infos.phase = PHASE_BATTLE_STEP;
core.new_fchain.clear();
core.new_ochain.clear();
core.quick_f_chain.clear();
core.delayed_quick_tmp.clear();
core.phase_action = FALSE;
core.chain_attack = FALSE;
add_process(PROCESSOR_BATTLE_COMMAND, 0, 0, 0, 0, 0);
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 12: {
if(core.units.begin()->arg2 == 0 && returns.at<int32>(1)) { // 2nd Battle Phase
core.units.begin()->arg2 = 1;
core.units.begin()->step = 8;
for(uint8 p = 0; p < 2; ++p) {
for(auto& pcard : player[p].list_mzone) {
if(!pcard)
continue;
pcard->attack_announce_count = 0;
pcard->announce_count = 0;
pcard->attacked_count = 0;
pcard->announced_cards.clear();
pcard->attacked_cards.clear();
pcard->battled_cards.clear();
}
}
return FALSE;
}
if(is_flag(DUEL_NO_MAIN_PHASE_2)) {
core.units.begin()->step = 14;
adjust_all();
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
core.skip_m2 = FALSE;
if(returns.at<int32>(0) == 3 || core.force_turn_end) { // End Phase
core.skip_m2 = TRUE;
}
//Main2
infos.phase = PHASE_MAIN2;
core.phase_action = FALSE;
raise_event((card*)0, EVENT_PHASE_START + PHASE_MAIN2, 0, 0, 0, turn_player, 0);
process_instant_event();
adjust_all();
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 13: {
if(core.new_fchain.size() || core.new_ochain.size())
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, 0);
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 14: {
core.new_fchain.clear();
core.new_ochain.clear();
core.quick_f_chain.clear();
core.delayed_quick_tmp.clear();
auto message = pduel->new_message(MSG_NEW_PHASE);
message->write<uint16>(infos.phase);
infos.can_shuffle = TRUE;
add_process(PROCESSOR_IDLE_COMMAND, 0, 0, 0, 0, 0);
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 15: {
//End Phase
infos.phase = PHASE_END;
core.phase_action = FALSE;
if(is_player_affected_by_effect(infos.turn_player, EFFECT_SKIP_EP)) {
core.units.begin()->step = 17;
reset_phase(PHASE_END);
adjust_all();
return FALSE;
}
auto message = pduel->new_message(MSG_NEW_PHASE);
message->write<uint16>(infos.phase);
raise_event((card*)0, EVENT_PHASE_START + PHASE_END, 0, 0, 0, turn_player, 0);
process_instant_event();
adjust_all();
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 16: {
if(core.new_fchain.size() || core.new_ochain.size())
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, 0, 0);
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 17: {
core.new_fchain.clear();
core.new_ochain.clear();
core.quick_f_chain.clear();
core.delayed_quick_tmp.clear();
add_process(PROCESSOR_PHASE_EVENT, 0, 0, 0, PHASE_END, 0);
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 18: {
raise_event((card*)0, EVENT_TURN_END, 0, 0, 0, turn_player, 0);
process_instant_event();
adjust_all();
/*if(core.set_forced_attack)
add_process(PROCESSOR_FORCED_BATTLE, 0, 0, 0, 0, 0);*/
return FALSE;
}
case 19: {
core.new_fchain.clear();
core.new_ochain.clear();
core.quick_f_chain.clear();
core.delayed_quick_tmp.clear();
core.units.begin()->step = -1;
core.units.begin()->arg1 = 1 - core.units.begin()->arg1;
return FALSE;
}
}
return TRUE;
}
int32 field::add_chain(uint16 step) {
switch (step) {
case 0: {
if (!core.new_chains.size())
return TRUE;
auto& clit = core.new_chains.front();
effect* peffect = clit.triggering_effect;
card* phandler = peffect->get_handler();
effect_set eset;
filter_player_effect(clit.triggering_player, EFFECT_ACTIVATE_COST, &eset);
for(const auto& peff : eset) {
pduel->lua->add_param(peff, PARAM_TYPE_EFFECT);
pduel->lua->add_param(clit.triggering_effect, PARAM_TYPE_EFFECT);
pduel->lua->add_param(clit.triggering_player, PARAM_TYPE_INT);
if(!pduel->lua->check_condition(peff->target, 3))
continue;
if(peff->operation) {
core.sub_solving_event.push_back(clit.evt);
add_process(PROCESSOR_EXECUTE_OPERATION, 0, peff, 0, clit.triggering_player, 0);
}
}
if(peffect->type & EFFECT_TYPE_ACTIVATE) {
int32 ecode = 0;
if(phandler->current.location == LOCATION_HAND) {
if(phandler->data.type & TYPE_TRAP)
ecode = EFFECT_TRAP_ACT_IN_HAND;
else if((phandler->data.type & TYPE_SPELL) && (phandler->data.type & TYPE_QUICKPLAY || phandler->is_affected_by_effect(EFFECT_BECOME_QUICK))
&& infos.turn_player != phandler->current.controler)
ecode = EFFECT_QP_ACT_IN_NTPHAND;
} else if(phandler->current.location == LOCATION_SZONE) {
if((phandler->data.type & TYPE_TRAP) && phandler->get_status(STATUS_SET_TURN))
ecode = EFFECT_TRAP_ACT_IN_SET_TURN;
if((phandler->data.type & TYPE_SPELL) && (phandler->data.type & TYPE_QUICKPLAY || phandler->is_affected_by_effect(EFFECT_BECOME_QUICK)) && phandler->get_status(STATUS_SET_TURN))
ecode = EFFECT_QP_ACT_IN_SET_TURN;
}
if(ecode) {
eset.clear();
phandler->filter_effect(ecode, &eset);
effect* pactin = 0;
for(const auto& peff : eset) {
if(!peff->is_flag(EFFECT_FLAG_COUNT_LIMIT)) {
pactin = peff;
break;
}
}
if(!pactin) {
for(const auto& peff : eset) {
if(peff->check_count_limit(phandler->current.controler)) {
peff->dec_count(phandler->current.controler);
break;
}
}
}
}
if(phandler->current.location == LOCATION_SZONE) {
phandler->set_status(STATUS_ACT_FROM_HAND, FALSE);
change_position(phandler, 0, phandler->current.controler, POS_FACEUP, 0);
} else {
uint32 zone = 0xff;
if(!(phandler->data.type & (TYPE_FIELD | TYPE_PENDULUM)) && peffect->is_flag(EFFECT_FLAG_LIMIT_ZONE)) {
pduel->lua->add_param(clit.triggering_player, PARAM_TYPE_INT);
pduel->lua->add_param(clit.evt.event_cards , PARAM_TYPE_GROUP);
pduel->lua->add_param(clit.evt.event_player, PARAM_TYPE_INT);
pduel->lua->add_param(clit.evt.event_value, PARAM_TYPE_INT);
pduel->lua->add_param(clit.evt.reason_effect , PARAM_TYPE_EFFECT);
pduel->lua->add_param(clit.evt.reason, PARAM_TYPE_INT);
pduel->lua->add_param(clit.evt.reason_player, PARAM_TYPE_INT);
zone = peffect->get_value(7);
if(!zone)
return TRUE;
}
int32 loc = LOCATION_SZONE;
if(phandler->current.location == LOCATION_HAND) {
phandler->set_status(STATUS_ACT_FROM_HAND, TRUE);
if(phandler->data.type & TYPE_PENDULUM) {
loc = LOCATION_PZONE;
} else if(phandler->data.type & TYPE_FIELD){
loc = LOCATION_FZONE;
} else {
loc = LOCATION_SZONE;
}
}
if(!peffect->value.Empty() && !peffect->is_flag(EFFECT_FLAG_LIMIT_ZONE))
loc = peffect->value.GetInt();
if(loc > 0) {
phandler->enable_field_effect(false);
if(loc == LOCATION_MZONE) {
move_to_field(phandler, phandler->current.controler, phandler->current.controler, loc, POS_FACEUP_ATTACK);
} else {
move_to_field(phandler, phandler->current.controler, phandler->current.controler, loc, POS_FACEUP, FALSE, 0, zone);
}
}
}
}
return FALSE;
}
case 1: {
auto& clit = core.new_chains.front();
effect* peffect = clit.triggering_effect;
card* phandler = peffect->get_handler();
if(peffect->type & EFFECT_TYPE_ACTIVATE) {
clit.set_triggering_state(phandler);
}
auto message = pduel->new_message(MSG_CHAINING);
message->write<uint32>(phandler->data.code);
message->write(phandler->get_info_location());
message->write<uint8>(clit.triggering_controler);
message->write<uint8>((uint8)clit.triggering_location);
message->write<uint32>(clit.triggering_sequence);
message->write<uint64>(peffect->description);
message->write<uint32>(core.current_chain.size() + 1);
core.chain_limit.clear();
peffect->card_type = phandler->get_type();
if((peffect->card_type & (TYPE_TRAP | TYPE_MONSTER)) == (TYPE_TRAP | TYPE_MONSTER))
peffect->card_type -= TYPE_TRAP;
peffect->set_active_type();
peffect->active_handler = peffect->handler->overlay_target;
clit.chain_count = static_cast<uint8>(core.current_chain.size()) + 1;
clit.target_cards = 0;
clit.target_player = PLAYER_NONE;
clit.target_param = 0;
clit.disable_reason = 0;
clit.disable_player = PLAYER_NONE;
clit.replace_op = 0;
if(phandler->current.location == LOCATION_HAND)
clit.flag |= CHAIN_HAND_EFFECT;
core.current_chain.push_back(clit);
check_chain_counter(peffect, clit.triggering_player, clit.chain_count);
// triggered events which are not caused by RaiseEvent create relation with the handler
if(!peffect->is_flag(EFFECT_FLAG_FIELD_ONLY) && (!(peffect->type & 0x2a0) || (peffect->code & EVENT_PHASE) == EVENT_PHASE)) {
phandler->create_relation(clit);
}
peffect->effect_owner = clit.triggering_player;
// DISABLE_CHAIN should be check before cost
effect* deffect;
if(!peffect->is_flag(EFFECT_FLAG_FIELD_ONLY) && phandler->is_has_relation(clit) && (deffect = phandler->is_affected_by_effect(EFFECT_DISABLE_EFFECT)) != nullptr) {
effect* negeff = pduel->new_effect();
negeff->owner = deffect->owner;
negeff->type = EFFECT_TYPE_SINGLE;
negeff->code = EFFECT_DISABLE_CHAIN;
negeff->value = clit.chain_id;
negeff->reset_flag = RESET_CHAIN | RESET_EVENT | deffect->get_value();
phandler->add_effect(negeff);
}
core.new_chains.pop_front();
return FALSE;
}
case 2: {
auto& clit = core.current_chain.back();
int32 playerid = clit.triggering_player;
effect* peffect = clit.triggering_effect;
if(!is_flag(DUEL_USE_TRAPS_IN_NEW_CHAIN) && get_cteffect(peffect, playerid, TRUE)) {
const bool damage_step = infos.phase == PHASE_DAMAGE && !peffect->is_flag(EFFECT_FLAG_DAMAGE_STEP);
const bool damage_cal = infos.phase == PHASE_DAMAGE_CAL && !peffect->is_flag(EFFECT_FLAG_DAMAGE_CAL);
if(damage_step || damage_cal) {
returns.at<int32>(0) = TRUE;
return FALSE;
}
add_process(PROCESSOR_SELECT_EFFECTYN, 0, 0, (group*)peffect->get_handler(), playerid, 94);
} else
returns.at<int32>(0) = FALSE;
return FALSE;
}
case 3: {
if(!returns.at<int32>(0)) {
core.select_chains.clear();
core.select_options.clear();
core.units.begin()->step = 4;
return FALSE;
}
if(core.select_chains.size() > 1) {
auto& clit = core.current_chain.back();
add_process(PROCESSOR_SELECT_OPTION, 0, 0, 0, clit.triggering_player, 0);
} else
returns.at<int32>(0) = 0;
return FALSE;
}
case 4: {
auto& clit = core.current_chain.back();
chain& ch = core.select_chains[returns.at<int32>(0)];
int32 playerid = clit.triggering_player;
effect* peffect = ch.triggering_effect;
card* phandler = peffect->get_handler();
auto message = pduel->new_message(MSG_HINT);
message->write<uint8>(HINT_OPSELECTED);
message->write<uint8>(playerid);
message->write<uint64>(returns.at<int32>(0) >= core.select_options.size() ? core.select_options[returns.at<int32>(0)] : 65);
clit.triggering_effect = peffect;
clit.evt = ch.evt;
phandler->create_relation(clit);
peffect->dec_count(playerid);
if(!(peffect->type & EFFECT_TYPE_ACTIVATE)) {
peffect->type |= EFFECT_TYPE_ACTIVATE;
clit.flag |= CHAIN_ACTIVATING;
}
core.select_chains.clear();
core.select_options.clear();
effect* deffect = pduel->new_effect();
deffect->owner = phandler;
deffect->code = 0;
deffect->type = EFFECT_TYPE_SINGLE;
deffect->flag[0] = EFFECT_FLAG_CANNOT_DISABLE | EFFECT_FLAG_CLIENT_HINT;
deffect->description = 65;
deffect->reset_flag = RESET_CHAIN;
phandler->add_effect(deffect);
return FALSE;
}
case 5: {
auto& clit = core.current_chain.back();
effect* peffect = clit.triggering_effect;
if(peffect->cost) {
core.sub_solving_event.push_back(clit.evt);
add_process(PROCESSOR_EXECUTE_COST, 0, peffect, 0, clit.triggering_player, 0);
}
return FALSE;
}
case 6: {
auto& clit = core.current_chain.back();
effect* peffect = clit.triggering_effect;
if(peffect->target) {
core.sub_solving_event.push_back(clit.evt);
add_process(PROCESSOR_EXECUTE_TARGET, 0, peffect, 0, clit.triggering_player, 0);
}
return FALSE;
}
case 7: {
break_effect(false);
auto& clit = core.current_chain.back();
effect* peffect = clit.triggering_effect;
card* phandler = peffect->get_handler();
if(clit.target_cards && clit.target_cards->container.size()) {
if(peffect->is_flag(EFFECT_FLAG_CARD_TARGET)) {
for(auto& pcard : clit.target_cards->container)
raise_single_event(pcard, 0, EVENT_BECOME_TARGET, peffect, 0, clit.triggering_player, 0, clit.chain_count);
process_single_event();
if(clit.target_cards->container.size())
raise_event(&clit.target_cards->container, EVENT_BECOME_TARGET, peffect, 0, clit.triggering_player, clit.triggering_player, clit.chain_count);
}
}
if(peffect->type & EFFECT_TYPE_ACTIVATE) {
core.leave_confirmed.insert(phandler);
if(!(phandler->data.type & (TYPE_CONTINUOUS | TYPE_FIELD | TYPE_EQUIP | TYPE_PENDULUM | TYPE_LINK))
&& !phandler->is_affected_by_effect(EFFECT_REMAIN_FIELD))
phandler->set_status(STATUS_LEAVE_CONFIRMED, TRUE);
}
if((phandler->get_type() & (TYPE_SPELL | TYPE_TRAP))
&& (phandler->get_type() & (TYPE_CONTINUOUS | TYPE_FIELD | TYPE_EQUIP | TYPE_PENDULUM | TYPE_LINK))
&& phandler->is_has_relation(clit) && phandler->current.location == LOCATION_SZONE
&& !peffect->is_flag(EFFECT_FLAG_FIELD_ONLY))
clit.flag |= CHAIN_CONTINUOUS_CARD;
core.phase_action = TRUE;
if(clit.opinfos.count(0x200) && clit.opinfos[0x200].op_count) {
if(is_flag(DUEL_CANNOT_SUMMON_OATH_OLD)) {
core.spsummon_rst = true;
set_spsummon_counter(clit.triggering_player, true, true);
if(clit.opinfos[0x200].op_player == PLAYER_ALL)
set_spsummon_counter(1 - clit.triggering_player, true, true);
}
if(is_flag(DUEL_SPSUMMON_ONCE_OLD_NEGATE) && (core.global_flag & GLOBALFLAG_SPSUMMON_ONCE)) {
auto& optarget = clit.opinfos[0x200];
if(optarget.op_cards) {
if(optarget.op_player == PLAYER_ALL) {
auto opit = optarget.op_cards->container.begin();
uint32 sumplayer = optarget.op_param;
if((*opit)->spsummon_code) {
core.spsummon_once_map[sumplayer][(*opit)->spsummon_code]++;
core.spsummon_once_map_rst[sumplayer][(*opit)->spsummon_code]++;
}
++opit;
if((*opit)->spsummon_code) {
core.spsummon_once_map[1 - sumplayer][(*opit)->spsummon_code]++;
core.spsummon_once_map_rst[1 - sumplayer][(*opit)->spsummon_code]++;
}
} else {
uint32 sumplayer = clit.triggering_player;
// genarally setting op_player is unnecessary when the effect targets cards
// in the case of CATEGORY_SPECIAL_SUMMON(with EFFECT_FLAG_CARD_TARGET), op_player=0x10
// indecates that it is the opponent that special summons the target monsters
if(peffect->is_flag(EFFECT_FLAG_CARD_TARGET) && optarget.op_player == 0x10)
sumplayer = 1 - sumplayer;
for(auto& pcard : optarget.op_cards->container) {
if(pcard->spsummon_code) {
core.spsummon_once_map[sumplayer][pcard->spsummon_code]++;
core.spsummon_once_map_rst[sumplayer][pcard->spsummon_code]++;
}
}
}
}
}
}
auto message = pduel->new_message(MSG_CHAINED);
message->write<uint8>(clit.chain_count);
raise_event(phandler, EVENT_CHAINING, peffect, 0, clit.triggering_player, clit.triggering_player, clit.chain_count);
process_instant_event();
core.just_sent_cards.clear();
core.real_chain_count++;
if(core.new_chains.size())
add_process(PROCESSOR_ADD_CHAIN, 0, 0, 0, 0, 0);
adjust_all();
return TRUE;
}
}
return TRUE;
}
int32 field::sort_chain(uint16 step, uint8 tp) {
switch(step) {
case 0: {
core.select_cards.clear();
if(tp)
for(auto clit = core.tpchain.begin(); clit != core.tpchain.end(); ++clit)
core.select_cards.push_back(clit->triggering_effect->get_handler());
else
for(auto clit = core.ntpchain.begin(); clit != core.ntpchain.end(); ++clit)
core.select_cards.push_back(clit->triggering_effect->get_handler());
add_process(PROCESSOR_SORT_CARD, 0, 0, 0, tp ? infos.turn_player : (1 - infos.turn_player), 1);
return FALSE;
}
case 1: {
if(returns.at<int8>(0) == -1)
return TRUE;
if(tp) {
chain_array ch(core.tpchain.size());
int i = 0;
for(const auto& _ch : core.tpchain)
ch[returns.at<int8>(i++)] = _ch;
core.tpchain.clear();
for(const auto& _ch : ch)
core.tpchain.push_back(_ch);
} else {
chain_array ch(core.ntpchain.size());
int i = 0;
for(const auto& _ch : core.ntpchain)
ch[returns.at<int8>(i++)] = _ch;
core.ntpchain.clear();
for(const auto& _ch : ch)
core.ntpchain.push_back(_ch);
}
return TRUE;
}
}
return TRUE;
}
void field::solve_continuous(uint8 playerid, effect* peffect, const tevent& e) {
chain newchain;
newchain.chain_id = 0;
newchain.chain_count = 0;
newchain.triggering_effect = peffect;
newchain.triggering_player = playerid;
newchain.evt = e;
newchain.target_cards = 0;
newchain.target_player = PLAYER_NONE;
newchain.target_param = 0;
newchain.disable_player = PLAYER_NONE;
newchain.disable_reason = 0;
newchain.flag = 0;
core.sub_solving_continuous.push_back(newchain);
add_process(PROCESSOR_SOLVE_CONTINUOUS, 0, 0, 0, 0, 0);
}
int32 field::solve_continuous(uint16 step) {
switch(step) {
case 0: {
core.solving_continuous.splice(core.solving_continuous.begin(), core.sub_solving_continuous);
auto& clit = core.solving_continuous.front();
effect* peffect = clit.triggering_effect;
uint8 triggering_player = clit.triggering_player;
if(!peffect->check_count_limit(triggering_player)) {
core.solving_continuous.pop_front();
return TRUE;
}
core.continuous_chain.push_back(clit);
if(peffect->is_flag(EFFECT_FLAG_DELAY) || (!(peffect->code & 0x10030000) && (peffect->code & (EVENT_PHASE | EVENT_PHASE_START))))
core.conti_solving = TRUE;
core.units.begin()->ptarget = (group*)core.reason_effect;
core.units.begin()->arg2 = core.reason_player;
if(!peffect->target)
return FALSE;
core.sub_solving_event.push_back(clit.evt);
add_process(PROCESSOR_EXECUTE_TARGET, 0, peffect, 0, triggering_player, 0);
return FALSE;
}
case 1: {
return FALSE;
}
case 2: {
auto& clit = core.solving_continuous.front();
effect* peffect = clit.triggering_effect;
uint8 triggering_player = clit.triggering_player;
if(!peffect->operation)
return FALSE;
peffect->dec_count(triggering_player);
core.sub_solving_event.push_back(clit.evt);
add_process(PROCESSOR_EXECUTE_OPERATION, 0, peffect, 0, triggering_player, 0);
return FALSE;
}
case 3: {
auto& clit = core.solving_continuous.front();
effect* peffect = clit.triggering_effect;
// UNUSED VARIABLE
// uint8 triggering_player = clit.triggering_player;
core.reason_effect = (effect*)core.units.begin()->ptarget;
core.reason_player = core.units.begin()->arg2;
if(core.continuous_chain.back().target_cards)
pduel->delete_group(core.continuous_chain.back().target_cards);
for(auto& oit : core.continuous_chain.back().opinfos) {
if(oit.second.op_cards)
pduel->delete_group(oit.second.op_cards);
}
core.continuous_chain.pop_back();
core.solving_continuous.pop_front();
if(peffect->is_flag(EFFECT_FLAG_DELAY) || (!(peffect->code & 0x10030000) && (peffect->code & (EVENT_PHASE | EVENT_PHASE_START)))) {
core.conti_solving = FALSE;
adjust_all();
return FALSE;
}
return TRUE;
}
case 4: {
if(core.conti_player == PLAYER_NONE)
core.conti_player = infos.turn_player;
if(core.conti_player == infos.turn_player) {
if(core.delayed_continuous_tp.size()) {
core.sub_solving_continuous.splice(core.sub_solving_continuous.end(), core.delayed_continuous_tp, core.delayed_continuous_tp.begin());
add_process(PROCESSOR_SOLVE_CONTINUOUS, 0, 0, 0, 0, 0);
} else
core.conti_player = 1 - infos.turn_player;
}
if(core.conti_player == 1 - infos.turn_player) {
if(core.delayed_continuous_ntp.size()) {
core.sub_solving_continuous.splice(core.sub_solving_continuous.end(), core.delayed_continuous_ntp, core.delayed_continuous_ntp.begin());
add_process(PROCESSOR_SOLVE_CONTINUOUS, 0, 0, 0, 0, 0);
} else if(core.delayed_continuous_tp.size()) {
core.conti_player = infos.turn_player;
core.sub_solving_continuous.splice(core.sub_solving_continuous.end(), core.delayed_continuous_tp, core.delayed_continuous_tp.begin());
add_process(PROCESSOR_SOLVE_CONTINUOUS, 0, 0, 0, 0, 0);
} else
core.conti_player = PLAYER_NONE;
}
return TRUE;
}
}
return TRUE;
}
int32 field::solve_chain(uint16 step, uint32 chainend_arg1, uint32 chainend_arg2) {
if(core.current_chain.size() == 0 && step == 0)
return TRUE;
auto cait = core.current_chain.rbegin();
switch(step) {
case 0: {
if(core.spsummon_rst) {
if(is_flag(DUEL_CANNOT_SUMMON_OATH_OLD)) {
set_spsummon_counter(0, false, true);
set_spsummon_counter(1, false, true);
core.spsummon_rst = false;
}
if(is_flag(DUEL_SPSUMMON_ONCE_OLD_NEGATE)) {
for(int plr = 0; plr < 2; ++plr) {
for(auto& iter : core.spsummon_once_map[plr]) {
auto spcode = iter.first;
core.spsummon_once_map[plr][spcode] -= core.spsummon_once_map_rst[plr][spcode];
core.spsummon_once_map_rst[plr][spcode] = 0;
}
}
}
}
auto message = pduel->new_message(MSG_CHAIN_SOLVING);
message->write<uint8>(cait->chain_count);
add_to_disable_check_list(cait->triggering_effect->get_handler());
adjust_instant();
raise_event((card*)0, EVENT_CHAIN_ACTIVATING, cait->triggering_effect, 0, cait->triggering_player, cait->triggering_player, cait->chain_count);
process_instant_event();
return FALSE;
}
case 1: {
effect* peffect = cait->triggering_effect;
if(cait->flag & CHAIN_DISABLE_ACTIVATE && is_chain_negatable(cait->chain_count)) {
remove_oath_effect(peffect);
if(peffect->is_flag(EFFECT_FLAG_COUNT_LIMIT) && (peffect->count_flag & EFFECT_COUNT_CODE_OATH)) {
dec_effect_code(peffect->count_code, peffect->count_flag, cait->triggering_player);
}
check_chain_counter(peffect, cait->triggering_player, cait->chain_count, true);
core.new_fchain.remove_if([chaincount = cait->chain_count](chain ch) { return ch.evt.event_code == EVENT_CHAINING && ch.evt.event_value == chaincount; });
core.new_ochain.remove_if([chaincount = cait->chain_count](chain ch) { return ch.evt.event_code == EVENT_CHAINING && ch.evt.event_value == chaincount; });
raise_event((card*)0, EVENT_CHAIN_NEGATED, peffect, 0, cait->triggering_player, cait->triggering_player, cait->chain_count);
process_instant_event();
core.units.begin()->step = 9;
return FALSE;
}
release_oath_relation(peffect);
break_effect();
core.chain_solving = TRUE;
raise_event((card*)0, EVENT_CHAIN_SOLVING, peffect, 0, cait->triggering_player, cait->triggering_player, cait->chain_count);
process_instant_event();
return FALSE;
}
case 2: {
core.spsummon_state_count_tmp[0] = core.spsummon_state_count[0];
core.spsummon_state_count_tmp[1] = core.spsummon_state_count[1];
effect* peffect = cait->triggering_effect;
card* pcard = peffect->get_handler();
if((peffect->type & EFFECT_TYPE_ACTIVATE) && pcard->is_has_relation(*cait)) {
pcard->enable_field_effect(true);
if(is_flag(DUEL_1_FACEUP_FIELD)) {
if(pcard->data.type & TYPE_FIELD) {
card* fscard = player[1 - pcard->current.controler].list_szone[5];
if(fscard && fscard->is_position(POS_FACEUP))
fscard->enable_field_effect(false);
}
}
adjust_instant();
}
// creating continuous target: peffect->is_flag(EFFECT_FLAG_CONTINUOUS_TARGET) && !cait->replace_op
// operation function creating continuous target should be executed even when disabled
if(is_chain_disablable(cait->chain_count) && (!peffect->is_flag(EFFECT_FLAG_CONTINUOUS_TARGET) || cait->replace_op)) {
if(is_chain_disabled(cait->chain_count) || (pcard->get_status(STATUS_DISABLED | STATUS_FORBIDDEN) && pcard->is_has_relation(*cait))) {
if(!(cait->flag & CHAIN_DISABLE_EFFECT)) {
auto message = pduel->new_message(MSG_CHAIN_DISABLED);
message->write<uint8>(cait->chain_count);
}
raise_event((card*)0, EVENT_CHAIN_DISABLED, peffect, 0, cait->triggering_player, cait->triggering_player, cait->chain_count);
process_instant_event();
core.units.begin()->step = 3;
return FALSE;
}
}
if(cait->replace_op) {
core.units.begin()->arg4 = TRUE;
cait->tmp_replace_reserve.swap(cait->triggering_effect->operation);
cait->triggering_effect->operation = cait->replace_op;
} else
core.units.begin()->arg4 = 0;
if((cait->flag & CHAIN_CONTINUOUS_CARD) && !pcard->is_has_relation(*cait))
return FALSE;
if(cait->triggering_effect->operation) {
core.sub_solving_event.push_back(cait->evt);
add_process(PROCESSOR_EXECUTE_OPERATION, 0, cait->triggering_effect, 0, cait->triggering_player, 0);
}
return FALSE;
}
case 3: {
effect* peffect = cait->triggering_effect;
if(core.units.begin()->arg4) {
peffect->operation = std::move(cait->tmp_replace_reserve);
}
core.special_summoning.clear();
core.equiping_cards.clear();
return FALSE;
}
case 4: {
if(core.units.begin()->arg4 == 0) {
if(cait->opinfos.count(0x200) && cait->opinfos[0x200].op_count) {
if(is_flag(DUEL_CANNOT_SUMMON_OATH_OLD)) {
if(core.spsummon_state_count_tmp[cait->triggering_player] == core.spsummon_state_count[cait->triggering_player])
set_spsummon_counter(cait->triggering_player);
if(cait->opinfos[0x200].op_player == PLAYER_ALL && core.spsummon_state_count_tmp[1 - cait->triggering_player] == core.spsummon_state_count[1 - cait->triggering_player])
set_spsummon_counter(1 - cait->triggering_player);
}
if(is_flag(DUEL_CANNOT_SUMMON_OATH_OLD)) {
//sometimes it may add twice, only works for once per turn
auto& optarget = cait->opinfos[0x200];
if(optarget.op_cards) {
if(optarget.op_player == PLAYER_ALL) {
uint32 sumplayer = optarget.op_param;
if(is_flag(DUEL_SPSUMMON_ONCE_OLD_NEGATE) && (core.global_flag & GLOBALFLAG_SPSUMMON_ONCE)) {
auto opit = optarget.op_cards->container.begin();
if((*opit)->spsummon_code)
core.spsummon_once_map[sumplayer][(*opit)->spsummon_code]++;
++opit;
if((*opit)->spsummon_code)
core.spsummon_once_map[1 - sumplayer][(*opit)->spsummon_code]++;
}
auto opit = optarget.op_cards->container.begin();
check_card_counter(*opit, 3, sumplayer);
++opit;
check_card_counter(*opit, 3, 1 - sumplayer);
} else {
uint32 sumplayer = cait->triggering_player;
// genarally setting op_player is unnecessary when the effect targets cards
// in the case of CATEGORY_SPECIAL_SUMMON(with EFFECT_FLAG_CARD_TARGET), op_player=0x10
// indecates that it is the opponent that special summons the target monsters
if(cait->triggering_effect->is_flag(EFFECT_FLAG_CARD_TARGET) && optarget.op_player == 0x10)
sumplayer = 1 - sumplayer;
for(auto& ptarget : optarget.op_cards->container) {
if(is_flag(DUEL_SPSUMMON_ONCE_OLD_NEGATE) && (core.global_flag & GLOBALFLAG_SPSUMMON_ONCE) && ptarget->spsummon_code)
core.spsummon_once_map[sumplayer][ptarget->spsummon_code]++;
check_card_counter(ptarget, 3, sumplayer);
}
}
}
}
}
}
core.spsummon_state_count_tmp[0] = 0;
core.spsummon_state_count_tmp[1] = 0;
core.chain_solving = FALSE;
if(core.delayed_continuous_tp.size()) {
core.conti_player = infos.turn_player;
core.sub_solving_continuous.splice(core.sub_solving_continuous.end(), core.delayed_continuous_tp, core.delayed_continuous_tp.begin());
add_process(PROCESSOR_SOLVE_CONTINUOUS, 0, 0, 0, 0, 0);
} else if(core.delayed_continuous_ntp.size()) {
core.conti_player = 1 - infos.turn_player;
core.sub_solving_continuous.splice(core.sub_solving_continuous.end(), core.delayed_continuous_ntp, core.delayed_continuous_ntp.begin());
add_process(PROCESSOR_SOLVE_CONTINUOUS, 0, 0, 0, 0, 0);
} else
core.conti_player = PLAYER_NONE;
raise_event((card*)0, EVENT_CHAIN_SOLVED, cait->triggering_effect, 0, cait->triggering_player, cait->triggering_player, cait->chain_count);
adjust_disable_check_list();
process_instant_event();
core.units.begin()->step = 9;
return FALSE;
}
case 10: {
auto message = pduel->new_message(MSG_CHAIN_SOLVED);
message->write<uint8>(cait->chain_count);
effect* peffect = cait->triggering_effect;
card* pcard = peffect->get_handler();
if((peffect->type & EFFECT_TYPE_ACTIVATE) && (cait->flag & CHAIN_ACTIVATING))
peffect->type &= ~EFFECT_TYPE_ACTIVATE;
if((cait->flag & CHAIN_HAND_EFFECT) && !pcard->is_position(POS_FACEUP) && (pcard->current.location == LOCATION_HAND))
shuffle(pcard->current.controler, LOCATION_HAND);
if(cait->target_cards && cait->target_cards->container.size()) {
for(auto& ptarget : cait->target_cards->container)
ptarget->release_relation(*cait);
}
if((pcard->data.type & TYPE_EQUIP) && (peffect->type & EFFECT_TYPE_ACTIVATE)
&& !pcard->equiping_target && pcard->is_has_relation(*cait))
pcard->set_status(STATUS_LEAVE_CONFIRMED, TRUE);
if(is_flag(DUEL_1_FACEUP_FIELD)) {
if((pcard->data.type & TYPE_FIELD) && (peffect->type & EFFECT_TYPE_ACTIVATE)
&& !pcard->is_status(STATUS_LEAVE_CONFIRMED) && pcard->is_has_relation(*cait)) {
card* fscard = player[1 - pcard->current.controler].list_szone[5];
if(fscard && fscard->is_position(POS_FACEUP))
destroy(fscard, 0, REASON_RULE, 1 - pcard->current.controler);
}
}
peffect->active_type = 0;
peffect->active_handler = 0;
pcard->release_relation(*cait);
if(cait->target_cards)
pduel->delete_group(cait->target_cards);
for(auto& oit : cait->opinfos) {
if(oit.second.op_cards)
pduel->delete_group(oit.second.op_cards);
}
for(auto& cit : core.delayed_enable_set) {
if(cit->current.location == LOCATION_MZONE)
cit->enable_field_effect(true);
}
core.delayed_enable_set.clear();
adjust_all();
core.current_chain.pop_back();
if(--core.real_chain_count < 0)
core.real_chain_count = 0;
if(!core.current_chain.size()) {
core.chain_limit.clear();
return FALSE;
}
if(core.summoning_card || core.summoning_proc_group_type)
core.subunits.push_back(core.reserved);
core.summoning_card = 0;
core.summoning_proc_group_type = 0;
core.units.begin()->step = -1;
return FALSE;
}
case 11: {
for(auto cit = core.leave_confirmed.begin(); cit != core.leave_confirmed.end();) {
auto rm = cit++;
if(!(*rm)->is_status(STATUS_LEAVE_CONFIRMED))
core.leave_confirmed.erase(rm);
}
if(core.leave_confirmed.size())
send_to(&core.leave_confirmed, 0, REASON_RULE, PLAYER_NONE, PLAYER_NONE, LOCATION_GRAVE, 0, POS_FACEUP);
return FALSE;
}
case 12: {
core.used_event.splice(core.used_event.end(), core.point_event);
pduel->new_message(MSG_CHAIN_END);
core.chain_limit_p.clear();
reset_chain();
if(core.summoning_card || core.summoning_proc_group_type || core.effect_damage_step == 1)
core.subunits.push_back(core.reserved);
core.summoning_proc_group_type = 0;
core.summoning_card = nullptr;
return FALSE;
}
case 13: {
core.just_sent_cards.clear();
raise_event((card*)0, EVENT_CHAIN_END, 0, 0, 0, 0, 0);
process_instant_event();
adjust_all();
if(chainend_arg1 != 0x101 || chainend_arg2 != TRUE) {
core.hint_timing[0] |= TIMING_CHAIN_END;
core.hint_timing[1] |= TIMING_CHAIN_END;
add_process(PROCESSOR_POINT_EVENT, 0, 0, 0, chainend_arg1, chainend_arg2);
}
returns.at<int32>(0) = TRUE;
return TRUE;
}
}
return TRUE;
}
int32 field::break_effect(bool clear_sent) {
if(clear_sent)
core.just_sent_cards.clear();
core.hint_timing[0] &= TIMING_DAMAGE_STEP | TIMING_DAMAGE_CAL;
core.hint_timing[1] &= TIMING_DAMAGE_STEP | TIMING_DAMAGE_CAL;
for (auto chit = core.new_ochain.begin(); chit != core.new_ochain.end();) {
auto rm = chit++;
effect* peffect = rm->triggering_effect;
if (!peffect->is_flag(EFFECT_FLAG_DELAY)) {
if (peffect->is_flag(EFFECT_FLAG_FIELD_ONLY)
|| !(peffect->type & EFFECT_TYPE_FIELD) || peffect->in_range(*rm)) {
auto message = pduel->new_message(MSG_MISSED_EFFECT);
message->write(peffect->get_handler()->get_info_location());
message->write<uint32>(peffect->get_handler()->data.code);
}
core.new_ochain.erase(rm);
}
}
core.used_event.splice(core.used_event.end(), core.instant_event);
adjust_instant();
if(!is_flag(DUEL_RELAY) && !core.force_turn_end) {
uint32 winp = 5, rea = 1;
if(player[0].lp <= 0 && player[1].lp > 0 && !is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_LP)) {
winp = 1;
rea = 1;
}
if(core.overdraw[0] && !core.overdraw[1] && !is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_DECK)) {
winp = 1;
rea = 2;
}
if(player[1].lp <= 0 && player[0].lp > 0 && !is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_LP)) {
winp = 0;
rea = 1;
}
if(core.overdraw[1] && !core.overdraw[0] && !is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_DECK)) {
winp = 0;
rea = 2;
}
if(player[1].lp <= 0 && player[0].lp <= 0 && !(is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_LP) && is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_LP))) {
if(is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_LP))
winp = 0;
else if(is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_LP))
winp = 1;
else
winp = PLAYER_NONE;
rea = 1;
}
if(core.overdraw[1] && core.overdraw[0] && !(is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_DECK) && is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_DECK))) {
if(is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_DECK))
winp = 0;
else if(is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_DECK))
winp = 1;
else
winp = PLAYER_NONE;
rea = 2;
}
if(winp != 5) {
auto message = pduel->new_message(MSG_WIN);
message->write<uint8>(winp);
message->write<uint8>(rea);
core.overdraw[0] = core.overdraw[1] = FALSE;
core.win_player = 5;
core.win_reason = 0;
} else if(core.win_player != 5) {
auto message = pduel->new_message(MSG_WIN);
message->write<uint8>(core.win_player);
message->write<uint8>(core.win_reason);
core.win_player = 5;
core.win_reason = 0;
core.overdraw[0] = core.overdraw[1] = FALSE;
}
}
return 0;
}
void field::adjust_instant() {
infos.event_id++;
adjust_disable_check_list();
adjust_self_destroy_set();
}
void field::adjust_all() {
infos.event_id++;
core.readjust_map.clear();
add_process(PROCESSOR_ADJUST, 0, 0, 0, 0, 0);
}
void field::refresh_location_info_instant() {
effect_set eset;
uint32 dis1 = player[0].disabled_location | (player[1].disabled_location << 16);
player[0].disabled_location = 0;
player[1].disabled_location = 0;
filter_field_effect(EFFECT_DISABLE_FIELD, &eset);
for(const auto& peff : eset) {
uint32 value = peff->get_value();
player[0].disabled_location |= value & 0xff7f;
player[1].disabled_location |= (value >> 16) & 0xff7f;
}
eset.clear();
filter_field_effect(EFFECT_USE_EXTRA_MZONE, &eset);
for(const auto& peff : eset) {
uint32 p = peff->get_handler_player();
uint32 value = peff->get_value();
player[p].disabled_location |= (value >> 16) & 0x1f;
}
eset.clear();
filter_field_effect(EFFECT_USE_EXTRA_SZONE, &eset);
for(const auto& peff : eset) {
uint32 p = peff->get_handler_player();
uint32 value = peff->get_value();
player[p].disabled_location |= (value >> 8) & 0x1f00;
}
player[0].disabled_location |= (((player[1].disabled_location >> 5) & 1) << 6) | (((player[1].disabled_location >> 6) & 1) << 5);
player[1].disabled_location |= (((player[0].disabled_location >> 5) & 1) << 6) | (((player[0].disabled_location >> 6) & 1) << 5);
uint32 dis2 = player[0].disabled_location | (player[1].disabled_location << 16);
if(dis1 != dis2) {
auto message = pduel->new_message(MSG_FIELD_DISABLED);
message->write<uint32>(dis2);
}
}
int32 field::refresh_location_info(uint16 step) {
switch(step) {
case 0: {
effect_set eset;
if(is_flag(DUEL_3_COLUMNS_FIELD)) {
player[0].used_location |= 0x1111;
player[1].used_location |= 0x1111;
}
core.units.begin()->arg2 = player[0].disabled_location | (player[1].disabled_location << 16);
player[0].disabled_location = 0;
player[1].disabled_location = 0;
core.disfield_effects.clear();
core.extra_mzone_effects.clear();
core.extra_szone_effects.clear();
filter_field_effect(EFFECT_DISABLE_FIELD, &eset);
for(const auto& peff : eset) {
uint32 value = peff->get_value();
if(value && !peff->is_flag(EFFECT_FLAG_REPEAT)) {
player[0].disabled_location |= value & 0xff7f;
player[1].disabled_location |= (value >> 16) & 0xff7f;
} else
core.disfield_effects.push_back(peff);
}
eset.clear();
filter_field_effect(EFFECT_USE_EXTRA_MZONE, &eset);
for(const auto& peff : eset) {
uint32 p = peff->get_handler_player();
uint32 value = peff->get_value();
player[p].disabled_location |= (value >> 16) & 0x1f;
if((uint32)field_used_count[(value >> 16) & 0x1f] < (value & 0xffff))
core.extra_mzone_effects.push_back(peff);
}
eset.clear();
filter_field_effect(EFFECT_USE_EXTRA_SZONE, &eset);
for(const auto& peff : eset) {
uint32 p = peff->get_handler_player();
uint32 value = peff->get_value();
player[p].disabled_location |= (value >> 8) & 0x1f00;
if((uint32)field_used_count[(value >> 16) & 0x1f] < (value & 0xffff))
core.extra_szone_effects.push_back(peff);
}
return FALSE;
}
case 1: {
if(core.disfield_effects.size() == 0) {
core.units.begin()->step = 2;
return FALSE;
}
effect* peffect = core.disfield_effects[0];
core.units.begin()->peffect = peffect;
core.disfield_effects.erase(core.disfield_effects.begin());
if(!peffect->operation) {
peffect->value = 0x80;
core.units.begin()->step = 0;
return FALSE;
}
core.sub_solving_event.push_back(nil_event);
add_process(PROCESSOR_EXECUTE_OPERATION, 0, peffect, 0, peffect->get_handler_player(), 0);
return FALSE;
}
case 2: {
returns.at<int32>(0) &= 0xff7fff7f;
if(returns.at<int32>(0) == 0)
returns.at<int32>(0) = 0x80;
if(core.units.begin()->peffect->get_handler_player() == 0) {
core.units.begin()->peffect->value = returns.at<int32>(0);
player[0].disabled_location |= returns.at<int32>(0) & 0xff7f;
player[1].disabled_location |= (returns.at<int32>(0) >> 16) & 0xff7f;
} else {
core.units.begin()->peffect->value = ((returns.at<int32>(0) << 16) | (returns.at<int32>(0) >> 16));
player[1].disabled_location |= returns.at<int32>(0) & 0xff7f;
player[0].disabled_location |= (returns.at<int32>(0) >> 16) & 0xff7f;
}
core.units.begin()->step = 0;
return FALSE;
}
case 3: {
if(core.extra_mzone_effects.size() == 0) {
core.units.begin()->step = 4;
return FALSE;
}
effect* peffect = core.extra_mzone_effects[0];
core.units.begin()->peffect = peffect;
core.extra_mzone_effects.erase(core.extra_mzone_effects.begin());
uint32 p = peffect->get_handler_player();
uint32 mzone_flag = (player[p].disabled_location | player[p].used_location) & 0x1f;
if(mzone_flag == 0x1f) {
core.units.begin()->step = 4;
return FALSE;
}
int32 val = peffect->get_value();
int32 dis_count = (val & 0xffff) - field_used_count[(val >> 16) & 0x1f];
int32 empty_count = 5 - field_used_count[mzone_flag];
uint32 flag = mzone_flag | 0xffffffe0;
if(dis_count > empty_count)
dis_count = empty_count;
core.units.begin()->arg1 = dis_count;
add_process(PROCESSOR_SELECT_DISFIELD, 0, 0, 0, p, flag, dis_count);
return FALSE;
}
case 4: {
uint32 dis_count = core.units.begin()->arg1;
uint32 mzone_flag = 0;
uint8 pt = 0;
for(uint32 i = 0; i < dis_count; ++i) {
uint8 s = returns.at<int8>(pt + 2);
mzone_flag |= 0x1u << s;
pt += 3;
}
effect* peffect = core.units.begin()->peffect;
player[peffect->get_handler_player()].disabled_location |= mzone_flag;
peffect->value = (int32)(peffect->value.GetInt() | (mzone_flag << 16));
core.units.begin()->step = 2;
return FALSE;
}
case 5: {
if(core.extra_szone_effects.size() == 0) {
core.units.begin()->step = 6;
return FALSE;
}
effect* peffect = core.extra_szone_effects[0];
core.units.begin()->peffect = peffect;
core.extra_szone_effects.erase(core.extra_szone_effects.begin());
uint32 p = peffect->get_handler_player();
uint32 szone_flag = ((player[p].disabled_location | player[p].used_location) >> 8) & 0x1f;
if(szone_flag == 0x1f) {
core.units.begin()->step = 6;
return FALSE;
}
int32 val = peffect->get_value();
uint32 dis_count = (val & 0xffff) - field_used_count[(val >> 16) & 0x1f];
uint32 empty_count = 5 - field_used_count[szone_flag];
uint32 flag = (szone_flag << 8) | 0xffffe0ff;
if(dis_count > empty_count)
dis_count = empty_count;
core.units.begin()->arg1 = dis_count;
add_process(PROCESSOR_SELECT_DISFIELD, 0, 0, 0, p, flag, dis_count);
return FALSE;
}
case 6: {
uint32 dis_count = core.units.begin()->arg1;
uint32 szone_flag = 0;
uint8 pt = 0;
for(uint32 i = 0; i < dis_count; ++i) {
uint8 s = returns.at<int8>(pt + 2);
szone_flag |= 0x1u << s;
pt += 3;
}
effect* peffect = core.units.begin()->peffect;
player[peffect->get_handler_player()].disabled_location |= szone_flag << 8;
peffect->value = (int32)(peffect->value.GetInt() | (szone_flag << 16));
core.units.begin()->step = 4;
return FALSE;
}
case 7: {
player[0].disabled_location |= (((player[1].disabled_location >> 5) & 1) << 6) | (((player[1].disabled_location >> 6) & 1) << 5);
player[1].disabled_location |= (((player[0].disabled_location >> 5) & 1) << 6) | (((player[0].disabled_location >> 6) & 1) << 5);
uint32 dis = player[0].disabled_location | (player[1].disabled_location << 16);
if(dis != (uint32)core.units.begin()->arg2) {
auto message = pduel->new_message(MSG_FIELD_DISABLED);
message->write<uint32>(dis);
}
return TRUE;
}
}
return TRUE;
}
int32 field::adjust_step(uint16 step) {
switch(step) {
case 0: {
core.re_adjust = FALSE;
return FALSE;
}
case 1: {
//win check(deck=0 or lp=0)
if(!core.force_turn_end){
uint32 winp = 5, rea = 1;
if (player[0].lp <= 0 && player[1].lp > 0 && !is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_LP)) {
winp = 1;
rea = 1;
}
if (core.overdraw[0] && !core.overdraw[1] && !is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_DECK)) {
winp = 1;
rea = 2;
}
if (player[1].lp <= 0 && player[0].lp > 0 && !is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_LP)) {
winp = 0;
rea = 1;
}
if (core.overdraw[1] && !core.overdraw[0] && !is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_DECK)) {
winp = 0;
rea = 2;
}
if (player[1].lp <= 0 && player[0].lp <= 0 && !(is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_LP) && is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_LP))) {
if (is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_LP))
winp = 0;
else if (is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_LP))
winp = 1;
else
winp = PLAYER_NONE;
rea = 1;
}
if (core.overdraw[1] && core.overdraw[0] && !(is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_DECK) && is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_DECK))) {
if (is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_DECK))
winp = 0;
else if (is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_DECK))
winp = 1;
else
winp = PLAYER_NONE;
rea = 2;
}
if (is_flag(DUEL_RELAY)) {
if (winp == PLAYER_NONE) {
bool p1 = relay_check(0);
bool p2 = relay_check(1);
if (p1 && !p2)
winp = 0;
else if (!p1 && p2)
winp = 1;
else if (p1 && p2) {
winp = 5;
core.overdraw[0] = core.overdraw[1] = FALSE;
}
} else if (winp < PLAYER_NONE)
if (relay_check(1 - winp)) {
winp = 5;
core.overdraw[0] = core.overdraw[1] = FALSE;
}
}
if(winp != 5) {
auto message = pduel->new_message(MSG_WIN);
message->write<uint8>(winp);
message->write<uint8>(rea);
core.overdraw[0] = core.overdraw[1] = FALSE;
core.win_player = 5;
core.win_reason = 0;
} else if(core.win_player != 5) {
auto message = pduel->new_message(MSG_WIN);
message->write<uint8>(core.win_player);
message->write<uint8>(core.win_reason);
core.win_player = 5;
core.win_reason = 0;
core.overdraw[0] = core.overdraw[1] = FALSE;
}
}
return FALSE;
}
case 2: {
//disable check
uint8 tp = infos.turn_player;
for(uint8 p = 0; p < 2; ++p) {
for(auto& pcard : player[tp].list_mzone) {
if(pcard)
add_to_disable_check_list(pcard);
}
for(auto& pcard : player[tp].list_szone) {
if(pcard)
add_to_disable_check_list(pcard);
}
tp = 1 - tp;
}
adjust_disable_check_list();
add_process(PROCESSOR_REFRESH_LOC, 0, 0, 0, 0, 0);
return FALSE;
}
case 3: {
//trap monster
core.trap_monster_adjust_set[0].clear();
core.trap_monster_adjust_set[1].clear();
for(uint8 p = 0; p < 2; ++p) {
for(auto& pcard : player[p].list_mzone) {
if(!pcard) continue;
if((pcard->get_type() & TYPE_TRAPMONSTER) && pcard->is_affected_by_effect(EFFECT_DISABLE_TRAPMONSTER)) {
core.trap_monster_adjust_set[p].insert(pcard);
}
}
}
if(core.trap_monster_adjust_set[0].size() || core.trap_monster_adjust_set[1].size()) {
core.re_adjust = TRUE;
add_process(PROCESSOR_TRAP_MONSTER_ADJUST, 0, 0, 0, 0, 0);
}
return FALSE;
}
case 4: {
//control
core.control_adjust_set[0].clear();
core.control_adjust_set[1].clear();
card_set reason_cards;
for(uint8 p = 0; p < 2; ++p) {
for(auto& pcard : player[p].list_mzone) {
if(!pcard) continue;
uint8 cur = pcard->current.controler;
auto res = pcard->refresh_control_status();
uint8 ref = std::get<uint8>(res);
effect* peffect = std::get<effect*>(res);
if(cur != ref && pcard->is_capable_change_control()) {
core.control_adjust_set[p].insert(pcard);
if(peffect && (!(peffect->type & EFFECT_TYPE_SINGLE) || peffect->condition))
reason_cards.insert(peffect->get_handler());
}
}
}
if(core.control_adjust_set[0].size() || core.control_adjust_set[1].size()) {
core.re_adjust = TRUE;
get_control(&core.control_adjust_set[1 - infos.turn_player], 0, PLAYER_NONE, infos.turn_player, 0, 0, 0xff);
get_control(&core.control_adjust_set[infos.turn_player], 0, PLAYER_NONE, 1 - infos.turn_player, 0, 0, 0xff);
for(auto& rcard : reason_cards) {
core.readjust_map[rcard]++;
if(core.readjust_map[rcard] > 3)
destroy(rcard, 0, REASON_RULE, PLAYER_NONE);
}
}
core.last_control_changed_id = infos.field_id;
return FALSE;
}
case 5: {
//remove brainwashing
if(core.global_flag & GLOBALFLAG_BRAINWASHING_CHECK) {
core.control_adjust_set[0].clear();
core.control_adjust_set[1].clear();
effect_set eset;
filter_field_effect(EFFECT_REMOVE_BRAINWASHING, &eset, FALSE);
uint32 res = eset.size() ? TRUE : FALSE;
if(res) {
for(uint8 p = 0; p < 2; ++p) {
for(auto& pcard : player[p].list_mzone) {
if(pcard && pcard->is_affected_by_effect(EFFECT_REMOVE_BRAINWASHING)) {
//the opposite of pcard->check_control_effect()
auto pr = pcard->single_effect.equal_range(EFFECT_SET_CONTROL);
for(auto eit = pr.first; eit != pr.second;) {
effect* peffect = eit->second;
++eit;
if(!peffect->condition)
peffect->handler->remove_effect(peffect);
}
if(p != pcard->owner && pcard->is_capable_change_control())
core.control_adjust_set[p].insert(pcard);
}
}
}
}
core.remove_brainwashing = res;
if(core.control_adjust_set[0].size() || core.control_adjust_set[1].size()) {
core.re_adjust = TRUE;
get_control(&core.control_adjust_set[1 - infos.turn_player], 0, PLAYER_NONE, infos.turn_player, 0, 0, 0xff);
get_control(&core.control_adjust_set[infos.turn_player], 0, PLAYER_NONE, 1 - infos.turn_player, 0, 0, 0xff);
}
}
core.units.begin()->step = 7;
return FALSE;
}
case 8: {
if(adjust_grant_effect())
core.re_adjust = TRUE;
return FALSE;
}
case 9: {
if(core.selfdes_disabled) {
core.units.begin()->step = 10;
return FALSE;
}
//self destroy
adjust_self_destroy_set();
return FALSE;
}
case 10: {
//equip check
uint8 tp = infos.turn_player;
card_set destroy_set;
for(uint8 p = 0; p < 2; ++p) {
for(uint8 i = 0; i < 5; ++i) {
card* pcard = player[tp].list_szone[i];
if(pcard && pcard->equiping_target && !pcard->is_affected_by_effect(EFFECT_EQUIP_LIMIT, pcard->equiping_target))
destroy_set.insert(pcard);
}
tp = 1 - tp;
}
if(destroy_set.size()) {
core.re_adjust = TRUE;
destroy(&destroy_set, 0, REASON_RULE, PLAYER_NONE);
}
return FALSE;
}
case 11: {
//position
uint32 tp = infos.turn_player, pos;
card_set pos_adjust;
effect_set eset;
for(uint8 p = 0; p < 2; ++p) {
for(auto& pcard : player[tp].list_mzone) {
if(!pcard || ((pcard->data.type & TYPE_LINK) && (pcard->data.type & TYPE_MONSTER)) || pcard->is_affected_by_effect(EFFECT_CANNOT_CHANGE_POS_E))
continue;
eset.clear();
pcard->filter_effect(EFFECT_SET_POSITION, &eset);
if(eset.size()) {
pos = eset.back()->get_value();
if((pos & 0xff) != pcard->current.position) {
pos_adjust.insert(pcard);
pcard->position_param = pos;
if(pcard->is_status(STATUS_JUST_POS))
pcard->set_status(STATUS_CONTINUOUS_POS, TRUE);
else
pcard->set_status(STATUS_CONTINUOUS_POS, FALSE);
} else
pcard->set_status(STATUS_CONTINUOUS_POS, FALSE);
pcard->set_status(STATUS_JUST_POS, FALSE);
}
}
tp = 1 - tp;
}
if(pos_adjust.size()) {
core.re_adjust = TRUE;
group* ng = pduel->new_group();
ng->container.swap(pos_adjust);
ng->is_readonly = TRUE;
add_process(PROCESSOR_CHANGEPOS, 0, 0, ng, PLAYER_NONE, TRUE);
}
return FALSE;
}
case 12: {
//shuffle check
for(auto& pcard : player[0].list_hand) {
effect* pub = pcard->is_affected_by_effect(EFFECT_PUBLIC);
if(!pub && pcard->is_position(POS_FACEUP))
core.shuffle_hand_check[0] = TRUE;
pcard->current.position = pub ? POS_FACEUP : POS_FACEDOWN;
}
for(auto& pcard : player[1].list_hand) {
effect* pub = pcard->is_affected_by_effect(EFFECT_PUBLIC);
if(!pub && pcard->is_position(POS_FACEUP))
core.shuffle_hand_check[1] = TRUE;
pcard->current.position = pub ? POS_FACEUP : POS_FACEDOWN;
}
if(core.shuffle_hand_check[infos.turn_player])
shuffle(infos.turn_player, LOCATION_HAND);
if(core.shuffle_hand_check[1 - infos.turn_player])
shuffle(1 - infos.turn_player, LOCATION_HAND);
return FALSE;
}
case 13: {
//reverse_deck
effect_set eset;
uint32 res = 0;
if(core.global_flag & GLOBALFLAG_DECK_REVERSE_CHECK) {
filter_field_effect(EFFECT_REVERSE_DECK, &eset, FALSE);
res = eset.size() ? TRUE : FALSE;
if(core.deck_reversed ^ res) {
reverse_deck(0);
reverse_deck(1);
pduel->new_message(MSG_REVERSE_DECK);
if(res) {
if(player[0].list_main.size()) {
card* ptop = player[0].list_main.back();
auto message = pduel->new_message(MSG_DECK_TOP);
message->write<uint8>(0);
message->write<uint32>(0);
message->write<uint32>(ptop->data.code);
message->write<uint32>(ptop->current.position);
}
if(player[1].list_main.size()) {
card* ptop = player[1].list_main.back();
auto message = pduel->new_message(MSG_DECK_TOP);
message->write<uint8>(1);
message->write<uint32>(0);
message->write<uint32>(ptop->data.code);
message->write<uint32>(ptop->current.position);
}
}
}
core.deck_reversed = res;
}
return FALSE;
}
case 14: {
//attack cancel
card* attacker = core.attacker;
if(!attacker)
return FALSE;
if(!attacker->is_affected_by_effect(EFFECT_UNSTOPPABLE_ATTACK)) {
if(attacker->is_status(STATUS_ATTACK_CANCELED))
return FALSE;
}
if(infos.phase != PHASE_DAMAGE && infos.phase != PHASE_DAMAGE_CAL) {
if(!core.attacker->is_capable_attack()
|| core.attacker->current.controler != core.attacker->attack_controler
|| core.attacker->fieldid_r != core.pre_field[0]) {
attacker->set_status(STATUS_ATTACK_CANCELED, TRUE);
return FALSE;
}
if(core.attack_rollback)
return FALSE;
std::set<uint16> fidset;
for(auto& pcard : player[1 - infos.turn_player].list_mzone) {
if(pcard)
fidset.insert(pcard->fieldid_r);
}
if(fidset != core.opp_mzone || !confirm_attack_target())
core.attack_rollback = TRUE;
} else {
if(core.attacker->current.location != LOCATION_MZONE || core.attacker->fieldid_r != core.pre_field[0]
|| ((core.attacker->current.position & POS_DEFENSE) && !(core.attacker->is_affected_by_effect(EFFECT_DEFENSE_ATTACK)))
|| core.attacker->current.controler != core.attacker->attack_controler
|| (core.attack_target && (core.attack_target->current.location != LOCATION_MZONE
|| core.attack_target->current.controler != core.attack_target->attack_controler
|| core.attack_target->fieldid_r != core.pre_field[1])))
core.attacker->set_status(STATUS_ATTACK_CANCELED, TRUE);
}
return FALSE;
}
case 15: {
raise_event((card*)0, EVENT_ADJUST, 0, 0, PLAYER_NONE, PLAYER_NONE, 0);
process_instant_event();
return FALSE;
}
case 16: {
if(core.re_adjust) {
core.units.begin()->step = -1;
return FALSE;
}
if(core.shuffle_hand_check[0])
shuffle(0, LOCATION_HAND);
if(core.shuffle_hand_check[1])
shuffle(1, LOCATION_HAND);
if(core.shuffle_deck_check[0])
shuffle(0, LOCATION_DECK);
if(core.shuffle_deck_check[1])
shuffle(1, LOCATION_DECK);
return TRUE;
}
}
return TRUE;
}
int32 field::startup(uint16 step) {
switch(step) {
case 0: {
core.shuffle_hand_check[0] = FALSE;
core.shuffle_hand_check[1] = FALSE;
core.shuffle_deck_check[0] = FALSE;
core.shuffle_deck_check[1] = FALSE;
raise_event((card*)0, EVENT_STARTUP, 0, 0, 0, 0, 0);
process_instant_event();
return FALSE;
}
case 1: {
for(int p = 0; p < 2; p++) {
core.shuffle_hand_check[p] = FALSE;
core.shuffle_deck_check[p] = FALSE;
if(player[p].start_count > 0)
draw(0, REASON_RULE, PLAYER_NONE, p, player[p].start_count);
auto list_size = player[p].extra_lists_main.size();
for(size_t l = 0; l < list_size; l++) {
auto& main = player[p].extra_lists_main[l];
auto& hand = player[p].extra_lists_hand[l];
for(int i = 0; i < player[p].start_count && !main.empty(); ++i) {
card* pcard = main.back();
main.pop_back();
hand.push_back(pcard);
pcard->current.controler = p;
pcard->current.location = LOCATION_HAND;
pcard->current.sequence = hand.size() - 1;
pcard->current.position = POS_FACEDOWN;
}
}
}
add_process(PROCESSOR_TURN, 0, 0, 0, 0, 0);
return TRUE;
}
}
return TRUE;
}