require 'gui' local shared = require 'shared' local update_rate = shared.update_rate local update_slots = shared.update_slots local compactify = shared.compactify local validity_check = shared.validity_check local combine_tempatures = shared.combine_tempatures local function setup() global.units = global.units or {} if remote.interfaces['PickerDollies'] then remote.call('PickerDollies', 'add_blacklist_name', 'fluid-memory-unit', true) remote.call('PickerDollies', 'add_blacklist_name', 'fluid-memory-unit-combinator', true) end end script.on_init(setup) script.on_configuration_changed(function() setup() for unit_number, unit_data in pairs(global.units) do if unit_data.item and not validity_check(unit_number, unit_data) then if not game.fluid_prototypes[unit_data.item] then shared.memory_unit_corruption(unit_number, unit_data) end end end end) local min = math.min local function render_fluid_animation(item, entity) local color = game.fluid_prototypes[item].base_color rendering.draw_animation{ animation = 'fluid-memory-unit-animation', tint = { min(0.9, color.r + 0.2), min(0.9, color.g + 0.2), min(0.9, color.b + 0.2) }, render_layer = 'higher-object-above', target = entity, surface = entity.surface } end local function update_unit_exterior(unit_data, inventory_count) local entity = unit_data.entity unit_data.previous_inventory_count = inventory_count local total_count = unit_data.count + inventory_count if inventory_count > 0 then local temperature = combine_tempatures(unit_data.count, unit_data.temperature, inventory_count, entity.fluidbox[1].temperature) entity.fluidbox[1].temperature = temperature unit_data.temperature = temperature end shared.update_combinator(unit_data.combinator, {type = 'fluid', name = unit_data.item}, total_count) shared.update_display_text(unit_data, entity, compactify(total_count)) shared.update_power_usage(unit_data, total_count) end local function detect_item(unit_data) local fluidbox = unit_data.entity.fluidbox local fluid = fluidbox[1] if fluid then fluidbox.set_filter(1, {name = fluid.name, force = true}) render_fluid_animation(fluid.name, unit_data.entity) unit_data.item = fluid.name unit_data.temperature = fluid.temperature return true end return false end local function update_unit(unit_data, unit_number, force) local entity = unit_data.entity local powersource = unit_data.powersource local combinator = unit_data.combinator local container = unit_data.container if validity_check(unit_number, unit_data, force) then return end local changed = false if unit_data.item == nil then changed = detect_item(unit_data) end local item = unit_data.item if item == nil then return end local comfortable = unit_data.comfortable local inventory_count = entity.get_fluid_count(item) if inventory_count > comfortable then local amount_removed = entity.remove_fluid{name = item, amount = inventory_count - comfortable} unit_data.temperature = combine_tempatures(unit_data.count, unit_data.temperature, amount_removed, entity.fluidbox[1].temperature) unit_data.count = unit_data.count + amount_removed inventory_count = inventory_count - amount_removed changed = true elseif inventory_count < comfortable then if unit_data.previous_inventory_count ~= inventory_count then changed = true end local to_add = comfortable - inventory_count if unit_data.count < to_add then to_add = unit_data.count end if to_add ~= 0 then local amount_added = entity.insert_fluid{name = item, amount = to_add, temperature = unit_data.temperature} unit_data.count = unit_data.count - amount_added inventory_count = inventory_count + amount_added end end if force or changed then update_unit_exterior(unit_data, inventory_count) end end script.on_nth_tick(update_rate, function(event) local smooth_ups = event.tick % update_slots for unit_number, unit_data in pairs(global.units) do if unit_data.lag_id == smooth_ups then update_unit(unit_data, unit_number) end end end) local function on_created(event) local entity = event.created_entity or event.entity if entity.name ~= 'fluid-memory-unit' then return end local position = entity.position local surface = entity.surface local force = entity.force local combinator = surface.create_entity{ name = 'fluid-memory-unit-combinator', position = {position.x, position.y - 1.25}, force = force } combinator.operable = false combinator.destructible = false local powersource = surface.create_entity{ name = 'fluid-memory-unit-powersource', position = position, force = force } powersource.destructible = false local unit_data = { entity = entity, comfortable = 0.5 * entity.fluidbox.get_capacity(1), powersource = powersource, combinator = combinator, count = 0, lag_id = math.random(0, update_slots - 1) } global.units[entity.unit_number] = unit_data local stack = event.stack local tags = stack and stack.valid_for_read and stack.type == 'item-with-tags' and stack.tags if tags and tags.name then unit_data.count = tags.count unit_data.temperature = tags.temperature unit_data.item = tags.name entity.fluidbox.set_filter(1, {name = tags.name, force = true}) render_fluid_animation(tags.name, entity) update_unit(unit_data, entity.unit_number, true) else shared.update_power_usage(unit_data, 0) end end script.on_event(defines.events.on_built_entity, on_created) script.on_event(defines.events.on_robot_built_entity, on_created) script.on_event(defines.events.script_raised_built, on_created) script.on_event(defines.events.script_raised_revive, on_created) script.on_event(defines.events.on_entity_cloned, function(event) local entity = event.source if entity.name ~= 'fluid-memory-unit' then return end local destination = event.destination local unit_data = global.units[entity.unit_number] local position = destination.position local surface = destination.surface local powersource, combinator = unit_data.powersource, unit_data.combinator if powersource.valid then powersource = powersource.clone{position = position, surface = surface} else powersource = surface.create_entity{ name = 'memory-unit-powersource', position = position, force = force } powersource.destructible = false end if combinator.valid then combinator = combinator.clone{position = {position.x, position.y - 1.25}, surface = surface} else combinator = surface.create_entity{ name = 'fluid-memory-unit-combinator', position = {position.x, position.y - 1.25}, force = force } combinator.destructible = false combinator.operable = false end local item = unit_data.item global.units[destination.unit_number] = { powersource = powersource, combinator = combinator, item = item, count = unit_data.count, entity = destination, temperature = unit_data.temperature, comfortable = unit_data.comfortable, lag_id = math.random(0, update_slots - 1) } if item then render_fluid_animation(item, destination) destination.fluidbox.set_filter(1, {name = item, force = true}) update_unit(global.units[destination.unit_number], destination.unit_number, true) end end) local function on_destroyed(event) local entity = event.entity if entity.name ~= 'fluid-memory-unit' then return end local unit_data = global.units[entity.unit_number] global.units[entity.unit_number] = nil unit_data.powersource.destroy() unit_data.combinator.destroy() local item = unit_data.item local count = unit_data.count local buffer = event.buffer if buffer and item and count ~= 0 then buffer.clear() buffer.insert('fluid-memory-unit-with-tags') local stack = buffer.find_item_stack('fluid-memory-unit-with-tags') local temperature = unit_data.temperature stack.tags = {name = item, count = count, temperature = temperature} stack.custom_description = { 'item-description.fluid-memory-unit-with-tags', compactify(count), item, string.format('%.2f', temperature) } end end script.on_event(defines.events.on_player_mined_entity, on_destroyed) script.on_event(defines.events.on_robot_mined_entity, on_destroyed) script.on_event(defines.events.on_entity_died, on_destroyed) script.on_event(defines.events.script_raised_destroy, on_destroyed) local function pre_mined(event) local entity = event.entity if entity.name ~= 'fluid-memory-unit' then return end local unit_data = global.units[entity.unit_number] local item = unit_data.item if item then local in_inventory = entity.get_fluid_count(item) if in_inventory > 0 then local temperature = entity.fluidbox[1].temperature local new_count = unit_data.count + entity.remove_fluid{name = item, amount = in_inventory} unit_data.temperature = combine_tempatures(unit_data.count, unit_data.temperature, in_inventory, temperature) unit_data.count = new_count end end end script.on_event(defines.events.on_pre_player_mined_item, pre_mined) script.on_event(defines.events.on_robot_pre_mined, pre_mined) script.on_event(defines.events.on_marked_for_deconstruction, pre_mined)