Jump to content

Creating a Potion-Brewing Station (Mostly Complete)


Recommended Posts

Hello! I need help with coding something, I'm working on a potion station that works similarly to a crock pot, you put 4 ingredients in they get deleted and out spews out potions! The potions you can brew is based on what level the Player's skills component is at (maximum is 3)

The following code is... not working very well. I got so desperate I even used ChatGPT in order to help me but I got nowhere.

What I'm trying to achieve:

  • Make it so that it spews out up to 3 potions randomly [WORKING]
  • Make it spew out a large potions (25% chance) or a small potion (75% chance) [WORKING]
  • Have multiple recipes per potion craft! [Not sure if it's working]
  • If the ingredients don't match up with any of the recipes then spew out Wet Goop. (For some reason the station ALWAYS spews out wetgoop even if the ingredients match up with the recipe)

I'm only sending the part where the potions pop out, the rest works just fine but if you need more information (like the component for the brewery or the rest of the prefab's code) then just reply

So, here's the code:

Spoiler
local function OnScienceWasMade(inst)
    local player = GetPlayer()
    local brewingSkillLevel = player.components.skills and player.components.skills.potion_brewing or 0

    -- Define potion recipes based on brewing skill level
    -- Key (numeric) = skill level
    -- Value = all recipes for specified skill level
    -- Each recipe consists of arrays of ingredients and corresponding potions
    local all_potion_recipes_ever = {
        [1] = {
            {
                recipes = {
                    {"flint", "flint", "flint", "flint"},
                    {"flint", "flint", "flint", "cutgrass"}
                },
                potions = {
                    {prefab = "potion_embers", rarity = 75},
                    {prefab = "potion_sparks", rarity = 25}
                }
            }
        },
        [2] = {
            {
                recipes = {
                    {"rocks", "rocks", "rocks", "rocks"},
                    {"rocks", "rocks", "rocks", "twigs"},
                },
                potions = {
                    {prefab = "potion_plant_small", rarity = 75},
                    {prefab = "potion_plant_large", rarity = 25}
                }
            }
        },
        [3] = {
            {
                recipes = {
                    {"cutgrass", "cutgrass", "cutgrass", "cutgrass"},
                    {"cutgrass", "cutgrass", "cutgrass", "rocks"},
                },
                potions = {
                    {prefab = "potion_sanity_small", rarity = 75},
                    {prefab = "potion_sanity_large", rarity = 25}
                }
            },
            {
                recipes = {
                    {"twigs", "twigs", "twigs", "twigs"},
                    {"twigs", "twigs", "twigs", "rocks"}
                },
                potions = {
                    {prefab = "potion_health_small", rarity = 75},
                    {prefab = "potion_health_large", rarity = 25}
                }
            }
        }
    }

    -- Choose recipe based on brewing skill level
    local recipeInfo = all_potion_recipes_ever[brewingSkillLevel]
    if recipeInfo == nil then
        -- If brewing skill level is greater than 3, use the recipe for level 3
        recipeInfo = all_potion_recipes_ever[3]
    end

    -- Determine number of potions to drop (up to 3)
    local numPotions = math.random(3)
    for i = 1, numPotions do
        local selectedRecipe = nil
        for _, recipe in ipairs(recipeInfo) do
            local canCraft = true
            for _, ingredient in ipairs(recipe.recipes) do
                local ingredientCount = 0
                for _, ing in ipairs(recipe.recipes) do
                    if ing == ingredient then
                        ingredientCount = ingredientCount + 1
                    end
                end
                local requiredCount = 1 -- Default required count is 1
                if ingredientCount > 1 then
                    requiredCount = ingredientCount
                end
                if not inst.components.container:Has(ingredient, requiredCount) then
                    canCraft = false
                    break
                end
            end
            if canCraft then
                selectedRecipe = recipe
                break
            end
        end

        if selectedRecipe then
            local potionTypes = selectedRecipe.potions
            local totalRarity = 0
            for _, potion in ipairs(potionTypes) do
                totalRarity = totalRarity + potion.rarity
            end
            local randomValue = math.random(totalRarity)
            local cumulativeRarity = 0
            local selectedPotion
            for _, potion in ipairs(potionTypes) do
                cumulativeRarity = cumulativeRarity + potion.rarity
                if randomValue <= cumulativeRarity then
                    selectedPotion = potion.prefab
                    break
                end
            end

            local x, y, z = inst.Transform:GetWorldPosition()
            local reward = SpawnPrefab(selectedPotion)
            local pt = Vector3(inst.Transform:GetWorldPosition()) + Vector3(0, 2.5, 0)
            reward.Transform:SetPosition(pt:Get())
            local down = TheCamera:GetDownVec()
            local angle = math.atan2(down.z, down.x) + (math.random() * 60 - 30) * DEGREES
            local sp = math.random() * 4 + 2
            reward.Physics:SetVel(sp * math.cos(angle), math.random() * 2 + 4, sp * math.sin(angle))
            reward.components.inventoryitem:OnStartFalling()
        else
            -- If no recipe fulfills the requirement, spawn "wetgoop"
            local reward = SpawnPrefab("wetgoop")
            local x, y, z = inst.Transform:GetWorldPosition()
            reward.Transform:SetPosition(x, y, z)
            reward.components.inventoryitem:OnStartFalling()
        end
    end

    PlayAnimation(inst, "cooking_finish")
    inst.SoundEmitter:KillSound("brew")
    inst.SoundEmitter:PlaySound("dontstarve/common/potionbrewer/finish")
    inst:ListenForEvent("animover", OnInactive)

    inst._firefx.AnimState:PlayAnimation("cooking_finish_fire")
    inst:ListenForEvent("animover", OnFireFXOver, inst._firefx)
