dep-ygopro-core/effect.cpp
2018-11-17 13:14:43 +01:00

810 lines
29 KiB
C++

/*
* effect.cpp
*
* Created on: 2010-5-7
* Author: Argon
*/
#include "effect.h"
#include "card.h"
#include "duel.h"
#include "group.h"
#include "interpreter.h"
bool effect_sort_id(const effect* e1, const effect* e2) {
return e1->id < e2->id;
}
effect::effect(duel* pd) {
ref_handle = 0;
pduel = pd;
owner = 0;
handler = 0;
description = 0;
effect_owner = PLAYER_NONE;
card_type = 0;
active_type = 0;
active_location = 0;
active_sequence = 0;
active_handler = 0;
id = 0;
code = 0;
type = 0;
flag[0] = 0;
flag[1] = 0;
copy_id = 0;
range = 0;
s_range = 0;
o_range = 0;
count_limit = 0;
count_limit_max = 0;
reset_count = 0;
reset_flag = 0;
count_code = 0;
count_flag = 0;
category = 0;
label = 0;
label_object = 0;
hint_timing[0] = 0;
hint_timing[1] = 0;
status = 0;
condition = 0;
cost = 0;
target = 0;
value = 0;
operation = 0;
}
int32 effect::is_disable_related() {
if (code == EFFECT_IMMUNE_EFFECT || code == EFFECT_DISABLE || code == EFFECT_CANNOT_DISABLE || code == EFFECT_FORBIDDEN)
return TRUE;
return FALSE;
}
int32 effect::is_can_be_forbidden() {
uint32 ctr = code & 0xf0000;
if (is_flag(EFFECT_FLAG_CANNOT_DISABLE) && !is_flag(EFFECT_FLAG_CANNOT_NEGATE))
return FALSE;
if (code == EFFECT_CHANGE_CODE || ctr == EFFECT_COUNTER_PERMIT || ctr == EFFECT_COUNTER_LIMIT)
return FALSE;
return TRUE;
}
// check if a single/field/equip effect is available
// check properties: range, EFFECT_FLAG_OWNER_RELATE, STATUS_BATTLE_DESTROYED, STATUS_EFFECT_ENABLED, disabled/forbidden
// check fucntions: condition
int32 effect::is_available() {
if (type & EFFECT_TYPE_ACTIONS)
return FALSE;
if ((type & (EFFECT_TYPE_SINGLE | EFFECT_TYPE_XMATERIAL)) && !(type & EFFECT_TYPE_FIELD)) {
card* phandler = get_handler();
card* powner = get_owner();
if (phandler->current.controler == PLAYER_NONE)
return FALSE;
if(is_flag(EFFECT_FLAG_SINGLE_RANGE) && !in_range(phandler))
return FALSE;
if(is_flag(EFFECT_FLAG_SINGLE_RANGE) && !phandler->get_status(STATUS_EFFECT_ENABLED) && !is_flag(EFFECT_FLAG_IMMEDIATELY_APPLY))
return FALSE;
if(is_flag(EFFECT_FLAG_SINGLE_RANGE) && (phandler->current.location & LOCATION_ONFIELD) && !phandler->is_position(POS_FACEUP))
return FALSE;
if(is_flag(EFFECT_FLAG_OWNER_RELATE) && is_can_be_forbidden() && powner->is_status(STATUS_FORBIDDEN))
return FALSE;
if(powner == phandler && is_can_be_forbidden() && phandler->get_status(STATUS_FORBIDDEN))
return FALSE;
if(is_flag(EFFECT_FLAG_OWNER_RELATE) && !is_flag(EFFECT_FLAG_CANNOT_DISABLE) && powner->is_status(STATUS_DISABLED))
return FALSE;
if(powner == phandler && !is_flag(EFFECT_FLAG_CANNOT_DISABLE) && phandler->get_status(STATUS_DISABLED))
return FALSE;
}
if (type & EFFECT_TYPE_EQUIP) {
if(handler->current.controler == PLAYER_NONE)
return FALSE;
if(is_flag(EFFECT_FLAG_OWNER_RELATE) && is_can_be_forbidden() && owner->is_status(STATUS_FORBIDDEN))
return FALSE;
if(owner == handler && is_can_be_forbidden() && handler->get_status(STATUS_FORBIDDEN))
return FALSE;
if(is_flag(EFFECT_FLAG_OWNER_RELATE) && !is_flag(EFFECT_FLAG_CANNOT_DISABLE) && owner->is_status(STATUS_DISABLED))
return FALSE;
if(owner == handler && !is_flag(EFFECT_FLAG_CANNOT_DISABLE) && handler->get_status(STATUS_DISABLED))
return FALSE;
if(!is_flag(EFFECT_FLAG_SET_AVAILABLE)) {
if(!(handler->get_status(STATUS_EFFECT_ENABLED)))
return FALSE;
if(!handler->is_position(POS_FACEUP))
return FALSE;
}
}
if (type & EFFECT_TYPE_FIELD) {
card* phandler = get_handler();
card* powner = get_owner();
if (!is_flag(EFFECT_FLAG_FIELD_ONLY)) {
if(phandler->current.controler == PLAYER_NONE)
return FALSE;
if(!in_range(phandler))
return FALSE;
if(!phandler->get_status(STATUS_EFFECT_ENABLED) && !is_flag(EFFECT_FLAG_IMMEDIATELY_APPLY))
return FALSE;
if((phandler->current.location & LOCATION_ONFIELD) && !phandler->is_position(POS_FACEUP))
return FALSE;
if(is_flag(EFFECT_FLAG_OWNER_RELATE) && is_can_be_forbidden() && powner->is_status(STATUS_FORBIDDEN))
return FALSE;
if(powner == phandler && is_can_be_forbidden() && phandler->get_status(STATUS_FORBIDDEN))
return FALSE;
if(is_flag(EFFECT_FLAG_OWNER_RELATE) && !is_flag(EFFECT_FLAG_CANNOT_DISABLE) && powner->is_status(STATUS_DISABLED))
return FALSE;
if(powner == phandler && !is_flag(EFFECT_FLAG_CANNOT_DISABLE) && phandler->get_status(STATUS_DISABLED))
return FALSE;
if(phandler->is_status(STATUS_BATTLE_DESTROYED))
return FALSE;
}
}
if (!condition)
return TRUE;
pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
int32 res = pduel->lua->check_condition(condition, 1);
if(res) {
if(!(status & EFFECT_STATUS_AVAILABLE))
id = pduel->game_field->infos.field_id++;
status |= EFFECT_STATUS_AVAILABLE;
} else
status &= ~EFFECT_STATUS_AVAILABLE;
return res;
}
// reset_count: count of effect reset
// count_limit: left count of activation
// count_limit_max: max count of activation
int32 effect::check_count_limit(uint8 playerid) {
if(is_flag(EFFECT_FLAG_COUNT_LIMIT)) {
if(count_limit == 0)
return FALSE;
if(count_code || count_flag) {
uint32 count = count_limit_max;
if(count_flag & EFFECT_COUNT_CODE_SINGLE) {
if(pduel->game_field->get_effect_code(get_handler()->fieldid, count_flag, PLAYER_NONE) >= count)
return FALSE;
} else {
if(pduel->game_field->get_effect_code(count_code, count_flag, playerid) >= count)
return FALSE;
}
}
}
return TRUE;
}
// check if an EFFECT_TYPE_ACTIONS effect can be activated
// for triggering effects, it checks EFFECT_FLAG_DAMAGE_STEP, EFFECT_FLAG_SET_AVAILABLE
// for continuous effect, it checks EFFECT_FLAG_AVAILABLE_BD
int32 effect::is_activateable(uint8 playerid, const tevent& e, int32 neglect_cond, int32 neglect_cost, int32 neglect_target, int32 neglect_loc, int32 neglect_faceup) {
if(!(type & EFFECT_TYPE_ACTIONS))
return FALSE;
if(!check_count_limit(playerid))
return FALSE;
if (!is_flag(EFFECT_FLAG_FIELD_ONLY)) {
if (type & EFFECT_TYPE_ACTIVATE) {
if((handler->current.controler != playerid) && !(flag[0] & EFFECT_FLAG_BOTH_SIDE))
return FALSE;
if(pduel->game_field->check_unique_onfield(handler, playerid, LOCATION_SZONE))
return FALSE;
if(!(handler->data.type & TYPE_COUNTER)) {
if((code < 1132 || code > 1149) && pduel->game_field->infos.phase == PHASE_DAMAGE && !is_flag(EFFECT_FLAG_DAMAGE_STEP)
&& !pduel->game_field->get_cteffect(this, playerid, FALSE))
return FALSE;
if((code < 1134 || code > 1136) && pduel->game_field->infos.phase == PHASE_DAMAGE_CAL && !is_flag(EFFECT_FLAG_DAMAGE_CAL)
&& !pduel->game_field->get_cteffect(this, playerid, FALSE))
return FALSE;
}
uint32 zone = 0xff;
if(!(handler->data.type & (TYPE_FIELD | TYPE_PENDULUM)) && is_flag(EFFECT_FLAG_LIMIT_ZONE)) {
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(e.event_cards , PARAM_TYPE_GROUP);
pduel->lua->add_param(e.event_player, PARAM_TYPE_INT);
pduel->lua->add_param(e.event_value, PARAM_TYPE_INT);
pduel->lua->add_param(e.reason_effect , PARAM_TYPE_EFFECT);
pduel->lua->add_param(e.reason, PARAM_TYPE_INT);
pduel->lua->add_param(e.reason_player, PARAM_TYPE_INT);
zone = get_value(7);
if(!zone)
zone = 0xff;
}
// additional check for each location
if(handler->current.location == LOCATION_SZONE) {
if(handler->is_position(POS_FACEUP))
return FALSE;
if(handler->equiping_target)
return FALSE;
if(handler->get_status(STATUS_SET_TURN)) {
if((handler->data.type & TYPE_SPELL) && ((handler->data.type & TYPE_QUICKPLAY) || handler->is_affected_by_effect(EFFECT_BECOME_QUICK)))
return FALSE;
}
if(!(handler->data.type & (TYPE_FIELD | TYPE_PENDULUM)) && is_flag(EFFECT_FLAG_LIMIT_ZONE) && !(zone & (1u << handler->current.sequence)))
return FALSE;
} else {
if(!(((handler->data.type & TYPE_FIELD) && value<=0) || (value & LOCATION_FZONE) || (value & LOCATION_HAND))) {
if (value & LOCATION_MZONE) {
if (pduel->game_field->get_useable_count(handler, playerid, LOCATION_MZONE, playerid, LOCATION_REASON_TOFIELD) <= 0)
return FALSE;
} else if ((handler->data.type & TYPE_PENDULUM) || (value & LOCATION_PZONE)) {
if(!pduel->game_field->is_location_useable(playerid, LOCATION_PZONE, 0)
&& !pduel->game_field->is_location_useable(playerid, LOCATION_PZONE, 1))
return FALSE;
} else {
if (pduel->game_field->get_useable_count(handler, playerid, LOCATION_SZONE, playerid, LOCATION_REASON_TOFIELD, zone) <= 0)
return FALSE;
}
}
}
// check activate in hand/in set turn
int32 ecode = 0;
if(handler->current.location == LOCATION_HAND && !neglect_loc) {
if(handler->data.type & TYPE_TRAP)
ecode = EFFECT_TRAP_ACT_IN_HAND;
else if((handler->data.type & TYPE_SPELL) && pduel->game_field->infos.turn_player != playerid) {
if((handler->data.type & TYPE_QUICKPLAY) || handler->is_affected_by_effect(EFFECT_BECOME_QUICK))
ecode = EFFECT_QP_ACT_IN_NTPHAND;
else
return FALSE;
}
} else if(handler->current.location == LOCATION_SZONE) {
if((handler->data.type & TYPE_TRAP) && handler->get_status(STATUS_SET_TURN))
ecode = EFFECT_TRAP_ACT_IN_SET_TURN;
if((handler->data.type & TYPE_SPELL) && (handler->data.type & TYPE_QUICKPLAY || handler->is_affected_by_effect(EFFECT_BECOME_QUICK)) && handler->get_status(STATUS_SET_TURN))
ecode = EFFECT_QP_ACT_IN_SET_TURN;
}
if(ecode) {
bool available = false;
effect_set eset;
handler->filter_effect(ecode, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
if(eset[i]->check_count_limit(playerid)) {
available = true;
break;
}
}
if(!available)
return FALSE;
}
if(handler->is_status(STATUS_FORBIDDEN))
return FALSE;
if(handler->is_affected_by_effect(EFFECT_CANNOT_TRIGGER))
return FALSE;
} else if(!(type & EFFECT_TYPE_CONTINUOUS)) {
card* phandler = get_handler();
if(!(phandler->get_type() & TYPE_MONSTER) && (get_active_type() & TYPE_MONSTER))
return FALSE;
if(!neglect_faceup && (phandler->current.location & (LOCATION_ONFIELD | LOCATION_REMOVED))) {
// effects which can be activated while face-down:
// 1. effects with EFFECT_FLAG_SET_AVAILABLE
// 2. events with FLIP_SET_AVAILABLE
if(!phandler->is_position(POS_FACEUP) && !is_flag(EFFECT_FLAG_SET_AVAILABLE) && (code != EVENT_FLIP || !(e.event_value & (FLIP_SET_AVAILABLE >> 16))))
return FALSE;
if(phandler->is_position(POS_FACEUP) && !phandler->is_status(STATUS_EFFECT_ENABLED))
return FALSE;
}
if(!(type & (EFFECT_TYPE_FLIP | EFFECT_TYPE_TRIGGER_F))
&& !((type & EFFECT_TYPE_SINGLE) && (code == EVENT_TO_GRAVE || code == EVENT_DESTROYED || code == EVENT_SPSUMMON_SUCCESS || code == EVENT_TO_HAND || code == EVENT_REMOVE))) {
if((code < 1132 || code > 1149) && pduel->game_field->infos.phase == PHASE_DAMAGE && !is_flag(EFFECT_FLAG_DAMAGE_STEP))
return FALSE;
if((code < 1134 || code > 1136) && pduel->game_field->infos.phase == PHASE_DAMAGE_CAL && !is_flag(EFFECT_FLAG_DAMAGE_CAL))
return FALSE;
}
if(phandler->current.location == LOCATION_OVERLAY)
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))
return FALSE;
if(phandler->is_affected_by_effect(EFFECT_CANNOT_TRIGGER))
return FALSE;
} else {
card* phandler = get_handler();
if((type & EFFECT_TYPE_FIELD) && phandler->is_status(STATUS_BATTLE_DESTROYED))
return FALSE;
if(((type & EFFECT_TYPE_FIELD) || ((type & EFFECT_TYPE_SINGLE) && is_flag(EFFECT_FLAG_SINGLE_RANGE))) && (phandler->current.location & LOCATION_ONFIELD)
&& (!phandler->is_position(POS_FACEUP) || !phandler->is_status(STATUS_EFFECT_ENABLED)))
return FALSE;
if((type & EFFECT_TYPE_SINGLE) && is_flag(EFFECT_FLAG_SINGLE_RANGE) && !in_range(phandler))
return FALSE;
if(is_flag(EFFECT_FLAG_OWNER_RELATE) && is_can_be_forbidden() && owner->is_status(STATUS_FORBIDDEN))
return FALSE;
if(phandler == owner && is_can_be_forbidden() && phandler->is_status(STATUS_FORBIDDEN))
return FALSE;
if(is_flag(EFFECT_FLAG_OWNER_RELATE) && !is_flag(EFFECT_FLAG_CANNOT_DISABLE) && owner->is_status(STATUS_DISABLED))
return FALSE;
if(phandler == owner && !is_flag(EFFECT_FLAG_CANNOT_DISABLE) && phandler->is_status(STATUS_DISABLED))
return FALSE;
}
} else {
if((get_owner_player() != playerid) && !is_flag(EFFECT_FLAG_BOTH_SIDE))
return FALSE;
}
pduel->game_field->save_lp_cost();
effect* oreason = pduel->game_field->core.reason_effect;
uint8 op = pduel->game_field->core.reason_player;
pduel->game_field->core.reason_effect = this;
pduel->game_field->core.reason_player = playerid;
int32 result = TRUE;
if(!(type & EFFECT_TYPE_CONTINUOUS))
result = is_action_check(playerid);
if(result)
result = is_activate_ready(playerid, e, neglect_cond, neglect_cost, neglect_target);
pduel->game_field->core.reason_effect = oreason;
pduel->game_field->core.reason_player = op;
pduel->game_field->restore_lp_cost();
return result;
}
// check functions: value of EFFECT_CANNOT_ACTIVATE, target, cost of EFFECT_ACTIVATE_COST
int32 effect::is_action_check(uint8 playerid) {
effect_set eset;
pduel->game_field->filter_player_effect(playerid, EFFECT_CANNOT_ACTIVATE, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
if(eset[i]->check_value_condition(2))
return FALSE;
}
eset.clear();
pduel->game_field->filter_player_effect(playerid, EFFECT_ACTIVATE_COST, &eset);
for(int32 i = 0; i < eset.size(); ++i) {
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
if(!pduel->lua->check_condition(eset[i]->target, 3))
continue;
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
if(!pduel->lua->check_condition(eset[i]->cost, 3))
return FALSE;
}
return TRUE;
}
// check functions: condition, cost(chk=0), target(chk=0)
int32 effect::is_activate_ready(uint8 playerid, const tevent& e, int32 neglect_cond, int32 neglect_cost, int32 neglect_target) {
if (!neglect_cond && condition) {
pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(e.event_cards , PARAM_TYPE_GROUP);
pduel->lua->add_param(e.event_player, PARAM_TYPE_INT);
pduel->lua->add_param(e.event_value, PARAM_TYPE_INT);
pduel->lua->add_param(e.reason_effect , PARAM_TYPE_EFFECT);
pduel->lua->add_param(e.reason, PARAM_TYPE_INT);
pduel->lua->add_param(e.reason_player, PARAM_TYPE_INT);
if (!pduel->lua->check_condition(condition, 8)) {
return FALSE;
}
}
if(!neglect_cost && cost && !(type & EFFECT_TYPE_CONTINUOUS)) {
pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(e.event_cards , PARAM_TYPE_GROUP);
pduel->lua->add_param(e.event_player, PARAM_TYPE_INT);
pduel->lua->add_param(e.event_value, PARAM_TYPE_INT);
pduel->lua->add_param(e.reason_effect , PARAM_TYPE_EFFECT);
pduel->lua->add_param(e.reason, PARAM_TYPE_INT);
pduel->lua->add_param(e.reason_player, PARAM_TYPE_INT);
pduel->lua->add_param((ptr)0, PARAM_TYPE_INT);
if (!pduel->lua->check_condition(cost, 9)) {
return FALSE;
}
}
if(!neglect_target && target) {
pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(e.event_cards , PARAM_TYPE_GROUP);
pduel->lua->add_param(e.event_player, PARAM_TYPE_INT);
pduel->lua->add_param(e.event_value, PARAM_TYPE_INT);
pduel->lua->add_param(e.reason_effect , PARAM_TYPE_EFFECT);
pduel->lua->add_param(e.reason, PARAM_TYPE_INT);
pduel->lua->add_param(e.reason_player, PARAM_TYPE_INT);
pduel->lua->add_param((ptr)0, PARAM_TYPE_INT);
if (!pduel->lua->check_condition(target, 9)) {
return FALSE;
}
}
return TRUE;
}
// check functions: condition
int32 effect::is_condition_check(uint8 playerid, const tevent& e) {
card* phandler = get_handler();
if(!(type & EFFECT_TYPE_ACTIVATE) && (phandler->current.location & (LOCATION_ONFIELD | LOCATION_REMOVED)) && !phandler->is_position(POS_FACEUP))
return FALSE;
if(!condition)
return TRUE;
effect* oreason = pduel->game_field->core.reason_effect;
uint8 op = pduel->game_field->core.reason_player;
pduel->game_field->core.reason_effect = this;
pduel->game_field->core.reason_player = playerid;
pduel->game_field->save_lp_cost();
pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
pduel->lua->add_param(playerid, PARAM_TYPE_INT);
pduel->lua->add_param(e.event_cards , PARAM_TYPE_GROUP);
pduel->lua->add_param(e.event_player, PARAM_TYPE_INT);
pduel->lua->add_param(e.event_value, PARAM_TYPE_INT);
pduel->lua->add_param(e.reason_effect , PARAM_TYPE_EFFECT);
pduel->lua->add_param(e.reason, PARAM_TYPE_INT);
pduel->lua->add_param(e.reason_player, PARAM_TYPE_INT);
if(!pduel->lua->check_condition(condition, 8)) {
pduel->game_field->restore_lp_cost();
pduel->game_field->core.reason_effect = oreason;
pduel->game_field->core.reason_player = op;
return FALSE;
}
pduel->game_field->restore_lp_cost();
pduel->game_field->core.reason_effect = oreason;
pduel->game_field->core.reason_player = op;
return TRUE;
}
int32 effect::is_activate_check(uint8 playerid, const tevent& e, int32 neglect_cond, int32 neglect_cost, int32 neglect_target) {
pduel->game_field->save_lp_cost();
effect* oreason = pduel->game_field->core.reason_effect;
uint8 op = pduel->game_field->core.reason_player;
pduel->game_field->core.reason_effect = this;
pduel->game_field->core.reason_player = playerid;
int32 result = is_activate_ready(playerid, e, neglect_cond, neglect_cost, neglect_target);
pduel->game_field->core.reason_effect = oreason;
pduel->game_field->core.reason_player = op;
pduel->game_field->restore_lp_cost();
return result;
}
// check if pcard is the target of the field effect this
int32 effect::is_target(card* pcard) {
if(type & EFFECT_TYPE_ACTIONS)
return FALSE;
if(type & (EFFECT_TYPE_SINGLE | EFFECT_TYPE_EQUIP | EFFECT_TYPE_XMATERIAL) && !(type & EFFECT_TYPE_FIELD))
return TRUE;
if(pcard && !is_flag(EFFECT_FLAG_SET_AVAILABLE) && (pcard->current.location & LOCATION_ONFIELD)
&& !pcard->is_position(POS_FACEUP))
return FALSE;
if(!is_flag(EFFECT_FLAG_IGNORE_RANGE)) {
if(pcard->get_status(STATUS_SUMMONING | STATUS_SUMMON_DISABLED | STATUS_ACTIVATE_DISABLED | STATUS_SPSUMMON_STEP))
return FALSE;
if(is_flag(EFFECT_FLAG_ABSOLUTE_TARGET)) {
if(pcard->current.controler == 0) {
if(!pcard->current.is_location(s_range))
return FALSE;
} else {
if(!pcard->current.is_location(o_range))
return FALSE;
}
} else {
if(pcard->current.controler == get_handler_player()) {
if(!pcard->current.is_location(s_range))
return FALSE;
} else {
if(!pcard->current.is_location(o_range))
return FALSE;
}
}
}
return is_fit_target_function(pcard);
}
int32 effect::is_fit_target_function(card* pcard) {
if(target) {
pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
if (!pduel->lua->check_condition(target, 2)) {
return FALSE;
}
}
return TRUE;
}
int32 effect::is_target_player(uint8 playerid) {
if(!is_flag(EFFECT_FLAG_PLAYER_TARGET))
return FALSE;
uint8 self = get_handler_player();
if(is_flag(EFFECT_FLAG_ABSOLUTE_TARGET)) {
if(s_range && playerid == 0)
return TRUE;
if(o_range && playerid == 1)
return TRUE;
} else {
if(s_range && self == playerid)
return TRUE;
if(o_range && self != playerid)
return TRUE;
}
return FALSE;
}
int32 effect::is_player_effect_target(card* pcard) {
if(target) {
handler->pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
handler->pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
if(!handler->pduel->lua->check_condition(target, 2)) {
return FALSE;
}
}
return TRUE;
}
int32 effect::is_immuned(card* pcard) {
effect_set_v effects = pcard->immune_effect;
for (int32 i = 0; i < effects.size(); ++i) {
effect* peffect = effects.at(i);
if(peffect->value) {
pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
pduel->lua->add_param(pcard, PARAM_TYPE_CARD);
if(peffect->check_value_condition(2))
return TRUE;
}
}
return FALSE;
}
int32 effect::is_chainable(uint8 tp) {
if(!(type & EFFECT_TYPE_ACTIONS))
return FALSE;
int32 sp = get_speed();
// Curse of Field is the exception
if((type & EFFECT_TYPE_ACTIVATE) && (sp <= 1) && !is_flag(EFFECT_FLAG2_COF))
return FALSE;
if(pduel->game_field->core.current_chain.size()) {
if(!is_flag(EFFECT_FLAG_FIELD_ONLY) && (type & EFFECT_TYPE_TRIGGER_O)
&& (get_handler()->current.location == LOCATION_HAND)) {
if(pduel->game_field->core.current_chain.rbegin()->triggering_effect->get_speed() > 2)
return FALSE;
} else if(sp < pduel->game_field->core.current_chain.rbegin()->triggering_effect->get_speed())
return FALSE;
}
for(const auto& ch_lim : pduel->game_field->core.chain_limit) {
pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
pduel->lua->add_param(ch_lim.player, PARAM_TYPE_INT);
pduel->lua->add_param(tp, PARAM_TYPE_INT);
if(!pduel->lua->check_condition(ch_lim.function, 3))
return FALSE;
}
for(const auto& ch_lim_p : pduel->game_field->core.chain_limit_p) {
pduel->lua->add_param(this, PARAM_TYPE_EFFECT);
pduel->lua->add_param(ch_lim_p.player, PARAM_TYPE_INT);
pduel->lua->add_param(tp, PARAM_TYPE_INT);
if(!pduel->lua->check_condition(ch_lim_p.function, 3))
return FALSE;
}
return TRUE;
}
//return: this can be reset by reset_level or not
//RESET_CODE can only reset single effects without EFFECT_FLAG_SINGLE_RANGE
//RESET_DISABLE is valid only when owner == handler
int32 effect::reset(uint32 reset_level, uint32 reset_type) {
switch (reset_type) {
case RESET_EVENT: {
if(!(reset_flag & RESET_EVENT))
return FALSE;
if(owner != handler)
reset_level &= ~RESET_DISABLE;
if(reset_level & 0xffff0000 & reset_flag)
return TRUE;
return FALSE;
break;
}
case RESET_CARD: {
return owner && (owner->data.code == reset_level);
break;
}
case RESET_PHASE: {
if(!(reset_flag & RESET_PHASE))
return FALSE;
uint8 pid = get_handler_player();
uint8 tp = handler->pduel->game_field->infos.turn_player;
if((((reset_flag & RESET_SELF_TURN) && pid == tp) || ((reset_flag & RESET_OPPO_TURN) && pid != tp))
&& (reset_level & 0x3ff & reset_flag))
reset_count--;
if(reset_count == 0)
return TRUE;
return FALSE;
break;
}
case RESET_CODE: {
return (code == reset_level) && (type & EFFECT_TYPE_SINGLE) && !(type & EFFECT_TYPE_ACTIONS)
&& !is_flag(EFFECT_FLAG_SINGLE_RANGE);
break;
}
case RESET_COPY: {
return copy_id == reset_level;
break;
}
}
return FALSE;
}
void effect::dec_count(uint32 playerid) {
if(!is_flag(EFFECT_FLAG_COUNT_LIMIT))
return;
if(count_limit == 0)
return;
count_limit -= 1;
if(count_code || count_flag) {
if(count_flag & EFFECT_COUNT_CODE_SINGLE)
pduel->game_field->add_effect_code(get_handler()->fieldid, count_flag, PLAYER_NONE);
else
pduel->game_field->add_effect_code(count_code, count_flag, playerid);
}
}
void effect::recharge() {
if(is_flag(EFFECT_FLAG_COUNT_LIMIT)) {
count_limit = count_limit_max;
}
}
int32 effect::get_value(uint32 extraargs) {
if(is_flag(EFFECT_FLAG_FUNC_VALUE)) {
pduel->lua->add_param(this, PARAM_TYPE_EFFECT, TRUE);
int32 res = pduel->lua->get_function_value(value, 1 + extraargs);
return res;
} else {
pduel->lua->params.clear();
return (int32)value;
}
}
int32 effect::get_value(card* pcard, uint32 extraargs) {
if(is_flag(EFFECT_FLAG_FUNC_VALUE)) {
pduel->lua->add_param(pcard, PARAM_TYPE_CARD, TRUE);
pduel->lua->add_param(this, PARAM_TYPE_EFFECT, TRUE);
int32 res = pduel->lua->get_function_value(value, 2 + extraargs);
return res;
} else {
pduel->lua->params.clear();
return (int32)value;
}
}
int32 effect::get_value(effect* peffect, uint32 extraargs) {
if(is_flag(EFFECT_FLAG_FUNC_VALUE)) {
pduel->lua->add_param(peffect, PARAM_TYPE_EFFECT, TRUE);
pduel->lua->add_param(this, PARAM_TYPE_EFFECT, TRUE);
int32 res = pduel->lua->get_function_value(value, 2 + extraargs);
return res;
} else {
pduel->lua->params.clear();
return (int32)value;
}
}
void effect::get_value(uint32 extraargs, std::vector<int32>* result) {
if(is_flag(EFFECT_FLAG_FUNC_VALUE)) {
pduel->lua->add_param(this, PARAM_TYPE_EFFECT, TRUE);
pduel->lua->get_function_value(value, 1 + extraargs, result);
} else {
pduel->lua->params.clear();
result->push_back((int32)value);
}
}
void effect::get_value(card* pcard, uint32 extraargs, std::vector<int32>* result) {
if(is_flag(EFFECT_FLAG_FUNC_VALUE)) {
pduel->lua->add_param(pcard, PARAM_TYPE_CARD, TRUE);
pduel->lua->add_param(this, PARAM_TYPE_EFFECT, TRUE);
pduel->lua->get_function_value(value, 2 + extraargs, result);
} else {
pduel->lua->params.clear();
result->push_back((int32)value);
}
}
void effect::get_value(effect* peffect, uint32 extraargs, std::vector<int32>* result) {
if(is_flag(EFFECT_FLAG_FUNC_VALUE)) {
pduel->lua->add_param(peffect, PARAM_TYPE_EFFECT, TRUE);
pduel->lua->add_param(this, PARAM_TYPE_EFFECT, TRUE);
pduel->lua->get_function_value(value, 2 + extraargs, result);
} else {
pduel->lua->params.clear();
result->push_back((int32)value);
}
}
int32 effect::check_value_condition(uint32 extraargs) {
if(is_flag(EFFECT_FLAG_FUNC_VALUE)) {
pduel->lua->add_param(this, PARAM_TYPE_EFFECT, TRUE);
int32 res = pduel->lua->check_condition(value, 1 + extraargs);
return res;
} else {
pduel->lua->params.clear();
return (int32)value;
}
}
void* effect::get_label_object() {
return pduel->lua->get_ref_object(label_object);
}
int32 effect::get_speed() {
if(!(type & EFFECT_TYPE_ACTIONS))
return 0;
if(type & (EFFECT_TYPE_TRIGGER_O | EFFECT_TYPE_TRIGGER_F | EFFECT_TYPE_IGNITION))
return 1;
else if(type & (EFFECT_TYPE_QUICK_O | EFFECT_TYPE_QUICK_F))
return 2;
else if(type & EFFECT_TYPE_ACTIVATE) {
if(handler->data.type & TYPE_MONSTER)
return 0;
else if(handler->data.type & TYPE_SPELL) {
if((handler->data.type & TYPE_QUICKPLAY) || handler->is_affected_by_effect(EFFECT_BECOME_QUICK))
return 2;
return 1;
} else {
if (handler->data.type & TYPE_COUNTER)
return 3;
return 2;
}
}
return 0;
}
effect* effect::clone(int32 majestic) {
effect* ceffect = pduel->new_effect();
int32 ref = ceffect->ref_handle;
*ceffect = *this;
ceffect->ref_handle = ref;
ceffect->handler = 0;
if(condition)
ceffect->condition = pduel->lua->clone_function_ref(condition);
if(cost)
ceffect->cost = pduel->lua->clone_function_ref(cost);
if(target)
ceffect->target = pduel->lua->clone_function_ref(target);
if(operation)
ceffect->operation = pduel->lua->clone_function_ref(operation);
if(value && is_flag(EFFECT_FLAG_FUNC_VALUE))
ceffect->value = pduel->lua->clone_function_ref(value);
if(majestic && is_flag(EFFECT_FLAG2_MAJESTIC_MUST_COPY)) {
if(value && !is_flag(EFFECT_FLAG_FUNC_VALUE))
ceffect->value = value;
if(label)
ceffect->label = label;
if(label_object)
ceffect->label_object = label_object;
if(s_range)
ceffect->s_range = s_range;
if(o_range)
ceffect->o_range = o_range;
if(flag[0])
ceffect->flag[0] = flag[0];
if(hint_timing[0])
ceffect->hint_timing[0] = hint_timing[0];
if(hint_timing[1])
ceffect->hint_timing[1] = hint_timing[1];
if(code)
ceffect->code = code;
if(type)
ceffect->type = type;
}
return ceffect;
}
card* effect::get_owner() const {
if(active_handler)
return active_handler;
if(type & EFFECT_TYPE_XMATERIAL)
return handler->overlay_target;
return owner;
}
uint8 effect::get_owner_player() {
if(effect_owner != PLAYER_NONE)
return effect_owner;
return get_owner()->current.controler;
}
card* effect::get_handler() const {
if(active_handler)
return active_handler;
if(type & EFFECT_TYPE_XMATERIAL)
return handler->overlay_target;
return handler;
}
uint8 effect::get_handler_player() {
if(is_flag(EFFECT_FLAG_FIELD_ONLY))
return effect_owner;
return get_handler()->current.controler;
}
int32 effect::in_range(card* pcard) {
if(type & EFFECT_TYPE_XMATERIAL)
return handler->overlay_target ? TRUE : FALSE;
return pcard->current.is_location(range);
}
int32 effect::in_range(const chain& ch) {
if(type & EFFECT_TYPE_XMATERIAL)
return handler->overlay_target ? TRUE : FALSE;
return range & ch.triggering_location;
}
void effect::set_activate_location() {
card* phandler = get_handler();
active_location = phandler->current.location;
active_sequence = phandler->current.sequence;
}
void effect::set_active_type() {
card* phandler = get_handler();
active_type = phandler->get_type();
if(active_type & TYPE_TRAPMONSTER)
active_type &= ~TYPE_TRAP;
}
uint32 effect::get_active_type() {
if(type & 0x7f0) {
if(active_type)
return active_type;
else if((type & EFFECT_TYPE_ACTIVATE) && (get_handler()->data.type & TYPE_PENDULUM))
return TYPE_PENDULUM + TYPE_SPELL;
else
return get_handler()->get_type();
} else
return owner->get_type();
}