Commit 7a9fd22d authored by salix5's avatar salix5 Committed by GitHub

delete card target on RESET_COPY & remove EFFECT_FLAG_COPY_INHERIT (#644)

* remove EFFECT_FLAG_COPY_INHERIT

* delete card target on RESET_COPY

* add effect_indexer::iterator remove_effect(effect* peffect)

* minor fix

* fix field::add_effect

avoid duplicate entries like card::add_effect

* reload script after removing all effects

* update signature

* always call field::remove_effect

* fix field::adjust_grant_effect

* avoid nested EFFECT_TYPE_GRANT
parent b579cda9
......@@ -414,7 +414,7 @@ int32 card::get_infos(byte* buf, uint32 query_flag, int32 use_cache) {
buffer_write<uint32_t>(finalize, query_flag);
return (int32)(p - buf);
}
uint32 card::get_info_location() {
uint32 card::get_info_location() const {
if(overlay_target) {
uint32 c = overlay_target->current.controler;
uint32 l = overlay_target->current.location | LOCATION_OVERLAY;
......@@ -1715,9 +1715,7 @@ void card::cancel_field_effect() {
if (current.controler == PLAYER_NONE)
return;
for (auto& it : field_effect) {
if (it.second->in_range(this) || it.second->is_hand_trigger()) {
pduel->game_field->remove_effect(it.second);
}
pduel->game_field->remove_effect(it.second);
}
if(unique_code && (current.location & unique_location))
pduel->game_field->remove_unique_card(this);
......@@ -1882,12 +1880,6 @@ int32 card::add_effect(effect* peffect) {
peffect->reset_count = pduel->game_field->core.copy_reset_count;
}
effect* reason_effect = pduel->game_field->core.reason_effect;
if(peffect->is_flag(EFFECT_FLAG_COPY_INHERIT) && reason_effect && reason_effect->copy_id) {
peffect->copy_id = reason_effect->copy_id;
peffect->reset_flag |= reason_effect->reset_flag;
if(peffect->reset_count > reason_effect->reset_count)
peffect->reset_count = reason_effect->reset_count;
}
indexer.emplace(peffect, eit);
peffect->handler = this;
if((peffect->type & EFFECT_TYPE_FIELD)) {
......@@ -1927,13 +1919,11 @@ int32 card::add_effect(effect* peffect) {
}
return peffect->id;
}
void card::remove_effect(effect* peffect) {
auto it = indexer.find(peffect);
if (it == indexer.end())
return;
remove_effect(peffect, it->second);
}
void card::remove_effect(effect* peffect, effect_container::iterator it) {
effect_indexer::iterator card::remove_effect(effect* peffect) {
auto index = indexer.find(peffect);
if (index == indexer.end())
return index;
auto& it = index->second;
card_set check_target = { this };
if (peffect->type & EFFECT_TYPE_SINGLE) {
single_effect.erase(it);
......@@ -1961,8 +1951,6 @@ void card::remove_effect(effect* peffect, effect_container::iterator it) {
pduel->game_field->update_disable_check_list(peffect);
}
field_effect.erase(it);
if(peffect->in_range(this) || current.controler != PLAYER_NONE && peffect->is_hand_trigger())
pduel->game_field->remove_effect(peffect);
}
if ((current.controler != PLAYER_NONE) && !get_status(STATUS_DISABLED | STATUS_FORBIDDEN) && !check_target.empty()) {
if (peffect->is_disable_related()) {
......@@ -1970,16 +1958,7 @@ void card::remove_effect(effect* peffect, effect_container::iterator it) {
pduel->game_field->add_to_disable_check_list(target);
}
}
if (peffect->is_flag(EFFECT_FLAG_INITIAL) && peffect->copy_id && is_status(STATUS_EFFECT_REPLACED)) {
set_status(STATUS_EFFECT_REPLACED, FALSE);
if (interpreter::is_load_script(data)) {
set_status(STATUS_INITIALIZING, TRUE);
pduel->lua->add_param(this, PARAM_TYPE_CARD);
pduel->lua->call_card_function(this, "initial_effect", 1, 0);
set_status(STATUS_INITIALIZING, FALSE);
}
}
indexer.erase(peffect);
auto ret = indexer.erase(index);
if(peffect->is_flag(EFFECT_FLAG_OATH))
pduel->game_field->effects.oath.erase(peffect);
if(peffect->reset_flag & RESET_PHASE)
......@@ -2011,7 +1990,9 @@ void card::remove_effect(effect* peffect, effect_container::iterator it) {
unique_pos[0] = unique_pos[1] = 0;
unique_code = 0;
}
pduel->game_field->remove_effect(peffect);
pduel->game_field->core.reseted_effects.insert(peffect);
return ret;
}
int32 card::copy_effect(uint32 code, uint32 reset, int32 count) {
card_data cdata;
......@@ -2056,12 +2037,12 @@ int32 card::replace_effect(uint32 code, uint32 reset, int32 count) {
return -1;
if(is_status(STATUS_EFFECT_REPLACED))
set_status(STATUS_EFFECT_REPLACED, FALSE);
for(auto i = indexer.begin(); i != indexer.end();) {
auto rm = i++;
effect* peffect = rm->first;
auto& it = rm->second;
if (peffect->is_flag(EFFECT_FLAG_INITIAL | EFFECT_FLAG_COPY_INHERIT))
remove_effect(peffect, it);
for(auto it = indexer.begin(); it != indexer.end();) {
effect* const& peffect = it->first;
if (peffect->is_flag(EFFECT_FLAG_INITIAL))
it = remove_effect(peffect);
else
++it;
}
auto cr = pduel->game_field->core.copy_reset;
auto crc = pduel->game_field->core.copy_reset_count;
......@@ -2160,17 +2141,34 @@ void card::reset(uint32 id, uint32 reset_type) {
}
}
}
for (auto i = indexer.begin(); i != indexer.end();) {
auto rm = i++;
effect* peffect = rm->first;
auto& it = rm->second;
if (peffect->reset(id, reset_type))
remove_effect(peffect, it);
else if (reset_type == RESET_COPY) {
delete_card_target(TRUE);
effect_target_cards.clear();
}
bool reload = false;
for (auto it = indexer.begin(); it != indexer.end();) {
effect* const& peffect = it->first;
if (peffect->reset(id, reset_type)) {
if (is_status(STATUS_EFFECT_REPLACED) && peffect->is_flag(EFFECT_FLAG_INITIAL) && peffect->copy_id)
reload = true;
it = remove_effect(peffect);
}
else
++it;
}
if (reload) {
set_status(STATUS_EFFECT_REPLACED, FALSE);
if (interpreter::is_load_script(data)) {
set_status(STATUS_INITIALIZING, TRUE);
pduel->lua->add_param(this, PARAM_TYPE_CARD);
pduel->lua->call_card_function(this, "initial_effect", 1, 0);
set_status(STATUS_INITIALIZING, FALSE);
}
}
}
void card::reset_effect_count() {
for (auto& i : indexer) {
effect* peffect = i.first;
effect* const& peffect = i.first;
if (peffect->is_flag(EFFECT_FLAG_COUNT_LIMIT))
peffect->recharge();
}
......@@ -2478,6 +2476,26 @@ void card::cancel_card_target(card* pcard) {
pduel->write_buffer32(pcard->get_info_location());
}
}
void card::delete_card_target(uint32 send_msg) {
for (auto& pcard : effect_target_cards) {
pcard->effect_target_owner.erase(this);
for (auto& it : target_effect) {
if (it.second->is_disable_related())
pduel->game_field->add_to_disable_check_list(pcard);
}
for (auto it = pcard->single_effect.begin(); it != pcard->single_effect.end();) {
auto rm = it++;
effect* const& peffect = rm->second;
if ((peffect->owner == this) && peffect->is_flag(EFFECT_FLAG_OWNER_RELATE))
pcard->remove_effect(peffect);
}
if (send_msg) {
pduel->write_buffer8(MSG_CANCEL_TARGET);
pduel->write_buffer32(get_info_location());
pduel->write_buffer32(pcard->get_info_location());
}
}
}
void card::clear_card_target() {
for(auto& pcard : effect_target_owner) {
pcard->effect_target_cards.erase(this);
......@@ -2486,19 +2504,7 @@ void card::clear_card_target() {
pduel->game_field->add_to_disable_check_list(this);
}
}
for(auto& pcard : effect_target_cards) {
pcard->effect_target_owner.erase(this);
for(auto& it : target_effect) {
if(it.second->is_disable_related())
pduel->game_field->add_to_disable_check_list(pcard);
}
for(auto it = pcard->single_effect.begin(); it != pcard->single_effect.end();) {
auto rm = it++;
effect* peffect = rm->second;
if((peffect->owner == this) && peffect->is_flag(EFFECT_FLAG_OWNER_RELATE))
pcard->remove_effect(peffect, rm);
}
}
delete_card_target(FALSE);
effect_target_owner.clear();
effect_target_cards.clear();
}
......@@ -2703,7 +2709,7 @@ void card::filter_immune_effect() {
// 4. Insert continuous target of this into it.
void card::filter_disable_related_cards() {
for (auto& it : indexer) {
effect* peffect = it.first;
effect* const& peffect = it.first;
if (peffect->is_disable_related()) {
if (peffect->type & EFFECT_TYPE_FIELD)
pduel->game_field->update_disable_check_list(peffect);
......
......@@ -28,6 +28,7 @@ using card_set = std::set<card*, card_sort>;
using card_vector = std::vector<card*>;
using effect_container = std::multimap<uint32, effect*>;
using effect_indexer = std::unordered_map<effect*, effect_container::iterator>;
using effect_collection = std::unordered_set<effect*>;
struct card_state {
uint32 code{ 0 };
......@@ -216,7 +217,7 @@ public:
bool is_extra_deck_monster() const { return !!(data.type & TYPES_EXTRA_DECK); }
int32 get_infos(byte* buf, uint32 query_flag, int32 use_cache = TRUE);
uint32 get_info_location();
uint32 get_info_location() const;
uint32 get_original_code() const;
std::tuple<uint32, uint32> get_original_code_rule() const;
uint32 get_code();
......@@ -286,8 +287,7 @@ public:
void cancel_field_effect();
void enable_field_effect(bool enabled);
int32 add_effect(effect* peffect);
void remove_effect(effect* peffect);
void remove_effect(effect* peffect, effect_container::iterator it);
effect_indexer::iterator remove_effect(effect* peffect);
int32 copy_effect(uint32 code, uint32 reset, int32 count);
int32 replace_effect(uint32 code, uint32 reset, int32 count);
void reset(uint32 id, uint32 reset_type);
......@@ -316,6 +316,7 @@ public:
void set_material(card_set* materials);
void add_card_target(card* pcard);
void cancel_card_target(card* pcard);
void delete_card_target(uint32 send_msg);
void clear_card_target();
void set_special_summon_status(effect* peffect);
......
......@@ -63,6 +63,7 @@ public:
int32 operation{ 0 };
uint8 cost_checked{ FALSE };
effect_set required_handorset_effects;
LuaParamType object_type{ PARAM_TYPE_INT };
explicit effect(duel* pd);
~effect() = default;
......@@ -190,7 +191,7 @@ enum effect_flag : uint32 {
EFFECT_FLAG_CANNOT_DISABLE = 0x0400,
EFFECT_FLAG_PLAYER_TARGET = 0x0800,
EFFECT_FLAG_BOTH_SIDE = 0x1000,
EFFECT_FLAG_COPY_INHERIT = 0x2000,
// EFFECT_FLAG_COPY_INHERIT = 0x2000,
EFFECT_FLAG_DAMAGE_STEP = 0x4000,
EFFECT_FLAG_DAMAGE_CAL = 0x8000,
EFFECT_FLAG_DELAY = 0x10000,
......
......@@ -1161,13 +1161,8 @@ void field::tag_swap(uint8 playerid) {
pduel->write_buffer32(pcard->data.code | (pcard->is_position(POS_FACEUP) ? 0x80000000 : 0));
}
void field::add_effect(effect* peffect, uint8 owner_player) {
if (!peffect->handler) {
peffect->flag[0] |= EFFECT_FLAG_FIELD_ONLY;
peffect->handler = peffect->owner;
peffect->effect_owner = owner_player;
peffect->id = infos.field_id++;
}
peffect->card_type = peffect->owner->data.type;
if (effects.indexer.find(peffect) != effects.indexer.end())
return;
effect_container::iterator it;
if (!(peffect->type & EFFECT_TYPE_ACTIONS)) {
it = effects.aura_effect.emplace(peffect->code, peffect);
......@@ -1178,9 +1173,9 @@ void field::add_effect(effect* peffect, uint8 owner_player) {
} else {
if (peffect->type & EFFECT_TYPE_IGNITION)
it = effects.ignition_effect.emplace(peffect->code, peffect);
else if (peffect->type & EFFECT_TYPE_TRIGGER_O && peffect->type & EFFECT_TYPE_FIELD)
else if (peffect->type & EFFECT_TYPE_TRIGGER_O)
it = effects.trigger_o_effect.emplace(peffect->code, peffect);
else if (peffect->type & EFFECT_TYPE_TRIGGER_F && peffect->type & EFFECT_TYPE_FIELD)
else if (peffect->type & EFFECT_TYPE_TRIGGER_F)
it = effects.trigger_f_effect.emplace(peffect->code, peffect);
else if (peffect->type & EFFECT_TYPE_QUICK_O)
it = effects.quick_o_effect.emplace(peffect->code, peffect);
......@@ -1190,7 +1185,16 @@ void field::add_effect(effect* peffect, uint8 owner_player) {
it = effects.activate_effect.emplace(peffect->code, peffect);
else if (peffect->type & EFFECT_TYPE_CONTINUOUS)
it = effects.continuous_effect.emplace(peffect->code, peffect);
else
return;
}
if (!peffect->handler) {
peffect->flag[0] |= EFFECT_FLAG_FIELD_ONLY;
peffect->handler = peffect->owner;
peffect->effect_owner = owner_player;
peffect->id = infos.field_id++;
}
peffect->card_type = peffect->owner->data.type;
effects.indexer.emplace(peffect, it);
if(peffect->is_flag(EFFECT_FLAG_FIELD_ONLY)) {
if(peffect->is_disable_related())
......@@ -1228,7 +1232,7 @@ void field::remove_effect(effect* peffect) {
auto eit = effects.indexer.find(peffect);
if (eit == effects.indexer.end())
return;
auto it = eit->second;
auto& it = eit->second;
if (!(peffect->type & EFFECT_TYPE_ACTIONS)) {
effects.aura_effect.erase(it);
if(peffect->code == EFFECT_SPSUMMON_COUNT_LIMIT)
......@@ -1287,16 +1291,14 @@ void field::remove_effect(effect* peffect) {
}
void field::remove_oath_effect(effect* reason_effect) {
for(auto oeit = effects.oath.begin(); oeit != effects.oath.end();) {
if(oeit->second == reason_effect) {
effect* peffect = oeit->first;
oeit = effects.oath.erase(oeit);
auto rm = oeit++;
if(rm->second == reason_effect) {
effect* peffect = rm->first;
if(peffect->is_flag(EFFECT_FLAG_FIELD_ONLY))
remove_effect(peffect);
else
peffect->handler->remove_effect(peffect);
}
else
++oeit;
}
}
void field::release_oath_relation(effect* reason_effect) {
......@@ -1309,7 +1311,7 @@ void field::reset_phase(uint32 phase) {
auto rm = eit++;
if((*rm)->reset(phase, RESET_PHASE)) {
if((*rm)->is_flag(EFFECT_FLAG_FIELD_ONLY))
remove_effect((*rm));
remove_effect(*rm);
else
(*rm)->handler->remove_effect((*rm));
}
......@@ -1319,7 +1321,7 @@ void field::reset_chain() {
for(auto eit = effects.cheff.begin(); eit != effects.cheff.end();) {
auto rm = eit++;
if((*rm)->is_flag(EFFECT_FLAG_FIELD_ONLY))
remove_effect((*rm));
remove_effect(*rm);
else
(*rm)->handler->remove_effect((*rm));
}
......@@ -1366,9 +1368,11 @@ void field::filter_field_effect(uint32 code, effect_set* eset, uint8 sort) {
if(sort)
eset->sort();
}
//Get all cards in the target range of a EFFECT_TYPE_FIELD effect
void field::filter_affected_cards(effect* peffect, card_set* cset) {
if((peffect->type & EFFECT_TYPE_ACTIONS) || !(peffect->type & EFFECT_TYPE_FIELD)
|| peffect->is_flag(EFFECT_FLAG_PLAYER_TARGET | EFFECT_FLAG_SPSUM_PARAM))
if ((peffect->type & EFFECT_TYPE_ACTIONS) || !(peffect->type & EFFECT_TYPE_FIELD))
return;
if (peffect->is_flag(EFFECT_FLAG_PLAYER_TARGET | EFFECT_FLAG_SPSUM_PARAM))
return;
uint8 self = peffect->get_handler_player();
if (!check_playerid(self))
......@@ -2097,6 +2101,8 @@ void field::adjust_self_destroy_set() {
}
void field::erase_grant_effect(effect* peffect) {
auto eit = effects.grant_effect.find(peffect);
if (eit == effects.grant_effect.end())
return;
for(auto& it : eit->second)
it.first->remove_effect(it.second);
effects.grant_effect.erase(eit);
......@@ -2105,7 +2111,10 @@ int32 field::adjust_grant_effect() {
int32 adjusted = FALSE;
for(auto& eit : effects.grant_effect) {
effect* peffect = eit.first;
if(!peffect->label_object)
if (peffect->object_type != PARAM_TYPE_EFFECT)
continue;
effect* geffect = (effect*)peffect->get_label_object();
if (geffect->type & EFFECT_TYPE_GRANT)
continue;
card_set cset;
if(peffect->is_available())
......@@ -2121,8 +2130,10 @@ int32 field::adjust_grant_effect() {
if(!pcard->is_affect_by_effect(peffect) || !cset.count(pcard))
remove_set.insert(pcard);
}
//X gains an effect from itself will break card::remove_effect
if (!peffect->is_flag(EFFECT_FLAG_FIELD_ONLY))
add_set.erase(peffect->handler);
for(auto& pcard : add_set) {
effect* geffect = (effect*)peffect->get_label_object();
effect* ceffect = geffect->clone();
ceffect->owner = pcard;
pcard->add_effect(ceffect);
......
......@@ -103,7 +103,6 @@ struct player_info {
};
struct field_effect {
using oath_effects = std::unordered_map<effect*, effect*>;
using effect_collection = std::unordered_set<effect*>;
using gain_effects = std::unordered_map<card*, effect*>;
using grant_effect_container = std::unordered_map<effect*, gain_effects>;
......@@ -417,7 +416,7 @@ public:
void refresh_player_info(uint8 playerid);
void tag_swap(uint8 playerid);
void add_effect(effect* peffect, uint8 owner_player = 2);
void add_effect(effect* peffect, uint8 owner_player = PLAYER_NONE);
void remove_effect(effect* peffect);
void remove_oath_effect(effect* reason_effect);
void release_oath_relation(effect* reason_effect);
......
......@@ -3342,7 +3342,6 @@ int32 scriptlib::card_set_unique_onfield(lua_State *L) {
peffect->owner = pcard;
peffect->type = EFFECT_TYPE_SINGLE;
peffect->code = EFFECT_UNIQUE_CHECK;
peffect->flag[0] = EFFECT_FLAG_COPY_INHERIT;
pcard->add_effect(peffect);
pcard->unique_effect = peffect;
if(pcard->current.location & location)
......
......@@ -190,17 +190,21 @@ int32 scriptlib::effect_set_label_object(lua_State *L) {
effect* peffect = *(effect**) lua_touserdata(L, 1);
if(lua_isnil(L, 2)) {
peffect->label_object = 0;
peffect->object_type = PARAM_TYPE_INT;
return 0;
}
if(check_param(L, PARAM_TYPE_CARD, 2, TRUE)) {
card* p = *(card**)lua_touserdata(L, 2);
peffect->label_object = p->ref_handle;
peffect->object_type = PARAM_TYPE_CARD;
} else if(check_param(L, PARAM_TYPE_EFFECT, 2, TRUE)) {
effect* p = *(effect**)lua_touserdata(L, 2);
peffect->label_object = p->ref_handle;
peffect->object_type = PARAM_TYPE_EFFECT;
} else if(check_param(L, PARAM_TYPE_GROUP, 2, TRUE)) {
group* p = *(group**)lua_touserdata(L, 2);
peffect->label_object = p->ref_handle;
peffect->object_type = PARAM_TYPE_GROUP;
} else
return luaL_error(L, "Parameter 2 should be \"Card\" or \"Effect\" or \"Group\".");
return 0;
......
......@@ -1039,7 +1039,7 @@ int32 field::process_phase_event(int16 step, int32 phase) {
++cn_count;
}
//all effects taking control non-permanently are only until End Phase, not until Turn end
for(auto* peffect : effects.pheff) {
for(auto& peffect : effects.pheff) {
if(peffect->code != EFFECT_SET_CONTROL)
continue;
if(!(peffect->reset_flag & phase))
......
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