use of mage.abilities.effects.RequirementEffect in project mage by magefree.
the class InciteWarMustAttackEffect method apply.
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source));
if (player != null) {
FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(new ControllerIdPredicate(player.getId()));
RequirementEffect effect = new AttacksIfAbleAllEffect(filter, Duration.EndOfTurn);
game.addEffect(effect, source);
return true;
}
return false;
}
use of mage.abilities.effects.RequirementEffect in project mage by magefree.
the class PermanentImpl method getRules.
/**
* @param game can be null, e.g. for cards viewer
* @return
*/
@Override
public List<String> getRules(Game game) {
try {
List<String> rules = getRules();
// info
if (info != null) {
for (String data : info.values()) {
rules.add(data);
}
}
// ability hints
List<String> abilityHints = new ArrayList<>();
if (HintUtils.ABILITY_HINTS_ENABLE) {
for (Ability ability : getAbilities(game)) {
for (Hint hint : ability.getHints()) {
String s = hint.getText(game, ability);
if (s != null && !s.isEmpty()) {
abilityHints.add(s);
}
}
}
}
// restrict hints
List<String> restrictHints = new ArrayList<>();
if (game != null && HintUtils.RESTRICT_HINTS_ENABLE) {
// restrict
for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) {
for (Ability ability : entry.getValue()) {
if (!entry.getKey().canAttack(game, false) || !entry.getKey().canAttack(this, null, ability, game, false)) {
restrictHints.add(HintUtils.prepareText("Can't attack" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT));
}
if (!entry.getKey().canBlock(null, this, ability, game, false)) {
restrictHints.add(HintUtils.prepareText("Can't block" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT));
}
if (!entry.getKey().canBeUntapped(this, ability, game, false)) {
restrictHints.add(HintUtils.prepareText("Can't untapped" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT));
}
if (!entry.getKey().canUseActivatedAbilities(this, ability, game, false)) {
restrictHints.add(HintUtils.prepareText("Can't use activated abilities" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT));
}
if (!entry.getKey().canTransform(this, ability, game, false)) {
restrictHints.add(HintUtils.prepareText("Can't transform" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT));
}
}
}
// requirement
for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(this, false, game).entrySet()) {
for (Ability ability : entry.getValue()) {
if (entry.getKey().mustAttack(game)) {
restrictHints.add(HintUtils.prepareText("Must attack" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_REQUIRE));
}
if (entry.getKey().mustBlock(game)) {
restrictHints.add(HintUtils.prepareText("Must block" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_REQUIRE));
}
if (entry.getKey().mustBlockAny(game)) {
restrictHints.add(HintUtils.prepareText("Must block any" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_REQUIRE));
}
if (entry.getKey().mustBlockAllAttackers(game)) {
restrictHints.add(HintUtils.prepareText("Must block all attackers" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_REQUIRE));
}
MageObject object = game.getObject(entry.getKey().mustAttackDefender(ability, game));
if (object != null) {
restrictHints.add(HintUtils.prepareText("Must attack defender " + object.getLogName() + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_REQUIRE));
}
object = game.getObject(entry.getKey().mustBlockAttacker(ability, game));
if (object != null) {
restrictHints.add(HintUtils.prepareText("Must block attacker " + object.getLogName() + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_REQUIRE));
}
object = game.getObject(entry.getKey().mustBlockAttackerIfElseUnblocked(ability, game));
if (object != null) {
restrictHints.add(HintUtils.prepareText("Must block attacker if able " + object.getLogName() + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_REQUIRE));
}
}
}
restrictHints.sort(String::compareTo);
}
// total hints
if (!abilityHints.isEmpty() || !restrictHints.isEmpty()) {
rules.add(HintUtils.HINT_START_MARK);
HintUtils.appendHints(rules, abilityHints);
HintUtils.appendHints(rules, restrictHints);
}
return rules;
} catch (Exception e) {
return CardUtil.RULES_ERROR_INFO;
}
}
use of mage.abilities.effects.RequirementEffect in project mage by magefree.
the class DomineeringWillEffect method apply.
@Override
public boolean apply(Game game, Ability source) {
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
if (targetPlayer != null) {
ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfTurn, targetPlayer.getId());
effect.setTargetPointer(new SecondTargetPointer());
effect.setText("Target player gains control of up to three target nonattacking creatures until end of turn");
game.addEffect(effect, source);
Effect effect2 = new UntapTargetEffect();
effect2.setTargetPointer(new SecondTargetPointer());
effect2.setText("Untap those creatures");
effect2.apply(game, source);
RequirementEffect effect3 = new BlocksIfAbleTargetEffect(Duration.EndOfTurn);
effect3.setTargetPointer(new SecondTargetPointer());
effect3.setText("They block this turn if able");
game.addEffect(effect3, source);
return true;
}
return false;
}
use of mage.abilities.effects.RequirementEffect in project mage by magefree.
the class ImaginaryThreatsEffect method apply.
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source));
if (player != null) {
FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(new ControllerIdPredicate(player.getId()));
RequirementEffect effect = new AttacksIfAbleAllEffect(filter, Duration.EndOfTurn);
game.addEffect(effect, source);
return true;
}
return false;
}
use of mage.abilities.effects.RequirementEffect in project mage by magefree.
the class Combat method checkBlockRequirementsAfter.
/**
* 509.1c The defending player checks each creature they control to see
* whether it's affected by any requirements (effects that say a creature
* must block, or that it must block if some condition is met). If the
* number of requirements that are being obeyed is fewer than the maximum
* possible number of requirements that could be obeyed without disobeying
* any restrictions, the declaration of blockers is illegal. If a creature
* can't block unless a player pays a cost, that player is not required to
* pay that cost, even if blocking with that creature would increase the
* number of requirements being obeyed.
* <p>
* <p>
* Example: A player controls one creature that "blocks if able" and another
* creature with no abilities. An effect states "Creatures can't be blocked
* except by two or more creatures." Having only the first creature block
* violates the restriction. Having neither creature block fulfills the
* restriction but not the requirement. Having both creatures block the same
* attacking creature fulfills both the restriction and the requirement, so
* that's the only option.
*
* @param player
* @param controller
* @param game
* @return
*/
public boolean checkBlockRequirementsAfter(Player player, Player controller, Game game) {
// Get once a list of all opponents in range
Set<UUID> opponents = game.getOpponents(attackingPlayerId);
// 20101001 - 509.1c
// map with attackers (UUID) that must be blocked by at least one blocker and a set of all creatures that can block it and don't block yet
Map<UUID, Set<UUID>> mustBeBlockedByAtLeastX = new HashMap<>();
Map<UUID, Integer> minNumberOfBlockersMap = new HashMap<>();
// check mustBlock requirements of creatures from opponents of attacking player
for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED, player.getId(), game)) {
// creature is controlled by an opponent of the attacker
if (opponents.contains(creature.getControllerId())) {
// Creature is already blocking but not forced to do so
if (creature.getBlocking() > 0) {
// get all requirement effects that apply to the creature (e.g. is able to block attacker)
for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, false, game).entrySet()) {
RequirementEffect effect = entry.getKey();
// get possible mustBeBlockedByAtLeastX blocker
for (Ability ability : entry.getValue()) {
UUID toBeBlockedCreature = effect.mustBlockAttackerIfElseUnblocked(ability, game);
if (toBeBlockedCreature != null) {
CombatGroup toBeBlockedGroup = findGroup(toBeBlockedCreature);
if (toBeBlockedGroup != null && toBeBlockedGroup.getDefendingPlayerId().equals(creature.getControllerId())) {
minNumberOfBlockersMap.put(toBeBlockedCreature, effect.getMinNumberOfBlockers());
Set<UUID> potentialBlockers;
if (mustBeBlockedByAtLeastX.containsKey(toBeBlockedCreature)) {
potentialBlockers = mustBeBlockedByAtLeastX.get(toBeBlockedCreature);
} else {
potentialBlockers = new HashSet<>();
mustBeBlockedByAtLeastX.put(toBeBlockedCreature, potentialBlockers);
}
potentialBlockers.add(creature.getId());
}
}
}
// check the mustBlockAllAttackers requirement for creatures already blocking (Blaze of Glory) -------------------------------
if (effect.mustBlockAllAttackers(game)) {
// find all the attackers that the creature can block (and no restictions prevent this)
Set<UUID> attackersToBlock = new HashSet<>();
boolean mayBlock = false;
for (UUID attackingCreatureId : getAttackers()) {
if (creature.canBlock(attackingCreatureId, game)) {
Permanent attackingCreature = game.getPermanent(attackingCreatureId);
if (attackingCreature != null) {
// check if the attacker is already blocked by a max of blockers, so blocker can't block it also
if (attackingCreature.getMaxBlockedBy() != 0) {
// 0 = no restriction about the number of possible blockers
int alreadyBlockingCreatures = 0;
for (CombatGroup group : getGroups()) {
if (group.getAttackers().contains(attackingCreatureId)) {
alreadyBlockingCreatures = group.getBlockers().size();
break;
}
}
if (attackingCreature.getMaxBlockedBy() <= alreadyBlockingCreatures) {
// Attacker can't be blocked by more blockers so check next attacker
continue;
}
}
// check if enough possible blockers are available, if true, mayBlock can be set to true
if (attackingCreature.getMinBlockedBy() > 1) {
int alreadyBlockingCreatures = 0;
for (CombatGroup group : getGroups()) {
if (group.getAttackers().contains(attackingCreatureId)) {
alreadyBlockingCreatures = group.getBlockers().size();
break;
}
}
if (attackingCreature.getMinBlockedBy() >= alreadyBlockingCreatures) {
// Attacker can't be blocked by the current blocker amount so check next attacker
continue;
}
} else {
attackersToBlock.add(attackingCreatureId);
}
}
}
}
if (!attackersToBlock.isEmpty()) {
for (UUID attackerId : attackersToBlock) {
if (!findGroup(attackerId).getBlockers().contains(creature.getId())) {
mayBlock = true;
break;
}
}
}
// if creature can block more attackers, inform human player or set blocks for AI player
if (mayBlock) {
if (controller.isHuman()) {
controller.resetPlayerPassedActions();
game.informPlayer(controller, "Creature should block all attackers it's able to this turn: " + creature.getIdName());
} else {
Player defender = game.getPlayer(creature.getControllerId());
if (defender != null) {
for (UUID attackingCreatureId : getAttackers()) {
if (creature.canBlock(attackingCreatureId, game) && !findGroup(attackingCreatureId).getBlockers().contains(creature.getId()) && attackersToBlock.contains(attackingCreatureId)) {
// TODO: might need to revisit this (calls some pickBlockerOrder instances even for a single blocker - damage distribution appears to be working correctly however)
defender.declareBlocker(defender.getId(), creature.getId(), attackingCreatureId, game);
}
}
}
}
return false;
}
}
}
}
// Creature is not blocking yet
if (creature.getBlocking() == 0) {
// get all requirement effects that apply to the creature
for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, false, game).entrySet()) {
RequirementEffect effect = entry.getKey();
// get possible mustBeBlockedByAtLeastX blocker
for (Ability ability : entry.getValue()) {
UUID toBeBlockedCreature = effect.mustBlockAttackerIfElseUnblocked(ability, game);
if (toBeBlockedCreature != null) {
CombatGroup toBeBlockedGroup = findGroup(toBeBlockedCreature);
if (toBeBlockedGroup != null && toBeBlockedGroup.getDefendingPlayerId().equals(creature.getControllerId())) {
minNumberOfBlockersMap.put(toBeBlockedCreature, effect.getMinNumberOfBlockers());
Set<UUID> potentialBlockers;
if (mustBeBlockedByAtLeastX.containsKey(toBeBlockedCreature)) {
potentialBlockers = mustBeBlockedByAtLeastX.get(toBeBlockedCreature);
} else {
potentialBlockers = new HashSet<>();
mustBeBlockedByAtLeastX.put(toBeBlockedCreature, potentialBlockers);
}
potentialBlockers.add(creature.getId());
}
}
}
// check the mustBlockAny requirement (and mustBlockAllAttackers for not blocking creatures) ----------------------------------------
if (effect.mustBlockAny(game) || effect.mustBlockAllAttackers(game)) {
// check that it can block at least one of the attackers and no restictions prevent this
boolean mayBlock = false;
for (UUID attackingCreatureId : getAttackers()) {
if (creature.canBlock(attackingCreatureId, game)) {
Permanent attackingCreature = game.getPermanent(attackingCreatureId);
if (attackingCreature != null) {
// check if the attacker is already blocked by a max of blockers, so blocker can't block it also
if (attackingCreature.getMaxBlockedBy() != 0) {
// 0 = no restriction about the number of possible blockers
int alreadyBlockingCreatures = 0;
for (CombatGroup group : getGroups()) {
if (group.getAttackers().contains(attackingCreatureId)) {
alreadyBlockingCreatures = group.getBlockers().size();
break;
}
}
if (attackingCreature.getMaxBlockedBy() <= alreadyBlockingCreatures) {
// Attacker can't be blocked by more blockers so check next attacker
continue;
}
}
// check if enough possible blockers are available, if true, mayBlock can be set to true
if (attackingCreature.getMinBlockedBy() > 1) {
int alreadyBlockingCreatures = 0;
for (CombatGroup group : getGroups()) {
if (group.getAttackers().contains(attackingCreatureId)) {
alreadyBlockingCreatures = group.getBlockers().size();
break;
}
}
if (attackingCreature.getMinBlockedBy() >= alreadyBlockingCreatures) {
// Attacker can't be blocked by the current blocker amount so check next attacker
continue;
}
} else {
mayBlock = true;
break;
}
}
}
}
// if creature can block, inform human player or set block for AI player
if (mayBlock) {
if (controller.isHuman()) {
controller.resetPlayerPassedActions();
game.informPlayer(controller, "Creature should block this turn: " + creature.getIdName());
} else {
Player defender = game.getPlayer(creature.getControllerId());
if (defender != null) {
for (UUID attackingCreatureId : getAttackers()) {
if (creature.canBlock(attackingCreatureId, game) && !findGroup(attackingCreatureId).getBlockers().contains(creature.getId())) {
defender.declareBlocker(defender.getId(), creature.getId(), attackingCreatureId, game);
break;
}
}
}
}
return false;
}
}
}
}
}
}
// check if for attacking creatures with mustBeBlockedByAtLeastX requirements are fulfilled
for (UUID toBeBlockedCreatureId : mustBeBlockedByAtLeastX.keySet()) {
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
if (combatGroup.getAttackers().contains(toBeBlockedCreatureId)) {
boolean requirementFulfilled = false;
// Check whether an applicable creature is blocking.
for (UUID blockerId : combatGroup.getBlockers()) {
if (mustBeBlockedByAtLeastX.get(toBeBlockedCreatureId).contains(blockerId)) {
requirementFulfilled = true;
break;
}
}
requirementFulfilled &= (combatGroup.getBlockers().size() >= Math.min(minNumberOfBlockersMap.get(toBeBlockedCreatureId), mustBeBlockedByAtLeastX.get(toBeBlockedCreatureId).size()));
if (!requirementFulfilled) {
// creature is not blocked but has possible blockers
if (controller.isHuman()) {
Permanent toBeBlockedCreature = game.getPermanent(toBeBlockedCreatureId);
if (toBeBlockedCreature != null) {
// read through all possible blockers
for (UUID possibleBlockerId : mustBeBlockedByAtLeastX.get(toBeBlockedCreatureId)) {
if (combatGroup.getBlockers().contains(possibleBlockerId)) {
continue;
}
String blockRequiredMessage = isCreatureDoingARequiredBlock(possibleBlockerId, toBeBlockedCreatureId, mustBeBlockedByAtLeastX, game);
if (blockRequiredMessage != null) {
// message means not required
removeBlocker(possibleBlockerId, game);
controller.resetPlayerPassedActions();
game.informPlayer(controller, blockRequiredMessage + " Existing block removed. It's a requirement to block " + toBeBlockedCreature.getIdName() + '.');
return false;
}
}
}
} else {
// take the first potential blocker from the set to block for the AI
for (UUID possibleBlockerId : mustBeBlockedByAtLeastX.get(toBeBlockedCreatureId)) {
String blockRequiredMessage = isCreatureDoingARequiredBlock(possibleBlockerId, toBeBlockedCreatureId, mustBeBlockedByAtLeastX, game);
if (blockRequiredMessage != null) {
// set the block
Permanent possibleBlocker = game.getPermanent(possibleBlockerId);
Player defender = game.getPlayer(possibleBlocker.getControllerId());
if (defender != null) {
if (possibleBlocker.getBlocking() > 0) {
removeBlocker(possibleBlockerId, game);
}
defender.declareBlocker(defender.getId(), possibleBlockerId, toBeBlockedCreatureId, game);
}
if (combatGroup.getBlockers().size() >= minNumberOfBlockersMap.get(toBeBlockedCreatureId)) {
break;
}
}
}
}
}
}
}
}
// check if creatures are forced to block but do not block at all or block creatures they are not forced to block
StringBuilder sb = new StringBuilder();
for (Map.Entry<UUID, Set<UUID>> entry : creatureMustBlockAttackers.entrySet()) {
boolean blockIsValid = true;
Permanent creatureForcedToBlock = game.getPermanent(entry.getKey());
if (creatureForcedToBlock == null) {
break;
}
if (!creatureForcedToBlock.isControlledBy(player.getId())) {
// ignore creatures controlled by other players
continue;
}
// While if assigned all to one the block is possible
if (creatureForcedToBlock.getBlocking() == 0) {
blockIsValid = entry.getValue().isEmpty();
for (UUID possibleAttackerId : entry.getValue()) {
CombatGroup attackersGroup = game.getCombat().findGroup(possibleAttackerId);
Permanent attackingCreature = game.getPermanent(possibleAttackerId);
if (attackersGroup == null || attackingCreature == null) {
continue;
}
if (attackingCreature.getMinBlockedBy() > 1) {
// e.g. Menace
if (attackersGroup.getBlockers().size() + 1 < attackingCreature.getMinBlockedBy()) {
blockIsValid = true;
}
}
}
} else {
blockIsValid = false;
// which attacker is the creature blocking
CombatGroups: for (CombatGroup combatGroup : game.getCombat().getGroups()) {
if (combatGroup.getBlockers().contains(creatureForcedToBlock.getId())) {
for (UUID forcingAttackerId : combatGroup.getAttackers()) {
if (entry.getValue().contains(forcingAttackerId)) {
// the creature is blocking a forcing attacker, so the block is ok
blockIsValid = true;
break CombatGroups;
} else // check if the blocker blocks a attacker that must be blocked at least by one and is the only blocker, this block is also valid
{
if (combatGroup.getBlockers().size() == 1) {
if (mustBeBlockedByAtLeastX.containsKey(forcingAttackerId)) {
if (mustBeBlockedByAtLeastX.get(forcingAttackerId).contains(creatureForcedToBlock.getId())) {
blockIsValid = true;
break CombatGroups;
}
}
}
}
}
}
}
}
if (!blockIsValid) {
sb.append(' ').append(creatureForcedToBlock.getIdName());
}
}
if (sb.length() > 0) {
if (controller.isHuman()) {
controller.resetPlayerPassedActions();
sb.insert(0, "Some creatures are forced to block certain attacker(s):\n");
sb.append("\nPlease block with each of these creatures an appropriate attacker.");
game.informPlayer(controller, sb.toString());
}
return false;
}
return true;
}
Aggregations