diff --git a/Mage.Sets/src/mage/cards/g/GoldbugHumanitysAlly.java b/Mage.Sets/src/mage/cards/g/GoldbugHumanitysAlly.java
new file mode 100644
index 0000000000..7f00881bbe
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/g/GoldbugHumanitysAlly.java
@@ -0,0 +1,63 @@
+package mage.cards.g;
+
+import mage.MageInt;
+import mage.abilities.common.CastSecondSpellTriggeredAbility;
+import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.effects.common.PreventAllDamageToAllEffect;
+import mage.abilities.effects.common.TransformSourceEffect;
+import mage.abilities.keyword.MoreThanMeetsTheEyeAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.SubType;
+import mage.constants.SuperType;
+import mage.filter.FilterPermanent;
+import mage.filter.common.FilterControlledCreaturePermanent;
+import mage.filter.predicate.permanent.AttackingPredicate;
+
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class GoldbugHumanitysAlly extends CardImpl {
+
+ private static final FilterPermanent filter
+ = new FilterControlledCreaturePermanent(SubType.HUMAN, "attacking Humans you control");
+
+ static {
+ filter.add(AttackingPredicate.instance);
+ }
+
+ public GoldbugHumanitysAlly(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{W}{U}");
+
+ this.addSuperType(SuperType.LEGENDARY);
+ this.subtype.add(SubType.ROBOT);
+ this.power = new MageInt(3);
+ this.toughness = new MageInt(3);
+
+ this.secondSideCardClazz = mage.cards.g.GoldbugScrappyScout.class;
+
+ // More Than Meets the Eye {W}{U}
+ this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{W}{U}"));
+
+ // Prevent all combat damage that would be dealt to attacking Humans you control.
+ this.addAbility(new SimpleStaticAbility(new PreventAllDamageToAllEffect(
+ Duration.WhileOnBattlefield, filter, true
+ )));
+
+ // Whenever you cast your second spell each turn, convert Goldbug.
+ this.addAbility(new CastSecondSpellTriggeredAbility(new TransformSourceEffect().setText("convert {this}")));
+ }
+
+ private GoldbugHumanitysAlly(final GoldbugHumanitysAlly card) {
+ super(card);
+ }
+
+ @Override
+ public GoldbugHumanitysAlly copy() {
+ return new GoldbugHumanitysAlly(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/g/GoldbugScrappyScout.java b/Mage.Sets/src/mage/cards/g/GoldbugScrappyScout.java
new file mode 100644
index 0000000000..59348487c9
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/g/GoldbugScrappyScout.java
@@ -0,0 +1,104 @@
+package mage.cards.g;
+
+import mage.MageInt;
+import mage.abilities.TriggeredAbilityImpl;
+import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.effects.common.CantBeCounteredControlledEffect;
+import mage.abilities.effects.common.DrawCardSourceControllerEffect;
+import mage.abilities.effects.common.TransformSourceEffect;
+import mage.abilities.keyword.LivingMetalAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.*;
+import mage.filter.FilterSpell;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+
+import java.util.Objects;
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class GoldbugScrappyScout extends CardImpl {
+
+ private static final FilterSpell filter = new FilterSpell("Human spells");
+
+ static {
+ filter.add(SubType.HUMAN.getPredicate());
+ }
+
+ public GoldbugScrappyScout(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "");
+
+ this.addSuperType(SuperType.LEGENDARY);
+ this.subtype.add(SubType.VEHICLE);
+ this.power = new MageInt(1);
+ this.toughness = new MageInt(3);
+ this.color.setWhite(true);
+ this.color.setBlue(true);
+ this.nightCard = true;
+
+ // Living metal
+ this.addAbility(new LivingMetalAbility());
+
+ // Human spells you control can't be countered.
+ this.addAbility(new SimpleStaticAbility(new CantBeCounteredControlledEffect(
+ filter, Duration.WhileOnBattlefield
+ )));
+
+ // Whenever Goldbug and at least one Human attack, draw a card and convert Goldbug.
+ this.addAbility(new GoldbugScrappyScoutTriggeredAbility());
+ }
+
+ private GoldbugScrappyScout(final GoldbugScrappyScout card) {
+ super(card);
+ }
+
+ @Override
+ public GoldbugScrappyScout copy() {
+ return new GoldbugScrappyScout(this);
+ }
+}
+
+class GoldbugScrappyScoutTriggeredAbility extends TriggeredAbilityImpl {
+
+ GoldbugScrappyScoutTriggeredAbility() {
+ super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1));
+ this.addEffect(new TransformSourceEffect());
+ }
+
+ private GoldbugScrappyScoutTriggeredAbility(final GoldbugScrappyScoutTriggeredAbility ability) {
+ super(ability);
+ }
+
+ @Override
+ public GoldbugScrappyScoutTriggeredAbility copy() {
+ return new GoldbugScrappyScoutTriggeredAbility(this);
+ }
+
+ @Override
+ public boolean checkEventType(GameEvent event, Game game) {
+ return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS;
+ }
+
+ @Override
+ public boolean checkTrigger(GameEvent event, Game game) {
+ return game
+ .getCombat()
+ .getAttackers()
+ .contains(getSourceId())
+ && game
+ .getCombat()
+ .getAttackers()
+ .stream()
+ .map(game::getPermanent)
+ .filter(Objects::nonNull)
+ .anyMatch(permanent -> permanent.hasSubtype(SubType.HUMAN, game));
+ }
+
+ @Override
+ public String getRule() {
+ return "Whenever {this} and at least one Human attack, draw a card and convert {this}.";
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/Transformers.java b/Mage.Sets/src/mage/sets/Transformers.java
index f2fd1730fe..482b00b78c 100644
--- a/Mage.Sets/src/mage/sets/Transformers.java
+++ b/Mage.Sets/src/mage/sets/Transformers.java
@@ -1,6 +1,7 @@
package mage.sets;
import mage.cards.ExpansionSet;
+import mage.constants.Rarity;
import mage.constants.SetType;
/**
@@ -17,5 +18,8 @@ public final class Transformers extends ExpansionSet {
private Transformers() {
super("Transformers", "BOT", ExpansionSet.buildDate(2022, 11, 18), SetType.SUPPLEMENTAL);
this.hasBasicLands = false;
+
+ cards.add(new SetCardInfo("Goldbug, Humanity's Ally", 11, Rarity.MYTHIC, mage.cards.g.GoldbugHumanitysAlly.class));
+ cards.add(new SetCardInfo("Goldbug, Scrappy Scout", 11, Rarity.MYTHIC, mage.cards.g.GoldbugScrappyScout.class));
}
}
diff --git a/Mage/src/main/java/mage/abilities/keyword/LivingMetalAbility.java b/Mage/src/main/java/mage/abilities/keyword/LivingMetalAbility.java
new file mode 100644
index 0000000000..9504e5b3c0
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/keyword/LivingMetalAbility.java
@@ -0,0 +1,36 @@
+package mage.abilities.keyword;
+
+import mage.abilities.common.EntersBattlefieldTriggeredAbility;
+import mage.abilities.condition.common.MyTurnCondition;
+import mage.abilities.decorator.ConditionalContinuousEffect;
+import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect;
+import mage.abilities.hint.common.MyTurnHint;
+import mage.constants.CardType;
+import mage.constants.Duration;
+
+/**
+ * @author TheElk801
+ */
+public class LivingMetalAbility extends EntersBattlefieldTriggeredAbility {
+
+ public LivingMetalAbility() {
+ super(new ConditionalContinuousEffect(new AddCardTypeSourceEffect(
+ Duration.WhileOnBattlefield, CardType.ARTIFACT, CardType.CREATURE
+ ), MyTurnCondition.instance, ""));
+ this.addHint(MyTurnHint.instance);
+ }
+
+ public LivingMetalAbility(final LivingMetalAbility ability) {
+ super(ability);
+ }
+
+ @Override
+ public LivingMetalAbility copy() {
+ return new LivingMetalAbility(this);
+ }
+
+ @Override
+ public String getRule() {
+ return "Living metal (As long as it's your turn, this Vehicle is also a creature.)";
+ }
+}
diff --git a/Mage/src/main/java/mage/abilities/keyword/MoreThanMeetsTheEyeAbility.java b/Mage/src/main/java/mage/abilities/keyword/MoreThanMeetsTheEyeAbility.java
new file mode 100644
index 0000000000..fac02e3cf4
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/keyword/MoreThanMeetsTheEyeAbility.java
@@ -0,0 +1,96 @@
+package mage.abilities.keyword;
+
+import mage.abilities.Ability;
+import mage.abilities.SpellAbility;
+import mage.abilities.costs.mana.ManaCostsImpl;
+import mage.abilities.effects.ContinuousEffectImpl;
+import mage.cards.Card;
+import mage.constants.*;
+import mage.game.Game;
+import mage.game.stack.Spell;
+
+/**
+ * @author weirddan455, JayDi85, TheElk801 (based heavily on disturb)
+ */
+public class MoreThanMeetsTheEyeAbility extends SpellAbility {
+
+ private final String manaCost;
+ private SpellAbility spellAbilityToResolve;
+
+ public MoreThanMeetsTheEyeAbility(Card card, String manaCost) {
+ super(card.getSecondFaceSpellAbility());
+ this.newId();
+
+ // getSecondFaceSpellAbility() already verified that second face exists
+ this.setCardName(card.getSecondCardFace().getName() + " with Disturb");
+ this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE;
+ this.spellAbilityCastMode = SpellAbilityCastMode.DISTURB;
+
+ this.manaCost = manaCost;
+ this.getManaCosts().clear();
+ this.getManaCostsToPay().clear();
+ this.addManaCost(new ManaCostsImpl<>(manaCost));
+ this.addSubAbility(new TransformAbility());
+ }
+
+ private MoreThanMeetsTheEyeAbility(final MoreThanMeetsTheEyeAbility ability) {
+ super(ability);
+ this.manaCost = ability.manaCost;
+ this.spellAbilityToResolve = ability.spellAbilityToResolve;
+ }
+
+ @Override
+ public MoreThanMeetsTheEyeAbility copy() {
+ return new MoreThanMeetsTheEyeAbility(this);
+ }
+
+ @Override
+ public boolean activate(Game game, boolean noMana) {
+ if (super.activate(game, noMana)) {
+ game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getSourceId(), Boolean.TRUE);
+ // TODO: must be removed after transform cards (one side) migrated to MDF engine (multiple sides)
+ game.addEffect(new MoreThanMeetsTheEyeEffect(), this);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String getRule(boolean all) {
+ return this.getRule();
+ }
+
+ @Override
+ public String getRule() {
+ return "More Than Meets The Eye " + this.manaCost
+ + " (You may cast this card converted for" + this.manaCost + ".)";
+ }
+}
+
+class MoreThanMeetsTheEyeEffect extends ContinuousEffectImpl {
+
+ public MoreThanMeetsTheEyeEffect() {
+ super(Duration.WhileOnStack, Layer.CopyEffects_1, SubLayer.CopyEffects_1a, Outcome.BecomeCreature);
+ staticText = "";
+ }
+
+ private MoreThanMeetsTheEyeEffect(final MoreThanMeetsTheEyeEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public MoreThanMeetsTheEyeEffect copy() {
+ return new MoreThanMeetsTheEyeEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Spell spell = game.getSpell(source.getSourceId());
+ if (spell == null || spell.getCard().getSecondCardFace() == null) {
+ return false;
+ }
+ // simulate another side as new card (another code part in spell constructor)
+ TransformAbility.transformCardSpellDynamic(spell, spell.getCard().getSecondCardFace(), game);
+ return true;
+ }
+}
diff --git a/Utils/keywords.txt b/Utils/keywords.txt
index de11461294..e82af89e24 100644
--- a/Utils/keywords.txt
+++ b/Utils/keywords.txt
@@ -68,6 +68,7 @@ Jump-start|card|
Kicker|manaString|
Level up|cost|
Lifelink|instance|
+Living metal|new|
Living weapon|new|
Madness|cost|
Melee|new|
@@ -77,6 +78,7 @@ Miracle|manaString|
Modular|card, number|
Mountaincycling|cost|
Mountainwalk|new|
+More Than Meets The Eye|card, manaString|
Morph|cost|
Mutate|card, manaString|
Myriad|new|
diff --git a/Utils/known-sets.txt b/Utils/known-sets.txt
index 1a881b1a31..67243862d7 100644
--- a/Utils/known-sets.txt
+++ b/Utils/known-sets.txt
@@ -222,6 +222,7 @@ Throne of Eldraine|ThroneOfEldraine|
Time Spiral|TimeSpiral|
Time Spiral "Timeshifted"|TimeSpiralTimeshifted|
Torment|Torment|
+Transformers|Transformers|
Ugin's Fate|UginsFate|
Unglued|Unglued|
Unhinged|Unhinged|
diff --git a/Utils/mtg-sets-data.txt b/Utils/mtg-sets-data.txt
index 4efab5a564..e9631293a3 100644
--- a/Utils/mtg-sets-data.txt
+++ b/Utils/mtg-sets-data.txt
@@ -218,6 +218,7 @@ Torment|TOR|
Tempest Remastered|TPR|
Time Spiral "Timeshifted"|TSB|
Time Spiral|TSP|
+Transformers|BOT|
Urza's Destiny|UDS|
Ugin's Fate|UGIN|
Unglued|UGL|