The forums moved on March 1, 2021. Please read this page for more information.

I'm bored...

24 posts / 0 new
Last post
TheJayMann
TheJayMann's picture
Offline
Last seen: 8 years 7 months ago
Playtester
Joined: Aug 07, 2011
I'm bored...

    class SubZeroAtmosphere : LastingCard {

        private class SubZeroStartVillainTurnTrigger : ITrigger {
            private Trigger _VillainStart;
            private Trigger _VillainEnd;

            public SubZeroStartVillainTurnTrigger(Trigger villainStart, Trigger villainEnd) {
                _VillainStart = villainStart;
                _VillainEnd = villainEnd;
            }

            public bool Raise(Player value) {
                var responses = new SortedSet>(_VillainStart.Responses, new Trigger.ResponseByDateComparer());
                foreach (var response in _VillainEnd.Responses.Where(r => r.Card.Type == CardType.Villain)) responses.Add(response);
                var c = new Cancelable() { Value = value, IsCancelled = false };
                foreach (var response in responses) {
                    response.OnNext(c);
                    if (c.IsCancelled) return false;
                }
                return true;
            }

            public IDisposable Subscribe(IObserver> observer) {
                return _VillainStart.Subscribe(observer);
               
            }
        }

        private class SubZeroEndVillainTurnTrigger : ITrigger {
            private Trigger _VillainEnd;

            public SubZeroEndVillainTurnTrigger(Trigger villainEnd) {
                _VillainEnd = villainEnd;
            }

            public bool Raise(Player value) {
                var responses = new SortedSet>(
                    _VillainEnd.Responses.Where(r => r.Card.Type != CardType.Villain),
                    new Trigger.ResponseByDateComparer()
                );
                var c = new Cancelable() { Value = value, IsCancelled = false };
                foreach (var response in responses) {
                    response.OnNext(c);
                    if (c.IsCancelled) return false;
                }
                return true;
            }

            public IDisposable Subscribe(IObserver> observer) {
                return _VillainEnd.Subscribe(observer);
            }

        }

        private Trigger _VillainStart;
        private Trigger _VillainEnd;

        public SubZeroAtmosphere(HeroPlayer player) : base("Sub-Zero Atmosphere", player) { }

        protected override bool PlayLasting() {
            if (!(Game.Villain.OnStartTurn is Trigger && Game.Villain.OnEndTurn is Trigger)) return false;
            _VillainStart = (Trigger)Game.Villain.OnStartTurn;
            _VillainEnd = (Trigger)Game.Villain.OnEndTurn;
            Game.Villain.OnStartTurn = new SubZeroStartVillainTurnTrigger(_VillainStart, _VillainEnd);
            Game.Villain.OnEndTurn = new SubZeroEndVillainTurnTrigger(_VillainEnd);
            return true;
        }

        protected override void DestroyCard() {
            Game.Villain.OnStartTurn = _VillainStart;
            Game.Villain.OnEndTurn = _VillainEnd;
            base.DestroyCard();
        }

        public override bool CanPlay {
            get { throw new NotImplementedException(); }
        }

        public override CardType Type {
            get { return CardType.Hero; }
        }

        public override IEnumerable Keywords {
            get { return new string[]{"ongoing"}; }
        }

        public override string GameText {
            get {
                return "Any villain card which would act at the end of the villain turn instead acts at the start of the villain turn.";
            }
        }

        public override IEnumerable Powers {
            get { return Enumerable.Empty(); }
        }
    }


Do good, I? No! Evil anon I deliver, I maim nine more hero men in Miami, sanitary sword a-tuck, carol I. Lo! Rack, cut a drowsy rat in Aswan. I gas nine more hero men in Saginaw. Reviled I, Nona, live on. I do... o, God!

Adam
Adam's picture
Offline
Last seen: 3 years 4 months ago
Admin
Joined: Aug 02, 2011

Just out of curiosity, at what percentage of coding the entire card game are you? ???

TheJayMann
TheJayMann's picture
Offline
Last seen: 8 years 7 months ago
Playtester
Joined: Aug 07, 2011

