mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
add ExileFromTop<1/Card> (for example) as a Cost.
add Royal Herbalist as an example.
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -5407,6 +5407,7 @@ res/cardsfolder/rowan_treefolk.txt -text svneol=native#text/plain
|
|||||||
res/cardsfolder/royal_assassin.txt -text svneol=native#text/plain
|
res/cardsfolder/royal_assassin.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/royal_decree.txt -text svneol=native#text/plain
|
res/cardsfolder/royal_decree.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/royal_falcon.txt -text svneol=native#text/plain
|
res/cardsfolder/royal_falcon.txt -text svneol=native#text/plain
|
||||||
|
res/cardsfolder/royal_herbalist.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/royal_trooper.txt -text svneol=native#text/plain
|
res/cardsfolder/royal_trooper.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/rubinia_soulsinger.txt -text svneol=native#text/plain
|
res/cardsfolder/rubinia_soulsinger.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/ruby_leech.txt -text svneol=native#text/plain
|
res/cardsfolder/ruby_leech.txt -text svneol=native#text/plain
|
||||||
|
|||||||
9
res/cardsfolder/royal_herbalist.txt
Normal file
9
res/cardsfolder/royal_herbalist.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Royal Herbalist
|
||||||
|
ManaCost:W
|
||||||
|
Types:Creature Human Cleric
|
||||||
|
Text:no text
|
||||||
|
PT:1/1
|
||||||
|
A:AB$GainLife | Cost$ 2 ExileFromTop<1/Card> | LifeAmount$ 1 | SpellDescription$ You gain 1 life.
|
||||||
|
SVar:Rarity:Common
|
||||||
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/royal_herbalist.jpg
|
||||||
|
End
|
||||||
@@ -245,6 +245,10 @@ public class AllZoneUtil {
|
|||||||
return PlayerZoneUtil.isCardInZone(AllZone.getZone(Constant.Zone.Hand, player), card);
|
return PlayerZoneUtil.isCardInZone(AllZone.getZone(Constant.Zone.Hand, player), card);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isCardInPlayerLibrary(Player player, Card card) {
|
||||||
|
return PlayerZoneUtil.isCardInZone(AllZone.getZone(Constant.Zone.Library, player), card);
|
||||||
|
}
|
||||||
|
|
||||||
////////////// EXILE
|
////////////// EXILE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -425,6 +425,21 @@ public class ComputerUtil
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(cost.getExileFromTopCost()){
|
||||||
|
if(!cost.getExileFromTopThis()){
|
||||||
|
CardList typeList = AllZoneUtil.getPlayerCardsInLibrary(AllZone.ComputerPlayer);
|
||||||
|
typeList = typeList.getValidCards(cost.getExileFromTopType().split(","), sa.getActivatingPlayer(), sa.getSourceCard());
|
||||||
|
Card target = sa.getTargetCard();
|
||||||
|
if (target != null && target.getController().equals(AllZone.ComputerPlayer)) // don't exile the card we're pumping
|
||||||
|
typeList.remove(target);
|
||||||
|
|
||||||
|
if (cost.getExileFromTopAmount() > typeList.size())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (cost.getExileFromTopThis() && !AllZoneUtil.isCardInPlayerLibrary(card.getController(), card))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (cost.getReturnCost()){
|
if (cost.getReturnCost()){
|
||||||
// if there's a return in the cost, just because we can Pay it doesn't mean we want to.
|
// if there's a return in the cost, just because we can Pay it doesn't mean we want to.
|
||||||
if (!cost.getReturnThis()){
|
if (!cost.getReturnThis()){
|
||||||
@@ -720,6 +735,10 @@ public class ComputerUtil
|
|||||||
return chooseExileFrom(Constant.Zone.Graveyard, type, activate, target, amount);
|
return chooseExileFrom(Constant.Zone.Graveyard, type, activate, target, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public CardList chooseExileFromTopType(String type, Card activate, Card target, int amount){
|
||||||
|
return chooseExileFrom(Constant.Zone.Library, type, activate, target, amount);
|
||||||
|
}
|
||||||
|
|
||||||
static public CardList chooseExileFrom(String zone, String type, Card activate, Card target, int amount){
|
static public CardList chooseExileFrom(String zone, String type, Card activate, Card target, int amount){
|
||||||
PlayerZone grave = AllZone.getZone(zone, AllZone.ComputerPlayer);
|
PlayerZone grave = AllZone.getZone(zone, AllZone.ComputerPlayer);
|
||||||
CardList typeList = new CardList(grave.getCards());
|
CardList typeList = new CardList(grave.getCards());
|
||||||
|
|||||||
@@ -46,6 +46,15 @@ public class Cost {
|
|||||||
private int exileFromGraveAmount = 0;
|
private int exileFromGraveAmount = 0;
|
||||||
public int getExileFromGraveAmount() { return exileFromGraveAmount; }
|
public int getExileFromGraveAmount() { return exileFromGraveAmount; }
|
||||||
|
|
||||||
|
private boolean exileFromTopCost = false;
|
||||||
|
public boolean getExileFromTopCost() { return exileFromTopCost; }
|
||||||
|
private String exileFromTopType = ""; // <type> or CARDNAME
|
||||||
|
public String getExileFromTopType() { return exileFromTopType; }
|
||||||
|
private boolean exileFromTopThis = false;
|
||||||
|
public boolean getExileFromTopThis() { return exileFromTopThis; }
|
||||||
|
private int exileFromTopAmount = 0;
|
||||||
|
public int getExileFromTopAmount() { return exileFromTopAmount; }
|
||||||
|
|
||||||
private boolean tapCost = false;
|
private boolean tapCost = false;
|
||||||
public boolean getTap() { return tapCost; }
|
public boolean getTap() { return tapCost; }
|
||||||
|
|
||||||
@@ -105,8 +114,8 @@ public class Cost {
|
|||||||
public void setXMana(int xCost) { manaXCost = xCost; }
|
public void setXMana(int xCost) { manaXCost = xCost; }
|
||||||
|
|
||||||
public boolean isOnlyManaCost() {
|
public boolean isOnlyManaCost() {
|
||||||
return !sacCost && !exileCost && !exileFromHandCost && !exileFromGraveCost && !tapCost && !tapXTypeCost &&
|
return !sacCost && !exileCost && !exileFromHandCost && !exileFromGraveCost && !exileFromTopCost && !tapCost &&
|
||||||
!untapCost && !subtractCounterCost && !addCounterCost && !lifeCost && !discardCost && !returnCost;
|
!tapXTypeCost && !untapCost && !subtractCounterCost && !addCounterCost && !lifeCost && !discardCost && !returnCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTotalMana() {
|
public String getTotalMana() {
|
||||||
@@ -232,6 +241,17 @@ public class Cost {
|
|||||||
exileFromGraveThis = (exileFromGraveType.equals("CARDNAME"));
|
exileFromGraveThis = (exileFromGraveType.equals("CARDNAME"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String exileFromTopStr = "ExileFromTop<";
|
||||||
|
if(parse.contains(exileFromTopStr)) {
|
||||||
|
exileFromTopCost = true;
|
||||||
|
String[] splitStr = abCostParse(parse, exileFromTopStr, 2);
|
||||||
|
parse = abUpdateParse(parse, exileFromTopStr);
|
||||||
|
|
||||||
|
exileFromTopAmount = Integer.parseInt(splitStr[0]);
|
||||||
|
exileFromTopType = splitStr[1];
|
||||||
|
exileFromTopThis = false;
|
||||||
|
}
|
||||||
|
|
||||||
String returnStr = "Return<";
|
String returnStr = "Return<";
|
||||||
if(parse.contains(returnStr)) {
|
if(parse.contains(returnStr)) {
|
||||||
returnCost = true;
|
returnCost = true;
|
||||||
@@ -310,7 +330,7 @@ public class Cost {
|
|||||||
|
|
||||||
public boolean isUndoable() {
|
public boolean isUndoable() {
|
||||||
return !(sacCost || exileCost || exileFromHandCost || exileFromGraveCost || tapXTypeCost || discardCost ||
|
return !(sacCost || exileCost || exileFromHandCost || exileFromGraveCost || tapXTypeCost || discardCost ||
|
||||||
returnCost || lifeCost) && hasNoXManaCost() && hasNoManaCost();
|
returnCost || lifeCost || exileFromTopCost) && hasNoXManaCost() && hasNoManaCost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -399,6 +419,11 @@ public class Cost {
|
|||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(exileFromTopCost) {
|
||||||
|
cost.append(exileFromTopString(first));
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (returnCost){
|
if (returnCost){
|
||||||
cost.append(returnString(first));
|
cost.append(returnString(first));
|
||||||
first = false;
|
first = false;
|
||||||
@@ -526,6 +551,11 @@ public class Cost {
|
|||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( exileFromTopCost ) {
|
||||||
|
cost.append( exileFromTopString(first) );
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (returnCost){
|
if (returnCost){
|
||||||
cost.append(returnString(first));
|
cost.append(returnString(first));
|
||||||
first = false;
|
first = false;
|
||||||
@@ -657,6 +687,32 @@ public class Cost {
|
|||||||
return cost.toString();
|
return cost.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String exileFromTopString(boolean first) {
|
||||||
|
StringBuilder cost = new StringBuilder();
|
||||||
|
if(first) {
|
||||||
|
if(isAbility)
|
||||||
|
cost.append("Exile ");
|
||||||
|
else
|
||||||
|
cost.append("exile ");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cost.append(", Exile ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(exileType.equals("CARDNAME"))
|
||||||
|
cost.append(name).append(" ");
|
||||||
|
else {
|
||||||
|
cost.append("the top");
|
||||||
|
if(exileFromTopAmount != 1) {
|
||||||
|
cost.append(convertIntAndTypeToWords(exileFromTopAmount, exileFromTopType));
|
||||||
|
}
|
||||||
|
cost.append(" card");
|
||||||
|
if(exileFromTopAmount != 1) cost.append("s");
|
||||||
|
cost.append(" of your library");
|
||||||
|
}
|
||||||
|
return cost.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public String returnString(boolean first)
|
public String returnString(boolean first)
|
||||||
{
|
{
|
||||||
StringBuilder cost = new StringBuilder();
|
StringBuilder cost = new StringBuilder();
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public class Cost_Payment {
|
|||||||
private boolean payExile;
|
private boolean payExile;
|
||||||
private boolean payExileFromHand;
|
private boolean payExileFromHand;
|
||||||
private boolean payExileFromGrave;
|
private boolean payExileFromGrave;
|
||||||
|
private boolean payExileFromTop;
|
||||||
private boolean payLife;
|
private boolean payLife;
|
||||||
private boolean payDiscard;
|
private boolean payDiscard;
|
||||||
private boolean payTapXType;
|
private boolean payTapXType;
|
||||||
@@ -65,6 +66,7 @@ public class Cost_Payment {
|
|||||||
public void setPayExile(boolean bExile) { payExile = bExile; }
|
public void setPayExile(boolean bExile) { payExile = bExile; }
|
||||||
public void setPayExileFromHand(boolean bExileFromHand) { payExileFromHand = bExileFromHand; }
|
public void setPayExileFromHand(boolean bExileFromHand) { payExileFromHand = bExileFromHand; }
|
||||||
public void setPayExileFromGrave(boolean bExileFromGrave) { payExileFromGrave = bExileFromGrave; }
|
public void setPayExileFromGrave(boolean bExileFromGrave) { payExileFromGrave = bExileFromGrave; }
|
||||||
|
public void setPayExileFromTop(boolean bExileFromTop) { payExileFromTop = bExileFromTop; }
|
||||||
public void setPayTapXType(boolean bTapX) { payTapXType = bTapX; }
|
public void setPayTapXType(boolean bTapX) { payTapXType = bTapX; }
|
||||||
public void setPayReturn(boolean bReturn){ payReturn = bReturn; }
|
public void setPayReturn(boolean bReturn){ payReturn = bReturn; }
|
||||||
|
|
||||||
@@ -82,6 +84,7 @@ public class Cost_Payment {
|
|||||||
payExile = !cost.getExileCost();
|
payExile = !cost.getExileCost();
|
||||||
payExileFromHand = !cost.getExileFromHandCost();
|
payExileFromHand = !cost.getExileFromHandCost();
|
||||||
payExileFromGrave = !cost.getExileFromGraveCost();
|
payExileFromGrave = !cost.getExileFromGraveCost();
|
||||||
|
payExileFromTop = !cost.getExileFromTopCost();
|
||||||
payLife = !cost.getLifeCost();
|
payLife = !cost.getLifeCost();
|
||||||
payDiscard = !cost.getDiscardCost();
|
payDiscard = !cost.getDiscardCost();
|
||||||
payTapXType = !cost.getTapXTypeCost();
|
payTapXType = !cost.getTapXTypeCost();
|
||||||
@@ -215,6 +218,18 @@ public class Cost_Payment {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cost.getExileFromTopCost()){
|
||||||
|
if (!cost.getExileFromTopThis()){
|
||||||
|
CardList typeList = AllZoneUtil.getPlayerCardsInLibrary(card.getController());
|
||||||
|
|
||||||
|
typeList = typeList.getValidCards(cost.getExileFromTopType().split(";"), ability.getActivatingPlayer(), ability.getSourceCard());
|
||||||
|
if (typeList.size() < cost.getExileFromTopAmount())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (!AllZoneUtil.isCardInPlayerLibrary(card.getController(), card))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (cost.getReturnCost()){
|
if (cost.getReturnCost()){
|
||||||
if (!cost.getReturnThis()){
|
if (!cost.getReturnThis()){
|
||||||
PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, card.getController());
|
PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, card.getController());
|
||||||
@@ -399,6 +414,14 @@ public class Cost_Payment {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!payExileFromTop && cost.getExileFromTopCost()) { // exile stuff here
|
||||||
|
if (cost.getExileFromTopThis())
|
||||||
|
setInput(exileFromTopThis(ability, this));
|
||||||
|
else
|
||||||
|
setInput(exileFromTopType(ability, cost.getExileFromTopType(), this));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!payReturn && cost.getReturnCost()){ // return stuff here
|
if (!payReturn && cost.getReturnCost()){ // return stuff here
|
||||||
if (cost.getReturnThis())
|
if (cost.getReturnThis())
|
||||||
setInput(returnThis(ability, this));
|
setInput(returnThis(ability, this));
|
||||||
@@ -416,7 +439,7 @@ public class Cost_Payment {
|
|||||||
// if you add a new Cost type add it here
|
// if you add a new Cost type add it here
|
||||||
return (payTap && payUntap && payMana && payXMana && paySubCounter && payAddCounter &&
|
return (payTap && payUntap && payMana && payXMana && paySubCounter && payAddCounter &&
|
||||||
paySac && payExile && payLife && payDiscard && payTapXType && payReturn &&
|
paySac && payExile && payLife && payDiscard && payTapXType && payReturn &&
|
||||||
payExileFromHand && payExileFromGrave);
|
payExileFromHand && payExileFromGrave && payExileFromTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetUndoList(){
|
public void resetUndoList(){
|
||||||
@@ -478,6 +501,7 @@ public class Cost_Payment {
|
|||||||
CardList exileCard = new CardList();
|
CardList exileCard = new CardList();
|
||||||
CardList exileFromHandCard = new CardList();
|
CardList exileFromHandCard = new CardList();
|
||||||
CardList exileFromGraveCard = new CardList();
|
CardList exileFromGraveCard = new CardList();
|
||||||
|
CardList exileFromTopCard = new CardList();
|
||||||
CardList tapXCard = new CardList();
|
CardList tapXCard = new CardList();
|
||||||
CardList returnCard = new CardList();
|
CardList returnCard = new CardList();
|
||||||
ability.setActivatingPlayer(AllZone.ComputerPlayer);
|
ability.setActivatingPlayer(AllZone.ComputerPlayer);
|
||||||
@@ -536,6 +560,18 @@ public class Cost_Payment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cost.getExileFromTopCost()){
|
||||||
|
if (cost.getExileFromTopThis())
|
||||||
|
exileFromTopCard.add(card);
|
||||||
|
else
|
||||||
|
exileFromTopCard = ComputerUtil.chooseExileFromTopType(cost.getExileFromTopType(), card, ability.getTargetCard(), cost.getExileFromTopAmount());
|
||||||
|
|
||||||
|
if (exileFromTopCard.size() != cost.getExileFromTopAmount()){
|
||||||
|
System.out.println("Couldn't find a valid card to exile for: "+card.getName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (cost.getReturnCost()){
|
if (cost.getReturnCost()){
|
||||||
if (cost.getReturnThis())
|
if (cost.getReturnThis())
|
||||||
returnCard.add(card);
|
returnCard.add(card);
|
||||||
@@ -643,6 +679,11 @@ public class Cost_Payment {
|
|||||||
AllZone.GameAction.exile(c);
|
AllZone.GameAction.exile(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(cost.getExileFromTopCost()) {
|
||||||
|
for(Card c : exileFromTopCard)
|
||||||
|
AllZone.GameAction.exile(c);
|
||||||
|
}
|
||||||
|
|
||||||
if (cost.getReturnCost()){
|
if (cost.getReturnCost()){
|
||||||
for(Card c : returnCard)
|
for(Card c : returnCard)
|
||||||
AllZone.GameAction.moveToHand(c);
|
AllZone.GameAction.moveToHand(c);
|
||||||
@@ -1022,6 +1063,33 @@ public class Cost_Payment {
|
|||||||
return target;
|
return target;
|
||||||
}//input_exile()
|
}//input_exile()
|
||||||
|
|
||||||
|
public static Input exileFromTopThis(final SpellAbility spell, final Cost_Payment payment) {
|
||||||
|
Input target = new Input() {
|
||||||
|
private static final long serialVersionUID = 3416809678763443014L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showMessage() {
|
||||||
|
Card card = spell.getSourceCard();
|
||||||
|
if(card.getController().equals(AllZone.HumanPlayer) && AllZoneUtil.isCardInPlayerHand(card.getController(), card)) {
|
||||||
|
//This can't really happen, but if for some reason it could....
|
||||||
|
if(AllZoneUtil.getPlayerCardsInLibrary(card.getController()).size() > 0) {
|
||||||
|
payment.setPayExileFromTop(true);
|
||||||
|
payment.getAbility().addExiledCost(card);
|
||||||
|
AllZone.GameAction.exile(card);
|
||||||
|
stop();
|
||||||
|
payment.payCost();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
payment.setCancel(true);
|
||||||
|
stop();
|
||||||
|
payment.payCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return target;
|
||||||
|
}//input_exile()
|
||||||
|
|
||||||
public static Input exileFromGraveThis(final SpellAbility spell, final Cost_Payment payment) {
|
public static Input exileFromGraveThis(final SpellAbility spell, final Cost_Payment payment) {
|
||||||
Input target = new Input() {
|
Input target = new Input() {
|
||||||
private static final long serialVersionUID = 6237561876518762902L;
|
private static final long serialVersionUID = 6237561876518762902L;
|
||||||
@@ -1229,6 +1297,53 @@ public class Cost_Payment {
|
|||||||
return target;
|
return target;
|
||||||
}//exileFromGraveType()
|
}//exileFromGraveType()
|
||||||
|
|
||||||
|
public static Input exileFromTopType(final SpellAbility spell, final String type, final Cost_Payment payment){
|
||||||
|
Input target = new Input() {
|
||||||
|
private static final long serialVersionUID = -4764871768555887091L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showMessage() {
|
||||||
|
//Card card = spell.getSourceCard();
|
||||||
|
CardList typeList;
|
||||||
|
int nNeeded = payment.getCost().getExileFromTopAmount();
|
||||||
|
PlayerZone lib = AllZone.getZone(Constant.Zone.Library, spell.getSourceCard().getController());
|
||||||
|
typeList = new CardList(lib.getCards());
|
||||||
|
typeList = typeList.getValidCards(type.split(";"), spell.getActivatingPlayer(), spell.getSourceCard());
|
||||||
|
|
||||||
|
for (int i=0; i < nNeeded; i++) {
|
||||||
|
if (typeList.size() == 0)
|
||||||
|
cancel();
|
||||||
|
|
||||||
|
if(lib.size() > 0) {
|
||||||
|
Card c = typeList.get(0);
|
||||||
|
typeList.remove(c);
|
||||||
|
payment.getAbility().addExiledCost(c);
|
||||||
|
AllZone.GameAction.exile(c);
|
||||||
|
if (i == nNeeded-1) done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void selectButtonCancel() {
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void done(){
|
||||||
|
payment.setPayExileFromTop(true);
|
||||||
|
stop();
|
||||||
|
payment.payCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel(){
|
||||||
|
payment.setCancel(true);
|
||||||
|
stop();
|
||||||
|
payment.payCost();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return target;
|
||||||
|
}//exileFromTopType()
|
||||||
|
|
||||||
public static Input input_tapXCost(final int nCards, final String cardType, final CardList cardList, SpellAbility sa, final Cost_Payment payment) {
|
public static Input input_tapXCost(final int nCards, final String cardType, final CardList cardList, SpellAbility sa, final Cost_Payment payment) {
|
||||||
//final SpellAbility sp = sa;
|
//final SpellAbility sp = sa;
|
||||||
Input target = new Input() {
|
Input target = new Input() {
|
||||||
|
|||||||
Reference in New Issue
Block a user