Jump to content

Recommended Posts

I thought a neat idea for my character would be to allow them to craft items from the Magic tab at a cheaper price, but looking at the code for the Construction Amulet leads me to the function ingredientmod, which applies to all crafting operations, and I don't see how, if possible, I could split it to only affect a certain tab.

I would add the code from the builder.lua of what parts affect the ingredientmod, but it's split up all over the lua

6 hours ago, Winona said:

In theory you could make it so there's new cheaper recipes that only she can craft (via a tag) and then prevent her from seeing the old, expensive recipes (though I'm not sure how to do that.)

That is a solution definitely, though I'd prefer not doing that unless I have to, since it would be time consuming to make each individual recipe, and wouldn't be dynamic with new updates or mods that add new magic items.

If there's no progress on the original idea soonish I'll look into doing that.

Well, things are little tricky as component/replica/widget calculates the demand separately, so all of them needs to be overwritten.

And the mod is all client required:

Quote

--TODO: customize these constants
--prefab name of your character
local CHARACTER_PREFAB = "wickerbottom"
--need 10% of original ingredients, rounded to integer
local INGREDIENT_MODIFIER = 0.1
--tab name(s)
local RECIPE_TAB = {
    "DRESS",
    "LIGHT"
}

local Text = GLOBAL.require("widgets/text")
local Image = GLOBAL.require("widgets/image")

AddComponentPostInit("builder",function(inst)
    inst.GetIngredients=function(self, recname)
        local recipe = GLOBAL.AllRecipes[recname]
        if recipe then
            local ingredients = {}
            local modifier = (self.inst.prefab == CHARACTER_PREFAB and GLOBAL.table.contains(RECIPE_TAB, recipe.tab.str)) and INGREDIENT_MODIFIER or 1
            modifier = math.min(modifier, self.ingredientmod)
            for k,v in pairs(recipe.ingredients) do
                local amt = math.max(1, GLOBAL.RoundBiasedUp(v.amount * modifier))
                local items = self.inst.components.inventory:GetItemByName(v.type, amt)
                ingredients[v.type] = items
            end
            return ingredients
        end
    end
    inst.CanBuild=function(self, recname)
        local recipe = GLOBAL.GetValidRecipe(recname)
        if recipe == nil then
            return false
        elseif not self.freebuildmode then
            local modifier = (self.inst.prefab == CHARACTER_PREFAB and GLOBAL.table.contains(RECIPE_TAB, recipe.tab.str)) and INGREDIENT_MODIFIER or 1
            modifier = math.min(modifier, self.ingredientmod)
            for i, v in ipairs(recipe.ingredients) do
                if not self.inst.components.inventory:Has(v.type, math.max(1, GLOBAL.RoundBiasedUp(v.amount * modifier))) then
                    return false
                end
            end
        end
        for i, v in ipairs(recipe.character_ingredients) do
            if not self:HasCharacterIngredient(v) then
                return false
            end
        end
        for i, v in ipairs(recipe.tech_ingredients) do
            if not self:HasTechIngredient(v) then
                return false
            end
        end
        return true
    end
end)

AddClassPostConstruct("components/builder_replica",function(inst)
    inst.CanBuild=function(self, recipename)
        if self.inst.components.builder ~= nil then
            return self.inst.components.builder:CanBuild(recipename)
        elseif self.classified ~= nil then
            local recipe = GLOBAL.GetValidRecipe(recipename)
            if recipe == nil then
                return false
            elseif not self.classified.isfreebuildmode:value() then
                local modifier = (self.inst.prefab == CHARACTER_PREFAB and GLOBAL.table.contains(RECIPE_TAB, recipe.tab.str)) and INGREDIENT_MODIFIER or 1
                modifier = math.min(modifier, self:IngredientMod())
                for i, v in ipairs(recipe.ingredients) do
                    if not self.inst.replica.inventory:Has(v.type, math.max(1, GLOBAL.RoundBiasedUp(v.amount * modifier))) then
                        return false
                    end
                end
            end
            for i, v in ipairs(recipe.character_ingredients) do
                if not self:HasCharacterIngredient(v) then
                    return false
                end
            end
            for i, v in ipairs(recipe.tech_ingredients) do
                if not self:HasTechIngredient(v) then
                    return false
                end
            end
            return true
        else
            return false
        end
    end
end)

