http://qs321.pair.com?node_id=83892

Tiefling has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks,

I am presently undertaking what will forever after be known as 'Tiefling's daft text adventure project'. I am well aware that the advice of many here will be simply 'don't'. I am not deterred. :-)

Some time ago, I wrote a simple text adventure in QBasic, and I was heartily pleased with it. I expanded it, incorporating a rudimentary combat system, and experience, so that it became a crude but playable RPG. But the incoporation of moving monsters made the code elephantine, and DATA lines were overflowing the code size allowed by the free version of QBasic. So I re-wrote the thing from the start. This time I used lots of data files, and used a pointed to move groups of monsters in serial rotation. It coped fine with the file of 1800+ rooms, 200+ objects, and the like, but I was tired of having to read every data item from disk. And then, before the new combat system had been coded, I overran the code size again, and also started getting other spurious, Gates-oriented errors.

I threw up my hands and asked a hacker friend what I should do.

'Use Perl,' he said 'because it has nice, friendly text-handling, which you need lots of, and moreover, you already have it on the Linux dual-boot I set up for you.'

'Excellent!' I said, and set to learning Perl. I studied the wisdom of merlyn, and began to grasp the wonders of the Rubbish Lister.

Then I returned to the text adventure. I managed to write code to convert my Basic-friendly data files to Perl-friendly ones. (I'd used '/' as a list delimiter - what was I thinking?) All went well. The 1800 rooms are now in a format that Perl will read, although I intend to modify that format later.

I got ambitious, and remain so. The new incarnation of the adventure will be a full port of Dungeons and Dragons Third Edition to Linux. (After all, TSR WotC Hasbro has gone all opensource friendly, with the d20 Open Gaming Licence.) So I'm writing the character generator. So far, so good.

But (quite aside from the ludicrous scale of the project) there are a few problems. Traditionally, character generators for CRPGs have had a 'back' function, allowing you to ditch the results of the latest stage and start again with the data from the previous step. I'm trying to figure out a nice way of implementing this. Also, vast amounts of data (character races, skills, feats, spells) will be common to most areas of the code for one reason or another. Everyone says 'use strict'. This will, in my case, mean placing vast strings of my definitions at the head of my program. Is this either (a) normal or (b) avoidable?

I know that these are the queries of an ignorant, over-ambitious novice. But too often, the Right Way to Do X sends me to learn about references, which are all Greek Martian to me, or something similar. I am a mere beginner, but I want to be enlightened.

Tiefling

Replies are listed 'Best First'.
Re: Daft text adventure project
by arhuman (Vicar) on May 29, 2001 at 16:16 UTC
    Several points :

    • Super Search is your friend !
      'rpg' or 'adventure game' would provide useful links like
      RPG rolls or Rule Based Game Engines for example
    • Use strict shouldn't be avoid !
      Just understand that it will HELP you avoid mistake, and find somes quite tricky !
    • use strict and lexically scoped variables (my) don't prevent you to use large quantity of data
      (I'd suggest to store your data in (separated) files and load them in your lexically scoped hash, for example, at execution.)

    Anyway, as an old DM and Perl lover I'd be glad to help if you have more specific questions...

    "Only Bad Coders Code Badly In Perl" (OBC2BIP)
      Thanks for your fast response!

      In order:

      1: SuperSearching for 'text adventure' yielded the useful fact that I'm very far from the first person to try this flavour of thing for a first project. Thanks for the further links.

      2: I appreciate the benefit of use strict - I was just wondering if the twenty or so lines of multiple-argument my commands it will require were normal.

      3: What, exactly, does 'lexically scoped' mean? As a mathematician, it suggests something like 'having a alphanumeric string value' to me - is that correct? I'm already storing my data in files and loading multiple hashes with common keys at execution.

      To explain that last bit in a little more detail, so as to help those who would help me:

      In an inheritance from the QBasic implementation, everything has an identification code, such as R001234 (for rooms) or Z054321 (for spells - S was taken by another feature, so I used my scrappy knowledge of German to implement a poor mathmo in-joke), which is used to key all the hashes for the given type. Some hashes are keyed to more than one family of codes. For example, the PC races and the general species classes ('Humanoid', 'dragon', etc) both call the same hash for their names and superspecies references, so that the routine which classifies creatures can be fed a race or a species and won't quibble.

      Thanks again,

      Tiefling
        • 2. several my ($var1,$var2,%hash1); lines is ok.
          Learn to use hash/array to reduce the number of variables and group them in useful structure.
        • 3. Super Search my frien, Super Search is your friend.
          Almost all is said in my and local??.
          In brief lexically scoped variables are a kind of local variables.

        As Jepri said you'll probably have to play with Objects,
        as he already suggested perlboot, I will only add perltoot and Object Oriented Perl
        (I haven't read it yet but I've only heard good comment about it...)

        "Only Bad Coders Code Badly In Perl" (OBC2BIP)
Re: Daft text adventure project
by jepri (Parson) on May 29, 2001 at 16:33 UTC
    It's even worse, you will need to learn about objects. Well, you don't have to use objects, but sometimes they are fantastically useful. If you've come from QBasic, you will struggle for a while until you learn to relax and use the power. Start by reading merlyns absolutely fantastic perlboot tutorial. It even uses animals as examples.

    In the meantime you can build yourself a function library by reading through perlmod. As always I recommend using the example there to start your module building experiments.

    Modules are just like adding functions to Perl, but you can also add variables full of data. You just set them up in the module, export them and then any program that calls a use module; will be able to use those functions and variables. The declarations happen in the module, so you can declare hundreds of variables (but you shouldn't) inside the module and then use them in the program.

    Doing that will give you a firm basis for moving into object orientated programming, since packages are the basis for objects. ( I think they are actually classes, but I'm just learning this stuff too ).

    ____________________
    Jeremy
    I didn't believe in evil until I dated it.

      This all sounds very positive! I am aware of OO principles, but (for a variety of reasons) I'm sticking to pure function Perl initially. Hopefully, if I do a sufficiently good job first time through, then an OO re-write will be either easy or unneeded. I presently lack a home 'net connection, so building a function library will require care, time and floppies. I wasn't overtly aware that modules could be used to generate data, although I guess I'd have known if I'd thought about it for half a nano. However, as I will almost certainly want to use a 'god mode' for at least some of the game-world development, I'd need to be certain that such a usage was open-ended, rather than binding in a fixed quantity of data at the export time of the module.

      Thanks!

      Tiefling }:-)
Re: Daft text adventure project
by jeroenes (Priest) on May 29, 2001 at 16:53 UTC
    I like this kind of ambitions very much :-).

    For the 'back' feature: You need a whole new interface for that, whether you implement it in object-oriented perl or just in function-perl.

    You'll have to rewrite every instance of changing a variable to use code that remembers that chance. So instead of saying $foo++ you would say something like increment( $foo, $undo_stack). Because of inheritance, this is somewhat easier to mix in some OOP code than into non-OOP code, but your that really depends on how you have written/will write the code.

    Anyhow, you have to put into an extra layer between your normal code and the change of variables.

    I would use a undo-stack of a certain size (depending on the amount of resources you want to use). You can only undo the action that has been pushed onto the stack the last. When the stack exceeds its predefined size, you 'freeze' the first action of that stack into the vars.

    Many GUI-OO libs have a predefined undo-class. However, you need to write your own methods/ childs to define undo-actions for your own code...

    Hope this helps,

    Jeroen
    "We are not alone"(FZ)

      Actually, since (as is typical in this family of software) I'm writing a different kind of data at each step, it's not as difficult as you might think.

      Here's a little pseudo-code to illustrate:

      initialise_stuff; set_abilities; set_race; set_class; set_skills;

      That's the way (roughly) that it looks now. In my bad old BASIC days, I'd simply have had a GOTO triggered on the return value of each procedure to send the program back a chunk if the user asked to go back. Since you're given the chance to review any decision you make at the time you make it, this should allow procedures called to offer up the previously made choice for revision (and if it doesn't, I'll re-write the procedure so that it does) - I just need a clean way to drop back a stage on the appropriate return value.

      Tiefling
        My mind is not in general compatibility mode, apparently.

        Does this mean that you only allow the user to correct his input? Otherwise, the state of your program has changed since that step, because variables/objects have been altered. So you need to revoke these alterations.

        Checking for return values is really simple in perl:

        #This example is wearn out to the bone due to it's general use open FILE, 'data.txt' or die "Could not open data.txt: $!"; #in general, if function() returns either false or some true info: MAIN: { initialise_stuff; ask_user(); function( @_ ) or redo MAIN; .... }
        Jeroen
Re: Daft text adventure project
by gregor42 (Parson) on May 29, 2001 at 17:52 UTC

    I am well aware that the advice of many here will be simply 'don't'. I am not deterred.

    Brother, praise your determination! Many's the new disciple to the wisdom, magesty & magic of PERL, but few are so eager! This is a Good Thing. Don't let it go. It seems that you've been wresting with this for some time now & are not deterred, blessed be!

    Here's some advice & maybe a little bit of a simplified explanation of what has been said before:

    Since you are new to PERL and OOP, you are right to stick with functional programming for the time being to get out your first revision. However, anyone who has written a game that has to keep track of 'critters' in the backround, moving about & doing dirty deeds in deep dark places or whatever, will learn that OOP was invented for just this sort of problem! What you are creating in essence is, a simulation. Each monster would become an object. Each room would become an object. The relationship between them would be "contains". In this way, you don't need to hard code a monster's movement (unless you need to for some storyline of course) all you would do is to create a method called "move" in the monster class. It would find the room that contained it, see how many exits there are & say pick one at random to go through. Then you could call all of the monsters every turn or so & call to the move method on all of them. This is much simpler than how you're dealing with it. BUT, you've got to start your whole design from scratch to make it OOP friendly. If you're already drowning in code (which it sounds like) then this would probably be another Good Thing. But again, don't change cars in the middle of a race. Aim for that in version 2.0

    As for the question of the use of my.. Yes, you should always use it. It helps! Especially when you have a lot of code to deal with. And yes, it is normal to have a lot of declarations at the top of your code. But, as pointed out earlier, this can illustrate a problem in your design also. Rather than using a gaggle of global variables to deal with your data, look at it from a 50,000' aerial view... See the patterns in the data usage & build yourself Data Structures that more appropriately deal with the problem. Limit their existence to only where they are needed so they can't step on each other. You're going to want to deal with array & hashes & yes - references. I will tell you this right up front: PERL makes references Easy. So take your enthusiasm & use it as fuel to get through the textbook time & learn about them. You'll be glad you did.

    I will point out that T$R, though they are going towards an open platform of sorts is still very much the owner and junk yard dog of the intellectual property rights involved in their gaming system. (i.e. AD&D) So I would be very careful about saying that "I'm making a game that's D&D" or whatever. Especially if this is going to be a MUD/MOO. Or especially if you ever plan to bring the product to market. Besides, their system is overwrought with problems & overcomplexities. Use GURPS. (Steve Jackson Games) It gives you more freedom through simplicity; and remember, Laziness is a virtue!

    HTH!



    Wait! This isn't a Parachute, this is a Backpack!

      On copyright points: There was a degree of sarcasm inherent in my earlier allusion to the Open Gaming Licence. For reference, this is not going to be a MUD/MOO in the normal sense, nor is it going to be distributed. (Although, of course, if it were made suitably modular, rewriting certain elements could produce an engine that was OGL-friendly, so that I could distribute. But all that is far in the future. For the time being, this project may be considered a utility for personal use only. I can't be investing in GURPS. I'm out of bookshelf space, and as I write for the RPGA, I am somewhat tied to D&D. 3e is much, much more modular and coder-friendly than earlier versions - that's what inspired my dream of automating the system. (Although combat will be a kludge, since I'm _not_ providing floorplans of every room.)

      Again, I understand the principles of OO that you describe, in the same way that I understand, say, heavier-than-air flight. I understand that it's possible, and could explain it to someone else, but I couldn't do it personally. Not yet. To continue the analogy, the present implentation is a hot air balloon (QBasic was diving off a church tower with feathers glued to my arms), and the OO version will be my aeroplane (or helicopter).

      Perl may make references easy, but I have to confess I'm floored, even by merlyn's lovely books.

      And obviously, if the PCs and the monsters were both subtypes of the same class, they could presumably possess the same movement routine, called in different ways. I think.

      Tiefling
        And obviously, if the PCs and the monsters were both subtypes of the same class, they could presumably possess the same movement routine, called in different ways. I think

        Actually the way it would work would be that they would both inherit from a common class (prototype critter?) and therefore would be called the same way, via say the hypothetical "move" method. But, you would override the move method to make it function differently depending on the type of NPC or to add an interface for the PC's. But you would still call it by the same method name. i.e. move



        Wait! This isn't a Parachute, this is a Backpack!

Re: Daft text adventure project
by rchiav (Deacon) on May 29, 2001 at 17:07 UTC
    Now this isn't very perlish, but if you're at all familiar with C you might want to look at some MUD code to flesh out your implementation ideas.

    The one I'd recomend looking at is Circlemud. As far as text processing, you're not going to find useful information being that you're writing this is perl and circlemud is written in C; but as far as the structure and implemenataion of races, skills, spells, etc.. it would be an excelent refrence. IMO, things like their magic system could be improved.. and it might have being that I haven't looked at this code in over 2 years. But there's probably a lot there that you can draw from since this has been an evergreen type of project for many years.

    As far as having a bunch of constant data declared, It's pretty common. In perl, I'm not exactly sure of the socially acceptable way of doing this, but if you look at the header files for any (well written) C program, you have declaration upon declaration of constant data. Wether you put that at the top of your script or put it in another file that you include or require is a matter of style and what's socially acceptable. Personally, with something as large as this, I'd farm out all the constant declarations to a seperate file. It helps to keep things as simple as possible. I'd also try to keep all systems in a seperate file. For instance.. all combat related subs would be in one file.. magic in another.. communication in yet another.. etc..

    Hope this helps..
    Rich

      Last things first: the idea of storing separate routines in different files sounds nice - especially as the creator and adventure software will be distinct, but share certain functions. How is this achieved?

      As for the use of CircleMUD or the like: I don't know any C, despite other hacker friends singing the 'Code in C' filk irritatingly, and I don't want to overburden myself, as I'm already dealing with a new job and learning Swedish. Moreover, lots of MUD software I've seen has ignored the 'zero-one-infinity' rule, and allowed for, for example, at most six exits from a location, each with a fixed name. I want _very_ flexible exits - preferably allowing more than one with the same name, and a descriptive menu to allow you to choose between them. (This is partly because I want the spell fly to have some real application, and I'm somewhat unwilling to code separate locales for the airspace over every street-level area. Consequently, the option to have ten or so exits called 'down' would be a plus.) And the magic system is going to be as close a port of D&D 3e's system as I can manage (probably by having the spell file call routines via eval, and keeping the spell effect routines in a distinct file, as suggested.

      Thanks!

      Tiefling
        Undersatandable if you don't know C. Just thought I'd throw it out there in case you did. Ad far as using different files, you're going to want to look at use and require.

        There's some significat differences between the two and you're going to want to read up on them first. A basic example of require would be..

        #!/usr/bin/perl -w # # This is the main script # use strict; require "test.pl"; somefunc("test");
        And the required file...
        #!/usr/bin/perl -w # # This is test.pl # use strict; sub somefunc { print shift, "\n"; } 1; #file needs to return true on require or use.
        Now this probably isn't a good example, but it shows you the basic usage. You're probably going to be better off creating modules and useing them instead. I'm still relativly new to perl so I can't give you all the reasons, but the 2 bigest benifits of modules and use will be 1) you're not going to (or you can avoid) polluting your namespace. Which means you can do something like DaftMagic::Cast($source, $target, $spell); where "Cast" doesn't exist in your namespace. Keeps things a little cleaner. 2) Things are loaded at compile time instaed of run time.

        I'm sure others could give you the pros and cons of requiring files vs. using them.. and the usage of modules. There's also some other reading - perlmod, perlmodlib, perltoot, and perlobj.

        HTH..
        Rich

        1. How to store routines in separate files:
        #file shared1.pm: use strict; sub xxx1 ($\%\@@) # define xxx1 with prototype { blah blah; return ...; } # end sub xxx1 use Exporter(); @ISA=qw(Exporter); @EXPORT = qw(xxx1); # exports name xxx1
        -----------------
        Now, in your main.pl program file, you may call subroutine defined in shared1.pm above:
        use strict; use shared1; # 'include' shared code ... # call sub defined in shared1.pm my $result = xxx1($arg1, %arg2, @arg3, $optarg1, $optarg2); ...
        ---------------------
        2. In project this huge, I advise to use not only 'use strict' everywhere, you may want to learn how to do 'prototypes' as well. It will help you to detect (some) errors when wrong numbers or types of parameters are passed to subroutine. While on that, you can also learn to pass hashes as references. Good luck on your long jourmey! PMAS
Re: Daft text adventure project
by Masem (Monsignor) on May 29, 2001 at 17:00 UTC
    As per handling the 'back' data, I'm encountering a similar problem, and I think what I'll do is create an array of hashes. Each 'page' would write a hash of settings, and push that onto the array. Subsequent pages create new hashes which are pushed onto the back of the array. To determine the value of a variable at any time, run through the array looking for a given key in the hashes, and return the last instance found. To go back, simply pop off the last hashref from the array.


    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
Re: Daft text adventure project
by Sprad (Hermit) on May 29, 2001 at 18:14 UTC
    You may also want to take a look at Inform. It's a language designed purely for creating text adventures, in the vein of the wonderful Infocom games of yore. In fact, it's actually an extension of the original language that Infocom used to create their games. It's been pretty heavily extended, though -- people have even written Tetris in it. It's not Perl, but it's fun, free, and worth a look.

    ---
    A fair fight is a sign of poor planning.

Re: Daft text adventure project
by mbond (Beadle) on May 29, 2001 at 18:27 UTC
    Okay ... I did this once, then began converting what i had done to work as a MUD. It is still a work in progress, but this is what i have learned.

    1) use strict; -- It will save LOTS of headaches later on

    2) Use modules for everything -- Don't try to cram it all into one large file. Break it up. Have your movemnt commands in one modules, fight commands in another, etc ...

    3) plan for the future. Make it EASY to add features. More player information, room info, object info. No matter how much you plan when you start, theres always something you have forgotten.

    I like using data dumper to dump hashes to text files and get tehm back again. It cuts down on a lot of coding, you don't have to parse any text files. In fact i put all my config stuff in a hash and dumped it to a file that gets loaded when the game starts.

    Good luck ... i hopy you have more luck with it than i have ... I have been away from the project coding for another mud for so long that mine is prolly dead ...

    Get something good going, RPG games in perl will rock.

    Mbond
      Tell me about the data dumper, please, brother. The aforementioned hacker friend said that there was a capacity for hash-dumping, and if the first draft of the program is to retain the current way of handling the data, such a facility would be ideal. I've tried to find out about this before, and failed. (Don't say 'use Super Search', because I'm wasting office time on this thread already, and I don't have a home connection ... yet. I'll do a proper search for all these things later - I greatly appreciate the input of my fellow monks right now. Bless you all.)

      1) Ok, I believe you all about use strict. :-)
      2) This is clearly what I have to learn next.

      3) Absolutely. It struck me that I'm going to have to recode the room data by hand, because I'm going to want the olfactory, visual, auditory and tactile/environmental data of each room to be accessible in bits, to allow for the spells blindness and deafness, not to mention darkness and other environmental effects. Clearly, using a format that will enable me to add other such elements later without another re-write is essential.

      Thanks!

      Tiefling
        this is a real simple breakdown of the code ...

        its quite simple to do, and not very difficult to figure out :)

        to read a file:
        $filename = "$player_dir/$temp";
        do($filename);

        to save a file:
        print FILE Dumper \%myhash;

        Mbond.
