diff --git a/locale/en/mtn_fortress_v3.cfg b/locale/en/mtn_fortress_v3.cfg index 24b90739..e0647891 100644 --- a/locale/en/mtn_fortress_v3.cfg +++ b/locale/en/mtn_fortress_v3.cfg @@ -1,7 +1,7 @@ [mountain_fortress_v3] map_info_main_caption=M O U N T A I N F O R T R E S S V3 map_info_sub_caption= ~~ diggy diggy rocky rocky ~~ -map_info_text=[color=red][img=utility/danger_icon] READ THIS! [img=utility/danger_icon]\nIf there are any code bugs or desyncs. Please report asap to @Gerkiz!\nIf there are any game breaking bugs then this map might be shutdown to hot-fix the issue.[/color]\n\nCheck out the [img=utility/custom_tag_icon] for information regarding on how one can win the game!\nCompleting/winning the map increases the difficulty (damage/health).\n\nThe biters have caught the scent of fish in the cargo wagon.\nGuide the choo into the mountain and protect it as long as possible!\nThis however will not be an easy task,\nsince their strength and numbers increase over time.\n\nIn addition, the southern grounds collapse over time.\n\nDelve deep for greater treasures, but also face increased dangers.\nMining productivity research will overhaul your mining equipment, increasing the size of your backpack.\n\nAs you dig, you will encounter impassable dark chasms or rivers.\nArtillery will try to shoot you down! Dig fast, dig north!\n\nSome explosives may cause rocks to fall down the mountain, filling the void, creating new ways.\nAll they need is a container and a well aimed shot.\n\nEnter the cargo wagon to reveal the wagon surface!\n\nRandom buildings that generate resources can be found throughout the world.\n\nPlacing steel-chests near cargo-wagons enables you to quickly move content.\n\nStaying inside the train aura prevents biters from spawning when mining entities.\n\nRadars cannot be built near each other.\n\nRPG GUI is disabled inside the train.\n\nDisconnecting wagons is disabled.\nYou can't cancel crafting when standing inside the train aura.\n\nDon't try to run north with your Spidertron if the train is not near you.\nYou have been warned.\n\nMining drills have great mining-bonus which also is increased after each research, use them when you can!\n\nThe mystical chest in the locomotive offers some rewards.\nOne must feed the chest to receive such rewards.\n\nGood luck on your journey! +map_info_text=[color=red][img=utility/danger_icon] READ THIS! [img=utility/danger_icon]\nIf there are any code bugs or desyncs. Please report asap to @Gerkiz!\nIf there are any game breaking bugs then this map might be shutdown to hot-fix the issue.[/color]\n\nCheck out the [img=utility/custom_tag_icon] for information regarding on how one can win the game!\nCompleting/winning the map increases the difficulty (damage/health).\n\nTo link a chest within the locomotive place a iron or steel chest.\nThen open the chest and press the button in the top right.\n\nThe biters have caught the scent of fish in the cargo wagon.\nGuide the choo into the mountain and protect it as long as possible!\nThis however will not be an easy task,\nsince their strength and numbers increase over time.\n\nIn addition, the southern grounds collapse over time.\n\nDelve deep for greater treasures, but also face increased dangers.\nMining productivity research will overhaul your mining equipment, increasing the size of your backpack.\n\nAs you dig, you will encounter impassable dark chasms or rivers.\nArtillery will try to shoot you down! Dig fast, dig north!\n\nSome explosives may cause rocks to fall down the mountain, filling the void, creating new ways.\nAll they need is a container and a well aimed shot.\n\nEnter the cargo wagon to reveal the wagon surface!\n\nRandom buildings that generate resources can be found throughout the world.\n\nPlacing steel-chests near cargo-wagons enables you to quickly move content.\n\nStaying inside the train aura prevents biters from spawning when mining entities.\n\nRadars cannot be built near each other.\n\nRPG GUI is disabled inside the train.\n\nDisconnecting wagons is disabled.\nYou can't cancel crafting when standing inside the train aura.\n\nDon't try to run north with your Spidertron if the train is not near you.\nYou have been warned.\n\nMining drills have great mining-bonus which also is increased after each research, use them when you can!\n\nThe mystical chest in the locomotive offers some rewards.\nOne must feed the chest to receive such rewards.\n\nGood luck on your journey! [breached_wall] collapse_start=[color=blue]Mapkeeper:[/color]\nWarning, Collapse has begun! @@ -139,6 +139,7 @@ win_conditions=Win conditions rounds_survived=[font=default-bold]Rounds survived: [/font] zone=[font=default-bold]Breach zones: [/font] wave=[font=default-bold]Survive until wave: [/font] +linked=[font=default-bold]Convert chests to linked: [/font] mystical_chest=[font=default-bold]Feeding the hungry chest: [/font] enemies_killed=[font=default-bold]Enemies killed: [/font] launch_rockets=[font=default-bold]Rockets launched: [/font] @@ -155,6 +156,7 @@ locomotive_market_xp_points=[font=default-bold]XP points from market: [/font] rounds_survived_tooltip=Winning the game increases this number by 1.\nThis number resets as of now each month. zone_tooltip=Complete this objective by breaching/moving forward until you've reached the given zone. wave_tooltip=Complete this objective by surviving until the given wave. +linked_tooltip=Complete this objective by converting the given amount of chests to linked chests. production_tooltip=Complete this objective by producing the given item(s). locomotive_tooltip=Complete this objective by purchasing the following item X times. time_until_attack_tooltip=Time in either minutes or seconds until the biters attack. diff --git a/maps/mountain_fortress_v3/core.lua b/maps/mountain_fortress_v3/core.lua index 9dd5ae5f..d567f494 100644 --- a/maps/mountain_fortress_v3/core.lua +++ b/maps/mountain_fortress_v3/core.lua @@ -24,7 +24,6 @@ Public.surface = require 'maps.mountain_fortress_v3.surface' Public.traps = require 'maps.mountain_fortress_v3.traps' Public.defense_system = require 'maps.mountain_fortress_v3.locomotive.defense_system' Public.friendly_pet = require 'maps.mountain_fortress_v3.locomotive.friendly_pet' -Public.linked_chests = require 'maps.mountain_fortress_v3.locomotive.linked_chests' Public.market = require 'maps.mountain_fortress_v3.locomotive.market' Public.permission_groups = require 'maps.mountain_fortress_v3.locomotive.permission_groups' Public.spawn_locomotive = require 'maps.mountain_fortress_v3.locomotive.spawn_locomotive' diff --git a/maps/mountain_fortress_v3/gui.lua b/maps/mountain_fortress_v3/gui.lua index 20019d65..dedace3b 100644 --- a/maps/mountain_fortress_v3/gui.lua +++ b/maps/mountain_fortress_v3/gui.lua @@ -156,15 +156,6 @@ local function create_main_frame(player) line.style.left_padding = 4 line.style.right_padding = 4 - label = frame.add({type = 'label', caption = ' ', name = 'chest_upgrades'}) - label.style.font_color = {r = 0.88, g = 0.88, b = 0.88} - label.style.font = 'default-bold' - label.style.right_padding = 4 - - line = frame.add({type = 'line', direction = 'vertical'}) - line.style.left_padding = 4 - line.style.right_padding = 4 - label = frame.add({type = 'label', caption = ' ', name = 'defense_enabled'}) label.style.font_color = {r = 0.88, g = 0.88, b = 0.88} label.style.font = 'default-bold' @@ -532,9 +523,6 @@ function Public.update_gui(player) gui.train_upgrade_contribution.caption = ' [img=entity.locomotive]: ' .. train_upgrade_contribution .. 'k' gui.train_upgrade_contribution.tooltip = ({'gui.train_upgrade_contribution'}) - gui.chest_upgrades.caption = ' [img=entity.steel-chest]: ' .. format_number(upgrades.chests_outside_upgrades, true) - gui.chest_upgrades.tooltip = ({'gui.chest_placed'}) - local robotics_deployed = Public.get('robotics_deployed') if robotics_deployed then diff --git a/maps/mountain_fortress_v3/icw/functions.lua b/maps/mountain_fortress_v3/icw/functions.lua index 5f056dff..e6b11645 100644 --- a/maps/mountain_fortress_v3/icw/functions.lua +++ b/maps/mountain_fortress_v3/icw/functions.lua @@ -17,7 +17,7 @@ local fallout_width = 64 local fallout_debris = {} for x = fallout_width * -1 - 42, fallout_width + 42, 1 do - if x < -31 or x > 31 then + if x < -42 or x > 42 then for y = fallout_width * -1 - 42, fallout_width + 42, 1 do local position = {x = x, y = y} local fallout = sqrt(position.x ^ 2 + position.y ^ 2) @@ -29,6 +29,84 @@ for x = fallout_width * -1 - 42, fallout_width + 42, 1 do end local size_of_debris = #fallout_debris +local add_chests_to_wagon_token = + Token.register( + function(data) + local wagon = data.wagon + local surface = data.surface + local wagon_areas = ICW.get('wagon_areas') + local cargo_wagon = wagon_areas['cargo-wagon'] + local position1 = {cargo_wagon.left_top.x + 4, cargo_wagon.left_top.y + 1} + local position2 = {cargo_wagon.right_bottom.x - 5, cargo_wagon.left_top.y + 1} + local position3 = {cargo_wagon.left_top.x + 4, cargo_wagon.right_bottom.y - 2} + local position4 = {cargo_wagon.right_bottom.x - 5, cargo_wagon.right_bottom.y - 2} + + local left_1 = LinkedChests.add(surface, position1, 'player', 'wagon_' .. wagon.entity.unit_number .. '_1') + left_1.destructible = false + left_1.minable = false + + local left_2 = LinkedChests.add(surface, {position1[1] - 1, position1[2]}, 'player', 'wagon_' .. wagon.entity.unit_number .. '_2') + left_2.destructible = false + left_2.minable = false + + local left_3 = LinkedChests.add(surface, {position1[1] - 2, position1[2]}, 'player', 'wagon_' .. wagon.entity.unit_number .. '_3') + left_3.destructible = false + left_3.minable = false + + local left_4 = LinkedChests.add(surface, {position1[1] - 3, position1[2]}, 'player', 'wagon_' .. wagon.entity.unit_number .. '_4') + left_4.destructible = false + left_4.minable = false + + local right_1 = LinkedChests.add(surface, position2, 'player', 'wagon_' .. wagon.entity.unit_number .. '_5') + right_1.destructible = false + right_1.minable = false + + local right_2 = LinkedChests.add(surface, {position2[1] + 1, position2[2]}, 'player', 'wagon_' .. wagon.entity.unit_number .. '_6') + right_2.destructible = false + right_2.minable = false + + local right_3 = LinkedChests.add(surface, {position2[1] + 2, position2[2]}, 'player', 'wagon_' .. wagon.entity.unit_number .. '_7') + right_3.destructible = false + right_3.minable = false + + local right_4 = LinkedChests.add(surface, {position2[1] + 3, position2[2]}, 'player', 'wagon_' .. wagon.entity.unit_number .. '_8') + right_4.destructible = false + right_4.minable = false + + local bottom_left_1 = LinkedChests.add(surface, position3, 'player', 'wagon_' .. wagon.entity.unit_number .. '_9') + bottom_left_1.destructible = false + bottom_left_1.minable = false + + local bottom_left_2 = LinkedChests.add(surface, {position3[1] - 1, position3[2]}, 'player', 'wagon_' .. wagon.entity.unit_number .. '_10') + bottom_left_2.destructible = false + bottom_left_2.minable = false + + local bottom_left_3 = LinkedChests.add(surface, {position3[1] - 2, position3[2]}, 'player', 'wagon_' .. wagon.entity.unit_number .. '_11') + bottom_left_3.destructible = false + bottom_left_3.minable = false + + local bottom_left_4 = LinkedChests.add(surface, {position3[1] - 3, position3[2]}, 'player', 'wagon_' .. wagon.entity.unit_number .. '_12') + bottom_left_4.destructible = false + bottom_left_4.minable = false + + local bottom_right_1 = LinkedChests.add(surface, position4, 'player', 'wagon_' .. wagon.entity.unit_number .. '_13') + bottom_right_1.destructible = false + bottom_right_1.minable = false + + local bottom_right_2 = LinkedChests.add(surface, {position4[1] + 1, position4[2]}, 'player', 'wagon_' .. wagon.entity.unit_number .. '_14') + bottom_right_2.destructible = false + bottom_right_2.minable = false + + local bottom_right_3 = LinkedChests.add(surface, {position4[1] + 2, position4[2]}, 'player', 'wagon_' .. wagon.entity.unit_number .. '_15') + bottom_right_3.destructible = false + bottom_right_3.minable = false + + local bottom_right_4 = LinkedChests.add(surface, {position4[1] + 3, position4[2]}, 'player', 'wagon_' .. wagon.entity.unit_number .. '_16') + bottom_right_4.destructible = false + bottom_right_4.minable = false + end +) + local reconstruct_all_trains = Token.register( function(data) @@ -178,33 +256,6 @@ local function divide_fluid(wagon, storage_tank) equal_fluid(storage_tank, fluid_wagon) end -local function input_filtered(wagon_inventory, chest, chest_inventory, free_slots) - local request_stacks = {} - local prototypes = game.item_prototypes - for slot_index = 1, 30, 1 do - local stack = chest.get_request_slot(slot_index) - if stack then - request_stacks[stack.name] = 10 * prototypes[stack.name].stack_size - end - end - if wagon_inventory.supports_bar() then - for i = 1, wagon_inventory.get_bar() - 1, 1 do - if free_slots <= 0 then - return - end - local stack = wagon_inventory[i] - if stack.valid_for_read then - local request_stack = request_stacks[stack.name] - if request_stack and request_stack > chest_inventory.get_item_count(stack.name) then - chest_inventory.insert(stack) - stack.clear() - free_slots = free_slots - 1 - end - end - end - end -end - function Public.disable_auto_minimap() local icw = ICW.get() @@ -344,75 +395,8 @@ function Public.hazardous_debris() end end -local function input_cargo(wagon, chest, wagon_inventory, chest_inventory) - if not chest.request_from_buffers then - goto continue - end - - local wagon_entity = wagon.entity - if not validate_entity(wagon_entity) then - wagon.transfer_entities = nil - goto continue - end - - if wagon_inventory.is_empty() then - goto continue - end - - local free_slots = 0 - if chest_inventory.supports_bar() then - for i = 1, chest_inventory.get_bar() - 1, 1 do - if not chest_inventory[i].valid_for_read then - free_slots = free_slots + 1 - end - end - end - - if chest.get_request_slot(1) then - input_filtered(wagon_inventory, chest, chest_inventory, free_slots) - goto continue - end - - if wagon_inventory.supports_bar() then - for i = 1, wagon_inventory.get_bar() - 1, 1 do - if free_slots <= 0 then - goto continue - end - if wagon_inventory[i].valid_for_read then - chest_inventory.insert(wagon_inventory[i]) - wagon_inventory[i].clear() - free_slots = free_slots - 1 - end - end - end - - ::continue:: -end - -local function output_cargo(wagon, passive_chest, chest2, chest1) - if not validate_entity(wagon.entity) then - goto continue - end - - if not passive_chest.valid then - goto continue - end - for i = 1, #chest1 do - local t = chest1[i] - if t and t.valid then - local c = chest2.insert(t) - if (c > 0) then - chest1[i].count = chest1[i].count - c - end - end - end - ::continue:: -end - local transfer_functions = { - ['storage-tank'] = divide_fluid, - ['logistic-chest-requester'] = input_cargo, - ['logistic-chest-passive-provider'] = output_cargo + ['storage-tank'] = divide_fluid } local function get_wagon_for_entity(icw, entity) @@ -652,253 +636,7 @@ function Public.create_wagon_room(icw, wagon) end if wagon.entity.type == 'cargo-wagon' then - local multiple_chests = ICW.get('multiple_chests') - local wagon_areas = ICW.get('wagon_areas') - local cargo_wagon = wagon_areas['cargo-wagon'] - local position1 = {cargo_wagon.left_top.x + 4, cargo_wagon.left_top.y + 1} - local position2 = {cargo_wagon.right_bottom.x - 5, cargo_wagon.left_top.y + 1} - local position3 = {cargo_wagon.left_top.x + 4, cargo_wagon.right_bottom.y - 2} - local position4 = {cargo_wagon.right_bottom.x - 5, cargo_wagon.right_bottom.y - 2} - - if multiple_chests then - local left_1 = - surface.create_entity( - { - name = 'logistic-chest-requester', - position = position1, - force = 'neutral', - create_build_effect_smoke = false - } - ) - left_1.destructible = false - left_1.minable = false - - local left_2 = - surface.create_entity( - { - name = 'logistic-chest-requester', - position = {position1[1] - 1, position1[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - left_2.destructible = false - left_2.minable = false - - local left_3 = - surface.create_entity( - { - name = 'logistic-chest-requester', - position = {position1[1] - 2, position1[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - left_3.destructible = false - left_3.minable = false - - local left_4 = - surface.create_entity( - { - name = 'logistic-chest-requester', - position = {position1[1] - 3, position1[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - left_4.destructible = false - left_4.minable = false - - local right_1 = - surface.create_entity( - { - name = 'logistic-chest-passive-provider', - position = position2, - force = 'neutral', - create_build_effect_smoke = false - } - ) - right_1.destructible = false - right_1.minable = false - - local right_2 = - surface.create_entity( - { - name = 'logistic-chest-passive-provider', - position = {position2[1] + 1, position2[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - right_2.destructible = false - right_2.minable = false - - local right_3 = - surface.create_entity( - { - name = 'logistic-chest-passive-provider', - position = {position2[1] + 2, position2[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - right_3.destructible = false - right_3.minable = false - - local right_4 = - surface.create_entity( - { - name = 'logistic-chest-passive-provider', - position = {position2[1] + 3, position2[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - right_4.destructible = false - right_4.minable = false - - local bottom_left_1 = - surface.create_entity( - { - name = 'logistic-chest-requester', - position = position3, - force = 'neutral', - create_build_effect_smoke = false - } - ) - bottom_left_1.destructible = false - bottom_left_1.minable = false - - local bottom_left_2 = - surface.create_entity( - { - name = 'logistic-chest-requester', - position = {position3[1] - 1, position3[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - bottom_left_2.destructible = false - bottom_left_2.minable = false - - local bottom_left_3 = - surface.create_entity( - { - name = 'logistic-chest-requester', - position = {position3[1] - 2, position3[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - bottom_left_3.destructible = false - bottom_left_3.minable = false - - local bottom_left_4 = - surface.create_entity( - { - name = 'logistic-chest-requester', - position = {position3[1] - 3, position3[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - bottom_left_4.destructible = false - bottom_left_4.minable = false - - local bottom_right_1 = - surface.create_entity( - { - name = 'logistic-chest-passive-provider', - position = position4, - force = 'neutral', - create_build_effect_smoke = false - } - ) - bottom_right_1.destructible = false - bottom_right_1.minable = false - - local bottom_right_2 = - surface.create_entity( - { - name = 'logistic-chest-passive-provider', - position = {position4[1] + 1, position4[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - bottom_right_2.destructible = false - bottom_right_2.minable = false - - local bottom_right_3 = - surface.create_entity( - { - name = 'logistic-chest-passive-provider', - position = {position4[1] + 2, position4[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - bottom_right_3.destructible = false - bottom_right_3.minable = false - - local bottom_right_3 = - surface.create_entity( - { - name = 'logistic-chest-passive-provider', - position = {position4[1] + 2, position4[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - bottom_right_3.destructible = false - bottom_right_3.minable = false - - local bottom_right_4 = - surface.create_entity( - { - name = 'logistic-chest-passive-provider', - position = {position4[1] + 3, position4[2]}, - force = 'neutral', - create_build_effect_smoke = false - } - ) - bottom_right_4.destructible = false - bottom_right_4.minable = false - - wagon.transfer_entities = {left_1, right_1} - wagon.transfer_entities = {left_2, right_2} - wagon.transfer_entities = {left_3, right_3} - wagon.transfer_entities = {left_4, right_4} - wagon.transfer_entities = {bottom_left_1, bottom_right_1} - wagon.transfer_entities = {bottom_left_2, bottom_right_2} - wagon.transfer_entities = {bottom_left_3, bottom_right_3} - wagon.transfer_entities = {bottom_left_4, bottom_right_4} - else - local e1 = - surface.create_entity( - { - name = 'logistic-chest-requester', - position = position1, - force = 'neutral', - create_build_effect_smoke = false - } - ) - e1.destructible = false - e1.minable = false - - local e2 = - surface.create_entity( - { - name = 'logistic-chest-passive-provider', - position = position2, - force = 'neutral', - create_build_effect_smoke = false - } - ) - e2.destructible = false - e2.minable = false - wagon.transfer_entities = {e1, e2} - end + Task.set_timeout_in_ticks(5, add_chests_to_wagon_token, {wagon = wagon, surface = surface}) end end @@ -1118,12 +856,6 @@ local function move_room_to_train(icw, train, wagon) for _, e in pairs(wagon.surface.find_entities_filtered({type = 'electric-pole', area = wagon.area})) do connect_power_pole(e, left_top_y) end - - for _, e in pairs(wagon.surface.find_entities_filtered({area = wagon.area, force = 'neutral'})) do - if transfer_functions[e.name] then - wagon.transfer_entities[#wagon.transfer_entities + 1] = e - end - end end local function get_connected_rolling_stock(entity, direction, carriages) @@ -1244,18 +976,15 @@ function Public.item_transfer() local icw = ICW.get() local wagon icw.current_wagon_index, wagon = next(icw.wagons, icw.current_wagon_index) - if not wagon or not wagon.entity or not wagon.entity.valid or not wagon.transfer_entities then + if not wagon then return end - - local wagon_inventory = wagon.entity.get_inventory(defines.inventory.cargo_wagon) - for i = 1, #wagon.transfer_entities do - local chest = wagon.transfer_entities[i] - if not chest or not chest.valid then - break + if validate_entity(wagon.entity) and wagon.transfer_entities then + for _, e in pairs(wagon.transfer_entities) do + if validate_entity(e) then + transfer_functions[e.name](wagon, e) + end end - local chest_inventory = chest.get_inventory(defines.inventory.chest) - transfer_functions[chest.name](wagon, chest, wagon_inventory, chest_inventory) end end @@ -1388,6 +1117,10 @@ function Public.on_player_or_robot_built_tile(event) end end +function Public.on_entity_cloned(source, destination) + LinkedChests.migrate(source, destination) +end + Public.get_player_data = get_player_data return Public diff --git a/maps/mountain_fortress_v3/icw/linked_chests.lua b/maps/mountain_fortress_v3/icw/linked_chests.lua index 302a9e84..e87a00a2 100644 --- a/maps/mountain_fortress_v3/icw/linked_chests.lua +++ b/maps/mountain_fortress_v3/icw/linked_chests.lua @@ -5,20 +5,25 @@ local Gui = require 'utils.gui' local Task = require 'utils.task' local Token = require 'utils.token' local Where = require 'utils.commands.where' +local Math2D = require 'math2d' +local WPT = require 'maps.mountain_fortress_v3.table' +local Session = require 'utils.datastore.session_data' +local AG = require 'utils.antigrief' +local Discord = require 'utils.discord_handler' local this = { main_containers = {}, - inf_gui = {}, + linked_gui = {}, valid_chests = { ['linked-chest'] = true, - ['iron-chest'] = true, - ['steel-chest'] = true + ['steel-chest'] = true, + ['iron-chest'] = true }, enabled = true, - editor = {}, + uid_counter = 0, disable_normal_placement = true, - debug = false, - cost_to_convert = 200 + converted_chests = 0, + cost_to_convert = 500 } local chest_converter_frame_for_player_name = Gui.uid_name() @@ -26,6 +31,7 @@ local convert_chest_to_linked = Gui.uid_name() local item_name_frame_name = Gui.uid_name() local module_name = '[Linked Chests] ' +local deepcopy = table.deepcopy local insert = table.insert local pairs = pairs local Public = {} @@ -39,8 +45,23 @@ Global.register( local remove_chest -function Public.get_table() - return this +function Public.get(key) + if key then + return this[key] + else + return this + end +end + +function Public.set(key, value) + if key and (value or value == false) then + this[key] = value + return this[key] + elseif key then + return this[key] + else + return this + end end local remove_all_linked_items_token = @@ -56,6 +77,29 @@ local remove_all_linked_items_token = end ) +local function create_message(player, action, source_position, destination_position) + local data = { + title = 'Mountain_fortress_v3', + description = 'Linked chests action was triggered.', + field1 = { + text1 = player.name, + text2 = action + }, + field2 = { + text1 = 'Source position:', + text2 = '{x = ' .. source_position.x .. ', y = ' .. source_position.y .. '}' + } + } + if destination_position then + data.field3 = { + text1 = 'Destination position:', + text2 = '{x = ' .. destination_position.x .. ', y = ' .. destination_position.y .. '}' + } + end + + Discord.send_notification(data) +end + local function draw_convert_chest_button(parent, entity) local frame = parent[chest_converter_frame_for_player_name] if frame and frame.valid then @@ -85,6 +129,16 @@ local function draw_convert_chest_button(parent, entity) Gui.set_data(button, entity) end +local function uid_counter() + this.uid_counter = this.uid_counter + 1 + + if this.uid_counter > 4294967295 then + this.uid_counter = 5000 + end + + return this.uid_counter +end + local function validate_player(player) if not player then return false @@ -125,6 +179,12 @@ local function add_object(unit_number, state) end local function remove_object(unit_number) + local container = this.main_containers[unit_number] + + if container and container.chest and container.chest.valid then + container.chest.destroy() + end + this.main_containers[unit_number] = nil end @@ -152,42 +212,12 @@ local function fetch_link_id(id) return false end -local function toggle_render(container) - if not container.chest or not container.chest.valid then - remove_chest(container.unit_number) - return - end - - if container.render then - rendering.destroy(container.render) - end - - container.render = - rendering.draw_text { - text = '⚙️', - surface = container.chest.surface, - target = container.chest, - target_offset = {0, -0.6}, - scale = 2, - color = {r = 0, g = 0.6, b = 1}, - alignment = 'center' - } -end - -local function count_containers() - local n = 0 - local containers = this.main_containers - for _, _ in pairs(containers) do - n = n + 1 - end - return n -end - -local function create_chest(entity) +local function create_chest(entity, name, raised) entity.active = false + entity.destructible = false local unit_number = entity.unit_number - entity.link_id = count_containers() + 1 + entity.link_id = uid_counter() if not does_exists(unit_number) then local container = { @@ -196,11 +226,15 @@ local function create_chest(entity) mode = 1, link_id = entity.link_id, share = { - name = entity.unit_number + name = name or entity.unit_number } } - local c = add_object(unit_number, container) - toggle_render(c) + + if raised then + container.mode = 2 + end + + add_object(unit_number, container) return true end return false @@ -226,6 +260,18 @@ local function restore_links(unit_number) end end +local function restore_link(unit_number, new_unit_number) + local containers = this.main_containers + local source_container = fetch_container(unit_number) + for _, container in pairs(containers) do + if container.chest and container.chest.valid and container.linked_to == unit_number then + container.linked_to = new_unit_number + container.link_id = source_container.link_id + container.chest.link_id = source_container.link_id + end + end +end + local function built_entity_robot(event) if this.disable_normal_placement then return @@ -250,6 +296,7 @@ local function built_entity_robot(event) end remove_chest = function(unit_number) + restore_links(unit_number) remove_object(unit_number) end @@ -268,7 +315,7 @@ end local function on_entity_died(event) local entity = event.entity - if not entity then + if not entity or not entity.valid then return end if not this.valid_chests[entity.name] then @@ -289,9 +336,8 @@ local function on_pre_player_mined_item(event) return end refund_player(player, entity) - restore_links(entity.unit_number) remove_chest(entity.unit_number) - local data = this.inf_gui[player.name] + local data = this.linked_gui[player.name] if not data then return end @@ -309,7 +355,7 @@ local function text_changed(event) local player = game.get_player(event.player_index) - local data = this.inf_gui[player.name] + local data = this.linked_gui[player.name] if not data then return end @@ -362,7 +408,7 @@ local function text_changed(event) end end end - this.inf_gui[player.name].updated = false + this.linked_gui[player.name].updated = false end --- Iterates all chests. @@ -370,9 +416,10 @@ end ---@return table local function get_all_chests(unit_number) local t = {} + local loco_surface = WPT.get('loco_surface') local containers = this.main_containers for check_unit_number, container in pairs(containers) do - if container.chest and container.chest.valid and container.share.name ~= '' and container.share.name ~= container.unit_number then + if container.chest and container.chest.valid and container.share.name ~= '' and container.share.name ~= container.unit_number and container.chest.surface.index == loco_surface.index then if check_unit_number ~= unit_number then insert(t, container) end @@ -401,7 +448,8 @@ local function refresh_main_frame(data) return end - local player_gui = this.inf_gui[player.name] + local player_gui = this.linked_gui[player.name] + local trusted_player = Session.get_trusted_player(player) local volatile_tbl = player_gui.volatile_tbl volatile_tbl.clear() @@ -415,39 +463,23 @@ local function refresh_main_frame(data) end if mode == 1 then - local limit_tooltip = '[color=yellow]Link info:[/color]\nSetting this will allow for a new link to be initiated.' - local share_tooltip = '[color=red]REQUIRED[/color]\n[color=yellow]Share Info:[/color]\nA name for the share so you can easily find it when you want to link it with another chest.\nNeeds to be unique.' - local share_tbl = volatile_tbl.add {type = 'table', column_count = 8, name = 'share_tbl'} local share_one_bottom_flow = share_tbl.add {type = 'flow'} share_one_bottom_flow.style.minimal_width = 40 - local share_two_label = share_one_bottom_flow.add({type = 'label', caption = 'Share Name: ', tooltip = share_tooltip}) + local share_two_label = share_one_bottom_flow.add({type = 'label', caption = 'Share Name: '}) share_two_label.style.font = 'heading-2' local share_two_text = share_one_bottom_flow.add({type = 'textfield', name = 'share_name', text = get_share(entity).name}) + share_two_text.enabled = false share_two_text.style.width = 150 share_two_text.allow_decimal = true share_two_text.allow_negative = false - share_two_text.tooltip = share_tooltip share_two_text.style.minimal_width = 25 - - local limit_tbl = volatile_tbl.add {type = 'table', column_count = 8, name = 'limit_tbl'} - - local limit_two_label = limit_tbl.add({type = 'label', caption = 'Link ID: ', tooltip = limit_tooltip}) - limit_two_label.style.font = 'heading-2' - local limit_two_text = limit_tbl.add({type = 'textfield', name = 'link_id_label', text = container.chest.link_id}) - limit_two_text.style.width = 80 - limit_two_text.numeric = true - limit_two_text.allow_decimal = false - limit_two_text.allow_negative = false - limit_two_text.tooltip = limit_tooltip - limit_two_text.style.minimal_width = 25 - - this.inf_gui[player.name].text_field = limit_two_text elseif mode == 2 then local linker_tooltip = '[color=yellow]Link Info:[/color]\nThis will only work if there are any current placed linked chests.' if container then + local disconnect = volatile_tbl.add {type = 'table', column_count = 2, name = 'disconnect'} local linker = volatile_tbl.add {type = 'table', column_count = 1, name = 'linker'} local chests = get_all_chests(unit_number) local linked_container = fetch_container(container.linked_to) @@ -461,6 +493,17 @@ local function refresh_main_frame(data) end if container.linked_to and linked_container then + local disconnect_label = disconnect.add({type = 'label', caption = 'Disconnect link? '}) + disconnect_label.style.font = 'heading-2' + local disconnect_button = disconnect.add({type = 'checkbox', name = 'disconnect_state', state = false}) + disconnect_button.tooltip = 'Click to disconnect this link!' + disconnect_button.style.minimal_height = 25 + + if not trusted_player then + disconnect_button.enabled = false + disconnect_button.tooltip = '[Antigrief] You have not grown accustomed to this technology yet.' + end + local link_label = linker.add({type = 'label', caption = 'Linked with:', tooltip = linker_tooltip}) link_label.style.font = 'heading-2' @@ -500,6 +543,10 @@ local function refresh_main_frame(data) sprite = 'item/' .. source_chest.chest.name, tooltip = 'Chest: [color=yellow]' .. source_chest.share.name .. '[/color]\nRight click to show on map.' } + if not trusted_player then + chestitem.enabled = false + chestitem.tooltip = '[Antigrief] You have not grown accustomed to this technology yet.' + end Gui.set_data(chestitem, {name = nil, unit_number = unit_number, share = source_chest.share.name}) end end @@ -551,15 +598,12 @@ local function gui_opened(event) local selected = mode and mode or 1 local controltbl = controls.add {type = 'table', column_count = 1} local btntbl = controltbl.add {type = 'table', column_count = 2} - local modetbl = controltbl.add {type = 'table', column_count = 2} local volatile_tbl = controls2.add {type = 'table', column_count = 1} - local mode_tooltip = '[color=yellow]Mode Info:[/color]\nMaster: will active the chest and allow for links if share name is set.\nLinked: this mode is set when the chest is linked to another chest.' - local btn = btntbl.add { type = 'sprite-button', - tooltip = '[color=blue]Info![/color]\nChest ID: ' .. unit_number, + tooltip = '[color=blue]Info![/color]\nChest ID: ' .. unit_number .. '\n\nFor a smoother link:\nSHIFT + RMB on the source entity\nSHIFT + LMB on the destination entity.\n\nTo mine a linked chest, disconnect the link first.', sprite = Gui.info_icon } btn.style.height = 20 @@ -567,29 +611,15 @@ local function gui_opened(event) btn.enabled = false btn.focus() - local mode_label = modetbl.add {type = 'label', caption = 'Mode: ', tooltip = mode_tooltip} - mode_label.style.font = 'heading-2' - local drop_down_items = {'Master', 'Linked'} - - local drop_down = - modetbl.add { - type = 'drop-down', - items = drop_down_items, - selected_index = selected, - name = unit_number, - tooltip = mode_tooltip - } - - this.inf_gui[player.name] = { + this.linked_gui[player.name] = { item_frame = items, frame = frame, volatile_tbl = volatile_tbl, - drop_down = drop_down, entity = entity, updated = false } - container.mode = drop_down.selected_index + container.mode = selected player.opened = frame refresh_main_frame({unit_number = unit_number, player = player}) @@ -617,7 +647,7 @@ local function on_built_entity(event, raised, bypass) return end - local s = create_chest(entity) + local s = create_chest(entity, nil, raised) if s then gui_opened(event) end @@ -625,7 +655,7 @@ end local function update_gui() for _, player in pairs(game.connected_players) do - local chest_gui_data = this.inf_gui[player.name] + local chest_gui_data = this.linked_gui[player.name] if not chest_gui_data then goto continue end @@ -697,7 +727,7 @@ local function update_gui() total = total + 1 end - this.inf_gui[player.name].updated = true + this.linked_gui[player.name].updated = true ::continue:: end end @@ -707,15 +737,60 @@ local function gui_closed(event) local type = event.gui_type if type == defines.gui_type.custom then - local data = this.inf_gui[player.name] + local data = this.linked_gui[player.name] if not data then return end data.frame.destroy() - this.inf_gui[player.name] = nil + this.linked_gui[player.name] = nil end end +local function on_gui_checked_state_changed(event) + local element = event.element + local player = game.get_player(event.player_index) + if not validate_player(player) then + return + end + if not element.valid then + return + end + + local pGui = this.linked_gui[player.name] + if not pGui then + return + end + + local entity = pGui.entity + if not (entity and entity.valid) then + return + end + + local unit_number = entity.unit_number + local container = fetch_container(unit_number) + if not container then + return + end + + if element.name == 'disconnect_state' then + container.chest.link_id = uid_counter() + AG.append_scenario_history(player, container.chest, player.name .. ' disconnected link from chest (' .. container.unit_number .. ') to chest (' .. container.linked_to .. ')') + local destination_chest = fetch_container(container.linked_to) + if destination_chest then + create_message(player, 'Disconnected link', container.chest.position, destination_chest.chest.position) + else + create_message(player, 'Disconnected link', container.chest.position, nil) + end + container.mode = 2 + container.linked_to = nil + container.link_id = nil + container.chest.minable = true + refresh_main_frame({unit_number = unit_number, player = player}) + end + + pGui.updated = false +end + local function state_changed(event) local player = game.get_player(event.player_index) if not validate_player(player) then @@ -744,10 +819,8 @@ local function state_changed(event) refresh_main_frame({unit_number = unit_number, player = player}) - toggle_render(container) - if mode >= 2 then - this.inf_gui[player.name].updated = false + this.linked_gui[player.name].updated = false return end end @@ -818,6 +891,7 @@ local function on_entity_settings_pasted(event) if content_mismatches(source_link_id, destination_link_id) then player.print(module_name .. 'The destination chest that you are trying to paste to mismatches with the original chest.', Color.fail) + destination_container.chest.link_id = destination_container.link_id return end @@ -825,47 +899,76 @@ local function on_entity_settings_pasted(event) goto continue end + if source_container.mode == 1 and destination_container.mode == 1 then + player.print(module_name .. 'Destination chest cannot be linked since source chest is of same mode.', Color.fail) + destination_container.chest.link_id = destination_container.link_id + return + end + if source_container.linked_to and destination_container.linked_to then player.print(module_name .. 'The destination chest is already linked.', Color.fail) + destination_container.chest.link_id = destination_container.link_id return end if source_container.share.name == '' then player.print(module_name .. 'The source chest is not shared.', Color.fail) + destination_container.chest.link_id = destination_container.link_id return end if source_container.chest.unit_number == source_container.share.name then player.print(module_name .. 'The source chest is not shared.', Color.fail) + destination_container.chest.link_id = destination_container.link_id return end if destination_container.linked_to then player.print(module_name .. 'The destination chest is already linked.', Color.fail) + destination_container.chest.link_id = destination_container.link_id return end ::continue:: if source_share and source_share.name ~= '' then + AG.append_scenario_history(player, destination_container.chest, player.name .. ' pasted settings from chest (' .. source_container.unit_number .. ') to chest (' .. destination_container.unit_number .. ')') + create_message(player, 'Pasted settings', source_container.chest.position, destination_container.chest.position) + destination_container.linked_to = source_container.linked_to or source.unit_number destination_container.link_id = source_link_id destination_container.chest.link_id = source_link_id destination_container.mode = 2 - toggle_render(source_container) - toggle_render(destination_container) end player.print(module_name .. 'Successfully pasted settings.', Color.success) end -function Public.add(surface, position, force) +function Public.add(surface, position, force, name) local entity = surface.create_entity {name = 'linked-chest', position = position, force = force, create_build_effect_smoke = false} if not entity.valid then return end - create_chest(entity) + create_chest(entity, name) + return entity +end + +function Public.migrate(source, destination) + local source_container = fetch_container(source.unit_number) + if not source_container then + return + end + + local source_data = deepcopy(source_container) + source_data.chest = destination + source_data.unit_number = destination.unit_number + + this.main_containers[destination.unit_number] = source_data + + restore_link(source.unit_number, destination.unit_number) + + this.main_containers[source.unit_number] = nil end Event.on_nth_tick( @@ -878,6 +981,24 @@ Event.on_nth_tick( end ) +Event.on_nth_tick( + 120, + function() + local containers = this.main_containers + local loco_surface = WPT.get('loco_surface') + for index, container in pairs(containers) do + if container and container.chest and container.chest.valid and container.chest.surface.index ~= loco_surface.index then + if not WPT.locomotive.is_around_train(container.chest) then + remove_chest(container.unit_number) + end + end + if container and not container.chest or not container.chest.valid then + containers[index] = nil + end + end + end +) + Gui.on_click( convert_chest_to_linked, function(event) @@ -885,14 +1006,32 @@ Gui.on_click( local inventory = player.get_main_inventory() local player_item_count = inventory.get_item_count('coin') + local active_surface_index = WPT.get('active_surface_index') + + local trusted_player = Session.get_trusted_player(player) + + if not trusted_player then + player.print('[Antigrief] You have not grown accustomed to this technology yet.', Color.warning) + return + end + if player_item_count >= this.cost_to_convert then local entity = Gui.get_data(event.element) if entity and entity.valid then + if not WPT.locomotive.is_around_train(entity) or active_surface_index ~= entity.surface.index then + player.print(module_name .. 'The placed entity is not near the locomotive or is on the wrong surface.', Color.warning) + return + end + player.remove_item({name = 'coin', count = this.cost_to_convert}) player.opened = nil event.created_entity = entity event.entity = entity event.player_index = player.index + AG.append_scenario_history(player, entity, player.name .. ' converted chest (' .. entity.unit_number .. ')') + create_message(player, 'Converted chest', entity.position, nil) + + this.converted_chests = this.converted_chests + 1 on_built_entity(event, true) end @@ -960,36 +1099,63 @@ Gui.on_click( return end + AG.append_scenario_history(event.player, container.chest, event.player.name .. ' linked chest (' .. data.unit_number .. ') with: ' .. share_container.share.name) + create_message(event.player, 'Linked chest', container.chest.position, share_container.chest.position) container.linked_to = _unit_number container.chest.link_id = share_container.link_id container.link_id = share_container.link_id - this.inf_gui[event.player.name].updated = false - toggle_render(container) + container.chest.minable = false + + this.linked_gui[event.player.name].updated = false refresh_main_frame({unit_number = container.unit_number, player = event.player}) end end ) +local function on_player_changed_position(event) + local player = game.get_player(event.player_index) + local data = this.linked_gui[player.name] + if not data then + return + end + + if data and data.frame and data.frame.valid then + local position = data.entity.position + local area = { + left_top = {x = position.x - 8, y = position.y - 8}, + right_bottom = {x = position.x + 8, y = position.y + 8} + } + if Math2D.bounding_box.contains_point(area, player.position) then + return + end + data.frame.destroy() + end +end + +function Public.reset() + this.main_containers = {} + this.linked_gui = {} + this.valid_chests = { + ['linked-chest'] = true, + ['steel-chest'] = true, + ['iron-chest'] = true + } + this.enabled = true + this.converted_chests = 0 + this.uid_counter = 0 + this.disable_normal_placement = true + this.cost_to_convert = 500 +end + Event.add(defines.events.on_built_entity, on_built_entity) Event.add(defines.events.on_robot_built_entity, built_entity_robot) Event.add(defines.events.on_pre_player_mined_item, on_pre_player_mined_item) Event.add(defines.events.on_gui_selection_state_changed, state_changed) Event.add(defines.events.on_entity_died, on_entity_died) Event.add(defines.events.on_gui_text_changed, text_changed) +Event.add(defines.events.on_gui_checked_state_changed, on_gui_checked_state_changed) Event.add(defines.events.on_entity_settings_pasted, on_entity_settings_pasted) - -Event.on_nth_tick( - 120, - function() - local containers = this.main_containers - for i = 1, #containers do - local container = containers[i] - if container and container.chest and container.chest.valid and container.linked_to then - container.chest.link_id = container.linked_to - end - end - end -) +Event.add(defines.events.on_player_changed_position, on_player_changed_position) return Public diff --git a/maps/mountain_fortress_v3/icw/main.lua b/maps/mountain_fortress_v3/icw/main.lua index 22d145c3..10d1f70b 100644 --- a/maps/mountain_fortress_v3/icw/main.lua +++ b/maps/mountain_fortress_v3/icw/main.lua @@ -104,8 +104,12 @@ end local function on_tick() local tick = game.tick - if tick % 20 == 0 then + + if tick % 10 == 0 then Functions.item_transfer() + end + + if tick % 20 == 0 then Functions.hazardous_debris() end if tick % 240 == 0 then @@ -134,6 +138,12 @@ local function on_gui_switch_state_changed(event) end end +local function on_entity_cloned(event) + local source = event.source + local destination = event.destination + Functions.on_entity_cloned(source, destination) +end + function Public.register_wagon(wagon_entity) local icw = ICW.get() return Functions.create_wagon(icw, wagon_entity) @@ -159,5 +169,6 @@ Event.add(defines.events.on_gui_opened, on_gui_opened) Event.add(defines.events.on_player_built_tile, on_player_or_robot_built_tile) Event.add(defines.events.on_robot_built_tile, on_player_or_robot_built_tile) Event.add(defines.events.on_gui_switch_state_changed, on_gui_switch_state_changed) +Event.add(defines.events.on_entity_cloned, on_entity_cloned) return Public diff --git a/maps/mountain_fortress_v3/icw/table.lua b/maps/mountain_fortress_v3/icw/table.lua index ecf98f2e..ddfc8dc5 100644 --- a/maps/mountain_fortress_v3/icw/table.lua +++ b/maps/mountain_fortress_v3/icw/table.lua @@ -1,4 +1,5 @@ local Global = require 'utils.global' +local LinkedChests = require 'maps.mountain_fortress_v3.icw.linked_chests' local this = {} Global.register( @@ -11,6 +12,7 @@ Global.register( local Public = {} function Public.reset() + LinkedChests.reset() if this.surfaces then for _, surface in pairs(this.surfaces) do if surface and surface.valid then diff --git a/maps/mountain_fortress_v3/locomotive.lua b/maps/mountain_fortress_v3/locomotive.lua index 845049fb..406c5b08 100644 --- a/maps/mountain_fortress_v3/locomotive.lua +++ b/maps/mountain_fortress_v3/locomotive.lua @@ -7,6 +7,7 @@ local Difficulty = require 'modules.difficulty_vote_by_amount' local RPG = require 'modules.rpg.main' local Gui = require 'utils.gui' local Alert = require 'utils.alert' +local Color = require 'utils.color_presets' local rpg_main_frame = RPG.main_frame_name local random = math.random @@ -34,6 +35,12 @@ local non_valid_vehicles = { ['spider-vehicle'] = true } +local denied_train_types = { + ['locomotive'] = true, + ['cargo-wagon'] = true, + ['artillery-wagon'] = true +} + local function add_random_loot_to_main_market(rarity) local main_market_items = Public.get('main_market_items') local items = Public.get_random_item(rarity, true, false) @@ -97,7 +104,7 @@ local messages = { local function is_around_train(data) local entity = data.entity - local locomotive_aura_radius = data.locomotive_aura_radius + 20 + local locomotive_aura_radius = data.locomotive_aura_radius local loco = data.locomotive.position local position = entity.position local inside = ((position.x - loco.x) ^ 2 + (position.y - loco.y) ^ 2) < locomotive_aura_radius ^ 2 @@ -558,6 +565,33 @@ local function on_player_driving_changed_state(event) end end +local function on_gui_opened(event) + local player = game.players[event.player_index] + if not player or not player.valid then + return + end + local entity = event.entity + if not entity or not entity.valid then + return + end + + if not denied_train_types[entity.type] then + return + end + + local block_non_trusted_opening_trains = Public.get('block_non_trusted_opening_trains') + if not block_non_trusted_opening_trains then + return + end + + local trusted_player = Session.get_trusted_player(player) + + if not trusted_player then + player.print('[Antigrief] You have not grown accustomed to this technology yet.', Color.warning) + player.opened = nil + end +end + function Public.boost_players_around_train() local rpg = RPG.get('rpg_t') local active_surface_index = Public.get('active_surface_index') @@ -736,5 +770,6 @@ Event.add(defines.events.on_research_finished, on_research_finished) Event.add(defines.events.on_player_changed_surface, on_player_changed_surface) Event.add(defines.events.on_player_driving_changed_state, on_player_driving_changed_state) Event.add(defines.events.on_train_created, set_carriages) +Event.add(defines.events.on_gui_opened, on_gui_opened) return Public diff --git a/maps/mountain_fortress_v3/locomotive/linked_chests.lua b/maps/mountain_fortress_v3/locomotive/linked_chests.lua deleted file mode 100644 index 4179b1ba..00000000 --- a/maps/mountain_fortress_v3/locomotive/linked_chests.lua +++ /dev/null @@ -1,227 +0,0 @@ -local Event = require 'utils.event' -local Public = require 'maps.mountain_fortress_v3.table' -local ICW = require 'maps.mountain_fortress_v3.icw.main' - -local function contains_positions(area) - local function inside(pos) - local lt = area.left_top - local rb = area.right_bottom - - return pos.x >= lt.x and pos.y >= lt.y and pos.x <= rb.x and pos.y <= rb.y - end - - local wagons = ICW.get_table('wagons') - for _, wagon in pairs(wagons) do - if wagon.entity and wagon.entity.valid then - if wagon.entity.name == 'cargo-wagon' then - if inside(wagon.entity.position) then - return true, wagon.entity - end - end - end - end - return false, nil -end - -local function on_built_entity(event) - local entity = event.created_entity - if not entity.valid then - return - end - - if entity.name ~= 'steel-chest' then - return - end - - local map_name = 'mtn_v3' - - if string.sub(entity.surface.name, 0, #map_name) ~= map_name then - return - end - - local area = { - left_top = {x = entity.position.x - 3, y = entity.position.y - 3}, - right_bottom = {x = entity.position.x + 3, y = entity.position.y + 3} - } - - local success, train = contains_positions(area) - - if not success then - return - end - - local outside_chests = Public.get('outside_chests') - local chests_linked_to = Public.get('chests_linked_to') - local upgrades = Public.get('upgrades') - local chest_created - local increased = false - - for _, data in pairs(outside_chests) do - if data and data.chest and data.chest.valid then - if chests_linked_to[train.unit_number] then - local linked_to = chests_linked_to[train.unit_number].count - if linked_to == upgrades.chests_outside_upgrades then - return - end - outside_chests[entity.unit_number] = {chest = entity, position = entity.position, linked = train.unit_number} - - if not increased then - chests_linked_to[train.unit_number].count = linked_to + 1 - chests_linked_to[train.unit_number][entity.unit_number] = true - increased = true - - goto continue - end - else - outside_chests[entity.unit_number] = {chest = entity, position = entity.position, linked = train.unit_number} - chests_linked_to[train.unit_number] = {count = 1} - end - - ::continue:: - outside_chests[entity.unit_number].render = - rendering.draw_text { - text = '♠', - surface = entity.surface, - target = entity, - target_offset = {0, -0.6}, - scale = 2, - color = {r = 0, g = 0.6, b = 1}, - alignment = 'center' - } - chest_created = true - end - end - - if chest_created then - return - end - - if next(outside_chests) == nil then - outside_chests[entity.unit_number] = {chest = entity, position = entity.position, linked = train.unit_number} - chests_linked_to[train.unit_number] = {count = 1} - chests_linked_to[train.unit_number][entity.unit_number] = true - - outside_chests[entity.unit_number].render = - rendering.draw_text { - text = '♠', - surface = entity.surface, - target = entity, - target_offset = {0, -0.6}, - scale = 2, - color = {r = 0, g = 0.6, b = 1}, - alignment = 'center' - } - return - end -end - -local function on_player_and_robot_mined_entity(event) - local entity = event.entity - - if not entity.valid then - return - end - - local outside_chests = Public.get('outside_chests') - local chests_linked_to = Public.get('chests_linked_to') - - if outside_chests[entity.unit_number] then - for k, data in pairs(chests_linked_to) do - if data[entity.unit_number] then - data.count = data.count - 1 - if data.count <= 0 then - chests_linked_to[k] = nil - end - end - if chests_linked_to[k] and chests_linked_to[k][entity.unit_number] then - chests_linked_to[k][entity.unit_number] = nil - end - end - outside_chests[entity.unit_number] = nil - end -end - -local function divide_contents() - local outside_chests = Public.get('outside_chests') - local chests_linked_to = Public.get('chests_linked_to') - local target_chest - - if not next(outside_chests) then - goto final - end - - for key, data in pairs(outside_chests) do - local chest = data.chest - local area = { - left_top = {x = data.position.x - 4, y = data.position.y - 4}, - right_bottom = {x = data.position.x + 4, y = data.position.y + 4} - } - if not (chest and chest.valid) then - if chests_linked_to[data.linked] then - if chests_linked_to[data.linked][key] then - if data.render and rendering.is_valid(data.render) then - rendering.destroy(data.render) - end - chests_linked_to[data.linked][key] = nil - chests_linked_to[data.linked].count = chests_linked_to[data.linked].count - 1 - if chests_linked_to[data.linked].count <= 0 then - chests_linked_to[data.linked] = nil - end - end - end - outside_chests[key] = nil - goto continue - end - - local success, entity = contains_positions(area) - if success then - target_chest = entity - else - if chests_linked_to[data.linked] then - if data then - if data.render and rendering.is_valid(data.render) then - rendering.destroy(data.render) - end - chests_linked_to[data.linked][key] = nil - chests_linked_to[data.linked].count = chests_linked_to[data.linked].count - 1 - if chests_linked_to[data.linked].count <= 0 then - chests_linked_to[data.linked] = nil - end - outside_chests[key] = nil - end - end - goto continue - end - - local chest1 = chest.get_inventory(defines.inventory.chest) - local chest2 = target_chest.get_inventory(defines.inventory.cargo_wagon) - - for item, count in pairs(chest1.get_contents()) do - local t = {name = item, count = count} - local c = chest2.insert(t) - if (c > 0) then - chest1.remove({name = item, count = c}) - end - end - ::continue:: - end - ::final:: -end - -local function tick() - local ticker = game.tick - - if ticker % 30 == 0 then - divide_contents() - end -end - -Event.on_nth_tick(5, tick) - -Event.add(defines.events.on_built_entity, on_built_entity) -Event.add(defines.events.on_robot_built_entity, on_built_entity) -Event.add(defines.events.on_entity_died, on_player_and_robot_mined_entity) -Event.add(defines.events.on_pre_player_mined_item, on_player_and_robot_mined_entity) -Event.add(defines.events.on_robot_mined_entity, on_player_and_robot_mined_entity) - -return Public diff --git a/maps/mountain_fortress_v3/locomotive/market.lua b/maps/mountain_fortress_v3/locomotive/market.lua index f5ad4ac9..7acd3734 100644 --- a/maps/mountain_fortress_v3/locomotive/market.lua +++ b/maps/mountain_fortress_v3/locomotive/market.lua @@ -47,7 +47,6 @@ local function get_items() local upgrades = Public.get('upgrades') local fixed_prices = Public.get('marked_fixed_prices') - local chests_outside_cost = round(fixed_prices.chests_outside_cost * (1 + upgrades.chests_outside_upgrades)) local health_cost = round(fixed_prices.health_cost * (1 + upgrades.health_upgrades)) local pickaxe_cost = round(fixed_prices.pickaxe_cost * (0.1 + upgrades.pickaxe_tier / 2)) local aura_cost = round(fixed_prices.aura_cost * (1 + upgrades.aura_upgrades)) @@ -86,30 +85,6 @@ local function get_items() } end - if upgrades.chests_outside_upgrades == market_limits.chests_outside_limit then - main_market_items['chest_limit_outside'] = { - stack = 1, - value = 'coin', - price = chests_outside_cost, - tooltip = ({'locomotive.limit_reached'}), - sprite = 'entity.steel-chest', - enabled = false, - upgrade = true, - static = true - } - else - main_market_items['chest_limit_outside'] = { - stack = 1, - value = 'coin', - price = chests_outside_cost, - tooltip = ({'main_market.chest', upgrades.chests_outside_upgrades, market_limits.chests_outside_limit}), - sprite = 'entity.steel-chest', - enabled = true, - upgrade = true, - static = true - } - end - if upgrades.health_upgrades >= market_limits.health_upgrades_limit then main_market_items['locomotive_max_health'] = { stack = 1, @@ -976,29 +951,6 @@ local function gui_click(event) return end - if name == 'chest_limit_outside' then - if this.upgrades.chests_outside_upgrades == this.market_limits.chests_outside_limit then - redraw_market_items(data.item_frame, player, data.search_text) - player.print(({'locomotive.chests_full'}), {r = 0.98, g = 0.66, b = 0.22}) - return - end - player.remove_item({name = item.value, count = item.price}) - - local message = ({'locomotive.chest_bought_info', shopkeeper, player.name, format_number(item.price, true)}) - Alert.alert_all_players(5, message) - Server.to_discord_bold( - table.concat { - player.name .. ' has upgraded the chest limit for ' .. format_number(item.price, true) .. ' coins.' - } - ) - this.upgrades.chests_outside_upgrades = this.upgrades.chests_outside_upgrades + item.stack - this.upgrades.train_upgrade_contribution = this.upgrades.train_upgrade_contribution + item.price - - redraw_market_items(data.item_frame, player, data.search_text) - redraw_coins_left(data.coins_left, player) - - return - end if name == 'locomotive_max_health' then player.remove_item({name = item.value, count = item.price}) local message = ({'locomotive.health_bought_info', shopkeeper, player.name, format_number(item.price, true)}) diff --git a/maps/mountain_fortress_v3/stateful/gui.lua b/maps/mountain_fortress_v3/stateful/gui.lua index c9aad7ec..f4e71d8e 100644 --- a/maps/mountain_fortress_v3/stateful/gui.lua +++ b/maps/mountain_fortress_v3/stateful/gui.lua @@ -7,6 +7,7 @@ local Token = require 'utils.token' local Task = require 'utils.task' local Core = require 'utils.core' local Server = require 'utils.server' +local LinkedChests = require 'maps.mountain_fortress_v3.icw.linked_chests' local main_button_name = Gui.uid_name() local main_frame_name = Gui.uid_name() @@ -385,6 +386,7 @@ local function main_frame(player) local breached_wall = Public.get('breached_wall') breached_wall = breached_wall - 1 local wave_number = WD.get('wave_number') + local converted_chests = LinkedChests.get('converted_chests') local frame = player.gui.screen.add {type = 'frame', name = main_frame_name, caption = {'stateful.win_conditions'}, direction = 'vertical', tooltip = {'stateful.win_conditions_tooltip'}} frame.location = {x = 1, y = 45} @@ -477,8 +479,24 @@ local function main_frame(player) if wave_number >= stateful.objectives.randomized_wave then data.randomized_wave_label = wave_right_flow.add({type = 'label', caption = wave_number .. '/' .. stateful.objectives.randomized_wave .. ' [img=utility/check_mark_green]', tooltip = {'stateful.tooltip_completed'}}) else - local randomized_wave = wave_right_flow.add({type = 'label', caption = wave_number .. '/' .. stateful.objectives.randomized_wave .. ' [img=utility/not_available]', tooltip = {'stateful.tooltip_not_completed'}}) - data.randomized_wave_label = randomized_wave + data.randomized_wave_label = wave_right_flow.add({type = 'label', caption = wave_number .. '/' .. stateful.objectives.randomized_wave .. ' [img=utility/not_available]', tooltip = {'stateful.tooltip_not_completed'}}) + end + + -- new frame + local linked_left_flow = objective_tbl.add({type = 'flow'}) + linked_left_flow.style.horizontal_align = 'left' + linked_left_flow.style.horizontally_stretchable = true + + linked_left_flow.add({type = 'label', caption = {'stateful.linked'}, tooltip = {'stateful.linked_tooltip'}}) + frame.add({type = 'line', direction = 'vertical'}) + local linked_right_flow = objective_tbl.add({type = 'flow'}) + linked_right_flow.style.horizontal_align = 'right' + linked_right_flow.style.horizontally_stretchable = true + + if converted_chests >= stateful.objectives.randomized_linked_chests then + data.randomized_linked_label = linked_right_flow.add({type = 'label', caption = converted_chests .. '/' .. stateful.objectives.randomized_linked_chests .. ' [img=utility/check_mark_green]', tooltip = {'stateful.tooltip_completed'}}) + else + data.randomized_linked_label = linked_right_flow.add({type = 'label', caption = converted_chests .. '/' .. stateful.objectives.randomized_linked_chests .. ' [img=utility/not_available]', tooltip = {'stateful.tooltip_not_completed'}}) end --dynamic conditions @@ -510,6 +528,7 @@ local function update_data() local stateful = Public.get_stateful() local breached_wall = Public.get('breached_wall') local wave_number = WD.get('wave_number') + local converted_chests = LinkedChests.get('converted_chests') local collection = stateful.collection local supplies = stateful.objectives.supplies local single_item = stateful.objectives.single_item @@ -533,6 +552,7 @@ local function update_data() breached_wall = breached_wall - 1 if breached_wall >= stateful.objectives.randomized_zone then data.randomized_zone_label.caption = breached_wall .. '/' .. stateful.objectives.randomized_zone .. ' [img=utility/check_mark_green]' + data.randomized_zone_label.tooltip = {'stateful.tooltip_completed'} else data.randomized_zone_label.caption = breached_wall .. '/' .. stateful.objectives.randomized_zone .. ' [img=utility/not_available]' end @@ -541,11 +561,21 @@ local function update_data() if data.randomized_wave_label and data.randomized_wave_label.valid then if wave_number >= stateful.objectives.randomized_wave then data.randomized_wave_label.caption = wave_number .. '/' .. stateful.objectives.randomized_wave .. ' [img=utility/check_mark_green]' + data.randomized_wave_label.tooltip = {'stateful.tooltip_completed'} else data.randomized_wave_label.caption = wave_number .. '/' .. stateful.objectives.randomized_wave .. ' [img=utility/not_available]' end end + if data.randomized_linked_label and data.randomized_linked_label.valid then + if converted_chests >= stateful.objectives.randomized_linked_chests then + data.randomized_linked_label.caption = converted_chests .. '/' .. stateful.objectives.randomized_linked_chests .. ' [img=utility/check_mark_green]' + data.randomized_linked_label.tooltip = {'stateful.tooltip_completed'} + else + data.randomized_linked_label.caption = converted_chests .. '/' .. stateful.objectives.randomized_linked_chests .. ' [img=utility/not_available]' + end + end + if data.supply and next(data.supply) then local items_done = 0 for index = 1, #data.supply do @@ -673,6 +703,7 @@ local function update_raw() local stateful = Public.get_stateful() local breached_wall = Public.get('breached_wall') local wave_number = WD.get('wave_number') + local converted_chests = LinkedChests.get('converted_chests') local collection = stateful.collection local tick = game.tick local supplies = stateful.objectives.supplies @@ -701,6 +732,15 @@ local function update_raw() end end + if converted_chests >= stateful.objectives.randomized_linked_chests then + if not stateful.objectives_completed.randomized_linked_chests then + stateful.objectives_completed.randomized_linked_chests = true + play_achievement_unlocked() + Server.to_discord_embed('Objective: **convert chests** has been complete!') + stateful.objectives_completed_count = stateful.objectives_completed_count + 1 + end + end + if supplies and next(supplies) then local items_done = 0 for index = 1, #supplies do @@ -819,7 +859,7 @@ local function update_raw() end end - if stateful.objectives_completed_count == 5 and not stateful.objectives_completed.boss_time then + if stateful.objectives_completed_count == 6 and not stateful.objectives_completed.boss_time then stateful.objectives_completed.boss_time = true Server.to_discord_embed('All objectives has been completed!') stateful.collection.gather_time = tick + 54000 diff --git a/maps/mountain_fortress_v3/stateful/table.lua b/maps/mountain_fortress_v3/stateful/table.lua index aad321ee..8cae91b6 100644 --- a/maps/mountain_fortress_v3/stateful/table.lua +++ b/maps/mountain_fortress_v3/stateful/table.lua @@ -526,6 +526,7 @@ local apply_settings_token = this.objectives = { randomized_zone = scale(random(7, 20), 40), randomized_wave = scale(random(500, 2000), 4000), + randomized_linked_chests = scale(random(2, 4), 20), supplies = get_random_items(), single_item = get_random_item(), killed_enemies = scale(random(500000, 3000000), 10000000), @@ -573,6 +574,7 @@ function Public.reset_stateful() this.objectives = { randomized_zone = 2, randomized_wave = 2, + randomized_linked_chests = 2, supplies = get_random_items(), single_item = get_random_item(), killed_enemies = 10, @@ -588,6 +590,7 @@ function Public.reset_stateful() this.objectives = { randomized_zone = scale(random(7, 20), 40), randomized_wave = scale(random(500, 2000), 4000), + randomized_linked_chests = scale(random(2, 4), 20), supplies = get_random_items(), single_item = get_random_item(), killed_enemies = scale(random(500000, 3000000), 10000000), diff --git a/maps/mountain_fortress_v3/table.lua b/maps/mountain_fortress_v3/table.lua index 0e287ff1..85476513 100644 --- a/maps/mountain_fortress_v3/table.lua +++ b/maps/mountain_fortress_v3/table.lua @@ -123,6 +123,7 @@ function Public.reset_main_table() this.force_chunk = false this.bw = false this.allow_decon = true + this.block_non_trusted_opening_trains = true this.allow_decon_main_surface = true this.flamethrower_damage = {} this.mined_scrap = 0 @@ -165,8 +166,7 @@ function Public.reset_main_table() train_upgrade_contribution = 0, xp_points = 0, health_upgrades = 0, - pickaxe_tier = 1, - chests_outside_upgrades = 1 + pickaxe_tier = 1 } this.orbital_strikes = { enabled = true @@ -190,8 +190,6 @@ function Public.reset_main_table() this.main_market_items = {} this.spill_items_to_surface = false this.spectate = {} - this.outside_chests = {} - this.chests_linked_to = {} this.placed_trains_in_zone = { limit = 1, randomized = false,