Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re: Re: Modules: Building blocks for the Daft Adventure

by Tiefling (Monk)
on Jun 12, 2001 at 17:08 UTC ( [id://87790]=note: print w/replies, xml ) Need Help??


in reply to Re: Modules: Building blocks for the Daft Adventure
in thread Modules: Building blocks for the Daft Adventure

While everyone else has answered your question quite well, in terms of the technical Perl aspect, I would like to comment on the design of your application. (This is in no way meant to imply that I know everything that you're intending on doing, nor is it meant to imply that I have The Right Way. I merely wish to offer ideas, given my package experiences.)

Have you read the Daft text adventure project thread? That contains the original brief and a lot of the suggestions and responses initially produced. It also describes the origin of the program I was intending to create, and my own background in BASIC.

The first instinct I've seen in a lot of decent programmers has been to treat Perl with less respect than they would C, Java, or any other compiled language.

What does this mean, specifically? I was under the impression that Perl was the proverbial Swiss Army Chainsaw, capable of bringing more than enough power to bear on a wide range of tasks. How do I risk making an unstable app? (On re-reading, that question sounds silly, but I can't express it better right now.)

"Why?", you might ask. Well, you talk about a dice-rolling function called dice(). Then, you talk about a modifer() function. As someone who plays D&D, these, to me, instinctively seem as if they belong in the same place. This is because they both deal with ability scores.

I humbly disagree. dice() has nothing to do with ability scores specifically, or with D&D. dice() should be relevant to Call of Cthulhu or even In Nomine, as well as to D&D. modifier(), on the other hand, deals exclusively and explicitly with a property of D&D's ability scores. Perhaps an RPG::DND::Character module is mandated, perhaps not. I would incline toward thinking 'yes' here, especially given the modular nature of 3e's rules. (The dwarven defender and the barbarian have very different special abilities utilising 90% of the same 'code'.) modifier() clearly belongs in such a module, since it is absolutely specific to D&D characters.

I'm inclined to think that the top level should know how to roll dice, since it might need to use them for explicitly defined game features (as opposed to emulation of a given rules set). However, 99% of the calls to dice() and its cousins (the functions of RPG::Dice) will indeed be made by RPG::DND::Character, Combat, etc.

I'm opposed to the idea of coin_flip as a separate function. However, if it were required, the following line could go into Dice.pm:
sub coin_flip{ ("Heads", "Tails")[dice(2)-1] }

(Something tells me I can't take an element from a constant list, in which case that would have to change.)

Apart from the difference covered by the above line, how is a coin flip different from 1d2?

Certainly your answer has got me thinking about sane package construction. However, I'm not sure where you stand on the topic - or where I stand. This is, of course, the kind of discussion I have hoped to promote by discussing my project here at PerlMonks.

Thanks again,

Tiefling the Lazy

-----BEGIN GEEK CODE BLOCK----- Version: 3.1 GAT d++ s:- a-- C++ UL P++ L++(+) E? W+(++) N+ o? K w+(--) !O M- V? PS+ PE- Y PGP- t+ 5 X+ R+++ tv- b+++ DI++++ D+ G+ e++ h!(-) y +? ------END GEEK CODE BLOCK------

Replies are listed 'Best First'.
Re: Re: Re: Modules: Building blocks for the Daft Adventure
by dragonchild (Archbishop) on Jun 12, 2001 at 17:42 UTC
    (I will be responding initially to your response, Tiefling. Please read the whole post before responding. I explain myself a little better after babbling for a few minutes. :-)

    I have read the Daft Adventure thread, and I've also written similar programs myself (back in Apple BASIC). This was actually my first program over 100 lines, back in the day.

    However, given your responses, I wonder if you'd read everything I wrote. Yes, I originally said:

    "Why?", you might ask. Well, you talk about a dice-rolling function called dice(). Then, you talk about a modifer() function. As someone who plays D&D, these, to me, instinctively seem as if they belong in the same place. This is because they both deal with ability scores.

    However, I then said that both RPG::D&D::Character and RPG::Dice would be needed. That implies that dice() would be located in a non-D&D spot.

    However, I don't want to start a flame-war. This project is obviously something dear to your heart and I apologize if you felt that I was insulting your intelligence or your design capabilities. I was merely attempting to humbly offer up some ideas of my own.

    Now, onto the project!

    The basic functionality you're probably going to need involves (at least) the following areas:

    • Character/NPC/Monster Generation
    • Skills
    • Magic (both Arcane and Divine)
    • Combat (both mudnane and magical)
    • Items (both mundane and magical)
    • Map Generation

    Note that this is from an extremely high level. There is no mention of how things are adjudicated. From a DM/player perspective, this is what the game is all about - making a character, choose skills/magic, and then running around a world. Occasionally, you might have to fight stuff.

    Every single action you take from this high a level should call some method contained in another module. There are several reasons for this:

    • It makes your high level very instinctively obvious. Any new DM can, given a well-defined and documented API to your modules, create his/her own high-level programs.
    • It makes changing game systems very easy. You are creating RPG::D&D::* right now. However, by that very package nomenclature, RPG::Cthulhu::* is very possible. If you leave out all implementation details from the top level, switching systems is almost trivial.
    • It makes designing the system much easier. You don't have to remember that there is a 1% need to roll dice at the manager level. You'll know that all implementation details are hidden from the top level. You just need to have the appropriate module adjudicate itself.

    Now, we don't know exactly how these modules will go about doing their thing. In fact, we don't even know if they will be modules or classes. (RPG::D&D::Character may very well be a class - I find it easier to think of a PC or monster as an thing that knows how to do stuff versus a set of methods to be run on a data structure you have to maintain.) Each module will have an API (set of methods that other modules know about) and a mandate (what it takes care of for you). Once you have sketched this out, it becomes very simple to flesh out the skeleton.

      However, I then said that both RPG::D&D::Character and RPG::Dice would be needed. That implies that dice() would be located in a non-D&D spot.

      However, I don't want to start a flame-war. This project is obviously something dear to your heart and I apologize if you felt that I was insulting your intelligence or your design capabilities. I was merely attempting to humbly offer up some ideas of my own.


      No offence intended or taken, dragonchild. I was agreeing with you! I just didn't express myself very well. I was endorsing your point about the need to separate the Dice and Character modules. Consequently, I presented my version of the arguments against your initial suggestion - which you yourself argue against further down the post. I apologise for the confusion - nothing could be further from my intentions that to start a flame war with you or anyone.

      Now, onto the project!

      The basic functionality you're probably going to need involves (at least) the following areas:

      • Character/NPC/Monster Generation
      • Skills
      • Magic (both Arcane and Divine)
      • Combat (both mudnane and magical)
      • Items (both mundane and magical)
      • Map Generation

      Ok:
      • Character, monster and NPC generation. In my original BASIC implementation, PCs were generated by manually writing a character into a .txt file. My present attempts at writing the character generator software are naturally designed to improve on that rather unfriendly method. Thus far, yea good. Monster generation was one of the better aspects of the BASIC version (at least first time through) - individual instances of monsters were created by reference to arrays of base statistics - a technique I would repeat in a non-OO Perl implementation. However, OO offers a more natural way to handle this - provided I can get my head around OO. NPC generation will be essentially like mosnter generation for generic NPCs - 'farmer' is much like 'orc' in most ways. Special NPCs will be hand-written, possibly with a text editor, perhaps using a 'DM mode' feature of the main engine.
      • Skills are a side effect of PC generation, and have already been entered in a tabulated format. The table can be read into whatever data type takes our fancy/fits our purpose. Obviously, for RPG::Cthulhu::Character, a different, and differently-formatted list is required.
      • I conceive of spells as consisting of their casting details, as data, plus specific referenced calls to procedures in RPG::DND:Magic to invoke the unique effects. Duration spells would create objects with timers, checked periodically to detect expiry.
      • Combat will interrupt normal play. (As it happens so quickly, characters who are, say, shopping in the market, will have just about enough time to turn a corner while a group elsewhere fight and slay six orcs.) That will be a set fact about the game, no matter what engine is invoked, since the time-stamped actions are part of the text adventure interface, rather than the rules emulator. I had originally intended to fudge combat, but a curses-driven engine to produce roguelike floor plans does not seem impossible.
      • Items should be handled by a method parallel to that used for monsters. If, as seems likely, we go OO, Perl objects' ability to inherit from more than one parent is useful: objects which are both weapons and clothes (such as gauntlets) should pose little problem.
      • There is already a large map in a format friendly to the text-only BASIC implementation. An ideal Perl implementation would accept the data from this file, convert it to a 'vanilla' set for the Perl version, and leave me the ability to round the original data out to something more appropriate to the finished engine.


      It makes your high level very instinctively obvious. Any new DM can, given a well-defined and documented API to your modules, create his/her own high-level programs.
      It makes changing game systems very easy. You are creating RPG::D&D::* right now. However, by that very package nomenclature, RPG::Cthulhu::* is very possible. If you leave out all implementation details from the top level, switching systems is almost trivial.
      It makes designing the system much easier. You don't have to remember that there is a 1% need to roll dice at the manager level. You'll know that all implementation details are hidden from the top level. You just need to have the appropriate module adjudicate itself.


      But if we're employing modules that use RPG::Dice, won't we have the option, however undesirable its use may be, to access the dice rolls from the top level? I'm not saying we should - just trying to check that we could.

      Now, we don't know exactly how these modules will go about doing their thing. In fact, we don't even know if they will be modules or classes. (RPG::D&D::Character may very well be a class - I find it easier to think of a PC or monster as an thing that knows how to do stuff versus a set of methods to be run on a data structure you have to maintain.) Each module will have an API (set of methods that other modules know about) and a mandate (what it takes care of for you). Once you have sketched this out, it becomes very simple to flesh out the skeleton.

      Silly question: what does API stand for?

      That aside, this re-emphasises to me the need to go OO. On the other hand, it leaves me scratching my head as to where to begin. Clearly the current create.pl will have to be re-written from the ground up. At the risk of picking other people's brains too much - how do people think I should start?

      Suppose we have RPG::DND::Character. Would 'fighter' be best as a function or other form of data in that module, or as a separate module dependent on it? How can we produce a call to the appropriate 'new' (or whatever) function which creates the character with the statistics chosen by the player? Or should the character be created as a 'blank sheet' and then filled in?

      I recognise that people will say 'It's your project: do it your way.', as well as 'TMTOWTDI'. But I'd be interested to know what (in broad terms) people think of my attempts to understand this new (to me) field of programming, and how they think I can avoid hamstringing my own project with bad implementation.

      Thanks!

      The grateful and apologetic Tiefling

      -----BEGIN GEEK CODE BLOCK----- Version: 3.1 GAT d++ s:- a-- C++ UL P++ L++(+) E? W+(++) N+ o? K w+(--) !O M- V? PS+ PE- Y PGP- t+ 5 X+ R+++ tv- b+++ DI++++ D+ G+ e++ h!(-) y +? ------END GEEK CODE BLOCK------
        API = Application Programming Interface. It's often used to describe the way a given module is meant to be used.

        Ok. Here's how I'd begin designing this from an OO perspective:

        1. Start by listing out every single thing you think you might want to have. Weapons, armor, characters, buildings, mountains, etc. Don't group things right now. What this step is doing is to give you a pool of ideas to work from. (You can't edit nothing ...)
        2. Group like things together. So, all the beings (farmers, orcs, and fighters) get grouped under the "intelligent being" category. Armor and weapons are group with rings and relics, under "thing".
        3. Start identifying how a orc, a farmer, and a fighter are similar. What do they have in common? IMPORTANT: Don't worry about how you'll use that functionality. That's not the point. You want to have an idea of what shared methods and attributes they'll have. For example, every single PC, NPC, and monster has hit points. So, a RPG::D&D::Being::Generic will have an attribute for hit points. Orcs, farmers, and fighters will all inherit from RPG::D&D::Being::Generic, thus all of them will have hit points.
        4. Then, identify how they're different. This can be both how they're different in kind (orcs and farmers have different goals) and how they're different in treatment (you'll want different info for a PC fighter vs. an NPC fighter).
        Now, you've got the start of a class hierarchy. Remember to identify what can be stored as an attribute and what needs to be a separate class. The rule of thumb I use is to see if there is fundamentally different methods used by only that difference. So, if being a cleric adds significant difference, there should be a cleric class.

        You'll end up re-writing a lot of this for your first time. Don't be afraid of that! Re-writing is good for the soul.

        Now, you have the first type of object down - the "thing". The second type is more difficult, intuitively. This is the object-as-process. Maybe a little discussion will help.

        A battle between 4 players and 4 orcs is a very defined thing. It has a start, a middle, and an end. It takes given input (combatants, time/weather, map, etc) and transforms that input into output (orcs dead, players victorious).

        Based on that, it makes sense to make a Combat class. You instantiate a new Combat object every time you have a battle.

        Given that, run through the steps above again, but this time for processes instead. Do every single step. It's more critical to do that here. For example, would you consider a skill or a spell to be a class? I would, because they have a beginning and an end.

        Yes, this sounds like you're going to have a lot of classes, and you will. But, if you do it right, it makes maintenance really easy. For example, if you want to change how all spells work, you have to go to Spell::Generic and make the change there. Voila! All spells do this new way. Same with skills, or combat, or weather, or whatever.

        What if you wanted to add a new skill? The way you do it right now, you'd have to add a line to a table, then modify another line in the character classes to say who's allowed to use it, then add a function to handle how it works. Instead, you just add a class. The skill knows who is allowed to use it or not. The skill knows how to "do its thing." Once you add the new class, everything is added and you've added a file and changed a file (to link in the new skill, wherever it has to be linked in to).

        I hope this makes sense. I would be very interested in working with you on this, either on perlmonks or via email, if you'll have me. (I wouldn't want to take over the project ... it's yours! But, I'd like to be sort of a ... design consultant, so to speak. *grins*)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://87790]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (3)
As of 2024-04-24 21:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found