Home

Friday, December 24, 2021

Python: Text RPG - Entry 2.1 - Inventory

Python Text RPG

-Inventory-

 

In today's sprint I was changing gears to let some ideas ruminate about the Maps and organization problem. So I started tackling items and an inventory system. You can see the use example at the bottom of the article.

Sprint method: For my sprints I set a block of time to work and when it expires that's what I have for the day.

_______________________________________________________________

 

class Item():

    # class variable:
    gentype = "consumable"
    subtype = "potion"
    variant_type = "elixir"
    name_ = "elixir of healing"
    desc = "restores () health over () seconds"
    value = 5 #recomended value; value assigned per shop
    stack_size = 1
    quantity = 1
    weight_class = 0#, 1, 2, 3, 4 # none, light, medium, heavy, very heavy
    visable = True

    def __init__( self, name:str, qty:int, stack:int=1, **keywargs ):
        # instance variable:
        # Info
        self.gentype = "general category".lower()
        self.subtype = "local category".lower()
        self.variant_type = "specific category".lower()
        self.name_ = str( name ).lower()
        self.description = "does things".lower()
        # Inventory
        self.stack_size = stack
        self.quantity = qty if qty <= stack else stack
        self.weight_class = 0#, 1, 2, 3, 4 # none, light, medium, heavy, very heavy
        # Shop
        self.value = 5 #recomended value; value assigned per shop
        self.visable = True
    

    def __str__( self ):
        return f"{ self.name().title() }: { self.qty()[0] }/{ self.stack() }"

    def __repr__( self ):
        return f"{ self.name() }: { self.qty()[0] }/{ self.stack() }"
    
    # Public facing calls to set and get object string variables.
    def gen_type( self, new_gentype:str=None ) -> str:
        return self._set_string( "gentype", new_gentype )
    def sub_type( self, new_subtype:str=None ) -> str:
        return self._set_string( "subtype", new_subtype )
    def type( self, new_type:str=None ) -> str:
        return self._set_string( "variant_type", new_type )
    def name( self, new_name:str=None ) -> str:
        return self._set_string( "name_", new_name )
    def desc( self, new_desc:str=None ) -> str:
        return self._set_string( "description", new_desc )
    
    # The utility function for setting string variables
    def _set_string( self, attr, string ):
        if string:
            setattr(self, attr, str( string ).lower() )
        return getattr( self, attr )
    

    # Public facing calls to set and get object boolean variables.
    def show( self, new_state=None ):
        return self._toggle_bool( "visable", new_state )
    
    # The utility function for setting boolean variables
    def _toggle_bool( self, attr, state ):
        if None != state:
            setattr( self, attr, state )
        return getattr( self, attr )
    

    # Public facing calls to set and get object numeric variables.
    def price( self, new_price:int=None ) -> int:
        return self._set_digit( "value", new_price )
    def weight( self, new_weight:int=None ) -> int:
        return self._set_digit( "weight_class", new_weight )
    def stack( self, new_stack:int=None ) -> int:
        return self._set_digit( "stack_size", new_stack )
    def qty( self, new_qty:int=None ) -> ( int, int ):
        remainder = 0
        if not new_qty: pass
        elif 1 < ( new_qty / self.stack() ):
            remainder = new_qty - self.stack()
            new_qty = self.stack()
        return self._set_digit( "quantity", new_qty ), remainder
    
    # The utility function for setting numeric variables
    def _set_digit( self, attr:str, number:int ) -> int:
        if str( number ).isdigit():
            setattr( self, attr, number )
        return getattr( self, attr )

    # Get the current capacity for the item stack
    def capacity( self ) -> int:
        out = self.stack_size - self.quantity
        return out if out <= self.stack_size else 0

_______________________________________________________________


class Container():

    items = []
    size = 3
    # width x height ala diablo

    def __init__( self, size:int ):
        self.items = []
        self.size = size

    def item( self, item:Item=None ) -> Item or [ Item ]:
        """Takes in an item; If successful returns added item. If failed returns held items."""
        out = self.items
        if item:
            self._add_item( item )
            out = item
        return out

    def remove_item( self, item:Item ) -> bool:
        out = False
        if 1 not in self._validate_insert( item ):
            self.items.pop( self.items.index( item ) )
            out = True
        return out

    def _full( self ) -> int:
        return self.size - len( self.items )

    def _contains_obj( self, item:Item ) -> bool:
        return item in self.items
    
    def _contains_name( self, item:Item ) -> bool:
        return item.name() in ''.join( str( self.items ) )
    
    def _validate_insert( self, item:Item ) -> { int, str }:
        """returns a dictionary of { outcome_code : note, } "0, and -4 to -6" are invalid insertions. -2 to -3 denote the insertion is a duplicate. Return value of 1 indicates item is not present."""
        out = { }
        if not item:
            out.update( { 0 : "empty argument" } )
        if Item is not type(item):
            out.update( { -6 : "not an item" } )
        if 0 >= self._full():
            out.update( { -5 : "inventory full" } )
        if 0 >= item.stack():
            out.update( { -4 : "empty item stack" } )
        if self._contains_obj( item ):
            out.update( { -3 : "item duplicate" } )
        if self._contains_name( item ):
            out.update( { -2 : "name duplicate" } )
        else:
            out.update( { 1 : 'valid insert' } )
        return out

    def _add_item( self, item:Item ) -> bool:
        out = False
        if 1 == list( self._validate_insert( item ) )[0]:
            self.items.append( item )
            out = True
        return out

    def _item_to_index( self, item:Item ) -> [ int ] or None:
        out = None
        catch = self._validate_insert( item )
        if -3 in catch:
            # Index of objects matches
            out = self.items.index( i )
        if -2 in catch:
            # Index of Items with name matches
            out = [self.items.index( i ) for i in self.items if item.name() == i.name() ]
        return out
    
    def _index_to_item( self, index:int) -> Item:
        return self.items[ index ]

    def _qty( self, item:Item, new_qty:int=None ) -> Item:   
        out = item
        catch = self._validate_insert( item )
        if -2 in catch:
            # Case: item name exists in list
            index = self._item_to_index( item )[0]
            held_item = self._index_to_item(index)

            # add the current qty to the new qty and return the remainder
            updated_stock = held_item.qty( held_item.qty()[0] + item.qty()[0] )[1]
            catch = item.qty( updated_stock )
            out = item
        return out

_______________________________________________________________

 

# USE EXAMPLE:

# Change the bag size to exclude items below
inv = Container( 6 )
# Try it yourself: Item( name, qty, stack_size )
# 'Pickup' various items until inventory is full

inv.item( Item( "health potion", 1 ) ) # 1
inv.item( Item( "raw steak flank", 1 ) ) # 2
inv.item( Item( "rusty sword", 1 ) ) # 3
inv.item( Item( "mirror shield", 1 ) ) # 4
inv.item( Item( "iron greaves", 1 ) ) # 5
ps = Item( "platinum sword", 1, 4 ) #6
inv.item( ps )
#---- Inventory at capacity
inv.item( Item( "obsidian helm", 1 ) ) #7
inv.item( Item( "golden armor", 1 ) ) #8
print( inv.item( ) )
print()

# Use Scenario: top off an item you already have from one in a locker
world_item = Item( "platinum sword", 4, 4 ) # Item in the locker
# world_item = inv._qty( world_item ) # finding similar item in inventory and stacking to full

print( inv._qty( world_item ) ) # show new qty for locker item
print( inv.item( ) )

 

-END-

No comments:

Post a Comment

Conduct: Be nice and don't advertise or plug without adding value to the conversation.