Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines
(+2)

On version 0.2.1, if the first upgradable SKill or Equipment of a specific kind (id) is at Max level, and a second one is not at Max level, when the player gains an item of that specific kind, the second one is not upgraded and the notification section show a "[item_name] is already Max Level!" message.

The main cause of this behavior is some outdated code in the gain_item Function.

The legacy code from version 0.1.X only takes into account the first upgradable item of a specific kind in the inventory, since the dungeon was the only way for the player to obtain an instance of a specific item.

But since version 0.2.X, with the introduction of a "Home Inventory", the player can now move to/from the "Player Inventry" any item from previous explorations or purchases. Because of this, its possible for the player to have multiple instances of the same kind of upgradable item in the player's inventory before exploring the Dungeon, what needs to be taken into account for the "gain_item" Function in version 0.2.X.

 

A quick fix to allow upgrading any instance of the gained item in inventory is to reuse part of the logic for stackable items, upgrading a matching item on inventory instead of stacking it (if not Max level), and preventing the addition of a new item if there was at least one on the inventory (meaning that all instances of that item are already Max Level).

Additionally, to reuse the "upgradable_item" logic for Skills and Equipment, the different sections of the gain_item Function can be rearanged to new "private" Functions to do each separate logic to handle different item types. This makes easy to implement a way of setting a custom "starting level" for Skills and Equipment, and "starting uses" for Potions and Food.

[code]

  File "game/init.rpy", lines 1448-1618, at gain_item in the "# INVENTORY MANAGEMENT #" python block:

init -1 python: # INVENTORY MANAGEMENT #

    def gain_item(item_id, amount=None): # Added amount parameter, defaults defined by handlers

        if item_id not in item_definitions:

            renpy.log(f"Error: Tried to gain unknown item '{item_id}'")

            return

        

        item_data = item_definitions[item_id]

        item_type = item_data.get("type", "unknown")

        stack_limit = item_data.get("stack_limit") # Get stack limit if defined

        

        # --- NEW: Handle Unique Items (check for duplicates) ---

        if item_type == "unique":

            if not _gain_unique_item(item_id):

                return # Stop the function here to prevent adding the duplicate.

        

        # --- NEW: Handle Artifacts ---

        if item_type == "artifact":

            _gain_artifact_item(item_id)

            return # Artifacts are not added to persistent.player_inventory, so we notify and return.

        

        # --- Handle Stackable Items (like Gold Coins) ---

        if stack_limit is not None:

            if amount is None: _gain_stackable_item(item_id)

            else: _gain_stackable_item(item_id, amount)

        

        # --- Handle Skills (logic: upgrade and reset cooldown if exists, else add new if space) ---

        elif item_type == "skill":

            if amount is None: _gain_upgradeable_item(item_id, _reset_cooldown=True)

            else: _gain_upgradeable_item(item_id, amount, _reset_cooldown=True)

        

        # --- Handle Equipment (logic: upgrade if exists and is upgradeable, else add new if space) ---

        elif item_type == "equipment":

            if amount is None: _gain_upgradeable_item(item_id, _allow_duplicates=True)

            else: _gain_upgradeable_item(item_id, amount, _allow_duplicates=True)

        

        # --- NEW: Handle Potions and Food Items (logic: limited uses) ---

        elif item_type in ["potion", "food"]:

            if amount is None: _gain_consumable_item(item_id)

            else: _gain_consumable_item(item_id, amount)

        

        # --- Handle Non-Stackable, Non-Upgradeable Items (Uniques) ---

        # --- Handle Non-Stackable, Non-Upgradeable Items (Potions, Food, Uniques) ---

        else:

            _gain_other_item(item_id)

...

