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

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

I am creating a fairly simple text-based MUD alike hack'n'slash game, that knows about three entity types: Player (the one who plays), Items (things like weapons and armor and magical items and such) and Foes (the ones you have to fight).

Well, Foe and Item are two very similar packages but they behave different on certain points (d'uh, an item is not supposed to walk around and fight you, while a foe is).

Now here's the problem: when the player kills a foe called "a male elf soldier", it should turn into an item called "the corps of a male elf soldier".
Therefor, I need to change the parent of this particular instance of Foe to Item.
I have tried to change its @ISA but that has two more problems:
- first, I failed.
- second, this is not the thing I want, actually, since the Item module has some methods with names that equal method names on the Foe module, but with different code in it.

So I really want to change the parent of the instance itself.

It might be useful to know that all three entity types (Player, Foe and Item) have a common parent called MotherOfAll, altough I don't know why. Consider this a FYI.

Replies are listed 'Best First'.
Re: Change the parent of an instance
by chromatic (Archbishop) on May 11, 2004 at 18:26 UTC
    Now here's the problem: when the player kills a foe called "a male elf soldier", it should turn into an item called "the corps of a male elf soldier". Therefor, I need to change the parent of this particular instance of Foe to Item.

    Perhaps you'd find it easier to create a new Item, copying over the appropriate data from the Foe. That's what I'd do anyway.

      Hmm... that tought has passed my mind in one way or another but I just didn't see the way how to do it. Now you've stated it like a simple thing, I indeed see how simple it is. I'll condsider it.
Re: Change the parent of an instance
by perrin (Chancellor) on May 11, 2004 at 18:29 UTC
    Whoa, bad idea. You should re-think your model so that you are changing properties, not identity, and make your code handle multiple types of objects that implement the same interface (polymorphism). For example, add a "is_carryable" method to all of your classes, with an implementation for the Foe class like this:

    sub is_carryable { my $self = shift; if ( $self->is_alive() ) { # can't carry a live orc! return 0; } else { # dead body return 1; } }
      Might be a good idea, altough in this case many of the methods will be in an if-else manner, just because the two things share a lot although they hardly share anything.

      I know it might look like I'm rejecting all advises, I'm aware of that, but the 'multimorphing' idea as it seems to be called is not very usable I think.
        What I'm suggesting is that you are thinking about it at the wrong level. What's important to your program might not be whether or not the object is a foe but rather whether or not it is carryable. Each kind of object may have unique rules about when it is carryable. In general, the idea is to push as much of the decision-making about how an object will behave in a certain situation into the object itself (by asking it with methods like this) rather than have some other code that decides what the object can do based on what type it is.
•Re: Change the parent of an instance
by merlyn (Sage) on May 11, 2004 at 18:27 UTC
    Well, you could do this by re-blessing, but that'll suck. Instead, you should have a member variable that handles certain behaviors as a pluggable value, and then replace that member variable as the role of the object changes.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      What's wrong with reblessing then? The variable keeping track of the actual type might be a good idea, but many of the methods will then look like
      if ($somehow_is_a_foe) { } else { }
      because the two share a lot, although they hardly share anything.

      Update: I have not yet thought about re-blessing. I think it's a good idea, worthwhile trying but if you say it's bad (or at least, will suck) I'll be glad to know why, just to find out if re-blessing is what I want.
        No, I mean you plug it like this:
        package Elf; sub named { my $class = shift; bless { Name => shift; Actions => Elf::Live::, Has => {}, }, $class; } sub die { shift->{Actions} = Elf::Dead::; } sub can_attack { # delegate to actions shift->{Actions}->can_attack(@_); } sub enemy_of { shift->{Actions}->enemy_of(@_); } package Elf::Live; sub can_attack { ... } sub enemy_of { ... } package Elf::Dead; sub can_attack { ... } sub enemy_of { ... }
        A simple change of the Actions variable by plugging in a different "behavior container" causes a bank-switch of those behaviors to a new motif. I forget the "gang of four" pattern for this, but it's one of those. {grin}

        -- Randal L. Schwartz, Perl hacker
        Be sure to read my standard disclaimer if this is a reply.