laziness, impatience, and hubris PerlMonks

### Modules: Building blocks for the Daft Adventure

by Tiefling (Monk)
 on Jun 12, 2001 at 15:20 UTC Need Help??

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

Following my earlier request for assistance, I'm beginning to see the joined-up way of working that I need. It is my intention to produce modules performing the general functions of the RPG. (If possible, I'd like them to be called RPG, RPG::DND, etc.) Once I have the answer to this query, I'll go away and produce the RPG::Dice module which converts any die roll, expressed as a string ('3d6' for 'the sum of three normal dice', for example) to the appropriate set of rand calls and sends back an appropriate roll. (A side-effect of this will probably be simpler calls for specific things - such as a dice(\$n) call to roll an n-sided die.) This module will, naturally, be posted here at PerlMonks.

All well and good. The small problem here is that every discussion of modules which I've encountered either jumps in the deep end or assumes prior knowledge which I haven't got. So, I'm going to ask for help with a trivial case:

In Dungeons and Dragons Third Edition, all ability score modifiers are drawn from a single table. This table's values are trivial: given a score of n, the modifier is (n/2)-5. (ie: 8-9: -1; 10-11: 0; 12-13: +1). In the first shot at the character generator, I stupidly plugged these values into a list. Simpler, cleaner, and more transferable, I now realise, to call a function modifier(\$n) for an arbitrary value of \$n. So:
```sub modifier { int(\$_[0]/2)-5 }

(I hope that does what I said it did - I just wrote it on the fly.) The question is, how can I turn that into an element of the (as yet unwritten) Module RPG::DND, and how will the function then be called?

Thanks very much,

Tiefling, Known Lazy Bastard

```-----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: Modules: Building blocks for the Daft Adventure
by davorg (Chancellor) on Jun 12, 2001 at 15:47 UTC

In RPG/DND.pm

```package RPG::DND;

use Exporter;
use vars qw(@ISA @EXPORT_OK);

@ISA = qw(Exporter);
@EXPORT_OK = qw(modifier);

sub modifier { int(\$_[0]/2)-5 };

1;

In another_script.pl

```use RPG::DND qw(modifier);

# lots of code

modifier(\$value);

# lots of other code
--
<http://www.dave.org.uk>

Perl Training in the UK <http://www.iterative-software.com>

Many thanks, davorg! That looks like the Way to Do It I was looking for. Dare I ask what the @ISA does? I've seen @ISA in connection with OO, and one of these days I'll use it myself in that context. But what is its function in a Module?

Tiefling, seeking enlightenment

```-----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------

@ISA does the same thing here that it does in an OO module. It defines other modules that Perl should search for subroutines that you don't define in your module.

For example, in this case use Module is (almost) the same as:

```require Module;
Module::import;

So Perl tries to call the import function in your module. Your module doesn't have an import function so Perl searches the modules in @ISA and calls the first instance of import that it finds. This is in Exporter. Exporter::import does all sorts of clever things and exports the contents of your @EXPORT_OK array into the calling package.

Update: Ridiculous typo corrected. Thanks to ryddler.

--
<http://www.dave.org.uk>

Perl Training in the UK <http://www.iterative-software.com>

Re: Modules: Building blocks for the Daft Adventure
by dragonchild (Archbishop) on Jun 12, 2001 at 16:33 UTC
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.)

You are looking to write a series of modules that will help you develop a comprehensive D&D application. The key word there is "application". I don't know what your background is in Perl or programming, but 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. If you're looking to write a stable app, you need to realize that's what you're doing and design this a bit. If you intend on using this over and over, and/or extending it, this week or two in the beginning where you define where stuff lives will be absolutely critical.

"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.

Now, the immediate response would be that dice() also deals with combat. Ok. So, dice() may need to live elsewhere, and that's fine. The question would be "Where?"

modifier() seems to imply a character module. This would have things help you generate stats, choose skills, choose spells, and moderate when someone can cast a spell or not. Sounds like a lot? Well, it is ... and it isn't. Who says every bit of code has to be in RPG::D&D::Character?

A case could be made that the top level should not know how to roll dice. All the top level should know about is characters, spells, and combat. Why? Because it doesn't care how combat is resolved. All it cares about is that combat is resolved. All the details should be taken care of by RPG::D&D::Combat. No-one else wants to know, cares to know, or should know. Same goes with character generation, skill/spell adjudication, etc.

