mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 18:28:00 +00:00
Implement missing cards with dividable shields for damage replacement effects
This commit is contained in:
@@ -81,9 +81,9 @@ import forge.util.collect.FCollection;
|
||||
import forge.util.collect.FCollectionView;
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* A prototype for player controller class
|
||||
*
|
||||
*
|
||||
* Handles phase skips for now.
|
||||
*/
|
||||
public class PlayerControllerAi extends PlayerController {
|
||||
@@ -94,11 +94,11 @@ public class PlayerControllerAi extends PlayerController {
|
||||
|
||||
brains = new AiController(p, game);
|
||||
}
|
||||
|
||||
|
||||
public void allowCheatShuffle(boolean value){
|
||||
brains.allowCheatShuffle(value);
|
||||
}
|
||||
|
||||
|
||||
public void setUseSimulation(boolean value) {
|
||||
brains.setUseSimulation(value);
|
||||
}
|
||||
@@ -131,6 +131,12 @@ public class PlayerControllerAi extends PlayerController {
|
||||
return ComputerUtilCombat.distributeAIDamage(attacker, blockers, damageDealt, defender, overrideOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<GameEntity, Integer> divideShield(Card effectSource, Map<GameEntity, Integer> affected, int shieldAmount) {
|
||||
// TODO: AI current can't use this so this is not implemented.
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer announceRequirements(SpellAbility ability, String announce) {
|
||||
// For now, these "announcements" are made within the AI classes of the appropriate SA effects
|
||||
@@ -157,7 +163,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
case BidLife:
|
||||
return 0;
|
||||
default:
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null; // return incorrect value to indicate that
|
||||
@@ -240,7 +246,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||
return getAi().confirmAction(sa, mode, message);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode mode, String string,
|
||||
int bid, Player winner) {
|
||||
@@ -646,7 +652,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
public List<SpellAbility> chooseSpellAbilityToPlay() {
|
||||
return brains.chooseSpellAbilityToPlay();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean playChosenSpellAbility(SpellAbility sa) {
|
||||
if (sa instanceof LandAbility) {
|
||||
@@ -658,7 +664,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
ComputerUtil.handlePlayingSpellAbility(player, sa, getGame());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardCollection chooseCardsToDiscardToMaximumHandSize(int numDiscard) {
|
||||
@@ -711,7 +717,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
public int chooseNumber(SpellAbility sa, String title, int min, int max) {
|
||||
return brains.chooseNumber(sa, title, min, max);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int chooseNumber(SpellAbility sa, String string, int min, int max, Map<String, Object> params) {
|
||||
ApiType api = sa.getApi();
|
||||
@@ -814,7 +820,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see
|
||||
* forge.game.player.PlayerController#chooseBinary(forge.game.spellability.
|
||||
* SpellAbility, java.lang.String,
|
||||
@@ -855,7 +861,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
}
|
||||
return sa.getChosenList();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte chooseColorAllowColorless(String message, Card card, ColorSet colors) {
|
||||
final String c = ComputerUtilCard.getMostProminentColor(player.getCardsIn(ZoneType.Hand));
|
||||
@@ -901,7 +907,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see forge.game.player.PlayerController#chooseCounterType(java.util.List,
|
||||
* forge.game.spellability.SpellAbility, java.lang.String, java.util.Map)
|
||||
*/
|
||||
@@ -917,7 +923,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
|
||||
@Override
|
||||
public boolean confirmPayment(CostPart costPart, String prompt, SpellAbility sa) {
|
||||
return brains.confirmPayment(costPart); // AI is expected to know what it is paying for at the moment (otherwise add another parameter to this method)
|
||||
return brains.confirmPayment(costPart); // AI is expected to know what it is paying for at the moment (otherwise add another parameter to this method)
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1105,7 +1111,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
public void revealAnte(String message, Multimap<Player, PaperCard> removedAnteCards) {
|
||||
// Ai won't understand that anyway
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<? extends PaperCard> complainCardsCantPlayWell(Deck myDeck) {
|
||||
return brains.complainCardsCantPlayWell(myDeck);
|
||||
@@ -1153,7 +1159,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Do not convoke potential blockers until after opponent's attack
|
||||
final CardCollectionView blockers = ComputerUtilCard.getLikelyBlockers(ai, null);
|
||||
if ((ph.isPlayerTurn(ai) && ph.getPhase().isAfter(PhaseType.COMBAT_BEGIN)) ||
|
||||
|
||||
@@ -57,6 +57,7 @@ public enum AbilityKey {
|
||||
DefendingPlayer("DefendingPlayer"),
|
||||
Destination("Destination"),
|
||||
Devoured("Devoured"),
|
||||
DividedShieldAmount("DividedShieldAmount"),
|
||||
EchoPaid("EchoPaid"),
|
||||
EffectOnly("EffectOnly"),
|
||||
Exploited("Exploited"),
|
||||
|
||||
@@ -39,6 +39,10 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
|
||||
|
||||
if (prevent > 0) {
|
||||
int n = Math.min(dmg, prevent);
|
||||
// if the effect has divided shield, use that
|
||||
if (originalParams.get(AbilityKey.DividedShieldAmount) != null) {
|
||||
n = Math.min(n, (Integer)originalParams.get(AbilityKey.DividedShieldAmount));
|
||||
}
|
||||
dmg -= n;
|
||||
prevent -= n;
|
||||
|
||||
|
||||
@@ -38,6 +38,10 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
|
||||
|
||||
if (prevent > 0 && list.size() > 0 && list.get(0) instanceof GameEntity) {
|
||||
int n = Math.min(dmg, prevent);
|
||||
// if the effect has divided shield, use that
|
||||
if (originalParams.get(AbilityKey.DividedShieldAmount) != null) {
|
||||
n = Math.min(n, (Integer)originalParams.get(AbilityKey.DividedShieldAmount));
|
||||
}
|
||||
dmg -= n;
|
||||
prevent -= n;
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ public abstract class PlayerController {
|
||||
public abstract List<PaperCard> chooseCardsYouWonToAddToDeck(List<PaperCard> losses);
|
||||
|
||||
public abstract Map<Card, Integer> assignCombatDamage(Card attacker, CardCollectionView blockers, int damageDealt, GameEntity defender, boolean overrideOrder);
|
||||
public abstract Map<GameEntity, Integer> divideShield(Card effectSource, Map<GameEntity, Integer> affected, int shieldAmount);
|
||||
|
||||
public abstract Integer announceRequirements(SpellAbility ability, String announce);
|
||||
public abstract CardCollectionView choosePermanentsToSacrifice(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message);
|
||||
|
||||
@@ -688,6 +688,7 @@ public class ReplacementHandler {
|
||||
ApiType apiType = null;
|
||||
SpellAbility bufferedSA = effectSA;
|
||||
boolean needRestoreSubSA = false;
|
||||
boolean needDivideShield = false;
|
||||
boolean needChooseSource = false;
|
||||
int shieldAmount = 0;
|
||||
if (effectSA != null) {
|
||||
@@ -701,7 +702,8 @@ public class ReplacementHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if the prevent next N damage shield is large enough to replace all damage
|
||||
// Determine if need to divide shield among affected entity and
|
||||
// determine if the prevent next N damage shield is large enough to replace all damage
|
||||
Map<String, String> mapParams = chosenRE.getMapParams();
|
||||
if ((mapParams.containsKey("PreventionEffect") && mapParams.get("PreventionEffect").equals("NextN"))
|
||||
|| apiType == ApiType.ReplaceSplitDamage) {
|
||||
@@ -711,17 +713,50 @@ public class ReplacementHandler {
|
||||
shieldAmount = AbilityUtils.calculateAmount(effectSA.getHostCard(), effectSA.getParamOrDefault("VarName", "1"), effectSA);
|
||||
}
|
||||
int damageAmount = 0;
|
||||
boolean hasMultipleSource = false;
|
||||
boolean hasMultipleTarget = false;
|
||||
Card firstSource = null;
|
||||
GameEntity firstTarget = null;
|
||||
for (Map<AbilityKey, Object> runParams : runParamList) {
|
||||
// Only count damage that can be prevented
|
||||
if (apiType == ApiType.ReplaceDamage && Boolean.TRUE.equals(runParams.get(AbilityKey.NoPreventDamage))) continue;
|
||||
damageAmount += (int) runParams.get(AbilityKey.DamageAmount);
|
||||
if (firstSource == null) {
|
||||
firstSource = (Card) runParams.get(AbilityKey.DamageSource);
|
||||
} else if (!firstSource.equals(runParams.get(AbilityKey.DamageSource))) {
|
||||
hasMultipleSource = true;
|
||||
}
|
||||
if (firstTarget == null) {
|
||||
firstTarget = (GameEntity) runParams.get(AbilityKey.Affected);
|
||||
} else if (!firstTarget.equals(runParams.get(AbilityKey.Affected))) {
|
||||
hasMultipleTarget = true;
|
||||
}
|
||||
}
|
||||
if (damageAmount > shieldAmount) {
|
||||
needChooseSource = true;
|
||||
if (damageAmount > shieldAmount && runParamList.size() > 1) {
|
||||
if (hasMultipleSource)
|
||||
needChooseSource = true;
|
||||
if (effectSA.hasParam("DivideShield") && hasMultipleTarget)
|
||||
needDivideShield = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ask the decider to divide shield among affected damage target
|
||||
Map<GameEntity, Integer> shieldMap = null;
|
||||
if (needDivideShield) {
|
||||
Map<GameEntity, Integer> affected = new HashMap<>();
|
||||
for (Map<AbilityKey, Object> runParams : runParamList) {
|
||||
GameEntity target = (GameEntity) runParams.get(AbilityKey.Affected);
|
||||
Integer damage = (Integer) runParams.get(AbilityKey.DamageAmount);
|
||||
if (!affected.containsKey(target)) {
|
||||
affected.put(target, damage);
|
||||
} else {
|
||||
affected.put(target, damage + affected.get(target));
|
||||
}
|
||||
}
|
||||
shieldMap = decider.getController().divideShield(chosenRE.getHostCard(), affected, shieldAmount);
|
||||
}
|
||||
|
||||
// CR 615.7
|
||||
// If damage would be dealt to the shielded permanent or player by two or more applicable sources at the same time,
|
||||
// the player or the controller of the permanent chooses which damage the shield prevents.
|
||||
@@ -735,23 +770,42 @@ public class ReplacementHandler {
|
||||
while (shieldAmount > 0 && !sourcesToChooseFrom.isEmpty()) {
|
||||
Card source = decider.getController().chooseSingleEntityForEffect(sourcesToChooseFrom, effectSA, choiceTitle, null);
|
||||
sourcesToChooseFrom.remove(source);
|
||||
Map<AbilityKey, Object> runParams = null;
|
||||
for (Map<AbilityKey, Object> rp : runParamList) {
|
||||
if (source.equals(rp.get(AbilityKey.DamageSource))) {
|
||||
runParams = rp;
|
||||
break;
|
||||
Iterator<Map<AbilityKey, Object>> itr = runParamList.iterator();
|
||||
while (itr.hasNext()) {
|
||||
Map<AbilityKey, Object> runParams = itr.next();
|
||||
if (source.equals(runParams.get(AbilityKey.DamageSource))) {
|
||||
itr.remove();
|
||||
if (shieldMap != null) {
|
||||
GameEntity target = (GameEntity) runParams.get(AbilityKey.Affected);
|
||||
if (shieldMap.containsKey(target) && shieldMap.get(target) > 0) {
|
||||
Integer dividedShieldAmount = shieldMap.get(target);
|
||||
runParams.put(AbilityKey.DividedShieldAmount, dividedShieldAmount);
|
||||
shieldAmount -= (int) dividedShieldAmount;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
shieldAmount -= (int) runParams.get(AbilityKey.DamageAmount);
|
||||
}
|
||||
if (!runParams.containsKey(AbilityKey.ReplacementResultMap)) {
|
||||
Map<ReplacementEffect, ReplacementResult> resultMap = new HashMap<>();
|
||||
runParams.put(AbilityKey.ReplacementResultMap, resultMap);
|
||||
}
|
||||
runSingleReplaceDamageEffect(chosenRE, runParams, replaceCandidateMap, executedDamageMap, decider, damageMap, preventMap);
|
||||
}
|
||||
}
|
||||
runParamList.remove(runParams);
|
||||
shieldAmount -= (int) runParams.get(AbilityKey.DamageAmount);
|
||||
if (!runParams.containsKey(AbilityKey.ReplacementResultMap)) {
|
||||
Map<ReplacementEffect, ReplacementResult> resultMap = new HashMap<>();
|
||||
runParams.put(AbilityKey.ReplacementResultMap, resultMap);
|
||||
}
|
||||
runSingleReplaceDamageEffect(chosenRE, runParams, replaceCandidateMap, executedDamageMap, decider, damageMap, preventMap);
|
||||
}
|
||||
} else {
|
||||
for (Map<AbilityKey, Object> runParams : runParamList) {
|
||||
if (shieldMap != null) {
|
||||
GameEntity target = (GameEntity) runParams.get(AbilityKey.Affected);
|
||||
if (shieldMap.containsKey(target) && shieldMap.get(target) > 0) {
|
||||
Integer dividedShieldAmount = shieldMap.get(target);
|
||||
runParams.put(AbilityKey.DividedShieldAmount, dividedShieldAmount);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!runParams.containsKey(AbilityKey.ReplacementResultMap)) {
|
||||
Map<ReplacementEffect, ReplacementResult> resultMap = new HashMap<>();
|
||||
runParams.put(AbilityKey.ReplacementResultMap, resultMap);
|
||||
|
||||
@@ -760,7 +760,7 @@ public final class CMatchUI
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if (FThreads.isGuiThread()) { // run this now whether in EDT or not so that it doesn't clobber later stuff
|
||||
FThreads.invokeInEdtNowOrLater(focusRoutine);
|
||||
} else {
|
||||
@@ -1028,6 +1028,24 @@ public final class CMatchUI
|
||||
return result.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<GameEntityView, Integer> assignGenericAmount(final CardView effectSource, final Map<GameEntityView, Integer> target,
|
||||
final int amount, final boolean atLeastOne, final String amountLabel) {
|
||||
if (amount <= 0) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
final AtomicReference<Map<GameEntityView, Integer>> result = new AtomicReference<>();
|
||||
FThreads.invokeInEdtAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final VAssignGenericAmount v = new VAssignGenericAmount(CMatchUI.this, effectSource, target, amount, atLeastOne, amountLabel);
|
||||
result.set(v.getAssignedMap());
|
||||
}});
|
||||
return result.get();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void openView(final TrackableCollection<PlayerView> myPlayers) {
|
||||
final GameView gameView = getGameView();
|
||||
@@ -1273,28 +1291,28 @@ public final class CMatchUI
|
||||
String stackNotificationPolicy = FModel.getPreferences().getPref(FPref.UI_STACK_EFFECT_NOTIFICATION_POLICY);
|
||||
boolean isAi = sa.getActivatingPlayer().isAI();
|
||||
boolean isTrigger = sa.isTrigger();
|
||||
int stackIndex = event.stackIndex;
|
||||
if(stackIndex == nextNotifiableStackIndex) {
|
||||
int stackIndex = event.stackIndex;
|
||||
if(stackIndex == nextNotifiableStackIndex) {
|
||||
if(ForgeConstants.STACK_EFFECT_NOTIFICATION_ALWAYS.equals(stackNotificationPolicy) || (ForgeConstants.STACK_EFFECT_NOTIFICATION_AI_AND_TRIGGERED.equals(stackNotificationPolicy) && (isAi || isTrigger))) {
|
||||
// We can go and show the modal
|
||||
SpellAbilityStackInstance si = event.si;
|
||||
|
||||
|
||||
MigLayout migLayout = new MigLayout("insets 15, left, gap 30, fill");
|
||||
JPanel mainPanel = new JPanel(migLayout);
|
||||
final Dimension parentSize = JOptionPane.getRootFrame().getSize();
|
||||
Dimension maxSize = new Dimension(1400, parentSize.height - 100);
|
||||
mainPanel.setMaximumSize(maxSize);
|
||||
mainPanel.setOpaque(false);
|
||||
mainPanel.setOpaque(false);
|
||||
|
||||
// Big Image
|
||||
addBigImageToStackModalPanel(mainPanel, si);
|
||||
|
||||
|
||||
// Text
|
||||
addTextToStackModalPanel(mainPanel,sa,si);
|
||||
|
||||
|
||||
// Small images
|
||||
int numSmallImages = 0;
|
||||
|
||||
|
||||
// If current effect is a triggered/activated ability of an enchantment card, I want to show the enchanted card
|
||||
GameEntityView enchantedEntityView = null;
|
||||
Card hostCard = sa.getHostCard();
|
||||
@@ -1308,45 +1326,45 @@ public final class CMatchUI
|
||||
&& !sa.getRootAbility().getPaidList("Sacrificed").isEmpty()) {
|
||||
// If the player activated its ability by sacrificing the enchantment, the enchantment has not anything attached anymore and the ex-enchanted card has to be searched in other ways.. for example, the green enchantment "Carapace"
|
||||
enchantedEntity = sa.getRootAbility().getPaidList("Sacrificed").get(0).getEnchantingCard();
|
||||
if(enchantedEntity != null) {
|
||||
enchantedEntityView = enchantedEntity.getView();
|
||||
if(enchantedEntity != null) {
|
||||
enchantedEntityView = enchantedEntity.getView();
|
||||
numSmallImages++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If current effect is a triggered ability, I want to show the triggering card if present
|
||||
SpellAbility sourceSA = (SpellAbility) si.getTriggeringObject(AbilityKey.SourceSA);
|
||||
CardView sourceCardView = null;
|
||||
if(sourceSA != null) {
|
||||
sourceCardView = sourceSA.getHostCard().getView();
|
||||
numSmallImages++;
|
||||
}
|
||||
}
|
||||
|
||||
// I also want to show each type of targets (both cards and players)
|
||||
List<GameEntityView> targets = getTargets(si,new ArrayList<GameEntityView>());
|
||||
numSmallImages = numSmallImages + targets.size();
|
||||
|
||||
|
||||
// Now I know how many small images - on to render them
|
||||
if(enchantedEntityView != null) {
|
||||
addSmallImageToStackModalPanel(enchantedEntityView,mainPanel,numSmallImages);
|
||||
addSmallImageToStackModalPanel(enchantedEntityView,mainPanel,numSmallImages);
|
||||
}
|
||||
if(sourceCardView != null) {
|
||||
addSmallImageToStackModalPanel(sourceCardView,mainPanel,numSmallImages);
|
||||
addSmallImageToStackModalPanel(sourceCardView,mainPanel,numSmallImages);
|
||||
}
|
||||
for(GameEntityView gev : targets) {
|
||||
addSmallImageToStackModalPanel(gev, mainPanel, numSmallImages);
|
||||
}
|
||||
|
||||
FOptionPane.showOptionDialog(null, "Forge", null, mainPanel, ImmutableList.of(Localizer.getInstance().getMessage("lblOK")));
|
||||
}
|
||||
|
||||
FOptionPane.showOptionDialog(null, "Forge", null, mainPanel, ImmutableList.of(Localizer.getInstance().getMessage("lblOK")));
|
||||
// here the user closed the modal - time to update the next notifiable stack index
|
||||
|
||||
|
||||
}
|
||||
// In any case, I have to increase the counter
|
||||
nextNotifiableStackIndex++;
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
// Not yet time to show the modal - schedule the method again, and try again later
|
||||
Runnable tryAgainThread = new Runnable() {
|
||||
@Override
|
||||
@@ -1355,8 +1373,8 @@ public final class CMatchUI
|
||||
}
|
||||
};
|
||||
GuiBase.getInterface().invokeInEdtLater(tryAgainThread);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private List<GameEntityView> getTargets(SpellAbilityStackInstance si, List<GameEntityView> result){
|
||||
@@ -1380,22 +1398,22 @@ public final class CMatchUI
|
||||
|
||||
return getTargets(si.getSubInstance(),result);
|
||||
}
|
||||
|
||||
|
||||
private void addBigImageToStackModalPanel(JPanel mainPanel, SpellAbilityStackInstance si) {
|
||||
StackItemView siv = si.getView();
|
||||
int rotation = getRotation(si.getCardView());
|
||||
|
||||
FImagePanel imagePanel = new FImagePanel();
|
||||
BufferedImage bufferedImage = FImageUtil.getImage(siv.getSourceCard().getCurrentState());
|
||||
FImagePanel imagePanel = new FImagePanel();
|
||||
BufferedImage bufferedImage = FImageUtil.getImage(siv.getSourceCard().getCurrentState());
|
||||
imagePanel.setImage(bufferedImage, rotation, AutoSizeImageMode.SOURCE);
|
||||
int imageWidth = 433;
|
||||
int imageHeight = 600;
|
||||
Dimension imagePanelDimension = new Dimension(imageWidth,imageHeight);
|
||||
imagePanel.setMinimumSize(imagePanelDimension);
|
||||
|
||||
mainPanel.add(imagePanel, "cell 0 0, spany 3");
|
||||
|
||||
mainPanel.add(imagePanel, "cell 0 0, spany 3");
|
||||
}
|
||||
|
||||
|
||||
private void addTextToStackModalPanel(JPanel mainPanel, SpellAbility sa, SpellAbilityStackInstance si) {
|
||||
String who = sa.getActivatingPlayer().getName();
|
||||
String action = sa.isSpell() ? " cast " : sa.isTrigger() ? " triggered " : " activated ";
|
||||
@@ -1409,45 +1427,45 @@ public final class CMatchUI
|
||||
TargetChoices targets = si.getTargetChoices();
|
||||
sb.append(targets);
|
||||
}
|
||||
sb.append(".");
|
||||
sb.append(".");
|
||||
String message1 = sb.toString();
|
||||
String message2 = si.getStackDescription();
|
||||
String message2 = si.getStackDescription();
|
||||
String messageTotal = message1 + "\n\n" + message2;
|
||||
|
||||
|
||||
final FTextArea prompt1 = new FTextArea(messageTotal);
|
||||
prompt1.setFont(FSkin.getFont(21));
|
||||
prompt1.setAutoSize(true);
|
||||
prompt1.setMinimumSize(new Dimension(475,200));
|
||||
mainPanel.add(prompt1, "cell 1 0, aligny top");
|
||||
mainPanel.add(prompt1, "cell 1 0, aligny top");
|
||||
}
|
||||
|
||||
|
||||
private void addSmallImageToStackModalPanel(GameEntityView gameEntityView, JPanel mainPanel, int numTarget) {
|
||||
if(gameEntityView instanceof CardView) {
|
||||
CardView cardView = (CardView) gameEntityView;
|
||||
int currRotation = getRotation(cardView);
|
||||
int currRotation = getRotation(cardView);
|
||||
FImagePanel targetPanel = new FImagePanel();
|
||||
BufferedImage bufferedImage = FImageUtil.getImage(cardView.getCurrentState());
|
||||
BufferedImage bufferedImage = FImageUtil.getImage(cardView.getCurrentState());
|
||||
targetPanel.setImage(bufferedImage, currRotation, AutoSizeImageMode.SOURCE);
|
||||
int imageWidth = 217;
|
||||
int imageHeight = 300;
|
||||
Dimension targetPanelDimension = new Dimension(imageWidth,imageHeight);
|
||||
targetPanel.setMinimumSize(targetPanelDimension);
|
||||
mainPanel.add(targetPanel, "cell 1 1, split " + numTarget+ ", aligny bottom");
|
||||
mainPanel.add(targetPanel, "cell 1 1, split " + numTarget+ ", aligny bottom");
|
||||
} else if(gameEntityView instanceof PlayerView) {
|
||||
PlayerView playerView = (PlayerView) gameEntityView;
|
||||
SkinImage playerAvatar = getPlayerAvatar(playerView, 0);
|
||||
final FLabel lblIcon = new FLabel.Builder().icon(playerAvatar).build();
|
||||
Dimension dimension = playerAvatar.getSizeForPaint(JOptionPane.getRootFrame().getGraphics());
|
||||
mainPanel.add(lblIcon, "cell 1 1, split " + numTarget+ ", w " + dimension.getWidth() + ", h " + dimension.getHeight() + ", aligny bottom");
|
||||
mainPanel.add(lblIcon, "cell 1 1, split " + numTarget+ ", w " + dimension.getWidth() + ", h " + dimension.getHeight() + ", aligny bottom");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private int getRotation(CardView cardView) {
|
||||
final int rotation;
|
||||
if (cardView.isSplitCard()) {
|
||||
String cardName = cardView.getName();
|
||||
if (cardName.isEmpty()) { cardName = cardView.getAlternateState().getName(); }
|
||||
|
||||
|
||||
PaperCard pc = StaticData.instance().getCommonCards().getCard(cardName);
|
||||
boolean hasKeywordAftermath = pc != null && Card.getCardForUi(pc).hasKeyword(Keyword.AFTERMATH);
|
||||
|
||||
@@ -1459,7 +1477,7 @@ public final class CMatchUI
|
||||
|
||||
return rotation;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void notifyStackRemoval(GameEventSpellRemovedFromStack event) {
|
||||
// I always decrease the counter
|
||||
@@ -1474,49 +1492,49 @@ public final class CMatchUI
|
||||
createLandPopupPanel(land);
|
||||
}
|
||||
};
|
||||
GuiBase.getInterface().invokeInEdtAndWait(createPopupThread);
|
||||
GuiBase.getInterface().invokeInEdtAndWait(createPopupThread);
|
||||
}
|
||||
|
||||
private void createLandPopupPanel(Card land) {
|
||||
|
||||
|
||||
String landPlayedNotificationPolicy = FModel.getPreferences().getPref(FPref.UI_LAND_PLAYED_NOTIFICATION_POLICY);
|
||||
Player cardController = land.getController();
|
||||
boolean isAi = cardController.isAI();
|
||||
if(ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS.equals(landPlayedNotificationPolicy)
|
||||
Player cardController = land.getController();
|
||||
boolean isAi = cardController.isAI();
|
||||
if(ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS.equals(landPlayedNotificationPolicy)
|
||||
|| (ForgeConstants.LAND_PLAYED_NOTIFICATION_AI.equals(landPlayedNotificationPolicy) && (isAi))
|
||||
|| (ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS_FOR_NONBASIC_LANDS.equals(landPlayedNotificationPolicy) && !land.isBasicLand())
|
||||
|| (ForgeConstants.LAND_PLAYED_NOTIFICATION_AI_FOR_NONBASIC_LANDS.equals(landPlayedNotificationPolicy) && !land.isBasicLand()) && (isAi)) {
|
||||
String title = "Forge";
|
||||
String title = "Forge";
|
||||
List<String> options = ImmutableList.of(Localizer.getInstance().getMessage("lblOK"));
|
||||
|
||||
|
||||
MigLayout migLayout = new MigLayout("insets 15, left, gap 30, fill");
|
||||
JPanel mainPanel = new JPanel(migLayout);
|
||||
final Dimension parentSize = JOptionPane.getRootFrame().getSize();
|
||||
Dimension maxSize = new Dimension(1400, parentSize.height - 100);
|
||||
mainPanel.setMaximumSize(maxSize);
|
||||
mainPanel.setOpaque(false);
|
||||
|
||||
mainPanel.setOpaque(false);
|
||||
|
||||
int rotation = getRotation(land.getView());
|
||||
|
||||
FImagePanel imagePanel = new FImagePanel();
|
||||
BufferedImage bufferedImage = FImageUtil.getImage(land.getCurrentState().getView());
|
||||
FImagePanel imagePanel = new FImagePanel();
|
||||
BufferedImage bufferedImage = FImageUtil.getImage(land.getCurrentState().getView());
|
||||
imagePanel.setImage(bufferedImage, rotation, AutoSizeImageMode.SOURCE);
|
||||
int imageWidth = 433;
|
||||
int imageHeight = 600;
|
||||
Dimension imagePanelDimension = new Dimension(imageWidth,imageHeight);
|
||||
imagePanel.setMinimumSize(imagePanelDimension);
|
||||
|
||||
|
||||
mainPanel.add(imagePanel, "cell 0 0, spany 3");
|
||||
|
||||
String msg = cardController.toString() + " puts " + land.toString() + " into play into " + ZoneType.Battlefield.toString() + ".";
|
||||
|
||||
|
||||
String msg = cardController.toString() + " puts " + land.toString() + " into play into " + ZoneType.Battlefield.toString() + ".";
|
||||
|
||||
final FTextArea prompt1 = new FTextArea(msg);
|
||||
prompt1.setFont(FSkin.getFont(21));
|
||||
prompt1.setAutoSize(true);
|
||||
prompt1.setMinimumSize(new Dimension(475,200));
|
||||
mainPanel.add(prompt1, "cell 1 0, aligny top");
|
||||
|
||||
FOptionPane.showOptionDialog(null, title, null, mainPanel, options);
|
||||
}
|
||||
mainPanel.add(prompt1, "cell 1 0, aligny top");
|
||||
|
||||
FOptionPane.showOptionDialog(null, title, null, mainPanel, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2021 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.screens.match;
|
||||
|
||||
import java.awt.Dialog.ModalityType;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.Border;
|
||||
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.gui.SOverlayUtils;
|
||||
import forge.toolbox.FButton;
|
||||
import forge.toolbox.FLabel;
|
||||
import forge.toolbox.FScrollPane;
|
||||
import forge.toolbox.FSkin;
|
||||
import forge.toolbox.FSkin.SkinnedPanel;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.TextUtil;
|
||||
import forge.view.FDialog;
|
||||
import forge.view.arcane.CardPanel;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
/**
|
||||
* Assembles Swing components of assign damage dialog.
|
||||
*
|
||||
* This needs a JDialog to maintain a modal state.
|
||||
* Without the modal state, the PhaseHandler automatically
|
||||
* moves forward to phase Main2 without assigning damage.
|
||||
*
|
||||
* <br><br><i>(V at beginning of class name denotes a view class.)</i>
|
||||
*/
|
||||
public class VAssignGenericAmount {
|
||||
final Localizer localizer = Localizer.getInstance();
|
||||
private final CMatchUI matchUI;
|
||||
|
||||
// Width and height of assign dialog
|
||||
private final int wDlg = 700;
|
||||
private final int hDlg = 500;
|
||||
private final FDialog dlg = new FDialog();
|
||||
|
||||
// Amount storage
|
||||
private final int totalAmountToAssign;
|
||||
|
||||
private final String lblAmount;
|
||||
private final JLabel lblTotalAmount;
|
||||
// Label Buttons
|
||||
private final FButton btnOK = new FButton(localizer.getMessage("lblOk"));
|
||||
private final FButton btnReset = new FButton(localizer.getMessage("lblReset"));
|
||||
|
||||
private static class AssignTarget {
|
||||
public final GameEntityView entity;
|
||||
public final JLabel label;
|
||||
public final int max;
|
||||
public int amount;
|
||||
|
||||
public AssignTarget(final GameEntityView e, final JLabel lbl, int max0) {
|
||||
entity = e;
|
||||
label = lbl;
|
||||
max = max0;
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private final List<AssignTarget> targetsList = new ArrayList<>();
|
||||
private final Map<GameEntityView, AssignTarget> targetsMap = new HashMap<>();
|
||||
|
||||
// Mouse actions
|
||||
private final MouseAdapter mad = new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseEntered(final MouseEvent evt) {
|
||||
((CardPanel) evt.getSource()).setBorder(new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_ACTIVE), 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(final MouseEvent evt) {
|
||||
((CardPanel) evt.getSource()).setBorder((Border)null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(final MouseEvent evt) {
|
||||
CardView source = ((CardPanel) evt.getSource()).getCard(); // will be NULL for player
|
||||
|
||||
boolean meta = evt.isControlDown();
|
||||
boolean isLMB = SwingUtilities.isLeftMouseButton(evt);
|
||||
boolean isRMB = SwingUtilities.isRightMouseButton(evt);
|
||||
|
||||
if ( isLMB || isRMB)
|
||||
assignAmountTo(source, meta, isLMB);
|
||||
}
|
||||
};
|
||||
|
||||
public VAssignGenericAmount(final CMatchUI matchUI, final CardView effectSource, final Map<GameEntityView, Integer> targets, final int amount, final boolean atLeastOne, final String amountLabel) {
|
||||
this.matchUI = matchUI;
|
||||
dlg.setTitle(localizer.getMessage("lbLAssignAmountForEffect", amountLabel, effectSource.toString()));
|
||||
|
||||
totalAmountToAssign = amount;
|
||||
|
||||
lblAmount = amountLabel;
|
||||
lblTotalAmount = new FLabel.Builder().text(localizer.getMessage("lblTotalAmountText", lblAmount)).build();
|
||||
|
||||
// Top-level UI stuff
|
||||
final JPanel overlay = SOverlayUtils.genericOverlay();
|
||||
final SkinnedPanel pnlMain = new SkinnedPanel();
|
||||
pnlMain.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));
|
||||
|
||||
// Effect Source area
|
||||
final CardPanel pnlSource = new CardPanel(matchUI, effectSource);
|
||||
pnlSource.setOpaque(false);
|
||||
pnlSource.setCardBounds(0, 0, 105, 150);
|
||||
|
||||
final JPanel pnlInfo = new JPanel(new MigLayout("insets 0, gap 0, wrap"));
|
||||
pnlInfo.setOpaque(false);
|
||||
pnlInfo.add(lblTotalAmount, "gap 0 0 20px 5px");
|
||||
pnlInfo.add(new FLabel.Builder().text(localizer.getMessage("lblLClickAmountMessage", lblAmount)).build(), "gap 0 0 0 5px");
|
||||
pnlInfo.add(new FLabel.Builder().text(localizer.getMessage("lblRClickAmountMessage", lblAmount)).build(), "gap 0 0 0 5px");
|
||||
|
||||
// Targets area
|
||||
final JPanel pnlTargets = new JPanel();
|
||||
pnlTargets.setOpaque(false);
|
||||
int cols = targets.size();
|
||||
final String wrap = "wrap " + cols;
|
||||
pnlTargets.setLayout(new MigLayout("insets 0, gap 0, ax center, " + wrap));
|
||||
|
||||
final FScrollPane scrTargets = new FScrollPane(pnlTargets, false);
|
||||
|
||||
// Top row of cards...
|
||||
for (final Map.Entry<GameEntityView, Integer> e : targets.entrySet()) {
|
||||
int maxAmount = e.getValue() != null ? e.getValue() : amount;
|
||||
final AssignTarget at = new AssignTarget(e.getKey(), new FLabel.Builder().text("0").fontSize(18).fontAlign(SwingConstants.CENTER).build(), maxAmount);
|
||||
addPanelForTarget(pnlTargets, at);
|
||||
}
|
||||
|
||||
// ... bottom row of labels.
|
||||
for (final AssignTarget l : targetsList) {
|
||||
pnlTargets.add(l.label, "w 145px!, h 30px!, gap 5px 5px 0 5px");
|
||||
}
|
||||
|
||||
btnOK.addActionListener(new ActionListener() {
|
||||
@Override public void actionPerformed(ActionEvent arg0) { finish(); } });
|
||||
btnReset.addActionListener(new ActionListener() {
|
||||
@Override public void actionPerformed(ActionEvent arg0) { resetAssignedAmount(); initialAssignAmount(atLeastOne); } });
|
||||
|
||||
// Final UI layout
|
||||
pnlMain.setLayout(new MigLayout("insets 0, gap 0, wrap 2, ax center"));
|
||||
pnlMain.add(pnlSource, "w 125px!, h 160px!, gap 50px 0 0 15px");
|
||||
pnlMain.add(pnlInfo, "gap 20px 0 0 15px");
|
||||
pnlMain.add(scrTargets, "w 96%!, gap 2% 0 0 0, pushy, growy, ax center, span 2");
|
||||
|
||||
final JPanel pnlButtons = new JPanel(new MigLayout("insets 0, gap 0, ax center"));
|
||||
pnlButtons.setOpaque(false);
|
||||
pnlButtons.add(btnOK, "w 110px!, h 30px!, gap 0 10px 0 0");
|
||||
pnlButtons.add(btnReset, "w 110px!, h 30px!");
|
||||
|
||||
pnlMain.add(pnlButtons, "ax center, w 350px!, gap 10px 10px 10px 10px, span 2");
|
||||
overlay.add(pnlMain);
|
||||
|
||||
pnlMain.getRootPane().setDefaultButton(btnOK);
|
||||
|
||||
initialAssignAmount(atLeastOne);
|
||||
SOverlayUtils.showOverlay();
|
||||
|
||||
dlg.setUndecorated(true);
|
||||
dlg.setContentPane(pnlMain);
|
||||
dlg.setSize(new Dimension(wDlg, hDlg));
|
||||
dlg.setLocation((overlay.getWidth() - wDlg) / 2, (overlay.getHeight() - hDlg) / 2);
|
||||
dlg.setModalityType(ModalityType.APPLICATION_MODAL);
|
||||
dlg.setVisible(true);
|
||||
}
|
||||
|
||||
private void addPanelForTarget(final JPanel pnlTargets, final AssignTarget at) {
|
||||
CardView cv = null;
|
||||
if (at.entity instanceof CardView) {
|
||||
cv = (CardView)at.entity;
|
||||
} else if (at.entity instanceof PlayerView) {
|
||||
final PlayerView p = (PlayerView)at.entity;
|
||||
cv = new CardView(-1, null, at.entity.toString(), p, matchUI.getAvatarImage(p.getLobbyPlayerName()));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
final CardPanel cp = new CardPanel(matchUI, cv);
|
||||
cp.setCardBounds(0, 0, 105, 150);
|
||||
cp.setOpaque(true);
|
||||
pnlTargets.add(cp, "w 145px!, h 170px!, gap 5px 5px 3px 3px, ax center");
|
||||
cp.addMouseListener(mad);
|
||||
targetsMap.put(cv, at);
|
||||
targetsList.add(at);
|
||||
}
|
||||
|
||||
private void assignAmountTo(CardView source, final boolean meta, final boolean isAdding) {
|
||||
AssignTarget at = targetsMap.get(source);
|
||||
int assigned = at.amount;
|
||||
int leftToAssign = Math.max(0, at.max - assigned);
|
||||
int amountToAdd = isAdding ? 1 : -1;
|
||||
int remainingAmount = Math.min(getRemainingAmount(), leftToAssign);
|
||||
// Left click adds, right click substracts.
|
||||
// Hold Ctrl to assign to maximum amount
|
||||
if (meta) {
|
||||
if (isAdding) {
|
||||
amountToAdd = leftToAssign > 0 ? leftToAssign : 0;
|
||||
} else {
|
||||
amountToAdd = -assigned;
|
||||
}
|
||||
}
|
||||
|
||||
if (amountToAdd > remainingAmount) {
|
||||
amountToAdd = remainingAmount;
|
||||
}
|
||||
|
||||
if (0 == amountToAdd || amountToAdd + assigned < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
addAssignedAmount(at, amountToAdd);
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
private void initialAssignAmount(boolean atLeastOne) {
|
||||
if (!atLeastOne) {
|
||||
updateLabels();
|
||||
return;
|
||||
}
|
||||
|
||||
for(AssignTarget at : targetsList) {
|
||||
addAssignedAmount(at, 1);
|
||||
}
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
private void resetAssignedAmount() {
|
||||
for(AssignTarget at : targetsList)
|
||||
at.amount = 0;
|
||||
}
|
||||
|
||||
private void addAssignedAmount(final AssignTarget at, int addedAmount) {
|
||||
// If we don't have enough left or we're trying to unassign too much return
|
||||
final int canAssign = getRemainingAmount();
|
||||
if (canAssign < addedAmount) {
|
||||
addedAmount = canAssign;
|
||||
}
|
||||
|
||||
at.amount = Math.max(0, addedAmount + at.amount);
|
||||
}
|
||||
|
||||
private int getRemainingAmount() {
|
||||
int spent = 0;
|
||||
for(AssignTarget at : targetsList) {
|
||||
spent += at.amount;
|
||||
}
|
||||
return totalAmountToAssign - spent;
|
||||
}
|
||||
|
||||
/** Updates labels and other UI elements.*/
|
||||
private void updateLabels() {
|
||||
int amountLeft = totalAmountToAssign;
|
||||
|
||||
for ( AssignTarget at : targetsList )
|
||||
{
|
||||
amountLeft -= at.amount;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(at.amount);
|
||||
if (at.max - at.amount == 0) {
|
||||
sb.append(" (").append(localizer.getMessage("lblMax")).append(")");
|
||||
}
|
||||
at.label.setText(sb.toString());
|
||||
}
|
||||
|
||||
lblTotalAmount.setText(TextUtil.concatNoSpace(localizer.getMessage("lblAvailableAmount", lblAmount), ": " , String.valueOf(amountLeft), " (of ", String.valueOf(totalAmountToAssign), ")"));
|
||||
btnOK.setEnabled(amountLeft == 0);
|
||||
}
|
||||
|
||||
private void finish() {
|
||||
if ( getRemainingAmount() > 0 )
|
||||
return;
|
||||
|
||||
dlg.dispose();
|
||||
SOverlayUtils.hideOverlay();
|
||||
}
|
||||
|
||||
public Map<GameEntityView, Integer> getAssignedMap() {
|
||||
Map<GameEntityView, Integer> result = new HashMap<>(targetsList.size());
|
||||
for (AssignTarget at : targetsList)
|
||||
result.put(at.entity, at.amount);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -146,6 +146,12 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
throw new IllegalStateException("Erring on the side of caution here...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<GameEntity, Integer> divideShield(Card effectSource, Map<GameEntity, Integer> affected, int shieldAmount) {
|
||||
throw new IllegalStateException("Erring on the side of caution here...");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Integer announceRequirements(SpellAbility ability, String announce) {
|
||||
throw new IllegalStateException("Erring on the side of caution here...");
|
||||
|
||||
@@ -49,6 +49,7 @@ import forge.model.FModel;
|
||||
import forge.player.PlayerZoneUpdate;
|
||||
import forge.player.PlayerZoneUpdates;
|
||||
import forge.screens.match.views.VAssignCombatDamage;
|
||||
import forge.screens.match.views.VAssignGenericAmount;
|
||||
import forge.screens.match.views.VPhaseIndicator;
|
||||
import forge.screens.match.views.VPhaseIndicator.PhaseLabel;
|
||||
import forge.screens.match.views.VPlayerPanel;
|
||||
@@ -395,6 +396,18 @@ public class MatchController extends AbstractGuiGame {
|
||||
}.invokeAndWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<GameEntityView, Integer> assignGenericAmount(final CardView effectSource, final Map<GameEntityView, Integer> targets,
|
||||
final int amount, final boolean atLeastOne, final String amountLabel) {
|
||||
return new WaitCallback<Map<GameEntityView, Integer>>() {
|
||||
@Override
|
||||
public void run() {
|
||||
final VAssignGenericAmount v = new VAssignGenericAmount(effectSource, targets, amount, atLeastOne, amountLabel, this);
|
||||
v.show();
|
||||
}
|
||||
}.invokeAndWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateManaPool(final Iterable<PlayerView> manaPoolUpdate) {
|
||||
for (final PlayerView p : manaPoolUpdate) {
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.screens.match.views;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
|
||||
import forge.Forge;
|
||||
import forge.Graphics;
|
||||
import forge.assets.FImage;
|
||||
import forge.assets.FSkinColor;
|
||||
import forge.assets.FSkinColor.Colors;
|
||||
import forge.assets.FSkinFont;
|
||||
import forge.assets.FSkinImage;
|
||||
import forge.card.CardZoom;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.screens.match.MatchController;
|
||||
import forge.toolbox.FCardPanel;
|
||||
import forge.toolbox.FContainer;
|
||||
import forge.toolbox.FDialog;
|
||||
import forge.toolbox.FDisplayObject;
|
||||
import forge.toolbox.FEvent;
|
||||
import forge.toolbox.FEvent.FEventHandler;
|
||||
import forge.toolbox.FLabel;
|
||||
import forge.toolbox.FOptionPane;
|
||||
import forge.toolbox.FScrollPane;
|
||||
import forge.util.Callback;
|
||||
import forge.util.CardTranslation;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.Utils;
|
||||
import forge.util.WaitCallback;
|
||||
|
||||
public class VAssignGenericAmount extends FDialog {
|
||||
private static final float CARD_GAP_X = Utils.scale(10);
|
||||
private static final float ADD_BTN_HEIGHT = Utils.AVG_FINGER_HEIGHT * 0.75f;
|
||||
|
||||
private final Callback<Map<GameEntityView, Integer>> callback;
|
||||
private final int totalAmountToAssign;
|
||||
|
||||
private final String lblAmount;
|
||||
private final FLabel lblTotalAmount;
|
||||
|
||||
private final EffectSourcePanel pnlSource;
|
||||
private final TargetsPanel pnlTargets;
|
||||
|
||||
private final List<AssignTarget> targetsList = new ArrayList<>();
|
||||
private final Map<GameEntityView, AssignTarget> targetsMap = new HashMap<>();
|
||||
|
||||
/** Constructor.
|
||||
*
|
||||
* @param attacker0 {@link forge.game.card.Card}
|
||||
* @param targets Map<GameEntity, Integer>, map of GameEntity and its maximum assignable amount
|
||||
* @param amount Total amount to be assigned
|
||||
* @param atLeastOne Must assign at least one amount to each target
|
||||
*/
|
||||
public VAssignGenericAmount(final CardView effectSource, final Map<GameEntityView, Integer> targets, final int amount, final boolean atLeastOne, final String amountLabel, final WaitCallback<Map<GameEntityView, Integer>> waitCallback) {
|
||||
super(Localizer.getInstance().getMessage("lbLAssignAmountForEffect", amountLabel, CardTranslation.getTranslatedName(effectSource.getName())) , 2);
|
||||
|
||||
callback = waitCallback;
|
||||
totalAmountToAssign = amount;
|
||||
|
||||
lblAmount = amountLabel;
|
||||
lblTotalAmount = add(new FLabel.Builder().text(Localizer.getInstance().getMessage("lblTotalAmountText", lblAmount)).align(Align.center).build());
|
||||
|
||||
pnlSource = add(new EffectSourcePanel(effectSource));
|
||||
pnlTargets = add(new TargetsPanel(targets));
|
||||
|
||||
initButton(0, Localizer.getInstance().getMessage("lblOK"), new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
initButton(1, Localizer.getInstance().getMessage("lblReset"), new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
resetAssignedDamage();
|
||||
initialAssignAmount(atLeastOne);
|
||||
}
|
||||
});
|
||||
|
||||
initialAssignAmount(atLeastOne);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float layoutAndGetHeight(float width, float maxHeight) {
|
||||
float padding = FOptionPane.PADDING;
|
||||
float w = width - 2 * padding;
|
||||
|
||||
float x = padding;
|
||||
float labelHeight = lblTotalAmount.getAutoSizeBounds().height;
|
||||
float y = maxHeight - labelHeight + padding;
|
||||
|
||||
float dtOffset = ADD_BTN_HEIGHT + targetsList.get(0).label.getAutoSizeBounds().height;
|
||||
float cardPanelHeight = (y - dtOffset - labelHeight - 3 * padding) / 2;
|
||||
float cardPanelWidth = cardPanelHeight / FCardPanel.ASPECT_RATIO;
|
||||
|
||||
y = padding;
|
||||
pnlSource.setBounds(x + (w - cardPanelWidth) / 2, y, cardPanelWidth, cardPanelHeight);
|
||||
|
||||
y += cardPanelHeight + padding;
|
||||
lblTotalAmount.setBounds(x, y, w, labelHeight);
|
||||
|
||||
y += labelHeight + padding;
|
||||
pnlTargets.setBounds(0, y, width, cardPanelHeight + dtOffset);
|
||||
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
private class TargetsPanel extends FScrollPane {
|
||||
private TargetsPanel(final Map<GameEntityView, Integer> targets) {
|
||||
for (final Map.Entry<GameEntityView, Integer> e : targets.entrySet()) {
|
||||
addDamageTarget(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void addDamageTarget(GameEntityView entity, int max) {
|
||||
AssignTarget at = add(new AssignTarget(entity, max));
|
||||
targetsMap.put(entity, at);
|
||||
targetsList.add(at);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
|
||||
float cardPanelHeight = visibleHeight - ADD_BTN_HEIGHT - targetsList.get(0).label.getAutoSizeBounds().height;
|
||||
float width = cardPanelHeight / FCardPanel.ASPECT_RATIO;
|
||||
float dx = width + CARD_GAP_X;
|
||||
|
||||
float x = (visibleWidth - targetsList.size() * dx + CARD_GAP_X) / 2;
|
||||
if (x < FOptionPane.PADDING) {
|
||||
x = FOptionPane.PADDING;
|
||||
}
|
||||
|
||||
for (AssignTarget at : targetsList) {
|
||||
at.setBounds(x, 0, width, visibleHeight);
|
||||
x += dx;
|
||||
}
|
||||
return new ScrollBounds(x - CARD_GAP_X + FOptionPane.PADDING, visibleHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private class AssignTarget extends FContainer {
|
||||
private final GameEntityView entity;
|
||||
private final FDisplayObject obj;
|
||||
private final FLabel label, btnSubtract, btnAdd;
|
||||
private final int max;
|
||||
private int amount;
|
||||
|
||||
public AssignTarget(GameEntityView entity0, int max0) {
|
||||
entity = entity0;
|
||||
max = max0;
|
||||
if (entity instanceof CardView) {
|
||||
obj = add(new EffectSourcePanel((CardView)entity));
|
||||
}
|
||||
else if (entity instanceof PlayerView) {
|
||||
PlayerView player = (PlayerView)entity;
|
||||
obj = add(new MiscTargetPanel(player.getName(), MatchController.getPlayerAvatar(player)));
|
||||
}
|
||||
else {
|
||||
obj = add(new MiscTargetPanel(entity.toString(), FSkinImage.UNKNOWN));
|
||||
}
|
||||
label = add(new FLabel.Builder().text("0").font(FSkinFont.get(18)).align(Align.center).build());
|
||||
btnSubtract = add(new FLabel.ButtonBuilder().icon(FSkinImage.MINUS).command(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
assignAmountTo(entity, false);
|
||||
}
|
||||
}).build());
|
||||
btnAdd = add(new FLabel.ButtonBuilder().icon(Forge.hdbuttons ? FSkinImage.HDPLUS : FSkinImage.PLUS).command(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
assignAmountTo(entity, true);
|
||||
}
|
||||
}).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
float y = 0;
|
||||
obj.setBounds(0, y, width, FCardPanel.ASPECT_RATIO * width);
|
||||
y += obj.getHeight();
|
||||
|
||||
label.setBounds(0, y, width, label.getAutoSizeBounds().height);
|
||||
y += label.getHeight();
|
||||
|
||||
float buttonSize = (width - FOptionPane.PADDING) / 2;
|
||||
btnSubtract.setBounds(0, y, buttonSize, ADD_BTN_HEIGHT);
|
||||
btnAdd.setBounds(width - buttonSize, y, buttonSize, ADD_BTN_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
private static class EffectSourcePanel extends FCardPanel {
|
||||
private EffectSourcePanel(CardView card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
CardZoom.show(getCard());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(float x, float y) {
|
||||
CardZoom.show(getCard());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getPadding() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MiscTargetPanel extends FDisplayObject {
|
||||
private static final FSkinFont FONT = FSkinFont.get(18);
|
||||
private static final FSkinColor FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT);
|
||||
private final String name;
|
||||
private final FImage image;
|
||||
|
||||
private MiscTargetPanel(String name0, FImage image0) {
|
||||
name = name0;
|
||||
image = image0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
float w = getWidth();
|
||||
float h = getHeight();
|
||||
g.drawImage(image, 0, 0, w, w);
|
||||
g.drawText(name, FONT, FORE_COLOR, 0, w, w, h - w, false, Align.center, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void assignAmountTo(GameEntityView source, boolean isAdding) {
|
||||
AssignTarget at = targetsMap.get(source);
|
||||
int assigned = at.amount;
|
||||
int leftToAssign = Math.max(0, at.max - assigned);
|
||||
int amountToAdd = isAdding ? 1 : -1;
|
||||
int remainingAmount = Math.min(getRemainingAmount(), leftToAssign);
|
||||
|
||||
if (amountToAdd > remainingAmount) {
|
||||
amountToAdd = remainingAmount;
|
||||
}
|
||||
|
||||
if (0 == amountToAdd || amountToAdd + assigned < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
addAssignedAmount(at, amountToAdd);
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
private void initialAssignAmount(boolean atLeastOne) {
|
||||
if (!atLeastOne) {
|
||||
updateLabels();
|
||||
return;
|
||||
}
|
||||
|
||||
for(AssignTarget at : targetsList) {
|
||||
addAssignedAmount(at, 1);
|
||||
}
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
private void resetAssignedDamage() {
|
||||
for (AssignTarget at : targetsList) {
|
||||
at.amount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void addAssignedAmount(final AssignTarget at, int addedAmount) {
|
||||
// If we don't have enough left or we're trying to unassign too much return
|
||||
int canAssign = getRemainingAmount();
|
||||
if (canAssign < addedAmount) {
|
||||
addedAmount = canAssign;
|
||||
}
|
||||
|
||||
at.amount = Math.max(0, addedAmount + at.amount);
|
||||
}
|
||||
|
||||
private int getRemainingAmount() {
|
||||
int spent = 0;
|
||||
for (AssignTarget at : targetsList) {
|
||||
spent += at.amount;
|
||||
}
|
||||
return totalAmountToAssign - spent;
|
||||
}
|
||||
|
||||
/** Updates labels and other UI elements.*/
|
||||
private void updateLabels() {
|
||||
int amountLeft = totalAmountToAssign;
|
||||
|
||||
for (AssignTarget at : targetsList) {
|
||||
amountLeft -= at.amount;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(at.amount);
|
||||
if (at.max - at.amount == 0) {
|
||||
sb.append(" (").append(Localizer.getInstance().getMessage("lblMax")).append(")");
|
||||
}
|
||||
at.label.setText(sb.toString());
|
||||
}
|
||||
|
||||
lblTotalAmount.setText(TextUtil.concatNoSpace(Localizer.getInstance().getMessage("lblAvailableAmount", lblAmount) + ": ",
|
||||
String.valueOf(amountLeft), " (of ", String.valueOf(totalAmountToAssign), ")"));
|
||||
setButtonEnabled(0, amountLeft == 0);
|
||||
}
|
||||
|
||||
// Dumps damage onto cards. Damage must be stored first, because if it is
|
||||
// assigned dynamically, the cards die off and further damage to them can't
|
||||
// be modified.
|
||||
private void finish() {
|
||||
if (getRemainingAmount() > 0) {
|
||||
return;
|
||||
}
|
||||
hide();
|
||||
callback.run(getAssignedMap());
|
||||
}
|
||||
|
||||
public Map<GameEntityView, Integer> getAssignedMap() {
|
||||
Map<GameEntityView, Integer> result = new HashMap<>(targetsList.size());
|
||||
for (AssignTarget at : targetsList)
|
||||
result.put(at.entity, at.amount);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
13
forge-gui/res/cardsfolder/d/divine_deflection.txt
Normal file
13
forge-gui/res/cardsfolder/d/divine_deflection.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Name:Divine Deflection
|
||||
ManaCost:X W
|
||||
Types:Instant
|
||||
A:SP$ StoreSVar | Cost$ X W | SVar$ ShieldAmount | Type$ Calculate | Expression$ X | SubAbility$ DBEffect | StackDescription$ SpellDescription | SpellDescription$ Prevent the next X damage that would be dealt to you and/or permanents you control this turn. If damage is prevented this way, CARDNAME deals that much damage to any target.
|
||||
SVar:DBEffect:DB$ Effect | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target to deal prevented damage to | ReplacementEffects$ ReDamage | RememberObjects$ Targeted
|
||||
SVar:ReDamage:Event$ DamageDone | ActiveZones$ Command | ValidTarget$ You,Permanent.YouCtrl | ReplaceWith$ PreventDamage | PreventionEffect$ NextN | Description$ Prevent the next X damage that would be dealt to you and/or permanents you control this turn. If damage is prevented this way, EFFECTSOURCE deals that much damage to any target.
|
||||
SVar:PreventDamage:DB$ ReplaceDamage | Amount$ ShieldAmount | DivideShield$ True | SubAbility$ DBDealDamage
|
||||
SVar:DBDealDamage:DB$ DealDamage | NumDmg$ Y | Defined$ Remembered | DamageSource$ EffectSource
|
||||
SVar:X:Count$xPaid
|
||||
SVar:ShieldAmount:Number$0
|
||||
SVar:Y:ReplaceCount$DamageAmount
|
||||
AI:RemoveDeck:All
|
||||
Oracle:Prevent the next X damage that would be dealt to you and/or permanents you control this turn. If damage is prevented this way, Divine Deflection deals that much damage to any target.
|
||||
11
forge-gui/res/cardsfolder/h/harms_way.txt
Normal file
11
forge-gui/res/cardsfolder/h/harms_way.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
Name:Harm's Way
|
||||
ManaCost:W
|
||||
Types:Instant
|
||||
A:SP$ ChooseSource | Cost$ W | Choices$ Card,Emblem | AILogic$ NeedsPrevention | SubAbility$ DBEffect | StackDescription$ SpellDescription | SpellDescription$ The next 2 damage that a source of your choice would deal to you and/or permanents you control this turn is dealt to any target instead.
|
||||
SVar:DBEffect:DB$ Effect | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target to redirect damage to | ReplacementEffects$ ReDamage | RememberObjects$ Targeted | SubAbility$ DBCleanup
|
||||
SVar:ReDamage:Event$ DamageDone | ActiveZones$ Command | ValidTarget$ You,Permanent.YouCtrl | ValidSource$ Card.ChosenCard,Emblem.ChosenCard | ReplaceWith$ SplitDamage | DamageTarget$ Remembered | Description$ The next 2 damage that a source of your choice would deal to you and/or permanents you control this turn is dealt to any target instead.
|
||||
SVar:SplitDamage:DB$ ReplaceSplitDamage | DamageTarget$ Remembered | VarName$ ShieldAmount | DivideShield$ True
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True
|
||||
SVar:ShieldAmount:Number$2
|
||||
AI:RemoveDeck:All
|
||||
Oracle:The next 2 damage that a source of your choice would deal to you and/or permanents you control this turn is dealt to any target instead.
|
||||
15
forge-gui/res/cardsfolder/r/refraction_trap.txt
Normal file
15
forge-gui/res/cardsfolder/r/refraction_trap.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
Name:Refraction Trap
|
||||
ManaCost:3 W
|
||||
Types:Instant Trap
|
||||
SVar:AltCost:Cost$ W | CheckSVar$ X | SVarCompare$ GE1 | Description$ If an opponent cast a red instant or sorcery spell this turn, you may pay {W} rather than pay this spell's mana cost.
|
||||
A:SP$ ChooseSource | Cost$ 3 W | Choices$ Card,Emblem | AILogic$ NeedsPrevention | SubAbility$ DBEffect | StackDescription$ SpellDescription | SpellDescription$ Prevent the next 3 damage that a source of your choice would deal to you and/or permanents you control this turn. If damage is prevented this way, CARDNAME deals that much damage to any target.
|
||||
SVar:DBEffect:DB$ Effect | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target to deal prevented damage to | ReplacementEffects$ ReDamage | RememberObjects$ Targeted | SubAbility$ DBCleanup
|
||||
SVar:ReDamage:Event$ DamageDone | ActiveZones$ Command | ValidTarget$ You,Permanent.YouCtrl | ValidSource$ Card.ChosenCard,Emblem.ChosenCard | ReplaceWith$ PreventDamage | PreventionEffect$ NextN | Description$ Prevent the next 3 damage that a source of your choice would deal to you and/or permanents you control this turn. If damage is prevented this way, EFFECTSOURCE deals that much damage to any target.
|
||||
SVar:PreventDamage:DB$ ReplaceDamage | Amount$ ShieldAmount | DivideShield$ True | SubAbility$ DBDealDamage
|
||||
SVar:DBDealDamage:DB$ DealDamage | NumDmg$ Y | Defined$ Remembered | DamageSource$ EffectSource
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True
|
||||
SVar:X:Count$ThisTurnCast_Instant.Red+OppCtrl,Sorcery.Red+OppCtrl
|
||||
SVar:ShieldAmount:Number$3
|
||||
SVar:Y:ReplaceCount$DamageAmount
|
||||
AI:RemoveDeck:All
|
||||
Oracle:If an opponent cast a red instant or sorcery spell this turn, you may pay {W} rather than pay this spell's mana cost.\nPrevent the next 3 damage that a source of your choice would deal to you and/or permanents you control this turn. If damage is prevented this way, Refraction Trap deals that much damage to any target.
|
||||
16
forge-gui/res/cardsfolder/s/shining_shoal.txt
Normal file
16
forge-gui/res/cardsfolder/s/shining_shoal.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
Name:Shining Shoal
|
||||
ManaCost:X W W
|
||||
Types:Instant Arcane
|
||||
SVar:AltCost:Cost$ ExileFromHand<1/Card.White+Other/white card> | Description$ You may exile a white card with mana value X from your hand rather than pay this spell's mana cost.
|
||||
A:SP$ ChooseSource | Cost$ X W W | Choices$ Card,Emblem | AILogic$ NeedsPrevention | SubAbility$ DBStoreSVar | StackDescription$ SpellDescription | SpellDescription$ The next X damage that a source of your choice would deal to you and/or creatures you control this turn is dealt to any target instead.
|
||||
SVar:DBStoreSVar:DB$ StoreSVar | SVar$ ShieldAmount | Type$ Calculate | Expression$ Z | SubAbility$ DBEffect
|
||||
SVar:DBEffect:DB$ Effect | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target to redirect damage to | ReplacementEffects$ ReDamage | RememberObjects$ Targeted | SubAbility$ DBCleanup
|
||||
SVar:ReDamage:Event$ DamageDone | ActiveZones$ Command | ValidTarget$ You,Creature.YouCtrl | ValidSource$ Card.ChosenCard,Emblem.ChosenCard | ReplaceWith$ SplitDamage | DamageTarget$ Remembered | Description$ The next X damage that a source of your choice would deal to you and/or creatures you control this turn is dealt to any target instead.
|
||||
SVar:SplitDamage:DB$ ReplaceSplitDamage | DamageTarget$ Remembered | VarName$ ShieldAmount | DivideShield$ True
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True
|
||||
SVar:X:Count$xPaid
|
||||
SVar:Y:Exiled$CardManaCost
|
||||
SVar:Z:SVar$Y/Plus.X
|
||||
SVar:ShieldAmount:Number$0
|
||||
AI:RemoveDeck:All
|
||||
Oracle:You may exile a white card with mana value X from your hand rather than pay this spell's mana cost.\nThe next X damage that a source of your choice would deal to you and/or creatures you control this turn is dealt to any target instead.
|
||||
@@ -361,6 +361,15 @@ lblTotalDamageText=Gesamtschaden: Unbekannt
|
||||
lblAssignRemainingText=Verteile verbleibenden Schaden unter tödlich Verwundeten
|
||||
lblLethal=Tödlich
|
||||
lblAvailableDamagePoints=Verfügbare Schadenspunkte
|
||||
#VAssignGenericAmount.java
|
||||
# The {0} below should be amount label (like "shield" or "damage"), and {1} will be the name of the effect source
|
||||
lbLAssignAmountForEffect=Assign {0} by {1}
|
||||
lblLClickAmountMessage=Left click: Assign 1 {0}. (Left Click + Control): Assign maximum {0} points
|
||||
lblRClickAmountMessage=Right click: Unassign 1 {0}. (Right Click + Control): Unassign all {0} points.
|
||||
lblTotalAmountText=Available {0} points: Unknown
|
||||
lblAvailableAmount=Available {0} points
|
||||
lblMax=Max
|
||||
lblShield=shield
|
||||
#KeyboardShortcuts.java
|
||||
lblSHORTCUT_SHOWSTACK=Duell: Zeige Stapelfenster
|
||||
lblSHORTCUT_SHOWCOMBAT=Duell: Zeige Kampffenster
|
||||
@@ -416,7 +425,7 @@ lblSelectOpponentDeck=Wähle das Deck des Gegners
|
||||
lblGenerateNewDeck=Erzeuge ein neues Deck
|
||||
lblRandomTheme=Zufälliges Deck
|
||||
lblTestDeck=Teste Deck
|
||||
lblLoading=Lade
|
||||
lblLoading=Lade
|
||||
#GameType.java
|
||||
lblSealed=Sealed
|
||||
lblDraft=Draft
|
||||
@@ -1131,7 +1140,7 @@ lblSwipeUpTo=Wische hoch für %s
|
||||
lblSwipeDownDetailView=Wische runter für Detailansicht
|
||||
lblSwipeDownPictureView=Wische runter für Bildansicht
|
||||
#VGameMenu.java
|
||||
lblShowWinLoseOverlay=Zeige Sieg/Verlust-Anzeige
|
||||
lblShowWinLoseOverlay=Zeige Sieg/Verlust-Anzeige
|
||||
lblNoPlayerPriorityNoDeckListViewed=Kein Spieler hat Priorität, daher keine Decklistenanzeige möglich.
|
||||
#FilesPage.java
|
||||
lblFiles=Dateien
|
||||
@@ -2276,7 +2285,7 @@ lblConquestName=Eroberung-Name
|
||||
#HumanCostDecision.java
|
||||
lblChooseXValueForCard={0} - Wähle Wert für X
|
||||
lblSelectOneSameNameCardToDiscardAlreadyChosen=Wähle eine Karte mit dem gleichen Namen zum Abwerfen. Bereits gewählt:
|
||||
lblSelectOneDifferentNameCardToDiscardAlreadyChosen=Wähle eine Karte mit einem anderen Namen zum Abwerfen. Bereits gewählt:
|
||||
lblSelectOneDifferentNameCardToDiscardAlreadyChosen=Wähle eine Karte mit einem anderen Namen zum Abwerfen. Bereits gewählt:
|
||||
lblSelectNMoreTargetTypeCardToDiscard=Wähle {0} weitere {1} zum Abwerfen.
|
||||
lblDoYouWantCardDealNDamageToYou=Möchtest du, daß {0} dir {1} Schaden zufügt?
|
||||
lblDrawNCardsConfirm=Ziehe {0} Karte(n)?
|
||||
@@ -2672,7 +2681,7 @@ lblDetectedInvalidHostAddress=Ungültige Host-Adresse ({0}) wurde festgestellt.
|
||||
#Player.java
|
||||
lblChooseACompanion=Wähle einen Gefährten
|
||||
lblChooseAColorFor=Wähle eine Farbe für {0}
|
||||
lblRevealFaceDownCards=Enthülle verdeckte Karten von
|
||||
lblRevealFaceDownCards=Enthülle verdeckte Karten von
|
||||
lblLearnALesson=Lerne eine Lektion
|
||||
#QuestPreferences.java
|
||||
lblWildOpponentNumberError=Anzahl der Wild-Gegner kann nur 0 bis 3 sein
|
||||
|
||||
@@ -18,8 +18,8 @@ lblerrLoadingLayoutFile=Your %s layout file could not be read. It will be delete
|
||||
lblLoadingQuest=Loading quest...
|
||||
#FScreen.java
|
||||
#translate lblHomeWithSpaces,lblDeckEditorWithSpaces need keep spaces in text
|
||||
lblHomeWithSpaces=Home
|
||||
lblDeckEditorWithSpaces=Deck Editor
|
||||
lblHomeWithSpaces=Home
|
||||
lblDeckEditorWithSpaces=Deck Editor
|
||||
lblWorkshop=Workshop
|
||||
lblBacktoHome=Back to Home
|
||||
lblCloseEditor=Close Editor
|
||||
@@ -52,7 +52,7 @@ btnResetJavaFutureCompatibilityWarnings=Reset Java Compatibility Warnings
|
||||
btnClearImageCache=Clear Image Cache
|
||||
btnTokenPreviewer=Token Previewer
|
||||
btnCopyToClipboard=Copy to Clipboard
|
||||
cbpAutoUpdater=Auto updater
|
||||
cbpAutoUpdater=Auto updater
|
||||
nlAutoUpdater=Select the release channel to use for updating Forge
|
||||
cbpSelectLanguage=Language
|
||||
nlSelectLanguage=Select Language (Excluded Game part. Still a work in progress) (RESTART REQUIRED)
|
||||
@@ -361,6 +361,15 @@ lblTotalDamageText=Available damage points: Unknown
|
||||
lblAssignRemainingText=Distribute the remaining damage points among lethally wounded entities
|
||||
lblLethal=Lethal
|
||||
lblAvailableDamagePoints=Available damage points
|
||||
#VAssignGenericAmount.java
|
||||
# The {0} below should be amount label (like "shield" or "damage"), and {1} will be the name of the effect source
|
||||
lbLAssignAmountForEffect=Assign {0} by {1}
|
||||
lblLClickAmountMessage=Left click: Assign 1 {0}. (Left Click + Control): Assign maximum {0} points
|
||||
lblRClickAmountMessage=Right click: Unassign 1 {0}. (Right Click + Control): Unassign all {0} points.
|
||||
lblTotalAmountText=Available {0} points: Unknown
|
||||
lblAvailableAmount=Available {0} points
|
||||
lblMax=Max
|
||||
lblShield=shield
|
||||
#KeyboardShortcuts.java
|
||||
lblSHORTCUT_SHOWSTACK=Match: show stack panel
|
||||
lblSHORTCUT_SHOWCOMBAT=Match: show combat panel
|
||||
@@ -416,7 +425,7 @@ lblSelectOpponentDeck=Select Opponent''s Deck
|
||||
lblGenerateNewDeck=Generate New Deck
|
||||
lblRandomTheme=Random Theme
|
||||
lblTestDeck=Test Deck
|
||||
lblLoading=Loading
|
||||
lblLoading=Loading
|
||||
#GameType.java
|
||||
lblSealed=Sealed
|
||||
lblDraft=Draft
|
||||
@@ -763,8 +772,8 @@ lblWinsperDraftRotation=Wins per Draft Rotation
|
||||
ttWinsperDraftRotation=If a Draft is not played for this many match wins, it will be removed or replaced.
|
||||
lblRotationType=Rotation Type
|
||||
ttRotationType=If set to 0, old drafts disappear, if set to 1, they are replaced with another one using different sets.
|
||||
lblWildOpponentNumber=Number of Wild Opponents
|
||||
lblWildOpponentMultiplier=Wild Multiplier
|
||||
lblWildOpponentNumber=Number of Wild Opponents
|
||||
lblWildOpponentMultiplier=Wild Multiplier
|
||||
#StatTypeFilter.java
|
||||
lblclicktotoogle=click to toggle the filter, right-click to show only
|
||||
#SItemManagerUtil.java
|
||||
@@ -1193,7 +1202,7 @@ lblSelectAttackTarget= or select player/planeswalker you wish to attack.
|
||||
lblSelectBandingTarget= To attack as a band, select an attacking creature to activate its ''band'' then select another to join it.
|
||||
#InputBlock.java
|
||||
lblSelectBlockTarget=Select another attacker to declare blockers for.
|
||||
lblSelectBlocker=Select creatures to block
|
||||
lblSelectBlocker=Select creatures to block
|
||||
lblOrSelectBlockTarget= or select another attacker to declare blockers for.
|
||||
lblMorph=Morph
|
||||
#PlayerControllerHuman.java
|
||||
@@ -1569,9 +1578,9 @@ lblCreature=Creature
|
||||
btnRestartRound=Restart Round
|
||||
btnTournamentInfo=Tournament Info
|
||||
btnNextRound=Next Round
|
||||
btnWonRound=YOU HAVE WON ROUND
|
||||
btnWonRound=YOU HAVE WON ROUND
|
||||
btnWonTournament=***CONGRATULATIONS! YOU HAVE WON THE TOURNAMENT!***
|
||||
btnLoseRound=YOU HAVE LOST ON ROUND
|
||||
btnLoseRound=YOU HAVE LOST ON ROUND
|
||||
btnQuit=Quit
|
||||
btnContinue=Continue
|
||||
btnRestart=Restart
|
||||
@@ -1588,8 +1597,8 @@ lblFailedGauntlet=You have failed to pass the gauntlet.
|
||||
lblLeaveTournamentDraftWarning1=If you leave now, this tournament will be forever gone.\nYou will keep the cards you drafted, but will receive no other prizes.\n\nWould you still like to quit the tournament?
|
||||
lblLeaveTournamentDraftWarning2=You have matches left to play!\nLeaving the tournament early will forfeit your potential future winnings.\nYou will still receive winnings as if you conceded your next match and you will keep the cards you drafted.\n\nWould you still like to quit the tournament?
|
||||
lblReallyQuit=Really Quit?
|
||||
lblForPlacing=For placing
|
||||
lblHaveBeAward=, you have been awarded
|
||||
lblForPlacing=For placing
|
||||
lblHaveBeAward=, you have been awarded
|
||||
lblTournamentReward=Tournament Reward
|
||||
lblParticipateingTournamentReward=For participating in the tournament, you have been awarded the following promotional card:
|
||||
lblCreditsAwarded=Credits Awarded
|
||||
@@ -1608,22 +1617,22 @@ lblWouldLikeSaveDraft=Would you like to save this draft to the regular draft mod
|
||||
lblSaveDraft=Save Draft
|
||||
lblNoAvailableDraftsMessage=You do not have any draft-able sets unlocked!\nCome back later when you''ve unlocked more sets.
|
||||
lblNoAvailableDrafts=No Available Drafts
|
||||
lblEntryFeeOfDraftTournament=The entry fee for this booster draft tournament is
|
||||
lblEntryFeeOfDraftTournament=The entry fee for this booster draft tournament is
|
||||
lblWouldLikeCreateTournament= credits.\nWould you like to spend a token and create this tournament?
|
||||
lblCreatingDraftTournament=Creating a Booster Draft Tournament
|
||||
lblUnexpectedCreatingDraftTournament=Unexpected error when creating a draft tournament
|
||||
lblUnexpectedCreatingDraftTournament=Unexpected error when creating a draft tournament
|
||||
lblPleaseReportBug=. Please report this as a bug.
|
||||
lbl1stPlace=1st Place:
|
||||
lbl2ndPlace=2nd Place:
|
||||
lbl3rdPlace=3rd Place:
|
||||
lbl4thPlace=4th Place:
|
||||
lbl1stPlace=1st Place:
|
||||
lbl2ndPlace=2nd Place:
|
||||
lbl3rdPlace=3rd Place:
|
||||
lbl4thPlace=4th Place:
|
||||
lblTime= time
|
||||
lblCollectPrizes=Collect Prizes
|
||||
lblCurrentlyInDraft=You are currently in a draft.\nYou should leave or finish that draft before starting another.
|
||||
lblYouNeed=You need
|
||||
lblYouNeed=You need
|
||||
lblMoreCredits=more credits to enter this tournament.
|
||||
lblNotEnoughCredits=Not Enough Credits
|
||||
lblTournamentCosts=This tournament costs
|
||||
lblTournamentCosts=This tournament costs
|
||||
lblSureEnterTournament= credits to enter.\nAre you sure you wish to enter?
|
||||
lblEnterDraftTournament=Enter Draft Tournament?
|
||||
lblLeaveDraftConfirm=This will end the current draft and you will not be able to join this tournament again.\nYour credits will be refunded and the draft will be removed.\n\nLeave anyway?
|
||||
@@ -1683,7 +1692,7 @@ lblWinsForRankIncrease=Wins For Rank Increase
|
||||
lblWinsForMediumAI=Wins For Medium AI
|
||||
lblWinsForHardAI=Wins For Hard AI
|
||||
lblWinsForExpertAI=Wins For Expert AI
|
||||
lblSaveFailed=Save Failed -
|
||||
lblSaveFailed=Save Failed -
|
||||
#QuestSpellShopScreen.java
|
||||
lblMaximumSellingCredits=Maximum selling price is %d credits.
|
||||
lblSellCardsAt=Selling cards at
|
||||
@@ -2274,8 +2283,8 @@ lblHistoriiansWillRecallYourConquestAs=Historians will recall your conquest as:
|
||||
lblConquestName=Conquest Name
|
||||
#HumanCostDecision.java
|
||||
lblChooseXValueForCard={0} - Choose a Value for X
|
||||
lblSelectOneSameNameCardToDiscardAlreadyChosen=Select one of the cards with the same name to discard. Already chosen:
|
||||
lblSelectOneDifferentNameCardToDiscardAlreadyChosen=Select one of the cards with a different name to discard. Already chosen:
|
||||
lblSelectOneSameNameCardToDiscardAlreadyChosen=Select one of the cards with the same name to discard. Already chosen:
|
||||
lblSelectOneDifferentNameCardToDiscardAlreadyChosen=Select one of the cards with a different name to discard. Already chosen:
|
||||
lblSelectNMoreTargetTypeCardToDiscard=Select {0} more {1} to discard.
|
||||
lblDoYouWantCardDealNDamageToYou=Do you want {0} to deal {1} damage to you?
|
||||
lblDrawNCardsConfirm=Draw {0} Card(s)?
|
||||
@@ -2312,7 +2321,7 @@ lblRemoveNTargetCounterFromCardPayCostConfirm=Pay Cost: Remove {0} {1} counter f
|
||||
lblRemoveCountersFromAInZoneCard=Remove counter(s) from a card in {0}
|
||||
lblSacrificeCardConfirm=Sacrifice {0}?
|
||||
lblSelectATargetToSacrifice=Select a {0} to sacrifice ({1} left)
|
||||
lblSelectOneOfCardsToTapAlreadyChosen=Select one of the cards to tap. Already chosen:
|
||||
lblSelectOneOfCardsToTapAlreadyChosen=Select one of the cards to tap. Already chosen:
|
||||
lblSelectACreatureToTap=Select a creature to tap.
|
||||
lblEnoughValidCardNotToPayTheCost=Not enough valid cards left to tap to pay the cost.
|
||||
lblCostPaymentInvalid=Cost payment invalid
|
||||
@@ -2671,7 +2680,7 @@ lblDetectedInvalidHostAddress=Invalid host address ({0}) was detected.
|
||||
#Player.java
|
||||
lblChooseACompanion=Choose a companion
|
||||
lblChooseAColorFor=Choose a color for {0}
|
||||
lblRevealFaceDownCards=Revealing face-down cards from
|
||||
lblRevealFaceDownCards=Revealing face-down cards from
|
||||
lblLearnALesson=Learn a Lesson
|
||||
#QuestPreferences.java
|
||||
lblWildOpponentNumberError=Wild Opponents can only be 0 to 3
|
||||
|
||||
@@ -18,8 +18,8 @@ lblerrLoadingLayoutFile=No se pudo leer el archivo de diseño %s. Se eliminará
|
||||
lblLoadingQuest=Cargando datos de aventura....
|
||||
#FScreen.java
|
||||
#translate lblHomeWithSpaces,lblDeckEditorWithSpaces need keep spaces in text
|
||||
lblHomeWithSpaces=Inicio
|
||||
lblDeckEditorWithSpaces=Editor de mazos
|
||||
lblHomeWithSpaces=Inicio
|
||||
lblDeckEditorWithSpaces=Editor de mazos
|
||||
lblWorkshop=Taller
|
||||
lblBacktoHome=Volver a Inicio
|
||||
lblCloseEditor=Cerrar editor
|
||||
@@ -361,6 +361,15 @@ lblTotalDamageText=Puntos de daño disponibles: Desconocido
|
||||
lblAssignRemainingText=Distribuye los puntos de daño restantes entre las entidades letalmente heridas.
|
||||
lblLethal=Letal
|
||||
lblAvailableDamagePoints=Puntos de daño disponibles
|
||||
#VAssignGenericAmount.java
|
||||
# The {0} below should be amount label (like "shield" or "damage"), and {1} will be the name of the effect source
|
||||
lbLAssignAmountForEffect=Assign {0} by {1}
|
||||
lblLClickAmountMessage=Left click: Assign 1 {0}. (Left Click + Control): Assign maximum {0} points
|
||||
lblRClickAmountMessage=Right click: Unassign 1 {0}. (Right Click + Control): Unassign all {0} points.
|
||||
lblTotalAmountText=Available {0} points: Unknown
|
||||
lblAvailableAmount=Available {0} points
|
||||
lblMax=Max
|
||||
lblShield=shield
|
||||
#KeyboardShortcuts.java
|
||||
lblSHORTCUT_SHOWSTACK=Partida: mostrar panel de pila
|
||||
lblSHORTCUT_SHOWCOMBAT=Partida: mostrar panel de combate
|
||||
@@ -416,7 +425,7 @@ lblSelectOpponentDeck=Seleccionar mazo del oponente
|
||||
lblGenerateNewDeck=Generar nuevo mazo
|
||||
lblRandomTheme=Tema aleatorio
|
||||
lblTestDeck=Probar mazo
|
||||
lblLoading=Cargando
|
||||
lblLoading=Cargando
|
||||
#GameType.java
|
||||
lblSealed=Sellado
|
||||
lblDraft=Draft
|
||||
@@ -763,8 +772,8 @@ lblWinsperDraftRotation=Victorias rotación de Draft
|
||||
ttWinsperDraftRotation=Si no se juega un Draft para esta cantidad de victorias, se eliminará o reemplazará.
|
||||
lblRotationType=Tipo de rotación
|
||||
ttRotationType=Si se establece en 0, los anteriores Draft desaparecen, si se establece en 1, se reemplazan por otros que utilizan sets diferentes.
|
||||
lblWildOpponentNumber=Número de oponentes salvajes
|
||||
lblWildOpponentMultiplier=Multiplicador salvaje
|
||||
lblWildOpponentNumber=Número de oponentes salvajes
|
||||
lblWildOpponentMultiplier=Multiplicador salvaje
|
||||
#StatTypeFilter.java
|
||||
lblclicktotoogle=haz clic para alternar el filtro, haz clic con el botón derecho para solo mostrar
|
||||
#SItemManagerUtil.java
|
||||
@@ -1569,9 +1578,9 @@ lblCreature=Criatura
|
||||
btnRestartRound=Reiniciar ronda
|
||||
btnTournamentInfo=Info del torneo
|
||||
btnNextRound=Siguiente ronda
|
||||
btnWonRound=HAS GANADO LA RONDA
|
||||
btnWonRound=HAS GANADO LA RONDA
|
||||
btnWonTournament=***¡FELICIDADES! ¡HAS GANADO EL TORNEO!***
|
||||
btnLoseRound=HAS PERDIDO EN LA RONDA
|
||||
btnLoseRound=HAS PERDIDO EN LA RONDA
|
||||
btnQuit=Salir
|
||||
btnContinue=Continuar
|
||||
btnRestart=Reiniciar
|
||||
@@ -1588,8 +1597,8 @@ lblFailedGauntlet=No has podido superar el desafío.
|
||||
lblLeaveTournamentDraftWarning1=Si te retiras ahora, este torneo se acabará para siempre.\nConservarás las cartas que has sacado, pero no recibirás ningún otro premio.\n\n¿Sigues queriendo dejar el torneo?
|
||||
lblLeaveTournamentDraftWarning2=¡Te quedan partidas por jugar!\nSi dejas el torneo antes de tiempo, perderás tus potenciales ganancias futuras.\nSeguirás recibiendo ganancias como si te hubieras rendido en tu próxima partida y te quedarás con las cartas que has sacado.\n\n¿Sigues queriendo dejar el torneo?
|
||||
lblReallyQuit=¿Realmente quieres abandonar?
|
||||
lblForPlacing=Para colocar
|
||||
lblHaveBeAward=, has sido premiado
|
||||
lblForPlacing=Para colocar
|
||||
lblHaveBeAward=, has sido premiado
|
||||
lblTournamentReward=Recompensa del Torneo
|
||||
lblParticipateingTournamentReward=Por participar en el torneo, se le ha premiado con la siguiente carta promocional:
|
||||
lblCreditsAwarded=Créditos ganados
|
||||
@@ -1608,22 +1617,22 @@ lblWouldLikeSaveDraft=¿Te gustaría guardar este Draft en el modo de draft norm
|
||||
lblSaveDraft=Guardar Draft
|
||||
lblNoAvailableDraftsMessage=¡No tienes ningún set de draft desbloqueado!\nVuelve más tarde cuando hayas desbloqueado más ediciones.
|
||||
lblNoAvailableDrafts=No hay Drafts disponibles
|
||||
lblEntryFeeOfDraftTournament=La cuota de inscripción para este torneo de booster draft es
|
||||
lblEntryFeeOfDraftTournament=La cuota de inscripción para este torneo de booster draft es
|
||||
lblWouldLikeCreateTournament= créditos.\n¿Te gustaría gastar una ficha y crear este torneo?
|
||||
lblCreatingDraftTournament=Creación de un Torneo de Booster Draft
|
||||
lblUnexpectedCreatingDraftTournament=Error inesperado al crear un torneo de draft
|
||||
lblUnexpectedCreatingDraftTournament=Error inesperado al crear un torneo de draft
|
||||
lblPleaseReportBug=. Por favor, informe de esto como un error.
|
||||
lbl1stPlace=1er Puesto:
|
||||
lbl2ndPlace=2o Puesto:
|
||||
lbl3rdPlace=3er Puesto:
|
||||
lbl4thPlace=4o Puesto:
|
||||
lbl1stPlace=1er Puesto:
|
||||
lbl2ndPlace=2o Puesto:
|
||||
lbl3rdPlace=3er Puesto:
|
||||
lbl4thPlace=4o Puesto:
|
||||
lblTime= veces
|
||||
lblCollectPrizes=Recoger Premios
|
||||
lblCurrentlyInDraft=Actualmente estás en un draft.\nDeberías dejar o terminar ese draft antes de empezar otro.
|
||||
lblYouNeed=Necesitas
|
||||
lblYouNeed=Necesitas
|
||||
lblMoreCredits=créditos más para entrar en este torneo.
|
||||
lblNotEnoughCredits=No hay suficientes créditos
|
||||
lblTournamentCosts=Este torneo cuesta
|
||||
lblTournamentCosts=Este torneo cuesta
|
||||
lblSureEnterTournament= créditos para entrar.\n¿Está seguro de que desea entrar?
|
||||
lblEnterDraftTournament=¿Entrar en el Torneo de Draft?
|
||||
lblLeaveDraftConfirm=Esto terminará con el actual Draft y no podrás volver a unirte a este torneo.\nTus créditos serán reembolsados y el Draft será eliminado.\n\n¿Abandonar de todos modos?
|
||||
@@ -1683,7 +1692,7 @@ lblWinsForRankIncrease=Ganancias por aumento de rango
|
||||
lblWinsForMediumAI=Ganancias para la IA media
|
||||
lblWinsForHardAI=Ganancias para la IA difícil
|
||||
lblWinsForExpertAI=Ganancias para la IA experta
|
||||
lblSaveFailed=Error al Guardar -
|
||||
lblSaveFailed=Error al Guardar -
|
||||
#QuestSpellShopScreen.java
|
||||
lblMaximumSellingCredits=El precio máximo de venta es de %d créditos.
|
||||
lblSellCardsAt=Vender cartas a
|
||||
@@ -1769,7 +1778,7 @@ lblDoYouWantMoveTargetFromOriToDest=¿Quieres mover {0} de {1} a {2}?
|
||||
lblPutThatCardFromPlayerOriginToDestination=¿Poner esa carta desde {0} {1} hasta {2}?
|
||||
lblSearchPlayerZoneConfirm=¿Buscar {0} {1}?
|
||||
lblCardMatchSearchingTypeInAlternateZones=las cartas coinciden con tu tipo de búsqueda en las zonas alternativas.
|
||||
lblLookingCardIn=Mirando las cartas en
|
||||
lblLookingCardIn=Mirando las cartas en
|
||||
lblDoYouWantPlayCard=¿Quieres jugar {0}?
|
||||
lblSelectCardFromPlayerZone=Selecciona una carta de {0} {1}
|
||||
lblSelectUpToNumCardFromPlayerZone=Selecciona hasta {0} cartas de {1} {2}
|
||||
@@ -1861,7 +1870,7 @@ lblChooseACardLeaveTarget=Elige una carta para dejar en {0} {1}
|
||||
lblChooseCardsPutIntoZone=Elige la(s) carta(s) a poner en {0}
|
||||
lblChooseCardPutOnTargetLibraryBottom=Elige la(s) carta(s) a poner en la parte inferior de la biblioteca {0}
|
||||
lblChooseCardPutOnTargetLibraryTop=Elige la(s) carta(s) a poner en la parte superior de la biblioteca {0}
|
||||
lblPlayerPickedCardFrom={0} eligió carta(s) de
|
||||
lblPlayerPickedCardFrom={0} eligió carta(s) de
|
||||
lblNoValidCards=No hay cartas válidas
|
||||
#DigUntilEffect.java
|
||||
lblDoYouWantDigYourLibrary=¿Quieres escarbar en tu biblioteca?
|
||||
@@ -2281,7 +2290,7 @@ lblDoYouWantCardDealNDamageToYou=¿Quieres que {0} te haga {1} de daño?
|
||||
lblDrawNCardsConfirm=¿Robar {0} carta(s)?
|
||||
lblExileConfirm=¿Exiliar {0}?
|
||||
lblExileNCardsFromYourZone=Exilia {0} carta(s) de tu {1}
|
||||
lblExileFromWhoseZone=Exilia {0} de quién
|
||||
lblExileFromWhoseZone=Exilia {0} de quién
|
||||
lblExileProgressFromZone=Exilia {0}/{1} de {2}
|
||||
lblToBeExiled=Para ser exiliado
|
||||
lblExileFromStack=Exiliar de la pila
|
||||
@@ -2312,7 +2321,7 @@ lblRemoveNTargetCounterFromCardPayCostConfirm=Paga el coste: ¿Quitar el contado
|
||||
lblRemoveCountersFromAInZoneCard=Quitar contador(es) de una carta en {0}
|
||||
lblSacrificeCardConfirm=¿Sacrificar {0}?
|
||||
lblSelectATargetToSacrifice=Selecciona un {0} para sacrificar ({1} pendiente)
|
||||
lblSelectOneOfCardsToTapAlreadyChosen=Selecciona una de las cartas para girar. Ya elegido:
|
||||
lblSelectOneOfCardsToTapAlreadyChosen=Selecciona una de las cartas para girar. Ya elegido:
|
||||
lblSelectACreatureToTap=Selecciona una criatura para girar.
|
||||
lblEnoughValidCardNotToPayTheCost=No quedan suficientes cartas válidas para girar para pagar el coste.
|
||||
lblCostPaymentInvalid=Pago del coste no válido
|
||||
@@ -2570,7 +2579,7 @@ lblRecordAndAssets=Registro | Bienes
|
||||
lblXWinOfYLost={0} G/{1} P
|
||||
lblDeleteThisQuest=Eliminar esta aventura
|
||||
lblRenameThisQuest=Renombrar esta aventura
|
||||
lblRenameQuestTo=Renombrar aventura como
|
||||
lblRenameQuestTo=Renombrar aventura como
|
||||
lblQuestRename=Renombrar aventura
|
||||
#StartingPoolType.java
|
||||
lblUnrestricted=Sin restriciones
|
||||
@@ -2671,7 +2680,7 @@ lblDetectedInvalidHostAddress=Dirección de host inválida ({0}) detectada.
|
||||
#Player.java
|
||||
lblChooseACompanion=Elige un compañero
|
||||
lblChooseAColorFor=Elige un color para {0}
|
||||
lblRevealFaceDownCards=Mostrar cartas boca abajo de
|
||||
lblRevealFaceDownCards=Mostrar cartas boca abajo de
|
||||
lblLearnALesson=Learn a Lesson
|
||||
#QuestPreferences.java
|
||||
lblWildOpponentNumberError=Los oponentes salvajes sólo pueden ser de 0 a 3
|
||||
|
||||
@@ -18,8 +18,8 @@ lblerrLoadingLayoutFile=Impossibile leggere il file di layout %s. Verrà elimina
|
||||
lblLoadingQuest=Caricamento avevntura ...
|
||||
#FScreen.java
|
||||
#translate lblHomeWithSpaces,lblDeckEditorWithSpaces need keep spaces in text
|
||||
lblHomeWithSpaces=Home
|
||||
lblDeckEditorWithSpaces=Gestione dei mazzi
|
||||
lblHomeWithSpaces=Home
|
||||
lblDeckEditorWithSpaces=Gestione dei mazzi
|
||||
lblWorkshop=Officina
|
||||
lblBacktoHome=Torna a Home
|
||||
lblCloseEditor=Esci dalla gestione
|
||||
@@ -361,6 +361,15 @@ lblTotalDamageText=Punti di danno disponibili: Sconosciuto
|
||||
lblAssignRemainingText=Distribuire i punti di danno rimanenti tra le entità ferite letalmente
|
||||
lblLethal=Letale
|
||||
lblAvailableDamagePoints=Punti danno disponibili
|
||||
#VAssignGenericAmount.java
|
||||
# The {0} below should be amount label (like "shield" or "damage"), and {1} will be the name of the effect source
|
||||
lbLAssignAmountForEffect=Assign {0} by {1}
|
||||
lblLClickAmountMessage=Left click: Assign 1 {0}. (Left Click + Control): Assign maximum {0} points
|
||||
lblRClickAmountMessage=Right click: Unassign 1 {0}. (Right Click + Control): Unassign all {0} points.
|
||||
lblTotalAmountText=Available {0} points: Unknown
|
||||
lblAvailableAmount=Available {0} points
|
||||
lblMax=Max
|
||||
lblShield=shield
|
||||
#KeyboardShortcuts.java
|
||||
lblSHORTCUT_SHOWSTACK=Incontro: mostra il pannello della pila
|
||||
lblSHORTCUT_SHOWCOMBAT=Incontro: mostra il pannello di combattimento
|
||||
@@ -1613,10 +1622,10 @@ lblWouldLikeCreateTournament= monete.\nDesideri usare un token e creare questo t
|
||||
lblCreatingDraftTournament=Creazione del torneo Booster Draft
|
||||
lblUnexpectedCreatingDraftTournament=Errore inaspettato durante la creazione del torneo
|
||||
lblPleaseReportBug=. Per favore segnala il bug.
|
||||
lbl1stPlace=Primo posto:
|
||||
lbl2ndPlace=Secondo posto:
|
||||
lbl3rdPlace=Terzo posto:
|
||||
lbl4thPlace=Quarto posto:
|
||||
lbl1stPlace=Primo posto:
|
||||
lbl2ndPlace=Secondo posto:
|
||||
lbl3rdPlace=Terzo posto:
|
||||
lbl4thPlace=Quarto posto:
|
||||
lblTime= tempo
|
||||
lblCollectPrizes=Ricevi i premi
|
||||
lblCurrentlyInDraft=Stai partecipando a un draft.\nDevi terminare o abbandonare quel draft prima di iniziarne un altro.
|
||||
@@ -1683,10 +1692,10 @@ lblWinsForRankIncrease=Vittorie per aumento di rango
|
||||
lblWinsForMediumAI=Numero di vittorie per IA livello Apprendista
|
||||
lblWinsForHardAI=Numero di vittorie per IA livello Esperto
|
||||
lblWinsForExpertAI=Numero di vittorie per IA livello Maestro
|
||||
lblSaveFailed=Salvataggio fallito -
|
||||
lblSaveFailed=Salvataggio fallito -
|
||||
#QuestSpellShopScreen.java
|
||||
lblMaximumSellingCredits=Il prezzo massimo di vendita è di %d monete.
|
||||
lblSellCardsAt=Carte in vendita al
|
||||
lblSellCardsAt=Carte in vendita al
|
||||
lblTheirValue=% del loro valore.\n
|
||||
lblSell=Vendi
|
||||
lblItem=oggetto
|
||||
@@ -2274,7 +2283,7 @@ lblHistoriiansWillRecallYourConquestAs=Gli storici ricorderanno la tua Conquista
|
||||
lblConquestName=Nome della Conquista
|
||||
#HumanCostDecision.java
|
||||
lblChooseXValueForCard={0} - Scegli un valore per X
|
||||
lblSelectOneSameNameCardToDiscardAlreadyChosen=Seleziona una delle carte con lo stesso nome da scartare. Già scelto:
|
||||
lblSelectOneSameNameCardToDiscardAlreadyChosen=Seleziona una delle carte con lo stesso nome da scartare. Già scelto:
|
||||
lblSelectOneDifferentNameCardToDiscardAlreadyChosen=Seleziona una delle carte con un nome diverso da scartare. Già scelto:
|
||||
lblSelectNMoreTargetTypeCardToDiscard=Seleziona altre{0} {1} da scartare.
|
||||
lblDoYouWantCardDealNDamageToYou=Vuoi che {0} ti infligga {1} danno/i?
|
||||
@@ -2312,7 +2321,7 @@ lblRemoveNTargetCounterFromCardPayCostConfirm=Paga il costot: Vuoi rimuovere {0}
|
||||
lblRemoveCountersFromAInZoneCard=Rimuovi segnalini da una carta in {0}
|
||||
lblSacrificeCardConfirm=Vuoi sacrificare {0}?
|
||||
lblSelectATargetToSacrifice=Seleziona una carta {0} da scarificare ({1} rimasta/e)
|
||||
lblSelectOneOfCardsToTapAlreadyChosen=Seleziona una delle carta da tappare. Già scelto:
|
||||
lblSelectOneOfCardsToTapAlreadyChosen=Seleziona una delle carta da tappare. Già scelto:
|
||||
lblSelectACreatureToTap=Seleziona una creatura da tappare.
|
||||
lblEnoughValidCardNotToPayTheCost=Non sono rimaste abbastanza carte valide da tappare per pagare il costo
|
||||
lblCostPaymentInvalid=Pagamento del costo non valido
|
||||
@@ -2386,7 +2395,7 @@ lblHandOrLibraryOrGraveyard=mano, grimorio e cimitero
|
||||
lblHandOrLibraryOrGraveyardOrBattlefield=mano, grimorio, cimitero e campo di battaglia
|
||||
#LifeToSpare.java
|
||||
lblLifeToSpare=Vita da vendere
|
||||
lblWinGameWith=Vinci una partita con
|
||||
lblWinGameWith=Vinci una partita con
|
||||
lblMoreThanStartedLifeN={0} punti vita in più di quelli con cui hai iniziato
|
||||
#ManaFlooded.java
|
||||
lblManaFlooded=Inondazione di mana
|
||||
|
||||
@@ -18,8 +18,8 @@ lblerrLoadingLayoutFile=%s レイアウトファイルを読み取れません
|
||||
lblLoadingQuest=クエストを読み込んでいます...
|
||||
#FScreen.java
|
||||
#translate lblHomeWithSpaces,lblDeckEditorWithSpaces need keep spaces in text
|
||||
lblHomeWithSpaces=ホーム
|
||||
lblDeckEditorWithSpaces=デッキエディター
|
||||
lblHomeWithSpaces=ホーム
|
||||
lblDeckEditorWithSpaces=デッキエディター
|
||||
lblWorkshop=ワークショップ
|
||||
lblBacktoHome=ホームに戻る
|
||||
lblCloseEditor=エディターを閉じる
|
||||
@@ -355,12 +355,21 @@ lblReset=リセット
|
||||
lblAuto=自動
|
||||
#VAssignDamage.java
|
||||
lbLAssignDamageDealtBy=%sによって与えられるダメージを割り当てます
|
||||
lblLClickDamageMessage=左クリック:1ダメージを割り当てます。 (Ctrl + 左クリック):残りのダメージを致死まで割り当てる
|
||||
lblRClickDamageMessage=右クリック:1ダメージの割り当てを解除します。 (Ctrl + 右クリック):すべての損傷の割り当てを解除します。
|
||||
lblLClickDamageMessage=左クリック:1点ダメージを割り当てます。 (Ctrl + 左クリック):残りのダメージを致死まで割り当てます。
|
||||
lblRClickDamageMessage=右クリック:1点ダメージの割り当てを解除します。 (Ctrl + 右クリック):すべてのダメージの割り当てを解除します。
|
||||
lblTotalDamageText=利用可能なダメージポイント:不明
|
||||
lblAssignRemainingText=致命傷を負ったエンティティに残りのダメージポイントを分配する
|
||||
lblAssignRemainingText=致死ダメージを負ったオブジェクトに残りのダメージを割り当てます。
|
||||
lblLethal=リーサル
|
||||
lblAvailableDamagePoints=利用可能なダメージポイント
|
||||
#VAssignGenericAmount.java
|
||||
# The {0} below should be amount label (like "shield" or "damage"), and {1} will be the name of the effect source
|
||||
lbLAssignAmountForEffect={1}によって効果の{0}を割り当てます
|
||||
lblLClickAmountMessage=左クリック: 1点{0}を割り当てます。 (Ctrl + 左クリック):{0}を最大まで割り当てます。
|
||||
lblRClickAmountMessage=右クリック:1点{0}の割り当てを解除します。 (Ctrl + 右クリック):すべての{0}の割り当てを解除します。
|
||||
lblTotalAmountText=残りの{0}のポイント:不明
|
||||
lblAvailableAmount=残りの{0}のポイント
|
||||
lblMax=最大
|
||||
lblShield=盾
|
||||
#KeyboardShortcuts.java
|
||||
lblSHORTCUT_SHOWSTACK=スタックパネルを表示
|
||||
lblSHORTCUT_SHOWCOMBAT=戦闘パネルを表示
|
||||
@@ -1039,7 +1048,7 @@ lblLog=ログ
|
||||
lblDev=開発者
|
||||
lblCombatTab=戦闘
|
||||
lblStack=スタック
|
||||
lblMustWaitPriority=優先権を待つ必要があります...
|
||||
lblMustWaitPriority=優先権を待つ必要があります...
|
||||
#FDeckEditor.java
|
||||
lblImportFromClipboard=クリップボードからインポート
|
||||
lblSaveAs=名前を付けて保存...
|
||||
@@ -1075,7 +1084,7 @@ lblLoadingCardTranslations=カードの翻訳を読み込んでいます...
|
||||
lblFinishingStartup=起動を終了しています...
|
||||
lblPreloadExtendedArt=拡張アートのプリロード...
|
||||
#LobbyScreen.java
|
||||
lblMore=もっと...
|
||||
lblMore=もっと...
|
||||
lblLoadingNewGame=新しいゲームを読み込んでいます...
|
||||
lblSelectVariants=バリエーションを選択
|
||||
msgSelectAdeckBeforeReadying=始まる前にデッキを選択してください!
|
||||
@@ -1624,7 +1633,7 @@ lblCurrentlyInDraft=今はドラフトを参加中です。\n新しいドラフ
|
||||
lblYouNeed=このトーナメントを参加するにはもっと
|
||||
lblMoreCredits=のクレジットが必要です。
|
||||
lblNotEnoughCredits=クレジット不足
|
||||
lblTournamentCosts=このトーナメントの参加費は
|
||||
lblTournamentCosts=このトーナメントの参加費は
|
||||
lblSureEnterTournament=クレジットです。\n参加してもよろしいでしょうか?
|
||||
lblEnterDraftTournament=トーナメントに参加しますか?
|
||||
lblLeaveDraftConfirm=これによりこのドラフトを終了して、再度参加することは出来ません。\n使ったクレジットは返金されて、そしてドラフトを削除します。\n\nそれでも退場しますか?
|
||||
@@ -2275,8 +2284,8 @@ lblHistoriiansWillRecallYourConquestAs=歴史家たちはあなたの征服紀
|
||||
lblConquestName=征服紀録名
|
||||
#HumanCostDecision.java
|
||||
lblChooseXValueForCard={0} - Xの値を選択
|
||||
lblSelectOneSameNameCardToDiscardAlreadyChosen=同名カードを 1つ選んで捨てる。既に選択:
|
||||
lblSelectOneDifferentNameCardToDiscardAlreadyChosen=違う名前のカードを 1つ選んで捨てる。既に選択:
|
||||
lblSelectOneSameNameCardToDiscardAlreadyChosen=同名カードを 1つ選んで捨てる。既に選択:
|
||||
lblSelectOneDifferentNameCardToDiscardAlreadyChosen=違う名前のカードを 1つ選んで捨てる。既に選択:
|
||||
lblSelectNMoreTargetTypeCardToDiscard=もっと {0}枚の {1}を選んで捨てる。
|
||||
lblDoYouWantCardDealNDamageToYou={0}があなたに {1}点のダメージを与えてもいいですか?
|
||||
lblDrawNCardsConfirm={0}枚のカードを引きますか?
|
||||
|
||||
@@ -18,8 +18,8 @@ lblerrLoadingLayoutFile=无法读取你的布局文件:%s。按OK然后删除
|
||||
lblLoadingQuest=加载冒险之旅...
|
||||
#FScreen.java
|
||||
#翻译lblHomeWithSpaces,lblDeckEditorWithSpaces时需要保留翻译文本中的空格
|
||||
lblHomeWithSpaces=主页
|
||||
lblDeckEditorWithSpaces=套牌编辑器
|
||||
lblHomeWithSpaces=主页
|
||||
lblDeckEditorWithSpaces=套牌编辑器
|
||||
lblWorkshop=作坊页面
|
||||
lblBacktoHome=回退到主页
|
||||
lblCloseEditor=关闭编辑器
|
||||
@@ -53,7 +53,7 @@ btnClearImageCache=清除图片缓存
|
||||
btnTokenPreviewer=衍生物预览器
|
||||
btnCopyToClipboard=复制到剪切板
|
||||
cbpSelectLanguage=语言
|
||||
cbpAutoUpdater=自动更新
|
||||
cbpAutoUpdater=自动更新
|
||||
nlAutoUpdater=选择用于更新Forge的发布渠道
|
||||
nlSelectLanguage=选择语言(除了正在进行中的游戏)(需要重新启动)
|
||||
cbRemoveSmall=删除小生物
|
||||
@@ -361,6 +361,15 @@ lblTotalDamageText=可用的伤害值:未知
|
||||
lblAssignRemainingText=对受到致命伤害的对象分配过量的伤害
|
||||
lblLethal=致死
|
||||
lblAvailableDamagePoints=可用的伤害值
|
||||
#VAssignGenericAmount.java
|
||||
# The {0} below should be amount label (like "shield" or "damage"), and {1} will be the name of the effect source
|
||||
lbLAssignAmountForEffect=Assign {0} by {1}
|
||||
lblLClickAmountMessage=Left click: Assign 1 {0}. (Left Click + Control): Assign maximum {0} points
|
||||
lblRClickAmountMessage=Right click: Unassign 1 {0}. (Right Click + Control): Unassign all {0} points.
|
||||
lblTotalAmountText=Available {0} points: Unknown
|
||||
lblAvailableAmount=Available {0} points
|
||||
lblMax=Max
|
||||
lblShield=shield
|
||||
#KeyboardShortcuts.java
|
||||
lblSHORTCUT_SHOWSTACK=匹配:显示堆叠面板
|
||||
lblSHORTCUT_SHOWCOMBAT=匹配:显示战斗面板
|
||||
@@ -416,7 +425,7 @@ lblSelectOpponentDeck=为对手选择套牌
|
||||
lblGenerateNewDeck=生成新的套牌
|
||||
lblRandomTheme=随机主题
|
||||
lblTestDeck=测试套牌
|
||||
lblLoading=加载中
|
||||
lblLoading=加载中
|
||||
#GameType.java
|
||||
lblSealed=现开
|
||||
lblDraft=轮抓
|
||||
@@ -764,7 +773,7 @@ ttWinsperDraftRotation=如果轮抓没有赢这么多场,那么它将被删除
|
||||
lblRotationType=轮替类型
|
||||
ttRotationType=如果设置为0,旧系列消失,如果设置为1,则用不同系列替换。
|
||||
lblWildOpponentNumber=野外对手数量
|
||||
lblWildOpponentMultiplier=野外对手倍数
|
||||
lblWildOpponentMultiplier=野外对手倍数
|
||||
#StatTypeFilter.java
|
||||
lblclicktotoogle=单击以切换筛选器,右键单机以仅显示
|
||||
#SItemManagerUtil.java
|
||||
@@ -1288,7 +1297,7 @@ lblLibrary=牌库
|
||||
lblGraveyard=坟场
|
||||
lblTop=顶
|
||||
lblBottom=底
|
||||
lblNColorManaFromCard={2}产{0}个{1}法术力
|
||||
lblNColorManaFromCard={2}产{0}个{1}法术力
|
||||
lblPayManaFromManaPool=从法术力池支付法术力
|
||||
lblChooseATargetType=选择一个{0}类型
|
||||
lblUntap=重置
|
||||
@@ -1621,10 +1630,10 @@ lbl4thPlace=第四名:
|
||||
lblTime= 时间
|
||||
lblCollectPrizes=收藏品
|
||||
lblCurrentlyInDraft=你现在正在一场轮抓中。\n你应该先离开轮抓或者玩完这场轮抓,然后再开始新的轮抓。
|
||||
lblYouNeed=你还需要
|
||||
lblYouNeed=你还需要
|
||||
lblMoreCredits=积分才可以参与这场锦标赛。
|
||||
lblNotEnoughCredits=积分不足
|
||||
lblTournamentCosts=这次锦标赛的费用为
|
||||
lblTournamentCosts=这次锦标赛的费用为
|
||||
lblSureEnterTournament= 积分。\n你确定要进入吗?
|
||||
lblEnterDraftTournament=进入轮抓锦标赛?
|
||||
lblLeaveDraftConfirm=这将结束当前轮抓,你将无法再次加入此锦标赛。\n你的积分将被退还,轮抓将被删除。\n\n仍然要离开吗?
|
||||
|
||||
@@ -56,6 +56,7 @@ public enum ProtocolMethod {
|
||||
setPanelSelection (Mode.SERVER, Void.TYPE, CardView.class),
|
||||
getAbilityToPlay (Mode.SERVER, SpellAbilityView.class, CardView.class, List/*SpellAbilityView*/.class, ITriggerEvent.class),
|
||||
assignCombatDamage (Mode.SERVER, Map.class, CardView.class, List/*CardView*/.class, Integer.TYPE, GameEntityView.class, Boolean.TYPE),
|
||||
divideShield (Mode.SERVER, Map.class, CardView.class, Map.class, Integer.TYPE, Boolean.TYPE, String.class),
|
||||
message (Mode.SERVER, Void.TYPE, String.class, String.class),
|
||||
showErrorDialog (Mode.SERVER, Void.TYPE, String.class, String.class),
|
||||
showConfirmDialog (Mode.SERVER, Boolean.TYPE, String.class, String.class, String.class, String.class, Boolean.TYPE),
|
||||
|
||||
@@ -74,7 +74,7 @@ public class NetGuiGame extends AbstractGuiGame {
|
||||
updateGameView();
|
||||
send(ProtocolMethod.showPromptMessage, playerView, message);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void showPromptMessage(final PlayerView playerView, final String message, final CardView card) {
|
||||
updateGameView();
|
||||
@@ -206,6 +206,11 @@ public class NetGuiGame extends AbstractGuiGame {
|
||||
return sendAndWait(ProtocolMethod.assignCombatDamage, attacker, blockers, damage, defender, overrideOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<GameEntityView, Integer> assignGenericAmount(final CardView effectSource, final Map<GameEntityView, Integer> targets, final int amount, final boolean atLeastOne, final String amountLabel) {
|
||||
return sendAndWait(ProtocolMethod.divideShield, effectSource, targets, amount, atLeastOne, amountLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void message(final String message, final String title) {
|
||||
send(ProtocolMethod.message, message, title);
|
||||
|
||||
@@ -69,6 +69,7 @@ public interface IGuiGame {
|
||||
void setPanelSelection(CardView hostCard);
|
||||
SpellAbilityView getAbilityToPlay(CardView hostCard, List<SpellAbilityView> abilities, ITriggerEvent triggerEvent);
|
||||
Map<CardView, Integer> assignCombatDamage(CardView attacker, List<CardView> blockers, int damage, GameEntityView defender, boolean overrideOrder);
|
||||
Map<GameEntityView, Integer> assignGenericAmount(CardView effectSource, Map<GameEntityView, Integer> target, int amount, final boolean atLeastOne, final String amountLabel);
|
||||
|
||||
void message(String message);
|
||||
void message(String message, String title);
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@@ -389,6 +390,24 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<GameEntity, Integer> divideShield(Card effectSource, Map<GameEntity, Integer> affected, int shieldAmount) {
|
||||
final CardView vSource = CardView.get(effectSource);
|
||||
final Map<GameEntityView, Integer> vAffected = new HashMap<>(affected.size());
|
||||
for (Map.Entry<GameEntity, Integer> e : affected.entrySet()) {
|
||||
vAffected.put(GameEntityView.get(e.getKey()), e.getValue());
|
||||
}
|
||||
final Map<GameEntityView, Integer> vResult = getGui().assignGenericAmount(vSource, vAffected, shieldAmount, false,
|
||||
localizer.getMessage("lblShield"));
|
||||
Map<GameEntity, Integer> result = new HashMap<>(vResult.size());
|
||||
for (Map.Entry<GameEntity, Integer> e : affected.entrySet()) {
|
||||
if (vResult.containsKey(GameEntityView.get(e.getKey()))) {
|
||||
result.put(e.getKey(), vResult.get(GameEntityView.get(e.getKey())));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer announceRequirements(final SpellAbility ability, final String announce) {
|
||||
int max = Integer.MAX_VALUE;
|
||||
|
||||
Reference in New Issue
Block a user