• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Action [TFS 1.X] Simple RPG: Forging/Crafting/Cooking following a recipe without Modal Windows

Tenzhiro

Fool of a Took!
Premium User
Joined
May 4, 2010
Messages
211
Solutions
3
Reaction score
179
Crafting Stations
In my case a forging script, but you can change the anvil id to be something else.

As I never released anything, I decided to release this script I made with the help of my best friend Henk, known by some as ChatGBT, edited from an initial movement script to an action script by @Xikini so it allows for experience gain if you have additional skills setup.

What does it do?
It allows players to immersefully and in an old-school way to forge weapons and armor, or any item they want.
This can also be made into an upgrading system or cooking station, the sky is the limit.
I've made it with the concept of how easy "creating bread" in Tibia is and followed up on that.

You can configure a recipe that players can stack upon an Anvil,
upon using a Blacksmith Hammer on the Anvil, the materials will transform into the item configured.

View attachment 2024-02-16 13-15-47.mp4

actions.xml
Code:
<!-- Crafting Stations -->
    <action itemid="2422" script="forging.lua"/>


actions/scripts/forging.lua
Lua:
local recipes = {
    -- Ores to Bars
    {
        resultItemID = 49257, -- Brass Bar
        requiredItems = {
            {itemID = 49242, count = 2}, -- Copper Ore
            {itemID = 49256, count = 1} -- Zinc Ore
        }
    }
}

local ANVIL_ID = 2555

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if not target then
        return true
    end
    if not target:isItem() then
        return true
    end
   
    local position = target:getPosition()
    if position.x == CONTAINER_POSITION then
        return true
    end

    local tile = Tile(position)
    if not tile then
        return false
    end

    local items = tile:getItems()
    if items then
        local hasAnvil = false
        local bestMatchRecipe = nil

        for _, itemOnTile in ipairs(items) do
            if itemOnTile:getId() == ANVIL_ID then
                hasAnvil = true
            end
        end

        if hasAnvil then
            for _, recipe in ipairs(recipes) do
                local requiredItemsFound = true
               
                for _, reqItem in ipairs(recipe.requiredItems) do
                    local foundCount = 0
                    for _, itemOnTile in ipairs(items) do
                        if itemOnTile:getId() == reqItem.itemID then
                            foundCount = foundCount + itemOnTile:getCount()
                        end
                    end

                    if foundCount < reqItem.count then
                        requiredItemsFound = false
                        break
                    end
                end

                if requiredItemsFound then
                    for _, reqItem in ipairs(recipe.requiredItems) do
                        local remainingCount = reqItem.count
                        for _, itemOnTile in ipairs(items) do
                            if itemOnTile:getId() == reqItem.itemID then
                                local countToRemove = math.min(remainingCount, itemOnTile:getCount())
                                itemOnTile:remove(countToRemove)
                                remainingCount = remainingCount - countToRemove
                                if remainingCount <= 0 then
                                    break
                                end
                            end
                        end
                    end

                    Game.createItem(recipe.resultItemID, recipe.count or 1, toPosition)
                    toPosition:sendMagicEffect(CONST_ME_HITBYFIRE)
                    doPlayerAddSkillTry(player:getId(), SKILL_METALWORKING, 1) -- remove line if no skill
                    local formula = (getPlayerSkill(player:getId(), SKILL_METALWORKING) / 200) + (0.85 * math.random()) -- remove line if no skill
                    return true
               
                end
            end
        end
    end

    return false
end
 
Last edited:
I Will try this on my server. Seems like a cool and abit retro way of doing crafting :)

How do you present recipes for your players? Like, how would they know what the ingredients are for making any item?
 
I Will try this on my server. Seems like a cool and abit retro way of doing crafting :)

How do you present recipes for your players? Like, how would they know what the ingredients are for making any item?

I have NPC talk about material combinations, I have recipes written in books and scrolls to hint at items they may create.
There are more ways to implement a recipe, but having players figure out combinations themselves makes it more fun.
Although requires recipes that are somewhat logical in what materials they require.

