foul-magics/Mage/src/main/java/mage/MageObject.java
Evan Kranzler cdf91e66fb
Change tribal card type to kindred, update viashino and naga (#12271)
* change tribal card type to kindred

* update viashino to lizard

* update naga to snake
2024-06-08 13:55:52 -04:00

626 lines
18 KiB
Java

package mage;
import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.cards.Card;
import mage.cards.FrameStyle;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SubTypeSet;
import mage.constants.SuperType;
import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import mage.util.Copyable;
import mage.util.SubTypes;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public interface MageObject extends MageItem, Serializable, Copyable<MageObject> {
String getExpansionSetCode();
void setExpansionSetCode(String expansionSetCode);
String getCardNumber();
void setCardNumber(String cardNumber);
Integer getImageNumber();
void setImageNumber(Integer imageNumber);
/**
* Set contains multiple cards with same card name but different images (also used for token from card)
*/
boolean getUsesVariousArt();
void setUsesVariousArt(boolean usesVariousArt);
/**
* Get image file name
* - empty for default name from a card
* - non-empty for face down objects like Morph (GUI show empty name, but image must show some image)
*/
String getImageFileName();
void setImageFileName(String imageFile);
String getName();
/**
* Warning, don't use it as a key - multiple objects can have same parts of the id in rare use cases
*
* @return
*/
String getIdName();
String getLogName();
void setName(String name);
default List<CardType> getCardType() {
return getCardType(null);
}
/**
* Return dynamic card types (game isn't null) or static card types (game is null)
*
* @param game can be null
* @return
*/
List<CardType> getCardType(Game game);
/**
* Return original object's subtypes
*
* @return
*/
SubTypes getSubtype();
/**
* Return full subtypes list (from object, from effects)
*
* @param game
* @return
*/
SubTypes getSubtype(Game game);
boolean hasSubtype(SubType subtype, Game game);
default List<SuperType> getSuperType() {
return getSuperType(null);
}
List<SuperType> getSuperType(Game game);
/**
* For cards: return basic abilities (without dynamic added)
* For permanents: return all abilities (dynamic ability inserts into permanent)
*
* @return
*/
Abilities<Ability> getAbilities();
/**
* Must return object specific abilities that will be added to the game
* It's a one time action on card/command object putting to the game
* <p>
* If your object contains inner cards/parts then each card will be added separately,
* see GameImpl.loadCards. So you must return only parent specific abilities here. All
* other abilities will be added from the parts.
*
* @return
*/
default Abilities<Ability> getInitAbilities() {
return getAbilities();
}
boolean hasAbility(Ability ability, Game game);
ObjectColor getColor();
ObjectColor getColor(Game game);
ObjectColor getFrameColor(Game game);
FrameStyle getFrameStyle();
ManaCosts<ManaCost> getManaCost();
void setManaCost(ManaCosts<ManaCost> costs);
default List<String> getManaCostSymbols() {
List<String> symbols = new ArrayList<>();
for (ManaCost cost : getManaCost()) {
symbols.add(cost.getText());
}
return symbols;
}
int getManaValue();
MageInt getPower();
MageInt getToughness();
int getStartingLoyalty();
void setStartingLoyalty(int startingLoyalty);
int getStartingDefense();
void setStartingDefense(int startingDefense);
// memory object copy (not mtg)
@Override
MageObject copy();
// copied card info (mtg)
void setCopy(boolean isCopy, MageObject copiedFrom);
MageObject getCopyFrom();
boolean isCopy();
int getZoneChangeCounter(Game game);
void updateZoneChangeCounter(Game game, ZoneChangeEvent event);
void setZoneChangeCounter(int value, Game game);
default boolean isHistoric(Game game) {
return isArtifact(game)
|| isLegendary(game)
|| hasSubtype(SubType.SAGA, game);
}
default boolean isOutlaw(Game game) {
return hasSubtype(SubType.ASSASSIN, game)
|| hasSubtype(SubType.MERCENARY, game)
|| hasSubtype(SubType.PIRATE, game)
|| hasSubtype(SubType.ROGUE, game)
|| hasSubtype(SubType.WARLOCK, game);
}
default boolean isCreature() {
return isCreature(null);
}
default boolean isCreature(Game game) {
return getCardType(game).contains(CardType.CREATURE);
}
default boolean isArtifact() {
return isArtifact(null);
}
default boolean isArtifact(Game game) {
return getCardType(game).contains(CardType.ARTIFACT);
}
default boolean isLand() {
return isLand(null);
}
default boolean isLand(Game game) {
return getCardType(game).contains(CardType.LAND);
}
default boolean isEnchantment() {
return isEnchantment(null);
}
default boolean isEnchantment(Game game) {
return getCardType(game).contains(CardType.ENCHANTMENT);
}
default boolean isInstant() {
return isInstant(null);
}
default boolean isInstant(Game game) {
return getCardType(game).contains(CardType.INSTANT);
}
default boolean isSorcery() {
return isSorcery(null);
}
default boolean isSorcery(Game game) {
return getCardType(game).contains(CardType.SORCERY);
}
default boolean isInstantOrSorcery() {
return this.isInstant() || this.isSorcery();
}
default boolean isInstantOrSorcery(Game game) {
return this.isInstant(game) || this.isSorcery(game);
}
default boolean isPlaneswalker() {
return isPlaneswalker(null);
}
default boolean isPlaneswalker(Game game) {
return getCardType(game).contains(CardType.PLANESWALKER);
}
default boolean isKindred() {
return isKindred(null);
}
default boolean isKindred(Game game) {
return getCardType(game).contains(CardType.KINDRED);
}
default boolean isBattle() {
return isBattle(null);
}
default boolean isBattle(Game game) {
return getCardType(game).contains(CardType.BATTLE);
}
default boolean isPermanent() {
return isCreature() || isArtifact() || isPlaneswalker() || isEnchantment() || isLand() || isBattle();
}
default boolean isPermanent(Game game) {
return isCreature(game) || isArtifact(game) || isPlaneswalker(game) || isEnchantment(game) || isLand(game) || isBattle(game);
}
default boolean isLegendary() {
return isLegendary(null);
}
default boolean isLegendary(Game game) {
return getSuperType(game).contains(SuperType.LEGENDARY);
}
default boolean isSnow() {
return isSnow(null);
}
default boolean isSnow(Game game) {
return getSuperType(game).contains(SuperType.SNOW);
}
default boolean isBasic() {
return isBasic(null);
}
default boolean isBasic(Game game) {
return getSuperType(game).contains(SuperType.BASIC);
}
default boolean isWorld() {
return isWorld(null);
}
default boolean isWorld(Game game) {
return getSuperType(game).contains(SuperType.WORLD);
}
default void addSuperType(SuperType superType) {
addSuperType(null, superType);
}
default void addSuperType(Game game, SuperType superType) {
List<SuperType> currentSuperTypes;
if (game != null) {
// dynamic
currentSuperTypes = game.getState().getCreateMageObjectAttribute(this, game).getSuperType();
} else {
// static
currentSuperTypes = getSuperType();
}
if (!currentSuperTypes.contains(superType)) {
currentSuperTypes.add(superType);
}
}
default void removeAllSuperTypes() {
removeAllSuperTypes(null);
}
default void removeAllSuperTypes(Game game) {
List<SuperType> currentSuperTypes;
if (game != null) {
// dynamic
currentSuperTypes = game.getState().getCreateMageObjectAttribute(this, game).getSuperType();
} else {
// static
currentSuperTypes = getSuperType();
}
currentSuperTypes.clear();
}
default void removeSuperType(SuperType superType) {
removeSuperType(null, superType);
}
default void removeSuperType(Game game, SuperType superType) {
List<SuperType> currentSuperTypes;
if (game != null) {
// dynamic
currentSuperTypes = game.getState().getCreateMageObjectAttribute(this, game).getSuperType();
} else {
// static
currentSuperTypes = getSuperType();
}
currentSuperTypes.remove(superType);
}
/**
* Add card type from static effects (permanently)
*
* @param cardTypes
*/
default void addCardType(CardType... cardTypes) {
addCardType(null, cardTypes);
}
/**
* Add card type from dynamic effects (game isn't null) and from static effects (game is null)
*
* @param game
* @param cardTypes
*/
default void addCardType(Game game, CardType... cardTypes) {
List<CardType> currentCardTypes;
if (game != null) {
// dynamic
currentCardTypes = game.getState().getCreateMageObjectAttribute(this, game).getCardType();
} else {
// static
currentCardTypes = getCardType();
}
for (CardType cardType : cardTypes) {
if (!currentCardTypes.contains(cardType)) {
currentCardTypes.add(cardType);
}
}
}
default void removeCardType(CardType... cardTypes) {
removeCardType(null, cardTypes);
}
default void removeCardType(Game game, CardType... cardTypes) {
List<CardType> currentCardTypes;
if (game != null) {
// dynamic
currentCardTypes = game.getState().getCreateMageObjectAttribute(this, game).getCardType();
} else {
// static
currentCardTypes = getCardType();
}
for (CardType cardType : cardTypes) {
currentCardTypes.remove(cardType);
}
}
default void removeAllCardTypes() {
removeAllCardTypes(null);
}
default void removeAllCardTypes(Game game) {
List<CardType> currentCardTypes;
if (game != null) {
// dynamic
currentCardTypes = game.getState().getCreateMageObjectAttribute(this, game).getCardType();
} else {
// static
currentCardTypes = getCardType();
}
currentCardTypes.clear();
}
/**
* Add subtype temporary, for continuous effects only
*
* @param game
* @param subTypes
*/
default void addSubType(Game game, Collection<SubType> subTypes) {
for (SubType subType : subTypes) {
addSubType(game, subType);
}
}
/**
* Add subtype permanently, for one shot effects and tokens setup
*
* @param subTypes
*/
default void addSubType(SubType... subTypes) {
for (SubType subType : subTypes) {
if (subType.canGain(this)
&& !getSubtype().contains(subType)) {
getSubtype().add(subType);
}
}
}
/**
* Add subtype temporary, for continuous effects only
*
* @param game
* @param subTypes
*/
default void addSubType(Game game, SubType... subTypes) {
for (SubType subType : subTypes) {
if (subType.canGain(game, this)
&& !hasSubtype(subType, game)) {
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().add(subType);
}
}
}
default void copySubTypesFrom(Game game, MageObject mageObject) {
copySubTypesFrom(game, mageObject, null);
}
default void copySubTypesFrom(Game game, MageObject mageObject, SubTypeSet subTypeSet) {
if (subTypeSet == SubTypeSet.CreatureType || subTypeSet == null) {
this.setIsAllCreatureTypes(game, mageObject.isAllCreatureTypes(game));
}
if (subTypeSet == SubTypeSet.NonBasicLandType || subTypeSet == null) {
this.setIsAllNonbasicLandTypes(game, mageObject.isAllNonbasicLandTypes(game));
}
for (SubType subType : mageObject.getSubtype(game)) {
if (subType.getSubTypeSet() == subTypeSet || subTypeSet == null) {
this.addSubType(game, subType);
}
}
}
default void removeAllSubTypes(Game game) {
removeAllSubTypes(game, null);
}
default void removeAllSubTypes(Game game, SubTypeSet subTypeSet) {
if (subTypeSet == null) {
setIsAllCreatureTypes(game, false);
setIsAllNonbasicLandTypes(game, false);
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().clear();
} else if (subTypeSet == SubTypeSet.CreatureType) {
removeAllCreatureTypes(game);
} else if (subTypeSet == SubTypeSet.NonBasicLandType) {
setIsAllNonbasicLandTypes(game, false);
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().removeAll(SubType.getLandTypes());
} else {
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().removeAll(SubType.getBySubTypeSet(subTypeSet));
}
}
default void retainAllArtifactSubTypes(Game game) {
setIsAllCreatureTypes(game, false);
setIsAllNonbasicLandTypes(game, false);
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().retainAll(SubType.getArtifactTypes());
}
default void retainAllEnchantmentSubTypes(Game game) {
setIsAllCreatureTypes(game, false);
setIsAllNonbasicLandTypes(game, false);
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().retainAll(SubType.getEnchantmentTypes());
}
default void retainAllLandSubTypes(Game game) {
setIsAllCreatureTypes(game, false);
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().retainAll(SubType.getLandTypes());
}
/**
* Remove object's own creature types forever (for copy effects usage)
*/
default void removeAllCreatureTypes() {
setIsAllCreatureTypes(false);
getSubtype().removeAll(SubType.getCreatureTypes());
}
/**
* Remove object attribute's creature types temporary (for continuous effects usage)
*
* @param game
*/
default void removeAllCreatureTypes(Game game) {
setIsAllCreatureTypes(game, false);
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().removeAll(SubType.getCreatureTypes());
}
default void removeSubType(Game game, SubType subType) {
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().remove(subType);
}
/**
* Checks whether two cards share card types.
*
* @param otherCard
* @param game
* @return
*/
default boolean shareTypes(Card otherCard, Game game) {
return this.shareTypes(otherCard, game, false);
}
default boolean shareTypes(Card otherCard, Game game, boolean permanentOnly) {
if (otherCard == null) {
throw new IllegalArgumentException("Params can't be null");
}
for (CardType type : getCardType(game)) {
if (otherCard.getCardType(game).contains(type)
&& (!permanentOnly || type.isPermanentType())) {
return true;
}
}
return false;
}
default boolean shareCreatureTypes(Game game, MageObject otherCard) {
if (!isCreature(game) && !isKindred(game)) {
return false;
}
if (!otherCard.isCreature(game) && !otherCard.isKindred(game)) {
return false;
}
boolean isAllA = this.isAllCreatureTypes(game);
boolean isAnyA = isAllA || this.getSubtype(game)
.stream()
.map(SubType::getSubTypeSet)
.anyMatch(SubTypeSet.CreatureType::equals);
boolean isAllB = otherCard.isAllCreatureTypes(game);
boolean isAnyB = isAllB || otherCard
.getSubtype(game)
.stream()
.map(SubType::getSubTypeSet)
.anyMatch(SubTypeSet.CreatureType::equals);
if (!isAnyA || !isAnyB) {
return false;
}
if (isAllA) {
return isAllB || isAnyB;
}
return isAnyA
&& (isAllB || this
.getSubtype(game)
.stream()
.filter(subType -> subType.getSubTypeSet() == SubTypeSet.CreatureType)
.anyMatch(subType -> otherCard.hasSubtype(subType, game)));
}
boolean isAllCreatureTypes(Game game);
void setIsAllCreatureTypes(boolean value);
/**
* Change all creature type mark temporary, for continuous effects only
*
* @param game
* @param value
*/
void setIsAllCreatureTypes(Game game, boolean value);
boolean isAllNonbasicLandTypes(Game game);
void setIsAllNonbasicLandTypes(boolean value);
/**
* Change all nonbasic land type mark temporary, for continuous effects only
*
* @param game
* @param value
*/
void setIsAllNonbasicLandTypes(Game game, boolean value);
void removePTCDA();
}