2
\$\begingroup\$

For example, let's say in total there may be 5 cards that are in the game, let's use:

Axe-thrower (3-cost, Creature, 5 Power, 3 Defense, Rush ability)

Ice Elemental (2-cost, Creature, 2 Power, 5 Defense, Crystalized ability)

Party Trick (3-cost, Spell, Swap the Power and defense of a single creature)

Blademaster (3-cost, Creature, 3 Power, 3 Defense, Gains +1/+1 for every other creature on the field)

Minefield (3-cost, Trap, Deal X damage to all enemies, where X is the number of creatures on the opponent's side of the field)

With those in mind, some have default values, which would be simple to store in the database, some would likely remain as 0's or another default value until their effects came into play, etc. Simple enough.

My question is more about how to handle the cards and their values once they're in decks, a player's hand, and on the field.

For example:

The Axe-Thrower is a 5/3 creature, but let's say it's buffed in some fashion - how am I differentiating an object which is the base version of a card, version the version which is modified in some way? The only values stored in the DB Would be the base values, not the modified ones, correct? Unless there was some kind of suspend functionality in which case I would have to track the modified values as well.

My initial thought of an implementation, at least for the Database side of things was as follows:

Cards (ID, Name) -- Base card

CardVersions (ID, CardID, Version, ImagePath, CardStatsID) -- Cards' stats dependent on version

CardStats (ID, Cost, Power, Defense) -- Stats for a given CardVersion

Now those would be the "base" cards, the following could be how the specific instances are handled?:

PlayerCards (ID, PlayerID, CardID, Count) -- Player's cards

Decks (ID, PlayerID, Name) -- Player's decks

DeckCards (ID, DeckID, PlayerCardID, Count) -- How many of a card in a given deck

Which is a decent start, I think, for the cards in a player's deck.

For the cards in a player's hand / on their field, would those all simply be references to the PlayerCards with objects that have modifiable versions of the stats? For example, a GameCard with Original Stats and Modified Stats, where the majority of the time, the Modified Stats will be the Original Stats to start, but will change as the cards are buffed or their abilities are invoked?

Am I missing a super-simple solution to this, what I would imagine, common case for TCGs?

\$\endgroup\$
  • 1
    \$\begingroup\$ Are any of these modifications to the cards supposed to persist after a round of the game is finished? If not then having the modifications be outside of the database in the way you describe seems fine. But if the modifications are not supposed to persist, then having the Cards, CardVersions and CardStats be separate tables seems overly complicated to me. If the values for those tables are all in one table you can still have two cards with the same name and stats but different art for example. \$\endgroup\$ – Ryan1729 Dec 3 '19 at 2:00
  • 1
    \$\begingroup\$ I'm also not sure why the DeckCards table uses a PlayerCardID rather than just a CardID. In fact the PlayerCard table looks like it could just use a composite key of PlayerID and CardID. \$\endgroup\$ – Ryan1729 Dec 3 '19 at 2:02
  • \$\begingroup\$ @Ryan1729 The reason I have the "PlayerCard" being referenced, instead of the Card is because I need to be able to track how many of each card the player has in their collection. Whether or not the card can be considered in the deck is dependent on whether or not the user still has that card in their collection. That being said, it's possible that my implementation is overkill even still. You're absolutely right about the composite key for PlayerCards - good call, thanks :) The separation of the Cards, CardVersions, and CardStats tables is still something I'm playing around with, for sure. \$\endgroup\$ – GrowingCode247 Dec 3 '19 at 2:34
  • \$\begingroup\$ Possible duplicate of Where and how to store players collection in a computer card game? \$\endgroup\$ – Philipp Dec 3 '19 at 19:57
  • \$\begingroup\$ @Philipp It's very clearly not a duplicate of that question at all. \$\endgroup\$ – Miles Rout Dec 3 '19 at 20:47
2
\$\begingroup\$

If you carefully read the text of Magic: the Gathering cards you will notice a distinction made between cards and 'permanents' and 'spells'. When a card is in play, say representing a creature that has been summoned, it is not just a card but a permanent. Things that aren't cards - like ephemeral 'tokens' made by other cards - are ALSO permanents if they're in play.

From a computer implemention perspective I think of this as having two different levels. Cards have all sorts of statistics associated with them but are essentially static. Very few very obscure effects track the identities of actual cards themselves. Most effects affect permanents, which would come in a few types: those that are a card would be a CardPermanent which contains a pointer to a card and represents a physical card on the battlefield, while a creature token that is created as a 'copy' of another permanent might be a TokenCopyPermanent that contains a pointer to another permanent.

Effects mostly affect permanents. Permanents can be enchanted, destroyed, damaged, blocked, etc. The card inside is mostly unaffected, but for example if a permanent that contains a card is destroyed, the card inside goes to the discard pile.

Your hand contains plain cards. You can't have tokens in your hand or in your deck. When you cast a card it goes onto the stack, where it's a SPELL rather than a permanent, and again you can have effects that affect spells (countering them, copying them, etc.) and you can create noncard spells, although I don't think MTG calls them 'tokens' in this case.

This multi level approach separates things quite nicely and I have used it in an implementation of a subset of magic's rules. It seems to have covered everything I've needed to do so far.

\$\endgroup\$
  • 1
    \$\begingroup\$ I'd add that whatever you do to deal with differently versions of cards, try to avoid the problem that the MTGO developers had where different printings of the same card that should be functionally identical somehow had different bugs! \$\endgroup\$ – Miles Rout Dec 3 '19 at 19:12
  • \$\begingroup\$ Good call on watching out for weird version-related bugs. Also, it would probably suffice to have only a permanent object and simply set an "IsToken" flag, right? And still reference the appropriate card? \$\endgroup\$ – GrowingCode247 Dec 4 '19 at 22:30
  • \$\begingroup\$ @GrowingCode247 It depends how you want the rules to work, of course! But the way it works in Magic, the card itself isn't duplicated, because it's a computer simulation of a physical card game and you can't physically duplicate Magic cards on the spot in real life. So when a token copy of a creature dies, it works differently in the sense that the underlying card doesn't go to the graveyard (discard pile), while if the original creature dies, the card does go to your graveyard. If the game you are implementing is digital-first like Hearthstone then yes of course you can blur this distinction. \$\endgroup\$ – Miles Rout Dec 4 '19 at 22:59
  • \$\begingroup\$ @GrowingCode247 To be clear, this answer wasn't really intended to be about copying specifically, but just about the general distinction between cards (which can't be copied or destroyed, can survive changing zones, etc.) and permanents and spells which may or may not contain a card, can be targeted, exist on the battlefield/stack, etc. In Magic when a card changes zones it becomes a new object, and when tokens are put into the graveyard for example they cease to exist. \$\endgroup\$ – Miles Rout Dec 4 '19 at 23:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.