Skip to content

Commit

Permalink
Update handling for EFFECT_MUST_ATTACK_MONSTER
Browse files Browse the repository at this point in the history
Properly implement 58c488d:
 * If only one effect is providing EFFECT_MUST_ATTACK_MONSTER the attack selection proceeds as normal, with the turn player choosing the attack targets
  * If multiple effects are providing EFFECT_MUST_ATTACK_MONSTER, the opponent choose the attack target like it did prior to the other change, if then the EFFECT_MUST_ATTACK_MONSTER effect applied on the selected monster was also applying to other monsters, the turn player will then choose among those monsters a valid attack target
  • Loading branch information
edo9300 committed Feb 10, 2024
1 parent bac44b7 commit f1ec813
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 6 deletions.
7 changes: 5 additions & 2 deletions field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2381,7 +2381,7 @@ int32_t field::effect_replace_check(uint32_t code, const tevent& e) {
}
return FALSE;
}
int32_t field::get_attack_target(card* pcard, card_vector* v, bool chain_attack, bool select_target) {
int32_t field::get_attack_target(card* pcard, card_vector* v, bool chain_attack, bool select_target, std::multimap<effect*, card*>* must_attack_map) {
pcard->direct_attackable = 0;
uint8_t p = pcard->current.controler;
card_vector auto_attack, only_attack, must_attack, attack_tg;
Expand All @@ -2391,8 +2391,11 @@ int32_t field::get_attack_target(card* pcard, card_vector* v, bool chain_attack,
auto_attack.push_back(atarget);
if(pcard->is_affected_by_effect(EFFECT_ONLY_ATTACK_MONSTER, atarget))
only_attack.push_back(atarget);
if(pcard->is_affected_by_effect(EFFECT_MUST_ATTACK_MONSTER, atarget))
if(auto* peffect = pcard->is_affected_by_effect(EFFECT_MUST_ATTACK_MONSTER, atarget); peffect) {
must_attack.push_back(atarget);
if(must_attack_map)
must_attack_map->emplace(peffect, atarget);
}
}
}
card_vector* pv = nullptr;
Expand Down
2 changes: 1 addition & 1 deletion field.h
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ class field {

uint32_t get_field_counter(uint8_t playerid, uint8_t self, uint8_t oppo, uint16_t countertype);
int32_t effect_replace_check(uint32_t code, const tevent& e);
int32_t get_attack_target(card* pcard, card_vector* v, bool chain_attack = false, bool select_target = true);
int32_t get_attack_target(card* pcard, card_vector* v, bool chain_attack = false, bool select_target = true, std::multimap<effect*, card*>* must_attack_map = nullptr);
bool confirm_attack_target();
void attack_all_target_check();
int32_t check_tribute(card* pcard, int32_t min, int32_t max, group* mg, uint8_t toplayer, uint32_t zone = 0x1f, uint32_t releasable = 0xff00ff, uint32_t pos = 0x1);
Expand Down
45 changes: 42 additions & 3 deletions processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1973,7 +1973,8 @@ bool field::process(Processors::BattleCommand& arg) {
core.attack_player = FALSE;
core.select_cards.clear();
return_cards.clear();
get_attack_target(core.attacker, &core.select_cards, core.chain_attack);
arg.must_attack_map.clear();
auto atype = get_attack_target(core.attacker, &core.select_cards, core.chain_attack, true, &arg.must_attack_map);
// direct attack
if(core.attacker->direct_attackable) {
if(core.select_cards.size() == 0) {
Expand All @@ -1993,7 +1994,15 @@ bool field::process(Processors::BattleCommand& arg) {
arg.step = 6;
return FALSE;
}
if(is_player_affected_by_effect(infos.turn_player, EFFECT_PATRICIAN_OF_DARKNESS)) {
auto differentMustAttackMonsterEffects = [&] {
size_t count = 0;
const auto& must = arg.must_attack_map;
for(auto it = must.begin(), end = must.end(); it != end; it = must.upper_bound(it->first))
++count;
return count;
}();

if((atype == 3 && differentMustAttackMonsterEffects != 1) || 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 {
Expand All @@ -2005,13 +2014,17 @@ bool field::process(Processors::BattleCommand& arg) {
message->write<uint8_t>(1 - infos.turn_player);
message->write<uint64_t>(549);
emplace_process<Processors::SelectCard>(1 - infos.turn_player, false, 1, 1);
if(atype == 3 && arg.must_attack_map.size() != differentMustAttackMonsterEffects) {
arg.step = 15;
return FALSE;
}
}
} else {
auto message = pduel->new_message(MSG_HINT);
message->write<uint8_t>(HINT_SELECTMSG);
message->write<uint8_t>(infos.turn_player);
message->write<uint64_t>(549);
emplace_process<Processors::SelectCard>(infos.turn_player, static_cast<bool>(core.attack_cancelable), 1, 1);
emplace_process<Processors::SelectCard>(infos.turn_player, core.attack_cancelable, 1, 1);
}
arg.step = 5;
return FALSE;
Expand Down Expand Up @@ -2210,6 +2223,32 @@ bool field::process(Processors::BattleCommand& arg) {
arg.step = -1;
return FALSE;
}
// EFFECT_MUST_ATTACK_MONSTER where an effect affects more than 1 monster
case 16: {
auto selected_card = return_cards.list.front();
const auto range = arg.must_attack_map.equal_range(
std::find_if(arg.must_attack_map.begin(), arg.must_attack_map.end(),
[selected_card](const auto& must_pair) {
return must_pair.second == selected_card;
})->first);
if(std::distance(range.first, range.second) < 2) {
core.attack_target = selected_card;
core.pre_field[1] = core.attack_target->fieldid_r;
arg.step = 5;
return FALSE;
}
core.select_cards.clear();
std::transform(range.first, range.second, std::back_inserter(core.select_cards), [](const auto& pair) {
return pair.second;
});
auto message = pduel->new_message(MSG_HINT);
message->write<uint8_t>(HINT_SELECTMSG);
message->write<uint8_t>(infos.turn_player);
message->write<uint64_t>(549);
emplace_process<Processors::SelectCard>(infos.turn_player, core.attack_cancelable, 1, 1);
arg.step = 5;
return FALSE;
}
case 19: {
infos.phase = PHASE_DAMAGE;
core.chain_attack = false;
Expand Down
2 changes: 2 additions & 0 deletions processor_unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define PROCESSOR_UNIT_H_

#include <cstdint>
#include <map> //std::multimap
#include <memory> //std::unique_ptr
#include <type_traits> //std::false_type, std::true_type
#include <variant>
Expand Down Expand Up @@ -235,6 +236,7 @@ struct BattleCommand : public Process<false> {
effect* damage_change_effect;
group* cards_destroyed_by_battle;
card* reason_card;
std::multimap<effect*, card*> must_attack_map;
BattleCommand(uint16_t step_, group* cards_destroyed_by_battle_ = nullptr) :
Process(step_), phase_to_change_to(0), is_replaying_attack(false), attack_announce_failed(false),
repeat_battle_phase(false), second_battle_phase_is_optional(false),
Expand Down

0 comments on commit f1ec813

Please sign in to comment.