Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

On version 0.2.1, all actions centered on spending "Gold Coins" from player's inventory may fail to detect payability from the total gold amount and only will take into account the first "gold_coins" stack item in inventory. This is not allways a problem, if the player has a "gold_coins" stack item equal or above the required amount, he can use the inventory menu (right-click) to move the higher stack to be first one.

But in cases where the required amount is only reached using 2 gold stacks (each gold stacks been bellow the required amount), the player will not be able to perform that action. The most extreme case of this behavior if getting a debt to Cubi of 110 or more (11 services), making impossible for the player to pay the debt.

Solution to avoid these scenarios is:

  1. Use a function to calculate the total collective gold quantity from all the player's inventory,
  2. Use another function to substract a given amount from multiple "gold_coins" items (or any other item quantity), and
  3. Adapt the gold-spending-centered mechanics to use these functions.

The following list show all the places affected by the minor bug, and the quick fixes I applied (all code line numbers based on original v0.2.1 unaltered files):

 

1) Refactor the (unused) get_current_gold_amount Function to return the total quantity of gold from all "gold_coins" items in the inventory.

[code]

  File "game/init.rpy", lines 1926-1937, inside get_current_gold_amount:

    def get_current_gold_amount():

        gold_qty = 0

        # Ensure persistent.player_inventory is a list before iterating

        if not isinstance(store.persistent.player_inventory, list):

            renpy.log("Warning: persistent.player_inventory is not a list in get_current_gold_amount.")

            return 0 # Or handle as an error

        for item_dict in store.persistent.player_inventory:

            if item_dict.get("id") == "gold_coins":

                gold_qty += item_dict.get("quantity", 0) # <-- Collective gold quantity

                #break # <-- Continue with all the items

        return gold_qty

[/code]

 

2) Add a "lose_item" Function to remove the stackable (and maybe non-stackable) items, like "gold_coins". This function does the opposite of the gain_item Function (File "game/init.rpy", lines 1449-1616) for stackable items on the "# INVENTORY MANAGEMENT #" python block (lines 1448-1945).

# (!) This fix doesnt handle "cursed" equipment that cannot be discarted, or any other special item (that is handled by the discard_item Function, invoked by player).

[code]

  File "game/init.rpy", lines 1939-1948, appended after yuki_has_item:

    def yuki_has_item(item_id_to_check):

        ...

        return False

 

    def lose_item(item_id, amount=1): # Removed amount parameter, defaults to 1

        if item_id not in item_definitions:

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

            return 0

        if amount <= 0:

            return 0

        

        item_data = item_definitions[item_id]

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

        

        amount_to_remove = amount # Start with the full amount requested

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

        i = 0

        while i <= len(persistent.player_inventory) and amount_to_remove > 0:

            index_in_list = i

            item_dict = persistent.player_inventory[index_in_list]

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

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

                can_remove_from_stack = current_quantity

                if can_remove_from_stack > 0:

                    remove_now = min(amount_to_remove, can_remove_from_stack)

                    item_dict["quantity"] = current_quantity - remove_now

                    amount_to_remove -= remove_now

                

                if item_dict["quantity"] <= 0:

                    # Continue next iteration using the same index after removing current item

                    store.persistent.player_inventory.pop(index_in_list)

                    message_text = f"Subtracted {remove_now} {item_name}."

                else:

                    # Continue next iteration using the next index

                    i += 1

                    message_text = f"Subtracted {remove_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")

                continue

            

            i += 1 # Continue next iteration using the next index

        

        return amount - amount_to_remove # The effectively removed item quantity

 

init -1 python: # QTE FUNCTIONS #

[/code]

;)

3.1) Implement the new functions in the Cubi room:

# pay out the debt to Cubi; pay out the current services to Cubi.

# 10 gold per requested service after used.