AddClassPostConstruct("widgets/recipepopup",function(inst)
    oldRefresh=inst.Refresh
    inst.Refresh=function(self)
        oldRefresh(self)
        if self.owner == nil then
            return false
        end
        if self.owner.prefab == CHARACTER_PREFAB and GLOBAL.table.contains(RECIPE_TAB, self.recipe.tab.str) and self.owner.replica.builder:IngredientMod() > INGREDIENT_MODIFIER then
            local skip=#self.recipe.tech_ingredients
            for i,v in ipairs(self.recipe.ingredients) do
                local quantity = math.max(1,GLOBAL.RoundBiasedUp(v.amount * INGREDIENT_MODIFIER))
                local has, num_found = self.owner.replica.inventory:Has(v.type, quantity)
                local hud_atlas = GLOBAL.resolvefilepath("images/hud.xml")
                self.ing[i+skip]:RemoveChild(self.ing[i+skip].bg)
                self.ing[i+skip].bg:Kill()
                self.ing[i+skip]:RemoveChild(self.ing[i+skip].ing)
                self.ing[i+skip].ing:Kill()
                self.ing[i+skip]:RemoveChild(self.ing[i+skip].quant)
                self.ing[i+skip].quant:Kill()
                self.ing[i+skip].bg = self.ing[i+skip]:AddChild(Image(hud_atlas, has and "inv_slot.tex" or "resource_needed.tex"))
                self.ing[i+skip].ing = self.ing[i+skip]:AddChild(Image(v.atlas, v.type..".tex"))
                self.ing[i+skip].quant = self.ing[i+skip]:AddChild(Text(GLOBAL.SMALLNUMBERFONT, GLOBAL.JapaneseOnPS4() and 30 or 24))
                self.ing[i+skip].quant:SetPosition(7, -32, 0)
                self.ing[i+skip].quant:SetString(string.format("%d/%d", num_found, quantity))
                if not has then
                    self.ing[i+skip].quant:SetColour(1, 155/255, 155/255, 1)
                end
            end
        end
    end
end)

 

tab name could be:

"TOOLS"
"LIGHT"
"SURVIVAL"
"FARM"
"SCIENCE"
"WAR"
"TOWN"
"REFINE"
"MAGIC"
"DRESS"
"ANCIENT"
"CARTOGRAPHY"
"SCULPTING"
"ORPHANAGE"
"PERDOFFERING"
"BOOKS"
"SHADOW"

or other tabs created in mods

 

Holy heck thats quite a code, but I plugged it into my modmain, changed the values as instructed and it works!

Feel kinda bad not figuring it out myself but looking at that makes me think I probably wouldn't have been able to regardless.

Thank you so much for the help though! I'll be sure to credit you on the mod page for the help.

Okay, kinda big question, and I know it's not exactly what this board is for, but do you know how I would go about making this code Singleplayer Don't Starve compatible? I can tell I'd have to remove the "AddClassPostConstruct("components/builder_replica",function(inst)" part since builder_replica isn't a thing in SP but I don't know how I would go about putting everything where it needs to go without it.

EDIT: Before it gets asked, yes I've made a DS compatible version of the rest of the mod.

Edited by Eevelion

It is more complicated than simply removing the RPC component, vanilla and ROG and SW and DST all have slight differences in API than the others. The following code is ALL compatible now.

Quote

 

--TODO: customize these constants
--prefab name of your character
local CHARACTER_PREFAB = "wickerbottom"
--need 10% of original ingredients, rounded to integer
local INGREDIENT_MODIFIER = 0.1
--tab name(s)
local RECIPE_TAB = {
    "DRESS",
    "LIGHT"
}

local ISDST = GLOBAL.TheSim:GetGameID() == "DST"
local Text = GLOBAL.require("widgets/text")
local Image = GLOBAL.require("widgets/image")
local function Round(num)
    return ISDST and GLOBAL.RoundBiasedUp(num) or GLOBAL.RoundUp(num)
end

AddComponentPostInit("builder",function(inst)
    if not inst.GetIngredients then
        inst.RemoveIngredients=function(self, recname)
            local recipe = GLOBAL.GetRecipe(recname)
            self.inst:PushEvent("consumeingredients", {recipe = recipe})
            if recipe then
                local modifier = (self.inst.prefab == CHARACTER_PREFAB and table.contains(RECIPE_TAB, recipe.tab.str)) and INGREDIENT_MODIFIER or 1
                modifier = math.min(modifier, self.ingredientmod)
                for k, v in pairs(recipe.ingredients) do
                    local amt = math.max(1, GLOBAL.RoundUp(v.amount * modifier))
                    self.inst.components.inventory:ConsumeByName(v.type, amt)
                end
            end
        end
    else
        inst.GetIngredients=function(self, recname)
            local recipe = ISDST and GLOBAL.AllRecipes[recname] or GLOBAL.GetRecipe(recname)
            if recipe then
                local ingredients = {}
                local modifier = (self.inst.prefab == CHARACTER_PREFAB and table.contains(RECIPE_TAB, recipe.tab.str)) and INGREDIENT_MODIFIER or 1
                modifier = math.min(modifier, self.ingredientmod)
                for k,v in pairs(recipe.ingredients) do
                    local amt = math.max(1, Round(v.amount * modifier))
                    local items = self.inst.components.inventory:GetItemByName(v.type, amt)
                    ingredients[v.type] = items
                end
                return ingredients
            end
        end
    end
    inst.CanBuild=function(self, recname)
        local recipe = ISDST and GLOBAL.GetValidRecipe(recname) or GLOBAL.GetRecipe(recname)
        if recipe == nil then
            return false
        elseif not self.freebuildmode then
            local modifier = (self.inst.prefab == CHARACTER_PREFAB and table.contains(RECIPE_TAB, recipe.tab.str)) and INGREDIENT_MODIFIER or 1
            modifier = math.min(modifier, self.ingredientmod)
            for i, v in ipairs(recipe.ingredients) do
                if not self.inst.components.inventory:Has(v.type, math.max(1, Round(v.amount * modifier))) then
                    return false
                end
            end
        end
        if ISDST then
            for i, v in ipairs(recipe.character_ingredients) do
                if not self:HasCharacterIngredient(v) then
                    return false
                end
            end
            for i, v in ipairs(recipe.tech_ingredients) do
                if not self:HasTechIngredient(v) then
                    return false
                end
            end
        end
        return true
    end
end)