Well, as far as anything specific to Sentinels of the Multiverse itself, I've only coded two cards (one of which doesn't exactly fit the current API).  Right now I've probably implemented most of the model, but none of the engine.  I know one tough hurdle I'm going to hit is the fact most (all?) enumerators already defined in the .NET framework are either wrappers around other enumerators, or they throw an exception when the underlying collection is modified while being enumerated.  I'll likely have to implement my own wrapper enumerator which sets itself back to where it left off when the wrapped enumerator throws its exception.  Either that or reimplement a trigger's collection of responses using the observer pattern while not relying on any enumerators, but the former sounds much simpler.


Do good, I? No! Evil anon I deliver, I maim nine more hero men in Miami, sanitary sword a-tuck, carol I. Lo! Rack, cut a drowsy rat in Aswan. I gas nine more hero men in Saginaw. Reviled I, Nona, live on. I do... o, God!

Adam
Adam's picture
Offline
Last seen: 3 years 4 months ago
Admin
Joined: Aug 02, 2011

So.....magic then? You're using magic?

TheJayMann
TheJayMann's picture
Offline
Last seen: 8 years 7 months ago
Playtester
Joined: Aug 07, 2011

If that's what you people believe when you see a computer working, then yes, I'm using magic, hehehehe.

Once I get the engine up to a decent point, I wouldn't mind releasing it open source.  Of course, card packs would be a completely different story, as it would contain various IP (copyrights and trademarks) of Greater Than Games, and could get me in trouble.


Do good, I? No! Evil anon I deliver, I maim nine more hero men in Miami, sanitary sword a-tuck, carol I. Lo! Rack, cut a drowsy rat in Aswan. I gas nine more hero men in Saginaw. Reviled I, Nona, live on. I do... o, God!

Christopher
Christopher's picture
Offline
Last seen: 3 years 1 month ago
AdminGame Designer
Joined: Aug 01, 2011

"Any sufficiently advanced technology is indistinguishable from magic."
                        - Arthur C. Clarke


"Your goodness must have some edge to it — else it is none."
 - Ralph Waldo Emerson

TheJayMann
TheJayMann's picture
Offline
Last seen: 8 years 7 months ago
Playtester
Joined: Aug 07, 2011

That must mean I'm some sort of grand warlock, yes?


Do good, I? No! Evil anon I deliver, I maim nine more hero men in Miami, sanitary sword a-tuck, carol I. Lo! Rack, cut a drowsy rat in Aswan. I gas nine more hero men in Saginaw. Reviled I, Nona, live on. I do... o, God!

Tamar
Offline
Last seen: 11 years 8 months ago
Joined: Aug 02, 2011

Adam wrote:
So.....magic then? You're using magic?

Sure looks like magic to me!


I am the Bad Wolf. I create myself.
I take the words. I scatter them in time... and space.
A message to lead myself here.

arenson9
arenson9's picture
Offline
Last seen: 3 years 1 month ago
ModeratorPlaytester
Joined: Aug 08, 2011

In thinking how I'd code the game, it seemed like a queue of actions to take would work well, where the result of an action could be more actions inserted into the queue at the head. I imagine the queue starting with a single task which is something like 'Do a Round'. That task would then spawn a Villain Turn, each Hero Turn, and an environment Turn, all to be put in the queue, followed by another 'Do a Round' task. Beyond the queue, the model would need to have heroes, villains, environment and their associated draw pile, trash pile, in-play set, and hand. The piles, set, and hands would then have cards associated with them. Each card would then have actions they could spawn and effect filters they could set. Some actions, such as doing damage, would be implemented by looking through a set of source filters (like Absolute Zero changing cold damage he does to +1), general filters (like Legacy's Galvanize setting all damage done by heroes to +1), and target filters (like Warlord Voss having all damage decreased by 1 or 2 for each minion). Other actions would primarily change the status of cards -- this card is no longer in the hand, it is in the in-play set.

I share this both because I felt like writing down what's in my head and to ask The JayMann if this is like what he envisions.


Hi. My name's Andy. Feel free to call me Andy, since, ya know, that's my name. (he/him/his)

If I am not for myself, who will be for me? If not now, when? If I am for myself alone, what am I? -- Hillel

TheJayMann
TheJayMann's picture
Offline
Last seen: 8 years 7 months ago
Playtester
Joined: Aug 07, 2011

