mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
Support selecting cards further back in stack if tapped card not selectable
This commit is contained in:
@@ -173,12 +173,28 @@ public abstract class VCardDisplayArea extends VDisplayArea {
|
||||
ThreadUtil.invokeInGameThread(new Runnable() { //must invoke in game thread in case a dialog needs to be shown
|
||||
@Override
|
||||
public void run() {
|
||||
FControl.getInputProxy().selectCard(getCard(), null);
|
||||
if (!selectCard()) {
|
||||
//if no cards in stack can be selected, just show zoom/details for card
|
||||
CardZoom.show(getCard());
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean selectCard() {
|
||||
if (FControl.getInputProxy().selectCard(getCard(), null)) {
|
||||
return true;
|
||||
}
|
||||
//if panel can't do anything with card selection, try selecting an attached panel
|
||||
for (CardAreaPanel panel : attachedPanels) {
|
||||
if (panel.selectCard()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(float x, float y) {
|
||||
CardZoom.show(getCard());
|
||||
|
||||
@@ -9,7 +9,7 @@ import forge.util.ITriggerEvent;
|
||||
public interface Input {
|
||||
void showMessageInitial();
|
||||
|
||||
void selectCard(Card c, ITriggerEvent triggerEvent);
|
||||
boolean selectCard(Card c, ITriggerEvent triggerEvent);
|
||||
|
||||
void selectAbility(SpellAbility ab);
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected final void onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
protected final boolean onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
final List<Card> att = combat.getAttackers();
|
||||
if (triggerEvent != null && triggerEvent.getButton() == 3 && att.contains(card) && !card.hasKeyword("CARDNAME attacks each turn if able.")
|
||||
&& !card.hasStartOfKeyword("CARDNAME attacks specific player each combat if able")) {
|
||||
@@ -135,32 +135,37 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
this.activateBand(null);
|
||||
|
||||
GuiBase.getInterface().fireEvent(new UiEventAttackerDeclared(card, null));
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (combat.isAttacking(card, currentDefender)) {
|
||||
// Activate band by selecting/deselecting a band member
|
||||
boolean validAction = true;
|
||||
if (this.activeBand == null) {
|
||||
this.activateBand(combat.getBandOfAttacker(card));
|
||||
} else if (this.activeBand.getAttackers().contains(card)) {
|
||||
}
|
||||
else if (this.activeBand.getAttackers().contains(card)) {
|
||||
this.activateBand(null);
|
||||
} else { // Join a band by selecting a non-active band member after activating a band
|
||||
}
|
||||
else { // Join a band by selecting a non-active band member after activating a band
|
||||
if (this.activeBand.canJoinBand(card)) {
|
||||
combat.removeFromCombat(card);
|
||||
declareAttacker(card);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
flashIncorrectAction();
|
||||
validAction = false;
|
||||
}
|
||||
}
|
||||
|
||||
updateMessage();
|
||||
return;
|
||||
return validAction;
|
||||
}
|
||||
|
||||
if (card.getController().isOpponentOf(playerAttacks)) {
|
||||
if (defenders.contains(card)) { // planeswalker?
|
||||
setCurrentDefender(card);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +174,7 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
this.activateBand(null);
|
||||
updateMessage();
|
||||
flashIncorrectAction();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(combat.isAttacking(card)) {
|
||||
@@ -178,12 +183,12 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
|
||||
declareAttacker(card);
|
||||
showCombat();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
flashIncorrectAction();
|
||||
}
|
||||
} // selectCard()
|
||||
|
||||
flashIncorrectAction();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
|
||||
@@ -71,12 +71,14 @@ public abstract class InputBase implements java.io.Serializable, Input {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void selectCard(final Card c, final ITriggerEvent triggerEvent) {
|
||||
if (isFinished()) { return; }
|
||||
onCardSelected(c, triggerEvent);
|
||||
public final boolean selectCard(final Card c, final ITriggerEvent triggerEvent) {
|
||||
if (isFinished()) { return false; }
|
||||
return onCardSelected(c, triggerEvent);
|
||||
}
|
||||
|
||||
protected void onCardSelected(final Card c, final ITriggerEvent triggerEvent) {}
|
||||
protected boolean onCardSelected(final Card c, final ITriggerEvent triggerEvent) {
|
||||
return false;
|
||||
}
|
||||
protected void onPlayerSelected(final Player p, final ITriggerEvent triggerEvent) {}
|
||||
protected void onCancel() {}
|
||||
protected void onOk() {}
|
||||
|
||||
@@ -97,18 +97,20 @@ public class InputBlock extends InputSyncronizedBase {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final void onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
public final boolean onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
boolean isCorrectAction = false;
|
||||
if (triggerEvent != null && triggerEvent.getButton() == 3 && card.getController() == defender) {
|
||||
combat.removeFromCombat(card);
|
||||
GuiBase.getInterface().fireEvent(new UiEventBlockerAssigned(card, (Card)null));
|
||||
} else {
|
||||
isCorrectAction = true;
|
||||
}
|
||||
else {
|
||||
// is attacking?
|
||||
boolean isCorrectAction = false;
|
||||
|
||||
if (combat.isAttacking(card)) {
|
||||
setCurrentAttacker(card);
|
||||
isCorrectAction = true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// Make sure this card is valid to even be a blocker
|
||||
if (this.currentAttacker != null && card.isCreature() && defender.getZone(ZoneType.Battlefield).contains(card)) {
|
||||
isCorrectAction = CombatUtil.canBlock(this.currentAttacker, card, combat);
|
||||
@@ -124,8 +126,8 @@ public class InputBlock extends InputSyncronizedBase {
|
||||
}
|
||||
}
|
||||
this.showMessage();
|
||||
} // selectCard()
|
||||
|
||||
return isCorrectAction;
|
||||
}
|
||||
|
||||
private void setCurrentAttacker(Card card) {
|
||||
currentAttacker = card;
|
||||
|
||||
@@ -111,13 +111,13 @@ public class InputConfirmMulligan extends InputSyncronizedBase {
|
||||
volatile boolean cardSelectLocked = false;
|
||||
|
||||
@Override
|
||||
protected void onCardSelected(final Card c0, final ITriggerEvent triggerEvent) { // the only place that would cause troubles - input is supposed only to confirm, not to fire abilities
|
||||
protected boolean onCardSelected(final Card c0, final ITriggerEvent triggerEvent) { // the only place that would cause troubles - input is supposed only to confirm, not to fire abilities
|
||||
boolean fromHand = player.getZone(ZoneType.Hand).contains(c0);
|
||||
boolean isSerumPowder = c0.getName().equals("Serum Powder");
|
||||
boolean isLegalChoice = fromHand && (isCommander || isSerumPowder);
|
||||
if (!isLegalChoice || cardSelectLocked) {
|
||||
flashIncorrectAction();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isSerumPowder && SGuiDialog.confirm(c0, "Use " + c0.getName() + "'s ability?")) {
|
||||
@@ -132,7 +132,7 @@ public class InputConfirmMulligan extends InputSyncronizedBase {
|
||||
cardSelectLocked = false;
|
||||
}
|
||||
});
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isCommander) { // allow to choose cards for partial paris
|
||||
@@ -151,6 +151,7 @@ public class InputConfirmMulligan extends InputSyncronizedBase {
|
||||
ButtonUtil.enableAllFocusOk();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public final boolean isKeepHand() {
|
||||
|
||||
@@ -59,10 +59,20 @@ public class InputLockUI implements Input {
|
||||
GuiBase.getInterface().showPromptMessage(message);
|
||||
}
|
||||
|
||||
@Override public void selectCard(Card c, ITriggerEvent triggerEvent) {}
|
||||
@Override public void selectAbility(SpellAbility ab) {}
|
||||
@Override public void selectPlayer(Player player, ITriggerEvent triggerEvent) {}
|
||||
@Override public void selectButtonOK() {}
|
||||
@Override public void selectButtonCancel() {}
|
||||
|
||||
@Override
|
||||
public boolean selectCard(Card c, ITriggerEvent triggerEvent) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public void selectAbility(SpellAbility ab) {
|
||||
}
|
||||
@Override
|
||||
public void selectPlayer(Player player, ITriggerEvent triggerEvent) {
|
||||
}
|
||||
@Override
|
||||
public void selectButtonOK() {
|
||||
}
|
||||
@Override
|
||||
public void selectButtonCancel() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,15 +60,16 @@ public class InputPassPriority extends InputSyncronizedBase {
|
||||
public SpellAbility getChosenSa() { return chosenSa; }
|
||||
|
||||
@Override
|
||||
protected void onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
protected boolean onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
//remove unplayable unless triggerEvent specified, in which case unplayable may be shown as disabled options
|
||||
List<SpellAbility> abilities = card.getAllPossibleAbilities(player, triggerEvent == null);
|
||||
if (abilities.isEmpty()) {
|
||||
flashIncorrectAction();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
selectAbility(player.getController().getAbilityToPlay(abilities, triggerEvent));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -49,13 +49,13 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
protected boolean onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
if (card.getManaAbility().isEmpty()) {
|
||||
flashIncorrectAction();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// only tap card if the mana is needed
|
||||
activateManaAbility(card, this.manaCost);
|
||||
return activateManaAbility(card, this.manaCost);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,18 +123,18 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
* a {@link forge.game.mana.ManaCostBeingPaid} object.
|
||||
* @return a {@link forge.game.mana.ManaCostBeingPaid} object.
|
||||
*/
|
||||
protected void activateManaAbility(final Card card, ManaCostBeingPaid manaCost) {
|
||||
activateManaAbility(card, manaCost, null);
|
||||
protected boolean activateManaAbility(final Card card, ManaCostBeingPaid manaCost) {
|
||||
return activateManaAbility(card, manaCost, null);
|
||||
}
|
||||
protected void activateManaAbility(final Card card, ManaCostBeingPaid manaCost, SpellAbility chosenAbility) {
|
||||
protected boolean activateManaAbility(final Card card, ManaCostBeingPaid manaCost, SpellAbility chosenAbility) {
|
||||
if (locked) {
|
||||
System.err.print("Should wait till previous call to playAbility finishes.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure computer's lands aren't selected
|
||||
if (card.getController() != player) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
byte colorCanUse = 0;
|
||||
@@ -149,7 +149,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
}
|
||||
|
||||
if (colorCanUse == 0) { // no mana cost or something
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
List<SpellAbility> abilities = new ArrayList<SpellAbility>();
|
||||
@@ -157,7 +157,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
|
||||
final String typeRes = manaCost.getSourceRestriction();
|
||||
if (StringUtils.isNotBlank(typeRes) && !card.isType(typeRes)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean guessAbilityWithRequiredColors = true;
|
||||
@@ -179,7 +179,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
}
|
||||
|
||||
if (abilities.isEmpty() || (chosenAbility != null && !abilities.contains(chosenAbility))) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store some information about color costs to help with any mana choices
|
||||
@@ -251,6 +251,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
};
|
||||
locked = true;
|
||||
game.getAction().invoke(proc);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -92,9 +92,9 @@ public class InputPayManaX extends InputPayMana {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
protected boolean onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
// don't allow here the cards that produce only wrong colors
|
||||
activateManaAbility(card, this.manaCost);
|
||||
return activateManaAbility(card, this.manaCost);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -42,9 +42,9 @@ public final class InputProliferate extends InputSelectManyBase<GameEntity> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
protected boolean onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
if (!card.hasCounters()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean entityWasSelected = chosenCounters.containsKey(card);
|
||||
@@ -64,6 +64,7 @@ public final class InputProliferate extends InputSelectManyBase<GameEntity> {
|
||||
}
|
||||
|
||||
refresh();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -136,11 +136,12 @@ public class InputProxy implements Observer {
|
||||
* a {@link forge.game.card.Card} object.
|
||||
* @param triggerEvent
|
||||
*/
|
||||
public final void selectCard(final Card card, final ITriggerEvent triggerEvent) {
|
||||
public final boolean selectCard(final Card card, final ITriggerEvent triggerEvent) {
|
||||
Input inp = getInput();
|
||||
if (inp != null) {
|
||||
inp.selectCard(card, triggerEvent);
|
||||
return inp.selectCard(card, triggerEvent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final void selectAbility(SpellAbility ab) {
|
||||
|
||||
@@ -38,11 +38,11 @@ public final class InputSelectCardsForConvoke extends InputSelectManyBase<Card>
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
protected boolean onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
if (!availableCreatures.contains(card)) {
|
||||
// Not in untapped creatures list provided. Not a legal Convoke selection.
|
||||
flashIncorrectAction();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean entityWasSelected = chosenCards.containsKey(card);
|
||||
@@ -57,11 +57,12 @@ public final class InputSelectCardsForConvoke extends InputSelectManyBase<Card>
|
||||
|
||||
if (remainingCost.getColorlessManaAmount() > 0 && (chosenColor == 0 || !remainingCost.needsColor(chosenColor, player.getManaPool()))) {
|
||||
registerConvoked(card, ManaCostShard.COLORLESS, chosenColor);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
for (ManaCostShard shard : remainingCost.getDistinctShards()) {
|
||||
if (shard.canBePaidWithManaOfColor(chosenColor)) {
|
||||
registerConvoked(card, shard, chosenColor);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
showMessage("The colors provided by " + card.toString() + " you've chosen cannot be used to decrease the manacost of " + remainingCost.toString());
|
||||
@@ -70,6 +71,7 @@ public final class InputSelectCardsForConvoke extends InputSelectManyBase<Card>
|
||||
}
|
||||
|
||||
refresh();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void registerConvoked(Card card, ManaCostShard shard, byte chosenColor) {
|
||||
|
||||
@@ -25,11 +25,12 @@ public class InputSelectEntitiesFromList<T extends GameEntity> extends InputSele
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCardSelected(final Card c, final ITriggerEvent triggerEvent) {
|
||||
protected boolean onCardSelected(final Card c, final ITriggerEvent triggerEvent) {
|
||||
if (!selectEntity(c)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
refresh();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -104,33 +104,33 @@ public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
protected final boolean onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
if (!tgt.isUniqueTargets() && targetDepth.containsKey(card)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// leave this in temporarily, there some seriously wrong things going on here
|
||||
// Can be targeted doesn't check if the target is a valid type, only if a card is generally "targetable"
|
||||
if (!card.canBeTargetedBy(sa)) {
|
||||
showMessage(sa.getHostCard() + " - Cannot target this card (Shroud? Protection? Restrictions).");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// If all cards must be from the same zone
|
||||
if (tgt.isSingleZone() && lastTarget != null && !card.getController().equals(lastTarget.getController())) {
|
||||
showMessage(sa.getHostCard() + " - Cannot target this card (not in the same zone)");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If all cards must be from different zones
|
||||
if (tgt.isDifferentZone() && lastTarget != null && !card.getController().equals(lastTarget.getController().getOpponent())) {
|
||||
showMessage(sa.getHostCard() + " - Cannot target this card (not in different zones)");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the cards can't share a creature type
|
||||
if (tgt.isWithoutSameCreatureType() && lastTarget != null && card.sharesCreatureTypeWith(lastTarget)) {
|
||||
showMessage(sa.getHostCard() + " - Cannot target this card (should not share a creature type)");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If all cards must have different controllers
|
||||
@@ -144,17 +144,18 @@ public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
}
|
||||
if (targetedControllers.contains(card.getController())) {
|
||||
showMessage(sa.getHostCard() + " - Cannot target this card (must have different controllers)");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!choices.contains(card)) {
|
||||
if (card.isPlaneswalker() && sa.getApi() == ApiType.DealDamage) {
|
||||
showMessage(sa.getHostCard() + " - To deal an opposing Planeswalker direct damage, target its controller and then redirect the damage on resolution.");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
showMessage(sa.getHostCard() + " - The selected card is not a valid choice to be targeted.");
|
||||
}
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tgt.isDividedAsYouChoose()) {
|
||||
@@ -179,8 +180,8 @@ public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
sb.append(apiBasedMessage);
|
||||
sb.append(card.toString());
|
||||
Integer chosen = SGuiChoose.oneOrNone(sb.toString(), choices);
|
||||
if (null == chosen) {
|
||||
return;
|
||||
if (chosen == null) {
|
||||
return true; //still return true since there was a valid choice
|
||||
}
|
||||
allocatedPortion = chosen;
|
||||
} else { // otherwise assign the rest of the damage/protection
|
||||
@@ -190,6 +191,7 @@ public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
tgt.addDividedAllocation(card, allocatedPortion);
|
||||
}
|
||||
addTarget(card);
|
||||
return true;
|
||||
} // selectCard()
|
||||
|
||||
@Override
|
||||
|
||||
@@ -727,11 +727,12 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
private static final long serialVersionUID = 8338626212893374798L;
|
||||
|
||||
@Override
|
||||
protected void onCardSelected(Card c, ITriggerEvent triggerEvent) {
|
||||
protected boolean onCardSelected(Card c, ITriggerEvent triggerEvent) {
|
||||
Card firstCard = Iterables.getFirst(this.selected, null);
|
||||
if(firstCard != null && !CardPredicates.sharesColorWith(firstCard).apply(c))
|
||||
return;
|
||||
super.onCardSelected(c, triggerEvent);
|
||||
if (firstCard != null && !CardPredicates.sharesColorWith(firstCard).apply(c)) {
|
||||
return false;
|
||||
}
|
||||
return super.onCardSelected(c, triggerEvent);
|
||||
}
|
||||
};
|
||||
inp.setMessage("Select " + Lang.nounWithAmount(num, "card" ) + " of same color to reveal.");
|
||||
@@ -817,9 +818,9 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCardSelected(Card c, ITriggerEvent triggerEvent) {
|
||||
protected boolean onCardSelected(Card c, ITriggerEvent triggerEvent) {
|
||||
if (!isValidChoice(c) || c.getCounters(counterType) <= getTimesSelected(c)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
int tc = getTimesSelected(c);
|
||||
@@ -827,6 +828,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
|
||||
onSelectStateChanged(c, true);
|
||||
refresh();
|
||||
return true;
|
||||
};
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user