if ISDST then
    AddClassPostConstruct("components/builder_replica",function(inst)
        inst.CanBuild=function(self, recipename)
            if self.inst.components.builder ~= nil then
                return self.inst.components.builder:CanBuild(recipename)
            elseif self.classified ~= nil then
                local recipe = GLOBAL.GetValidRecipe(recipename)
                if recipe == nil then
                    return false
                elseif not self.classified.isfreebuildmode:value() then
                    local modifier = (self.inst.prefab == CHARACTER_PREFAB and GLOBAL.table.contains(RECIPE_TAB, recipe.tab.str)) and INGREDIENT_MODIFIER or 1
                    modifier = math.min(modifier, self:IngredientMod())
                    for i, v in ipairs(recipe.ingredients) do
                        if not self.inst.replica.inventory:Has(v.type, math.max(1, GLOBAL.RoundBiasedUp(v.amount * modifier))) then
                            return false
                        end
                    end
                end
                for i, v in ipairs(recipe.character_ingredients) do
                    if not self:HasCharacterIngredient(v) then
                        return false
                    end
                end
                for i, v in ipairs(recipe.tech_ingredients) do
                    if not self:HasTechIngredient(v) then
                        return false
                    end
                end
                return true
            else
                return false
            end
        end
    end)
end

AddClassPostConstruct("widgets/recipepopup",function(inst)
    local oldRefresh=inst.Refresh
    inst.Refresh=function(self)
        oldRefresh(self)
        if self.owner == nil then
            return false
        end
        local ingredientmod = ISDST and self.owner.replica.builder:IngredientMod() or self.owner.components.builder.ingredientmod
        local inventory = ISDST and self.owner.replica.inventory or self.owner.components.inventory
        if self.owner.prefab == CHARACTER_PREFAB and GLOBAL.table.contains(RECIPE_TAB, self.recipe.tab.str) and ingredientmod > INGREDIENT_MODIFIER then
            local skip = ISDST and #self.recipe.tech_ingredients or 0
            for i,v in ipairs(self.recipe.ingredients) do
                local quantity = math.max(1,Round(v.amount * INGREDIENT_MODIFIER))
                local has, num_found = inventory:Has(v.type, quantity)
                local hud_atlas = GLOBAL.resolvefilepath("images/hud.xml")
                self.ing[i+skip]:RemoveChild(self.ing[i+skip].bg)
                self.ing[i+skip].bg:Kill()
                self.ing[i+skip]:RemoveChild(self.ing[i+skip].ing)
                self.ing[i+skip].ing:Kill()
                self.ing[i+skip]:RemoveChild(self.ing[i+skip].quant)
                self.ing[i+skip].quant:Kill()
                self.ing[i+skip].bg = self.ing[i+skip]:AddChild(Image(hud_atlas, has and "inv_slot.tex" or "resource_needed.tex"))
                local item_img = (not ISDST and GLOBAL.SaveGameIndex:IsModeShipwrecked() and GLOBAL.SW_ICONS[v.type] ~= nil) and GLOBAL.SW_ICONS[v.type] or v.type
                self.ing[i+skip].ing = self.ing[i+skip]:AddChild(Image(v.atlas, v.type..".tex"))
                self.ing[i+skip].quant = self.ing[i+skip]:AddChild(Text(GLOBAL.SMALLNUMBERFONT, GLOBAL.JapaneseOnPS4() and 30 or 24))
                self.ing[i+skip].quant:SetPosition(7, -32, 0)
                self.ing[i+skip].quant:SetString(string.format("%d/%d", num_found, quantity))
                if not has then
                    self.ing[i+skip].quant:SetColour(1, 155/255, 155/255, 1)
                end
            end
        end
    end
end)

 

 

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
×
  • Create New...