Commit a3465f5b authored by DailyShana's avatar DailyShana Committed by GitHub

new ruling (#294)

* new trap monster rule

* new ruling of special summon once

* new ruling of (special) summon count in oath

* new ruling of trigger effect

trigger effect cannot be activated if the card is moved to other place

* update (extra) deck effect handling

including new rule that effect of face down card in extra deck cannot be activated unless explicitly written

* new trap monster rule: changing to face down

* new trap monster rule: disabled

* fix changing to face down of trap monster
parent 9974cf8f
......@@ -3593,7 +3593,8 @@ int32 card::is_control_can_be_changed(int32 ignore_mzone, uint32 zone) {
return FALSE;
if(!ignore_mzone && pduel->game_field->get_useable_count(this, 1 - current.controler, LOCATION_MZONE, current.controler, LOCATION_REASON_CONTROL, zone) <= 0)
return FALSE;
if((get_type() & TYPE_TRAPMONSTER) && pduel->game_field->get_useable_count(this, 1 - current.controler, LOCATION_SZONE, current.controler, LOCATION_REASON_CONTROL) <= 0)
if(pduel->game_field->core.duel_rule <= 4 && (get_type() & TYPE_TRAPMONSTER)
&& pduel->game_field->get_useable_count(this, 1 - current.controler, LOCATION_SZONE, current.controler, LOCATION_REASON_CONTROL) <= 0)
return FALSE;
if(is_affected_by_effect(EFFECT_CANNOT_CHANGE_CONTROL))
return FALSE;
......
......@@ -278,6 +278,13 @@ int32 effect::is_activateable(uint8 playerid, const tevent& e, int32 neglect_con
}
if(phandler->current.location == LOCATION_OVERLAY)
return FALSE;
if(phandler->current.location == LOCATION_DECK
|| pduel->game_field->core.duel_rule >= 5 && phandler->current.location == LOCATION_EXTRA && (phandler->current.position & POS_FACEDOWN)) {
if((type & EFFECT_TYPE_SINGLE) && code != EVENT_TO_DECK)
return FALSE;
if((type & EFFECT_TYPE_FIELD) && !(range & (LOCATION_DECK | LOCATION_EXTRA)))
return FALSE;
}
if((type & EFFECT_TYPE_FIELD) && (phandler->current.controler != playerid) && !is_flag(EFFECT_FLAG_BOTH_SIDE | EFFECT_FLAG_EVENT_PLAYER))
return FALSE;
if(phandler->is_status(STATUS_FORBIDDEN))
......
......@@ -3368,19 +3368,6 @@ int32 field::check_cteffect_hint(effect* peffect, uint8 playerid) {
}
return FALSE;
}
int32 field::check_deck_effect(chain& ch) const {
effect* peffect = ch.triggering_effect;
card* phandler = peffect->get_handler();
if(!peffect->is_flag(EFFECT_FLAG_FIELD_ONLY)
&& ch.triggering_location == LOCATION_DECK && (phandler->current.location & LOCATION_DECK)) {
if((peffect->type & EFFECT_TYPE_SINGLE) && !peffect->is_flag(EFFECT_FLAG_SINGLE_RANGE)
&& peffect->code == EVENT_TO_DECK || (peffect->range & LOCATION_DECK)) {
ch.flag |= CHAIN_DECK_EFFECT;
} else
return FALSE;
}
return TRUE;
}
int32 field::check_hand_trigger(chain& ch) {
effect* peffect = ch.triggering_effect;
card* phandler = peffect->get_handler();
......@@ -3396,23 +3383,6 @@ int32 field::check_hand_trigger(chain& ch) {
}
return TRUE;
}
int32 field::check_trigger_effect(const chain& ch) const {
effect* peffect = ch.triggering_effect;
card* phandler = peffect->get_handler();
if((peffect->type & EFFECT_TYPE_FIELD) && !phandler->is_has_relation(ch))
return FALSE;
if(peffect->code == EVENT_FLIP && infos.phase == PHASE_DAMAGE)
return TRUE;
if((phandler->current.location & LOCATION_DECK) && !(ch.flag & CHAIN_DECK_EFFECT))
return FALSE;
if((ch.triggering_location & (LOCATION_DECK | LOCATION_HAND | LOCATION_EXTRA))
&& (ch.triggering_position & POS_FACEDOWN))
return TRUE;
if(!(phandler->current.location & (LOCATION_DECK | LOCATION_HAND | LOCATION_EXTRA))
|| phandler->is_position(POS_FACEUP))
return TRUE;
return FALSE;
}
int32 field::check_spself_from_hand_trigger(const chain& ch) const {
effect* peffect = ch.triggering_effect;
uint8 tp = ch.triggering_player;
......
......@@ -219,6 +219,7 @@ struct processor {
card_set unique_destroy_set;
card_set self_destroy_set;
card_set self_tograve_set;
card_set trap_monster_adjust_set[2];
card_set release_cards;
card_set release_cards_ex;
card_set release_cards_ex_oneof;
......@@ -240,7 +241,6 @@ struct processor {
std::unordered_map<uint32, uint32> effect_count_code;
std::unordered_map<uint32, uint32> effect_count_code_duel;
std::unordered_map<uint32, uint32> spsummon_once_map[2];
std::unordered_map<uint32, uint32> spsummon_once_map_rst[2];
std::multimap<int32, card*, std::greater<int32>> xmaterial_lst;
ptr temp_var[4];
uint32 global_flag;
......@@ -484,9 +484,7 @@ public:
int32 get_cteffect(effect* peffect, int32 playerid, int32 store);
int32 get_cteffect_evt(effect* feffect, int32 playerid, const tevent& e, int32 store);
int32 check_cteffect_hint(effect* peffect, uint8 playerid);
int32 check_deck_effect(chain& ch) const;
int32 check_hand_trigger(chain& ch);
int32 check_trigger_effect(const chain& ch) const;
int32 check_spself_from_hand_trigger(const chain& ch) const;
int32 is_able_to_enter_bp();
......@@ -565,6 +563,7 @@ public:
int32 swap_control(uint16 step, effect* reason_effect, uint8 reason_player, group* targets1, group* targets2, uint16 reset_phase, uint8 reset_count);
int32 control_adjust(uint16 step);
int32 self_destroy(uint16 step, card* ucard, int32 p);
int32 trap_monster_adjust(uint16 step);
int32 equip(uint16 step, uint8 equip_player, card* equip_card, card* target, uint32 up, uint32 is_step);
int32 draw(uint16 step, effect* reason_effect, uint32 reason, uint8 reason_player, uint8 playerid, uint32 count);
int32 damage(uint16 step, effect* reason_effect, uint32 reason, uint8 reason_player, card* reason_card, uint8 playerid, uint32 amount, uint32 is_step);
......@@ -626,7 +625,7 @@ public:
#define CHAIN_CONTINUOUS_CARD 0x08
#define CHAIN_ACTIVATING 0x10
#define CHAIN_HAND_TRIGGER 0x20
#define CHAIN_DECK_EFFECT 0x40
//#define CHAIN_DECK_EFFECT 0x40
#define CHAININFO_CHAIN_COUNT 0x01
#define CHAININFO_TRIGGERING_EFFECT 0x02
#define CHAININFO_TRIGGERING_PLAYER 0x04
......@@ -756,6 +755,7 @@ public:
#define PROCESSOR_SWAP_CONTROL 75
#define PROCESSOR_CONTROL_ADJUST 76
#define PROCESSOR_SELF_DESTROY 77
#define PROCESSOR_TRAP_MONSTER_ADJUST 78
#define PROCESSOR_PAY_LPCOST 80
#define PROCESSOR_REMOVE_COUNTER 81
#define PROCESSOR_ATTACK_DISABLE 82
......
......@@ -4104,7 +4104,7 @@ int32 scriptlib::duel_is_chain_negatable(lua_State * L) {
chain* ch = pduel->game_field->get_chain(chaincount);
if(!ch)
return 0;
if(ch->flag & CHAIN_DECK_EFFECT)
if(ch->triggering_location == LOCATION_DECK)
lua_pushboolean(L, 0);
else
lua_pushboolean(L, 1);
......@@ -4121,7 +4121,7 @@ int32 scriptlib::duel_is_chain_disablable(lua_State * L) {
chain* ch = pduel->game_field->get_chain(chaincount);
if(!ch)
return 0;
if(ch->flag & CHAIN_DECK_EFFECT)
if(ch->triggering_location == LOCATION_DECK)
lua_pushboolean(L, 0);
else
lua_pushboolean(L, 1);
......
This diff is collapsed.
......@@ -490,6 +490,13 @@ int32 field::process() {
it->step++;
return pduel->bufferlen;
}
case PROCESSOR_TRAP_MONSTER_ADJUST: {
if (trap_monster_adjust(it->step))
core.units.pop_front();
else
it->step++;
return pduel->bufferlen;
}
case PROCESSOR_PAY_LPCOST: {
if (pay_lp_cost(it->step, it->arg1, it->arg2))
core.units.pop_front();
......@@ -1306,8 +1313,7 @@ int32 field::process_point_event(int16 step, int32 skip_trigger, int32 skip_free
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(check_deck_effect(*clit) && check_trigger_effect(*clit)
&& peffect->is_chainable(tp) && peffect->is_activateable(tp, clit->evt, TRUE)) {
if(phandler->is_has_relation(*clit) && peffect->is_chainable(tp) && peffect->is_activateable(tp, clit->evt, TRUE)) {
if(tp == core.current_player)
core.select_chains.push_back(*clit);
} else {
......@@ -1364,7 +1370,7 @@ int32 field::process_point_event(int16 step, int32 skip_trigger, int32 skip_free
clit->set_triggering_state(phandler);
}
uint8 tp = clit->triggering_player;
if(check_hand_trigger(*clit) && check_deck_effect(*clit) && check_trigger_effect(*clit)
if(check_hand_trigger(*clit) && phandler->is_has_relation(*clit)
&& peffect->is_chainable(tp) && peffect->is_activateable(tp, clit->evt, TRUE)
&& check_spself_from_hand_trigger(*clit)) {
if(tp == core.current_player)
......@@ -3643,7 +3649,6 @@ int32 field::process_turn(uint16 step, uint8 turn_player) {
core.summon_count[p] = 0;
core.extra_summon[p] = 0;
core.spsummon_once_map[p].clear();
core.spsummon_once_map_rst[p].clear();
}
core.spsummon_rst = false;
for(auto& peffect : effects.rechargeable)
......@@ -4156,37 +4161,6 @@ int32 field::add_chain(uint16 step) {
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(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]++;
}
}
}
}
}
}
pduel->write_buffer8(MSG_CHAINED);
pduel->write_buffer8(clit.chain_count);
......@@ -4308,13 +4282,6 @@ int32 field::solve_chain(uint16 step, uint32 chainend_arg1, uint32 chainend_arg2
if(core.spsummon_rst) {
set_spsummon_counter(0, false, true);
set_spsummon_counter(1, false, true);
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;
}
}
core.spsummon_rst = false;
}
pduel->write_buffer8(MSG_CHAIN_SOLVING);
......@@ -4408,37 +4375,6 @@ int32 field::solve_chain(uint16 step, uint32 chainend_arg1, uint32 chainend_arg2
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);
//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(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((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;
......@@ -4839,18 +4775,19 @@ int32 field::adjust_step(uint16 step) {
}
case 3: {
//trap monster
uint8 tp = infos.turn_player;
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[tp].list_mzone) {
for(auto& pcard : player[p].list_mzone) {
if(!pcard) continue;
if((pcard->get_type() & TYPE_TRAPMONSTER) && pcard->is_affected_by_effect(EFFECT_DISABLE_TRAPMONSTER)) {
pcard->reset(RESET_TURN_SET, RESET_EVENT);
refresh_location_info_instant();
move_to_field(pcard, tp, tp, LOCATION_SZONE, pcard->current.position, FALSE, 2);
core.re_adjust = TRUE;
core.trap_monster_adjust_set[p].insert(pcard);
}
}
tp = 1 - tp;
}
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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment