240 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			240 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
--[Helper Functions]--
 | 
						|
-- Currently mostly picker specific with plans to flesh out and add to appropriate places
 | 
						|
 | 
						|
local lib = {}
 | 
						|
local Area = require('__stdlib__/stdlib/area/area')
 | 
						|
local Position = require('__stdlib__/stdlib/area/position')
 | 
						|
 | 
						|
function lib.get_or_create_main_left_flow(player, flow_name)
 | 
						|
    local main_flow = player.gui.left[flow_name .. '_main_flow']
 | 
						|
    if not main_flow then
 | 
						|
        main_flow =
 | 
						|
            player.gui.left.add {
 | 
						|
            type = 'flow',
 | 
						|
            name = flow_name .. '_main_flow',
 | 
						|
            direction = 'vertical',
 | 
						|
            style = 'slot_table_spacing_vertical_flow'
 | 
						|
        }
 | 
						|
        main_flow.style.top_padding = 4
 | 
						|
        main_flow.style.right_padding = 0
 | 
						|
        main_flow.style.left_padding = 0
 | 
						|
        main_flow.style.bottom_padding = 0
 | 
						|
    end
 | 
						|
    return main_flow
 | 
						|
end
 | 
						|
 | 
						|
lib.ghosts = {
 | 
						|
    ['entity-ghost'] = true,
 | 
						|
    ['tile-ghost'] = true
 | 
						|
}
 | 
						|
 | 
						|
--Return localised name, entity_prototype, and item_prototype
 | 
						|
function lib.get_placeable_item(entity)
 | 
						|
    local locname, ep
 | 
						|
    if entity.name == 'entity-ghost' or entity.name == 'tile-ghost' then
 | 
						|
        locname = entity.ghost_localised_name
 | 
						|
        ep = entity.ghost_prototype
 | 
						|
    else
 | 
						|
        locname = entity.localised_name
 | 
						|
        ep = entity.prototype
 | 
						|
    end
 | 
						|
    if ep and ep.mineable_properties and ep.mineable_properties.minable and ep.mineable_properties.products and ep.mineable_properties.products[1].type == 'item' then -- If the entity has mineable products.
 | 
						|
        local ip = game.item_prototypes[ep.mineable_properties.products[1].name] -- Retrieve first available item prototype
 | 
						|
        if ip and (ip.place_result or ip.place_as_tile_result) then -- If the entity has an item with a placeable prototype,
 | 
						|
            return (ip.localised_name or locname), ep, ip
 | 
						|
        end
 | 
						|
        return locname, ep
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
function lib.stack_is_ghost(stack, ghost)
 | 
						|
    if ghost.name == 'entity-ghost' then
 | 
						|
        return stack.prototype.place_result and stack.prototype.place_result.name == ghost.ghost_name
 | 
						|
    elseif ghost.name == 'tile-ghost' then
 | 
						|
        return stack.prototype.place_as_tile_result and stack.prototype.place_as_tile_result.result.name == ghost.ghost_name
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
function lib.find_resources(entity)
 | 
						|
    if entity.type == 'mining-drill' then
 | 
						|
        local area = Position.expand_to_area(entity.position, game.entity_prototypes[entity.name].mining_drill_radius)
 | 
						|
        local name = entity.mining_target and entity.mining_target.name or nil
 | 
						|
        return entity.surface.count_entities_filtered {area = area, type = 'resource', name = name}
 | 
						|
    end
 | 
						|
    return 0
 | 
						|
end
 | 
						|
 | 
						|
function lib.get_item_stack(e, name, give_free)
 | 
						|
    local stack = e.get_main_inventory().find_item_stack(name)
 | 
						|
    if stack then
 | 
						|
        return stack
 | 
						|
    end
 | 
						|
    if e.vehicle then
 | 
						|
        local trunk = e.vehicle.get_inventory(defines.inventory.car_trunk)
 | 
						|
        stack = trunk and trunk.find_item_stack(name)
 | 
						|
        if stack then
 | 
						|
            return stack
 | 
						|
        end
 | 
						|
    end
 | 
						|
    if e.is_player() and (e.cheat_mode or give_free) then
 | 
						|
        local inv = lib.create_buffer_corpse(e).get_inventory(defines.inventory.character_corpse)
 | 
						|
        if inv[1].set_stack(name) then
 | 
						|
            return inv[1]
 | 
						|
        end
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
function lib.create_buffer_corpse(player, inf)
 | 
						|
    return player.surface.create_entity {
 | 
						|
        name = 'picker-buffer-corpse-' .. (inf and 'inf' or 'instant'),
 | 
						|
        position = {0, 0},
 | 
						|
        force = player.force,
 | 
						|
        inventory_size = 1,
 | 
						|
        player_index = player.index
 | 
						|
    }
 | 
						|
end
 | 
						|
 | 
						|
-- Attempt to insert an item_stack or array of item_stacks into the entity
 | 
						|
-- Spill to the ground at the entity/player anything that doesn't get inserted
 | 
						|
-- @param entity: the entity or player object
 | 
						|
-- @param item_stacks: a SimpleItemStack or array of SimpleItemStacks to insert
 | 
						|
-- @return bool : there was some items inserted or spilled
 | 
						|
function lib.insert_or_spill_items(entity, item_stacks)
 | 
						|
    local new_stacks = {}
 | 
						|
    if item_stacks then
 | 
						|
        if item_stacks[1] and item_stacks[1].name then
 | 
						|
            new_stacks = item_stacks
 | 
						|
        elseif item_stacks and item_stacks.name then
 | 
						|
            new_stacks = {item_stacks}
 | 
						|
        end
 | 
						|
        for _, stack in pairs(new_stacks) do
 | 
						|
            local name, count, health = stack.name, stack.count, stack.health or 1
 | 
						|
            if game.item_prototypes[name] and not game.item_prototypes[name].has_flag('hidden') and stack.count > 0 then
 | 
						|
                local inserted = entity.insert {name = name, count = count, health = health}
 | 
						|
                if inserted ~= count then
 | 
						|
                    entity.surface.spill_item_stack(entity.position, {name = name, count = count - inserted, health = health}, true)
 | 
						|
                end
 | 
						|
            end
 | 
						|
        end
 | 
						|
        return new_stacks[1] and new_stacks[1].name and true
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
function lib.satisfy_requests(player, proxy)
 | 
						|
    local entity
 | 
						|
 | 
						|
    if proxy.name == 'item-request-proxy' then
 | 
						|
        entity = proxy.proxy_target
 | 
						|
    elseif Area(proxy.selection_box):size() > 0 then
 | 
						|
        proxy =
 | 
						|
            proxy.surface.find_entities_filtered {
 | 
						|
            name = 'item-request-proxy',
 | 
						|
            area = proxy.selection_box
 | 
						|
        }[1]
 | 
						|
        entity = proxy and proxy.proxy_target
 | 
						|
    end
 | 
						|
 | 
						|
    if proxy and entity then
 | 
						|
        local pinv = player.get_main_inventory()
 | 
						|
        local new_requests = {}
 | 
						|
        local pos = Position.increment(entity.position, 0, -0.35)
 | 
						|
        for name, count in pairs(proxy.item_requests) do
 | 
						|
            local removed = player.cheat_mode and count or (entity and entity.can_insert(name) and pinv.remove({name = name, count = count})) or 0
 | 
						|
            if removed > 0 then
 | 
						|
                entity.insert({name = name, count = removed})
 | 
						|
                local txt = {'', -removed, ' ', {'item-name.' .. name}, ' (' .. player.get_item_count(name) .. ')'}
 | 
						|
                player.create_local_flying_text {
 | 
						|
                    text = txt,
 | 
						|
                    position = pos(),
 | 
						|
                    color = defines.color.white
 | 
						|
                }
 | 
						|
            end
 | 
						|
            local balance = count - removed
 | 
						|
            new_requests[name] = balance > 0 and balance or nil
 | 
						|
        end
 | 
						|
        proxy.item_requests = new_requests
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
function lib.get_planner(player, planner, label)
 | 
						|
    local found
 | 
						|
    local inventory = player.get_main_inventory()
 | 
						|
    for i = 1, #inventory do
 | 
						|
        local slot = inventory[i]
 | 
						|
        if slot.valid_for_read then
 | 
						|
            if slot.name == planner then
 | 
						|
                if slot.is_blueprint then
 | 
						|
                    if not slot.is_blueprint_setup() then
 | 
						|
                        found = slot
 | 
						|
                    elseif (label and slot.is_blueprint_setup() and slot.label and slot.label:find(label)) then
 | 
						|
                        if player.cursor_stack.swap_stack(slot) then
 | 
						|
                            return player.cursor_stack
 | 
						|
                        end
 | 
						|
                    end
 | 
						|
                elseif game.item_prototypes[planner] then
 | 
						|
                    if player.cursor_stack.swap_stack(slot) then
 | 
						|
                        return player.cursor_stack
 | 
						|
                    end
 | 
						|
                end
 | 
						|
            elseif planner == 'repair-tool' and slot.type == 'repair-tool' then
 | 
						|
                if player.cursor_stack.swap_stack(slot) then
 | 
						|
                    return player.cursor_stack
 | 
						|
                end
 | 
						|
            end
 | 
						|
        end
 | 
						|
    end
 | 
						|
    if found and player.cursor_stack.swap_stack(found) then
 | 
						|
        return player.cursor_stack
 | 
						|
    else
 | 
						|
        return planner and game.item_prototypes[planner] and player.cursor_stack.set_stack(planner) and player.cursor_stack
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
local function _matches_options(slot, options)
 | 
						|
    local matches = false
 | 
						|
    if options.is_blueprint_setup then
 | 
						|
        matches = slot.is_blueprint and slot.is_blueprint_setup()
 | 
						|
    end
 | 
						|
    if options.is_blueprint_not_setup then
 | 
						|
        matches = slot.is_blueprint and not slot.is_blueprint_setup()
 | 
						|
    end
 | 
						|
    if options.label then
 | 
						|
        matches = slot.is_item_with_label and slot.label and slot.label:find(options.label)
 | 
						|
    end
 | 
						|
    if options.is_deconstruction_setup then
 | 
						|
        matches = slot.is_deconstruction_item and (#slot.entity_filters > 0 or #slot.tile_filters > 0)
 | 
						|
    end
 | 
						|
    if options.is_deconstruction_not_setup then
 | 
						|
        matches = slot.is_deconstruction_item and (#slot.entity_filters == 0 and #slot.tile_filters == 0)
 | 
						|
    end
 | 
						|
    return matches
 | 
						|
end
 | 
						|
 | 
						|
-- Return the "inventory slot" where the item is found
 | 
						|
function lib.find_item_in_inventory(item_name, inventory, options)
 | 
						|
    options = options or {}
 | 
						|
    local found
 | 
						|
 | 
						|
    for i = 1, #inventory, 1 do
 | 
						|
        local slot = inventory[i]
 | 
						|
        if slot.valid_for_read and slot.name == item_name and (not options or _matches_options(slot, options)) then
 | 
						|
            found = slot
 | 
						|
            break
 | 
						|
        end
 | 
						|
    end
 | 
						|
    if found then
 | 
						|
        return found
 | 
						|
    end
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
function lib.set_or_swap_item(player, slot, item, set)
 | 
						|
    if type(item) == "string" then
 | 
						|
        return (set and slot.set_stack(item)) or (player.clear_cursor() and slot.set_stack(item))
 | 
						|
    end
 | 
						|
    return item and ((set and slot.set_stack(item)) or (player.clear_cursor() and slot.swap_stack(item) or slot.set_stack(item)))
 | 
						|
end
 | 
						|
 | 
						|
 | 
						|
return lib
 |