Re: Daft text adventure project
by bikeNomad (Priest) on May 30, 2001 at 00:05 UTC
    Sounds like a fun (and educational) project. A couple of things you may want to look further into:<bl>
  • A common pattern for handling Undo is to have each undoable operation return an object that knows how to undo that operation. These objects carry enough context (perhaps the old value of whatever was changed) that they can be told to undo (but only in order). For more discussion on this, see the discussion of the Command pattern in the book "Design Patterns: Elements of Reusable Object-Oriented Software" or in the many web sites dealing with Design Patterns.
  • One kind of software architecture that has been useful is what is known as a "prototype based" system. This is a kind of object oriented system that does not depend on "classes" for inheriting (reusing) behavior, but rather on maintaining references to objects whose behavior is similar. This works better than traditional class-based inheritance if you have many objects (or characters or other game artifacts in your system) that are almost but not quite the same in their behavior. For instance, a cursed sword of a certain kind might have subtle changes in its damage. Rather than testing this in the code for computing sword damage, you can instead attach the proper code bits for dealing with cursed swords. This is a more flexible and fine-grained way to deal with the many kinds of behavior than a class-based system. Perl's object model is flexible enough to support prototype based programming. To understand how to do this, you first have to understand how Perl's method lookup works for an object: when you call a method on an object like this:
    my $sword = Sword->new("Excalibur"); my $damage = $sword->damage($someOtherPlayer);

    Perl will first look in the Sword package for a subroutine called "damage". Failing this, it will search each of the packages named in the @Sword::ISA list for a subroutine called "damage". If it still doesn't find damage(), then it will call AUTOLOAD with the name of the missing method ("damage") as well as the arguments to that method. How can you do prototype based programming with this? Simple: by exclusively using AUTOLOAD to call whatever functions need to be overridden on a fine-grained basis (that is, anything you didn't define in the package of the object itself or one of the packages named in its class's @ISA array).

    You can do this by maintaining named slots for overridable methods, putting subroutine references into these slots, and then calling them from your AUTOLOAD method.

    Where the "prototype" comes in is that an object could refer to another object whose behavior it can share.

    Of course, being lazy, one could look at CPAN and find the modules Class::SelfMethods or Class::Classless, which provide for a couple of different kinds of prototype-based programming support.

  • </bl>

    Best of luck with this project!

    updated: clarified use of prototype