Creating a RPG::Randomize module is definitely appropriate. Within this module could be dice(), as well as other methods of randomization. coin_flip() could be here. (1d2 is different than flipping a coin, and you should code it that way, even if it would seem that, from the theory, it is the same.)

However, the high-level manager doesn't know about RPG::Randomize. It doesn't care about the mechanics of it. (If only I could draw a picture here!)

I hope this helps you understand a little of the deeper thinking behind sane package construction. Also, please use strict in everything you do. It will make your code much cleaner and clearer.

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------
(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.

Re: Modules: Building blocks for the Daft Adventure
by modred (Pilgrim) on Jun 12, 2001 at 15:39 UTC
Well, it all depends on how you setup your module. If it is just a basic package that is not an object and does not \ use Exporter then you would call it like

```RPG::DND::modifer(argument list here);

If you use the Exporter module when creating your module, then you can (optionally) import the function name into the current namespace and just call it is as

```modifer(argument list);

If you make RPG::DND an object, you would create an object of that type, something like my \$rpg = new RPG::DND;, and then you would call it like

```\$rpg->modifier(arguments);

Also, you might want to name it something like getModifer rather than just modifier so it is slightly clearer on what the subroutine does.
Thanks, as ever to the Monks, for the quick answer!

Now I need to know why would I want to use or not use Exporter. I can't see the advantage of having to write eight more characters every time I call the sub - what are the other pros and cons?

As for making RPG::DND an object, I'm a little confused now. I had thought I understood objects, but now I'm all at sea again. I thought an object was, or was the target of, a blessed reference. (Apologies if that's not expressed in a canonically clear manner.) What does it mean for a module to be an object?

As for the name of the sub, the name was chosen to bring readability to the final code. If I'm able to say modifier(\$strength), it'll make the finished text easier for me to read.

Tiefling, KLB

```-----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------
The reason not to use Exporter would be to easily identify which module contains the body of the subroutine that you are calling. If you create many modules and then export them all into the same namespace it might get confusing about which subroutine belongs with which module. Also, it helps to avoid the case of two modules exporting a subroutine with the same name. Just something to keep in the back of your mind as you develop the code.

As far as the object goes, I think you have a good grasp of what an object is. For a package to define an object, it must contain a subroutine that returns the blessed reference. This is typically named "new" but it does not have to be.

I may have caused some confusion by using the terms module and package interchangeably - which they are (for the most part) in my own mind. I am not sure of what the actual difference between the terms is though.

Re: Modules: Building blocks for the Daft Adventure
by Masem (Monsignor) on Jun 12, 2001 at 15:41 UTC
Right idea: you probably are meaning to use coderefs.

The way I've been using coderefs is as follows:

```sub do_stat {
my ( \$dice, \$mod ) = @_;
my \$roll = RPG::Dice::roll ( \$dice );
return &\$mod( \$roll );
}
That is, the &\$mod is a function call of a deref'ed coderef. To actually call this, you can do it by one of two ways:
```# anonymous function call
my \$roll = do_stat( "3d6", sub { int(\$_[0]/2)-5; } );

# Named function call
sub modify { int(\$_[0]/2)-5; }
my \$roll2 = do_stat( "3d6, \&modify );
(The \& here creates a reference to the function modify).

What's nice about coderefs is that they then can be used as variables, and allow you to quickly do different functions depending on what you pass:

```my @data = ( { name => 'STR',
dice => '3d6',
modifier => sub { \$_[0] + 2 }
},
{ name => 'INT',
dice => '3d6',
modifier => sub { \$_[0] - 5 }
}
);

foreach ( @data ) {
\$_->{ roll } =
&{ \$_->{ modifier } }( RPG::Dice::roll( \$_->{ dice } ) );
}
</CODE>
Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
Re: Modules: Building blocks for the Daft Adventure
by mbond (Beadle) on Jun 12, 2001 at 15:51 UTC
an simple excert from a package that I used in my perl mud.

because this is a learning experience, i'm just giving the skeleton of what i did.:) The ideas will be the same for making dice rolls into a module.

in a file called "comm.pm" which is in the same directory as the main perl script.
```package comm;
...

sub tell {
my(\$client,\$argument) = @_;

...

return(\$output);

}

####

and it is used in that main program somethign like this:

use comm;

...

comm::tell(\$client,\$arg);
It actually calls it through a funtion and the above line is completely variable (so that it works from any function call)

Michael Bond
Re: Modules: Building blocks for the Daft Adventure
by Syrkres (Sexton) on Jun 12, 2001 at 21:56 UTC
Tiefling,

We should work together on this. I have already created a RPG: module system with several modules. The first being :Dice.

I also have :Name, and have started working on :Classes and :Char. Another one is :RULGen which uses a rule structure for generating random things. I am currently re-writing this to work with XML templates.

Syrkres (syrkres@miniworld.com)
Syrkres:

I'd be happy to have you working with us on this project! (See elsewhere in the threads for copyright points.) What do the modules you've already got actually do? How transferable is the system you have devised? How would it relate to the proposed Text Adventure interface?

```-----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------
Re: Modules: Building blocks for the Daft Adventure
by Malkavian (Friar) on Jun 13, 2001 at 01:59 UTC
Auspicious timing.. :)
I've been working on a Rolemaster set of tools in Perl.
If it looks like the code is being generated as an ongoing Monastery members thing, I'd be happy to add routines and char gen tools for RM.

Malk.

Re: Modules: Building blocks for the Daft Adventure
by coreolyn (Parson) on Jun 13, 2001 at 02:15 UTC

Has anyone even checked Dice::Dice? If so what makes it impracticle? It handles 3d6 type of calls and other functionality is already built in. Your modifiers could then be implemented from thier own module outside of the roll and your modifier routine doesn't have to know squat about the roll type and would be far easier to maintain.

coreolyn
I just went and looked at Dice::Dice. It _might_ do what I want it to, but:

1: I want to be able to parse a string and return the appropriate roll. This is the main thrust of the module in question. Dice::Dice has some ability to do this - however, there are situations (particularly in games like Warhammer) where large bucketfuls of dice are needed. Dice::Dice might well not be efficient here, as I don't want persistent objects - only answers.
2: Dice::Dice, by your own admission, requires a re-write because of the use of deprecated features - unless the re-write has already taken place and I missed the note that says so.
3: I don't _want_ well-behaved object dice. I want a function which takes appropriate input and brings back a number, by munging the input and totting up a bunch of rand() calls. Perhaps I need to clarify what I expect my own module to do.

Desirable calls:

stringdice() - a function to take a string like '3d4 + 2d6 +4d8 +9' and return a properly-distributed random number in the appropriate range.
listdice() - a function to take a couplet (\$x, \$y) and return the individual values of xdy as a list.
bestdice() - bestdice(\$x, \$y, \$z) returns the best \$z values of listdice(\$x, \$y).
topdice() - topdice(\$x, \$y, \$z) returns the values of listdice(\$x, \$y) exceeding or equalling \$z. (For World of Darkness, for example).

Looking at the documentation for Dice::Dice, it could probably be persuaded to do the above, but I'm not sure if it's the best way to proceed.

All this is not intended to suggest Dice::Dice is at all bad - far from it - but TMTOWTDI. Also, I'm interested in being able to develop this stuff myself, and Dice were not a feature of the implementation which screamed to be OO.

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------

Thanks for the explanation, and yes the code was re-written, but I'm not completely sold on them either for performance reasons -- I'm just shamelessly trolling for opinions :)

Having coded many of the DnD charcter generation and battle tables in several languages over the years (It's my favorite way to learn and compare languages) separating the dice makes it easier to run the rolls against matrices as well as clearly delineating whose dice are being operated on.

Plus in the game design I've always pondered I've looked for ways to put the dice back in the hands of the players. In table top gaming picking and rolling your own dice is a part of the fun.

coreolyn
Re: Modules: Building blocks for the Daft Adventure
by mattr (Curate) on Jun 13, 2001 at 15:42 UTC
It's been a while since I played D&D but I was thinking that your work might be extensible to general descriptions of inhabited virtual worlds. In that case I'd try and boil down your huge knowledge of D&D to the absolute basic minimum number of concepts you need to describe what playing D&D is about. Maybe the basic ideas of players, monsters, and Dungeon Master are something you want to use. I don't know how you intend to use the module(s) but I just read Neil Stephenson's The Big U and it describes using a huge computer to run the game (with a DM seated in front of it) while the players actually run through the sewers in 2-way radio contact.

Anyway you might want to check out Games::Maze in CPAN just for an idea of how to generate mazes and populate them. Maybe you don't want this because the mazes are all preprepared, but the point I wanted to make is to think about how this system will actually be used and try to conceive of the main scenarios for use. This may help you decide what metaphors for game play are useful and the objects can be defined naturally from that.

I'm not sure if you are trying to build something like an intelligent gaming board on a server somewhere that interacts with many browsers, or if it is just a totally abstract system of descriptions of gaming and objects in a game that doesn't suggest a certain implementation. Or is this maybe just for a single user? I think the real question is, are you trying to build a general simulation system (it might work for military simulations too) or a simpler gaming aid for a DM to use. The nice thing about modules is that it helps you compartmentalize your thinking, and keep it simple. Of course you can just dive in and not worry about doing lots of revisions!

If you are trying to a general system to describe and run all kinds of simulations of players in virtual worlds, then you can start from the ground up and try to describe what D&D is all about from the ground up instead of starting with advanced concepts like monsters and multisided dice.

But the idea of respecting Perl that came out above I think has more to do with taking care of how you choose the underlying metaphors on which your system is built. If they are powerful metaphors which resonate strongly with the realities of gaming, you will be able to extend them for a long, long time.

It's been a while since I played D&D but I was thinking that your work might be extensible to general descriptions of inhabited virtual worlds.

Granted. You'll have noticed, elsewhere in this thread, discussion of Call of Cthulhu and other systems. A major part of this project is the development of a text adventure system that can accept rules sets as additions.

In that case I'd try and boil down your huge knowledge of D&D to the absolute basic minimum number of concepts you need to describe what playing D&D is about.

I was thinking of boiling it down to 'what is a text adventure' and 'how do we make the format extensible' myself.

Maybe the basic ideas of players, monsters, and Dungeon Master are something you want to use.

Curiously combat and monsters in the sense of physical adversaries are inessential. And the Dungeon Master in my original concept was to be me, coding the behaviour of rooms, characters, etc, to be interacted with by the players.

I don't know how you intend to use the module(s) but I just read Neil Stephenson's The Big U and it describes using a huge computer to run the game (with a DM seated in front of it) while the players actually run through the sewers in 2-way radio contact.

How can I say that this would be a very bad idea? I am a member of a Live Roleplay group, and any suggestion that players might be sent into a genuinely inimical environment without any form of direct supervision is...frowned upon. The intended format would be players sitting at one or more terminals, taking turns to issue actions, to be parsed by the computer and used to alter the state of play. Something like a MUD, people will say, although my idea of the passage of game time mandates a turn-based approach which means it won't actually be a MUD.

Sample output of a modern-idiom version:
```------------------------------------------------------------

[16:24 GMT]

This is Earlham Street, just north-west of Seven Dials. On
the south-west side of the road is a small games shop,
'Orc's Nest'. Other quaint and curious shops line the road,
and there is a market stall here selling gothic gewgaws.
Further along the street to the north-west you can see
Cambridge Circus, and the narrow streets of Soho beyond. The
weather is slightly overcast, and seagulls overhead suggest
storms in the Channel.

A stallholder, a goth and a passer-by are here.

You feel slightly hungry.

What now? > nw

Going north-west to Cambridge Circus. Next move at 16:26 GMT.

That's just an idea, but I hope it captures something of where I'm coming from. D&D, CoC or whatever other rules system and campaign idiom the operator chose could be applied to the core program to produce an appropriate campaign. I've looked at Games::Maze - it looks interesting, but the idea of the system at hand is that it should produce a realistic, deterministic, mimetic world for game play. As to monsters, I agree with you - not yet. I suggested the production of a dice module because doing so would make the subsequent implementation of _any_ deeper rules system easier. So it's not what D&D is about, because if you ask that, the answer is 'first and foremost, it's a work of creation and imagination, and not about rules at all'.

What does all this talk of metaphors mean? I've just got out of a meeting packed with talk of 'frameworks' and 'outcomes' and other civil service bafflegab, and I need a breath of fresh English/French/Swedish/Latin.

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------
Re: Modules: Building blocks for the Daft Adventure
by Syrkres (Sexton) on Jun 13, 2001 at 22:29 UTC
Ok,

Here is my dice package below. It allows for computing dice expressions, which I have created a bit of syntax for. Please give comments on it as this is my first package ever made public. And though it works, it may not be the best.

Syrkres
```package RPG::Dice;

require 5.005;
use strict;
use warnings;
use Carp;

use Exporter;

use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK @EXPORT \$VERSION);

@ISA = qw(Exporter);

# Items to export into callers namespace by default. Note: do not expo
+rt
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.

# This allows declaration    use RPG::Dice ':all';
# If you do not need this, moving things directly into @EXPORT or @EXP
+ORT_OK
# will save memory.
%EXPORT_TAGS = ( 'all' => [ qw(
&computeDice
) ] );

@EXPORT_OK = ( @{ \$EXPORT_TAGS{'all'} } );

@EXPORT = qw(
&computeDice
);
\$VERSION = '0.85';

my(\$no_ltz_results) = 1;

BEGIN {
srand(); # intitalize Randomizer
}

#---------------------------------------------------------------------
#---------------------------------------------------------------------
sub computeDice {
my(\$die_expr) = shift;
my(\$top_rolls, \$no_rolls, \$die_face, \$adj, \$die_modifier, \$list_rolls)
+  = 0;
my(\$roll);
my(\$result) = 0;
my(@dice_rolls) = ();
my(@temp_rolls) = ();

if (\$die_expr =~ /tt(\d+)/i) # Top rolls
{
\$top_rolls = \$1 * -1;
\$die_expr =~ s/tt(\d+)//i;
}

if (\$die_expr =~ /l/i) # lowercase L
{
\$list_rolls = 1;
\$die_expr =~ s/ *l *//i;
}

if (\$die_expr =~ /(\d+)d(\d+)(([-+])(\d+))*/)
{
\$no_rolls = \$1;
\$die_face = \$2;
\$die_modifier = \$5;

while (\$no_rolls-- > 0)
{
push(@dice_rolls, int(rand(\$die_face) + 1));
}
}

if (@dice_rolls) #@articles = sort {\$a <=> \$b} @files;
{
if (\$top_rolls)
{
@dice_rolls = sort {\$a <=> \$b} @dice_rolls;
@dice_rolls = splice(@dice_rolls, \$top_rolls);
}

foreach \$roll (@dice_rolls)
{
\$result +=  \$roll;
}

{ \$result -= \$die_modifier; }
else
{ \$result += \$die_modifier; }
}
else
{
\$result = -1;
}

\$result = 1 if ((\$no_ltz_results) && (\$result < 1));

if (\$list_rolls)
{
return(\$result, @dice_rolls);
}
else
{
return(\$result);
}
}

1;
__END__
# Below is stub documentation for your module. You better edit it!

RPG::Dice - Perl extension for Dice rolling expressions.

use RPG::Dice;
\$dice_roll = computeDice("1d10+1");
\$dice_roll = computeDice("tt3 4d6"); # Stat-Roll (roll 4d6 take top
+3)
-or-
\$dice_roll = RPG::Dice::computeDice("1d10+1");

Dice is a set of subroutines for parsing dice expressions. RPG is
an ongoing library for Role Playing Game systems written in Perl.

=item computeDice("1d2+3");

Function evaluates the expression. for example the expression
"1d2+3" means roll 1 '2 sided die' and add 3 to the result.

Dice Expression Syntax:

[tt#1] #2d#3[+/-#4] [l]

Where:
tt#1 = Take Top Number of rolls for result
#2 = Number of times to roll die face
#3 = Die Face
#4 = Result Modifier
l = List roll results (lower case L)
Returns list with result as first item
and rolls following. If tt is used it
returns all the rolls.

Example Syntax:

"tt3 4d6"  Roll 4 d6 and take top 3 rolls
"5d10-3"   Roll

An internal variable '\$no_ltz_results', if set to false(0) will al
+low
for zero or negative results from expression. This is by default
set to true.

computeDice().

Syrkres syrkres@miniworld.com

perl(1).

=cut

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://87770]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2022-05-17 16:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
Do you prefer to work remotely?

Results (68 votes). Check out past polls.

Notices?