try to prevent constructing Strings during simulations

This commit is contained in:
betasteward 2015-01-22 22:01:24 -05:00
parent 74255eb808
commit a0085673be
65 changed files with 372 additions and 241 deletions

View file

@ -296,7 +296,8 @@ public abstract class AbilityImpl implements Ability {
}
if (getTargets().size() > 0 && getTargets().chooseTargets(getEffects().get(0).getOutcome(), this.controllerId, this, game) == false) {
if (variableManaCost != null || announceString != null) {
game.informPlayer(controller, new StringBuilder(sourceObject != null ? sourceObject.getLogName(): "").append(": no valid targets with this value of X").toString());
if (!game.isSimulation())
game.informPlayer(controller, new StringBuilder(sourceObject != null ? sourceObject.getLogName(): "").append(": no valid targets with this value of X").toString());
}
return false; // when activation of ability is canceled during target selection
}
@ -345,12 +346,14 @@ public abstract class AbilityImpl implements Ability {
return false;
}
// inform about x costs now, so canceled announcements are not shown in the log
if (announceString != null) {
game.informPlayers(announceString);
}
if (variableManaCost != null) {
int xValue = getManaCostsToPay().getX();
game.informPlayers(new StringBuilder(controller.getName()).append(" announces a value of ").append(xValue).append(" for ").append(variableManaCost.getText()).toString());
if (!game.isSimulation()) {
if (announceString != null) {
game.informPlayers(announceString);
}
if (variableManaCost != null) {
int xValue = getManaCostsToPay().getX();
game.informPlayers(new StringBuilder(controller.getName()).append(" announces a value of ").append(xValue).append(" for ").append(variableManaCost.getText()).toString());
}
}
activated = true;
// fire if tapped for mana (may only fire now because else costs of ability itself can be payed with mana of abilities that trigger for that event

View file

@ -89,7 +89,8 @@ class TurnFaceUpEffect extends OneShotEffect {
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (sourcePermanent != null) {
if (sourcePermanent.turnFaceUp(game, source.getControllerId())) {
game.informPlayers(controller.getName() + " pays the costs of " + card.getLogName() + " to turn it face up");
if (!game.isSimulation())
game.informPlayers(controller.getName() + " pays the costs of " + card.getLogName() + " to turn it face up");
return true;
}

View file

@ -63,7 +63,7 @@ public class ExileFromStackCost extends CostImpl {
return false;
}
paid |= spellToExile.moveToExile(null, "", ability.getSourceId(), game);
if (paid) {
if (paid && !game.isSimulation()) {
game.informPlayers(player.getName() + " exiles " + spellToExile.getName() +" (as costs)");
}
}

View file

@ -130,7 +130,8 @@ public class RemoveCounterCost extends CostImpl {
permanent.getCounters().removeCounter(counterName);
}
countersRemoved += numberOfCountersSelected;
game.informPlayers(new StringBuilder(controller.getName())
if (!game.isSimulation())
game.informPlayers(new StringBuilder(controller.getName())
.append(" removes ").append(numberOfCountersSelected == 1 ? "a":numberOfCountersSelected).append(" ")
.append(counterName).append(numberOfCountersSelected == 1 ? " counter from ":" counters from ")
.append(permanent.getName()).toString());

View file

@ -644,7 +644,7 @@ public class ContinuousEffects implements Serializable {
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
effect.setValue("targetAbility", targetAbility);
if (effect.applies(event, sourceAbility, game)) {
if (!checkPlayableMode) {
if (!checkPlayableMode && !game.isSimulation()) {
String message = effect.getInfoMessage(sourceAbility, event, game);
if (message != null && !message.isEmpty()) {
if (effect.sendMessageToUser()) {

View file

@ -82,7 +82,8 @@ public class PlaneswalkerRedirectionEffect extends RedirectionEffect {
else {
player.choose(Outcome.Damage, redirectTarget, null, game);
}
game.informPlayers(new StringBuilder(player.getName()).append(" redirects ")
if (!game.isSimulation())
game.informPlayers(new StringBuilder(player.getName()).append(" redirects ")
.append(event.getAmount())
.append(" damage to ")
.append(game.getPermanent(redirectTarget.getFirstTarget()).getLogName()).toString());

View file

@ -76,13 +76,15 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect {
while (player.chooseUse(Outcome.Benefit, choiceText, game)) {
Cards cards = player.getSideboard();
if (cards.isEmpty()) {
game.informPlayer(player, "You have no cards outside the game.");
if (!game.isSimulation())
game.informPlayer(player, "You have no cards outside the game.");
return false;
}
Set<Card> filtered = cards.getCards(filterCard, source.getSourceId(), source.getControllerId(), game);
if (filtered.isEmpty()) {
game.informPlayer(player, "You have no " + filterCard.getMessage() + " outside the game.");
if (!game.isSimulation())
game.informPlayer(player, "You have no " + filterCard.getMessage() + " outside the game.");
return false;
}

View file

@ -63,7 +63,8 @@ public class ChooseColorEffect extends OneShotEffect {
return false;
}
}
game.informPlayers(new StringBuilder(permanent.getLogName()).append(": ").append(controller.getName()).append(" has chosen ").append(choice.getChoice()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(permanent.getLogName()).append(": ").append(controller.getName()).append(" has chosen ").append(choice.getChoice()).toString());
game.getState().setValue(source.getSourceId() + "_color", choice.getColor());
permanent.addInfo("chosen color", "<font color = 'blue'>Chosen color: " + choice.getColor().getDescription() + "</font>", game);
return true;

View file

@ -67,7 +67,8 @@ public class ChooseCreatureTypeEffect extends OneShotEffect {
return false;
}
}
game.informPlayers(permanent.getName() + ": " + controller.getName() + " has chosen " + typeChoice.getChoice());
if (!game.isSimulation())
game.informPlayers(permanent.getName() + ": " + controller.getName() + " has chosen " + typeChoice.getChoice());
game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice());
permanent.addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game);
}

View file

@ -80,7 +80,8 @@ public class ChooseModeEffect extends OneShotEffect {
controller.choose(Outcome.Neutral, choice, game);
}
if (choice.isChosen()) {
game.informPlayers(new StringBuilder(sourcePermanent.getLogName()).append(": ").append(controller.getName()).append(" has chosen ").append(choice.getChoice()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(sourcePermanent.getLogName()).append(": ").append(controller.getName()).append(" has chosen ").append(choice.getChoice()).toString());
game.getState().setValue(source.getSourceId() + "_modeChoice", choice.getChoice());
sourcePermanent.addInfo("_modeChoice", "<font color = 'blue'>Chosen mode: " + choice.getChoice() + "</font>", game);
}

View file

@ -99,7 +99,8 @@ public class CipherEffect extends OneShotEffect {
ContinuousEffect effect = new GainAbilityTargetEffect(ability, Duration.Custom);
effect.setTargetPointer(new FixedTarget(target.getFirstTarget()));
game.addEffect(effect, source);
game.informPlayers(new StringBuilder(sourceCard.getLogName()).append(": Spell ciphered to ").append(targetCreature.getLogName()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(sourceCard.getLogName()).append(": Spell ciphered to ").append(targetCreature.getLogName()).toString());
return sourceCard.moveToExile(null, "", source.getSourceId(), game);
} else {
return false;

View file

@ -128,17 +128,19 @@ public class ClashEffect extends OneShotEffect implements MageSingleton {
} else {
message.append(" no card");
}
message.append(" - ");
if (cmcController > cmcOpponent) {
message.append(controller.getName()).append(" won the clash");
game.informPlayer(controller, "You won the clash!");
} else if (cmcController < cmcOpponent) {
message.append(opponent.getName()).append(" won the clash");
game.informPlayer(controller, opponent.getName() + " won the clash!");
} else {
message.append(" no winner ");
}
game.informPlayers(message.toString());
if (!game.isSimulation()) {
message.append(" - ");
if (cmcController > cmcOpponent) {
message.append(controller.getName()).append(" won the clash");
game.informPlayer(controller, "You won the clash!");
} else if (cmcController < cmcOpponent) {
message.append(opponent.getName()).append(" won the clash");
game.informPlayer(controller, opponent.getName() + " won the clash!");
} else {
message.append(" no winner ");
}
game.informPlayers(message.toString());
}
// decide to put the cards on top or on the buttom of library in turn order beginning with the active player in turn order
PlayerList playerList = game.getPlayerList().copy();

View file

@ -64,12 +64,14 @@ public class CopyTargetSpellEffect extends OneShotEffect {
copy.setCopiedSpell(true);
game.getStack().push(copy);
copy.chooseNewTargets(game, source.getControllerId());
Player player = game.getPlayer(source.getControllerId());
String activateMessage = copy.getActivatedMessage(game);
if (activateMessage.startsWith(" casts ")) {
activateMessage = activateMessage.substring(6);
if (!game.isSimulation()) {
Player player = game.getPlayer(source.getControllerId());
String activateMessage = copy.getActivatedMessage(game);
if (activateMessage.startsWith(" casts ")) {
activateMessage = activateMessage.substring(6);
}
game.informPlayers(player.getName() + " copies " + activateMessage);
}
game.informPlayers(player.getName() + " copies " + activateMessage);
return true;
}
return false;

View file

@ -73,7 +73,8 @@ public class DetainAllEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
List<FixedTarget> detainedObjects = new ArrayList<>();
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
game.informPlayers("Detained permanent: " + permanent.getName());
if (!game.isSimulation())
game.informPlayers("Detained permanent: " + permanent.getName());
FixedTarget fixedTarget = new FixedTarget(permanent.getId());
fixedTarget.init(game, source);
detainedObjects.add(fixedTarget);

View file

@ -79,10 +79,12 @@ public class DetainTargetEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
for (UUID target: this.getTargetPointer().getTargets(game, source)) {
Permanent permanent = game.getPermanent(target);
if (permanent != null) {
game.informPlayers("Detained permanent: " + permanent.getName());
if (!game.isSimulation()) {
for (UUID target: this.getTargetPointer().getTargets(game, source)) {
Permanent permanent = game.getPermanent(target);
if (permanent != null) {
game.informPlayers("Detained permanent: " + permanent.getName());
}
}
}
DetainRestrictionEffect effect = new DetainRestrictionEffect();

View file

@ -141,7 +141,8 @@ public class DevourEffect extends ReplacementEffectImpl {
if (target.getTargets().size() > 0) {
List<ArrayList<String>> cardSubtypes = new ArrayList<>();
int devouredCreatures = target.getTargets().size();
game.informPlayers(new StringBuilder(creature.getName()).append(" devours ").append(devouredCreatures).append(" creatures").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(creature.getName()).append(" devours ").append(devouredCreatures).append(" creatures").toString());
for (UUID targetId: target.getTargets()) {
Permanent targetCreature = game.getPermanent(targetId);
if (targetCreature != null) {

View file

@ -95,7 +95,8 @@ public class DoUnlessAnyPlayerPaysEffect extends OneShotEffect {
if (player != null && cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(Outcome.Detriment, message, game)) {
cost.clearPaid();
if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) {
game.informPlayers(player.getName() + " pays the cost to prevent the effect");
if (!game.isSimulation())
game.informPlayers(player.getName() + " pays the cost to prevent the effect");
doEffect = false;
break;
}

View file

@ -67,7 +67,8 @@ public class FightTargetSourceEffect extends OneShotEffect {
}
}
}
game.informPlayers(originalPermanent.getLogName() + ": Fighting effect has been fizzled.");
if (!game.isSimulation())
game.informPlayers(originalPermanent.getLogName() + ": Fighting effect has been fizzled.");
}
return false;
}

View file

@ -67,7 +67,8 @@ public class FightTargetsEffect extends OneShotEffect {
}
}
}
game.informPlayers(card.getName() + " has been fizzled.");
if (!game.isSimulation())
game.informPlayers(card.getName() + " has been fizzled.");
}
return false;
}

View file

@ -38,7 +38,8 @@ public class FlipSourceEffect extends OneShotEffect {
if (permanent.flip(game)) {
ContinuousEffect effect = new ConditionalContinousEffect(new CopyTokenEffect(flipToken), FlippedCondition.getInstance(), "");
game.addEffect(effect, source);
game.informPlayers(new StringBuilder(controller.getName()).append(" flips ").append(permanent.getName()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(controller.getName()).append(" flips ").append(permanent.getName()).toString());
return true;
}
}

View file

@ -141,7 +141,8 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff
player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId());
} else {
card.moveToZone(targetPickedCards, source.getSourceId(), game, false);
game.informPlayers(player.getName() + " moves a card to " + targetPickedCards.toString().toLowerCase());
if (!game.isSimulation())
game.informPlayers(player.getName() + " moves a card to " + targetPickedCards.toString().toLowerCase());
}
if (revealPickedCards) {
reveal.add(card);

View file

@ -93,7 +93,8 @@ public class NameACardEffect extends OneShotEffect {
}
}
String cardName = cardChoice.getChoice();
game.informPlayers(sourceObject.getLogName() + ", named card: [" + cardName + "]");
if (!game.isSimulation())
game.informPlayers(sourceObject.getLogName() + ", named card: [" + cardName + "]");
game.getState().setValue(source.getSourceId().toString() + INFO_KEY, cardName);
if (sourceObject instanceof Permanent) {
((Permanent)sourceObject).addInfo(INFO_KEY, CardUtil.addToolTipMarkTags("Named card: " + cardName), game);

View file

@ -94,7 +94,8 @@ public class PopulateEffect extends OneShotEffect {
player.choose(Outcome.Copy, target, source.getSourceId(), game);
Permanent tokenToCopy = game.getPermanent(target.getFirstTarget());
if (tokenToCopy != null) {
game.informPlayers("Token selected for populate: " + tokenToCopy.getLogName());
if (!game.isSimulation())
game.informPlayers("Token selected for populate: " + tokenToCopy.getLogName());
Effect effect = new PutTokenOntoBattlefieldCopyTargetEffect();
effect.setTargetPointer(new FixedTarget(target.getFirstTarget()));
return effect.apply(game, source);

View file

@ -80,15 +80,16 @@ public class PreventDamageToTargetMultiAmountEffect extends PreventionEffectImpl
player = game.getPlayer(targetId);
}
targetAmountMap.put(targetId, multiTarget.getTargetAmount(targetId));
StringBuilder sb = new StringBuilder(sourceObject.getName()).append(": Prevent the next ");
sb.append(multiTarget.getTargetAmount(targetId)).append(" damage to ");
if (player != null) {
sb.append(player.getName());
} else if (permanent != null) {
sb.append(permanent.getName());
if (!game.isSimulation()) {
StringBuilder sb = new StringBuilder(sourceObject.getName()).append(": Prevent the next ");
sb.append(multiTarget.getTargetAmount(targetId)).append(" damage to ");
if (player != null) {
sb.append(player.getName());
} else if (permanent != null) {
sb.append(permanent.getName());
}
game.informPlayers(sb.toString());
}
game.informPlayers(sb.toString());
}
}
}

View file

@ -69,8 +69,9 @@ public class PutTokenOntoBattlefieldCopySource extends OneShotEffect {
EmptyToken token = new EmptyToken();
CardUtil.copyTo(token).from((Permanent)thisCard);
if (token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId())) {
game.informPlayers(new StringBuilder(controller.getName())
.append(" puts a ").append(token.getName()).append(" token ").append("onto the Battlefield").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(controller.getName())
.append(" puts a ").append(token.getName()).append(" token ").append("onto the Battlefield").toString());
return true;
}
} else { // maybe it's token
@ -79,8 +80,9 @@ public class PutTokenOntoBattlefieldCopySource extends OneShotEffect {
EmptyToken token = new EmptyToken();
CardUtil.copyTo(token).from(permanent);
if (token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId())) {
game.informPlayers(new StringBuilder(controller.getName())
.append(" puts a ").append(token.getName()).append(" token ").append("onto the Battlefield").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(controller.getName())
.append(" puts a ").append(token.getName()).append(" token ").append("onto the Battlefield").toString());
return true;
}
}

View file

@ -92,7 +92,8 @@ public class ReturnFromExileEffect extends OneShotEffect {
switch (zone) {
case BATTLEFIELD:
card.moveToZone(zone, source.getSourceId(), game, tapped);
game.informPlayers(new StringBuilder(controller.getName()).append(" moves ").append(card.getName()).append(" to ").append(zone.toString()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(controller.getName()).append(" moves ").append(card.getName()).append(" to ").append(zone.toString()).toString());
break;
case HAND:
controller.moveCardToHandWithInfo(card, source.getSourceId(), game, Zone.EXILED);
@ -105,7 +106,8 @@ public class ReturnFromExileEffect extends OneShotEffect {
break;
default:
card.moveToZone(zone, source.getSourceId(), game, tapped);
game.informPlayers(new StringBuilder(controller.getName()).append(" moves ").append(card.getName()).append(" to ").append(zone.toString()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(controller.getName()).append(" moves ").append(card.getName()).append(" to ").append(zone.toString()).toString());
}
}
}

View file

@ -86,7 +86,8 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect {
if (card == null) {
return false;
}
game.informPlayers(controller.getName() + " moves " + card.getLogName() + " to " + zone.toString().toLowerCase());
if (!game.isSimulation())
game.informPlayers(controller.getName() + " moves " + card.getLogName() + " to " + zone.toString().toLowerCase());
card.moveToZone(zone, source.getSourceId(), game, tapped);
}
exile.clear();

View file

@ -80,10 +80,12 @@ public class TransformSourceEffect extends OneShotEffect {
} else {
permanent.transform(game);
}
if (fromDayToNight) {
game.informPlayers(new StringBuilder(permanent.getName()).append(" transforms into ").append(permanent.getSecondCardFace().getName()).toString());
} else {
game.informPlayers(new StringBuilder(permanent.getSecondCardFace().getName()).append(" transforms into ").append(permanent.getName()).toString());
if (!game.isSimulation()) {
if (fromDayToNight) {
game.informPlayers(new StringBuilder(permanent.getName()).append(" transforms into ").append(permanent.getSecondCardFace().getName()).toString());
} else {
game.informPlayers(new StringBuilder(permanent.getSecondCardFace().getName()).append(" transforms into ").append(permanent.getName()).toString());
}
}
}
}

View file

@ -96,7 +96,8 @@ public class BecomesColorTargetEffect extends ContinuousEffectImpl {
} else {
return false;
}
game.informPlayers(controller.getName() + " has chosen the color: " + objectColor.toString());
if (!game.isSimulation())
game.informPlayers(controller.getName() + " has chosen the color: " + objectColor.toString());
} else {
objectColor = this.setColor;
}

View file

@ -88,7 +88,8 @@ public class CommanderReplacementEffect extends ReplacementEffectImpl {
Player player = game.getPlayer(permanent.getOwnerId());
if (player != null && player.chooseUse(Outcome.Benefit, "Move commander to command zone?", game)){
boolean result = permanent.moveToZone(Zone.COMMAND, source.getSourceId(), game, false);
game.informPlayers(player.getName() + " has moved his or her commander to the command zone");
if (!game.isSimulation())
game.informPlayers(player.getName() + " has moved his or her commander to the command zone");
return result;
}
}
@ -107,7 +108,8 @@ public class CommanderReplacementEffect extends ReplacementEffectImpl {
Player player = game.getPlayer(card.getOwnerId());
if (player != null && player.chooseUse(Outcome.Benefit, "Move commander to command zone?", game)){
boolean result = card.moveToZone(Zone.COMMAND, source.getSourceId(), game, false);
game.informPlayers(player.getName() + " has moved his or her commander to the command zone");
if (!game.isSimulation())
game.informPlayers(player.getName() + " has moved his or her commander to the command zone");
return result;
}
}

View file

@ -77,7 +77,7 @@ public class GainProtectionFromColorTargetEffect extends GainAbilityTargetEffect
return;
}
}
if (choice.isChosen()) {
if (!game.isSimulation() && choice.isChosen()) {
game.informPlayers(sourceObject.getLogName() + ": " + controller.getName() + " has chosen protection from " + choice.getChoice());
}
}

View file

@ -72,7 +72,8 @@ public class AddCountersAllEffect extends OneShotEffect {
for (Permanent permanent : permanents) {
if (filter.match(permanent, source.getSourceId(), controllerId, game)) {
permanent.addCounters(counter.copy(), game);
game.informPlayers(new StringBuilder(sourceObject.getName()).append(": ")
if (!game.isSimulation())
game.informPlayers(new StringBuilder(sourceObject.getName()).append(": ")
.append(controller.getName()).append(" puts ")
.append(counter.getCount()).append(" ").append(counter.getName().toLowerCase())
.append(" counter on ").append(permanent.getName()).toString());

View file

@ -103,7 +103,7 @@ public class AddCountersSourceEffect extends OneShotEffect {
}
newCounter.add(countersToAdd);
card.addCounters(newCounter, game);
if (informPlayers) {
if (informPlayers && !game.isSimulation()) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
game.informPlayers(new StringBuilder(player.getName()).append(" puts ").append(newCounter.getCount()).append(" ").append(newCounter.getName().toLowerCase()).append(" counter on ").append(card.getLogName()).toString());
@ -125,7 +125,7 @@ public class AddCountersSourceEffect extends OneShotEffect {
int before = permanent.getCounters().getCount(newCounter.getName());
permanent.addCounters(newCounter, game);
int amountAdded = permanent.getCounters().getCount(newCounter.getName()) - before;
if (informPlayers) {
if (informPlayers && !game.isSimulation()) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
game.informPlayers(player.getName()+" puts "+amountAdded+" "+newCounter.getName().toLowerCase()+" counter on "+permanent.getLogName());

View file

@ -95,7 +95,8 @@ public class AddCountersTargetEffect extends OneShotEffect {
permanent.addCounters(newCounter, game);
int numberAdded = permanent.getCounters().getCount(counter.getName()) - before;
affectedTargets ++;
game.informPlayers(sourceObject.getLogName() +": "+ controller.getName()+ " puts " +
if (!game.isSimulation())
game.informPlayers(sourceObject.getLogName() +": "+ controller.getName()+ " puts " +
numberAdded + " " + counter.getName().toLowerCase() + " counter on " + permanent.getLogName());
}
} else {
@ -105,7 +106,8 @@ public class AddCountersTargetEffect extends OneShotEffect {
newCounter.add(amount.calculate(game, source, this));
player.addCounters(newCounter, game);
affectedTargets ++;
game.informPlayers(new StringBuilder(sourceObject.getLogName()).append(": ")
if (!game.isSimulation())
game.informPlayers(new StringBuilder(sourceObject.getLogName()).append(": ")
.append(controller.getName()).append(" puts ")
.append(counter.getCount()).append(" ").append(counter.getName().toLowerCase())
.append(" counter on ").append(player.getName()).toString());

View file

@ -60,14 +60,16 @@ public class RemoveCounterSourceEffect extends OneShotEffect {
Permanent p = game.getPermanent(source.getSourceId());
if (p != null && p.getCounters().getCount(counter.getName()) >= counter.getCount()) {
p.removeCounters(counter.getName(), counter.getCount(), game);
game.informPlayers(new StringBuilder("Removed ").append(counter.getCount()).append(" ").append(counter.getName())
if (!game.isSimulation())
game.informPlayers(new StringBuilder("Removed ").append(counter.getCount()).append(" ").append(counter.getName())
.append(" counter from ").append(p.getName()).toString());
return true;
}
Card c = game.getCard(source.getSourceId());
if (c != null && c.getCounters(game).getCount(counter.getName()) >= counter.getCount()) {
c.removeCounters(counter.getName(), counter.getCount(), game);
game.informPlayers(new StringBuilder("Removed ").append(counter.getCount()).append(" ").append(counter.getName())
if (!game.isSimulation())
game.informPlayers(new StringBuilder("Removed ").append(counter.getCount()).append(" ").append(counter.getName())
.append(" counter from ").append(c.getName())
.append(" (").append(c.getCounters(game).getCount(counter.getName())).append(" left)").toString());
return true;

View file

@ -61,14 +61,16 @@ public class RemoveCounterTargetEffect extends OneShotEffect {
Permanent p = game.getPermanent(targetPointer.getFirst(game, source));
if (p != null && p.getCounters().getCount(counter.getName()) >= counter.getCount()) {
p.removeCounters(counter.getName(), counter.getCount(), game);
game.informPlayers(new StringBuilder("Removed ").append(counter.getCount()).append(" ").append(counter.getName())
if (!game.isSimulation())
game.informPlayers(new StringBuilder("Removed ").append(counter.getCount()).append(" ").append(counter.getName())
.append(" counter from ").append(p.getName()).toString());
return true;
}
Card c = game.getCard(targetPointer.getFirst(game, source));
if (c != null && c.getCounters(game).getCount(counter.getName()) >= counter.getCount()) {
c.removeCounters(counter.getName(), counter.getCount(), game);
game.informPlayers(new StringBuilder("Removed ").append(counter.getCount()).append(" ").append(counter.getName())
if (!game.isSimulation())
game.informPlayers(new StringBuilder("Removed ").append(counter.getCount()).append(" ").append(counter.getName())
.append(" counter from ").append(c.getName())
.append(" (").append(c.getCounters(game).getCount(counter.getName())).append(" left)").toString());
return true;

View file

@ -98,7 +98,7 @@ public class SearchLibraryPutOnLibraryEffect extends SearchEffect {
if (forceShuffle) {
controller.shuffleLibrary(game);
}
if (cards.size() > 0) {
if (cards.size() > 0 && !game.isSimulation()) {
game.informPlayers(controller.getName() + " moves " + cards.size() + " card" + (cards.size() == 1 ? " ":"s ") + "on top of his or her library");
}
for (Card card: cards) {

View file

@ -165,7 +165,7 @@ public class ConvokeAbility extends SimpleStaticAbility implements AdjustingSour
if (costBefore == ability.getManaCostsToPay().convertedManaCost()) {
// creature could not reduce mana costs so tap must be reverted
perm.untap(game);
} else {
} else if (!game.isSimulation()) {
game.informPlayers("Convoke: " + player.getName() + " taps " + perm.getLogName() + " to reduce mana costs by " + manaCostsToReduce.getText());
}
}

View file

@ -109,7 +109,8 @@ import mage.util.CardUtil;
player.moveCardToExileWithInfo(card, null, "", getSourceId(), game, Zone.GRAVEYARD);
++adjCost;
}
game.informPlayers(new StringBuilder("Delve: ").append(player.getName()).append(" exiled ")
if (!game.isSimulation())
game.informPlayers(new StringBuilder("Delve: ").append(player.getName()).append(" exiled ")
.append(adjCost).append(" card").append(adjCost != 1?"s":"").append(" from his or her graveyard").toString());
CardUtil.adjustCost((SpellAbility)ability, adjCost);
}

View file

@ -97,7 +97,8 @@ class DredgeEffect extends ReplacementEffectImpl {
if (player != null && player.getLibrary().size() >= amount
&& player.chooseUse(outcome, new StringBuilder("Dredge ").append(sourceCard.getName()).
append("? (").append(amount).append(" cards go from top of library to graveyard)").toString(), game)) {
game.informPlayers(new StringBuilder(player.getName()).append(" dreges ").append(sourceCard.getName()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(player.getName()).append(" dreges ").append(sourceCard.getName()).toString());
for (int i = 0; i < amount; i++) {
Card card = player.getLibrary().removeFromTop(game);
if (card != null) {

View file

@ -109,7 +109,8 @@ class ExtortEffect extends OneShotEffect {
if (loseLife > 0) {
game.getPlayer(source.getControllerId()).gainLife(loseLife, game);
}
game.informPlayers(new StringBuilder(permanent.getName()).append(" extorted opponents ").append(loseLife).append(" life").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(permanent.getName()).append(" extorted opponents ").append(loseLife).append(" life").toString());
}
}
return true;

View file

@ -201,7 +201,8 @@ class FlashbackEffect extends OneShotEffect {
}
spellAbility.getManaCostsToPay().setX(amount);
}
game.informPlayers(new StringBuilder(controller.getName()).append(" flashbacks ").append(card.getName()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(controller.getName()).append(" flashbacks ").append(card.getName()).toString());
spellAbility.setCostModificationActive(false); // prevents to apply cost modification twice for flashbacked spells
return controller.cast(spellAbility, game, true);
}

View file

@ -170,8 +170,10 @@ class GraftDistributeCounterEffect extends OneShotEffect {
if (targetCreature != null) {
sourcePermanent.removeCounters(CounterType.P1P1.getName(), 1, game);
targetCreature.addCounters(CounterType.P1P1.createInstance(1), game);
StringBuilder sb = new StringBuilder("Moved one +1/+1 counter from ").append(sourcePermanent.getName()).append(" to ").append(targetCreature.getName());
game.informPlayers(sb.toString());
if (!game.isSimulation()) {
StringBuilder sb = new StringBuilder("Moved one +1/+1 counter from ").append(sourcePermanent.getName()).append(" to ").append(targetCreature.getName());
game.informPlayers(sb.toString());
}
return true;
}
}

View file

@ -179,7 +179,8 @@ class HauntEffect extends OneShotEffect {
game.getState().setValue(key, new FixedTarget(targetPointer.getFirst(game, source)));
card.addInfo("hauntinfo", new StringBuilder("Haunting ").append(hauntedCreature.getLogName()).toString(), game);
hauntedCreature.addInfo("hauntinfo", new StringBuilder("Haunted by ").append(card.getLogName()).toString(), game);
game.informPlayers(new StringBuilder(card.getName()).append(" haunting ").append(hauntedCreature.getLogName()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(card.getName()).append(" haunting ").append(hauntedCreature.getLogName()).toString());
}
return true;
}

View file

@ -212,7 +212,8 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
// use only first variable cost
xManaValue = game.getPlayer(this.controllerId).announceXMana(varCosts.get(0).getMinX(), Integer.MAX_VALUE, "Announce kicker value for " + varCosts.get(0).getText(), game, this);
// kicker variable X costs handled internally as multikicker with {1} cost (no multikicker on card)
game.informPlayers(new StringBuilder(game.getPlayer(this.controllerId).getName()).append(" announced a value of ").append(xManaValue).append(" for ").append(" kicker X ").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(game.getPlayer(this.controllerId).getName()).append(" announced a value of ").append(xManaValue).append(" for ").append(" kicker X ").toString());
ability.getManaCostsToPay().add(new GenericManaCost(xManaValue));
} else {
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());

View file

@ -249,7 +249,8 @@ class ReplicateCopyEffect extends OneShotEffect {
copy.setCopiedSpell(true);
game.getStack().push(copy);
copy.chooseNewTargets(game, source.getControllerId());
game.informPlayers(new StringBuilder(controller.getName()).append(copy.getActivatedMessage(game)).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(controller.getName()).append(copy.getActivatedMessage(game)).toString());
}
return true;
}

View file

@ -107,9 +107,11 @@ class SunburstEffect extends OneShotEffect {
permanent.addCounters(counter, game);
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
game.informPlayers(player.getName()+ " puts " + counter.getCount() + " " + counter.getName() + " counter on " + permanent.getName());
if (!game.isSimulation()) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
game.informPlayers(player.getName()+ " puts " + counter.getCount() + " " + counter.getName() + " counter on " + permanent.getName());
}
}
}
}

View file

@ -258,7 +258,8 @@ class SuspendExileEffect extends OneShotEffect {
suspend = source.getManaCostsToPay().getX();
}
card.addCounters(CounterType.TIME.createInstance(suspend), game);
game.informPlayers(new StringBuilder(controller.getName()).append(" suspends (").append(suspend).append(") ").append(card.getName()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(controller.getName()).append(" suspends (").append(suspend).append(") ").append(card.getName()).toString());
return true;
}
}

View file

@ -119,11 +119,13 @@ class TributeEffect extends OneShotEffect {
sb.append(" (add ").append(CardUtil.numberToText(tributeValue)).append(" +1/+1 counter");
sb.append(tributeValue > 1 ? "s":"").append(" to it)?");
if (opponent.chooseUse(outcome, sb.toString(), game)) {
game.informPlayers(new StringBuilder(opponent.getName()).append(" pays tribute to ").append(sourcePermanent.getName()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(opponent.getName()).append(" pays tribute to ").append(sourcePermanent.getName()).toString());
game.getState().setValue(new StringBuilder("tributeValue").append(source.getSourceId()).toString(), "yes");
return new AddCountersSourceEffect(CounterType.P1P1.createInstance(tributeValue), true).apply(game, source);
} else {
game.informPlayers(new StringBuilder(opponent.getName()).append(" does not pay tribute to ").append(sourcePermanent.getName()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(opponent.getName()).append(" does not pay tribute to ").append(sourcePermanent.getName()).toString());
game.getState().setValue(new StringBuilder("tributeValue").append(source.getSourceId()).toString(), "no");
}
return true;

View file

@ -112,7 +112,8 @@ class UnleashReplacementEffect extends ReplacementEffectImpl {
Player controller = game.getPlayer(source.getControllerId());
if (creature != null && controller != null) {
if (controller.chooseUse(outcome, "Unleash "+ creature.getName() +"?", game)) {
game.informPlayers(controller.getName() + " unleashes " + creature.getName());
if (!game.isSimulation())
game.informPlayers(controller.getName() + " unleashes " + creature.getName());
creature.addCounters(CounterType.P1P1.createInstance(), game);
}
}

View file

@ -53,7 +53,7 @@ public class MageDrawAction extends MageAction {
numDrawn++;
score += value;
}
if (!player.isTopCardRevealed() && numDrawn > 0) {
if (!game.isSimulation() && !player.isTopCardRevealed() && numDrawn > 0) {
game.fireInformEvent(player.getName() + " draws " + CardUtil.numberToText(numDrawn, "a") + " card" + (numDrawn > 1 ? "s" : ""));
}
if (player.isEmptyDraw()) {
@ -81,7 +81,7 @@ public class MageDrawAction extends MageAction {
if (card != null) {
drawnCards.add(card);
card.moveToZone(Zone.HAND, null, game, false);
if (player.isTopCardRevealed()) {
if (!game.isSimulation() && player.isTopCardRevealed()) {
game.fireInformEvent(player.getName() + " draws a revealed card (" + card.getLogName() + ")");
}

View file

@ -156,7 +156,8 @@ public abstract class GameCommanderImpl extends GameImpl {
}
}
player.drawCards(numCards - deduction, this);
fireInformEvent(new StringBuilder(player.getName())
if (!isSimulation())
fireInformEvent(new StringBuilder(player.getName())
.append(" mulligans ")
.append(numCards)
.append(numCards == 1? " card":" cards")

View file

@ -632,7 +632,8 @@ public abstract class GameImpl implements Game, Serializable {
boolean wasPaused = state.isPaused();
state.resume();
if (!gameOver(null)) {
fireInformEvent(new StringBuilder("Turn ").append(state.getTurnNum()).toString());
if (!isSimulation())
fireInformEvent(new StringBuilder("Turn ").append(state.getTurnNum()).toString());
if (checkStopOnTurnOption()) {
return;
}
@ -694,7 +695,8 @@ public abstract class GameImpl implements Game, Serializable {
if (extraPlayer != null && extraPlayer.isInGame()) {
state.setExtraTurn(true);
state.setTurnId(extraTurn.getId());
informPlayers(extraPlayer.getName() + " takes an extra turn");
if (!isSimulation())
informPlayers(extraPlayer.getName() + " takes an extra turn");
playTurn(extraPlayer);
state.setTurnNum(state.getTurnNum() + 1);
}
@ -723,7 +725,8 @@ public abstract class GameImpl implements Game, Serializable {
}
private boolean playTurn(Player player) {
this.logStartOfTurn(player);
if (!isSimulation())
this.logStartOfTurn(player);
if (checkStopOnTurnOption()) {
return false;
}
@ -809,17 +812,19 @@ public abstract class GameImpl implements Game, Serializable {
}
if (choosingPlayer != null && choosingPlayer.choose(Outcome.Benefit, targetPlayer, null, this)) {
startingPlayerId = targetPlayer.getTargets().get(0);
Player startingPlayer = state.getPlayer(startingPlayerId);
StringBuilder message = new StringBuilder(choosingPlayer.getName()).append(" chooses that ");
if (choosingPlayer.getId().equals(startingPlayerId)) {
message.append("he or she");
} else {
message.append(startingPlayer.getName());
}
message.append(" takes the first turn");
if (!isSimulation()) {
startingPlayerId = targetPlayer.getTargets().get(0);
Player startingPlayer = state.getPlayer(startingPlayerId);
StringBuilder message = new StringBuilder(choosingPlayer.getName()).append(" chooses that ");
if (choosingPlayer.getId().equals(startingPlayerId)) {
message.append("he or she");
} else {
message.append(startingPlayer.getName());
}
message.append(" takes the first turn");
this.informPlayers(message.toString());
this.informPlayers(message.toString());
}
} else {
// not possible to choose starting player, stop here
return;
@ -1698,7 +1703,8 @@ public abstract class GameImpl implements Game, Serializable {
private boolean movePermanentToGraveyardWithInfo(Permanent permanent) {
boolean result = false;
if (permanent.moveToZone(Zone.GRAVEYARD, null, this, false)) {
this.informPlayers(new StringBuilder(permanent.getLogName())
if (!isSimulation())
this.informPlayers(new StringBuilder(permanent.getLogName())
.append(" is put into graveyard from battlefield").toString());
result = true;
}
@ -2097,22 +2103,24 @@ public abstract class GameImpl implements Game, Serializable {
MageObject preventionSource = game.getObject(source.getSourceId());
if (damageSource != null && preventionSource != null) {
MageObject targetObject = game.getObject(event.getTargetId());
String targetName = "";
if (targetObject == null) {
Player targetPlayer = game.getPlayer(event.getTargetId());
if (targetPlayer != null) {
targetName = targetPlayer.getName();
if (!game.isSimulation()) {
MageObject targetObject = game.getObject(event.getTargetId());
String targetName = "";
if (targetObject == null) {
Player targetPlayer = game.getPlayer(event.getTargetId());
if (targetPlayer != null) {
targetName = targetPlayer.getName();
}
} else {
targetName = targetObject.getLogName();
}
} else {
targetName = targetObject.getLogName();
StringBuilder message = new StringBuilder(preventionSource.getLogName()).append(": Prevented ");
message.append(Integer.toString(result.getPreventedDamage())).append(" damage from ").append(damageSource.getName());
if (!targetName.isEmpty()) {
message.append(" to ").append(targetName);
}
game.informPlayers(message.toString());
}
StringBuilder message = new StringBuilder(preventionSource.getLogName()).append(": Prevented ");
message.append(Integer.toString(result.getPreventedDamage())).append(" damage from ").append(damageSource.getName());
if (!targetName.isEmpty()) {
message.append(" to ").append(targetName);
}
game.informPlayers(message.toString());
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, damageEvent.getTargetId(), source.getSourceId(), source.getControllerId(), result.getPreventedDamage()));
return result;

View file

@ -215,7 +215,8 @@ public class Combat implements Serializable, Copyable<Combat> {
}
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, attackerId, attackerId));
game.informPlayers(new StringBuilder(player.getName()).append(" attacks with ").append(groups.size()).append(groups.size() == 1 ? " creature":" creatures").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(player.getName()).append(" attacks with ").append(groups.size()).append(groups.size() == 1 ? " creature":" creatures").toString());
}
protected void checkAttackRequirements(Player player, Game game) {
@ -268,7 +269,8 @@ public class Combat implements Serializable, Copyable<Combat> {
for (UUID attackingCreatureId : group.getAttackers()) {
Permanent attacker = game.getPermanent(attackingCreatureId);
if (count > 1 && attacker != null && attacker.getAbilities(game).containsKey(CanAttackOnlyAloneAbility.getInstance().getId())) {
game.informPlayers(attacker.getLogName() + " can only attack alone. Removing it from combat.");
if (!game.isSimulation())
game.informPlayers(attacker.getLogName() + " can only attack alone. Removing it from combat.");
tobeRemoved.add(attackingCreatureId);
count--;
}
@ -285,7 +287,8 @@ public class Combat implements Serializable, Copyable<Combat> {
for (UUID attackingCreatureId : group.getAttackers()) {
Permanent attacker = game.getPermanent(attackingCreatureId);
if (attacker != null && attacker.getAbilities(game).containsKey(CantAttackAloneAbility.getInstance().getId())) {
game.informPlayers(attacker.getLogName() + " can't attack alone. Removing it from combat.");
if (!game.isSimulation())
game.informPlayers(attacker.getLogName() + " can't attack alone. Removing it from combat.");
tobeRemoved.add(attackingCreatureId);
}
}
@ -356,6 +359,8 @@ public class Combat implements Serializable, Copyable<Combat> {
*
*/
private void logBlockerInfo(Player defender, Game game) {
if (game.isSimulation())
return;
boolean shownDefendingPlayer = game.getPlayers().size() < 3; // only two players no ned to sow the attacked player
for (CombatGroup group : this.getGroups()) {
if (group.defendingPlayerId.equals(defender.getId())) {
@ -566,7 +571,8 @@ public class Combat implements Serializable, Copyable<Combat> {
// 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.getLogName());
if (!game.isSimulation())
game.informPlayer(controller, "Creature should block this turn: " + creature.getLogName());
} else {
Player defender = game.getPlayer(creature.getControllerId());
if (defender != null) {
@ -634,7 +640,8 @@ public class Combat implements Serializable, Copyable<Combat> {
}
}
if (possibleBlockerAvailable) {
game.informPlayer(controller, new StringBuilder(toBeBlockedCreature.getLogName()).append(" has to be blocked by at least one creature.").toString());
if (!game.isSimulation())
game.informPlayer(controller, new StringBuilder(toBeBlockedCreature.getLogName()).append(" has to be blocked by at least one creature.").toString());
return false;
}
}
@ -697,9 +704,11 @@ public class Combat implements Serializable, Copyable<Combat> {
}
}
if (sb.length() > 0) {
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());
if (!game.isSimulation()) {
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;
@ -723,7 +732,8 @@ public class Combat implements Serializable, Copyable<Combat> {
for (Ability ability : entry.getValue()) {
if (!effect.canBeBlockedCheckAfter(attackingCreature, ability, game)) {
if (controller.isHuman()) {
game.informPlayer(controller, new StringBuilder(attackingCreature.getLogName()).append(" can't be blocked this way.").toString());
if (!game.isSimulation())
game.informPlayer(controller, new StringBuilder(attackingCreature.getLogName()).append(" can't be blocked this way.").toString());
return false;
} else {
// remove blocking creatures for AI
@ -839,12 +849,14 @@ public class Combat implements Serializable, Copyable<Combat> {
numberCreaturesDefenderAttackedBy.put(defendingPlayer.getId(), defenderAttackedBy);
}
if (defenderAttackedBy.size() >= defendingPlayer.getMaxAttackedBy()) {
Player attackingPlayer = game.getPlayer(game.getControllerId(attackerId));
if (attackingPlayer != null) {
game.informPlayer(attackingPlayer, new StringBuilder("No more than ")
.append(CardUtil.numberToText(defendingPlayer.getMaxAttackedBy()))
.append(" creatures can attack ")
.append(defendingPlayer.getName()).toString());
if (!game.isSimulation()) {
Player attackingPlayer = game.getPlayer(game.getControllerId(attackerId));
if (attackingPlayer != null) {
game.informPlayer(attackingPlayer, new StringBuilder("No more than ")
.append(CardUtil.numberToText(defendingPlayer.getMaxAttackedBy()))
.append(" creatures can attack ")
.append(defendingPlayer.getName()).toString());
}
}
return false;
}

View file

@ -540,7 +540,8 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
Permanent blocker = game.getPermanent(blockerId);
if (blocker != null && blocker.getAbilities(game).containsKey(CantBlockAloneAbility.getInstance().getId())) {
blockWasLegal = false;
game.informPlayers(blocker.getLogName() + " can't block alone. Removing it from combat.");
if (!game.isSimulation())
game.informPlayers(blocker.getLogName() + " can't block alone. Removing it from combat.");
toBeRemoved.add(blockerId);
}
}
@ -566,7 +567,8 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
blockers.clear();
blockerOrder.clear();
this.blocked = false;
game.informPlayers(attacker.getLogName() + " can't be blocked except by " + attacker.getMinBlockedBy() + " or more creatures. Blockers discarded.");
if (!game.isSimulation())
game.informPlayers(attacker.getLogName() + " can't be blocked except by " + attacker.getMinBlockedBy() + " or more creatures. Blockers discarded.");
blockWasLegal = false;
}
// Check if there are to many blockers (maxBlockedBy = 0 means no restrictions)
@ -580,7 +582,8 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
blockers.clear();
blockerOrder.clear();
this.blocked = false;
game.informPlayers(new StringBuilder(attacker.getLogName())
if (!game.isSimulation())
game.informPlayers(new StringBuilder(attacker.getLogName())
.append(" can't be blocked by more than ").append(attacker.getMaxBlockedBy())
.append(attacker.getMaxBlockedBy()==1?" creature.":" creatures.")
.append(" Blockers discarded.").toString());

View file

@ -447,7 +447,8 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
if (!phasedIn) {
if (!replaceEvent(EventType.PHASE_IN, game)) {
this.phasedIn = true;
game.informPlayers(getLogName() + " phased in");
if (!game.isSimulation())
game.informPlayers(getLogName() + " phased in");
fireEvent(EventType.PHASED_IN, game);
return true;
}
@ -460,7 +461,8 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
if (phasedIn) {
if (!replaceEvent(EventType.PHASE_OUT, game)) {
this.phasedIn = false;
game.informPlayers(getLogName() + " phased out");
if (!game.isSimulation())
game.informPlayers(getLogName() + " phased out");
fireEvent(EventType.PHASED_OUT, game);
return true;
}
@ -864,17 +866,19 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
if (!game.replaceEvent(GameEvent.getEvent(EventType.DESTROY_PERMANENT, objectId, sourceId, controllerId, noRegen ? 1 : 0))) {
if (moveToZone(Zone.GRAVEYARD, sourceId, game, false)) {
String logName;
Card card = game.getCard(this.getId());
if (card != null) {
logName = card.getLogName();
} else {
logName = this.getLogName();
}
if (this.getCardType().contains(CardType.CREATURE)) {
game.informPlayers(logName +" died");
} else {
game.informPlayers(logName + " was destroyed");
if (!game.isSimulation()) {
String logName;
Card card = game.getCard(this.getId());
if (card != null) {
logName = card.getLogName();
} else {
logName = this.getLogName();
}
if (this.getCardType().contains(CardType.CREATURE)) {
game.informPlayers(logName +" died");
} else {
game.informPlayers(logName + " was destroyed");
}
}
game.fireEvent(GameEvent.getEvent(EventType.DESTROYED_PERMANENT, objectId, sourceId, controllerId));
return true;
@ -889,9 +893,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
if (!game.replaceEvent(GameEvent.getEvent(EventType.SACRIFICE_PERMANENT, objectId, sourceId, controllerId))) {
// Commander replacement effect or Rest in Peace (exile instead of graveyard) in play does not prevent successful sacrifice
moveToZone(Zone.GRAVEYARD, sourceId, game, false);
Player player = game.getPlayer(getControllerId());
if (player != null) {
game.informPlayers(new StringBuilder(player.getName()).append(" sacrificed ").append(this.getLogName()).toString());
if (!game.isSimulation()) {
Player player = game.getPlayer(getControllerId());
if (player != null) {
game.informPlayers(new StringBuilder(player.getName()).append(" sacrificed ").append(this.getLogName()).toString());
}
}
game.fireEvent(GameEvent.getEvent(EventType.SACRIFICED_PERMANENT, objectId, sourceId, controllerId));
return true;
@ -1090,7 +1096,8 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
public boolean removeFromCombat(Game game, boolean withInfo) {
if (this.isAttacking() || this.blocking > 0) {
if (game.getCombat().removeFromCombat(objectId, game) && withInfo) {
game.informPlayers(new StringBuilder(this.getLogName()).append(" removed from combat").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(this.getLogName()).append(" removed from combat").toString());
}
}
return true;

View file

@ -161,7 +161,8 @@ public class Token extends MageObjectImpl {
game.getCombat().addAttackingCreature(newToken.getId(), game);
}
}
game.informPlayers(new StringBuilder(controller.getName()).append(" puts ")
if (!game.isSimulation())
game.informPlayers(new StringBuilder(controller.getName()).append(" puts ")
.append(CardUtil.numberToText(amount, "a")).append(" ").append(this.getName()).append(" token").append(amount==1?"":"s")
.append(" onto the battlefield").toString());
return true;

View file

@ -212,7 +212,8 @@ public class Spell implements StackObject, Card {
return result;
}
//20091005 - 608.2b
game.informPlayers(getName() + " has been fizzled.");
if (!game.isSimulation())
game.informPlayers(getName() + " has been fizzled.");
counter(null, game);
return false;
} else if (this.getCardType().contains(CardType.ENCHANTMENT) && this.getSubtype().contains("Aura")) {
@ -247,7 +248,8 @@ public class Spell implements StackObject, Card {
return result;
} else {
//20091005 - 608.2b
game.informPlayers(getName() + " has been fizzled.");
if (!game.isSimulation())
game.informPlayers(getName() + " has been fizzled.");
counter(null, game);
return false;
}
@ -377,7 +379,7 @@ public class Spell implements StackObject, Card {
}
}
if (newTargetDescription.length() > 0) {
if (newTargetDescription.length() > 0 && !game.isSimulation()) {
game.informPlayers(this.getName() + " is now " + newTargetDescription.toString());
}
return true;

View file

@ -100,10 +100,12 @@ public class SpellStack extends ArrayDeque<StackObject> {
}
this.remove(stackObject);
stackObject.counter(sourceId, game); // tries to move to graveyard
game.informPlayers(counteredObjectName + " is countered by " + sourceObject.getLogName());
if (!game.isSimulation())
game.informPlayers(counteredObjectName + " is countered by " + sourceObject.getLogName());
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERED, objectId, sourceId, stackObject.getControllerId()));
} else {
game.informPlayers(counteredObjectName + " could not be countered by " + sourceObject.getLogName());
if (!game.isSimulation())
game.informPlayers(counteredObjectName + " could not be countered by " + sourceObject.getLogName());
}
return true;
}

View file

@ -100,7 +100,8 @@ public class StackAbility implements StackObject, Ability {
if (ability.getTargets().stillLegal(ability, game)) {
return ability.resolve(game);
}
game.informPlayers("Ability has been fizzled: " + getRule());
if (!game.isSimulation())
game.informPlayers("Ability has been fizzled: " + getRule());
counter(null, game);
return false;
}

View file

@ -234,9 +234,11 @@ public class Turn implements Serializable {
}
currentPhase = phase;
game.fireEvent(new GameEvent(GameEvent.EventType.PHASE_CHANGED, activePlayerId, extraPhaseTurnMod.getId(), activePlayerId));
Player activePlayer = game.getPlayer(activePlayerId);
if (activePlayer != null) {
game.informPlayers(new StringBuilder(activePlayer.getName()).append(" starts an additional ").append(phase.getType().toString()).append(" phase").toString());
if (!game.isSimulation()) {
Player activePlayer = game.getPlayer(activePlayerId);
if (activePlayer != null) {
game.informPlayers(new StringBuilder(activePlayer.getName()).append(" starts an additional ").append(phase.getType().toString()).append(" phase").toString());
}
}
phase.play(game, activePlayerId);

View file

@ -642,7 +642,8 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public void discardToMax(Game game) {
if (hand.size() > this.maxHandSize) {
game.informPlayers(new StringBuilder(getName()).append(" discards down to ").append(this.maxHandSize).append(this.maxHandSize == 1?" hand card":" hand cards").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(getName()).append(" discards down to ").append(this.maxHandSize).append(this.maxHandSize == 1?" hand card":" hand cards").toString());
discard(hand.size() - this.maxHandSize, null, game);
}
}
@ -733,7 +734,8 @@ public abstract class PlayerImpl implements Player, Serializable {
*/
if (card != null) {
// write info to game log first so game log infos from triggered or replacement effects follow in the game log
game.informPlayers(new StringBuilder(name).append(" discards ").append(card.getName()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(name).append(" discards ").append(card.getName()).toString());
/* If a card is discarded while Rest in Peace is on the battlefield, abilities that function
* when a card is discarded (such as madness) still work, even though that card never reaches
* a graveyard. In addition, spells or abilities that check the characteristics of a discarded
@ -936,7 +938,8 @@ public abstract class PlayerImpl implements Player, Serializable {
GameEvent event = GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId);
event.setZone(fromZone);
game.fireEvent(event);
game.informPlayers(new StringBuilder(name).append(spell.getActivatedMessage(game)).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(name).append(spell.getActivatedMessage(game)).toString());
game.removeBookmark(bookmark);
resetStoredBookmark(game);
return true;
@ -987,7 +990,8 @@ public abstract class PlayerImpl implements Player, Serializable {
if (card.putOntoBattlefield(game, zone, null, playerId)) {
landsPlayed++;
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LAND_PLAYED, card.getId(), card.getId(), playerId));
game.fireInformEvent(name + " plays " + card.getName());
if (!game.isSimulation())
game.fireInformEvent(name + " plays " + card.getName());
// game.removeBookmark(bookmark);
resetStoredBookmark(game);
return true;
@ -1025,7 +1029,8 @@ public abstract class PlayerImpl implements Player, Serializable {
game.getStack().push(new StackAbility(ability, playerId));
if (ability.activate(game, false)) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATED_ABILITY, ability.getId(), ability.getSourceId(), playerId));
game.informPlayers(new StringBuilder(name).append(ability.getGameLogMessage(game)).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(name).append(ability.getGameLogMessage(game)).toString());
game.removeBookmark(bookmark);
resetStoredBookmark(game);
return true;
@ -1051,7 +1056,8 @@ public abstract class PlayerImpl implements Player, Serializable {
int bookmark = game.bookmarkState();
if (action.activate(game, false)) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATED_ABILITY, action.getSourceId(), action.getId(), playerId));
game.informPlayers(new StringBuilder(name).append(action.getGameLogMessage(game)).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(name).append(action.getGameLogMessage(game)).toString());
if (action.resolve(game)) {
game.removeBookmark(bookmark);
resetStoredBookmark(game);
@ -1119,7 +1125,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
if (ability.activate(game, false)) {
if (ability.isUsesStack() || ability.getRuleVisible()) {
game.informPlayers(ability.getGameLogMessage(game));
if (!game.isSimulation())
game.informPlayers(ability.getGameLogMessage(game));
}
if (!ability.isUsesStack()) {
ability.resolve(game);
@ -1272,7 +1279,8 @@ public abstract class PlayerImpl implements Player, Serializable {
public void shuffleLibrary(Game game) {
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.SHUFFLE_LIBRARY, playerId, playerId))) {
this.library.shuffle();
game.informPlayers(new StringBuilder(this.name).append(" shuffles his or her library.").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(this.name).append(" shuffles his or her library.").toString());
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LIBRARY_SHUFFLED, playerId, playerId));
}
}
@ -1285,7 +1293,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public void revealCards(String name, Cards cards, Game game, boolean postToLog) {
game.getState().getRevealed().add(name, cards);
if (postToLog) {
if (postToLog && !game.isSimulation()) {
StringBuilder sb = new StringBuilder(this.getName()).append(" reveals ");
int current = 0, last = cards.size();
for (Card card :cards.getCards(game)) {
@ -1412,8 +1420,10 @@ public abstract class PlayerImpl implements Player, Serializable {
} while (isInGame() && playerCanceledSelection);
// show in log which permanents were selected to untap
for(Permanent permanent :selectedToUntap) {
game.informPlayers(new StringBuilder(this.getName()).append(" untapped ").append(permanent.getName()).toString());
if (!game.isSimulation()) {
for(Permanent permanent :selectedToUntap) {
game.informPlayers(new StringBuilder(this.getName()).append(" untapped ").append(permanent.getName()).toString());
}
}
// untap if permanent is not concerned by notMoreThan effects or is included in the selectedToUntapList
for (Permanent permanent: canBeUntapped) {
@ -1563,7 +1573,8 @@ public abstract class PlayerImpl implements Player, Serializable {
GameEvent event = new GameEvent(GameEvent.EventType.LOSE_LIFE, playerId, playerId, playerId, amount, false);
if (!game.replaceEvent(event)) {
this.life -= event.getAmount();
game.informPlayers(new StringBuilder(this.getName()).append(" loses ").append(event.getAmount()).append(" life").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(this.getName()).append(" loses ").append(event.getAmount()).append(" life").toString());
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LOST_LIFE, playerId, playerId, playerId, amount));
return amount;
}
@ -1588,7 +1599,8 @@ public abstract class PlayerImpl implements Player, Serializable {
GameEvent event = new GameEvent(GameEvent.EventType.GAIN_LIFE, playerId, playerId, playerId, amount, false);
if (!game.replaceEvent(event)) {
this.life += event.getAmount();
game.informPlayers(new StringBuilder(this.getName()).append(" gains ").append(event.getAmount()).append(" life").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(this.getName()).append(" gains ").append(event.getAmount()).append(" life").toString());
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.GAINED_LIFE, playerId, playerId, playerId, event.getAmount()));
return event.getAmount();
}
@ -1759,7 +1771,8 @@ public abstract class PlayerImpl implements Player, Serializable {
quit = true;
this.concede(game);
logger.debug(getName() + " quits the match.");
game.informPlayers(getName() + " quits the match.");
if (!game.isSimulation())
game.informPlayers(getName() + " quits the match.");
}
@Override
@ -1767,7 +1780,8 @@ public abstract class PlayerImpl implements Player, Serializable {
quit = true;
timerTimeout = true;
this.concede(game);
game.informPlayers(getName() + " has run out of time. Loosing the Match.");
if (!game.isSimulation())
game.informPlayers(getName() + " has run out of time. Loosing the Match.");
}
@Override
@ -1775,7 +1789,8 @@ public abstract class PlayerImpl implements Player, Serializable {
quit = true;
idleTimeout = true;
this.concede(game);
game.informPlayers(new StringBuilder(getName()).append(" was idle for too long. Loosing the Match.").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(getName()).append(" was idle for too long. Loosing the Match.").toString());
}
@Override
@ -1879,7 +1894,8 @@ public abstract class PlayerImpl implements Player, Serializable {
if (!this.wins) {
this.loses = true;
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LOST, null, null, playerId));
game.informPlayers(this.getName()+ " has lost the game.");
if (!game.isSimulation())
game.informPlayers(this.getName()+ " has lost the game.");
} else {
logger.debug(this.getName() + " has already won - stop lost");
}
@ -1919,7 +1935,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
if (opponentsAlive == 0 && !hasWon()) {
logger.debug("player won -> No more opponents alive game won: " + this.getName());
game.informPlayers(new StringBuilder(this.getName()).append(" has won the game").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(this.getName()).append(" has won the game").toString());
this.wins = true;
game.end();
}
@ -1985,12 +2002,14 @@ public abstract class PlayerImpl implements Player, Serializable {
//20091005 - 701.14c
Library searchedLibrary = null;
if (targetPlayerId.equals(playerId)) {
game.informPlayers(new StringBuilder(getName()).append(" searches his or her library").toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(getName()).append(" searches his or her library").toString());
searchedLibrary = library;
} else {
Player targetPlayer = game.getPlayer(targetPlayerId);
if (targetPlayer != null) {
game.informPlayers(new StringBuilder(getName()).append(" searches the library of ").append(targetPlayer.getName()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(getName()).append(" searches the library of ").append(targetPlayer.getName()).toString());
searchedLibrary = targetPlayer.getLibrary();
}
}
@ -2039,7 +2058,8 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean flipCoin(Game game, ArrayList<UUID> appliedEffects) {
boolean result = rnd.nextBoolean();
game.informPlayers("[Flip a coin] " + getName() + (result ? " won (head)." : " lost (tail)."));
if (!game.isSimulation())
game.informPlayers("[Flip a coin] " + getName() + (result ? " won (head)." : " lost (tail)."));
GameEvent event = new GameEvent(GameEvent.EventType.FLIP_COIN, playerId, null, playerId, 0, result);
event.setAppliedEffects(appliedEffects);
game.replaceEvent(event);
@ -2726,13 +2746,15 @@ public abstract class PlayerImpl implements Player, Serializable {
public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) {
boolean result = false;
if (card.moveToZone(Zone.HAND, sourceId, game, false)) {
if (card instanceof PermanentCard) {
card = game.getCard(card.getId());
}
game.informPlayers(new StringBuilder(this.getName())
if (!game.isSimulation()) {
if (card instanceof PermanentCard) {
card = game.getCard(card.getId());
}
game.informPlayers(new StringBuilder(this.getName())
.append(" puts ").append(card.getLogName()).append(" ")
.append(fromZone != null ? new StringBuilder("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" "):"")
.append(card.getOwnerId().equals(this.getId()) ? "into his or her hand":"into its owner's hand").toString());
}
result = true;
}
return result;
@ -2742,18 +2764,20 @@ public abstract class PlayerImpl implements Player, Serializable {
public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) {
boolean result = false;
if (card.moveToZone(Zone.GRAVEYARD, sourceId, game, fromZone != null ? fromZone.equals(Zone.BATTLEFIELD) : false)) {
if (card instanceof PermanentCard) {
card = game.getCard(card.getId());
}
StringBuilder sb = new StringBuilder(this.getName())
.append(" puts ").append(card.getLogName()).append(" ")
.append(fromZone != null ? new StringBuilder("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" "):"");
if (card.getOwnerId().equals(getId())) {
sb.append("into his or her graveyard");
} else {
sb.append("it into its owner's graveyard");
}
game.informPlayers(sb.toString());
if (!game.isSimulation()) {
if (card instanceof PermanentCard) {
card = game.getCard(card.getId());
}
StringBuilder sb = new StringBuilder(this.getName())
.append(" puts ").append(card.getLogName()).append(" ")
.append(fromZone != null ? new StringBuilder("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" "):"");
if (card.getOwnerId().equals(getId())) {
sb.append("into his or her graveyard");
} else {
sb.append("it into its owner's graveyard");
}
game.informPlayers(sb.toString());
}
result = true;
}
return result;
@ -2763,28 +2787,30 @@ public abstract class PlayerImpl implements Player, Serializable {
public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean toTop, boolean withName) {
boolean result = false;
if (card.moveToZone(Zone.LIBRARY, sourceId, game, toTop)) {
if (card instanceof PermanentCard) {
card = game.getCard(card.getId());
}
StringBuilder sb = new StringBuilder(this.getName())
.append(" puts ").append(withName ? card.getLogName():"a card").append(" ");
if (fromZone != null) {
if (fromZone.equals(Zone.PICK)) {
sb.append("a picked card ");
if (!game.isSimulation()) {
if (card instanceof PermanentCard) {
card = game.getCard(card.getId());
}
StringBuilder sb = new StringBuilder(this.getName())
.append(" puts ").append(withName ? card.getLogName():"a card").append(" ");
if (fromZone != null) {
if (fromZone.equals(Zone.PICK)) {
sb.append("a picked card ");
} else {
sb.append("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" ");
}
}
sb.append("to the ").append(toTop ? "top":"bottom");
if (card.getOwnerId().equals(getId())) {
sb.append(" of his or her library");
} else {
sb.append("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" ");
Player player = game.getPlayer(card.getOwnerId());
if (player != null) {
sb.append(" of ").append(player.getName()).append("'s library");
}
}
game.informPlayers(sb.toString());
}
sb.append("to the ").append(toTop ? "top":"bottom");
if (card.getOwnerId().equals(getId())) {
sb.append(" of his or her library");
} else {
Player player = game.getPlayer(card.getOwnerId());
if (player != null) {
sb.append(" of ").append(player.getName()).append("'s library");
}
}
game.informPlayers(sb.toString());
result = true;
}
return result;
@ -2794,13 +2820,15 @@ public abstract class PlayerImpl implements Player, Serializable {
public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, Game game, Zone fromZone) {
boolean result = false;
if (card.moveToExile(exileId, exileName, sourceId, game)) {
if (card instanceof PermanentCard) {
card = game.getCard(card.getId());
if (!game.isSimulation()) {
if (card instanceof PermanentCard) {
card = game.getCard(card.getId());
}
game.informPlayers(new StringBuilder(this.getName())
.append(" moves ").append(card.getLogName()).append(" ")
.append(fromZone != null ? new StringBuilder("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" "):"")
.append("to exile").toString());
}
game.informPlayers(new StringBuilder(this.getName())
.append(" moves ").append(card.getLogName()).append(" ")
.append(fromZone != null ? new StringBuilder("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" "):"")
.append("to exile").toString());
result = true;
}
return result;
@ -2815,7 +2843,8 @@ public abstract class PlayerImpl implements Player, Serializable {
public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped) {
boolean result = false;
if (card.putOntoBattlefield(game, fromZone, sourceId, this.getId(), tapped)) {
game.informPlayers(new StringBuilder(this.getName())
if (!game.isSimulation())
game.informPlayers(new StringBuilder(this.getName())
.append(" puts ").append(card.getLogName())
.append(" from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" ")
.append("onto the Battlefield").toString());
@ -2888,5 +2917,5 @@ public abstract class PlayerImpl implements Player, Serializable {
return usersAllowedToSeeHandCards;
}
}

View file

@ -93,7 +93,7 @@ public class TargetSource extends TargetObject {
else {
addTarget(id, source, game, notTarget);
}
if (object != null) {
if (object != null && !game.isSimulation()) {
game.informPlayers("Selected " + object.getLogName() + " as source");
}
}

View file

@ -84,7 +84,8 @@ public class CommanderCombatDamageWatcher extends Watcher {
Player player = game.getPlayer(playerUUID);
MageObject commander = game.getObject(sourceId);
if (player != null && commander != null){
game.informPlayers(commander.getLogName() + " did " + damage + " combat damage to " + player.getName() + " during the game.");
if (!game.isSimulation())
game.informPlayers(commander.getLogName() + " did " + damage + " combat damage to " + player.getName() + " during the game.");
this.addCardInfoToCommander(game);
}
}

View file

@ -88,7 +88,8 @@ public class SoulbondWatcher extends Watcher {
if (chosen != null) {
chosen.setPairedCard(permanent.getId());
permanent.setPairedCard(chosen.getId());
game.informPlayers(new StringBuilder(controller.getName()).append(" souldbonds ").append(permanent.getLogName()).append(" with ").append(chosen.getName()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(controller.getName()).append(" souldbonds ").append(permanent.getLogName()).append(" with ").append(chosen.getName()).toString());
}
}
}
@ -112,7 +113,8 @@ public class SoulbondWatcher extends Watcher {
if (controller.chooseUse(Outcome.Benefit, "Use Soulbond for recent " + permanent.getLogName() + "?", game)) {
chosen.setPairedCard(permanent.getId());
permanent.setPairedCard(chosen.getId());
game.informPlayers(new StringBuilder(controller.getName()).append(" souldbonds ").append(permanent.getLogName()).append(" with ").append(chosen.getName()).toString());
if (!game.isSimulation())
game.informPlayers(new StringBuilder(controller.getName()).append(" souldbonds ").append(permanent.getLogName()).append(" with ").append(chosen.getName()).toString());
break;
}
}