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

Hello fellow monks, I am a perl game programmer and would like to ask 2 questions : Can I templatize (C++) for a non player character which has a race.pm and class.pm without using e.g.
our @ISA = ("Race", "Class");
Using this I would like to use both classes to make :
package HollyGame::Entity; out @ISA = ("Race", "Class"); sub new { my ($class) = @_; $self = { ### positions and stuff }; bless $self, ref($class) || $class; };
Then do
package HollyGame::ElfRanger; out @ISA = ("Elf", "Ranger"); sub new { my ($class) = @_; $self = { ### more or less stuff }; };
Is there TMTOWTDI ? The second question is, can I use a parameter name in a $self hash of a module with a way to its change name ?
package Mod::Module; sub new { my $class = shift; $self = { tobechangedname => "value", } ### to change the tobechan +gedname at compile and runtime bless $self, ref($class) || $class; }
Thanks for any help.

Replies are listed 'Best First'.
Re: without CPAN, templates and random named module class members
by Corion (Patriarch) on Nov 11, 2017 at 10:52 UTC

    I'm sorry but I don't understand what you are asking, in both questions.

    I think in your first question, you want to compose a class from two other base classes, but I don't understand what part should be abstract ("Race", "Class") and what part should be concrete ("Elf", "Ranger"), or where your problem is.

    My approach for the first topic would be to keep the race and class of a character as separate objects in the player character. Maybe some transmutation changes the race of a character. Also, the boni/mali usually conferred by race and class are quite similar, so I think it would be more beneficial to keep them the same and have them add/subtract from the player base stats.

    sub HollyGame::ElfRanger::new { my( $class, %options ) = @_; $options{ class } = HollyGame::Ranger->new(...); $options{ race } = HollyGame::Elf->new(...); bless \%options => $class; }

    If you want to make even that more generic, you can maybe glean the race+class from the classname:

    sub HollyGame::RaceClassBase::new { my( $class, %options ) = @_; my( $race, $class ) = ($class =~ /::([A-Z][a-z]+)([A-Z][a-z]+)/); $options{ class } = "HollyGame::$class"->new(...); $options{ race } = "HollyGame::$race"->new(...); bless \%options => $class; } package HollyGame::ElfRanger; use base 'HollyGame::RaceClassBase'; ... HollyGame::ElfRanger->new();

    For your second question, an "object" is just a hash, so you can of course change the key in it:

    sub new { my( $class, %options) = @_; # rename from "tobechangedname" to "newname" my $optval = delete $options{ tobechangedname }; $options{ newname } = $optval; bless \%options => $class; }
Re: without CPAN, templates and random named module class members
by choroba (Cardinal) on Nov 11, 2017 at 11:17 UTC
    byterock had a series on an DnD-like game in Perl on blogs.perl.org. Maybe reading the articles and comments can give you some inspiration?

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: without CPAN, templates and random named module class members
by 1nickt (Canon) on Nov 11, 2017 at 14:08 UTC

    Hi, writing OO code by hand is a pain the arse and consumes valuable time that should be spent developing your game scenarios :-) Use a Modern Perl OO framework instead. Working "without CPAN" is for masochists.

    Here is a small demonstration using Moo based on what I could glean from your OP. I hope it's useful.

    use 5.026; use warnings; use Data::Dumper; { package Entity; use Moo; use Types::Standard qw/ InstanceOf Int /; has race => ( is => 'ro', isa => InstanceOf['Race'], require +d => 1 ); has class => ( is => 'ro', isa => InstanceOf['Class'], require +d => 1 ); has game_rank => ( is => 'rw', isa => Int, default => sub{ 0 } ); sub increase_rank { $_[0]->game_rank( $_[0]->game_rank + $_[1] ) } sub decrease_rank { $_[0]->game_rank( $_[0]->game_rank - $_[1] ) } 1; } { package Race; use Moo; use Types::Standard qw/ Str /; has name => ( is => 'ro', isa => Str, required => 1 ); has realm => ( is => 'ro', isa => Str, default => sub {'Middle Ear +th'} ); 1; } { package Class; use Moo; use Types::Standard qw/ Str /; has name => ( is => 'ro', isa => Str, required => 1 ); has is_noble => ( is => 'lazy', builder => sub { $_[0]->name eq 'h +igh' } ); 1; } { package Elf; use Moo::Role; use Types::Standard qw/ Enum Str /; has name => ( is => 'ro', isa => Str, required => 1 ); has sex => ( is => 'ro', isa => Enum[qw/ m f /], required => 1 ); 1; } { package Ranger; use Moo::Role; use Types::Standard qw/ Str /; has ranger_rank => ( is => 'ro', isa => Str, default => sub { 'Pri +vate' } ); 1; } { package RangerElf; use Moo; use Types::Standard qw/ Str /; extends 'Entity'; with 'Elf', 'Ranger'; around BUILDARGS => sub { my ( $orig, $class, %args ) = @_; $args{'class'} = Class->new( name => $args{'class'} ); $args{'race'} = Race->new( name => 'Elf', realm => 'Gondor' ) +; return $class->$orig( %args ); }; has sword_name => ( is => 'rw', isa => Str ); 1; } ##################################################### my $ranger = RangerElf->new( name => 'Fingolfin', sex => 'm', class => 'high', ranger_rank => 'Captain', ); say sprintf '%s\'s game ranking is now: %s', $ranger->name, $ranger->game_rank; if ( $ranger->race->name eq 'Elf' ) { say sprintf 'As an Elf, %s gets a special sword.', $ranger->name; $ranger->sword_name('Ringil'); } if ( $ranger->class->name eq 'high' and $ranger->sword_name ) { say sprintf '%s\'s game ranking is now: %s', $ranger->name, $ranger->increase_rank(10); } say sprintf '%s %s a member of the nobility.', $ranger->name, $ranger->class->is_noble ? 'is' : 'is not'; say '-' x 32; say 'Obj dump: ' . Dumper $ranger; __END__
    Outputs:
    $ perl 1203175.pl Fingolfin's game ranking is now: 0 As an Elf, Fingolfin gets a special sword. Fingolfin's game ranking is now: 10 Fingolfin is a member of the nobility. -------------------------------- Obj dump: $VAR1 = bless( { 'class' => bless( { 'is_noble' => 1, 'name' => 'high' }, 'Class' ), 'game_rank' => 10, 'name' => 'Fingolfin', 'race' => bless( { 'name' => 'Elf', 'realm' => 'Gondor' }, 'Race' ), 'ranger_rank' => 'Captain', 'sex' => 'm', 'sword_name' => 'Ringil' }, 'RangerElf' );


    The way forward always starts with a minimal test.
Re: without CPAN, templates and random named module class members
by jahero (Pilgrim) on Nov 12, 2017 at 06:01 UTC
Re: without CPAN, templates and random named module class members
by Anonymous Monk on Nov 11, 2017 at 10:56 UTC