I'm working on an idea for an "anvil". The idea is that, when some raw metal is placed inside, the hitpoints go to 1. Then a "hammer" tool that is actually a type of repair pack, is applied until the anvil is back to full health, and the raw metal is automatically replaced with processed metal. This would (kind of) simulate smithing: having to hammer the raw metal into shape.
But I can't find any events that get raised when a building's inventory changed. I could register a tick listener, but that seems a bit wasteful of performace to me. Is there any way to work around this?
Event when item inserted into building
-
- Inserter
- Posts: 35
- Joined: Thu Aug 02, 2018 3:02 pm
- Contact:
Re: Event when item inserted into building
There are a LOT of building inventory changes, asking the devs to add a listener would also be wasteful. So a tick listener is the best you can do.
Re: Event when item inserted into building
I think on_player_cursor_stack_changed should do pretty well, no? Check whether the player has your anvil selected and had a hammer in hand and there's one in the anvil now, then take it out and put it in hand or inventory and do the work, something along those lines?
-
- Inserter
- Posts: 35
- Joined: Thu Aug 02, 2018 3:02 pm
- Contact:
Re: Event when item inserted into building
All true. Just on_player_cursor_stack_changed won't be enough, since you can insert directly from you own inventory by ctrl + click. But I'll just listen to multiple player inventory changes and see if I can make it work like that.
Some kind of on_player_insert event would be nice perhaps, and not as wasteful as an event that also triggers on inserters. But beggars can't be choosers.
Some kind of on_player_insert event would be nice perhaps, and not as wasteful as an event that also triggers on inserters. But beggars can't be choosers.
Mod: Stone Age Factorio
Re: Event when item inserted into building
Maybe there's a way to make the anvil's gui not openable? I think that'd make the hand the only way to get things in or out.
I think I do agree with your point here, there's a player_dropped_item event and a built_entity event, maybe player_cursor_stack_changed could include the other inventory involved, where any items came from or went to?
I think I do agree with your point here, there's a player_dropped_item event and a built_entity event, maybe player_cursor_stack_changed could include the other inventory involved, where any items came from or went to?
Re: Event when item inserted into building
Here, this uses rocket silos (they've got stack size 1 for convenience here) and wooden chests as hammers and anvils,
edit: added init/load global maintenance, duh.
Code: Select all
local empty={}
local open_guis = {}
local de=defines.events
script.on_init(function() global.open_guis=open_guis end)
script.on_load(function() open_guis=global.open_guis end)
script.on_event(de.on_gui_opened, function(ev)
open_guis[ev.player_index]=(ev.entity or empty).unit_number or false
end)
script.on_event(de.on_gui_closed, function(ev)
local pidx,e = ev.player_index, ev.entity
local p = game.players[pidx]
open_guis[pidx]=false
if (e or empty).name == 'wooden-chest' then
local b,did = e.get_inventory(1), false
while b.remove'rocket-silo' == 1 do
-- the `true` parm says mark it lootable, it'll be put
-- back in player inventory if possible.
p.surface.spill_item_stack(p.position,'rocket-silo',true)
did = true
end
if did then
game.print"no no, don't place rocket silos in wooden chests gently!"
end
end
end)
script.on_event(de.on_player_cursor_stack_changed, function(ev)
local pidx,p,sel,stack
pidx = ev.player_index
p = game.players[pidx]
sel = p.selected
stack = p.cursor_stack
if (sel or empty).name ~= 'wooden-chest' then return end
if (sel or empty).unit_number == open_guis[pidx] then return end
if (stack or empty).valid_for_read
and stack.name ~= 'rocket-silo' then return end
if sel.get_inventory(1).remove'rocket-silo' == 0 then return end
-- stack changed, now has an empty hand or a rocket silo, and there
-- was a rocket silo in the chest. I conclude the player dropped
-- the rocket silo into it. Put it back in the player's hand or inventory
game.print'bang!'
if not stack.valid_for_read then
stack.set_stack'rocket-silo'
else
p.insert'rocket-silo'
end
end)
-
- Inserter
- Posts: 35
- Joined: Thu Aug 02, 2018 3:02 pm
- Contact:
Re: Event when item inserted into building
Thank you! I'll try this out and get back to you.
Mod: Stone Age Factorio
Re: Event when item inserted into building
haha, viewtopic.php?f=25&t=62712 has a much better idea for your anvil gui: just don't let players open it.
to replace the barrage of on_gui_x code above, leaving:
Code: Select all
script.on_event(de.on_gui_opened,function(ev)
if (ev.entity or {}).name=='wooden-chest' then game.players[ev.player_index].opened=nil end
end)
Code: Select all
local empty={}
local de=defines.events
script.on_event(de.on_gui_opened, function(ev)
if (ev.entity or empty).name == 'wooden-chest'
then game.players[ev.player_index].opened = nil end
end)
script.on_event(de.on_player_cursor_stack_changed, function(ev)
local pidx = ev.player_index
local p = game.players[pidx]
local sel, stack = p.selected, p.cursor_stack -- hand content changed
if (sel or empty).name == 'wooden-chest' -- over an anvil
and ( not (stack or empty).valid_for_read -- and hand's now empty
or stack.name == 'rocket-silo' ) -- or holding a hammer
and sel.get_inventory(1).remove'rocket-silo' == 1 and there's a hammer in the anvil
then -- make it so player didn't drop the hammer, player swung it.
game.print'bang!'
if stack.valid_for_read then
p.insert'rocket-silo'
else
stack.set_stack'rocket-silo'
end
end
end)
-
- Inserter
- Posts: 35
- Joined: Thu Aug 02, 2018 3:02 pm
- Contact:
Re: Event when item inserted into building
I modified it slightly and it works great! Here's my take on it (uses stdlib for the events):
It's not on the mod portal yet, but you can download the version of the mod that uses this here.
Thanks again for your help!
Code: Select all
require "stdlib/event/event"
Event.register(defines.events.on_built_entity, function(e)
if e.created_entity.name == "anvil" then
e.created_entity.set_recipe("copper-crude")
end
end)
Event.register(defines.events.on_gui_opened, function(e)
if (e.entity or {}).name == "anvil" then
game.players[e.player_index].opened = nil
game.players[e.player_index].print{"messages.anvil-cannot-be-opened"}
end
end)
Event.register(defines.events.on_player_cursor_stack_changed, function(e)
local player = game.players[e.player_index]
if (player.selected or {}).name ~= "anvil" then return end
local anvil = player.selected
local anvil_source = anvil.get_inventory(defines.inventory.assembling_machine_input)
local hammer_count = anvil_source.remove("stone-hammer")
if hammer_count == 0 then return end
-- return the hammer(s) to the player
player.insert{name = "stone-hammer", count = hammer_count}
-- update progress
local recipe = anvil.get_recipe()
anvil.crafting_progress = anvil.crafting_progress + 0.34
-- ingredients are not automatically removed when progress is artificial
-- https://forums.factorio.com/viewtopic.php?f=25&t=62727
if anvil.crafting_progress >= 1 then
for _, ingredient in ipairs(recipe.ingredients) do
anvil_source.remove{name = ingredient.name, count = ingredient.amount}
end
end
-- play hammering sound
for _, sound in ipairs(game.surfaces["nauvis"].find_entities_filtered{name="hammer-sound"}) do
sound.destroy()
end
player.surface.create_entity({
name = "hammer-sound",
position = player.position,
})
end)
Thanks again for your help!
Mod: Stone Age Factorio