The new forums will be named Coin Return (based on the most recent vote)! You can check on the status and timeline of the transition to the new forums here.
The Guiding Principles and New Rules document is now in effect.

Magic the Gathering Online... how'd they do it?

VThornheartVThornheart Registered User regular
edited April 2008 in Help / Advice Forum
Okay, so last night I came up with this idea for a CCG (Well, I'd been thinking about it for a while, but last night I finally hashed out enough of the rules that I felt making some sort of demo was in order), and I figured it might be a fun project to try and make a playable version of it on the computer as my prototype. It'd help a lot with playtesting and might (as a consequence) force me to make a structured database of the cards that I tentatively picture being in the first set.

However, when I sat down to start designing the game, I ran into a problem that I hadn't thought of. In any CCG, some cards can have extremely complex rules: they may have actions that trigger based on events in the game, actions that are activated by the user allocating resources, and even permanent actions that should take place for the entirety of the time that they're in play.

My first thought on how I'd make the game was to make a database of cards and their actions, but as the design went on it ended up being a gigantic and cumbersome web full of specialized niches for specific card examples I was imagining, but it would've been utterly unable to handle any generic card thrown at it.

Then I thought about Magic: The Gathering Online. Surely they ran into the same problem. What did they do? Searching the 'net has led nowhere thus far as to finding out how MTGO might have done it, and though their system is flawed in some aspects it's also impressively consistent and usable.

I have two guesses as to what they might've done, and neither might actually be it:

1) They have some kind of advanced parsing engine that parses the English text of each card and react to it as needed. (Though this would break down for cards with complex rules such as the Ink-Treader Nephilim or old cards that had inconsistent wording, so I'm not confident that this is what's happening)

2) They have some kind of scripting engine or plugin embedded into the game (perhaps on the server side), and each card has a script that programmatically details what's to be done in various situations (in response to game events, activated by user, etc...). This seems more likely than (1), but it also seems like this would be exceptionally cumbersome (having to explicitly program the features of every card). Also, how would they get the scripts incorporated in the game? Calling script in a compiled program is a subject that I'm unfamiliar with... I know it's done, but I don't know *how* it's done.

TL;DR

I'm looking to have a brainstorm session about the best way to go about enforcing rules on a card in a CCG. The ways I've thought of don't seem ideal, and I'm at a loss for other alternatives.

3DS Friend Code: 1950-8938-9095
VThornheart on