[code]

  File "game/dungeon_room.rpy", lines 7592-7610, inside room_cubi label:

        python:

            _can_afford_debt = get_current_gold_amount() >= persistent.cubi_debt_owed

        

        menu:

            "Pay the [persistent.cubi_debt_owed] Gold debt." if _can_afford_debt:

                y "Grrr... fine. Here's your blood money, you little toaster."

                python:

                    lose_item("gold_coins", persistent.cubi_debt_owed) # Should return persistent.cubi_debt_owed

                    persistent.cubi_debt_owed = 0

                    renpy.restart_interaction()

                cubi "\"Payment accepted. Account balance is now zero. Standard services are available.\""

[/code]

[/code]

  File "game/dungeon_room.rpy", lines 7692-7711, inside cubi_checkout label:

    python:

        _can_afford_checkout = get_current_gold_amount() >= _total_cost

    

    menu:

        "Pay the [_total_cost] Gold." if _can_afford_checkout:

            y "Grrr... fine! Here's your payment, you little extortionist!"

            python:

                lose_item("gold_coins", _total_cost) # Should return not _total_cost

                persistent.knows_about_cubi_fee = True

                renpy.restart_interaction()

            cubi "\"Payment accepted. Your compliance is... optimal. We value your patronage.\""

            jump cubi_exit_room

[/code]

 

3.2) Implement the new functions in the Vending Machine room:

# pay for buyable items in the Vending Machine.

# 5, 10 or 20 gold for "Fizzy Soda", "Random Potion" or "Potion of Relief" respectively.

[code]

  File "game/dungeon_room.rpy", lines 7342-7436, inside room_vending_machine label:

        python:

            # This block is now ONLY for displaying the gold and setting button sensitivity.

            store.vending_machine_current_gold = get_current_gold_amount()

        

        menu:

            "Buy Fizzy Soda (Cost: 5 Gold)":

                if store.vending_machine_current_gold >= 5:

                    y "A fizzy soda sounds... bubbly right now. Yuki will try it."

                    python:

                        # --- THIS IS THE FIX ---

                        lose_item("gold_coins", 5) # Should return 5

                        renpy.restart_interaction()

                        store._turn_notification_counter += 1

                        add_chat_notification("Spent 5 Gold on a Fizzy Soda.", store._turn_notification_counter)

                        gain_item("food_fizzy_soda")

                        # --- END OF FIX ---

                    y "Clunk! The machine dispenses a can of Fizzy Soda."

                else:

                    y "Yuki doesn't have enough gold for that. This machine is clearly not recognizing her status. (Need 5 Gold)"

                pause 0.5

                jump room_vending_machine_menu

            

            "Buy Random Potion (Cost: 10 Gold)":

                if store.vending_machine_current_gold >= 10:

                    y "A random potion? Sounds like a gamble, but Yuki is totally lucky!"

                    python:

                        # --- THIS IS THE FIX ---

                        lose_item("gold_coins", 10) # Should return 10

                        renpy.restart_interaction()

                        store._turn_notification_counter += 1

                        add_chat_notification("Spent 10 Gold on a Random Potion.", store._turn_notification_counter)

                        potion_pool_vm = [item_id for item_id, data in store.item_definitions.items() if data.get("type") == "potion"]

                        if potion_pool_vm:

                            chosen_potion_id_vm = renpy.random.choice(potion_pool_vm)

                            gain_item(chosen_potion_id_vm)

                            store.vending_machine_potion_name = store.item_definitions.get(chosen_potion_id_vm, {}).get("name", "a mysterious potion")

                        else:

                            store.vending_machine_potion_name = "an empty slot... how unlucky"

                        # --- END OF FIX ---

                    y "The machine whirs and drops... a [store.vending_machine_potion_name]! Yuki hopes it's not too disappointing."

                else:

                    y "Not enough gold for a mystery potion. (Need 10 Gold)"

                pause 0.5

                jump room_vending_machine_menu

            

            "Buy Potion of Relief (Cost: 20 Gold)":

                if store.vending_machine_current_gold >= 20:

                    y "A Potion of Relief sounds very useful for Yuki right about now. She might consider it."

                    python:

                        # --- THIS IS THE FIX ---

                        lose_item("gold_coins", 20) # Should return 20

                        renpy.restart_interaction()

                        store._turn_notification_counter += 1

                        add_chat_notification("Spent 20 Gold on a Potion of Relief.", store._turn_notification_counter)

                        gain_item("potion_relief")

                        # --- END OF FIX ---

                    y "The machine dispenses a Potion of Relief. Ah, just what Yuki might need, if she were lesser."

                else:

                    y "Yuki can't afford that right now. This machine is clearly overpriced. (Need 20 Gold)"

                pause 0.5

                jump room_vending_machine_menu

