kipyin / pokemaster

Checkout kipyin/pokemaster2 !
https://github.com/kipyin/pokemaster2
2 stars 2 forks source link

Implementing items #4

Open kipyin opened 5 years ago

kipyin commented 5 years ago

Here is a scratch of how implementing items using classes should look like:

@attr.s
class Item:
    """An Item in the Pokémon world."""

    cost: int = attr.ib(init=False)
    sell_price: int = attr.ib(init=False)
    pocket: str = attr.ib(init=False)

@attr.s(slots=True)
class _Medicine(Item):

    cost: int = attr.ib(init=False)
    sell_price: int = attr.ib(init=False)
    pocket: str = attr.ib(init=False)
    recover: int = attr.ib(init=False)

    def battle_effect(self, target):
        target.current_hp = min(target.permanent_stats.hp, self.recover)

    def field_effect(self, target):
        self.battle_effect(target)

@attr.s
class Potion(_Medicine):

    def __attrs_post_init__(self):
        self.cost = 300
        self.sell_price = self.cost // 2
        self.pocket = 'items'
        self.recover = 20

@attr.s
class SuperPotion(_Medicine):

    def __attrs_post_init__(self):
        self.cost = 700
        self.sell_price = self.cost // 2
        self.pocket = 'items'
        self.recover = 50

Now, we should be able to do the following:

>>> from pokemaster.pokemon import Pokemon
>>> from pokemaster.item import SuperPotion
>>> super_potion = SuperPotion()
>>> p = Pokemon(national_id=1, level=100)
>>> print(f'The original HP: {p.current_hp}')
The original HP: 216
>>> p.current_hp = 0
>>> print(f'The HP should be 0: {p.current_hp}')
The HP should be 0: 0
>>> super_potion.battle_effect(p)
>>> print(f'HP after recovered by {super_potion}: {p.current_hp}')
HP after recovered by SuperPotion(cost=700, sell_price=350, pocket='items', recover=50): 50

Is this a good enough solution to carry on?

kipyin commented 5 years ago

Use class variables instead:

@attr.s(slots=True, auto_attribs=True)
class Potion(_Medicine):
    COST: ClassVar[int] = 300
    SELL_PRICE: ClassVar[int] = 150
    RECOVER: ClassVar[int] = 20

    @classmethod
    def field_effect(cls, target):
        target.current_hp += min(cls.RECOVER, target.permanent_stats.hp - target.current_hp)
kipyin commented 5 years ago

float('inf')

For items like Full Restore or Max Potion, we can use float('inf') to represent the recover amount:

@attr.s
class MaxPotion(_Medicine):
    COST: ClassVar[int] = 2500
    SELL_PRICE: ClassVar[int] = 1250
    RECOVER: ClassVar[float] = float('inf')

This way we don't have to override the class methods _Medicine.field_effect().

Add a complementary database/data file to hold all the parameters?

Hand-writing all the class declarations is extremely repetitive (you have to write ClassVar[int] for all class variables). Although if those are class methods and we don't have any attributes, what stops us from doing COST = 200 instead? We don't have to set auto_attribs=True at all! This simplifies a class to:

@attr.s
class HyperPotion(_Medicine):
    COST = 1200
    SELL_PRICE = 600
    RECOVER = 200

(Maybe we can even drop @attr.s if we don't need comparison, hashing, slots, etc.?)

Instances of an Item class

If all methods and attributes are class-level, what is the difference between a Hyper Potion A and another Hyper Potion B? Apparently, hyper_potion_A is not hyper_potion_B, but should hyper_potion_A == hyper_potion_B?

If we want to use items as keys in dictionaries (e.g. to represent the content of a bag), items should be hashable. What is the meaning of {hyper_potion: 5}? Here hyper_potion is an item, and yet it is used to represent 5 different items. Oxymoron? In this case, here is an absolutely correct but totally unnecessary way to represent a bag: [HyperPotion() for _ in range(10)]. This would have 5 distinct Hyper Potions in the bag, meaningfully.

kipyin commented 5 years ago

This won't be included in release v0.1. Maybe v0.2. Maybe.

kipyin commented 5 years ago

Yes, the effect must be hard-coded. No, the data (recovery, cost, etc.) must not be hard-coded.

kipyin commented 5 years ago

All item has an effect column, which contains the descriptions on the item effect. Is it possible to use regex (or even NLP) to realize the effects?

kipyin commented 5 years ago

It works for medicines, since their descriptions are easy to understand. How about other items?

Take the item IronBall for example:

Held: Holder's Speed is halved. Negates all Ground-type immunities, and makes Flying-types take neutral damage from Ground-type moves. Arena Trap. Spikes, and Toxic Spikes affect the holder.

How do we even remotely regex/NLP this effect?