Posts

  • SzechuanosaurusSzechuanosaurus Registered User, ClubPA regular
    edited April 2008
    Yeah, I can't see it being a text parser. It would seem more likely to me that the rules for the card come from the card being played itself rather than the game 'listening' for every single possible eventuality in a huge list. Each card is going to have a relatively small number of individual rules and modifiers applied to itself so it makes sense for that card to 'carry' those rules into the game as needed. I'm not that hot on this sort of thing so it's kind of hard to explain, but perhaps The Sims would help me explain what I mean.

    In The Sims, the characters themselves have a very limited AI set - they basically just have a series of needs - and yet they can interact in a massive number of ways with all sorts of objects - furniture - that can be dropped into the game. What's more, the game easily allows for more furniture to be designed and included post-release without having to rewrite all the game code, just small snippets of code for each new piece of furniture. The way the designers made the game this flexible was to load the furniture rather than the characters with all the AI information. So you have these characters that are basically about as complicated as a single-cell organism with needs at varying levels of importance and then you have all this furniture that advertises it's capabilities to the character. If the furniture has what the character needs most at that time and can satisfy it better than other nearby furniture the character is compelled towards it and then upon interacting with it, the furniture deals with animating the character and so forth.

    Your problem is pretty different, but I think this context-sensitive approach is probably the neatest way to go. Less cumbersome having to write the main game code to second-guess every eventuality and will probably run a lot faster as well.

    Szechuanosaurus on
  • VThornheartVThornheart Registered User regular
    edited April 2008
    Aye, that's definitely a helpful analogy. If that's the way the Sims does it, it sounds like they're taking more of a "write a script for every object" approach, which definitely does seem more reasonable.

    So the key would be to have a robust enough API so that the "card rule scripts" would be able to affect other cards in the game and the state of the game itself... is that how it works in the Sims? Like when you create furniture, do you have to write a script (that uses some specialized Sims API or something) to reveal its functionality?

    I guess I could go look it up... this definitely seems like a point in the right direction though, thanks Szechuanosaurus! =) I'll report back with what I find.

    EDIT:

    http://www.gamedev.net/columns/events/coverage/feature.asp?feature_id=51

    I found this link, which doesn't give the details about how scripting was done (on a technical level) in the Sims 2, but definitely verifies that the interactive objects use some sort of exceptionally robust script to represent each object.

    This is making me think that perhaps instead of thinking in terms of a database with scripts just for the actions, perhaps I should be thinking about making each card a full Script object. Originally I was thinking that the database would hold common or non-complex information, such as resource costs to play cards, flavor text etc... but perhaps what I could do instead is centralize all the information for an individual card into one script file that had all of that.

    Hmm. I'll need to think about it further... any more information that anyone finds/can contribute to the conversation would be awesome, thanks again! =)

    VThornheart on
    3DS Friend Code: 1950-8938-9095
  • SzechuanosaurusSzechuanosaurus Registered User, ClubPA regular
    edited April 2008
    Yeah, the way I understand it, furniture in the Sims basically broadcasts it's benefits to the sim. If the sim needs what it's selling (ie, if it's bored and the TV set is saying - I've give 10 units of entertainment per minute) then it'll choose to interact with it. If the Sim is a little bit bored but really hungry, the Fridge will win out because it might only serve 5 units of hunger satisfaction per minute but the sim needs that more than it needs entertainment at that particular moment.

    I suppose if you have a card that modifies one or more cards or rules then you need to have that card tell the other cards or rules that they've been modified rather than having the cards and rules ask if they are being modified.

    It's like doing hit detection in an action game. Sometimes it easier to tell an object when it's been hit rather than having it constantly check if anything has hit it.

    I only really understand scripting from ActionScript in Flash, but what I'd probably think about doing is take an object oriented approach to actions. There'll be lots of common actions that just differ in the values fed into them, so all monster cards can use the same attack script kept in one place and the card just passes it's attack and defense values to the script that process them when it needs to attack. So yeah, the cards would hold all the raw values applicable to them but the scripts that process those values would be kept in a central place for easier editing. Which is kind of how it works when you play MtG for real, when you thin about it. You and your opponent know all the rules and how to handle encounters and values but you don't actually do any of that until a card is played and you can read the values off it.

    Szechuanosaurus on
  • VThornheartVThornheart Registered User regular
    edited April 2008
    Yeah, the way I understand it, furniture in the Sims basically broadcasts it's benefits to the sim. If the sim needs what it's selling (ie, if it's bored and the TV set is saying - I've give 10 units of entertainment per minute) then it'll choose to interact with it. If the Sim is a little bit bored but really hungry, the Fridge will win out because it might only serve 5 units of hunger satisfaction per minute but the sim needs that more than it needs entertainment at that particular moment.

    I suppose if you have a card that modifies one or more cards or rules then you need to have that card tell the other cards or rules that they've been modified rather than having the cards and rules ask if they are being modified.

    It's like doing hit detection in an action game. Sometimes it easier to tell an object when it's been hit rather than having it constantly check if anything has hit it.

    I only really understand scripting from ActionScript in Flash, but what I'd probably think about doing is take an object oriented approach to actions. There'll be lots of common actions that just differ in the values fed into them, so all monster cards can use the same attack script kept in one place and the card just passes it's attack and defense values to the script that process them when it needs to attack. So yeah, the cards would hold all the raw values applicable to them but the scripts that process those values would be kept in a central place for easier editing. Which is kind of how it works when you play MtG for real, when you thin about it. You and your opponent know all the rules and how to handle encounters and values but you don't actually do any of that until a card is played and you can read the values off it.

    Hmm... that's true! I hadn't thought about it that way (thinking about how you play MtG in real life in terms of scripts).

    Aye... so if I can find a scripting language that perhaps supports inheritance or something like that, I can make some base "card" objects that perform all the common actions... and then have the scripts for individual cards just have what differentiates them.

    You bring up a good point with a card needing to tell another card that it's modifying said target. I've never really used external scripting in any programming I've ever done before, so I need to research it more... but I imagine all of this could be possible. The common API could have some kind of querying capacity to retrieve one or more cards that match certain criteria (such as a user selecting it as a "target", or finding all the cards of a certain type that are controlled by the opponent, etc...), and then the cards themselves would have to have methods that would allow another card to modify them (or even associate the two together... like one card "owning" another, such as in Magic when you equip an artifact or place an enchantment on a specific card. Hmm....).

    I'm going to need to look more into how scripting languages can be incorporated into a program for this kind of purpose. Does anyone have any good resources on this? I'll start looking on my own as well.

    EDIT: Hmm... I see Microsoft is going to make this annoying to do in a CLR language. Apparently their native scripting solution (Vsa) was deprecated some years ago. I'll keep reading, maybe there's another solution... I'd definitely rather not try to hack my own solution here. The problem's become complex enough as it is. =)

    EDIT 2: VSTA! Apparently Visual Studio Tools for Applications provides a scripting engine that has full .NET Framework support. This could be what I was looking for. Must... read... more. I found a little teaser video about it, looking for some kind of tutorial/reference/something more substantial as we speak.

    VThornheart on
    3DS Friend Code: 1950-8938-9095
  • LegionnairedLegionnaired Registered User regular
    edited April 2008
    Just a thought, look into Ruby...

    It has a lot of neat tools for evaluating commands 'in the context of' certain objects. It also has some nifty on-the-fly re-classing and method definition things that can be pretty cool.

    For example, you can make a 'card' class with all the usual functions. Then, if you equip something to it, you can have the equip command do an instance_eval that defines a public method. Your right-click context menu can simply list every public method available to the card, perhaps passing through a 'rules' object, that filters out things that are impossible.

    So, for example, if I want to give something the ability to instant-speed poke for one:
    class Boots_of_Poking < Artifact  # boots of poking inherit the artifact actions
    def equip(some_card)
     define_command = "def Instant_Use_Boots_Of_Poking(target)
       target.find_in_game.Gamestate_Deal_Damage(1)
    end"
     instance_eval(some_card, define_comand)
    end
    
    and then your context menu:
    def context(somecard)
     somecard.find_in_gamestate.methods.filter_by_instant_or_sorcery.display
    end
    

    Hope that makes sense.

    Also, since everything is an object in Ruby, and objects all have an object_id, you're able to specify easily 'that prodigal sorcerer, not this one' (that's probably what the find_in_gamestate mock-up method I've written will do, return the object such that self = object.object_id.

    Yeah, sorry, way ahead of myself.

    Come to think of it, aside from all the display bits, all this business logic wouldn't be too terribly difficult to write. If you can handle the display elements, maybe I could contribute!

    Legionnaired on
  • DeathPrawnDeathPrawn Registered User regular
    edited April 2008
    Another important thing to consider with M:TG is that each turn is broken up into phases. The way I'm envisioning the code, you would iterate through each card in play, with each one checking if it needs to apply its ability or abilities. It would probably be best to have a flag for each ability that tells it at what point it needs to decide to activate or not (i.e. an enchantment that grands a bonus when attacking will only ever need to use its ability during the attack phase of your turn).

    DeathPrawn on
    Signature not found.
  • VThornheartVThornheart Registered User regular
    edited April 2008
    Just a thought, look into Ruby...

    It has a lot of neat tools for evaluating commands 'in the context of' certain objects. It also has some nifty on-the-fly re-classing and method definition things that can be pretty cool.

    (interesting code bits snipped for brevity =) )

    Hmm, interesting! I'll definitely look into Ruby. I've been meaning to learn Ruby for some time now, but never had a side project in mind that'd get me to actually figure it out. =)

    I like that you can programmatically refer to methods (as if they were objects themselves... are they in Ruby? Interesting idea!), that would allow for a very different way of looking at it than I had previously considered.

    Is instance_eval a method provided by Ruby itself? What's it do? Hmm... perhaps I should start reading up on Ruby.

    As far as the actual development itself goes, it could be a good collaborative project... though part of me wants to "maverick" this so I actually know what's going on (and hopefully apply the concepts/technologies I learn along the way to other projects later). It's been a long time since I've been excited about a non-work related project, and I want to see where it takes me.

    The last time I got excited was when I made BabelFish for WoW, which was a simple mod but I felt good about it... and then when I joined up with the guys that made the MorseCode and LeetSpeak mods to make a single universal interface, they ran with it (adding many really neat features) and did a great job: but by the time it was done I had no idea what was going on in the program anymore. =) I think this time I want to, at least for this specific instance of the concept, see where I can bring it on my own. But...

    Perhaps we could spin this off into a more generic project that those who are interested in could collaborate on? I think it'd be neat if we could end up making some sort of "all purpose" CCG rules processor (that let people script their own plugins for specific card games etc...). It'd be way beyond the scope of my original idea (making a demo for my own CCG), but it would be a really awesome open source project that everyone could get together to work on.

    VThornheart on
    3DS Friend Code: 1950-8938-9095
  • VThornheartVThornheart Registered User regular
    edited April 2008
    DeathPrawn wrote: »
    Another important thing to consider with M:TG is that each turn is broken up into phases. The way I'm envisioning the code, you would iterate through each card in play, with each one checking if it needs to apply its ability or abilities. It would probably be best to have a flag for each ability that tells it at what point it needs to decide to activate or not (i.e. an enchantment that grands a bonus when attacking will only ever need to use its ability during the attack phase of your turn).

    Aye, true... (and in traditional CCG fashion, my turns would go in phases as well... I can't imagine another way to do it sadly, though I tried. =( ) I'm envisioning a kind of "event based" system for that, if it is possible to do with scripts as the main objects.

    Basically, when a card comes into play it would register itself to be notified (called back to) when certain events took place... for example...

    Say you play an instant card that says "At the end of turn, destroy target permanent." When it resolves successfully, the instance of the card's script object would register itself with the game, requesting to observe the "end of turn" event.

    When the end of turn came around, all observers of the event would be notified through their callback method, and they could use the game's API to do whatever in-game function was intended to be done (in this case, destroying a card that was targeted when the instant first resolved).

    That's how I'm picturing it working, at least. In practice, I'm not sure how that'd work with the "scripting engine" approach involved, nor with the "Ruby" approach (as I'm inexperienced with both at the moment, but hopefully not for long ;) ). I know that's what I'd do if they were just standard, native classes and objects in the language.

    VThornheart on
    3DS Friend Code: 1950-8938-9095
  • vonPoonBurGervonPoonBurGer Registered User regular
    edited April 2008
    In any CCG, some cards can have extremely complex rules: they may have actions that trigger based on events in the game, actions that are activated by the user allocating resources, and even permanent actions that should take place for the entirety of the time that they're in play.
    Sounds like a good case for event handling. Internally, you code every card to broadcast events. For example, say you're tapping a land in M:TG Online. It could broadcast a "land tapped" event. Maybe it's even more specific than that, you have some constants (land types, mana types) and it specifies those in the event. So you tap a swamp, and it broadcasts "land tapped, land type is basic, mana type is black". If you had an enchantment that said something like "player gains 1 life whenever a swamp is tapped", you just have it listen for the "land tapped, land type is basic, mana type is black" event, and trigger it's effect (+1 life) whenever it sees that event. I'd say that's probably the easiest way to handle card effects in response to an in-game event. You have to be diligent about making sure each card is fully populated with broadcasts for the events it creates, and listeners for the events it needs to react to, but it makes it so that you don't have to revisit your entire card codebase every time you create a new card.
    Yeah, I can't see it being a text parser.
    Actually, I could see text parsing being useful, if the OP's game use the Foo rule. The Foo rule basically means that if a card says "foo" somewhere in the card title, then it is a Foo card. That saves print card designers a lot of hassle, because if they make a card called "Shadow Ninja", but forget to give him the "Ninja" trait in the spot on the card where traits go, then you'll have players arguing over whether or not that card should be considered a "Ninja" card for the purposes of being targeted by cards that affect ninjas. In a computerized context, you could easily have a card send its card title text as part of any events it produces. Then you can do a simple regex on the title to tell whether or not the source of the event is a swamp, or whatever. Or for global events in the game (e.g. "Pirate Assault - All ninjas in play are destroyed"), you just regex the titles of all the cards in play to see whether they contain the string "ninja". If physical card designers have found that the Foo rule saves them a lot of hassle with obsessively specifying card traits, I bet it would work for the OP's computerized version as well.
    wrote:
    The way I'm envisioning the code, you would iterate through each card in play, with each one checking if it needs to apply its ability or abilities.
    If you use an event system, you don't have to iterate through every card at the start of every phase. If a card that performs an effect at the start of each upkeep phase, then you have your app produce an "upkeep phase is starting" event, and code the card to trigger its effect when it sees that event. You'd need two events per phase, I think, a start event and an end event, since it's not uncommon to see "At the start of..." or "At the end of...".

    vonPoonBurGer on
    Xbox Live:vonPoon | PSN: vonPoon | Steam: vonPoonBurGer
  • LegionnairedLegionnaired Registered User regular
    edited April 2008
    Just a thought, look into Ruby...

    It has a lot of neat tools for evaluating commands 'in the context of' certain objects. It also has some nifty on-the-fly re-classing and method definition things that can be pretty cool.

    (interesting code bits snipped for brevity =) )

    Hmm, interesting! I'll definitely look into Ruby. I've been meaning to learn Ruby for some time now, but never had a side project in mind that'd get me to actually figure it out. =)

    I like that you can programmatically refer to methods (as if they were objects themselves... are they in Ruby? Interesting idea!), that would allow for a very different way of looking at it than I had previously considered.

    Is instance_eval a method provided by Ruby itself? What's it do? Hmm... perhaps I should start reading up on Ruby.

    As far as the actual development itself goes, it could be a good collaborative project... though part of me wants to "maverick" this so I actually know what's going on (and hopefully apply the concepts/technologies I learn along the way to other projects later). It's been a long time since I've been excited about a non-work related project, and I want to see where it takes me.

    The last time I got excited was when I made BabelFish for WoW, which was a simple mod but I felt good about it... and then when I joined up with the guys that made the MorseCode and LeetSpeak mods to make a single universal interface, they ran with it (adding many really neat features) and did a great job: but by the time it was done I had no idea what was going on in the program anymore. =) I think this time I want to, at least for this specific instance of the concept, see where I can bring it on my own. But...

    Perhaps we could spin this off into a more generic project that those who are interested in could collaborate on? I think it'd be neat if we could end up making some sort of "all purpose" CCG rules processor (that let people script their own plugins for specific card games etc...). It'd be way beyond the scope of my original idea (making a demo for my own CCG), but it would be a really awesome open source project that everyone could get together to work on.

    The Object#methods call returns an array of all methods available to the current object. Since all objects inherit from Object, they all have that method.

    So, what you can do is, if you want to look at all the sorcery-speed tricks available through a card object, you can do:

    Card.methods.select{|method| method =~ /Sorcery/}.display

    (So, return the list of every method that includes "Sorcery", and then call the 'display' method on it, which presumably displays some sort of tooltip menu.)

    That ugly select method, though, can be abstracted away through the method_missing method, which is also inherited from Object, but you can-re-define it to do whatever you want
    def method_missing(:method, *args)
     method = :method.to_s
     if =~ /Select(.*)/
       # use the result of the regex match to figure out what we're going to be selecting by
       selection_parameters = $1.split('_')
       commandstring = ""
       selection_parameters.each do |parameter|
         next if parameter =~ /by/ #ignore by... that's assumed
         if parameter =~ /and/
           commandstring += ' && '
         elsif parameter =~ /or/
           commandstring += ' || '
         else
           commandstring += ' method =~ /#{parameter}/ '
       end
      else super
    end
    end
    

    and then we can just do an 'eval' on that commandstring, and we have our method... dynamically parsed!

    So 'Select_By_Sorcery_And_Instant' and 'Select_By_Instant' are both valid method parsers.

    Now granted, this isn't the speediest way to do things, but it simplifies things quite a bit, as all you need are a few 'glue' methods and classes, and you've got the objects talking directly to the display. You can even abstract that whole methods.select mess with:
    def menu(*selection_params)
     eval "self.methods.Select_By_#{selection_params.join('_')}.display"
    end
    

    Legionnaired on
  • VThornheartVThornheart Registered User regular
    edited April 2008
    (several good points about event-driven approach)

    Aye, I agree with you 100%. That seems like the best way to approach it to me. I think the notion of putting it in external scripts is messing with me though... I'm not sure exactly how the notion of external scripts work (still collecting resources in that regard), so I'm not sure at the moment what the limitations are of such a thing.

    I guess in the worst case scenario, I could make each card set a DLL library filled with objects for the cards, and that'd ensure that I could do everything I'd normally be able to do in the language. Hmm... I guess I should read these resources before I jump to the conclusion that I can't do it. =) I'll keep reading them. =)

    VThornheart on
    3DS Friend Code: 1950-8938-9095
  • VThornheartVThornheart Registered User regular
    edited April 2008
    (More ruby goodness)

    Interesting! It's very different than how I'm used to thinking about what you can do. I'll use this opportunity to try and actually teach myself Ruby.

    Thanks for the info! It's definitely been helpful. I'll try to keep you all posted here.

    VThornheart on
    3DS Friend Code: 1950-8938-9095
  • TomantaTomanta Registered User regular
    edited April 2008
    You could check This out. It's an online game table for Magic written in Java, but the rules and cards are done almost completely in XML and just parsed/interpreted by the engine.

    I'm not convinced that's the BEST way to do it, though.

    Tomanta on
  • VThornheartVThornheart Registered User regular
    edited April 2008
    Tomanta wrote: »
    You could check This out. It's an online game table for Magic written in Java, but the rules and cards are done almost completely in XML and just parsed/interpreted by the engine.

    I'm not convinced that's the BEST way to do it, though.

    Aha! Thank you for that! I spent most of the night last night looking around to see if someone had attempted this in publicly-available source code before, and I came up empty in my search.

    Though I agree, given the lengthy conversation everyone had today, that parsing it to determine rules might not be the *best* way, it'll likely give me a lot of ideas about how it can be done, which'll be terribly useful.



    Oh, on an update... I've found some Ruby resources that I'll be reading (including what must be the most entertaining tutorial I've ever read in my life... it's all over the place, but it definitely doesn't have the problem of being dry).

    I also found earlier today that my idea of using VSTA (Visual Studio Tools for Applications) for scripting and doing the program in C# or VB.NET wouldn't work in practice because for anyone to use the program, I need to pay some sort of retarded royalty fee for it. I guess it's not retarded... but it makes me not want to use it in principle. However I did find that you can interface with LUA and use LUA as a scripting language... which may not be relevant now that I'm reading about Ruby, but it brings up an interesting issue that I figured I'd mention here (to see what others would do about it)...

    ... in Magic: the Gathering online, sometimes an event will cause an action to trigger that requires user interaction. For instance, if you had an enchantment on the table that said "At end of turn, target Octopus is dealt 12 damage".

    In MTGO, a prompt would appear for the user to select which Octopus (in this example) would receive the 12 damage. If they're using a script, however, that script would have to halt operation and wait for the users' UI (and thus the user) to make up its mind.

    Maybe I haven't gotten enough sleep in the past 24 hours, but it seems like a strange situation to me. The UI prompt would need to be open-ended and event driven, but the prompt itself would come about due to some linear code that needs the result immediately in order to continue processing.

    So if MTGO is using scripts for each of the cards' actions, does the API make the script "wait" for the UI prompt to finish by spitting it into a worker thread, or is there some kind of more complex event notification taking place (like the script keeps state information about where it was at in processing when it asks for UI interaction, passes control back to the UI through an API command, and watches for the UI event to fire saying it's done... at which time it reloads the state and position in the script that it was at before and keeps going)?

    I'm feeling the worker thread idea, because I'm having a hard time wrapping my head around the concept of keeping the state of which line of code in a script it was on... that seems messy... maybe I need to sleep on it though, all this research today and last night is fumbling around in my head. =)

    Anyways, the question might not be directly relevant anymore, but I think it'd be useful to think about in other scenarios anyways... and I still might want to go the C#/LUA route in the end, if for no other reason than it'd be neat to know how to incorporate scripting capability in .NET programs.

    Heh, I had no idea what I was getting into when I sat down to start working on this yesterday afternoon. =) lol

    VThornheart on
    3DS Friend Code: 1950-8938-9095
  • LewishamLewisham Registered User regular
    edited April 2008
    Lots of good stuff here.

    I was thinking you would want to think about cards as plugins, which have handlers coded in them, but it looks like you need something more complex. But yeah, I'm thinking for the complexity you're asking for, you need event broadcasts and event listening. Cocoa (the Mac OS X library) has, from my experience, a really mature system for this, so you might find some interesting tutorials that will help you work this out in your head.

    Lewisham on
  • VThornheartVThornheart Registered User regular
    edited April 2008
    Aye, sadly I don't have a Mac... but VB.NET has some good event handling features that (though I'm not positive) may be similar and will definitely come in handy. And I think the plugin idea is definitely good... if I can't get script-style plugins to work as I want them to, I think I'll end up having to resort to compiled plugins. I guess since it's just a demo it doesn't matter if you have to compile the cards... I think it's just evolved into a "figure out how to integrate scripting into a .NET program" project along with a "make a cool demo for a CCG idea" project. =) Now it's also a "learn Ruby" project, so I'm all over the place. =)

    I read the documentation of the XML for the program Tomanta linked... it's a really fascinating approach! They basically enumerated in XML form all of the possible actions that could happen in the game... which I could see being a very good thing for consistency, but a pain in the butt when a large amount of new features need to be added... though perhaps, in practice, not as much as having to write a script for every card individually. The total definition of all possible actions in XML would allow for some more re-use, at the expense of constantly having to update that XML definition as the game evolved.

    The trade-offs are interesting, and I could see some definite benefits in doing it either way. I also like some of the approaches they took in the XML file to enumerate certain actions (like tags for init, when it comes into play, etc...) It definitely gives some good ideas. I'm going to jump to the next step and look in the code tomorrow, after I get some sleep. =)

    Thanks for all the interesting information here guys, and the great brainstorming session! I'll keep posting info here, and we can continue the brainstorm as desired. =)


    EDIT:

    VThornheart on
    3DS Friend Code: 1950-8938-9095
  • DaenrisDaenris Registered User regular
    edited April 2008
    Maybe I haven't gotten enough sleep in the past 24 hours, but it seems like a strange situation to me. The UI prompt would need to be open-ended and event driven, but the prompt itself would come about due to some linear code that needs the result immediately in order to continue processing.

    So if MTGO is using scripts for each of the cards' actions, does the API make the script "wait" for the UI prompt to finish by spitting it into a worker thread, or is there some kind of more complex event notification taking place (like the script keeps state information about where it was at in processing when it asks for UI interaction, passes control back to the UI through an API command, and watches for the UI event to fire saying it's done... at which time it reloads the state and position in the script that it was at before and keeps going)?

    Well I don't know specifically about using LUA to do it, but in any of the .NET languages I would just have the card effect cause a Dialog window to be shown. This causes operation in the main window to wait until the Dialog window has been resolved (just like an open/save dialog window). So the Enchantment fires and a dialog pops up asking the player to click on a card to target. When they attempt to click on a card it checks to make sure it's a valid target, and then either immediately fires the damage or maybe just selects the card and waits for them to press ok. I assume there should be some way from LUA to trigger a (probably preconstructed) Dialog like this.

    Daenris on
  • VThornheartVThornheart Registered User regular
    edited April 2008
    Daenris wrote: »
    Maybe I haven't gotten enough sleep in the past 24 hours, but it seems like a strange situation to me. The UI prompt would need to be open-ended and event driven, but the prompt itself would come about due to some linear code that needs the result immediately in order to continue processing.

    So if MTGO is using scripts for each of the cards' actions, does the API make the script "wait" for the UI prompt to finish by spitting it into a worker thread, or is there some kind of more complex event notification taking place (like the script keeps state information about where it was at in processing when it asks for UI interaction, passes control back to the UI through an API command, and watches for the UI event to fire saying it's done... at which time it reloads the state and position in the script that it was at before and keeps going)?

    Well I don't know specifically about using LUA to do it, but in any of the .NET languages I would just have the card effect cause a Dialog window to be shown. This causes operation in the main window to wait until the Dialog window has been resolved (just like an open/save dialog window). So the Enchantment fires and a dialog pops up asking the player to click on a card to target. When they attempt to click on a card it checks to make sure it's a valid target, and then either immediately fires the damage or maybe just selects the card and waits for them to press ok. I assume there should be some way from LUA to trigger a (probably preconstructed) Dialog like this.

    Oh... yeah, that'd work! (smacks forehead) Researching all this stuff over the past couple of days has turned my head upside-down, I completely forgot that a modal dialog box would stop it.

    Oh... but would they be able to interact with the main form to select a card if the dialog box was modal? I'm going to have to try it... I know you couldn't back in VB6 days, and honestly at the moment I can't remember if it will in C# or VB.NET. I'll check it out. =)

    Something tells me that your idea will work a lot better than the not-so-pretty idea I had of using (and then pausing) a new thread to wait for the response. That notion didn't sit well with me. =)

    VThornheart on
    3DS Friend Code: 1950-8938-9095
  • LegionnairedLegionnaired Registered User regular
    edited April 2008
    Keep in mind, almost everything in Magic uses a Stack.

    Thus, you can have a stack object that is the only thing truly interacted with, and the 'legal target' type things can be checked before and after they are pushed onto the stack.

    You only need the broadcast stuff for triggered abilities.

    Speaking of triggered abilities: you could have a certain field for 'cares about' for each card object. So, my Moroii might care about things hitting the graveyard, while my Cloudstone Curio might care about 'creatures' that 'come into play'

    So then, you can have a 'broadcast' object, that keeps track of all card that care about certain things, and then alerts those cards whenever their trigger is hit.

    Just a thought.

    Legionnaired on
  • VThornheartVThornheart Registered User regular
    edited April 2008
    Ahh... true, you have a good point!

    AYe, I was thinking of a similar thing for the broadcasting, it'll definitely be a good plan to have it filter like that.

    VThornheart on
    3DS Friend Code: 1950-8938-9095
  • LegionnairedLegionnaired Registered User regular
    edited April 2008
    Oooh, I just found this: http://www.ruby-doc.org/docs/ProgrammingRuby/html/ospace.html

    Apparantly, ruby has an each_object method! So once you've created your 'Card' class, you're able to iterate over all of them by doing:

    ObjectSpace.each_object(Card){|this_card| (... do stuff)}

    This makes cards like Wrath of God one-line programs...

    ObjectSpace.each_object(Creature){|this_card| this_card.destroy unless this_card.indestructable?}

    Legionnaired on
  • VThornheartVThornheart Registered User regular
    edited April 2008
    Aye, that's kind of similar to VB.NET's For Each functionality (well, as long as the collection is IEnumerable), and it's definitely a nice thing that they've been adding to languages lately. I've never been a fan of the old school For Loop (using the counter to iterate etc...).

    VThornheart on
    3DS Friend Code: 1950-8938-9095
  • LegionnairedLegionnaired Registered User regular
    edited April 2008
    Aye, that's kind of similar to VB.NET's For Each functionality (well, as long as the collection is IEnumerable), and it's definitely a nice thing that they've been adding to languages lately. I've never been a fan of the old school For Loop (using the counter to iterate etc...).

    Yes, that's all well and good, ruby has that as well...

    But what I posted, the ObjectScope, allows you to iterate over every object in the current scope.

    Which is amazing.

    Legionnaired on
  • VThornheartVThornheart Registered User regular
    edited April 2008
    Oh, that's definitely different than what I thought you were talking about.

    But when would that be useful? I mean, theoretically the objects would all be part of one collection or another right? Is it just another way of doing the same thing, or does it have some further implication that I'm not considering at the moment?

    Perhaps the "metadata access" (if I can call it that) features of Ruby allow for some interesting combinations to happen with that feature. I'll need to wrap my head around it though. =) I've not yet worked with a language that allowed you to iterate over the methods in an object (to use an example you noted earlier), so I might not yet realize the full implications with what you can do with a system that allows that kind of access.

    VThornheart on
    3DS Friend Code: 1950-8938-9095
Sign In or Register to comment.