(1 edit) (+1)

    def _gain_unique_item(item_id):

        # --- NEW: Handle Unique Items (check for duplicates) ---

        if item_id in persistent.unique_items_acquired:

            # Player already has this unique item. Give a consolation prize instead.

            renpy.notify(f"Duplicate Unique Item! Converted to 100 Gold Coins.")

            gain_item("gold_coins", 100)

            return False # Dont add the duplicate item.

        else:

            # This is a new unique item. Add it to the master list.

            persistent.unique_items_acquired.add(item_id)

            return True # Add the first unique item.

 

    def _gain_artifact_item(item_id):

        # --- NEW: Handle Artifacts Separately ---

        if not hasattr(persistent, 'artifacts_collected'):

            persistent.artifacts_collected = set()

        persistent.artifacts_collected.add(item_id)

        # Artifacts are not added to persistent.player_inventory, so we notify and return.

        renpy.notify(f"Artifact Acquired: {item_definitions[item_id].get('name', item_id)}!")

 

    def _gain_stackable_item(item_id, amount=1):

        # --- Handle Stackable Items (like Gold Coins) ---

        current_max_capacity = inventory_capacity + getattr(persistent, 'inventory_capacity_bonus', 0) + getattr(store, 'temporary_inventory_bonus', 0) # Include temporary bonus

        item_data = item_definitions[item_id]

        item_name = item_data.get("name", item_id)

        stack_limit = item_data.get("stack_limit") # Stack limit for the item

        

        amount_to_add = max(amount, 1) # Start with the full amount requested (min 1)

        

        # 1. Try to add to existing, non-full stacks

        for item_dict in persistent.player_inventory:

            if not item_dict.get("id") == item_id:

                continue # Skip other items

            current_quantity = item_dict.get("quantity", 0)

            can_add_to_stack = stack_limit - current_quantity

            if not can_add_to_stack > 0:

                continue # Item is already max quantity

            add_now = min(amount_to_add, can_add_to_stack)

            item_dict["quantity"] = current_quantity + add_now

            amount_to_add -= add_now

            message_text = f"Added {add_now} {item_name} (Total: {item_dict['quantity']})."

            store._turn_notification_counter += 1 # Increment counter regardless of context

            add_chat_notification(message_text, store._turn_notification_counter)

            if not renpy.get_screen("chat_notify_display"): # Ensure chat display is shown

                renpy.show_screen("chat_notify_display")

            if amount_to_add <= 0: break # Added everything

        

        # 2. If amount still remains, try adding new stacks

        while amount_to_add > 0:

            if len(persistent.player_inventory) < current_max_capacity:

                add_this_stack = min(amount_to_add, stack_limit)

                persistent.player_inventory.append({"id": item_id, "quantity": add_this_stack})

                amount_to_add -= add_this_stack

                message_text = f"Added new stack of {add_this_stack} {item_name}."

                store._turn_notification_counter += 1

                add_chat_notification(message_text, store._turn_notification_counter)

                if not renpy.get_screen("chat_notify_display"):

                    renpy.show_screen("chat_notify_display")

            else:

                message_text = "Inventory Full!"

                store._turn_notification_counter += 1

                add_chat_notification(message_text, store._turn_notification_counter)

                if not renpy.get_screen("chat_notify_display"):

                    renpy.show_screen("chat_notify_display")

                break # Stop trying to add new stacks

 

    def _gain_upgradeable_item(item_id, level=1, _reset_cooldown=False, _allow_duplicates=False):

        # --- Handle Upgradeable Items (Equipment/Skill logic: upgrade if exists, else add new if space) ---

        global current_skill_cooldowns

        current_max_capacity = inventory_capacity + getattr(persistent, 'inventory_capacity_bonus', 0) + getattr(store, 'temporary_inventory_bonus', 0) # Include temporary bonus

        item_data = item_definitions[item_id]

        item_name = item_data.get("name", item_id)

        max_level = item_data.get("max_level", 1) # Max level for the item

        #is_upgradeable = item_data.get("upgradeable", False) # LEGACY

        is_upgradeable = max_level > 1

        

        if is_upgradeable or not _allow_duplicates: # Only skip non-upgradeable duplicable items (Equipment)

            found_existing = False # Found existing item

            for found_existing_index, existing_item_dict in enumerate(persistent.player_inventory):

                if not existing_item_dict.get("id") == item_id:

                    continue # Skip other items

                # Item already exists

                found_existing = True

                current_level = existing_item_dict.get("level", 1)

                # max_level is already defined from item_data

                if not current_level < max_level:

                    continue # Item is already max level

                new_level = max(level, 1)

                new_level = min(current_level + new_level, max_level)

                existing_item_dict["level"] = new_level

                message_text = f"Upgraded {item_name} to Level {new_level}!"

                store._turn_notification_counter += 1

                add_chat_notification(message_text, store._turn_notification_counter)

                if not renpy.get_screen("chat_notify_display"): # Ensure chat display is shown

                    renpy.show_screen("chat_notify_display")

                if not _reset_cooldown:

                    continue # No cooldown reset

                if item_id in current_skill_cooldowns: # Reset cooldown on upgrade

                    del current_skill_cooldowns[item_id]

                    if store.in_dungeon: renpy.restart_interaction()

                return # Stop the function here to prevent the "already Max Level!" notification.

            

            if found_existing: # All items are already max level

                message_text = f"{item_name} is already Max Level!"

                store._turn_notification_counter += 1

                add_chat_notification(message_text, store._turn_notification_counter)

                if not renpy.get_screen("chat_notify_display"): renpy.show_screen("chat_notify_display")

                return # Stop the function here to prevent adding the item.

        

        if len(persistent.player_inventory) < current_max_capacity: # Item doesn't exist or its non-upgradeable and duplicable, add new if space

            new_level = max(level, 1)

            new_level = min(new_level, max_level)

            persistent.player_inventory.append({"id": item_id, "level": new_level}) # Always add new items at level 1 (default if not given)

            if is_upgradeable: # Only show starting level for upgradeable items

                message_text = f"Obtained: {item_name} (Level {new_level})!"

            else:

                message_text = f"Obtained: {item_name}!"

            store._turn_notification_counter += 1

            add_chat_notification(message_text, store._turn_notification_counter)

            if not renpy.get_screen("chat_notify_display"):

                renpy.show_screen("chat_notify_display")

        

        else: # No space for new item

            message_text = "Inventory Full!"

            store._turn_notification_counter += 1

            add_chat_notification(message_text, store._turn_notification_counter)

            if not renpy.get_screen("chat_notify_display"):

                renpy.show_screen("chat_notify_display")

 

    def _gain_consumable_item(item_id, uses=0):

        # --- NEW: Handle Consumable Items (Potions/Food logic: limited uses) ---

        current_max_capacity = inventory_capacity + getattr(persistent, 'inventory_capacity_bonus', 0) + getattr(store, 'temporary_inventory_bonus', 0) # Include temporary bonus

        item_data = item_definitions[item_id]

        item_name = item_data.get("name", item_id)

        max_uses = item_data.get("uses", 1) # Max amount of uses for the item

        

        if len(persistent.player_inventory) < current_max_capacity: # Add new if space

            new_item_dict = {"id": item_id, "level": 1} # Base item dict

            remaining_uses = max_uses

            if not uses == 0:

                starting_uses = min(uses, max_uses - 1) if uses > 0 else max(max_uses + uses, 0) # Uses done from 0 to max-1, or, Uses remaining from max-abs(uses) to 0

                if not starting_uses == 0: # Only set if not default 0

                    new_item_dict["uses"] = starting_uses # Initialize with an amount of uses done

                remaining_uses -= starting_uses

            persistent.player_inventory.append(new_item_dict)

            

            if not max_uses == 1:

                message_text = f"Obtained: {item_name} ({remaining_uses} Uses)!" if remaining_uses > 1 else f"Obtained: {item_name} ({remaining_uses} Use)!"

            else:

                message_text = f"Obtained: {item_name}!"

            store._turn_notification_counter += 1

            add_chat_notification(message_text, store._turn_notification_counter)

            if not renpy.get_screen("chat_notify_display"):

                renpy.show_screen("chat_notify_display")

        

        else: # No space for new item

            message_text = "Inventory Full!"

            store._turn_notification_counter += 1

            add_chat_notification(message_text, store._turn_notification_counter)

            if not renpy.get_screen("chat_notify_display"):

                renpy.show_screen("chat_notify_display")

 

    def _gain_other_item(item_id):

        # --- Handle Non-Stackable, Non-Upgradeable Items ---

        current_max_capacity = inventory_capacity + getattr(persistent, 'inventory_capacity_bonus', 0) + getattr(store, 'temporary_inventory_bonus', 0) # Include temporary bonus

        item_data = item_definitions[item_id]

        item_name = item_data.get("name", item_id)

        

        if len(persistent.player_inventory) < current_max_capacity: # Add new if space

            # MODIFICATION START: Data-driven stack initialization

            new_item_dict = {"id": item_id, "level": 1} # Base item dict

            if item_data.get("has_stacks", False):

                new_item_dict["stacks"] = 0 # Initialize with 0 stacks if defined

            persistent.player_inventory.append(new_item_dict)

            # MODIFICATION END

            

            message_text = f"Obtained: {item_name}!"

            store._turn_notification_counter += 1

            add_chat_notification(message_text, store._turn_notification_counter)

            if not renpy.get_screen("chat_notify_display"):

                renpy.show_screen("chat_notify_display")

        

        else: # No space for new item

            message_text = "Inventory Full!"

            store._turn_notification_counter += 1

            add_chat_notification(message_text, store._turn_notification_counter)

            if not renpy.get_screen("chat_notify_display"):

                renpy.show_screen("chat_notify_display")

 

    def use_item(item_id, index_in_list):

[/code]

;)