mirror of
https://github.com/correl/mage.git
synced 2024-11-15 19:19:33 +00:00
Removed redundant combat code for handling block effect of Odric Master Tactician.
This commit is contained in:
parent
19679c9f6e
commit
bd77e476ee
2 changed files with 134 additions and 135 deletions
|
@ -142,28 +142,12 @@ class OdricMasterTacticianEffect extends ReplacementEffectImpl<OdricMasterTactic
|
|||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
//20101001 - 509.1c
|
||||
game.getCombat().checkBlockRequirementsBefore(player, game);
|
||||
for (UUID defenderId : game.getCombat().getPlayerDefenders(game)) {
|
||||
boolean choose = true;
|
||||
while (choose) {
|
||||
game.getPlayer(source.getControllerId()).selectBlockers(game, defenderId);
|
||||
if (game.isPaused() || game.isGameOver()) {
|
||||
Player blockController = game.getPlayer(source.getControllerId());
|
||||
if (blockController != null) {
|
||||
game.getCombat().selectBlockers(blockController, game);
|
||||
return true;
|
||||
}
|
||||
if (!game.getCombat().checkBlockRestrictions(game.getPlayer(defenderId), game)) {
|
||||
// only human player can decide to do the block in another way
|
||||
if (player.isHuman()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
choose = !game.getCombat().checkBlockRequirementsAfter(game.getPlayer(defenderId), player, game);
|
||||
}
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, defenderId, defenderId));
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,31 +1,30 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.game.combat;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
@ -57,7 +56,6 @@ import mage.util.CardUtil;
|
|||
import mage.util.Copyable;
|
||||
import mage.util.trace.TraceUtil;
|
||||
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
@ -81,7 +79,6 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
private final Map<UUID, Set<UUID>> creaturesForcedToAttack = new HashMap<UUID, Set<UUID>>();
|
||||
private int maxAttackers = Integer.MIN_VALUE;
|
||||
|
||||
|
||||
public Combat() {
|
||||
this.useToughnessForDamage = false;
|
||||
}
|
||||
|
@ -163,8 +160,8 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add an additional attacker to the combat (e.g. token of Geist of Saint Traft)
|
||||
* This method doesn't trigger ATTACKER_DECLARED event (as intended).
|
||||
* Add an additional attacker to the combat (e.g. token of Geist of Saint
|
||||
* Traft) This method doesn't trigger ATTACKER_DECLARED event (as intended).
|
||||
*
|
||||
* @param creatureId - creature that shall be added to the combat
|
||||
* @param game
|
||||
|
@ -175,8 +172,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
if (defenders.size() == 1) {
|
||||
declareAttacker(creatureId, defenders.iterator().next(), game);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
TargetDefender target = new TargetDefender(defenders, creatureId);
|
||||
target.setRequired(true);
|
||||
player.chooseTarget(Outcome.Damage, target, null, game);
|
||||
|
@ -204,8 +200,8 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
|
||||
public void resumeSelectAttackers(Game game) {
|
||||
Player player = game.getPlayer(attackerId);
|
||||
for (CombatGroup group: groups) {
|
||||
for (UUID attacker: group.getAttackers()) {
|
||||
for (CombatGroup group : groups) {
|
||||
for (UUID attacker : group.getAttackers()) {
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ATTACKER_DECLARED, group.defenderId, attacker, attackerId));
|
||||
}
|
||||
}
|
||||
|
@ -217,14 +213,14 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
//20101001 - 508.1d
|
||||
for (Permanent creature : player.getAvailableAttackers(game)) {
|
||||
boolean mustAttack = false;
|
||||
Set <UUID> defendersForcedToAttack = new HashSet<UUID>();
|
||||
Set<UUID> defendersForcedToAttack = new HashSet<UUID>();
|
||||
for (Map.Entry entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) {
|
||||
RequirementEffect effect = (RequirementEffect)entry.getKey();
|
||||
RequirementEffect effect = (RequirementEffect) entry.getKey();
|
||||
if (effect.mustAttack(game)) {
|
||||
mustAttack = true;
|
||||
for (Ability ability: (HashSet<Ability>)entry.getValue()) {
|
||||
for (Ability ability : (HashSet<Ability>) entry.getValue()) {
|
||||
UUID defenderId = effect.mustAttackDefender(ability, game);
|
||||
if(defenderId != null) {
|
||||
if (defenderId != null) {
|
||||
defendersForcedToAttack.add(defenderId);
|
||||
}
|
||||
break;
|
||||
|
@ -232,7 +228,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
}
|
||||
}
|
||||
if (mustAttack) {
|
||||
creaturesForcedToAttack.put(creature.getId(),defendersForcedToAttack);
|
||||
creaturesForcedToAttack.put(creature.getId(), defendersForcedToAttack);
|
||||
if (defendersForcedToAttack.isEmpty()) {
|
||||
if (defenders.size() == 1) {
|
||||
player.declareAttacker(creature.getId(), defenders.iterator().next(), game);
|
||||
|
@ -253,16 +249,16 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
|
||||
protected void checkAttackRestrictions(Player player, Game game) {
|
||||
int count = 0;
|
||||
for (CombatGroup group: groups) {
|
||||
for (CombatGroup group : groups) {
|
||||
count += group.getAttackers().size();
|
||||
}
|
||||
|
||||
if (count > 1) {
|
||||
List<UUID> tobeRemoved = new ArrayList<UUID>();
|
||||
for (CombatGroup group: groups) {
|
||||
for (UUID attackingCreatureId: group.getAttackers()) {
|
||||
for (CombatGroup group : groups) {
|
||||
for (UUID attackingCreatureId : group.getAttackers()) {
|
||||
Permanent attacker = game.getPermanent(attackingCreatureId);
|
||||
if (count >1 && attacker != null && attacker.getAbilities().containsKey(CanAttackOnlyAloneAbility.getInstance().getId())) {
|
||||
if (count > 1 && attacker != null && attacker.getAbilities().containsKey(CanAttackOnlyAloneAbility.getInstance().getId())) {
|
||||
game.informPlayers(attacker.getName() + " can only attack alone. Removing it from combat.");
|
||||
tobeRemoved.add(attackingCreatureId);
|
||||
count--;
|
||||
|
@ -276,8 +272,8 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
|
||||
if (count == 1) {
|
||||
List<UUID> tobeRemoved = new ArrayList<UUID>();
|
||||
for (CombatGroup group: groups) {
|
||||
for (UUID attackingCreatureId: group.getAttackers()) {
|
||||
for (CombatGroup group : groups) {
|
||||
for (UUID attackingCreatureId : group.getAttackers()) {
|
||||
Permanent attacker = game.getPermanent(attackingCreatureId);
|
||||
if (attacker != null && attacker.getAbilities().containsKey(CantAttackAloneAbility.getInstance().getId())) {
|
||||
game.informPlayers(attacker.getName() + " can't attack alone. Removing it from combat.");
|
||||
|
@ -295,40 +291,63 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
|
||||
public void selectBlockers(Game game) {
|
||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_BLOCKERS, attackerId, attackerId))) {
|
||||
game.getCombat().selectBlockers(null, game);
|
||||
}
|
||||
}
|
||||
|
||||
// !! Attention: Changes to this block must be also done in card "OdricMaster Tactician".
|
||||
Player player = game.getPlayer(attackerId);
|
||||
/**
|
||||
* Handle the blocker selection process
|
||||
*
|
||||
* @param blockController player that controlls how to block, if null the defender is the controller
|
||||
* @param game
|
||||
*/
|
||||
public void selectBlockers(Player blockController, Game game) {
|
||||
Player attacker = game.getPlayer(attackerId);
|
||||
//20101001 - 509.1c
|
||||
checkBlockRequirementsBefore(player, game);
|
||||
this.checkBlockRequirementsBefore(attacker, game);
|
||||
for (UUID defenderId : getPlayerDefenders(game)) {
|
||||
boolean choose = true;
|
||||
Player defender = game.getPlayer(defenderId);
|
||||
if (defender != null) {
|
||||
boolean choose = true;
|
||||
if (blockController == null) {
|
||||
blockController = defender;
|
||||
}
|
||||
while (choose) {
|
||||
game.getPlayer(defenderId).selectBlockers(game, defenderId);
|
||||
blockController.selectBlockers(game, defenderId);
|
||||
if (game.isPaused() || game.isGameOver()) {
|
||||
return;
|
||||
}
|
||||
if (!checkBlockRestrictions(game.getPlayer(defenderId), game)) {
|
||||
// only human player can decide to do the block in another way
|
||||
if (defender.isHuman()) {
|
||||
if (!this.checkBlockRestrictions(defender, game)) {
|
||||
if (blockController.isHuman()) { // only human player can decide to do the block in another way
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
choose = !checkBlockRequirementsAfter(defender, defender, game);
|
||||
choose = !this.checkBlockRequirementsAfter(defender, blockController, game);
|
||||
}
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, defenderId, defenderId));
|
||||
|
||||
// add info about attacker blocked by blocker to the game log
|
||||
this.logBlockerInfo(defender, game);
|
||||
}
|
||||
}
|
||||
// tool to catch the bug about flyers blocked by non flyers or intimidate blocked by creatures with other colors
|
||||
TraceUtil.traceCombatIfNeeded(game, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add info about attacker blocked by blocker to the game log
|
||||
*
|
||||
*/
|
||||
private void logBlockerInfo(Player defender, Game game) {
|
||||
boolean shownDefendingPlayer = false;
|
||||
for (CombatGroup group :this.getGroups()) {
|
||||
if (group.defendingPlayerId.equals(defenderId)) {
|
||||
if (!shownDefendingPlayer && defender != null) {
|
||||
for (CombatGroup group : this.getGroups()) {
|
||||
if (group.defendingPlayerId.equals(defender.getId())) {
|
||||
if (!shownDefendingPlayer) {
|
||||
game.informPlayers(new StringBuilder("Attacked player: ").append(defender.getName()).toString());
|
||||
shownDefendingPlayer = true;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(UUID attackingCreatureId : group.getAttackers()) {
|
||||
for (UUID attackingCreatureId : group.getAttackers()) {
|
||||
Permanent attackingCreature = game.getPermanent(attackingCreatureId);
|
||||
if (attackingCreature != null) {
|
||||
sb.append(attackingCreature.getName()).append(" (");
|
||||
|
@ -343,7 +362,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
}
|
||||
if (group.getBlockers().size() > 0) {
|
||||
sb.append("blocked by ");
|
||||
for(UUID blockingCreatureId : group.getBlockers()) {
|
||||
for (UUID blockingCreatureId : group.getBlockers()) {
|
||||
Permanent blockingCreature = game.getPermanent(blockingCreatureId);
|
||||
if (blockingCreature != null) {
|
||||
sb.append(blockingCreature.getName()).append(" (");
|
||||
|
@ -351,20 +370,17 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
}
|
||||
}
|
||||
|
||||
} else{
|
||||
} else {
|
||||
sb.append("unblocked");
|
||||
}
|
||||
game.informPlayers(sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
TraceUtil.traceCombatIfNeeded(game, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Check the block restrictions
|
||||
*
|
||||
* @param player
|
||||
* @param game
|
||||
* @return false - if block restrictions were not complied
|
||||
|
@ -372,7 +388,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
public boolean checkBlockRestrictions(Player player, Game game) {
|
||||
int count = 0;
|
||||
boolean blockWasLegal = true;
|
||||
for (CombatGroup group: groups) {
|
||||
for (CombatGroup group : groups) {
|
||||
count += group.getBlockers().size();
|
||||
}
|
||||
for (CombatGroup group : groups) {
|
||||
|
@ -412,9 +428,9 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
for (Permanent creature : game.getBattlefield().getActivePermanents(filterBlockers, player.getId(), game)) {
|
||||
if (game.getOpponents(attackerId).contains(creature.getControllerId())) {
|
||||
for (Map.Entry entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) {
|
||||
RequirementEffect effect = (RequirementEffect)entry.getKey();
|
||||
RequirementEffect effect = (RequirementEffect) entry.getKey();
|
||||
if (effect.mustBlock(game)) {
|
||||
for (Ability ability: (HashSet<Ability>)entry.getValue()) {
|
||||
for (Ability ability : (HashSet<Ability>) entry.getValue()) {
|
||||
UUID attackId = effect.mustBlockAttacker(ability, game);
|
||||
Player defender = game.getPlayer(creature.getControllerId());
|
||||
if (attackId != null && defender != null) {
|
||||
|
@ -451,9 +467,9 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
if (creature.getBlocking() > 0) {
|
||||
// get all requirement effects that apply to the creature (ce.g. is able to block attacker)
|
||||
for (Map.Entry entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) {
|
||||
RequirementEffect effect = (RequirementEffect)entry.getKey();
|
||||
RequirementEffect effect = (RequirementEffect) entry.getKey();
|
||||
// get possible mustBeBlockedByAtLeastOne blocker
|
||||
for (Ability ability: (HashSet<Ability>)entry.getValue()) {
|
||||
for (Ability ability : (HashSet<Ability>) entry.getValue()) {
|
||||
UUID toBeBlockedCreature = effect.mustBlockAttackerIfElseUnblocked(ability, game);
|
||||
if (toBeBlockedCreature != null) {
|
||||
Set<UUID> potentialBlockers;
|
||||
|
@ -473,9 +489,9 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
if (creature.getBlocking() == 0) {
|
||||
// get all requirement effects that apply to the creature
|
||||
for (Map.Entry entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) {
|
||||
RequirementEffect effect = (RequirementEffect)entry.getKey();
|
||||
RequirementEffect effect = (RequirementEffect) entry.getKey();
|
||||
// get possible mustBeBlockedByAtLeastOne blocker
|
||||
for (Ability ability: (HashSet<Ability>)entry.getValue()) {
|
||||
for (Ability ability : (HashSet<Ability>) entry.getValue()) {
|
||||
UUID toBeBlockedCreature = effect.mustBlockAttackerIfElseUnblocked(ability, game);
|
||||
if (toBeBlockedCreature != null) {
|
||||
Set<UUID> potentialBlockers;
|
||||
|
@ -499,7 +515,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
break;
|
||||
}
|
||||
}
|
||||
// is so inform human player or set block for AI player
|
||||
// if so inform human player or set block for AI player
|
||||
if (mayBlock) {
|
||||
if (controller.isHuman()) {
|
||||
game.informPlayer(controller, "Creature should block this turn: " + creature.getName());
|
||||
|
@ -526,7 +542,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
}
|
||||
|
||||
// check attacking creature mustBeBlockedByAtLeastOne
|
||||
for (UUID toBeBlockedCreatureId: mustBeBlockedByAtLeastOne.keySet()) {
|
||||
for (UUID toBeBlockedCreatureId : mustBeBlockedByAtLeastOne.keySet()) {
|
||||
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
|
||||
if (combatGroup.getBlockers().isEmpty() && combatGroup.getAttackers().contains(toBeBlockedCreatureId)) {
|
||||
// creature is not blocked but has possible blockers
|
||||
|
@ -592,7 +608,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
}
|
||||
// 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 :creaturesForcedToBlockAttackers.entrySet()) {
|
||||
for (Map.Entry<UUID, Set<UUID>> entry : creaturesForcedToBlockAttackers.entrySet()) {
|
||||
boolean blockIsValid;
|
||||
Permanent creatureForcedToBlock = game.getPermanent(entry.getKey());
|
||||
if (creatureForcedToBlock == null) {
|
||||
|
@ -607,7 +623,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
CombatGroups:
|
||||
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
|
||||
if (combatGroup.getBlockers().contains(creatureForcedToBlock.getId())) {
|
||||
for (UUID forcingAttackerId :combatGroup.getAttackers()) {
|
||||
for (UUID forcingAttackerId : combatGroup.getAttackers()) {
|
||||
if (entry.getValue().contains(forcingAttackerId)) {
|
||||
// the creature is blocking a forcing attacker, so the block is ok
|
||||
blockIsValid = true;
|
||||
|
@ -706,7 +722,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
return false;
|
||||
}
|
||||
|
||||
CombatGroup newGroup = new CombatGroup(defenderId, defender != null, defender != null ? defender.getControllerId(): defenderId);
|
||||
CombatGroup newGroup = new CombatGroup(defenderId, defender != null, defender != null ? defender.getControllerId() : defenderId);
|
||||
newGroup.attackers.add(attackerId);
|
||||
Permanent attacker = game.getPermanent(attackerId);
|
||||
if (!attacker.getAbilities().containsKey(VigilanceAbility.getInstance().getId())) {
|
||||
|
@ -969,7 +985,6 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
return maxAttackers;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Combat copy() {
|
||||
return new Combat(this);
|
||||
|
|
Loading…
Reference in a new issue