OOP ahoy?

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Therem Harth
    Knight
    • Jan 2008
    • 926

    OOP ahoy?

    I'm finally rewriting the unmaintainable mess that is Neoband's bookless spell system.

    This time around, I've opted for a vaguely OOP-like approach. Spell effects are named functions, spells are structs that include a function pointer. Realms are arrays of spells, and are declared with the function pointer for each spell pointing to the requisite effect function.

    It's a bit verbose, but (if it works!) it will allow for a kind of polymorphism; in that I can use one function for all of the bookless realms, invoking each spell effect through the spell's function pointer.

    Thus far I've implemented the required functions and reimplemented the original Pyromancer class, with some modifications. The other classes should follow soon, though also with modifications.

    Doing this loses me some flexibility in the handling of the different realms. OTOH it cuts out a lot of duplicated code, and lets me add new realms much more easily... Which I suppose is a good thing.

    Anyway, just note that I'm still working on this variant, and it should be more playable, more balanced, and less buggy in the near future.
  • Pete Mack
    Prophet
    • Apr 2007
    • 6883

    #2
    Sounds good. Spellcasting code is the one place where there's a lot of room for OOP work.

    Comment

    • Therem Harth
      Knight
      • Jan 2008
      • 926

      #3
      Getting it to compile was a humbling experience, but it now runs. Doesn't quite work though...

      Main issues:

      - Aborting a spell with Esc gives you a direction prompt. If you target a monster using this prompt, the game immediately crashes. Something is clearly wrong with the code I'm using to allow spells to be aborted.

      - More seriously, arrays in C are always passed as pointers, which means there's no easy way to know how big the array of spellholder structs is for a given realm. I hadn't realized this when I started on this project; but this is bad, because the bookless realms are of variable size. Currently I've no idea how to fix this.

      Comment

      • AnonymousHero
        Veteran
        • Jun 2007
        • 1393

        #4
        The simplest way is to simply use a sentinel element at the end of the array. If, for example, you have a list of spells:

        Code:
        struct spell {
           const char *name;
           ...
        };
        use an element with "name == NULL" to indicate that the element is really the EoL.

        A few other ways:
        1. Use arrays of pointers to X instead of arrays of X (or use singly linked lists). Use a NULL pointer as the end marker. This is arguably cleaner than the sentinel approach.
        2. Always pass the size as a parameter.
        3. Use an ADT (Abstract Data Type) like "list" or "vector" -- of course C doesn't have any of those built in, but implementing a "generic" list or vector storing any (void *) shouldn't be too difficult.

        Comment

        • Therem Harth
          Knight
          • Jan 2008
          • 926

          #5
          Hmm. The pointer array method sounds like the best in this case; I'll see if I can implement it. Thanks.

          Comment

          • Narvius
            Knight
            • Dec 2007
            • 589

            #6
            4) Make a small wrapper data structure that holds the array and its size.
            If you can convincingly pretend you're crazy, you probably are.

            Comment

            • Therem Harth
              Knight
              • Jan 2008
              • 926

              #7
              Meanwhile, I'm having some misgivings about all this...
              - Sappers need their spells to occasionally blow up on failure
              - Assassins need spell failure to poison them
              - Other classes may need other features, e.g. casting spells using gold or HP

              I could use conditionals or switch statements for this stuff, but that would be ugly in its own way. Basically I seem to be looking at a choice between
              a) Having consolidated bookless code in one file, but with bits of different realms scattered all over the place.
              b) Having each realm mostly confined to its own file - which is good when I need to edit one realm, but means code duplication and more work if I have to edit several.

              What I'd really like is to have each realm and its quirks confined to one file (or section of a file), with shared code in a common area.

              Consolidating common functions (e.g. for menu printing, failure stats, etc.) in bookless.c would probably be a good start there. Not sure how to go the rest of the way though, or even if I can. Maybe put the different spellholder structs all in bookless.h, and the different casting functions in bookless.c?

              (Never thought I'd say this, but it would be awfully nice to have real OOP capabilities here...)

              Comment

              • Zyphyr
                Adept
                • Jan 2008
                • 135

                #8
                Use Narvius' wrapper structure suggestion.

                Make different spell failure procedures for each realm.

                Each realms' wrapper can then contain a pointer to the relevant failure procedure.

                Any other special data can also be stored in that wrapper as well. Need classes that cast from HP? Have a field that indicates what resource the class uses (Mana for most, HP for others).

                In essence you will be using a Struct to simulate many of the features of a Class. This is entirely reasonable since C++ Classes are just an extension of C Structs.

                Comment

                • Therem Harth
                  Knight
                  • Jan 2008
                  • 926

                  #9
                  ...

                  THANK YOU. That sounds awesome. I'll have a go at it.

                  Comment

                  • AnonymousHero
                    Veteran
                    • Jun 2007
                    • 1393

                    #10
                    Originally posted by Zyphyr
                    Use Narvius' wrapper structure suggestion.
                    Aka. my 3rd suggestion, but whatever .

                    Originally posted by Zyphyr
                    Make different spell failure procedures for each realm.

                    Each realms' wrapper can then contain a pointer to the relevant failure procedure.

                    Any other special data can also be stored in that wrapper as well. Need classes that cast from HP? Have a field that indicates what resource the class uses (Mana for most, HP for others).
                    I don't understand why you're talking about a wrapper. A spell is a struct. If that struct happens to contain a "calculate_failure" (or whatever) function pointer, then so be it.

                    EDIT: Oh, and the wrapper (containing a "size" and "elements" part) shouldn't contain this stuff, it should surely be a per-element thing.

                    Originally posted by Zyphyr
                    In essence you will be using a Struct to simulate many of the features of a Class. This is entirely reasonable since C++ Classes are just an extension of C Structs.
                    It's reasonable until you start running into those cases where you want implementation inheritance or anything like that. Then it becomes unreasonable to still be in C. Not that implementation inheritance is necessarily a good idea, but it can be very handy if you're using the "mixin" style of OOP.

                    (Don't get me wrong, I'm emphatically not a fan of C++, but it's better than C in many ways.)

                    Comment

                    • Zyphyr
                      Adept
                      • Jan 2008
                      • 135

                      #11
                      Originally posted by AnonymousHero
                      I don't understand why you're talking about a wrapper. A spell is a struct. If that struct happens to contain a "calculate_failure" (or whatever) function pointer, then so be it.

                      EDIT: Oh, and the wrapper (containing a "size" and "elements" part) shouldn't contain this stuff, it should surely be a per-element thing.
                      What is hard to understand? My suggestion is essentially to build a 'Class SpellRealm' but as a Struct (and of course with function pointers instead of member functions since this is C and not C++).

                      Also, the inheritance thing is largely a non-issue since any functions would be implemented as a pointer and not a member.

                      Comment

                      • takkaria
                        Veteran
                        • Apr 2007
                        • 1951

                        #12
                        Why don't you just use C++ for your additions? Sounds like you're putting in a lot of effort to write the code in a way that doesn't easily come to C, so you might as well use a language which has the features you're trying to reimplement.
                        takkaria whispers something about options. -more-

                        Comment

                        • Therem Harth
                          Knight
                          • Jan 2008
                          • 926

                          #13
                          Umm... can I do that? I thought that linking C++ against C (or compiling C in g++) could get real nasty real fast...

                          Comment

                          • takkaria
                            Veteran
                            • Apr 2007
                            • 1951

                            #14
                            Originally posted by Therem Harth
                            Umm... can I do that? I thought that linking C++ against C (or compiling C in g++) could get real nasty real fast...
                            As long as you wrap your C includes in extern "C" { }, you should be OK I think. If you're not, Google will surely have loads of info on how to link the two together. I wouldn't compile the whole game with g++, just the new files you add, and you'll have to manage the boundary. It's just a suggestion, though, personally I would avoid C++ like the plague.
                            takkaria whispers something about options. -more-

                            Comment

                            Working...
                            😀
                            😂
                            🥰
                            😘
                            🤢
                            😎
                            😞
                            😡
                            👍
                            👎