mirror of
https://github.com/magefree/mage.git
synced 2025-12-24 20:41:58 -08:00
This commit is contained in:
parent
b885fffd9d
commit
09bc2575d8
23 changed files with 442 additions and 658 deletions
|
|
@ -769,7 +769,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
if (ruleStart.length() > 1) {
|
||||
String end = ruleStart.substring(ruleStart.length() - 2).trim();
|
||||
if (end.isEmpty() || end.equals(":") || end.equals(".")) {
|
||||
rule = ruleStart + Character.toUpperCase(text.charAt(0)) + text.substring(1);
|
||||
rule = ruleStart + CardUtil.getTextWithFirstCharUpperCase(text);
|
||||
} else {
|
||||
rule = ruleStart + text;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.Mode;
|
||||
import mage.constants.Outcome;
|
||||
import mage.target.targetpointer.TargetPointer;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
|
@ -31,7 +32,7 @@ public class Effects extends ArrayList<Effect> {
|
|||
public String getTextStartingUpperCase(Mode mode) {
|
||||
String text = getText(mode);
|
||||
if (text.length() > 3) {
|
||||
return Character.toUpperCase(text.charAt(0)) + text.substring(1);
|
||||
return CardUtil.getTextWithFirstCharUpperCase(text);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,166 @@
|
|||
package mage.abilities.effects.common.cost;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.constants.CostModificationType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class SpellsCostModificationThatTargetSourceEffect extends CostModificationEffectImpl {
|
||||
|
||||
private final FilterCard spellFilter;
|
||||
private final int modificationAmount;
|
||||
private String targetName = "{this}";
|
||||
private TargetController targetController;
|
||||
|
||||
public SpellsCostModificationThatTargetSourceEffect(int modificationAmount, FilterCard spellFilter, TargetController targetController) {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Neutral, modificationAmount < 0 ? CostModificationType.REDUCE_COST : CostModificationType.INCREASE_COST);
|
||||
this.spellFilter = spellFilter;
|
||||
this.modificationAmount = modificationAmount;
|
||||
this.targetController = targetController;
|
||||
|
||||
setText();
|
||||
}
|
||||
|
||||
private void setText() {
|
||||
// example: Spells your opponents cast that target Accursed Witch cost {1} less to cast.
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.spellFilter.getMessage());
|
||||
switch (this.targetController) {
|
||||
case ANY:
|
||||
break;
|
||||
case YOU:
|
||||
sb.append(" you");
|
||||
break;
|
||||
case OPPONENT:
|
||||
sb.append(" your opponents");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported target controller " + this.targetController);
|
||||
}
|
||||
|
||||
sb.append(" cast that target ").append(this.targetName);
|
||||
if (this.modificationAmount < 0) {
|
||||
sb.append(" cost {").append(-1 * this.modificationAmount).append("} less to cast");
|
||||
} else {
|
||||
sb.append(" cost {").append(this.modificationAmount).append("} more to cast");
|
||||
}
|
||||
this.staticText = sb.toString();
|
||||
}
|
||||
|
||||
private SpellsCostModificationThatTargetSourceEffect(SpellsCostModificationThatTargetSourceEffect effect) {
|
||||
super(effect);
|
||||
this.spellFilter = effect.spellFilter;
|
||||
this.modificationAmount = effect.modificationAmount;
|
||||
this.targetName = effect.targetName;
|
||||
this.targetController = effect.targetController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellsCostModificationThatTargetSourceEffect copy() {
|
||||
return new SpellsCostModificationThatTargetSourceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source, Ability abilityToModify) {
|
||||
if (this.modificationAmount >= 0) {
|
||||
CardUtil.increaseCost(abilityToModify, this.modificationAmount);
|
||||
} else {
|
||||
CardUtil.reduceCost(abilityToModify, -1 * this.modificationAmount);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
||||
if (!(abilityToModify instanceof SpellAbility)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player sourceController = game.getPlayer(source.getControllerId());
|
||||
Player abilityController = game.getPlayer(abilityToModify.getControllerId());
|
||||
if (sourceController == null || abilityController == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (this.targetController) {
|
||||
case ANY:
|
||||
break;
|
||||
case YOU:
|
||||
if (!sourceController.getId().equals(abilityController.getId())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OPPONENT:
|
||||
if (!sourceController.hasOpponent(abilityController.getId(), game)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId());
|
||||
if (spell != null && this.spellFilter.match(spell, game)) {
|
||||
// real cast with put on stack
|
||||
Set<UUID> allTargets = getAllSelectedTargets(abilityToModify, source, game);
|
||||
return allTargets.contains(source.getSourceId());
|
||||
} else {
|
||||
// get playable and other staff without put on stack
|
||||
// used at least for flashback ability because Flashback ability doesn't use stack
|
||||
Set<UUID> allTargets = getAllPossibleTargets(abilityToModify, source, game);
|
||||
switch (this.getModificationType()) {
|
||||
case REDUCE_COST:
|
||||
// reduce all the time
|
||||
return allTargets.contains(source.getSourceId());
|
||||
case INCREASE_COST:
|
||||
// increase if can't target another (e.g. user can choose another target without cost increase)
|
||||
return allTargets.contains(source.getSourceId()) && allTargets.size() <= 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Set<UUID> getAllSelectedTargets(Ability abilityToModify, Ability source, Game game) {
|
||||
return abilityToModify.getModes().getSelectedModes()
|
||||
.stream()
|
||||
.map(abilityToModify.getModes()::get)
|
||||
.map(Mode::getTargets)
|
||||
.flatMap(Collection::stream)
|
||||
.map(Target::getTargets)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Set<UUID> getAllPossibleTargets(Ability abilityToModify, Ability source, Game game) {
|
||||
return abilityToModify.getModes().values()
|
||||
.stream()
|
||||
.map(Mode::getTargets)
|
||||
.flatMap(Collection::stream)
|
||||
.map(t -> t.possibleTargets(abilityToModify.getSourceId(), abilityToModify.getControllerId(), game))
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public SpellsCostModificationThatTargetSourceEffect withTargetName(String targetName) {
|
||||
this.targetName = targetName;
|
||||
setText();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,5 @@
|
|||
package mage.abilities.effects.common.cost;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
|
|
@ -17,8 +14,11 @@ import mage.game.stack.Spell;
|
|||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class SpellsCostReductionAllEffect extends CostModificationEffectImpl {
|
||||
|
|
@ -125,8 +125,10 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl {
|
|||
if (abilityToModify instanceof SpellAbility) {
|
||||
Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId());
|
||||
if (spell != null) {
|
||||
// real cast with put on stack
|
||||
return this.filter.match(spell, game) && selectedByRuntimeData(spell, source, game);
|
||||
} else {
|
||||
// get playable and other staff without put on stack
|
||||
// used at least for flashback ability because Flashback ability doesn't use stack
|
||||
Card sourceCard = game.getCard(abilityToModify.getSourceId());
|
||||
return sourceCard != null && this.filter.match(sourceCard, game) && selectedByRuntimeData(sourceCard, source, game);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package mage.abilities.effects.common.cost;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -19,8 +17,10 @@ import mage.game.stack.Spell;
|
|||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author North
|
||||
*/
|
||||
public class SpellsCostReductionControllerEffect extends CostModificationEffectImpl {
|
||||
|
|
@ -116,9 +116,11 @@ public class SpellsCostReductionControllerEffect extends CostModificationEffectI
|
|||
if (abilityToModify.isControlledBy(source.getControllerId())) {
|
||||
Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId());
|
||||
if (spell != null) {
|
||||
// real cast with put on stack
|
||||
return this.filter.match(spell, source.getSourceId(), source.getControllerId(), game);
|
||||
} else {
|
||||
// used at least for flashback ability because Flashback ability doesn't use stack or for getPlayables where spell is not cast yet
|
||||
// get playable and other staff without put on stack
|
||||
// used at least for flashback ability because Flashback ability doesn't use stack
|
||||
Card sourceCard = game.getCard(abilityToModify.getSourceId());
|
||||
return sourceCard != null && this.filter.match(sourceCard, source.getSourceId(), source.getControllerId(), game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package mage.abilities.hint;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
|
|
@ -18,15 +19,19 @@ public class ConditionHint implements Hint {
|
|||
private Color falseColor;
|
||||
private Boolean useIcons;
|
||||
|
||||
public ConditionHint(Condition condition) {
|
||||
this(condition, condition.toString());
|
||||
}
|
||||
|
||||
public ConditionHint(Condition condition, String textWithIcons) {
|
||||
this(condition, textWithIcons, null, textWithIcons, null, true);
|
||||
}
|
||||
|
||||
public ConditionHint(Condition condition, String trueText, Color trueColor, String falseText, Color falseColor, Boolean useIcons) {
|
||||
this.condition = condition;
|
||||
this.trueText = trueText;
|
||||
this.trueText = CardUtil.getTextWithFirstCharUpperCase(trueText);
|
||||
this.trueColor = trueColor;
|
||||
this.falseText = falseText;
|
||||
this.falseText = CardUtil.getTextWithFirstCharUpperCase(falseText);
|
||||
this.falseColor = falseColor;
|
||||
this.useIcons = useIcons;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -800,4 +800,12 @@ public final class CardUtil {
|
|||
return object.getAbilities();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getTextWithFirstCharUpperCase(String text) {
|
||||
if (text != null && text.length() >= 1) {
|
||||
return Character.toUpperCase(text.charAt(0)) + text.substring(1);
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue