Ah, you just reminded me that rocks are stackable, so actually that original script will have an undesirable result (destroying a whole stack of rocks when it should only destroy one). Here is a general solution with examples that show how to use any combination of items, and is hopefully simple enough for you to use. You would connect the surface to the forgeSurface() function:
Code: Select all
-- Check a surface for a specific combination of items.
-- surface: the surface to search.
-- itemNames: an array of strings that should correspond to the names
-- of the items you want. Duplicates are not allowed.
-- If all the items were found, an array of arrays of item
-- references is returned. The arrays of item references are
-- in the same order as the strings in itemNames, so if
-- itemNames[1] is "rock", the first array will be an array of
-- references to all rocks on the surface.
-- If not all of the items were found, false is returned.
function surfaceContains(surface,itemNames)
local found = {}
for _,item in surface:contents() do
for index,itemName in ipairs(itemNames) do
if item.go.name == itemName then
if found[index] then
table.insert(found[index],item)
else
found[index] = {item}
end
break
end
end
end
for i = 1,#itemNames do
if not found[i] then return false end
end
return found
end
-- Check a surface for eligible item combinations, and turn them
-- into a new item if any are found.
function forgeSurface(surface)
-- Example: make a boulder from 3 rocks.
local foundItems = surfaceContains(surface,{"rock"})
if foundItems then
-- We found at least one "rock" item on the surface, but
-- we still need to count the rocks and see how many we
-- have.
if countItems(foundItems[1]) >= 3 then
-- We have 3 rocks.
-- Destroy exactly 3 rocks.
destroySomeOf(foundItems[1],3)
-- Add the boulder.
surface:addItem(spawn("boulder").item)
-- We don't need to do anything else.
-- (Here is where you might add a sound,
-- special effect, etc.)
return
end
end
-- Example 2: make a spiked club from 2 rocks, 3 branches,
-- and a warhammer.
-- Note: since Example 1 is checked first, and uses 3 rocks,
-- if there are 3 rocks on the altar then a boulder will
-- always be created from them, even if there are enough
-- items to make a spiked club instead. To prevent this, you
-- can easily just switch the order.
local foundItems = surfaceContains(surface,{"rock","branch","warhammer"})
if foundItems then
-- We found at least one "rock" item on the surface, but
-- we still need to count the rocks and see how many we
-- have.
local rocks = countItems(foundItems[1]) >= 2
-- Branches are NOT stackable items. Therefore, the number
-- of elements in the array will always be the number of
-- branches; we do not need countItems().
local branches = #foundItems[2] >= 3
-- We only wanted 1 warhammer, so we don't need any extra
-- checks: surfaceContains would have returned false in
-- the first place if there were no warhammers at all.
if rocks and branches then
-- Destroy exactly 2 rocks.
destroySomeOf(foundItems[1],2)
-- Destroy exactly 3 branches.
destroySomeOf(foundItems[2],3)
-- Destroy exactly 1 warhammer.
destroySomeOf(foundItems[3],1)
-- Add the club.
surface:addItem(spawn("spiked_club").item)
-- We don't need to do anything else.
-- (Here is where you might add a sound,
-- special effect, etc.)
return
end
end
end
-- Count the items in an array.
-- items: array of items to be counted
-- Returns the total number of items in the array, accounting for
-- stack size, so an array of one rock object with a stack size
-- of 3 would return 3.
function countItems(items)
local total = 0
for _,item in ipairs(items) do
total = total+item:getStackSize()
end
return total
end
-- Destroy some of the items in an array. Items appearing
-- later in the array will be destroyed first.
-- items: array of items to be destroyed
-- quantity: number of items to destroy
-- Returns true if the requested number of items was destroyed,
-- false if the array did not contain enough items to satisfy the
-- quantity (all the items in the array were still destroyed).
function destroySomeOf(items,quantity)
local destroyed = 0
for i = #items,1,-1 do
local diff = quantity-destroyed
local item = items[i]
if diff < item:getStackSize() then
item:setStackSize(item:getStackSize()-diff)
return true
else
destroyed = destroyed+item:getStackSize()
item.go:destroy()
end
if quantity == destroyed then return true end
end
return false
end