Re: Daft text adventure project
by swiftone (Curate) on May 29, 2001 at 21:10 UTC
      Thanks!

      I have looked at the existing state of play, and the conclusion I draw is that if I were only ever going to be interested in writing an RPG or IF I would certainly get, learn and use Inform. However, I am doing this with the two equally strong interests of writing an RPG and getting really good at Perl, OOP, etc. So I'm determined to do it the hard way, so that at the end (if there is an end), I can say 'thus did Tiefling', and understand every bit of my code. Also, I'm not sure how receptive Inform (for example) would be to an attempt to build all the core D&D character classes and several prestige classes.

      As a note, I will be producing (in the end) a modern-setting version of the game which will lack the specific copyrighted identities, and be a bit more in the whimsical line of early text adventures. This will be posted here on PM, in all likelihood.

      As for your explanation of references - thanks! This looks like the way to implement the first Perl version of my project. One question: is the long string in your penultimate line a single scalar for all purposes?

      Oh, and another: Could I include lists in that hash by reference? (Storing feats, spells, etc. as booleans is not efficient, IMHO. I want to be able to brew a new feat and not have to go and set the bit in all the PCs.)

      And another: If, for example, $character{'Bob'}->{'Class'} holds 'Ftr', and $class{'Ftr'}->{'Base Attack'} holds 'Good' (to indicate that fighters have Good attack bonuses, which are generated by a short procedure in the combat module), what would be the code to retrieve Bob's Base Attack type? I may be being dense here, but I'd rather be clear.

      Thanks again!

      Tiefling
        So I'm determined to do it the hard way, so that at the end (if there is an end),

        Doing it the hard way is a time-honored tradition :) I just suggested you check out how the others work so that you can steal good ideas & interfaces.

        is the long string in your penultimate line a single scalar for all purposes?

        You mean $character{'Bob the Fighter'}->{'Attributes'}->{'Str'}? Yes, because in the end it is just a value stored in a hash, and only scalars can be thus stored. By dereferencing part of that mess, you can get a hash. For example, %{ $character{'Bob the Fighter'}->{'Attributes'} } is the Attributes hash. (The scalar value $characters{'Bob the Fighter'}->{'Attributes'} is a reference to a hash. the %{ } dereferences the reference.

        Could I include lists in that hash by reference?

        Absolutely. A reference to anything is a scalar, and a hash can store a scalar. An anonymous list can be created by [], or you can use the backslash reference. So:

        $characters{'Bob the Fighter'}->{'Feats'}= [ 'Strong Spit', 'Perl Guru +']; # or @feats = ('Strong Spit', 'Perl Guru'); $characters{'Bob the Fighter'}->{'Feats'} = \@feats;
        both work just fine. You can then access them like:
        $characters{'Bob the Fighter'}->{'Feats'}->[1]; #is equal to 'Perl Guru'
        Remember that although we're using a hash as our "base" variable here, we could use any other data type that is appropriate. A list could work:
        $characters[3]->{'Attributes'}->{'Str'};
        as could a scalar:
        $characters->{'Bob the Fighter'}->{'Attributes'}->{'Str'};
        (Assuming you had stored the data in that fashion.)

        If, for example, $character{'Bob'}->{'Class'} holds 'Ftr', and $class{'Ftr'}->{'Base Attack'} holds 'Good' (to indicate that fighters have Good attack bonuses, which are generated by a short procedure in the combat module), what would be the code to retrieve Bob's Base Attack type?

        Well, $class{$character{'Bob'}->{'class'}}->{'Base Attack'} would be equal to $class{'Ftr'->{'Base Attack'} (actually, it would _BE_ the same, since all that happens is $character{'Bob'}->{'Class'} resolves to 'Ftr') However, this assumes that Bob's class will ALWAYS have an entry in %class.

        Storing feats, spells, etc. as booleans is not efficient, IMHO. I want to be able to brew a new feat and not have to go and set the bit in all the PCs.)

        Just so you know, Perl handles non-existant hash keys quite nicely, and it's quite common to see code that would be like:

        if($char{Bob}->{Feats}->{'Good With Pointy Objects'}){ Kill_Bad_Guy(); } else { Die_Hideous_Death(); }
        If Bob doesn't have that feat, you don't have to set it to 0, you simply don't set it to a true value, and it will evaluate False. (Well, undefined, which in turn is false)
Re: Daft text adventure project
by Cryptoknight (Initiate) on May 29, 2001 at 19:57 UTC
    I'm not sure this will fit your project exactly, but as a student of text adventure design (truly a lost art nowdays) you definitely should check out Rezrov... http://www.voicenet.com/~mikeedmo/rezrov/ One of the implementations is in Perl. Basically, Infocomm created their own language for writing adventures. It can do everything from Zork to Tetris.
Re: Daft text adventure project
by merlyn (Sage) on May 31, 2001 at 00:44 UTC
      Odd... after 30-ish posts in this thread, I still haven't seen anyone mention PerlMud from the brlliant Tom Boutell. I guess it's up to me! {grin}

      Thanks! I remembered having heard of such a project, but couldn't recall where or exactly what. Thanks very much for filling me in. Duly downloaded, and I'll install it tonight.

      Of course, as one of the intents of my project is to provide sequential play for multiple users at one terminal, PerlMUD won't *exactly* fit the bill, but by heck, it's going to be worth a look.

      Tiefling (Alex Roberts, not a Perl hacker)
Embrace Objects
by John M. Dlugosz (Monsignor) on May 29, 2001 at 19:04 UTC
    I applaud your efforts. The fun is in the building, not in the result, so don't worry how impractical it may be. It is a perfect project to enhance your skills with.

    Not only should you use strict;, you should embrace Object Oriented Programming concepts. As such, the undo is trivial—copy the object first and throw it away rather than copying it back with changes made. Learning how to architect a large project uses totally different skills than learning how to write in Perl (or whatever language).

    —John

    Edit 2001-05-30 by mirod: fixed typos

Re: Daft text adventure project
by pmas (Hermit) on May 30, 2001 at 18:50 UTC
    I like your project - and your courage.
    You already noticed that you have a lot of data, right?
    Now, you may consider to place your data into some database. MS Access will be my first choice, but it depends on platform you prefer. There are many free open-source SQL databases around.
    What new possibilities will it open for you?
    (1) You'll learn databases, SQL - and learning is you primary goal. right?
    (2) No limits for data. 50,000 rooms? No problem any more.
    (3) Design of tables should not be an issue: you already have data structures to store rooms, creatures and objects. Instead of hash you'll store them in database.
    Added bonus: database (as MS Access) will provide for you user-friendly interface to review/filter/update your data, to program behavior of creatures and objects.
    (4) You are opening doors into multiplayer game later. You can have one engine (Universe), and many clients may access it. Even more exciting, you can write program to play using Artifical Intelligence (AI) to play instead of you. And then have tournaments of AI players.
    What a Ultimate Laziness: to create program to play instead of you!

    Update: I can imagine how much of you, fellow monks, frowned when I proposed to use MS Access as database of choice. No so fast. I assumed Tiefling does not have experience with databases (otherwise he will used DB right away when run out of data space). MS Access is excellent for prototyping in Windows environment and has excellent 'wizards' to help with building SQL queries graphically and to visualize tables and their relationships.

    pmas

      I'm afraid this is the first helpful suggestion that I'm going to have to turn down wholesale, for a variety of reasons:

      1: I don't want to have to learn how to make Perl read a database created with some external package.

      2: My work involves two databases, one MS Abcess, the other SQL. I've just spent a hellish afternoon trying and failing to produce a list of items from a given list once each exactly in the SQL database. I know I could have written Perl to do the same thing, given an appropriate data structure, in about 5 minutes. I'm trying to learn, yes, but I'm doing this for fun.

      3: I have the version of Perl I got with Redhat Linux. I don't see Access for Linux anywhere, and I'm not about to start going to the mountings of the Windoze directories to fetch data. The adventure is intended to be self-contained.

      4: Judging by my experience today, transitive exits would be quite a challenge in SQL, etc. I'd rather produce my own editing features, integral to the program, so that I can tinker as I go.

      The game is intended to be multiplayer, in the sense of sitting around a single machine. AI is an option. But I'm not quite clear how drowning in SQL helps me write AI later.

      Sorry to discard your advice - I'm just not a databasey person! :-(

      Tiefling
Re: Daft text adventure project
by tekniko (Deacon) on May 29, 2001 at 21:55 UTC
    Heh, heh, heh...What an ambitious project! Good luck!

      So...In trying to support the "Daft text adventure project" I was totally harshed.

      Perhaps I should have done something like: <sincerity>Heh, heh, heh...What an ambitious project! Good luck!</sincerity>

      That might have made everyone feel a bit better about it, eh? If one were to peruse my write-ups, a comment made regarding community might have staved off some of the negativity regarding my post. Perhaps not.

      I really, really do wish Tiefling the best of luck in the project; I know that the project will be supported in any way possible through the Monastery. It is a huge undertaking, but everyone loves a challenge, yes?