in reply to Re^3: Module Organization
in thread Module Organization

So you think Roleplay::NPC would be sufficient? I'll do a few characters as objects just to get the game going as well as get used to perl objects- i'll move on afterwards.

Replies are listed 'Best First'.
Re^5: Module Organization
by Your Mother (Archbishop) on Oct 13, 2010 at 22:11 UTC

    I definitely think it could be. It's a design decision, of course, and however you prefer to code is the best way at first.

    Here's a what might be a better analogy: file types. You could definitely have a Perl module family for them where you had FileType::Text, FileTypeXML, FileType::Executable::Perl, etc but you'd end up with way too many, obviously, and then you'd also end up stuck trying to accommodate data types that are half-in-half-out of filedom, FileType::ApplicationVnds, FileType::OctectStream...

    When you consider that, MIME::Types is obviously superior and a natural partner for whatever specific datastore (file, scalar, stream, db record) or parser.

    And since you happened to have hit something I'm interested in, here's a prototype to see one way it could be done. I left out Moose roles and traits as they get kinda hairy. This has some idiomatic Perl in it but also a nice terse tour of some really cool nooks.

    # ---------------- path/to/lib/MyRPG.pm package MyRPG; our $VERSION = "0.01"; use MyRPG::Die; use MyRPG::NPC; # ---------------- path/to/lib/MyRPG/Die.pm package MyRPG::Die; use Moose; use Moose::Util::TypeConstraints; has "sides" => is => "ro", isa => enum([qw( 4 6 8 12 20 100 )]), required => 1, ; around BUILDARGS => sub { my $orig = shift; my $class = shift; if ( @_ == 1 && ! ref $_[0] ) { return $class->$orig(sides => $_[0]); } else { return $class->$orig(@_); } }; sub roll { int(rand(+shift->sides))+1; } __PACKAGE__->meta->make_immutable; 1; # ---------------- path/to/lib/MyRPG/NPC.pm package MyRPG::NPC; use Moose; has [qw( name type )] => is => "ro", isa => "Str", required => 1, ; has "hitdice" => is => "rw", isa => "ArrayRef[MyRPG::Die]", required => 1, auto_deref => 1, ; has "hitpoints" => is => "ro", isa => "Int", default => sub { my $hitpoints; $hitpoints += $_->roll for +shift->hitdice; return $hitpoints; }, lazy => 1, ; has "current_hitpoints" => is => "rw", isa => "Int", default => sub { +shift->hitpoints; }, lazy => 1, ; sub damage { # This would be trait/role/type/armor/alignment influence +d! my $self = shift; my $attack = shift; # Should be an object, we'll just call it raw +points. $self->current_hitpoints( $self->current_hitpoints - $attack ); } sub dump { my $self = shift; my $line = "-"x50; sprintf("%s\n%20s -> %s (%dhp)\n current hitpoints: %d (%s)\n%s\n" +, $line, $self->name, $self->type, $self->hitpoints, $self->current_hitpoints, $self->status, $line); } sub status { my $self = shift; $self->current_hitpoints <= 0 ? "dead" : ( $self->current_hitpoints < $self->hitpoints * .3 ) +? "not so hot..." : ( $self->current_hitpoints < $self->hitpoint +s * .8 ) ? "s'okay" : $self->current_hitpoints != $self->hitpoints ? "tip top" : "never better"; } __PACKAGE__->meta->make_immutable; 1; # ------------------- some test code in a regular executable use warnings; use strict; use MyRPG; my $six_sided = MyRPG::Die->new(6); print "Warming up the bones... test roll $_: ", $six_sided->roll, $/ f +or 1 .. 3; my $npc = MyRPG::NPC->new( name => "CmdrTaco", type => "SwampYankee", hitdice => [ ( $six_sided ) x 3 ] ); print $npc->dump; my $dodecahedron = MyRPG::Die->new(12); print "Take that, ", $npc->name, $/; $npc->damage( $dodecahedron->roll ); print $npc->dump;

    Sample output-

    Warming up the bones... test roll 1: 5 Warming up the bones... test roll 2: 2 Warming up the bones... test roll 3: 4 -------------------------------------------------- CmdrTaco -> SwampYankee (16hp) current hitpoints: 16 (never better) -------------------------------------------------- Take that, CmdrTaco -------------------------------------------------- CmdrTaco -> SwampYankee (16hp) current hitpoints: 6 (s'okay) --------------------------------------------------

    I'm kinda glad I am out of time today. This probably would have eaten up a few hours. :) As it is, that took me almost exactly 30 minutes to put together (I have an RPG background though, obviously). Viva la Perl!

      Haha! Thats awesome! Thanks for showing it to me! I'm going to have to use that as an example for my code! +rep :D
      The only problems that I have with reading that code are the +symbol, example: +? and I have no idea how to use has

      has [qw( name type )] => is => "ro", isa => "Str", required => 1, ;
      As I've never seen it anywhere... You mentioned that moose got hairy however I am told by others in this thread I should use it for my objects...also, is there a list of available terms anywhere for "is" and "isa" ?

        If I had time I'd write up a full description and some comparisons of the techniques and idioms. I don't. :( The good news is the Moose docs are pretty darn good. Start on the main Moose page and then walk through as many of the Moose::Cookbook entries as you can.

        The + in the +shift->$method statements is probably too idiomatic to ask you to discover on your own.

        my $thing = shift; # ...is equivalent to... my $thing = shift(@_); # ...which is, except for altering @_, functionally equivalent to... my ( $thing ) = @_; # ...or... my $thing = $_[0]; # Perl really is your friend though! # shift without parens can become ambiguous to the interpreter, # not just the next developer! in some cases like... my $lookup = $hash{shift}; # not going to shift(@_) # the unary plus forces shift to be interpreted as the function- my $lookup = $hash{+shift}; # Quick proof- perl -le '%a = (1 => 2, shift => 4); print $a{shift}' 1 4 perl -le '%a = (1 => 2, shift => 4); print $a{+shift}' 1 2 # I think in the cases in the prototype code I showed you # The "+" is not necessary. I use it habitually to visually # disambiguate shift's usage as a function. # This all means that sub o_hai { my $self = shift(@_); return $self->get_some_val(); } # ...is the same as... sub o_hai { +shift->get_some_val; }

        Just so you know, many hackers here will tell you that this is suboptimal terrible style. They'd have a case. I find idiomatic Perl easier to read because it's more terse but it is also more confusing to those who don't know Perl idioms. So...

        Moose gets conceptually hairy; ask someone to explain the finer points of traits versus roles and the dangers of multiple inheritance to get a feel for that. Moose itself is a joy and, I argue, the clearest path through this problem space and I highly recommend it.