Merge origin/master

This commit is contained in:
Oleg Agafonov 2018-12-07 01:21:32 +04:00
commit 1d450730c0
129 changed files with 5752 additions and 2644 deletions

View file

@ -1,4 +1,3 @@
package mage.abilities;
import java.util.UUID;
@ -154,13 +153,19 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
@Override
public ActivationStatus canActivate(UUID playerId, Game game) {
//20091005 - 602.2
if (!(hasMoreActivationsThisTurn(game) && (condition == null || condition.apply(game, this)))) {
if (!(hasMoreActivationsThisTurn(game)
&& (condition == null
|| condition.apply(game, this)))) {
return ActivationStatus.getFalse();
}
switch (mayActivate) {
case ANY:
break;
case ACTIVE:
if (game.getActivePlayerId() != playerId) {
return ActivationStatus.getFalse();
}
break;
case NOT_YOU:
if (controlsAbility(playerId, game)) {
return ActivationStatus.getFalse();
@ -198,9 +203,17 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
return ActivationStatus.getFalse();
}
//20091005 - 602.5d/602.5e
MageObjectReference permittingObject = game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game);
if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId) || null != permittingObject) {
if (costs.canPay(this, sourceId, playerId, game) && canChooseTarget(game)) {
MageObjectReference permittingObject = game.getContinuousEffects()
.asThough(sourceId,
AsThoughEffectType.ACTIVATE_AS_INSTANT,
this,
controllerId,
game);
if (timing == TimingRule.INSTANT
|| game.canPlaySorcery(playerId)
|| null != permittingObject) {
if (costs.canPay(this, sourceId, playerId, game)
&& canChooseTarget(game)) {
this.activatorId = playerId;
return new ActivationStatus(true, permittingObject);
}
@ -297,8 +310,10 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
}
protected ActivationInfo getActivationInfo(Game game) {
Integer turnNum = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsTurn" + originalId, sourceId, game));
Integer activationCount = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsCount" + originalId, sourceId, game));
Integer turnNum = (Integer) game.getState()
.getValue(CardUtil.getCardZoneString("activationsTurn" + originalId, sourceId, game));
Integer activationCount = (Integer) game.getState()
.getValue(CardUtil.getCardZoneString("activationsCount" + originalId, sourceId, game));
if (turnNum == null || activationCount == null) {
return null;
}
@ -306,7 +321,9 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
}
protected void setActivationInfo(ActivationInfo activationInfo, Game game) {
game.getState().setValue(CardUtil.getCardZoneString("activationsTurn" + originalId, sourceId, game), activationInfo.turnNum);
game.getState().setValue(CardUtil.getCardZoneString("activationsCount" + originalId, sourceId, game), activationInfo.activationCounter);
game.getState().setValue(CardUtil
.getCardZoneString("activationsTurn" + originalId, sourceId, game), activationInfo.turnNum);
game.getState().setValue(CardUtil
.getCardZoneString("activationsCount" + originalId, sourceId, game), activationInfo.activationCounter);
}
}

View file

@ -1,6 +1,6 @@
package mage.abilities.effects.common;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect;
@ -32,35 +32,58 @@ public class FightTargetsEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Card card = game.getCard(source.getSourceId());
if (card != null) {
// only if both targets are legal the effect will be applied
if (source.getTargets().get(0).isLegal(source, game) && source.getTargets().get(1).isLegal(source, game)) {
Permanent creature1 = game.getPermanent(source.getTargets().get(0).getFirstTarget());
Permanent creature2 = game.getPermanent(source.getTargets().get(1).getFirstTarget());
// 20110930 - 701.10
if (creature1 != null && creature2 != null) {
if (creature1.isCreature() && creature2.isCreature()) {
return creature1.fight(creature2, source, game);
}
UUID target1Id = null;
UUID target2Id = null;
// first target is in target pointer, second target is a normal target
if (source.getTargets().size() < 2) {
if (!source.getTargets().get(0).isLegal(source, game)) {
return false;
}
target1Id = getTargetPointer().getFirst(game, source);
target2Id = source.getTargets().getFirstTarget();
if (target1Id == target2Id) {
return false;
}
// two normal targets available, only if both targets are legal the effect will be applied
} else if (source.getTargets().get(0).isLegal(source, game) && source.getTargets().get(1).isLegal(source, game)) {
target1Id = source.getTargets().get(0).getFirstTarget();
target2Id = source.getTargets().get(1).getFirstTarget();
}
Permanent creature1 = game.getPermanent(target1Id);
Permanent creature2 = game.getPermanent(target2Id);
// 20110930 - 701.10
if (creature1 != null && creature2 != null) {
if (creature1.isCreature() && creature2.isCreature()) {
return creature1.fight(creature2, source, game);
}
}
if (!game.isSimulation()) {
game.informPlayers(card.getName() + " has been fizzled.");
}
}
if (!game.isSimulation()) {
game.informPlayers(card.getName() + " has been fizzled.");
}
return false;
}
@Override
public FightTargetsEffect copy() {
public FightTargetsEffect
copy() {
return new FightTargetsEffect(this);
}
@Override
public String getText(Mode mode) {
if (staticText != null && !staticText.isEmpty()) {
public String
getText(Mode mode
) {
if (staticText
!= null && !staticText
.isEmpty()) {
return staticText;
}
return "Target " + mode.getTargets().get(0).getTargetName() + " fights another target " + mode.getTargets().get(1).getTargetName();
return "Target " + mode
.getTargets().get(0).getTargetName() + " fights another target " + mode
.getTargets().get(1).getTargetName();
}
}

View file

@ -0,0 +1,55 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.events.GameEvent;
/**
*
* @author jeffwadsworth
*/
public class SkipCombatStepEffect extends ReplacementEffectImpl {
public SkipCombatStepEffect(Duration duration) {
super(duration, Outcome.Detriment);
staticText = "that player skips their next combat phase";
}
public SkipCombatStepEffect(final SkipCombatStepEffect effect) {
super(effect);
}
@Override
public SkipCombatStepEffect copy() {
return new SkipCombatStepEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.COMBAT_PHASE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return event.getPlayerId().equals(targetPointer.getFirst(game, source));
}
}

View file

@ -0,0 +1,55 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.events.GameEvent;
/**
*
* @author jeffwadsworth
*/
public class SkipNextDrawStepTargetEffect extends ReplacementEffectImpl {
public SkipNextDrawStepTargetEffect() {
super(Duration.OneUse, Outcome.Detriment);
staticText = "Target player skips his or her next draw step";
}
public SkipNextDrawStepTargetEffect(final SkipNextDrawStepTargetEffect effect) {
super(effect);
}
@Override
public SkipNextDrawStepTargetEffect copy() {
return new SkipNextDrawStepTargetEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DRAW_STEP;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return event.getPlayerId().equals(source.getFirstTarget());
}
}

View file

@ -1,5 +1,8 @@
package mage.abilities.meta;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.TriggeredAbility;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
@ -8,10 +11,6 @@ import mage.game.Game;
import mage.game.events.GameEvent;
import mage.watchers.Watcher;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* A triggered ability that combines several others and triggers whenever one or
* more of them would. The abilities passed in should have null as their effect,
@ -56,7 +55,6 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl {
public boolean checkEventType(GameEvent event, Game game) {
for (TriggeredAbility ability : triggeredAbilities) {
if (ability.checkEventType(event, game)) {
System.out.println("Correct event type (" + event.getType() + ")");
return true;
}
}
@ -69,11 +67,9 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl {
for (int i = 0; i < triggeredAbilities.length; i++) {
TriggeredAbility ability = triggeredAbilities[i];
if (ability.checkEventType(event, game) && ability.checkTrigger(event, game)) {
System.out.println("Triggered from " + ability.getRule());
triggeringAbilities.add(i);
toRet = true;
}
System.out.println("Checked " + ability.getRule());
}
return toRet;
}

View file

@ -32,7 +32,7 @@ public enum CardRepository {
// raise this if db structure was changed
private static final long CARD_DB_VERSION = 51;
// raise this if new cards were added to the server
private static final long CARD_CONTENT_VERSION = 122;
private static final long CARD_CONTENT_VERSION = 123;
private Dao<CardInfo, Object> cardDao;
private Set<String> classNames;

View file

@ -9,6 +9,7 @@ public enum CounterType {
AGE("age"),
AIM("aim"),
ARROW("arrow"),
ARROWHEAD("arrowhead"),
AWAKENING("awakening"),
BLAZE("blaze"),

View file

@ -0,0 +1,48 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.filter.predicate.other;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Mode;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
import mage.game.stack.StackObject;
import mage.players.Player;
import mage.target.Target;
/**
*
* @author jeffwadsworth
*/
public class TargetsPlayerPredicate implements ObjectSourcePlayerPredicate<ObjectSourcePlayer<MageObject>> {
public TargetsPlayerPredicate() {
}
@Override
public boolean apply(ObjectSourcePlayer<MageObject> input, Game game) {
StackObject object = game.getStack().getStackObject(input.getObject().getId());
if (object != null) {
for (UUID modeId : object.getStackAbility().getModes().getSelectedModes()) {
Mode mode = object.getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) {
Player player = game.getPlayer(targetId);
return player != null;
}
}
}
}
return false;
}
@Override
public String toString() {
return "that targets a player";
}
}

View file

@ -37,6 +37,7 @@ public class MatchOptions implements Serializable {
protected boolean spectatorsAllowed;
protected boolean planeChase;
protected int quitRatio;
protected int minimumRating;
protected int edhPowerLevel;
protected boolean rated;
protected int numSeatsForMatch;
@ -205,6 +206,10 @@ public class MatchOptions implements Serializable {
this.quitRatio = quitRatio;
}
public int getMinimumRating() { return minimumRating; }
public void setMinimumRating(int minimumRating) { this.minimumRating = minimumRating; }
public int getEdhPowerLevel() {
return edhPowerLevel;
}

View file

@ -24,6 +24,7 @@ public class TournamentOptions implements Serializable {
protected int numberRounds;
protected String password;
protected int quitRatio;
protected int minimumRating;
public TournamentOptions(String name, String matchType, int numSeats) {
this.name = name;
@ -98,4 +99,8 @@ public class TournamentOptions implements Serializable {
public void setQuitRatio(int quitRatio) {
this.quitRatio = quitRatio;
}
public int getMinimumRating() { return minimumRating; }
public void setMinimumRating(int minimumRating) { this.minimumRating = minimumRating; }
}

View file

@ -349,6 +349,15 @@ public interface Player extends MageItem, Copyable<Player> {
*/
boolean searchLibrary(TargetCardInLibrary target, Game game, UUID targetPlayerId, boolean triggerEvents);
/**
* Reveals all players' libraries. Useful for abilities like Jace, Architect of Thought's -8
* that have effects that require information from all libraries.
* @param source
* @param game
* @return
*/
void lookAtAllLibraries(Ability source, Game game);
boolean canPlayLand();
/**

View file

@ -2489,6 +2489,17 @@ public abstract class PlayerImpl implements Player, Serializable {
return false;
}
@Override
public void lookAtAllLibraries(Ability source, Game game) {
for(UUID playerId : game.getState().getPlayersInRange(this.getId(), game)){
Player player = game.getPlayer(playerId);
String playerName = this.getName().equals(player.getName()) ? "Your " : player.getName() + "'s ";
playerName += "library";
Cards cardsInLibrary = new CardsImpl(player.getLibrary().getTopCards(game, player.getLibrary().size()));
lookAtCards(playerName, cardsInLibrary, game);
}
}
private boolean handleLibraryCastableCards(Library library, Game game, UUID targetPlayerId) {
// for handling Panglacial Wurm
boolean alreadyChosenUse = false;

View file

@ -33,8 +33,8 @@ public final class ClassScanner {
if(classLoader == null) classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
HashMap<String, String> dirs = new HashMap<>();
TreeSet<String> jars = new TreeSet<>();
Map<String, String> dirs = new HashMap<>();
Set<String> jars = new TreeSet<>();
for (String packageName : packages) {
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
@ -51,8 +51,8 @@ public final class ClassScanner {
}
}
for (String filePath : dirs.keySet()) {
cards.addAll(findClasses(classLoader, new File(filePath), dirs.get(filePath), type));
for (Map.Entry<String, String> dir : dirs.entrySet()) {
cards.addAll(findClasses(classLoader, new File(dir.getKey()), dir.getValue(), type));
}
for (String filePath : jars) {
@ -66,7 +66,7 @@ public final class ClassScanner {
private static List<Class> findClasses(ClassLoader classLoader, File directory, String packageName, Class<?> type) {
List<Class> cards = new ArrayList<>();
if (!directory.exists()) return cards;
if (directory == null || !directory.exists()) return cards;
for (File file : directory.listFiles()) {
if (file.getName().endsWith(".class")) {