Players will be making notes, perhaps in a book, can possibly even sell the information etc
Over time they will make a wiki and most items will be in the open, but it will be a community effort, not a system effort :D

Edit: Lua - Xikini's Free Scripting Service TFS 1.4.2 (https://otland.net/threads/xikinis-free-scripting-service-tfs-1-4-2.287753/page-8#post-2744643)
You can use this script to make a Recipe Book based on storages gained!
 
Yes I like that idea. I'll figure I'll never get that amount of players to actually make a wiki for my game, but I like the idea of recipes and npcs that can help you out.

I also like the idea of having to use a recipe to make items for example so that the recipe is actually part of the ingredients, and that recipes can be looted by different bosses or mobs.
This I think will make it even harder to craft the really good and rare items.

And certain recipes can be bought. This I think will upkeep pricing Of items.
 
You could also make molds for equipment and weapon pieces, so you need a helmet mold to make a helmet etc.
Not really immersive as they will all be one-cast forgings but you could eventually expand on that and have molds that create parts, after that they have to tinker with those items at another crafting bench to create the eventually create the item, but that might be too many actions for the player 🤔
 
I have NPC talk about material combinations, I have recipes written in books and scrolls to hint at items they may create.
There are more ways to implement a recipe, but having players figure out combinations themselves makes it more fun.
Although requires recipes that are somewhat logical in what materials they require.

Players will be making notes, perhaps in a book, can possibly even sell the information etc
Over time they will make a wiki and most items will be in the open, but it will be a community effort, not a system effort :D

Edit: Lua - Xikini's Free Scripting Service TFS 1.4.2 (https://otland.net/threads/xikinis-free-scripting-service-tfs-1-4-2.287753/page-8#post-2744643)
You can use this script to make a Recipe Book based on storages gained!
A good way to show recipes is:
Each recipe have a storage to amount of times crafted(to track, give rewards, give bonus), when the storage is > 0, show the recipe in the book, because u already crafted it and 'discovered' the recipe. Good job!
 
A good way to show recipes is:
Each recipe have a storage to amount of times crafted(to track, give rewards, give bonus), when the storage is > 0, show the recipe in the book, because u already crafted it and 'discovered' the recipe. Good job!
That I would love!
Great idea
 
