Implement missing cards with dividable shields for damage replacement effects

This commit is contained in:
Lyu Zong-Hong
2021-06-05 18:18:34 +09:00
parent f95fb7d08b
commit ab31c8fa9d
25 changed files with 1077 additions and 173 deletions

View File

@@ -81,9 +81,9 @@ import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
/** /**
* A prototype for player controller class * A prototype for player controller class
* *
* Handles phase skips for now. * Handles phase skips for now.
*/ */
public class PlayerControllerAi extends PlayerController { public class PlayerControllerAi extends PlayerController {
@@ -94,11 +94,11 @@ public class PlayerControllerAi extends PlayerController {
brains = new AiController(p, game); brains = new AiController(p, game);
} }
public void allowCheatShuffle(boolean value){ public void allowCheatShuffle(boolean value){
brains.allowCheatShuffle(value); brains.allowCheatShuffle(value);
} }
public void setUseSimulation(boolean value) { public void setUseSimulation(boolean value) {
brains.setUseSimulation(value); brains.setUseSimulation(value);
} }
@@ -131,6 +131,12 @@ public class PlayerControllerAi extends PlayerController {
return ComputerUtilCombat.distributeAIDamage(attacker, blockers, damageDealt, defender, overrideOrder); 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 @Override
public Integer announceRequirements(SpellAbility ability, String announce) { public Integer announceRequirements(SpellAbility ability, String announce) {
// For now, these "announcements" are made within the AI classes of the appropriate SA effects // 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: case BidLife:
return 0; return 0;
default: default:
return null; return null;
} }
} }
return null; // return incorrect value to indicate that 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) { public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) {
return getAi().confirmAction(sa, mode, message); return getAi().confirmAction(sa, mode, message);
} }
@Override @Override
public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode mode, String string, public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode mode, String string,
int bid, Player winner) { int bid, Player winner) {
@@ -646,7 +652,7 @@ public class PlayerControllerAi extends PlayerController {
public List<SpellAbility> chooseSpellAbilityToPlay() { public List<SpellAbility> chooseSpellAbilityToPlay() {
return brains.chooseSpellAbilityToPlay(); return brains.chooseSpellAbilityToPlay();
} }
@Override @Override
public boolean playChosenSpellAbility(SpellAbility sa) { public boolean playChosenSpellAbility(SpellAbility sa) {
if (sa instanceof LandAbility) { if (sa instanceof LandAbility) {
@@ -658,7 +664,7 @@ public class PlayerControllerAi extends PlayerController {
ComputerUtil.handlePlayingSpellAbility(player, sa, getGame()); ComputerUtil.handlePlayingSpellAbility(player, sa, getGame());
} }
return true; return true;
} }
@Override @Override
public CardCollection chooseCardsToDiscardToMaximumHandSize(int numDiscard) { 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) { public int chooseNumber(SpellAbility sa, String title, int min, int max) {
return brains.chooseNumber(sa, title, min, max); return brains.chooseNumber(sa, title, min, max);
} }
@Override @Override
public int chooseNumber(SpellAbility sa, String string, int min, int max, Map<String, Object> params) { public int chooseNumber(SpellAbility sa, String string, int min, int max, Map<String, Object> params) {
ApiType api = sa.getApi(); ApiType api = sa.getApi();
@@ -814,7 +820,7 @@ public class PlayerControllerAi extends PlayerController {
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
* @see * @see
* forge.game.player.PlayerController#chooseBinary(forge.game.spellability. * forge.game.player.PlayerController#chooseBinary(forge.game.spellability.
* SpellAbility, java.lang.String, * SpellAbility, java.lang.String,
@@ -855,7 +861,7 @@ public class PlayerControllerAi extends PlayerController {
} }
return sa.getChosenList(); return sa.getChosenList();
} }
@Override @Override
public byte chooseColorAllowColorless(String message, Card card, ColorSet colors) { public byte chooseColorAllowColorless(String message, Card card, ColorSet colors) {
final String c = ComputerUtilCard.getMostProminentColor(player.getCardsIn(ZoneType.Hand)); final String c = ComputerUtilCard.getMostProminentColor(player.getCardsIn(ZoneType.Hand));
@@ -901,7 +907,7 @@ public class PlayerControllerAi extends PlayerController {
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
* @see forge.game.player.PlayerController#chooseCounterType(java.util.List, * @see forge.game.player.PlayerController#chooseCounterType(java.util.List,
* forge.game.spellability.SpellAbility, java.lang.String, java.util.Map) * forge.game.spellability.SpellAbility, java.lang.String, java.util.Map)
*/ */
@@ -917,7 +923,7 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public boolean confirmPayment(CostPart costPart, String prompt, SpellAbility sa) { 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 @Override
@@ -1105,7 +1111,7 @@ public class PlayerControllerAi extends PlayerController {
public void revealAnte(String message, Multimap<Player, PaperCard> removedAnteCards) { public void revealAnte(String message, Multimap<Player, PaperCard> removedAnteCards) {
// Ai won't understand that anyway // Ai won't understand that anyway
} }
@Override @Override
public Collection<? extends PaperCard> complainCardsCantPlayWell(Deck myDeck) { public Collection<? extends PaperCard> complainCardsCantPlayWell(Deck myDeck) {
return brains.complainCardsCantPlayWell(myDeck); return brains.complainCardsCantPlayWell(myDeck);
@@ -1153,7 +1159,7 @@ public class PlayerControllerAi extends PlayerController {
return new HashMap<>(); return new HashMap<>();
} }
} }
//Do not convoke potential blockers until after opponent's attack //Do not convoke potential blockers until after opponent's attack
final CardCollectionView blockers = ComputerUtilCard.getLikelyBlockers(ai, null); final CardCollectionView blockers = ComputerUtilCard.getLikelyBlockers(ai, null);
if ((ph.isPlayerTurn(ai) && ph.getPhase().isAfter(PhaseType.COMBAT_BEGIN)) || if ((ph.isPlayerTurn(ai) && ph.getPhase().isAfter(PhaseType.COMBAT_BEGIN)) ||

View File

@@ -57,6 +57,7 @@ public enum AbilityKey {
DefendingPlayer("DefendingPlayer"), DefendingPlayer("DefendingPlayer"),
Destination("Destination"), Destination("Destination"),
Devoured("Devoured"), Devoured("Devoured"),
DividedShieldAmount("DividedShieldAmount"),
EchoPaid("EchoPaid"), EchoPaid("EchoPaid"),
EffectOnly("EffectOnly"), EffectOnly("EffectOnly"),
Exploited("Exploited"), Exploited("Exploited"),

View File

@@ -39,6 +39,10 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
if (prevent > 0) { if (prevent > 0) {
int n = Math.min(dmg, prevent); 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; dmg -= n;
prevent -= n; prevent -= n;

View File

@@ -38,6 +38,10 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
if (prevent > 0 && list.size() > 0 && list.get(0) instanceof GameEntity) { if (prevent > 0 && list.size() > 0 && list.get(0) instanceof GameEntity) {
int n = Math.min(dmg, prevent); 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; dmg -= n;
prevent -= n; prevent -= n;

View File

@@ -108,6 +108,7 @@ public abstract class PlayerController {
public abstract List<PaperCard> chooseCardsYouWonToAddToDeck(List<PaperCard> losses); 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<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 Integer announceRequirements(SpellAbility ability, String announce);
public abstract CardCollectionView choosePermanentsToSacrifice(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message); public abstract CardCollectionView choosePermanentsToSacrifice(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message);

View File

@@ -688,6 +688,7 @@ public class ReplacementHandler {
ApiType apiType = null; ApiType apiType = null;
SpellAbility bufferedSA = effectSA; SpellAbility bufferedSA = effectSA;
boolean needRestoreSubSA = false; boolean needRestoreSubSA = false;
boolean needDivideShield = false;
boolean needChooseSource = false; boolean needChooseSource = false;
int shieldAmount = 0; int shieldAmount = 0;
if (effectSA != null) { 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(); Map<String, String> mapParams = chosenRE.getMapParams();
if ((mapParams.containsKey("PreventionEffect") && mapParams.get("PreventionEffect").equals("NextN")) if ((mapParams.containsKey("PreventionEffect") && mapParams.get("PreventionEffect").equals("NextN"))
|| apiType == ApiType.ReplaceSplitDamage) { || apiType == ApiType.ReplaceSplitDamage) {
@@ -711,17 +713,50 @@ public class ReplacementHandler {
shieldAmount = AbilityUtils.calculateAmount(effectSA.getHostCard(), effectSA.getParamOrDefault("VarName", "1"), effectSA); shieldAmount = AbilityUtils.calculateAmount(effectSA.getHostCard(), effectSA.getParamOrDefault("VarName", "1"), effectSA);
} }
int damageAmount = 0; int damageAmount = 0;
boolean hasMultipleSource = false;
boolean hasMultipleTarget = false;
Card firstSource = null;
GameEntity firstTarget = null;
for (Map<AbilityKey, Object> runParams : runParamList) { for (Map<AbilityKey, Object> runParams : runParamList) {
// Only count damage that can be prevented // Only count damage that can be prevented
if (apiType == ApiType.ReplaceDamage && Boolean.TRUE.equals(runParams.get(AbilityKey.NoPreventDamage))) continue; if (apiType == ApiType.ReplaceDamage && Boolean.TRUE.equals(runParams.get(AbilityKey.NoPreventDamage))) continue;
damageAmount += (int) runParams.get(AbilityKey.DamageAmount); 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) { if (damageAmount > shieldAmount && runParamList.size() > 1) {
needChooseSource = true; 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 // CR 615.7
// If damage would be dealt to the shielded permanent or player by two or more applicable sources at the same time, // 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. // 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()) { while (shieldAmount > 0 && !sourcesToChooseFrom.isEmpty()) {
Card source = decider.getController().chooseSingleEntityForEffect(sourcesToChooseFrom, effectSA, choiceTitle, null); Card source = decider.getController().chooseSingleEntityForEffect(sourcesToChooseFrom, effectSA, choiceTitle, null);
sourcesToChooseFrom.remove(source); sourcesToChooseFrom.remove(source);
Map<AbilityKey, Object> runParams = null; Iterator<Map<AbilityKey, Object>> itr = runParamList.iterator();
for (Map<AbilityKey, Object> rp : runParamList) { while (itr.hasNext()) {
if (source.equals(rp.get(AbilityKey.DamageSource))) { Map<AbilityKey, Object> runParams = itr.next();
runParams = rp; if (source.equals(runParams.get(AbilityKey.DamageSource))) {
break; 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 { } else {
for (Map<AbilityKey, Object> runParams : runParamList) { 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)) { if (!runParams.containsKey(AbilityKey.ReplacementResultMap)) {
Map<ReplacementEffect, ReplacementResult> resultMap = new HashMap<>(); Map<ReplacementEffect, ReplacementResult> resultMap = new HashMap<>();
runParams.put(AbilityKey.ReplacementResultMap, resultMap); runParams.put(AbilityKey.ReplacementResultMap, resultMap);

View File

@@ -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 if (FThreads.isGuiThread()) { // run this now whether in EDT or not so that it doesn't clobber later stuff
FThreads.invokeInEdtNowOrLater(focusRoutine); FThreads.invokeInEdtNowOrLater(focusRoutine);
} else { } else {
@@ -1028,6 +1028,24 @@ public final class CMatchUI
return result.get(); 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 @Override
public void openView(final TrackableCollection<PlayerView> myPlayers) { public void openView(final TrackableCollection<PlayerView> myPlayers) {
final GameView gameView = getGameView(); final GameView gameView = getGameView();
@@ -1273,28 +1291,28 @@ public final class CMatchUI
String stackNotificationPolicy = FModel.getPreferences().getPref(FPref.UI_STACK_EFFECT_NOTIFICATION_POLICY); String stackNotificationPolicy = FModel.getPreferences().getPref(FPref.UI_STACK_EFFECT_NOTIFICATION_POLICY);
boolean isAi = sa.getActivatingPlayer().isAI(); boolean isAi = sa.getActivatingPlayer().isAI();
boolean isTrigger = sa.isTrigger(); boolean isTrigger = sa.isTrigger();
int stackIndex = event.stackIndex; int stackIndex = event.stackIndex;
if(stackIndex == nextNotifiableStackIndex) { if(stackIndex == nextNotifiableStackIndex) {
if(ForgeConstants.STACK_EFFECT_NOTIFICATION_ALWAYS.equals(stackNotificationPolicy) || (ForgeConstants.STACK_EFFECT_NOTIFICATION_AI_AND_TRIGGERED.equals(stackNotificationPolicy) && (isAi || isTrigger))) { 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 // We can go and show the modal
SpellAbilityStackInstance si = event.si; SpellAbilityStackInstance si = event.si;
MigLayout migLayout = new MigLayout("insets 15, left, gap 30, fill"); MigLayout migLayout = new MigLayout("insets 15, left, gap 30, fill");
JPanel mainPanel = new JPanel(migLayout); JPanel mainPanel = new JPanel(migLayout);
final Dimension parentSize = JOptionPane.getRootFrame().getSize(); final Dimension parentSize = JOptionPane.getRootFrame().getSize();
Dimension maxSize = new Dimension(1400, parentSize.height - 100); Dimension maxSize = new Dimension(1400, parentSize.height - 100);
mainPanel.setMaximumSize(maxSize); mainPanel.setMaximumSize(maxSize);
mainPanel.setOpaque(false); mainPanel.setOpaque(false);
// Big Image // Big Image
addBigImageToStackModalPanel(mainPanel, si); addBigImageToStackModalPanel(mainPanel, si);
// Text // Text
addTextToStackModalPanel(mainPanel,sa,si); addTextToStackModalPanel(mainPanel,sa,si);
// Small images // Small images
int numSmallImages = 0; int numSmallImages = 0;
// If current effect is a triggered/activated ability of an enchantment card, I want to show the enchanted card // If current effect is a triggered/activated ability of an enchantment card, I want to show the enchanted card
GameEntityView enchantedEntityView = null; GameEntityView enchantedEntityView = null;
Card hostCard = sa.getHostCard(); Card hostCard = sa.getHostCard();
@@ -1308,45 +1326,45 @@ public final class CMatchUI
&& !sa.getRootAbility().getPaidList("Sacrificed").isEmpty()) { && !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" // 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(); enchantedEntity = sa.getRootAbility().getPaidList("Sacrificed").get(0).getEnchantingCard();
if(enchantedEntity != null) { if(enchantedEntity != null) {
enchantedEntityView = enchantedEntity.getView(); enchantedEntityView = enchantedEntity.getView();
numSmallImages++; numSmallImages++;
} }
} }
} }
// If current effect is a triggered ability, I want to show the triggering card if present // If current effect is a triggered ability, I want to show the triggering card if present
SpellAbility sourceSA = (SpellAbility) si.getTriggeringObject(AbilityKey.SourceSA); SpellAbility sourceSA = (SpellAbility) si.getTriggeringObject(AbilityKey.SourceSA);
CardView sourceCardView = null; CardView sourceCardView = null;
if(sourceSA != null) { if(sourceSA != null) {
sourceCardView = sourceSA.getHostCard().getView(); sourceCardView = sourceSA.getHostCard().getView();
numSmallImages++; numSmallImages++;
} }
// I also want to show each type of targets (both cards and players) // I also want to show each type of targets (both cards and players)
List<GameEntityView> targets = getTargets(si,new ArrayList<GameEntityView>()); List<GameEntityView> targets = getTargets(si,new ArrayList<GameEntityView>());
numSmallImages = numSmallImages + targets.size(); numSmallImages = numSmallImages + targets.size();
// Now I know how many small images - on to render them // Now I know how many small images - on to render them
if(enchantedEntityView != null) { if(enchantedEntityView != null) {
addSmallImageToStackModalPanel(enchantedEntityView,mainPanel,numSmallImages); addSmallImageToStackModalPanel(enchantedEntityView,mainPanel,numSmallImages);
} }
if(sourceCardView != null) { if(sourceCardView != null) {
addSmallImageToStackModalPanel(sourceCardView,mainPanel,numSmallImages); addSmallImageToStackModalPanel(sourceCardView,mainPanel,numSmallImages);
} }
for(GameEntityView gev : targets) { for(GameEntityView gev : targets) {
addSmallImageToStackModalPanel(gev, mainPanel, numSmallImages); 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 // here the user closed the modal - time to update the next notifiable stack index
} }
// In any case, I have to increase the counter // In any case, I have to increase the counter
nextNotifiableStackIndex++; nextNotifiableStackIndex++;
} else { } else {
// Not yet time to show the modal - schedule the method again, and try again later // Not yet time to show the modal - schedule the method again, and try again later
Runnable tryAgainThread = new Runnable() { Runnable tryAgainThread = new Runnable() {
@Override @Override
@@ -1355,8 +1373,8 @@ public final class CMatchUI
} }
}; };
GuiBase.getInterface().invokeInEdtLater(tryAgainThread); GuiBase.getInterface().invokeInEdtLater(tryAgainThread);
} }
} }
private List<GameEntityView> getTargets(SpellAbilityStackInstance si, List<GameEntityView> result){ private List<GameEntityView> getTargets(SpellAbilityStackInstance si, List<GameEntityView> result){
@@ -1380,22 +1398,22 @@ public final class CMatchUI
return getTargets(si.getSubInstance(),result); return getTargets(si.getSubInstance(),result);
} }
private void addBigImageToStackModalPanel(JPanel mainPanel, SpellAbilityStackInstance si) { private void addBigImageToStackModalPanel(JPanel mainPanel, SpellAbilityStackInstance si) {
StackItemView siv = si.getView(); StackItemView siv = si.getView();
int rotation = getRotation(si.getCardView()); int rotation = getRotation(si.getCardView());
FImagePanel imagePanel = new FImagePanel(); FImagePanel imagePanel = new FImagePanel();
BufferedImage bufferedImage = FImageUtil.getImage(siv.getSourceCard().getCurrentState()); BufferedImage bufferedImage = FImageUtil.getImage(siv.getSourceCard().getCurrentState());
imagePanel.setImage(bufferedImage, rotation, AutoSizeImageMode.SOURCE); imagePanel.setImage(bufferedImage, rotation, AutoSizeImageMode.SOURCE);
int imageWidth = 433; int imageWidth = 433;
int imageHeight = 600; int imageHeight = 600;
Dimension imagePanelDimension = new Dimension(imageWidth,imageHeight); Dimension imagePanelDimension = new Dimension(imageWidth,imageHeight);
imagePanel.setMinimumSize(imagePanelDimension); 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) { private void addTextToStackModalPanel(JPanel mainPanel, SpellAbility sa, SpellAbilityStackInstance si) {
String who = sa.getActivatingPlayer().getName(); String who = sa.getActivatingPlayer().getName();
String action = sa.isSpell() ? " cast " : sa.isTrigger() ? " triggered " : " activated "; String action = sa.isSpell() ? " cast " : sa.isTrigger() ? " triggered " : " activated ";
@@ -1409,45 +1427,45 @@ public final class CMatchUI
TargetChoices targets = si.getTargetChoices(); TargetChoices targets = si.getTargetChoices();
sb.append(targets); sb.append(targets);
} }
sb.append("."); sb.append(".");
String message1 = sb.toString(); String message1 = sb.toString();
String message2 = si.getStackDescription(); String message2 = si.getStackDescription();
String messageTotal = message1 + "\n\n" + message2; String messageTotal = message1 + "\n\n" + message2;
final FTextArea prompt1 = new FTextArea(messageTotal); final FTextArea prompt1 = new FTextArea(messageTotal);
prompt1.setFont(FSkin.getFont(21)); prompt1.setFont(FSkin.getFont(21));
prompt1.setAutoSize(true); prompt1.setAutoSize(true);
prompt1.setMinimumSize(new Dimension(475,200)); 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) { private void addSmallImageToStackModalPanel(GameEntityView gameEntityView, JPanel mainPanel, int numTarget) {
if(gameEntityView instanceof CardView) { if(gameEntityView instanceof CardView) {
CardView cardView = (CardView) gameEntityView; CardView cardView = (CardView) gameEntityView;
int currRotation = getRotation(cardView); int currRotation = getRotation(cardView);
FImagePanel targetPanel = new FImagePanel(); FImagePanel targetPanel = new FImagePanel();
BufferedImage bufferedImage = FImageUtil.getImage(cardView.getCurrentState()); BufferedImage bufferedImage = FImageUtil.getImage(cardView.getCurrentState());
targetPanel.setImage(bufferedImage, currRotation, AutoSizeImageMode.SOURCE); targetPanel.setImage(bufferedImage, currRotation, AutoSizeImageMode.SOURCE);
int imageWidth = 217; int imageWidth = 217;
int imageHeight = 300; int imageHeight = 300;
Dimension targetPanelDimension = new Dimension(imageWidth,imageHeight); Dimension targetPanelDimension = new Dimension(imageWidth,imageHeight);
targetPanel.setMinimumSize(targetPanelDimension); 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) { } else if(gameEntityView instanceof PlayerView) {
PlayerView playerView = (PlayerView) gameEntityView; PlayerView playerView = (PlayerView) gameEntityView;
SkinImage playerAvatar = getPlayerAvatar(playerView, 0); SkinImage playerAvatar = getPlayerAvatar(playerView, 0);
final FLabel lblIcon = new FLabel.Builder().icon(playerAvatar).build(); final FLabel lblIcon = new FLabel.Builder().icon(playerAvatar).build();
Dimension dimension = playerAvatar.getSizeForPaint(JOptionPane.getRootFrame().getGraphics()); 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) { private int getRotation(CardView cardView) {
final int rotation; final int rotation;
if (cardView.isSplitCard()) { if (cardView.isSplitCard()) {
String cardName = cardView.getName(); String cardName = cardView.getName();
if (cardName.isEmpty()) { cardName = cardView.getAlternateState().getName(); } if (cardName.isEmpty()) { cardName = cardView.getAlternateState().getName(); }
PaperCard pc = StaticData.instance().getCommonCards().getCard(cardName); PaperCard pc = StaticData.instance().getCommonCards().getCard(cardName);
boolean hasKeywordAftermath = pc != null && Card.getCardForUi(pc).hasKeyword(Keyword.AFTERMATH); boolean hasKeywordAftermath = pc != null && Card.getCardForUi(pc).hasKeyword(Keyword.AFTERMATH);
@@ -1459,7 +1477,7 @@ public final class CMatchUI
return rotation; return rotation;
} }
@Override @Override
public void notifyStackRemoval(GameEventSpellRemovedFromStack event) { public void notifyStackRemoval(GameEventSpellRemovedFromStack event) {
// I always decrease the counter // I always decrease the counter
@@ -1474,49 +1492,49 @@ public final class CMatchUI
createLandPopupPanel(land); createLandPopupPanel(land);
} }
}; };
GuiBase.getInterface().invokeInEdtAndWait(createPopupThread); GuiBase.getInterface().invokeInEdtAndWait(createPopupThread);
} }
private void createLandPopupPanel(Card land) { private void createLandPopupPanel(Card land) {
String landPlayedNotificationPolicy = FModel.getPreferences().getPref(FPref.UI_LAND_PLAYED_NOTIFICATION_POLICY); String landPlayedNotificationPolicy = FModel.getPreferences().getPref(FPref.UI_LAND_PLAYED_NOTIFICATION_POLICY);
Player cardController = land.getController(); Player cardController = land.getController();
boolean isAi = cardController.isAI(); boolean isAi = cardController.isAI();
if(ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS.equals(landPlayedNotificationPolicy) if(ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS.equals(landPlayedNotificationPolicy)
|| (ForgeConstants.LAND_PLAYED_NOTIFICATION_AI.equals(landPlayedNotificationPolicy) && (isAi)) || (ForgeConstants.LAND_PLAYED_NOTIFICATION_AI.equals(landPlayedNotificationPolicy) && (isAi))
|| (ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS_FOR_NONBASIC_LANDS.equals(landPlayedNotificationPolicy) && !land.isBasicLand()) || (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)) { || (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")); List<String> options = ImmutableList.of(Localizer.getInstance().getMessage("lblOK"));
MigLayout migLayout = new MigLayout("insets 15, left, gap 30, fill"); MigLayout migLayout = new MigLayout("insets 15, left, gap 30, fill");
JPanel mainPanel = new JPanel(migLayout); JPanel mainPanel = new JPanel(migLayout);
final Dimension parentSize = JOptionPane.getRootFrame().getSize(); final Dimension parentSize = JOptionPane.getRootFrame().getSize();
Dimension maxSize = new Dimension(1400, parentSize.height - 100); Dimension maxSize = new Dimension(1400, parentSize.height - 100);
mainPanel.setMaximumSize(maxSize); mainPanel.setMaximumSize(maxSize);
mainPanel.setOpaque(false); mainPanel.setOpaque(false);
int rotation = getRotation(land.getView()); int rotation = getRotation(land.getView());
FImagePanel imagePanel = new FImagePanel(); FImagePanel imagePanel = new FImagePanel();
BufferedImage bufferedImage = FImageUtil.getImage(land.getCurrentState().getView()); BufferedImage bufferedImage = FImageUtil.getImage(land.getCurrentState().getView());
imagePanel.setImage(bufferedImage, rotation, AutoSizeImageMode.SOURCE); imagePanel.setImage(bufferedImage, rotation, AutoSizeImageMode.SOURCE);
int imageWidth = 433; int imageWidth = 433;
int imageHeight = 600; int imageHeight = 600;
Dimension imagePanelDimension = new Dimension(imageWidth,imageHeight); Dimension imagePanelDimension = new Dimension(imageWidth,imageHeight);
imagePanel.setMinimumSize(imagePanelDimension); imagePanel.setMinimumSize(imagePanelDimension);
mainPanel.add(imagePanel, "cell 0 0, spany 3"); 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); final FTextArea prompt1 = new FTextArea(msg);
prompt1.setFont(FSkin.getFont(21)); prompt1.setFont(FSkin.getFont(21));
prompt1.setAutoSize(true); prompt1.setAutoSize(true);
prompt1.setMinimumSize(new Dimension(475,200)); prompt1.setMinimumSize(new Dimension(475,200));
mainPanel.add(prompt1, "cell 1 0, aligny top"); mainPanel.add(prompt1, "cell 1 0, aligny top");
FOptionPane.showOptionDialog(null, title, null, mainPanel, options); FOptionPane.showOptionDialog(null, title, null, mainPanel, options);
} }
} }
} }

View File

@@ -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;
}
}

View File

@@ -146,6 +146,12 @@ public class PlayerControllerForTests extends PlayerController {
throw new IllegalStateException("Erring on the side of caution here..."); 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 @Override
public Integer announceRequirements(SpellAbility ability, String announce) { public Integer announceRequirements(SpellAbility ability, String announce) {
throw new IllegalStateException("Erring on the side of caution here..."); throw new IllegalStateException("Erring on the side of caution here...");

View File

@@ -49,6 +49,7 @@ import forge.model.FModel;
import forge.player.PlayerZoneUpdate; import forge.player.PlayerZoneUpdate;
import forge.player.PlayerZoneUpdates; import forge.player.PlayerZoneUpdates;
import forge.screens.match.views.VAssignCombatDamage; import forge.screens.match.views.VAssignCombatDamage;
import forge.screens.match.views.VAssignGenericAmount;
import forge.screens.match.views.VPhaseIndicator; import forge.screens.match.views.VPhaseIndicator;
import forge.screens.match.views.VPhaseIndicator.PhaseLabel; import forge.screens.match.views.VPhaseIndicator.PhaseLabel;
import forge.screens.match.views.VPlayerPanel; import forge.screens.match.views.VPlayerPanel;
@@ -395,6 +396,18 @@ public class MatchController extends AbstractGuiGame {
}.invokeAndWait(); }.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 @Override
public void updateManaPool(final Iterable<PlayerView> manaPoolUpdate) { public void updateManaPool(final Iterable<PlayerView> manaPoolUpdate) {
for (final PlayerView p : manaPoolUpdate) { for (final PlayerView p : manaPoolUpdate) {

View File

@@ -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;
}
}

View 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.

View 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.

View 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.

View 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.

View File

@@ -361,6 +361,15 @@ lblTotalDamageText=Gesamtschaden: Unbekannt
lblAssignRemainingText=Verteile verbleibenden Schaden unter tödlich Verwundeten lblAssignRemainingText=Verteile verbleibenden Schaden unter tödlich Verwundeten
lblLethal=Tödlich lblLethal=Tödlich
lblAvailableDamagePoints=Verfügbare Schadenspunkte 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 #KeyboardShortcuts.java
lblSHORTCUT_SHOWSTACK=Duell: Zeige Stapelfenster lblSHORTCUT_SHOWSTACK=Duell: Zeige Stapelfenster
lblSHORTCUT_SHOWCOMBAT=Duell: Zeige Kampffenster lblSHORTCUT_SHOWCOMBAT=Duell: Zeige Kampffenster
@@ -416,7 +425,7 @@ lblSelectOpponentDeck=Wähle das Deck des Gegners
lblGenerateNewDeck=Erzeuge ein neues Deck lblGenerateNewDeck=Erzeuge ein neues Deck
lblRandomTheme=Zufälliges Deck lblRandomTheme=Zufälliges Deck
lblTestDeck=Teste Deck lblTestDeck=Teste Deck
lblLoading=Lade lblLoading=Lade
#GameType.java #GameType.java
lblSealed=Sealed lblSealed=Sealed
lblDraft=Draft lblDraft=Draft
@@ -1131,7 +1140,7 @@ lblSwipeUpTo=Wische hoch für %s
lblSwipeDownDetailView=Wische runter für Detailansicht lblSwipeDownDetailView=Wische runter für Detailansicht
lblSwipeDownPictureView=Wische runter für Bildansicht lblSwipeDownPictureView=Wische runter für Bildansicht
#VGameMenu.java #VGameMenu.java
lblShowWinLoseOverlay=Zeige Sieg/Verlust-Anzeige lblShowWinLoseOverlay=Zeige Sieg/Verlust-Anzeige
lblNoPlayerPriorityNoDeckListViewed=Kein Spieler hat Priorität, daher keine Decklistenanzeige möglich. lblNoPlayerPriorityNoDeckListViewed=Kein Spieler hat Priorität, daher keine Decklistenanzeige möglich.
#FilesPage.java #FilesPage.java
lblFiles=Dateien lblFiles=Dateien
@@ -2276,7 +2285,7 @@ lblConquestName=Eroberung-Name
#HumanCostDecision.java #HumanCostDecision.java
lblChooseXValueForCard={0} - Wähle Wert für X lblChooseXValueForCard={0} - Wähle Wert für X
lblSelectOneSameNameCardToDiscardAlreadyChosen=Wähle eine Karte mit dem gleichen Namen zum Abwerfen. Bereits gewählt: 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. lblSelectNMoreTargetTypeCardToDiscard=Wähle {0} weitere {1} zum Abwerfen.
lblDoYouWantCardDealNDamageToYou=Möchtest du, daß {0} dir {1} Schaden zufügt? lblDoYouWantCardDealNDamageToYou=Möchtest du, daß {0} dir {1} Schaden zufügt?
lblDrawNCardsConfirm=Ziehe {0} Karte(n)? lblDrawNCardsConfirm=Ziehe {0} Karte(n)?
@@ -2672,7 +2681,7 @@ lblDetectedInvalidHostAddress=Ungültige Host-Adresse ({0}) wurde festgestellt.
#Player.java #Player.java
lblChooseACompanion=Wähle einen Gefährten lblChooseACompanion=Wähle einen Gefährten
lblChooseAColorFor=Wähle eine Farbe für {0} lblChooseAColorFor=Wähle eine Farbe für {0}
lblRevealFaceDownCards=Enthülle verdeckte Karten von lblRevealFaceDownCards=Enthülle verdeckte Karten von
lblLearnALesson=Lerne eine Lektion lblLearnALesson=Lerne eine Lektion
#QuestPreferences.java #QuestPreferences.java
lblWildOpponentNumberError=Anzahl der Wild-Gegner kann nur 0 bis 3 sein lblWildOpponentNumberError=Anzahl der Wild-Gegner kann nur 0 bis 3 sein

View File

@@ -18,8 +18,8 @@ lblerrLoadingLayoutFile=Your %s layout file could not be read. It will be delete
lblLoadingQuest=Loading quest... lblLoadingQuest=Loading quest...
#FScreen.java #FScreen.java
#translate lblHomeWithSpaces,lblDeckEditorWithSpaces need keep spaces in text #translate lblHomeWithSpaces,lblDeckEditorWithSpaces need keep spaces in text
lblHomeWithSpaces=Home lblHomeWithSpaces=Home
lblDeckEditorWithSpaces=Deck Editor lblDeckEditorWithSpaces=Deck Editor
lblWorkshop=Workshop lblWorkshop=Workshop
lblBacktoHome=Back to Home lblBacktoHome=Back to Home
lblCloseEditor=Close Editor lblCloseEditor=Close Editor
@@ -52,7 +52,7 @@ btnResetJavaFutureCompatibilityWarnings=Reset Java Compatibility Warnings
btnClearImageCache=Clear Image Cache btnClearImageCache=Clear Image Cache
btnTokenPreviewer=Token Previewer btnTokenPreviewer=Token Previewer
btnCopyToClipboard=Copy to Clipboard btnCopyToClipboard=Copy to Clipboard
cbpAutoUpdater=Auto updater cbpAutoUpdater=Auto updater
nlAutoUpdater=Select the release channel to use for updating Forge nlAutoUpdater=Select the release channel to use for updating Forge
cbpSelectLanguage=Language cbpSelectLanguage=Language
nlSelectLanguage=Select Language (Excluded Game part. Still a work in progress) (RESTART REQUIRED) 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 lblAssignRemainingText=Distribute the remaining damage points among lethally wounded entities
lblLethal=Lethal lblLethal=Lethal
lblAvailableDamagePoints=Available damage points 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 #KeyboardShortcuts.java
lblSHORTCUT_SHOWSTACK=Match: show stack panel lblSHORTCUT_SHOWSTACK=Match: show stack panel
lblSHORTCUT_SHOWCOMBAT=Match: show combat panel lblSHORTCUT_SHOWCOMBAT=Match: show combat panel
@@ -416,7 +425,7 @@ lblSelectOpponentDeck=Select Opponent''s Deck
lblGenerateNewDeck=Generate New Deck lblGenerateNewDeck=Generate New Deck
lblRandomTheme=Random Theme lblRandomTheme=Random Theme
lblTestDeck=Test Deck lblTestDeck=Test Deck
lblLoading=Loading lblLoading=Loading
#GameType.java #GameType.java
lblSealed=Sealed lblSealed=Sealed
lblDraft=Draft 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. ttWinsperDraftRotation=If a Draft is not played for this many match wins, it will be removed or replaced.
lblRotationType=Rotation Type lblRotationType=Rotation Type
ttRotationType=If set to 0, old drafts disappear, if set to 1, they are replaced with another one using different sets. 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 lblWildOpponentNumber=Number of Wild Opponents
lblWildOpponentMultiplier=Wild Multiplier lblWildOpponentMultiplier=Wild Multiplier
#StatTypeFilter.java #StatTypeFilter.java
lblclicktotoogle=click to toggle the filter, right-click to show only lblclicktotoogle=click to toggle the filter, right-click to show only
#SItemManagerUtil.java #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. lblSelectBandingTarget= To attack as a band, select an attacking creature to activate its ''band'' then select another to join it.
#InputBlock.java #InputBlock.java
lblSelectBlockTarget=Select another attacker to declare blockers for. 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. lblOrSelectBlockTarget= or select another attacker to declare blockers for.
lblMorph=Morph lblMorph=Morph
#PlayerControllerHuman.java #PlayerControllerHuman.java
@@ -1569,9 +1578,9 @@ lblCreature=Creature
btnRestartRound=Restart Round btnRestartRound=Restart Round
btnTournamentInfo=Tournament Info btnTournamentInfo=Tournament Info
btnNextRound=Next Round btnNextRound=Next Round
btnWonRound=YOU HAVE WON ROUND btnWonRound=YOU HAVE WON ROUND
btnWonTournament=***CONGRATULATIONS! YOU HAVE WON THE TOURNAMENT!*** btnWonTournament=***CONGRATULATIONS! YOU HAVE WON THE TOURNAMENT!***
btnLoseRound=YOU HAVE LOST ON ROUND btnLoseRound=YOU HAVE LOST ON ROUND
btnQuit=Quit btnQuit=Quit
btnContinue=Continue btnContinue=Continue
btnRestart=Restart 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? 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? 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? lblReallyQuit=Really Quit?
lblForPlacing=For placing lblForPlacing=For placing
lblHaveBeAward=, you have been awarded lblHaveBeAward=, you have been awarded
lblTournamentReward=Tournament Reward lblTournamentReward=Tournament Reward
lblParticipateingTournamentReward=For participating in the tournament, you have been awarded the following promotional card: lblParticipateingTournamentReward=For participating in the tournament, you have been awarded the following promotional card:
lblCreditsAwarded=Credits Awarded lblCreditsAwarded=Credits Awarded
@@ -1608,22 +1617,22 @@ lblWouldLikeSaveDraft=Would you like to save this draft to the regular draft mod
lblSaveDraft=Save Draft lblSaveDraft=Save Draft
lblNoAvailableDraftsMessage=You do not have any draft-able sets unlocked!\nCome back later when you''ve unlocked more sets. lblNoAvailableDraftsMessage=You do not have any draft-able sets unlocked!\nCome back later when you''ve unlocked more sets.
lblNoAvailableDrafts=No Available Drafts 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? lblWouldLikeCreateTournament= credits.\nWould you like to spend a token and create this tournament?
lblCreatingDraftTournament=Creating a Booster Draft 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. lblPleaseReportBug=. Please report this as a bug.
lbl1stPlace=1st Place: lbl1stPlace=1st Place:
lbl2ndPlace=2nd Place: lbl2ndPlace=2nd Place:
lbl3rdPlace=3rd Place: lbl3rdPlace=3rd Place:
lbl4thPlace=4th Place: lbl4thPlace=4th Place:
lblTime= time lblTime= time
lblCollectPrizes=Collect Prizes lblCollectPrizes=Collect Prizes
lblCurrentlyInDraft=You are currently in a draft.\nYou should leave or finish that draft before starting another. 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. lblMoreCredits=more credits to enter this tournament.
lblNotEnoughCredits=Not Enough Credits lblNotEnoughCredits=Not Enough Credits
lblTournamentCosts=This tournament costs lblTournamentCosts=This tournament costs
lblSureEnterTournament= credits to enter.\nAre you sure you wish to enter? lblSureEnterTournament= credits to enter.\nAre you sure you wish to enter?
lblEnterDraftTournament=Enter Draft Tournament? 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? 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 lblWinsForMediumAI=Wins For Medium AI
lblWinsForHardAI=Wins For Hard AI lblWinsForHardAI=Wins For Hard AI
lblWinsForExpertAI=Wins For Expert AI lblWinsForExpertAI=Wins For Expert AI
lblSaveFailed=Save Failed - lblSaveFailed=Save Failed -
#QuestSpellShopScreen.java #QuestSpellShopScreen.java
lblMaximumSellingCredits=Maximum selling price is %d credits. lblMaximumSellingCredits=Maximum selling price is %d credits.
lblSellCardsAt=Selling cards at lblSellCardsAt=Selling cards at
@@ -2274,8 +2283,8 @@ lblHistoriiansWillRecallYourConquestAs=Historians will recall your conquest as:
lblConquestName=Conquest Name lblConquestName=Conquest Name
#HumanCostDecision.java #HumanCostDecision.java
lblChooseXValueForCard={0} - Choose a Value for X lblChooseXValueForCard={0} - Choose a Value for X
lblSelectOneSameNameCardToDiscardAlreadyChosen=Select one of the cards with the same 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: lblSelectOneDifferentNameCardToDiscardAlreadyChosen=Select one of the cards with a different name to discard. Already chosen:
lblSelectNMoreTargetTypeCardToDiscard=Select {0} more {1} to discard. lblSelectNMoreTargetTypeCardToDiscard=Select {0} more {1} to discard.
lblDoYouWantCardDealNDamageToYou=Do you want {0} to deal {1} damage to you? lblDoYouWantCardDealNDamageToYou=Do you want {0} to deal {1} damage to you?
lblDrawNCardsConfirm=Draw {0} Card(s)? 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} lblRemoveCountersFromAInZoneCard=Remove counter(s) from a card in {0}
lblSacrificeCardConfirm=Sacrifice {0}? lblSacrificeCardConfirm=Sacrifice {0}?
lblSelectATargetToSacrifice=Select a {0} to sacrifice ({1} left) 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. lblSelectACreatureToTap=Select a creature to tap.
lblEnoughValidCardNotToPayTheCost=Not enough valid cards left to tap to pay the cost. lblEnoughValidCardNotToPayTheCost=Not enough valid cards left to tap to pay the cost.
lblCostPaymentInvalid=Cost payment invalid lblCostPaymentInvalid=Cost payment invalid
@@ -2671,7 +2680,7 @@ lblDetectedInvalidHostAddress=Invalid host address ({0}) was detected.
#Player.java #Player.java
lblChooseACompanion=Choose a companion lblChooseACompanion=Choose a companion
lblChooseAColorFor=Choose a color for {0} lblChooseAColorFor=Choose a color for {0}
lblRevealFaceDownCards=Revealing face-down cards from lblRevealFaceDownCards=Revealing face-down cards from
lblLearnALesson=Learn a Lesson lblLearnALesson=Learn a Lesson
#QuestPreferences.java #QuestPreferences.java
lblWildOpponentNumberError=Wild Opponents can only be 0 to 3 lblWildOpponentNumberError=Wild Opponents can only be 0 to 3

View File

@@ -18,8 +18,8 @@ lblerrLoadingLayoutFile=No se pudo leer el archivo de diseño %s. Se eliminará
lblLoadingQuest=Cargando datos de aventura.... lblLoadingQuest=Cargando datos de aventura....
#FScreen.java #FScreen.java
#translate lblHomeWithSpaces,lblDeckEditorWithSpaces need keep spaces in text #translate lblHomeWithSpaces,lblDeckEditorWithSpaces need keep spaces in text
lblHomeWithSpaces=Inicio lblHomeWithSpaces=Inicio
lblDeckEditorWithSpaces=Editor de mazos lblDeckEditorWithSpaces=Editor de mazos
lblWorkshop=Taller lblWorkshop=Taller
lblBacktoHome=Volver a Inicio lblBacktoHome=Volver a Inicio
lblCloseEditor=Cerrar editor 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. lblAssignRemainingText=Distribuye los puntos de daño restantes entre las entidades letalmente heridas.
lblLethal=Letal lblLethal=Letal
lblAvailableDamagePoints=Puntos de daño disponibles 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 #KeyboardShortcuts.java
lblSHORTCUT_SHOWSTACK=Partida: mostrar panel de pila lblSHORTCUT_SHOWSTACK=Partida: mostrar panel de pila
lblSHORTCUT_SHOWCOMBAT=Partida: mostrar panel de combate lblSHORTCUT_SHOWCOMBAT=Partida: mostrar panel de combate
@@ -416,7 +425,7 @@ lblSelectOpponentDeck=Seleccionar mazo del oponente
lblGenerateNewDeck=Generar nuevo mazo lblGenerateNewDeck=Generar nuevo mazo
lblRandomTheme=Tema aleatorio lblRandomTheme=Tema aleatorio
lblTestDeck=Probar mazo lblTestDeck=Probar mazo
lblLoading=Cargando lblLoading=Cargando
#GameType.java #GameType.java
lblSealed=Sellado lblSealed=Sellado
lblDraft=Draft 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á. ttWinsperDraftRotation=Si no se juega un Draft para esta cantidad de victorias, se eliminará o reemplazará.
lblRotationType=Tipo de rotación 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. 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 lblWildOpponentNumber=Número de oponentes salvajes
lblWildOpponentMultiplier=Multiplicador salvaje lblWildOpponentMultiplier=Multiplicador salvaje
#StatTypeFilter.java #StatTypeFilter.java
lblclicktotoogle=haz clic para alternar el filtro, haz clic con el botón derecho para solo mostrar lblclicktotoogle=haz clic para alternar el filtro, haz clic con el botón derecho para solo mostrar
#SItemManagerUtil.java #SItemManagerUtil.java
@@ -1569,9 +1578,9 @@ lblCreature=Criatura
btnRestartRound=Reiniciar ronda btnRestartRound=Reiniciar ronda
btnTournamentInfo=Info del torneo btnTournamentInfo=Info del torneo
btnNextRound=Siguiente ronda btnNextRound=Siguiente ronda
btnWonRound=HAS GANADO LA RONDA btnWonRound=HAS GANADO LA RONDA
btnWonTournament=***¡FELICIDADES! ¡HAS GANADO EL TORNEO!*** btnWonTournament=***¡FELICIDADES! ¡HAS GANADO EL TORNEO!***
btnLoseRound=HAS PERDIDO EN LA RONDA btnLoseRound=HAS PERDIDO EN LA RONDA
btnQuit=Salir btnQuit=Salir
btnContinue=Continuar btnContinue=Continuar
btnRestart=Reiniciar 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? 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? 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? lblReallyQuit=¿Realmente quieres abandonar?
lblForPlacing=Para colocar lblForPlacing=Para colocar
lblHaveBeAward=, has sido premiado lblHaveBeAward=, has sido premiado
lblTournamentReward=Recompensa del Torneo lblTournamentReward=Recompensa del Torneo
lblParticipateingTournamentReward=Por participar en el torneo, se le ha premiado con la siguiente carta promocional: lblParticipateingTournamentReward=Por participar en el torneo, se le ha premiado con la siguiente carta promocional:
lblCreditsAwarded=Créditos ganados lblCreditsAwarded=Créditos ganados
@@ -1608,22 +1617,22 @@ lblWouldLikeSaveDraft=¿Te gustaría guardar este Draft en el modo de draft norm
lblSaveDraft=Guardar Draft lblSaveDraft=Guardar Draft
lblNoAvailableDraftsMessage=¡No tienes ningún set de draft desbloqueado!\nVuelve más tarde cuando hayas desbloqueado más ediciones. lblNoAvailableDraftsMessage=¡No tienes ningún set de draft desbloqueado!\nVuelve más tarde cuando hayas desbloqueado más ediciones.
lblNoAvailableDrafts=No hay Drafts disponibles 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? lblWouldLikeCreateTournament= créditos.\n¿Te gustaría gastar una ficha y crear este torneo?
lblCreatingDraftTournament=Creación de un Torneo de Booster Draft 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. lblPleaseReportBug=. Por favor, informe de esto como un error.
lbl1stPlace=1er Puesto: lbl1stPlace=1er Puesto:
lbl2ndPlace=2o Puesto: lbl2ndPlace=2o Puesto:
lbl3rdPlace=3er Puesto: lbl3rdPlace=3er Puesto:
lbl4thPlace=4o Puesto: lbl4thPlace=4o Puesto:
lblTime= veces lblTime= veces
lblCollectPrizes=Recoger Premios lblCollectPrizes=Recoger Premios
lblCurrentlyInDraft=Actualmente estás en un draft.\nDeberías dejar o terminar ese draft antes de empezar otro. 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. lblMoreCredits=créditos más para entrar en este torneo.
lblNotEnoughCredits=No hay suficientes créditos 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? lblSureEnterTournament= créditos para entrar.\n¿Está seguro de que desea entrar?
lblEnterDraftTournament=¿Entrar en el Torneo de Draft? 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? 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 lblWinsForMediumAI=Ganancias para la IA media
lblWinsForHardAI=Ganancias para la IA difícil lblWinsForHardAI=Ganancias para la IA difícil
lblWinsForExpertAI=Ganancias para la IA experta lblWinsForExpertAI=Ganancias para la IA experta
lblSaveFailed=Error al Guardar - lblSaveFailed=Error al Guardar -
#QuestSpellShopScreen.java #QuestSpellShopScreen.java
lblMaximumSellingCredits=El precio máximo de venta es de %d créditos. lblMaximumSellingCredits=El precio máximo de venta es de %d créditos.
lblSellCardsAt=Vender cartas a 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}? lblPutThatCardFromPlayerOriginToDestination=¿Poner esa carta desde {0} {1} hasta {2}?
lblSearchPlayerZoneConfirm=¿Buscar {0} {1}? lblSearchPlayerZoneConfirm=¿Buscar {0} {1}?
lblCardMatchSearchingTypeInAlternateZones=las cartas coinciden con tu tipo de búsqueda en las zonas alternativas. 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}? lblDoYouWantPlayCard=¿Quieres jugar {0}?
lblSelectCardFromPlayerZone=Selecciona una carta de {0} {1} lblSelectCardFromPlayerZone=Selecciona una carta de {0} {1}
lblSelectUpToNumCardFromPlayerZone=Selecciona hasta {0} cartas de {1} {2} 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} 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} 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} 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 lblNoValidCards=No hay cartas válidas
#DigUntilEffect.java #DigUntilEffect.java
lblDoYouWantDigYourLibrary=¿Quieres escarbar en tu biblioteca? 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)? lblDrawNCardsConfirm=¿Robar {0} carta(s)?
lblExileConfirm=¿Exiliar {0}? lblExileConfirm=¿Exiliar {0}?
lblExileNCardsFromYourZone=Exilia {0} carta(s) de tu {1} 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} lblExileProgressFromZone=Exilia {0}/{1} de {2}
lblToBeExiled=Para ser exiliado lblToBeExiled=Para ser exiliado
lblExileFromStack=Exiliar de la pila 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} lblRemoveCountersFromAInZoneCard=Quitar contador(es) de una carta en {0}
lblSacrificeCardConfirm=¿Sacrificar {0}? lblSacrificeCardConfirm=¿Sacrificar {0}?
lblSelectATargetToSacrifice=Selecciona un {0} para sacrificar ({1} pendiente) 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. lblSelectACreatureToTap=Selecciona una criatura para girar.
lblEnoughValidCardNotToPayTheCost=No quedan suficientes cartas válidas para girar para pagar el coste. lblEnoughValidCardNotToPayTheCost=No quedan suficientes cartas válidas para girar para pagar el coste.
lblCostPaymentInvalid=Pago del coste no válido lblCostPaymentInvalid=Pago del coste no válido
@@ -2570,7 +2579,7 @@ lblRecordAndAssets=Registro | Bienes
lblXWinOfYLost={0} G/{1} P lblXWinOfYLost={0} G/{1} P
lblDeleteThisQuest=Eliminar esta aventura lblDeleteThisQuest=Eliminar esta aventura
lblRenameThisQuest=Renombrar esta aventura lblRenameThisQuest=Renombrar esta aventura
lblRenameQuestTo=Renombrar aventura como lblRenameQuestTo=Renombrar aventura como
lblQuestRename=Renombrar aventura lblQuestRename=Renombrar aventura
#StartingPoolType.java #StartingPoolType.java
lblUnrestricted=Sin restriciones lblUnrestricted=Sin restriciones
@@ -2671,7 +2680,7 @@ lblDetectedInvalidHostAddress=Dirección de host inválida ({0}) detectada.
#Player.java #Player.java
lblChooseACompanion=Elige un compañero lblChooseACompanion=Elige un compañero
lblChooseAColorFor=Elige un color para {0} lblChooseAColorFor=Elige un color para {0}
lblRevealFaceDownCards=Mostrar cartas boca abajo de lblRevealFaceDownCards=Mostrar cartas boca abajo de
lblLearnALesson=Learn a Lesson lblLearnALesson=Learn a Lesson
#QuestPreferences.java #QuestPreferences.java
lblWildOpponentNumberError=Los oponentes salvajes sólo pueden ser de 0 a 3 lblWildOpponentNumberError=Los oponentes salvajes sólo pueden ser de 0 a 3

View File

@@ -18,8 +18,8 @@ lblerrLoadingLayoutFile=Impossibile leggere il file di layout %s. Verrà elimina
lblLoadingQuest=Caricamento avevntura ... lblLoadingQuest=Caricamento avevntura ...
#FScreen.java #FScreen.java
#translate lblHomeWithSpaces,lblDeckEditorWithSpaces need keep spaces in text #translate lblHomeWithSpaces,lblDeckEditorWithSpaces need keep spaces in text
lblHomeWithSpaces=Home lblHomeWithSpaces=Home
lblDeckEditorWithSpaces=Gestione dei mazzi lblDeckEditorWithSpaces=Gestione dei mazzi
lblWorkshop=Officina lblWorkshop=Officina
lblBacktoHome=Torna a Home lblBacktoHome=Torna a Home
lblCloseEditor=Esci dalla gestione 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 lblAssignRemainingText=Distribuire i punti di danno rimanenti tra le entità ferite letalmente
lblLethal=Letale lblLethal=Letale
lblAvailableDamagePoints=Punti danno disponibili 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 #KeyboardShortcuts.java
lblSHORTCUT_SHOWSTACK=Incontro: mostra il pannello della pila lblSHORTCUT_SHOWSTACK=Incontro: mostra il pannello della pila
lblSHORTCUT_SHOWCOMBAT=Incontro: mostra il pannello di combattimento 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 lblCreatingDraftTournament=Creazione del torneo Booster Draft
lblUnexpectedCreatingDraftTournament=Errore inaspettato durante la creazione del torneo lblUnexpectedCreatingDraftTournament=Errore inaspettato durante la creazione del torneo
lblPleaseReportBug=. Per favore segnala il bug. lblPleaseReportBug=. Per favore segnala il bug.
lbl1stPlace=Primo posto: lbl1stPlace=Primo posto:
lbl2ndPlace=Secondo posto: lbl2ndPlace=Secondo posto:
lbl3rdPlace=Terzo posto: lbl3rdPlace=Terzo posto:
lbl4thPlace=Quarto posto: lbl4thPlace=Quarto posto:
lblTime= tempo lblTime= tempo
lblCollectPrizes=Ricevi i premi lblCollectPrizes=Ricevi i premi
lblCurrentlyInDraft=Stai partecipando a un draft.\nDevi terminare o abbandonare quel draft prima di iniziarne un altro. 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 lblWinsForMediumAI=Numero di vittorie per IA livello Apprendista
lblWinsForHardAI=Numero di vittorie per IA livello Esperto lblWinsForHardAI=Numero di vittorie per IA livello Esperto
lblWinsForExpertAI=Numero di vittorie per IA livello Maestro lblWinsForExpertAI=Numero di vittorie per IA livello Maestro
lblSaveFailed=Salvataggio fallito - lblSaveFailed=Salvataggio fallito -
#QuestSpellShopScreen.java #QuestSpellShopScreen.java
lblMaximumSellingCredits=Il prezzo massimo di vendita è di %d monete. lblMaximumSellingCredits=Il prezzo massimo di vendita è di %d monete.
lblSellCardsAt=Carte in vendita al lblSellCardsAt=Carte in vendita al
lblTheirValue=% del loro valore.\n lblTheirValue=% del loro valore.\n
lblSell=Vendi lblSell=Vendi
lblItem=oggetto lblItem=oggetto
@@ -2274,7 +2283,7 @@ lblHistoriiansWillRecallYourConquestAs=Gli storici ricorderanno la tua Conquista
lblConquestName=Nome della Conquista lblConquestName=Nome della Conquista
#HumanCostDecision.java #HumanCostDecision.java
lblChooseXValueForCard={0} - Scegli un valore per X 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: lblSelectOneDifferentNameCardToDiscardAlreadyChosen=Seleziona una delle carte con un nome diverso da scartare. Già scelto:
lblSelectNMoreTargetTypeCardToDiscard=Seleziona altre{0} {1} da scartare. lblSelectNMoreTargetTypeCardToDiscard=Seleziona altre{0} {1} da scartare.
lblDoYouWantCardDealNDamageToYou=Vuoi che {0} ti infligga {1} danno/i? 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} lblRemoveCountersFromAInZoneCard=Rimuovi segnalini da una carta in {0}
lblSacrificeCardConfirm=Vuoi sacrificare {0}? lblSacrificeCardConfirm=Vuoi sacrificare {0}?
lblSelectATargetToSacrifice=Seleziona una carta {0} da scarificare ({1} rimasta/e) 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. lblSelectACreatureToTap=Seleziona una creatura da tappare.
lblEnoughValidCardNotToPayTheCost=Non sono rimaste abbastanza carte valide da tappare per pagare il costo lblEnoughValidCardNotToPayTheCost=Non sono rimaste abbastanza carte valide da tappare per pagare il costo
lblCostPaymentInvalid=Pagamento del costo non valido lblCostPaymentInvalid=Pagamento del costo non valido
@@ -2386,7 +2395,7 @@ lblHandOrLibraryOrGraveyard=mano, grimorio e cimitero
lblHandOrLibraryOrGraveyardOrBattlefield=mano, grimorio, cimitero e campo di battaglia lblHandOrLibraryOrGraveyardOrBattlefield=mano, grimorio, cimitero e campo di battaglia
#LifeToSpare.java #LifeToSpare.java
lblLifeToSpare=Vita da vendere 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 lblMoreThanStartedLifeN={0} punti vita in più di quelli con cui hai iniziato
#ManaFlooded.java #ManaFlooded.java
lblManaFlooded=Inondazione di mana lblManaFlooded=Inondazione di mana

View File

@@ -18,8 +18,8 @@ lblerrLoadingLayoutFile=%s レイアウトファイルを読み取れません
lblLoadingQuest=クエストを読み込んでいます... lblLoadingQuest=クエストを読み込んでいます...
#FScreen.java #FScreen.java
#translate lblHomeWithSpaces,lblDeckEditorWithSpaces need keep spaces in text #translate lblHomeWithSpaces,lblDeckEditorWithSpaces need keep spaces in text
lblHomeWithSpaces=ホーム lblHomeWithSpaces=ホーム
lblDeckEditorWithSpaces=デッキエディター lblDeckEditorWithSpaces=デッキエディター
lblWorkshop=ワークショップ lblWorkshop=ワークショップ
lblBacktoHome=ホームに戻る lblBacktoHome=ホームに戻る
lblCloseEditor=エディターを閉じる lblCloseEditor=エディターを閉じる
@@ -355,12 +355,21 @@ lblReset=リセット
lblAuto=自動 lblAuto=自動
#VAssignDamage.java #VAssignDamage.java
lbLAssignDamageDealtBy=%sによって与えられるダメージを割り当てます lbLAssignDamageDealtBy=%sによって与えられるダメージを割り当てます
lblLClickDamageMessage=左クリック1ダメージを割り当てます。 Ctrl + 左クリック):残りのダメージを致死まで割り当て lblLClickDamageMessage=左クリック1ダメージを割り当てます。 Ctrl + 左クリック):残りのダメージを致死まで割り当てます。
lblRClickDamageMessage=右クリック1ダメージの割り当てを解除します。 Ctrl + 右クリック):すべての損傷の割り当てを解除します。 lblRClickDamageMessage=右クリック1ダメージの割り当てを解除します。 Ctrl + 右クリック):すべてのダメージの割り当てを解除します。
lblTotalDamageText=利用可能なダメージポイント:不明 lblTotalDamageText=利用可能なダメージポイント:不明
lblAssignRemainingText=命傷を負ったエンティティに残りのダメージポイントを分配する lblAssignRemainingText=死ダメージを負ったオブジェクトに残りのダメージを割り当てます。
lblLethal=リーサル lblLethal=リーサル
lblAvailableDamagePoints=利用可能なダメージポイント 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 #KeyboardShortcuts.java
lblSHORTCUT_SHOWSTACK=スタックパネルを表示 lblSHORTCUT_SHOWSTACK=スタックパネルを表示
lblSHORTCUT_SHOWCOMBAT=戦闘パネルを表示 lblSHORTCUT_SHOWCOMBAT=戦闘パネルを表示
@@ -1039,7 +1048,7 @@ lblLog=ログ
lblDev=開発者 lblDev=開発者
lblCombatTab=戦闘 lblCombatTab=戦闘
lblStack=スタック lblStack=スタック
lblMustWaitPriority=優先権を待つ必要があります... lblMustWaitPriority=優先権を待つ必要があります...
#FDeckEditor.java #FDeckEditor.java
lblImportFromClipboard=クリップボードからインポート lblImportFromClipboard=クリップボードからインポート
lblSaveAs=名前を付けて保存... lblSaveAs=名前を付けて保存...
@@ -1075,7 +1084,7 @@ lblLoadingCardTranslations=カードの翻訳を読み込んでいます...
lblFinishingStartup=起動を終了しています... lblFinishingStartup=起動を終了しています...
lblPreloadExtendedArt=拡張アートのプリロード... lblPreloadExtendedArt=拡張アートのプリロード...
#LobbyScreen.java #LobbyScreen.java
lblMore=もっと... lblMore=もっと...
lblLoadingNewGame=新しいゲームを読み込んでいます... lblLoadingNewGame=新しいゲームを読み込んでいます...
lblSelectVariants=バリエーションを選択 lblSelectVariants=バリエーションを選択
msgSelectAdeckBeforeReadying=始まる前にデッキを選択してください! msgSelectAdeckBeforeReadying=始まる前にデッキを選択してください!
@@ -1624,7 +1633,7 @@ lblCurrentlyInDraft=今はドラフトを参加中です。\n新しいドラフ
lblYouNeed=このトーナメントを参加するにはもっと lblYouNeed=このトーナメントを参加するにはもっと
lblMoreCredits=のクレジットが必要です。 lblMoreCredits=のクレジットが必要です。
lblNotEnoughCredits=クレジット不足 lblNotEnoughCredits=クレジット不足
lblTournamentCosts=このトーナメントの参加費は lblTournamentCosts=このトーナメントの参加費は
lblSureEnterTournament=クレジットです。\n参加してもよろしいでしょうか lblSureEnterTournament=クレジットです。\n参加してもよろしいでしょうか
lblEnterDraftTournament=トーナメントに参加しますか? lblEnterDraftTournament=トーナメントに参加しますか?
lblLeaveDraftConfirm=これによりこのドラフトを終了して、再度参加することは出来ません。\n使ったクレジットは返金されて、そしてドラフトを削除します。\n\nそれでも退場しますか lblLeaveDraftConfirm=これによりこのドラフトを終了して、再度参加することは出来ません。\n使ったクレジットは返金されて、そしてドラフトを削除します。\n\nそれでも退場しますか
@@ -2275,8 +2284,8 @@ lblHistoriiansWillRecallYourConquestAs=歴史家たちはあなたの征服紀
lblConquestName=征服紀録名 lblConquestName=征服紀録名
#HumanCostDecision.java #HumanCostDecision.java
lblChooseXValueForCard={0} - Xの値を選択 lblChooseXValueForCard={0} - Xの値を選択
lblSelectOneSameNameCardToDiscardAlreadyChosen=同名カードを 1つ選んで捨てる。既に選択 lblSelectOneSameNameCardToDiscardAlreadyChosen=同名カードを 1つ選んで捨てる。既に選択
lblSelectOneDifferentNameCardToDiscardAlreadyChosen=違う名前のカードを 1つ選んで捨てる。既に選択 lblSelectOneDifferentNameCardToDiscardAlreadyChosen=違う名前のカードを 1つ選んで捨てる。既に選択
lblSelectNMoreTargetTypeCardToDiscard=もっと {0}枚の {1}を選んで捨てる。 lblSelectNMoreTargetTypeCardToDiscard=もっと {0}枚の {1}を選んで捨てる。
lblDoYouWantCardDealNDamageToYou={0}があなたに {1}点のダメージを与えてもいいですか? lblDoYouWantCardDealNDamageToYou={0}があなたに {1}点のダメージを与えてもいいですか?
lblDrawNCardsConfirm={0}枚のカードを引きますか? lblDrawNCardsConfirm={0}枚のカードを引きますか?

View File

@@ -18,8 +18,8 @@ lblerrLoadingLayoutFile=无法读取你的布局文件:%s。按OK然后删除
lblLoadingQuest=加载冒险之旅... lblLoadingQuest=加载冒险之旅...
#FScreen.java #FScreen.java
#翻译lblHomeWithSpaces,lblDeckEditorWithSpaces时需要保留翻译文本中的空格 #翻译lblHomeWithSpaces,lblDeckEditorWithSpaces时需要保留翻译文本中的空格
lblHomeWithSpaces=主页 lblHomeWithSpaces=主页
lblDeckEditorWithSpaces=套牌编辑器 lblDeckEditorWithSpaces=套牌编辑器
lblWorkshop=作坊页面 lblWorkshop=作坊页面
lblBacktoHome=回退到主页 lblBacktoHome=回退到主页
lblCloseEditor=关闭编辑器 lblCloseEditor=关闭编辑器
@@ -53,7 +53,7 @@ btnClearImageCache=清除图片缓存
btnTokenPreviewer=衍生物预览器 btnTokenPreviewer=衍生物预览器
btnCopyToClipboard=复制到剪切板 btnCopyToClipboard=复制到剪切板
cbpSelectLanguage=语言 cbpSelectLanguage=语言
cbpAutoUpdater=自动更新 cbpAutoUpdater=自动更新
nlAutoUpdater=选择用于更新Forge的发布渠道 nlAutoUpdater=选择用于更新Forge的发布渠道
nlSelectLanguage=选择语言(除了正在进行中的游戏)(需要重新启动) nlSelectLanguage=选择语言(除了正在进行中的游戏)(需要重新启动)
cbRemoveSmall=删除小生物 cbRemoveSmall=删除小生物
@@ -361,6 +361,15 @@ lblTotalDamageText=可用的伤害值:未知
lblAssignRemainingText=对受到致命伤害的对象分配过量的伤害 lblAssignRemainingText=对受到致命伤害的对象分配过量的伤害
lblLethal=致死 lblLethal=致死
lblAvailableDamagePoints=可用的伤害值 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 #KeyboardShortcuts.java
lblSHORTCUT_SHOWSTACK=匹配:显示堆叠面板 lblSHORTCUT_SHOWSTACK=匹配:显示堆叠面板
lblSHORTCUT_SHOWCOMBAT=匹配:显示战斗面板 lblSHORTCUT_SHOWCOMBAT=匹配:显示战斗面板
@@ -416,7 +425,7 @@ lblSelectOpponentDeck=为对手选择套牌
lblGenerateNewDeck=生成新的套牌 lblGenerateNewDeck=生成新的套牌
lblRandomTheme=随机主题 lblRandomTheme=随机主题
lblTestDeck=测试套牌 lblTestDeck=测试套牌
lblLoading=加载中 lblLoading=加载中
#GameType.java #GameType.java
lblSealed=现开 lblSealed=现开
lblDraft=轮抓 lblDraft=轮抓
@@ -764,7 +773,7 @@ ttWinsperDraftRotation=如果轮抓没有赢这么多场,那么它将被删除
lblRotationType=轮替类型 lblRotationType=轮替类型
ttRotationType=如果设置为0旧系列消失如果设置为1则用不同系列替换。 ttRotationType=如果设置为0旧系列消失如果设置为1则用不同系列替换。
lblWildOpponentNumber=野外对手数量 lblWildOpponentNumber=野外对手数量
lblWildOpponentMultiplier=野外对手倍数 lblWildOpponentMultiplier=野外对手倍数
#StatTypeFilter.java #StatTypeFilter.java
lblclicktotoogle=单击以切换筛选器,右键单机以仅显示 lblclicktotoogle=单击以切换筛选器,右键单机以仅显示
#SItemManagerUtil.java #SItemManagerUtil.java
@@ -1288,7 +1297,7 @@ lblLibrary=牌库
lblGraveyard=坟场 lblGraveyard=坟场
lblTop= lblTop=
lblBottom= lblBottom=
lblNColorManaFromCard={2}产{0}个{1}法术力 lblNColorManaFromCard={2}产{0}个{1}法术力
lblPayManaFromManaPool=从法术力池支付法术力 lblPayManaFromManaPool=从法术力池支付法术力
lblChooseATargetType=选择一个{0}类型 lblChooseATargetType=选择一个{0}类型
lblUntap=重置 lblUntap=重置
@@ -1621,10 +1630,10 @@ lbl4thPlace=第四名:
lblTime= 时间 lblTime= 时间
lblCollectPrizes=收藏品 lblCollectPrizes=收藏品
lblCurrentlyInDraft=你现在正在一场轮抓中。\n你应该先离开轮抓或者玩完这场轮抓然后再开始新的轮抓。 lblCurrentlyInDraft=你现在正在一场轮抓中。\n你应该先离开轮抓或者玩完这场轮抓然后再开始新的轮抓。
lblYouNeed=你还需要 lblYouNeed=你还需要
lblMoreCredits=积分才可以参与这场锦标赛。 lblMoreCredits=积分才可以参与这场锦标赛。
lblNotEnoughCredits=积分不足 lblNotEnoughCredits=积分不足
lblTournamentCosts=这次锦标赛的费用为 lblTournamentCosts=这次锦标赛的费用为
lblSureEnterTournament= 积分。\n你确定要进入吗 lblSureEnterTournament= 积分。\n你确定要进入吗
lblEnterDraftTournament=进入轮抓锦标赛? lblEnterDraftTournament=进入轮抓锦标赛?
lblLeaveDraftConfirm=这将结束当前轮抓,你将无法再次加入此锦标赛。\n你的积分将被退还轮抓将被删除。\n\n仍然要离开吗 lblLeaveDraftConfirm=这将结束当前轮抓,你将无法再次加入此锦标赛。\n你的积分将被退还轮抓将被删除。\n\n仍然要离开吗

View File

@@ -56,6 +56,7 @@ public enum ProtocolMethod {
setPanelSelection (Mode.SERVER, Void.TYPE, CardView.class), setPanelSelection (Mode.SERVER, Void.TYPE, CardView.class),
getAbilityToPlay (Mode.SERVER, SpellAbilityView.class, CardView.class, List/*SpellAbilityView*/.class, ITriggerEvent.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), 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), message (Mode.SERVER, Void.TYPE, String.class, String.class),
showErrorDialog (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), showConfirmDialog (Mode.SERVER, Boolean.TYPE, String.class, String.class, String.class, String.class, Boolean.TYPE),

View File

@@ -74,7 +74,7 @@ public class NetGuiGame extends AbstractGuiGame {
updateGameView(); updateGameView();
send(ProtocolMethod.showPromptMessage, playerView, message); send(ProtocolMethod.showPromptMessage, playerView, message);
} }
@Override @Override
public void showPromptMessage(final PlayerView playerView, final String message, final CardView card) { public void showPromptMessage(final PlayerView playerView, final String message, final CardView card) {
updateGameView(); updateGameView();
@@ -206,6 +206,11 @@ public class NetGuiGame extends AbstractGuiGame {
return sendAndWait(ProtocolMethod.assignCombatDamage, attacker, blockers, damage, defender, overrideOrder); 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 @Override
public void message(final String message, final String title) { public void message(final String message, final String title) {
send(ProtocolMethod.message, message, title); send(ProtocolMethod.message, message, title);

View File

@@ -69,6 +69,7 @@ public interface IGuiGame {
void setPanelSelection(CardView hostCard); void setPanelSelection(CardView hostCard);
SpellAbilityView getAbilityToPlay(CardView hostCard, List<SpellAbilityView> abilities, ITriggerEvent triggerEvent); 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<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);
void message(String message, String title); void message(String message, String title);

View File

@@ -11,6 +11,7 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; 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 @Override
public Integer announceRequirements(final SpellAbility ability, final String announce) { public Integer announceRequirements(final SpellAbility ability, final String announce) {
int max = Integer.MAX_VALUE; int max = Integer.MAX_VALUE;