[/code]

 

3.3) Implement the new functions in the Barter Peddler room:

# pay for trades with the Barter Peddler.

# 10 gold per trade (upon first trade).

[code]

  File "game/dungeon_room.rpy", lines 6489-6556, inside room_barter_peddler label:

                if offered_item_index is not None and 0 <= offered_item_index < len(persistent.player_inventory):

                    python:

                        item_to_be_traded = persistent.player_inventory[offered_item_index]

                        

                        cost_of_this_trade = 10 if peddler_trade_count_this_encounter > 0 else 0

                        can_afford_trade = True

                        

                        if cost_of_this_trade > 0:

                            can_afford_trade = get_current_gold_amount() >= cost_of_this_trade

                    ...

                    if store.trade_outcome == "success":

                        if cost_of_this_trade > 0:

                            # FIX: Using a temp variable for the f-string

                            $ _peddler_dialogue_line = f"Very well. That'll be {cost_of_this_trade} Gold Coins."

                            p "[_peddler_dialogue_line]"

                            python:

                                lose_item("gold_coins", cost_of_this_trade) # Should return cost_of_this_trade

                            y "(I hand over [cost_of_this_trade] Gold Coins.)"

                            $ renpy.restart_interaction()

                        

                        $ persistent.player_inventory.remove(item_to_be_traded)

                        $ renpy.restart_interaction()

                        

                        $ gain_item(store.new_item_id_from_trade)

[/code]

 

3.4) Implement the new functions in the Gamble room:

# pay for the "Spin with Gold" in the Gamble room.

# 10 gold per spin.

[code]

  File "game/dungeon_room.rpy", lines 1887-1894, inside gamble_unified_actions_screen screen:

                        python:

                            _can_afford_gold_spin_screen = get_current_gold_amount() >= 10

                        textbutton "Spin with Gold":

[/code]

[code]

  File "game/dungeon_room.rpy", lines 1943-1955, inside gamble_action_spin_inflation label:

    label gamble_action_spin_gold:

        y "A little spending couldn't hurt~"

        python:

            lose_item("gold_coins", 10) # Should return 10

            renpy.restart_interaction()

[/code]

 

3.5) Implement the new functions in the Curse Cleansing Pool room:

# toss coins in the Curse Cleansing Pool room ('The Font of Fickle Fortunes').

# 10 gold for tossing action.

[code]

  File "game/dungeon_room.rpy", lines 6380-6401, inside room_curse_cleansing_pool label:

            "Toss 10 Gold Coins into the pool." if "toss_coin" not in chosen_options_this_visit:

                python:

                    # This block re-checks affordability right before action, which is good practice.

                    _can_afford_pool_toss = get_current_gold_amount() >= 10

                

                if _can_afford_pool_toss:

                    python:

                        # Deduct 10 gold coins from stacks in inventory

                        lose_item("gold_coins", 10) #  Should return 10

                        renpy.restart_interaction() # Update HUD if inventory changed

[/code]

 

3.6) Implement the new functions in the MAX MIN Lever room:

# pay for 'MIN' Lever deflation in the MAX MIN Lever room.

# gold cost based on current total inflation level.

[code]

  File "game/dungeon_room.rpy", lines 6041-6058, inside room_lever_max_min label:

        "Pull 'MIN' Lever (Cost: [_dynamic_cost_min_lever_menu] Gold).":

            y "Let's reduce the pressure."

            python:

                _can_afford_min_lever = get_current_gold_amount() >= _dynamic_cost_min_lever_menu

                

                if _can_afford_min_lever:

                    # Deduct gold

                    lose_item("gold_coins", _dynamic_cost_min_lever_menu) # Should return _dynamic_cost_min_lever_menu

                    renpy.restart_interaction()

[/code]

;)