Half of what you have written is what I've implemented.  However, instead of something generic like "filters" or whatnot, I'm using the Observable/Observer pattern (Reactive Framework).  Basically, the opposite of an enumerator (a push based enumerator of sorts).  Basically, anything that needs to respond to any event registers it's response (observer) with a trigger (observable), and I've designed lasting cards to have a play time, and responses have a reference to a card, and if the card is lasting, it uses it's play time (otherwise uses the current time or a custom defined time) such that all responses can then be sorted by earliest so that earlier responses are triggered first.  Also, any response can cancel the trigger, prevent further responses from responding to the trigger.  Many triggers I'm implementing in pairs, such that one trigger occurs before the action takes place (allowing the action to be cancelled before it's performed) and one that occurs after the action (so it can respond to the fact the action actually took place).  Basically, the only thing I haven't implemented yet is the code that processes each round (engine), and that's because I'll need a good amount of the model defined and set in stone so that engine is strait forward, and so that a necessary change in model doesn't adversely effect the engine.

Basic M-C-VM-V pattern (Model, Controller, View Model, View)


Do good, I? No! Evil anon I deliver, I maim nine more hero men in Miami, sanitary sword a-tuck, carol I. Lo! Rack, cut a drowsy rat in Aswan. I gas nine more hero men in Saginaw. Reviled I, Nona, live on. I do... o, God!

arenson9
arenson9's picture
Offline
Last seen: 3 years 1 month ago
ModeratorPlaytester
Joined: Aug 08, 2011

TheJayMann wrote:
Half of what you have written is what I've implemented.  However, instead of something generic like "filters" or whatnot, I'm using the Observable/Observer pattern (Reactive Framework).  Basically, the opposite of an enumerator (a push based enumerator of sorts).  Basically, anything that needs to respond to any event registers it's response (observer) with a trigger (observable), and I've designed lasting cards to have a play time, and responses have a reference to a card, and if the card is lasting, it uses it's play time (otherwise uses the current time or a custom defined time) such that all responses can then be sorted by earliest so that earlier responses are triggered first.  Also, any response can cancel the trigger, prevent further responses from responding to the trigger.  Many triggers I'm implementing in pairs, such that one trigger occurs before the action takes place (allowing the action to be cancelled before it's performed) and one that occurs after the action (so it can respond to the fact the action actually took place).  Basically, the only thing I haven't implemented yet is the code that processes each round (engine), and that's because I'll need a good amount of the model defined and set in stone so that engine is strait forward, and so that a necessary change in model doesn't adversely effect the engine.

Basic M-C-VM-V pattern (Model, Controller, View Model, View)

Very cool. I'd be keen to see it if you make it available. What do you have in mind for the View? Are you envisioning a web app?


Hi. My name's Andy. Feel free to call me Andy, since, ya know, that's my name. (he/him/his)

If I am not for myself, who will be for me? If not now, when? If I am for myself alone, what am I? -- Hillel

TheJayMann
TheJayMann's picture
Offline
Last seen: 8 years 7 months ago
Playtester
Joined: Aug 07, 2011

Right now, WPF, as I'm experienced in using ViewModels in WPF.  ASP.NET MVC should work well with ViewModels as well, and Silverlight/WP7 is just a different version of WPF.  Other views shouldn't be too difficult (for someone with experience that is) like MonoTouch, Monodroid, GTK#, etc.


Do good, I? No! Evil anon I deliver, I maim nine more hero men in Miami, sanitary sword a-tuck, carol I. Lo! Rack, cut a drowsy rat in Aswan. I gas nine more hero men in Saginaw. Reviled I, Nona, live on. I do... o, God!

Ronway
Ronway's picture
Offline
Last seen: 2 years 11 months ago
PlaytesterTruth Seeker
Joined: Aug 02, 2011

Certainly is a lot of magic talk. I can't understand a bit, maybe speaking in Dragonic?

Tamar
Offline
Last seen: 11 years 8 months ago
Joined: Aug 02, 2011

I love listening in on other people's nerdery, even when I don't really get it :P  It's just fun to hear knowledgeable people talk about what they know.

And maybe if I pay enough attention I'll learn to cast fireball!


I am the Bad Wolf. I create myself.
I take the words. I scatter them in time... and space.
A message to lead myself here.

beevolant
Offline
Last seen: 4 years 2 months ago
Joined: Aug 03, 2011

Tamar wrote:
And maybe if I pay enough attention I'll learn to cast fireball!

Ooooh! Fireball! My favorite! :D

I once programmed a website in html *mumblemumble* years ago. So for me, this looks more like *cue Announcer voice* Science FICTION!


"Crime doesn't keep the Sabbath"

TheJayMann
TheJayMann's picture
Offline
Last seen: 8 years 7 months ago
Playtester
Joined: Aug 07, 2011

    class DrawnToTheFlame : LastingCard {

        protected override bool PlayLasting() {
            return true;
        }

        public override bool CanPlay {
            get { return true; }
        }

        public override CardType Type {
            get { return CardType.Hero; }
        }

        private string[] keywords = { "Ongoing" };

        public override IEnumerable Keywords {
            get { return keywords; }
        }

        public override string GameText {
            get { return string.Empty; }
        }

        Power power = new Power() {
            GameText = "Ra deals each non-hero target 1 fire damage for each villain ongoing card in play.",
            Play = () => {
                var damageCount = Game.Villain.CardsInPlay.Where(c => c.Keywords.Contains("Ongoing")).Count();
                foreach (var target in Game.CardsInPlay.OfType().Where(t => t.CardType != CardType.Hero)) this.DamageTarget(target, damageCount, DamageType.Fire);
            },
        };
               
        public override IEnumerable Powers {
            get { return new Power[] { power }; }
        }
    }

At a stuck point, more or less, so decided to draw a random card and implement it.  (Note: Card does not compile, as there currently is no Game.CardsInPlay list.  I'm still not sure if I should make a bunch of game level lists, or if I should just create a game level player list and compose the more specific lists as needed (e.g. Game.Players.SelectMany(p => p.CardsInPlay)).)

I also have yet to implement services (request dialogs, etc)...


Do good, I? No! Evil anon I deliver, I maim nine more hero men in Miami, sanitary sword a-tuck, carol I. Lo! Rack, cut a drowsy rat in Aswan. I gas nine more hero men in Saginaw. Reviled I, Nona, live on. I do... o, God!

arenson9
arenson9's picture
Offline
Last seen: 3 years 1 month ago
ModeratorPlaytester
Joined: Aug 08, 2011

TheJayMann wrote:

I'm still not sure if I should make a bunch of game level lists, or if I should just create a game level player list and compose the more specific lists as needed (e.g. Game.Players.SelectMany(p => p.CardsInPlay)).)

I was thinking that the lists should be specific to individual players, such that a game would consist of one (or more!) villains, one (or more!) environments, and three to five (or less or more!) heroes, and then within each villain, environment, and hero you'd have separate lists for draw pile, trash, hand, and in-play.

I mostly think of it that way because, well, that's how I think of the game, but if you have game-level lists, then you have to tag each individual card with who owns it and what state (draw pile, trash, hand, in-play) anyway.


Hi. My name's Andy. Feel free to call me Andy, since, ya know, that's my name. (he/him/his)

If I am not for myself, who will be for me? If not now, when? If I am for myself alone, what am I? -- Hillel

TheJayMann
TheJayMann's picture
Offline
Last seen: 8 years 7 months ago
Playtester
Joined: Aug 07, 2011

If I were to have game level lists, they would just be enumerable wrappers over the individual lists.  The internal debate is whether to create a game level wrapper for each possible list, or just create a player wrapper and compose the lists as needed.  (I.e. do I create public static Pile CardsInPlay { get { return players.SelectMany(p=>p.CardsInPlay);}} or do I just use Game.Players.SelectMany(p=> p.CardsInPlay) each time I need to get all cards in play?)


Do good, I? No! Evil anon I deliver, I maim nine more hero men in Miami, sanitary sword a-tuck, carol I. Lo! Rack, cut a drowsy rat in Aswan. I gas nine more hero men in Saginaw. Reviled I, Nona, live on. I do... o, God!

arenson9
arenson9's picture
Offline
Last seen: 3 years 1 month ago
ModeratorPlaytester
Joined: Aug 08, 2011

TheJayMann wrote:
If I were to have game level lists, they would just be enumerable wrappers over the individual lists.  The internal debate is whether to create a game level wrapper for each possible list, or just create a player wrapper and compose the lists as needed.  (I.e. do I create public static Pile CardsInPlay { get { return players.SelectMany(p=>p.CardsInPlay);}} or do I just use Game.Players.SelectMany(p=> p.CardsInPlay) each time I need to get all cards in play?)

Ah. Very interesting. I can see arguments on both sides in terms of understandability. I'd probably implement the wrappers after about the 2nd or third time I wanted all of the cards in play.


Hi. My name's Andy. Feel free to call me Andy, since, ya know, that's my name. (he/him/his)

If I am not for myself, who will be for me? If not now, when? If I am for myself alone, what am I? -- Hillel

TheJayMann
TheJayMann's picture
Offline
Last seen: 8 years 7 months ago
Playtester
Joined: Aug 07, 2011

So I created a chm based on what I've documented of the model thus far.  I can't attach more than 192 KB at a time, so I have to provide a link.

http://www.mediafire.com/download.php?spb13h8khh8dp8h


Do good, I? No! Evil anon I deliver, I maim nine more hero men in Miami, sanitary sword a-tuck, carol I. Lo! Rack, cut a drowsy rat in Aswan. I gas nine more hero men in Saginaw. Reviled I, Nona, live on. I do... o, God!

arenson9
arenson9's picture
Offline
Last seen: 3 years 1 month ago
ModeratorPlaytester
Joined: Aug 08, 2011

TheJayMann wrote:
So I created a chm based on what I've documented of the model thus far.  I can't attach more than 192 KB at a time, so I have to provide a link.

http://www.mediafire.com/download.php?spb13h8khh8dp8h

I'm unfamiliar with this file format. When I try to open it (under Win7), I get a window that has a nice heiarchy on the left-hand-side with what  looks like a bunch of Class names, but attempting to click on any particular class just gives me: 'Navigation to the web page was canceled'. What _should_ be seeing? Is there some particular software I need?


Hi. My name's Andy. Feel free to call me Andy, since, ya know, that's my name. (he/him/his)

If I am not for myself, who will be for me? If not now, when? If I am for myself alone, what am I? -- Hillel

TheJayMann
TheJayMann's picture
Offline
Last seen: 8 years 7 months ago
Playtester
Joined: Aug 07, 2011

Ah, I forgot to mention.

CHM is Compiled HTML, it's a new help file format to replace HLP.  However, starting with Windows XP SP2, Internet Explorer (and now Chrome, and maybe a few other browsers) set all files downloaded from the internet with an internet tag.  Various checks are performed by the system and applications if the tag is detected.  For EXE files, the system shows a dialog asking if you really want to run the application first, same with msiexec when an MSI is run.  When a ZIP file has the tag, every file extracted from the ZIP file has the same tag added on.  When hh sees that a CHM has the internet tag, all navigation attempts fail.  What you have to do is bring up the properties of the file (right cick -> Properties, among other methods) and unblock the file.


Do good, I? No! Evil anon I deliver, I maim nine more hero men in Miami, sanitary sword a-tuck, carol I. Lo! Rack, cut a drowsy rat in Aswan. I gas nine more hero men in Saginaw. Reviled I, Nona, live on. I do... o, God!

arenson9
arenson9's picture
Offline
Last seen: 3 years 1 month ago
ModeratorPlaytester
Joined: Aug 08, 2011

TheJayMann wrote:
What you have to do is bring up the properties of the file (right cick -> Properties, among other methods) and unblock the file.

Excellent. That worked.


Hi. My name's Andy. Feel free to call me Andy, since, ya know, that's my name. (he/him/his)

If I am not for myself, who will be for me? If not now, when? If I am for myself alone, what am I? -- Hillel

TheJayMann
TheJayMann's picture
Offline
Last seen: 8 years 7 months ago
Playtester
Joined: Aug 07, 2011

The first bit of actual code from the game engine to be made public.  I tried to document as well as I could.  Unfortunately, I can't post in color (or, at least, it would take me a very long time to format it here similar to how it is in Visual Studio.
using System;
using System.Collections.Generic;
using System.Linq;

namespace SotM.Utilities {

    ///
    /// This trigger fires in response to group of triggers.
    ///
    ///
    /// The type of data passed from the trigger.
    ///
    ///
    /// This special trigger filter is used to automatically subscribe
    /// all responses subscribed to it to a number of other triggers,
    /// and responds to other triggers that fire when another trigger
    /// is created, allowing that trigger to automatically be added
    /// to the trigger list.
    ///
    sealed class CompositeTrigger : IObservable>{

        private ISet> _Triggers;
        private IList _Registers;

        ///
        /// Creates a new composite trigger.
        ///
        ///
        /// A list of triggers to listen to.
        ///
        private CompositeTrigger(IEnumerable> triggers) {
            _Triggers = new HashSet>(triggers);
        }

        ///
        /// Creates a new composite trigger given a list of triggers,
        /// a trigger to add triggers, and a converter to select
        /// a trigger from the trigger.  Trigger trigger trigger
        /// trigger.
        ///
        ///
        /// The type of data passed when the update trigger is fired.
        ///
        ///
        /// The list of triggers to initialize the composite trigger
        /// with.
        ///
        ///
        /// A trigger that is fired when a new trigger should be added
        /// to the composite trigger.
        ///
        ///
        /// A function which obtains the trigger to be added from the
        /// data passed from the update trigger.
        ///
        ///
        /// An autoupdated composite trigger.
        ///
        public CompositeTrigger Create(IEnumerable> triggers, Trigger updateTrigger, Func> triggerSelector){
            var cTrigger = new CompositeTrigger(triggers);
            updateTrigger.Subscribe(new Response(DateTime.Now.AddYears(-1)) { Next = u => cTrigger.AddTrigger(triggerSelector(u.Value)) });
            return cTrigger;
        }

        ///
        /// Adds a trigger to the composite trigger.
        ///
        ///
        /// The trigger to add
        ///
        private void AddTrigger(Trigger trigger) {
            // We want to register all current registers with the
            // new trigger, but only if we haven't already registered
            // with the trigger.
            if (_Triggers.Add(trigger)) foreach (var register in _Registers) register.AddTrigger(trigger);
           
        }

        ///
        /// Registers a response with the composite trigger.  This in
        /// turn registers the response to all the composed triggers
        /// contained by the composite trigger.
        ///
        ///
        /// The response to register
        ///
        ///
        /// A registration object which can unregister from all
        /// composed triggers when unregistered.
        ///
        public override IDisposable Subscribe(IObserver> observer) {
            // Convert observable to response, as we need an actual
            // response object.
            var response = observer.AsResponse();

            // We need to create a register based on the response
            // and the list of triggers, add the register to the
            // list of registers, and then
            var register = new CompositeTriggerRegistration(response, _Triggers, this);
            _Registers.Add(register);
            return register;
        }

        ///
        /// A private class that handles the registration of responses
        /// to a composite trigger.
        ///
        ///
        /// This class handles subscribing a given response to all
        /// triggers, subscribes the response when new triggers are
        /// added, and removes all registrations of the response
        /// when the composite registration is unregistered.
        ///
        private class CompositeTriggerRegistration : IDisposable {

            private ISet _Registers;
            private CompositeTrigger _Owner;

            public Response Response { get; private set; }

            ///
            /// Creates a registration given a response and a list
            /// of triggers to register.
            ///
            ///
            /// The response to register
            ///
            ///
            /// An initial list of triggers to register to
            ///
            ///
            /// The composite trigger that owns the register.  This
            /// allows the register to remove itself from the owning
            /// composite trigger when it's unregistered.
            ///
            public CompositeTriggerRegistration(Response response, IEnumerable> triggers, CompositeTrigger owner) {
                Response = response;
                _Registers = new HashSet(triggers.Select(t => t.Subscribe(response)));
                _Owner = owner;
            }

            ///
            /// Registers the response to a new trigger.
            ///
            ///
            /// The new trigger to register to
            ///
            public void AddTrigger(Trigger trigger) {
                _Registers.Add(trigger.Subscribe(Response));
            }

            ///
            /// Unregisters the response from all triggers it is
            /// registered to.
            ///
            public void Dispose() {
                foreach (var register in _Registers) register.Dispose();
                _Owner._Registers.Remove(this);
            }
        }

    }
}


Do good, I? No! Evil anon I deliver, I maim nine more hero men in Miami, sanitary sword a-tuck, carol I. Lo! Rack, cut a drowsy rat in Aswan. I gas nine more hero men in Saginaw. Reviled I, Nona, live on. I do... o, God!