How to add more recipes? I can't do it, it's giving me an { error.
Lua:
local recipes = {
    -- Ores to Bars
    {
        resultItemID = 49257, -- Brass Bar
        requiredItems = {
            {itemID = 49242, count = 2}, -- Copper Ore
            {itemID = 49256, count = 1}, -- Zinc Ore
        }
    },
    -- Outra receita
    {
        resultItemID = 12345, -- Resulting item ID
        requiredItems = {
            {itemID = 67890, count = 3}, -- ID of first required item and quantity
            {itemID = 54321, count = 1}, --Second required item ID and quantity
        }
    }
}

local ANVIL_ID = 2555 -- ID hammer for forging

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if not target or not target:isItem() then
        return true
    end
  
    local position = target:getPosition()
    if position.x == CONTAINER_POSITION then
        return true
    end

    local tile = Tile(position)
    if not tile then
        return false
    end

    local items = tile:getItems()
    if items then
        local hasAnvil = false
        local bestMatchRecipe = nil

        for _, itemOnTile in ipairs(items) do
            if itemOnTile:getId() == ANVIL_ID then
                hasAnvil = true
            end
        end

        if hasAnvil then
            for _, recipe in ipairs(recipes) do
                local requiredItemsFound = true
              
                for _, reqItem in ipairs(recipe.requiredItems) do
                    local foundCount = 0
                    for _, itemOnTile in ipairs(items) do
                        if itemOnTile:getId() == reqItem.itemID then
                            foundCount = foundCount + itemOnTile:getCount()
                        end
                    end

                    if foundCount < reqItem.count then
                        requiredItemsFound = false
                        break
                    end
                end

                if requiredItemsFound then
                    for _, reqItem in ipairs(recipe.requiredItems) do
                        local remainingCount = reqItem.count
                        for _, itemOnTile in ipairs(items) do
                            if itemOnTile:getId() == reqItem.itemID then
                                local countToRemove = math.min(remainingCount, itemOnTile:getCount())
                                itemOnTile:remove(countToRemove)
                                remainingCount = remainingCount - countToRemove
                                if remainingCount <= 0 then
                                    break
                                end
                            end
                        end
                    end

                    Game.createItem(recipe.resultItemID, recipe.count or 1, toPosition)
                    toPosition:sendMagicEffect(CONST_ME_HITBYFIRE)
                    doPlayerAddSkillTry(player:getId(), SKILL_METALWORKING, 1) -- remove line if no skill
                    local formula = (getPlayerSkill(player:getId(), SKILL_METALWORKING) / 200) + (0.85 * math.random()) -- remove line if no skill
                    return true
                end
            end
        end
    end

    return false
end
 
woeps
Post automatically merged:

How to add more recipes? I can't do it, it's giving me an { error.

Lua:
local recipes = {
    -- Ores to Bars
    {
        resultItemID = 49257, -- Brass Bar
        requiredItems = {
            {itemID = 49242, count = 2}, -- Copper Ore
            {itemID = 49256, count = 1}, -- Zinc Ore
        }
    },
    -- Outra receita
    {
        resultItemID = 12345, -- Resulting item ID
        requiredItems = {
            {itemID = 67890, count = 3}, -- ID of first required item and quantity
            {itemID = 54321, count = 1}, --Second required item ID and quantity
        }
    }
}

local ANVIL_ID = 2555 -- ID hammer for forging

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if not target or not target:isItem() then
        return true
    end
 
    local position = target:getPosition()
    if position.x == CONTAINER_POSITION then
        return true
    end

    local tile = Tile(position)
    if not tile then
        return false
    end

    local items = tile:getItems()
    if items then
        local hasAnvil = false
        local bestMatchRecipe = nil

        for _, itemOnTile in ipairs(items) do
            if itemOnTile:getId() == ANVIL_ID then
                hasAnvil = true
            end
        end

        if hasAnvil then
            for _, recipe in ipairs(recipes) do
                local requiredItemsFound = true
             
                for _, reqItem in ipairs(recipe.requiredItems) do
                    local foundCount = 0
                    for _, itemOnTile in ipairs(items) do
                        if itemOnTile:getId() == reqItem.itemID then
                            foundCount = foundCount + itemOnTile:getCount()
                        end
                    end

                    if foundCount < reqItem.count then
                        requiredItemsFound = false
                        break
                    end
                end

                if requiredItemsFound then
                    for _, reqItem in ipairs(recipe.requiredItems) do
                        local remainingCount = reqItem.count
                        for _, itemOnTile in ipairs(items) do
                            if itemOnTile:getId() == reqItem.itemID then
                                local countToRemove = math.min(remainingCount, itemOnTile:getCount())
                                itemOnTile:remove(countToRemove)
                                remainingCount = remainingCount - countToRemove
                                if remainingCount <= 0 then
                                    break
                                end
                            end
                        end
                    end

                    Game.createItem(recipe.resultItemID, recipe.count or 1, toPosition)
                    toPosition:sendMagicEffect(CONST_ME_HITBYFIRE)
                    doPlayerAddSkillTry(player:getId(), SKILL_METALWORKING, 1) -- remove line if no skill
                    local formula = (getPlayerSkill(player:getId(), SKILL_METALWORKING) / 200) + (0.85 * math.random()) -- remove line if no skill
                    return true
                end
            end
        end
    end

    return false
end

Remove last "," in the recipes, probably had it by accident cause I deleted my other recipes for this script 😅
 
Back
Top