end

I hope there's anyone who can help me.

Thank you for reading!

Edited by mathem99
Link to comment
Share on other sites

Put the selectedRecipe variable outside of the for loop, like this

    -- Determine number of potions to drop (up to 3)
    local numPotions = math.random(3)
    local selectedRecipe
    for i = 1, numPotions do
        for _, recipe in ipairs(recipeInfo) do

        

 

Link to comment
Share on other sites

9 hours ago, _zwb said:

Put the selectedRecipe variable outside of the for loop, like this

    -- Determine number of potions to drop (up to 3)
    local numPotions = math.random(3)
    local selectedRecipe
    for i = 1, numPotions do
        for _, recipe in ipairs(recipeInfo) do

        

 

Thank you for the reply, sadly this doesn't seem to change the fact that the result is always wetgoop.

Link to comment
Share on other sites

Posted (edited)

I made a new interpretation of the potion-brewing and here it is:
 

local potion_recipe_common = {
    potion_health_small = {
        {
            ingredients = { "twigs", "twigs", "twigs", "twigs" },
            skill_level = 3
        },
        {
            ingredients = { "cutgrass", "cutgrass", "cutgrass", "cutgrass" },
            skill_level = 3
        }
    },
    potion_sanity_small = {
        {
            ingredients = { "carrot", "carrot", "carrot", "carrot" },
            skill_level = 3
        }
    },
    potion_plant_small = {
        {
            ingredients = { "bluegem", "bluegem", "bluegem", "bluegem" },
            skill_level = 2
        }
    },
    potion_embers = {
        {
            ingredients = { "redgem", "redgem", "redgem", "redgem" },
            skill_level = 1
        }
    }
}

local potion_recipe_rare = {
    potion_health_large = {
        {
            ingredients = { "twigs", "twigs", "twigs", "twigs" },
            skill_level = 3
        },
        {
            ingredients = { "cutgrass", "cutgrass", "cutgrass", "cutgrass" },
            skill_level = 3
        }
    },
    potion_sanity_large = {
        {
            ingredients = { "carrot", "carrot", "carrot", "carrot" },
            skill_level = 3
        }
    },
    potion_plant_large = {
        {
            ingredients = { "bluegem", "bluegem", "bluegem", "bluegem" },
            skill_level = 2
        }
    },
    potion_sparks = {
        {
            ingredients = { "redgem", "redgem", "redgem", "redgem" },
            skill_level = 1
        }
    }
}

local function GetPotionToBrew(items, skill_level, is_large)
    local potential_potions = {}
    local rare_potions = {}

    local potion_recipe = is_large and potion_recipe_rare or potion_recipe_common

    for potion_name, recipes in pairs(potion_recipe) do
        for _, recipe in ipairs(recipes) do
            if skill_level >= recipe.skill_level then
                local valid = true
                for i, item in ipairs(items) do
                    if recipe.ingredients[i] ~= item.prefab then
                        valid = false
                        break
                    end
                end
                if valid then
                    table.insert(is_large and rare_potions or potential_potions, potion_name)
                end
            elseif skill_level <= 0 then
				return "wetgoop"
			end
        end
    end

    if #rare_potions > 0 and is_large then
        return rare_potions[math.random(#rare_potions)]
    elseif #potential_potions > 0 then
        return potential_potions[math.random(#potential_potions)]
    else
        return "wetgoop"
    end
end

local function OnScienceWasMade(inst)
    local player = GetPlayer()
    local skill_level = player.components.skills and player.components.skills.potion_brewing or 0
    local rewarditem
    local maxDrops = math.random(3)

    for i = 1, maxDrops do
        local is_large = math.random() <= 0.25
        local potion_type

        if is_large then
            potion_type = GetPotionToBrew(inst.components.container.slots, skill_level, true)
        else
            potion_type = GetPotionToBrew(inst.components.container.slots, skill_level, false)
        end

        if potion_type then
            local x, y, z = inst.Transform:GetWorldPosition()
            local reward = SpawnPrefab(potion_type)
            local pt = Vector3(inst.Transform:GetWorldPosition()) + Vector3(0, 2.5, 0)
            reward.Transform:SetPosition(pt:Get())
            local down = TheCamera:GetDownVec()
            local angle = math.atan2(down.z, down.x) + (math.random() * 60 - 30) * DEGREES
            local sp = math.random() * 4 + 2
            reward.Physics:SetVel(sp * math.cos(angle), math.random() * 2 + 4, sp * math.sin(angle))
            reward.components.inventoryitem:OnStartFalling()
        end
    end
	
    PlayAnimation(inst, "cooking_finish")
    inst.SoundEmitter:KillSound("brew")
    inst.SoundEmitter:PlaySound("dontstarve/common/potionbrewer/finish")
    inst:ListenForEvent("animover", OnInactive)

    inst._firefx.AnimState:PlayAnimation("cooking_finish_fire")
    inst:ListenForEvent("animover", OnFireFXOver, inst._firefx)
end

It seems to work! But I don't know if there's a cleaner way of going about it.

Edited by mathem99
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
  • Create New...