2022-06-01 20:50:36 +02:00
-- This file is part of thesixthroc's Pirate Ship softmod, licensed under GPLv3 and stored at https://github.com/danielmartin0/ComfyFactorio-Pirates.
2022-03-19 23:20:55 +02:00
--luacheck: ignore
--luacheck ignores because tickinterval arguments are a code templating choice...
2021-10-13 10:21:53 +02:00
local Memory = require ' maps.pirates.memory '
local Gui = require ' maps.pirates.gui.gui '
local Ai = require ' maps.pirates.ai '
local Structures = require ' maps.pirates.structures.structures '
local Boats = require ' maps.pirates.structures.boats.boats '
2022-02-28 18:36:46 +02:00
local Islands = require ' maps.pirates.surfaces.islands.islands '
local IslandsCommon = require ' maps.pirates.surfaces.islands.common '
2021-10-13 10:21:53 +02:00
local Surfaces = require ' maps.pirates.surfaces.surfaces '
2022-05-29 13:36:27 +02:00
local PiratesApiEvents = require ' maps.pirates.api_events '
2021-10-13 10:21:53 +02:00
local Roles = require ' maps.pirates.roles.roles '
local Progression = require ' maps.pirates.progression '
local Crowsnest = require ' maps.pirates.surfaces.crowsnest '
local Hold = require ' maps.pirates.surfaces.hold '
local Cabin = require ' maps.pirates.surfaces.cabin '
local Balance = require ' maps.pirates.balance '
local Common = require ' maps.pirates.common '
local CoreData = require ' maps.pirates.coredata '
local Overworld = require ' maps.pirates.overworld '
local Utils = require ' maps.pirates.utils_local '
local Crew = require ' maps.pirates.crew '
local Parrot = require ' maps.pirates.parrot '
local Math = require ' maps.pirates.math '
2022-03-19 23:20:55 +02:00
local _inspect = require ' utils.inspect ' . inspect
2022-03-07 11:50:25 +02:00
local Kraken = require ' maps.pirates.surfaces.sea.kraken '
2021-10-13 10:21:53 +02:00
local Quest = require ' maps.pirates.quest '
2022-03-07 20:41:42 +02:00
local ShopDock = require ' maps.pirates.shop.dock '
2022-05-29 13:36:27 +02:00
local QuestStructures = require ' maps.pirates.structures.quest_structures.quest_structures '
2021-10-13 10:21:53 +02:00
local Public = { }
2022-02-26 20:25:48 +02:00
function Public . strobe_player_colors ( tickinterval )
local memory = Memory.get_crew_memory ( )
local strobing_players = memory.speed_boost_characters
2022-03-13 04:09:21 +02:00
if strobing_players and # strobing_players > 0 then
2022-02-27 18:42:25 +02:00
local col = Utils.rgb_from_hsv ( ( game.tick * 6 ) % 360 , 0.7 , 0.9 )
2022-02-26 20:25:48 +02:00
for index , val in pairs ( strobing_players ) do
if val then
local player = game.players [ index ]
if Common.validate_player_and_character ( player ) then
player.color = col
end
end
end
end
end
2021-10-13 10:21:53 +02:00
function Public . prevent_unbarreling_off_ship ( tickinterval )
2022-03-11 18:46:02 +02:00
if Common.allow_barreling_off_ship then return end
2021-10-13 10:21:53 +02:00
local memory = Memory.get_crew_memory ( )
local destination = Common.current_destination ( )
local boat = memory.boat
local surface_name = boat.surface_name
if not ( surface_name and game.surfaces [ surface_name ] and game.surfaces [ surface_name ] . valid ) then return end
local surface = game.surfaces [ surface_name ]
local assemblers = surface.find_entities_filtered { type = ' assembling-machine ' , force = memory.force_name }
for _ , a in pairs ( assemblers ) do
if a and a.valid then
local r = a.get_recipe ( )
if r and r.subgroup and r.subgroup . name and r.subgroup . name == ' fill-barrel ' and ( not ( r.name and r.name == ' fill-water-barrel ' ) ) then
if not Boats.on_boat ( boat , a.position ) then
2022-05-29 13:36:27 +02:00
Common.notify_force_error ( memory.force , { ' pirates.error_cant_carry_barrels ' } )
2021-10-13 10:21:53 +02:00
a.set_recipe ( ' fill-water-barrel ' )
end
end
end
end
end
function Public . prevent_disembark ( tickinterval )
local memory = Memory.get_crew_memory ( )
local destination = Common.current_destination ( )
local boat = memory.boat
if boat and boat.state and ( boat.state == Boats.enum_state . RETREATING or ( boat.state == Boats.enum_state . LEAVING_DOCK and ( not ( memory.crewstatus and memory.crewstatus == Crew.enum . LEAVING_INITIAL_DOCK ) ) ) ) then
if not destination.dynamic_data . cant_disembark_players then destination.dynamic_data . cant_disembark_players = { } end
local ps = destination.dynamic_data . cant_disembark_players
for _ , player in pairs ( game.connected_players ) do
if player.surface and player.surface . valid and boat.surface_name and player.surface . name == boat.surface_name and Boats.on_boat ( boat , player.position ) then
ps [ player.index ] = true
end
end
for _ , player in pairs ( game.connected_players ) do
2022-03-01 23:59:48 +02:00
if player.surface and player.surface . valid and boat.surface_name and player.surface . name == boat.surface_name and ps [ player.index ] and ( not Boats.on_boat ( boat , player.position ) ) and ( not ( player.controller_type == defines.controllers . spectator ) ) then
2022-05-29 13:36:27 +02:00
Common.notify_player_error ( player , { ' pirates.error_disembark ' } )
2022-02-28 18:36:46 +02:00
-- player.teleport(memory.spawnpoint)
local p = player.surface . find_non_colliding_position ( ' character ' , memory.spawnpoint , 5 , 0.1 )
if p then
player.teleport ( p )
else
player.teleport ( memory.spawnpoint )
end
2021-10-13 10:21:53 +02:00
end
end
end
end
function Public . check_all_spawners_dead ( tickinterval )
local memory = Memory.get_crew_memory ( )
local destination = Common.current_destination ( )
local boat = memory.boat
2022-03-14 14:44:30 +02:00
if destination.static_params and destination.static_params . base_cost_to_undock and ( not ( destination.subtype and destination.subtype == Islands.enum . RED_DESERT ) ) then
2021-10-13 10:21:53 +02:00
if boat and boat.surface_name and boat.surface_name == destination.surface_name then
local surface = game.surfaces [ destination.surface_name ]
if not ( surface and surface.valid ) then return end
local spawnerscount = Common.spawner_count ( surface )
if spawnerscount == 0 then
2022-03-14 14:44:30 +02:00
destination.static_params . base_cost_to_undock = nil
2022-05-29 13:36:27 +02:00
Common.notify_force ( memory.force , { ' pirates.destroyed_all_nests ' } )
2021-10-13 10:21:53 +02:00
end
end
end
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
end
function Public . raft_raids ( tickinterval )
local memory = Memory.get_crew_memory ( )
2022-02-24 21:39:03 +02:00
if memory.game_lost then return end
2021-10-13 10:21:53 +02:00
local destination = Common.current_destination ( )
if not destination then return end
if ( not destination.static_params ) or ( not destination.static_params . scheduled_raft_raids ) or ( not destination.dynamic_data . timer ) then return end
local scheduled_raft_raids = destination.static_params . scheduled_raft_raids
local timer = destination.dynamic_data . timer
2022-03-10 23:09:06 +02:00
for k , raid in pairs ( scheduled_raft_raids ) do
if timer >= raid.timeinseconds and ( not scheduled_raft_raids [ k ] . fired ) then
2022-02-28 18:36:46 +02:00
local type
2022-03-07 11:50:25 +02:00
if memory.overworldx >= 40 * 16 then
2022-02-28 18:36:46 +02:00
type = Boats.enum . RAFTLARGE
else
type = Boats.enum . RAFT
end
local boat = Islands.spawn_enemy_boat ( type )
2021-10-13 10:21:53 +02:00
if boat then
2022-02-28 18:36:46 +02:00
Ai.spawn_boat_biters ( boat , raid.max_evo , Boats.get_scope ( boat ) . Data.capacity , Boats.get_scope ( boat ) . Data.width )
2021-10-13 10:21:53 +02:00
end
2022-03-10 23:09:06 +02:00
scheduled_raft_raids [ k ] . fired = true
2021-10-13 10:21:53 +02:00
end
end
end
2022-02-24 21:39:03 +02:00
function Public . ship_deplete_fuel ( tickinterval )
local memory = Memory.get_crew_memory ( )
if memory.game_lost then return end
2022-03-14 14:44:30 +02:00
if not ( memory.stored_fuel and memory.boat . input_chests and memory.boat . input_chests [ 1 ] ) then return end
2022-02-24 21:39:03 +02:00
local rate = Progression.fuel_depletion_rate ( )
2022-03-13 03:44:32 +02:00
memory.fuel_depletion_rate_memoized = rate
2022-02-24 21:39:03 +02:00
local boat = memory.boat
local input_chests = boat.input_chests
local inv = input_chests [ 1 ] . get_inventory ( defines.inventory . chest )
local contents = inv.get_contents ( )
local item_type = ' coal '
local count = contents [ item_type ] or 0
if count > 0 then
inv.remove { name = ' coal ' , count = count }
end
memory.stored_fuel = memory.stored_fuel + count + rate * tickinterval / 60
2022-03-14 14:44:30 +02:00
if rate < 0 and memory.stored_fuel < 1000 and ( not ( memory.parrot_fuel_most_recent_warning and memory.parrot_fuel_most_recent_warning >= game.tick - 60 * 60 * 12 ) ) then --12 minutes
memory.parrot_fuel_most_recent_warning = game.tick
2022-05-29 13:36:27 +02:00
Common.parrot_speak ( memory.force , { ' pirates.parrot_fuel_warning ' } )
2022-03-14 14:44:30 +02:00
end
2022-02-24 21:39:03 +02:00
if memory.stored_fuel < 0 then
2022-05-29 13:36:27 +02:00
Crew.try_lose ( { ' pirates.loss_out_of_fuel ' } )
2022-02-24 21:39:03 +02:00
end
end
2021-10-13 10:21:53 +02:00
function Public . transfer_pollution ( tickinterval )
local memory = Memory.get_crew_memory ( )
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
local p = 0
for i = 1 , memory.hold_surface_count do
local surface = Hold.get_hold_surface ( i )
if not surface then return end
p = p + surface.get_total_pollution ( )
surface.clear_pollution ( )
end
if not ( p and memory.floating_pollution ) then return end
memory.floating_pollution = memory.floating_pollution + p
end
function Public . shop_ratelimit_tick ( tickinterval )
-- if memory.mainshop_rate_limit_ticker and memory.mainshop_rate_limit_ticker > 0 then
-- memory.mainshop_rate_limit_ticker = memory.mainshop_rate_limit_ticker - tickinterval
-- end
end
function Public . captain_warn_afk ( tickinterval )
local memory = Memory.get_crew_memory ( )
2022-02-24 21:39:03 +02:00
if memory.game_lost then return end
2021-10-13 10:21:53 +02:00
if memory.playerindex_captain then
for _ , player in pairs ( game.connected_players ) do
2022-03-01 23:59:48 +02:00
if Common.is_captain ( player ) and # Common.crew_get_nonafk_crew_members ( ) > 1 and player.afk_time >= Common.afk_time - 20 * 60 - 60 - tickinterval and player.afk_time < Common.afk_time - 20 * 60 then
2022-05-29 13:36:27 +02:00
Common.notify_player_announce ( player , { ' pirates.warn_nearly_afk_captain ' } )
2021-10-13 10:21:53 +02:00
player.play_sound { path = ' utility/scenario_message ' }
end
end
end
end
2022-03-09 01:36:03 +02:00
function Public . prune_offline_characters_list ( tickinterval )
local memory = Memory.get_crew_memory ( )
if memory.game_lost then return end
2022-03-19 23:20:55 +02:00
2022-03-09 01:36:03 +02:00
for player_index , tick in pairs ( memory.temporarily_logged_off_characters ) do
if player_index and game.players [ player_index ] and game.players [ player_index ] . connected then
--game.print("deleting already online character from list")
memory.temporarily_logged_off_characters [ player_index ] = nil
else
2022-03-09 23:39:47 +02:00
if player_index and tick < game.tick - 60 * 60 * Common.logged_off_items_preserved_minutes then
2022-03-09 01:36:03 +02:00
local player_inv = { }
player_inv [ 1 ] = game.players [ player_index ] . get_inventory ( defines.inventory . character_main )
player_inv [ 2 ] = game.players [ player_index ] . get_inventory ( defines.inventory . character_armor )
player_inv [ 3 ] = game.players [ player_index ] . get_inventory ( defines.inventory . character_ammo )
player_inv [ 4 ] = game.players [ player_index ] . get_inventory ( defines.inventory . character_guns )
player_inv [ 5 ] = game.players [ player_index ] . get_inventory ( defines.inventory . character_trash )
local any = false
for ii = 1 , 5 , 1 do
2022-03-14 19:37:18 +02:00
if player_inv [ ii ] and player_inv [ ii ] . valid then
2022-03-09 01:36:03 +02:00
for iii = 1 , # player_inv [ ii ] , 1 do
2022-03-14 19:37:18 +02:00
if player_inv [ ii ] [ iii ] and player_inv [ ii ] [ iii ] . valid and player_inv [ ii ] [ iii ] . valid_for_read then
2022-03-09 01:36:03 +02:00
-- items[#items + 1] = player_inv[ii][iii]
Common.give_items_to_crew ( player_inv [ ii ] [ iii ] )
any = true
end
end
end
end
if any then
2022-05-29 13:36:27 +02:00
Common.notify_force_light ( memory.force , { ' pirates.recover_offline_player_items ' } )
2022-03-09 01:36:03 +02:00
end
for ii = 1 , 5 , 1 do
if player_inv [ ii ] . valid then
player_inv [ ii ] . clear ( )
end
end
memory.temporarily_logged_off_characters [ player_index ] = nil
end
end
end
end
2021-10-13 10:21:53 +02:00
function Public . periodic_free_resources ( tickinterval )
local memory = Memory.get_crew_memory ( )
2022-02-24 21:39:03 +02:00
if memory.game_lost then return end
2021-10-13 10:21:53 +02:00
local destination = Common.current_destination ( )
local boat = memory.boat
if not ( destination and destination.type and destination.type == Surfaces.enum . ISLAND and boat and boat.surface_name and boat.surface_name == destination.surface_name ) then return end
2022-03-09 01:36:03 +02:00
Common.give_items_to_crew ( Balance.periodic_free_resources_per_destination_5_seconds ( ) )
2021-10-13 10:21:53 +02:00
2022-03-17 03:40:18 +02:00
if game.tick % ( 300 * 30 ) == 0 and ( destination and destination.subtype and destination.subtype == Islands.enum . RADIOACTIVE ) then -- every 150 seconds
2022-03-01 17:57:23 +02:00
local count = 2
2022-03-09 01:36:03 +02:00
Common.give_items_to_crew { { name = ' sulfuric-acid-barrel ' , count = count } }
2022-03-04 19:57:58 +02:00
local force = memory.force
2022-03-01 17:57:23 +02:00
if not ( force and force.valid ) then return end
2022-06-02 17:11:45 +02:00
local message = { ' pirates.granted_1 ' , { ' pirates.granted_periodic_barrel ' } , count .. ' [item=sulfuric-acid-barrel] ' }
2022-05-29 13:36:27 +02:00
Common.notify_force_light ( force , message )
2021-10-13 10:21:53 +02:00
end
end
function Public . pick_up_tick ( tickinterval )
local destination = Common.current_destination ( )
if not destination then return end
2022-03-13 20:19:59 +02:00
local dynamic_data = destination.dynamic_data
2021-10-13 10:21:53 +02:00
local surface_name = destination.surface_name
2022-03-13 20:19:59 +02:00
if not ( surface_name and dynamic_data ) then return end
2021-10-13 10:21:53 +02:00
local surface = game.surfaces [ surface_name ]
2022-03-13 20:19:59 +02:00
if not ( surface and surface.valid ) then return end
2021-10-13 10:21:53 +02:00
2022-03-13 20:19:59 +02:00
local maps = dynamic_data.treasure_maps or { }
local buried_treasure = dynamic_data.buried_treasure or { }
local ghosts = dynamic_data.ghosts or { }
2021-10-13 10:21:53 +02:00
for i = 1 , # maps do
local map = maps [ i ]
if map.state == ' on_ground ' then
local p = map.position
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
local nearby_characters = surface.find_entities_filtered { position = p , radius = 3 , name = ' character ' }
local nearby_characters_count = # nearby_characters
if nearby_characters_count > 0 then
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
local player
local j = 1
while j <= nearby_characters_count do
if nearby_characters [ j ] and nearby_characters [ j ] . valid and nearby_characters [ j ] . player and Common.validate_player ( nearby_characters [ j ] . player ) then
player = nearby_characters [ j ] . player
break
end
j = j + 1
end
if player then
local buried_treasure_candidates = { }
for _ , t in pairs ( buried_treasure ) do
if not ( t.associated_to_map ) then
buried_treasure_candidates [ # buried_treasure_candidates + 1 ] = t
end
end
if # buried_treasure_candidates == 0 then break end
local chosen = buried_treasure_candidates [ Math.random ( # buried_treasure_candidates ) ]
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
chosen.associated_to_map = true
local p2 = chosen.position
map.buried_treasure_position = p2
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
map.state = ' picked_up '
rendering.destroy ( map.mapobject_rendering )
2022-03-19 23:20:55 +02:00
2022-05-29 13:36:27 +02:00
Common.notify_force_light ( player.force , { ' pirates.find_map ' , player.name } )
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
map.x_renderings = {
rendering.draw_line {
width = 8 ,
surface = surface ,
from = { p2.x + 3 , p2.y + 3 } ,
to = { p2.x - 3 , p2.y - 3 } ,
color = { 1 , 0 , 0 } ,
gap_length = 0.2 ,
dash_length = 1 ,
draw_on_ground = true ,
-- players = {player},
} ,
rendering.draw_line {
width = 8 ,
surface = surface ,
from = { p2.x - 3 , p2.y + 3 } ,
to = { p2.x + 3 , p2.y - 3 } ,
color = { 1 , 0 , 0 } ,
gap_length = 0.2 ,
dash_length = 1 ,
draw_on_ground = true ,
-- players = {player},
} ,
}
end
end
end
end
2022-03-13 20:19:59 +02:00
if not ( dynamic_data.quest_type and ( not dynamic_data.quest_complete ) ) then return end
2021-10-13 10:21:53 +02:00
for i = 1 , # ghosts do
local ghost = ghosts [ i ]
if ghost.state == ' on_ground ' then
local p = ghost.position
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
local nearby_characters = surface.find_entities_filtered { position = p , radius = 3 , name = ' character ' }
local nearby_characters_count = # nearby_characters
if nearby_characters_count > 0 then
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
local player
local j = 1
while j <= nearby_characters_count do
if nearby_characters [ j ] and nearby_characters [ j ] . valid and nearby_characters [ j ] . player and Common.validate_player ( nearby_characters [ j ] . player ) then
player = nearby_characters [ j ] . player
break
end
j = j + 1
end
if player then
rendering.destroy ( ghost.ghostobject_rendering )
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
ghost.state = ' picked_up '
2022-03-19 23:20:55 +02:00
2022-05-29 13:36:27 +02:00
Common.notify_force ( player.force , { ' pirates.find_ghost ' , player.name } )
2022-03-19 23:20:55 +02:00
2022-03-13 20:19:59 +02:00
dynamic_data.quest_progress = dynamic_data.quest_progress + 1
2021-10-13 10:21:53 +02:00
Quest.try_resolve_quest ( )
end
end
end
end
end
2022-03-19 23:20:55 +02:00
local function cached_structure_delete_existing_entities_if_needed ( surface , position , special )
if ( not special.doNotDestroyExistingEntities ) then
-- destroy existing entities
local area = { left_top = { position.x - special.width / 2 , position.y - special.height / 2 } , right_bottom = { position.x + special.width / 2 + 0.5 , position.y + special.height / 2 + 0.5 } }
surface.destroy_decoratives { area = area }
local existing = surface.find_entities_filtered { area = area }
2022-05-29 13:36:27 +02:00
if existing then
2022-03-19 23:20:55 +02:00
for _ , e in pairs ( existing ) do
if not ( ( ( special.name == ' small_primitive_mining_base ' or special.name == ' small_mining_base ' ) and ( e.name == ' iron-ore ' or e.name == ' copper-ore ' or e.name == ' stone ' ) ) or ( special.name == ' uranium_miners ' and e.name == ' uranium-ore ' ) ) then
if not ( e.name and e.name == ' rocket-silo ' ) then
e.destroy ( )
end
end
end
end
end
end
2022-06-15 23:00:18 +02:00
local function cached_structure_delete_existing_unwalkable_tiles_if_needed ( surface , position , special )
local area = { left_top = { position.x - special.width / 2 , position.y - special.height / 2 } , right_bottom = { position.x + special.width / 2 + 0.5 , position.y + special.height / 2 + 0.5 } }
local existing = surface.find_tiles_filtered { area = area , collision_mask = " water-tile " }
if existing then
local tiles = { }
for _ , t in pairs ( existing ) do
tiles [ # tiles + 1 ] = { name = " landfill " , position = t.position }
end
if # tiles > 0 then
surface.set_tiles ( tiles , true )
end
end
end
2022-03-19 23:20:55 +02:00
function Public . interpret_shorthanded_force_name ( shorthanded_name )
local memory = Memory.get_crew_memory ( )
local ret
if shorthanded_name == ' ancient-friendly ' then
ret = memory.ancient_friendly_force_name
elseif shorthanded_name == ' ancient-hostile ' then
ret = memory.ancient_enemy_force_name
elseif shorthanded_name == ' crew ' then
ret = memory.force_name
elseif shorthanded_name == ' enemy ' then
ret = memory.enemy_force_name
2022-03-20 13:41:23 +02:00
else
ret = shorthanded_name
2022-03-19 23:20:55 +02:00
end
return ret
end
2022-05-29 13:36:27 +02:00
2021-10-13 10:21:53 +02:00
function Public . place_cached_structures ( tickinterval )
local memory = Memory.get_crew_memory ( )
local destination = Common.current_destination ( )
local surface_name = destination.surface_name
if ( not destination.dynamic_data ) or ( not destination.dynamic_data . structures_waiting_to_be_placed ) or ( not surface_name ) or ( not game.surfaces [ surface_name ] ) or ( not game.surfaces [ surface_name ] . valid ) then return end
2022-05-26 13:47:05 +02:00
if not ( memory.boat and memory.boat . surface_name and memory.boat . surface_name == surface_name ) then
return --We only want to generate structures once the players arrive on the island. Otherwise, the following issue happens. 2x2 structures force-generate nearby chunks. But if the island has many structures, that could cause a domino effect of chunk-generation, lagging the game.
-- Since this change, this function has little conceptual reason to be an on_tick function, but it makes sense to run it a few ticks after you teleport to the island, so it can stay one for now.
end
2021-10-13 10:21:53 +02:00
local surface = game.surfaces [ surface_name ]
local structures = destination.dynamic_data . structures_waiting_to_be_placed
2022-07-03 16:58:44 +02:00
for i = # structures , 1 , - 1 do
2021-10-13 10:21:53 +02:00
local structure = structures [ i ]
if game.tick > structure.tick + 5 then
local special = structure.data
local position = special.position
2022-07-03 16:58:44 +02:00
-- game.print(special.name)
2022-06-15 23:00:18 +02:00
-- Since this structure has cliffs, the positions need to be snapped and floored to nearest set of elements for x and y accordingly:
-- x: {..., -4, 0, 4, 8, ...}
-- y: {..., -4, 0, 4, 8, ...}
-- This is assuming that "cliff.position + offset" already has snapped positions as such:
-- x: {..., -2, 2, 6, ...}
-- y: {..., -1.5, 2.5, 6.5, ...}
-- The position would be corrected in "try_place" function, but it gets adjusted later with "terraingen_coordinates_offset", so have to do it here
if special.name == ' small_cliff_base ' then
position.x = position.x - position.x % 4
position.y = position.y - position.y % 4
-- add a small bias to avoid situations such as 7.999999999993
position.x = position.x + 0.01
position.y = position.y + 0.01
end
2022-05-29 13:36:27 +02:00
Common.ensure_chunks_at ( surface , position , Common.structure_ensure_chunk_radius )
2021-10-13 10:21:53 +02:00
2022-03-19 23:20:55 +02:00
cached_structure_delete_existing_entities_if_needed ( surface , position , special )
2022-06-15 23:00:18 +02:00
cached_structure_delete_existing_unwalkable_tiles_if_needed ( surface , position , special )
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
local saved_components = { }
for k = 1 , # special.components do
local c = special.components [ k ]
local force_name
2022-03-19 23:20:55 +02:00
if c.force then force_name = Public.interpret_shorthanded_force_name ( c.force ) end
2021-10-13 10:21:53 +02:00
if c.type == ' tiles ' then
local tiles = { }
for _ , p in pairs ( Common.tile_positions_from_blueprint ( c.bp_string , c.offset ) ) do
tiles [ # tiles + 1 ] = { name = c.tile_name , position = Utils.psum { position , p } }
end
if # tiles > 0 then
surface.set_tiles ( tiles , true )
end
2022-06-15 23:00:18 +02:00
elseif c.type == ' water_tiles ' then
local tiles = { }
for _ , p in pairs ( c.positions ) do
tiles [ # tiles + 1 ] = { name = c.tile_name , position = Utils.psum { position , p , c.offset } }
end
if # tiles > 0 then
surface.set_tiles ( tiles , true )
end
elseif c.type == ' cliffs ' then
--local c2 = {type = c.type, force_name = force_name, built_entities = {}}
for _ , e in pairs ( c.instances ) do
local p = Utils.psum { position , e.position , c.offset }
local e2 = surface.create_entity { name = c.name , position = p , cliff_orientation = e.cliff_orientation }
-- c2.built_entities[#c2.built_entities + 1] = e2
end
--saved_components[#saved_components + 1] = c2
2021-10-13 10:21:53 +02:00
elseif c.type == ' entities ' or c.type == ' entities_minable ' then
local c2 = { type = c.type , force_name = force_name , built_entities = { } }
for _ , e in pairs ( c.instances ) do
local p = Utils.psum { position , e.position , c.offset }
local e2 = surface.create_entity { name = c.name , position = p , direction = e.direction , force = force_name , amount = c.amount }
c2.built_entities [ # c2.built_entities + 1 ] = e2
end
saved_components [ # saved_components + 1 ] = c2
2022-06-15 23:00:18 +02:00
elseif c.type == ' vehicles ' then
local c2 = { type = c.type , force_name = force_name , built_entities = { } }
for _ , e in pairs ( c.instances ) do
local p = Utils.psum { position , e.position , c.offset }
local e2 = surface.create_entity { name = c.name , position = p , direction = e.direction }
c2.built_entities [ # c2.built_entities + 1 ] = e2
end
saved_components [ # saved_components + 1 ] = c2
2022-03-04 19:57:58 +02:00
elseif c.type == ' entities_grid ' then
local c2 = { type = c.type , force_name = force_name , built_entities = { } }
for x = Math.ceil ( - c.width / 2 ) , Math.ceil ( c.width / 2 ) , 1 do
for y = Math.ceil ( - c.height / 2 ) , Math.ceil ( c.height / 2 ) , 1 do
local p = Utils.psum { position , { x = x , y = y } , c.offset }
local e2 = surface.create_entity { name = c.name , position = p , direction = c.direction , force = force_name }
c2.built_entities [ # c2.built_entities + 1 ] = e2
end
end
saved_components [ # saved_components + 1 ] = c2
elseif c.type == ' entities_randomlyplaced ' then
local c2 = { type = c.type , force_name = force_name , built_entities = { } }
for _ = 1 , c.count do
local whilesafety = 0
local done = false
while whilesafety < 10 and done == false do
local rng_x = Math.random ( - c.r , c.r )
local rng_y = Math.random ( - c.r , c.r )
local p = Utils.psum { position , c.offset , { x = rng_x , y = rng_y } }
local name = c.name
if name == ' random-worm ' then name = Common.get_random_worm_type ( memory.evolution_factor ) end
local e = { name = name , position = p , force = force_name }
if surface.can_place_entity ( e ) then
local e2 = surface.create_entity ( e )
c2.built_entities [ # c2.built_entities + 1 ] = e2
done = true
end
whilesafety = whilesafety + 1
end
end
saved_components [ # saved_components + 1 ] = c2
elseif c.type == ' entities_randomlyplaced_border ' then
local c2 = { type = c.type , force_name = force_name , built_entities = { } }
for _ = 1 , c.count do
local whilesafety = 0
local done = false
while whilesafety < 10 and done == false do
local rng_1 = Math.random ( c.small_r , c.large_r )
local rng_2 = Math.random ( - c.large_r , c.large_r )
local p
if Math.random ( 2 ) == 1 then
if Math.random ( 2 ) == 1 then
p = { x = rng_1 , y = rng_2 }
else
p = { x = - rng_1 , y = rng_2 }
end
else
if Math.random ( 2 ) == 1 then
p = { x = rng_2 , y = rng_1 }
else
p = { x = rng_2 , y = - rng_1 }
end
end
local p2 = Utils.psum { position , c.offset , p }
local e = { name = c.name , position = p2 , force = force_name }
if surface.can_place_entity ( e ) then
local e2 = surface.create_entity ( e )
c2.built_entities [ # c2.built_entities + 1 ] = e2
done = true
end
whilesafety = whilesafety + 1
end
end
saved_components [ # saved_components + 1 ] = c2
2021-10-13 10:21:53 +02:00
elseif c.bp_string then
local c2 = { type = c.type , force_name = force_name , built_entities = { } }
local es = Common.build_from_blueprint ( c.bp_string , surface , Utils.psum { position , c.offset } , game.forces [ force_name ] )
2022-03-20 13:41:23 +02:00
2021-10-13 10:21:53 +02:00
for l = 1 , # es do
c2.built_entities [ # c2.built_entities + 1 ] = es [ l ]
end
saved_components [ # saved_components + 1 ] = c2
end
end
2022-05-29 13:36:27 +02:00
Structures.configure_structure_entities ( special.name , saved_components )
2021-10-13 10:21:53 +02:00
2022-05-29 13:36:27 +02:00
QuestStructures.create_quest_structure_entities ( special.name )
2021-10-13 10:21:53 +02:00
for j = i , # structures - 1 do
structures [ j ] = structures [ j + 1 ]
end
structures [ # structures ] = nil
end
end
end
function Public . update_boat_stored_resources ( tickinterval )
Common.update_boat_stored_resources ( )
end
function Public . buried_treasure_check ( tickinterval )
local memory = Memory.get_crew_memory ( )
local destination = Common.current_destination ( )
local remaining = destination.dynamic_data . treasure_remaining
if remaining and remaining > 0 and destination.surface_name and destination.dynamic_data . buried_treasure and # destination.dynamic_data . buried_treasure > 0 then
local surface = game.surfaces [ destination.surface_name ]
local treasure_table = destination.dynamic_data . buried_treasure
for i = 1 , # treasure_table do
local treasure = treasure_table [ i ]
if not treasure then break end
local p = treasure.position
local free = surface.can_place_entity { name = ' wooden-chest ' , position = p }
if free then
local inserters = {
surface.find_entities_filtered {
type = ' inserter ' ,
position = { x = p.x - 1 , y = p.y } ,
radius = 0.1 ,
direction = defines.direction . east
} ,
surface.find_entities_filtered {
type = ' inserter ' ,
position = { x = p.x + 1 , y = p.y } ,
radius = 0.1 ,
direction = defines.direction . west
} ,
surface.find_entities_filtered {
type = ' inserter ' ,
position = { x = p.x , y = p.y - 1 } ,
radius = 0.1 ,
direction = defines.direction . south
} ,
surface.find_entities_filtered {
type = ' inserter ' ,
position = { x = p.x , y = p.y + 1 } ,
radius = 0.1 ,
direction = defines.direction . north
}
}
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
for j = 1 , 4 do
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
if inserters [ j ] and inserters [ j ] [ 1 ] then
local ins = inserters [ j ] [ 1 ]
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
local t = treasure.treasure
-- if #treasure.treasure > 0 then
-- t = treasure.treasure
-- -- t = treasure.treasure[1]
-- end
if not t then break end
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
if destination.dynamic_data . treasure_remaining > 0 and ins.held_stack . count == 0 and ins.status == defines.entity_status . waiting_for_source_items then
surface.create_entity { name = ' item-on-ground ' , position = p , stack = { name = t.name , count = 1 } }
t.count = t.count - 1
destination.dynamic_data . treasure_remaining = destination.dynamic_data . treasure_remaining - 1
if destination.dynamic_data . treasure_remaining == 0 then
-- destroy all
local buried_treasure = destination.dynamic_data . buried_treasure
for _ , t2 in pairs ( buried_treasure ) do
t2 = nil
end
local maps = destination.dynamic_data . treasure_maps
for _ , m in pairs ( maps ) do
if m.state == ' on_ground ' then
rendering.destroy ( m.mapobject_rendering )
elseif m.state == ' picked_up ' and m.x_renderings and # m.x_renderings > 0 then
rendering.destroy ( m.x_renderings [ 1 ] )
rendering.destroy ( m.x_renderings [ 2 ] )
end
m = nil
end
elseif t.count <= 0 then
treasure.treasure = nil
local maps = destination.dynamic_data . treasure_maps
for _ , m in pairs ( maps ) do
if m.state == ' picked_up ' and m.buried_treasure_position and m.buried_treasure_position == p and m.x_renderings and # m.x_renderings > 0 then
m.state = ' inactive '
rendering.destroy ( m.x_renderings [ 1 ] )
rendering.destroy ( m.x_renderings [ 2 ] )
end
end
end
end
end
end
end
end
end
end
function Public . boat_movement_tick ( tickinterval )
local memory = Memory.get_crew_memory ( )
local destination = Common.current_destination ( )
2022-03-04 19:57:58 +02:00
local enemy_force_name = memory.enemy_force_name
2021-10-13 10:21:53 +02:00
local boat = memory.boat
if boat and boat.surface_name and game.surfaces [ boat.surface_name ] and game.surfaces [ boat.surface_name ] . valid and boat.speed and boat.speed > 0 and memory.game_lost == false then
local surface_type = destination.type
local ticker_increase = boat.speed / 60 * tickinterval
boat.speedticker1 = boat.speedticker1 + ticker_increase
boat.speedticker2 = boat.speedticker2 + ticker_increase
boat.speedticker3 = boat.speedticker3 + ticker_increase
if boat.speedticker1 >= Common.boat_steps_at_a_time then
boat.speedticker1 = 0
if not Progression.check_for_end_of_boat_movement ( boat ) then
Structures.Boats . currentdestination_move_boat_natural ( )
end
elseif boat.speedticker2 >= Common.boat_steps_at_a_time then
if surface_type and surface_type == Surfaces.enum . ISLAND and boat and boat.state and boat.state == Boats.enum_state . APPROACHING then
Structures.Boats . currentdestination_try_move_boat_steered ( )
end
boat.speedticker2 = 0
end
end
if memory.enemyboats then
for i = 1 , # memory.enemyboats do
local eboat = memory.enemyboats [ i ]
if eboat and eboat.surface_name and game.surfaces [ eboat.surface_name ] and game.surfaces [ eboat.surface_name ] . valid then
if eboat.state == Boats.enum_state . APPROACHING and eboat.speed and eboat.speed > 0 and memory.game_lost == false then
local ticker_increase = eboat.speed / 60 * tickinterval
eboat.speedticker1 = eboat.speedticker1 + ticker_increase
if eboat.speedticker1 >= 1 then
eboat.speedticker1 = 0
if eboat.state == Boats.enum_state . APPROACHING then
2022-03-04 19:57:58 +02:00
if Progression.check_for_end_of_boat_movement ( eboat ) then
-- if boat.unit_group and boat.unit_group.ref and boat.unit_group.ref.valid then boat.unit_group.ref.set_command({
-- type = defines.command.attack_area,
-- destination = ({memory.boat.position.x - 32, memory.boat.position.y} or {0,0}),
-- radius = 32,
-- distraction = defines.distraction.by_enemy
-- }) end
2022-03-11 00:11:51 +02:00
local units = game.surfaces [ eboat.surface_name ] . find_units { area = { { eboat.position . x - 12 , eboat.position . y - 12 } , { eboat.position . x + 12 , eboat.position . y + 12 } } , force = enemy_force_name , condition = ' same ' }
2022-03-04 19:57:58 +02:00
if # units > 0 then
local unit_group = game.surfaces [ eboat.surface_name ] . create_unit_group ( { position = eboat.position , force = enemy_force_name } )
for _ , unit in pairs ( units ) do
unit_group.add_member ( unit )
end
boat.unit_group = { ref = unit_group , script_type = ' landing-party ' }
boat.unit_group . ref.set_command ( {
type = defines.command . attack_area ,
destination = ( { memory.boat . position.x - 32 , memory.boat . position.y } or { 0 , 0 } ) ,
radius = 32 ,
distraction = defines.distraction . by_enemy
} )
end
else
2021-10-13 10:21:53 +02:00
local p = { x = eboat.position . x + 1 , y = eboat.position . y }
Boats.teleport_boat ( eboat , nil , p , CoreData.static_boat_floor )
if p.x % 7 < 1 then
Ai.update_landing_party_unit_groups ( eboat , 7 )
end
end
end
end
2022-03-04 19:57:58 +02:00
elseif eboat.state == Boats.enum_state . LANDED then
2022-03-19 23:20:55 +02:00
do end
2021-10-13 10:21:53 +02:00
end
else
memory.enemyboats [ i ] = nil
end
end
end
end
function Public . crowsnest_natural_move ( tickinterval )
local memory = Memory.get_crew_memory ( )
if not memory.loadingticks then
if not Public.overworld_check_collisions ( ) then
Overworld.try_overworld_move_v2 { x = 1 , y = 0 }
end
end
end
function Public . overworld_check_collisions ( tickinterval )
local memory = Memory.get_crew_memory ( )
if not memory.loadingticks then
Overworld.check_for_kraken_collisions ( )
return Overworld.check_for_destination_collisions ( )
end
return false
end
function Public . loading_update ( tickinterval )
local memory = Memory.get_crew_memory ( )
2022-02-24 21:39:03 +02:00
if memory.game_lost then return end
2022-03-13 04:09:21 +02:00
2021-10-13 10:21:53 +02:00
if not memory.loadingticks then return end
2022-03-13 03:44:32 +02:00
2022-03-13 04:09:21 +02:00
local currentdestination = Common.current_destination ( )
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
local destination_index = memory.mapbeingloadeddestination_index
if not destination_index then memory.loadingticks = nil return end
if ( not memory.boat . state ) or ( not ( memory.boat . state == Boats.enum_state . LANDED or memory.boat . state == Boats.enum_state . ATSEA_LOADING_MAP or memory.boat . state == Boats.enum_state . LEAVING_DOCK or ( memory.boat . state == Boats.enum_state . APPROACHING and destination_index == 1 ) ) ) then return end
memory.loadingticks = memory.loadingticks + tickinterval
-- if memory.loadingticks % 100 == 0 then game.print(memory.loadingticks) end
2022-03-13 04:09:21 +02:00
local destination_data = memory.destinations [ destination_index ]
if ( not destination_data ) then
if memory.boat and currentdestination.type == Surfaces.enum . LOBBY then
2021-10-13 10:21:53 +02:00
if memory.loadingticks >= 350 - Common.loading_interval then
if Boats.players_on_boat_count ( memory.boat ) > 0 then
if memory.loadingticks < 350 then
2022-05-29 13:36:27 +02:00
Common.notify_game ( { ' ' , ' [ ' .. memory.name .. ' ] ' , { ' pirates.loading_new_game ' } } )
2021-10-13 10:21:53 +02:00
elseif memory.loadingticks > 410 then
if not Crowsnest.get_crowsnest_surface ( ) then
Crew.initialise_crowsnest_1 ( )
elseif memory.loadingticks >= 470 then
Crew.initialise_crowsnest_2 ( )
Overworld.ensure_lane_generated_up_to ( 0 , 10 )
Surfaces.create_surface ( memory.destinations [ destination_index ] )
2022-05-29 13:36:27 +02:00
-- PiratesApiEvents.load_some_map_chunks(destination_index, 0.02)
2021-10-13 10:21:53 +02:00
end
end
else
if memory.loadingticks >= 1100 then
Boats.destroy_boat ( memory.boat )
Crew.disband_crew ( )
return
end
end
end
end
return
else
2022-03-13 04:09:21 +02:00
local surface_name = destination_data.surface_name
2021-10-13 10:21:53 +02:00
if not surface_name then return end
local surface = game.surfaces [ surface_name ]
if not surface then return end
2022-03-13 04:09:21 +02:00
if currentdestination.type == Surfaces.enum . LOBBY then
2021-10-13 10:21:53 +02:00
if memory.loadingticks >= 1260 then
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
if memory.boat and memory.boat . rendering_crewname_text and rendering.is_valid ( memory.boat . rendering_crewname_text ) then
rendering.destroy ( memory.boat . rendering_crewname_text )
memory.boat . rendering_crewname_text = nil
end
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
Progression.go_from_starting_dock_to_first_destination ( )
elseif memory.loadingticks > 1230 then
if memory.boat then
memory.boat . speed = 0
end
elseif memory.loadingticks > 860 then
if Boats.players_on_boat_count ( memory.boat ) > 0 then
local fraction = 0.07 + 0.7 * ( memory.loadingticks - 860 ) / 400
2022-05-29 13:36:27 +02:00
PiratesApiEvents.load_some_map_chunks ( destination_index , fraction )
2021-10-13 10:21:53 +02:00
else
Boats.destroy_boat ( memory.boat )
Crew.disband_crew ( )
return
end
elseif memory.loadingticks > 500 then
local d = ( Crowsnest.Data . visibilitywidth / 3 ) * ( memory.loadingticks - 500 ) / 500
Overworld.ensure_lane_generated_up_to ( 0 , d + 26 )
Overworld.ensure_lane_generated_up_to ( 24 , d + 13 )
Overworld.ensure_lane_generated_up_to ( - 24 , d )
-- elseif memory.loadingticks <= 500 and memory.loadingticks >= 100 then
-- local fraction = 0.02 + 0.05 * (memory.loadingticks - 100) / 400
2022-05-29 13:36:27 +02:00
-- PiratesApiEvents.load_some_map_chunks(destination_index, fraction)
2021-10-13 10:21:53 +02:00
end
elseif memory.boat . state == Boats.enum_state . ATSEA_LOADING_MAP then
2022-02-27 01:33:19 +02:00
local total = Common.map_loading_ticks_atsea
2022-03-13 04:09:21 +02:00
if currentdestination.type == Surfaces.enum . DOCK then
2022-02-27 01:33:19 +02:00
total = Common.map_loading_ticks_atsea_dock
2022-03-13 04:09:21 +02:00
elseif currentdestination.type == Surfaces.enum . ISLAND and currentdestination.subtype == Surfaces.Island . enum.MAZE then
2022-03-04 19:57:58 +02:00
total = Common.map_loading_ticks_atsea_maze
2022-02-27 01:33:19 +02:00
end
2022-03-04 19:57:58 +02:00
local eta_ticks = total - ( memory.loadingticks - ( memory.extra_time_at_sea or 0 ) )
2021-10-13 10:21:53 +02:00
2022-06-02 20:54:47 +02:00
-- log(_inspect{eta_ticks, (memory.active_sea_enemies.krakens and #memory.active_sea_enemies.krakens or 'nil'), memory.loadingticks})
2022-02-27 01:33:19 +02:00
if eta_ticks < 60 * 20 and memory.active_sea_enemies and ( memory.active_sea_enemies . krakens and # memory.active_sea_enemies . krakens > 0 ) then
2022-06-02 20:54:47 +02:00
memory.loadingticks = memory.loadingticks - tickinterval --reverse the change
2021-10-13 10:21:53 +02:00
else
2022-02-27 01:33:19 +02:00
local fraction = memory.loadingticks / ( total + ( memory.extra_time_at_sea or 0 ) )
2022-03-19 23:20:55 +02:00
2022-05-14 00:35:12 +02:00
if fraction > Common.fraction_of_map_loaded_at_sea then
2021-10-13 10:21:53 +02:00
Progression.progress_to_destination ( destination_index )
memory.loadingticks = 0
else
2022-05-29 13:36:27 +02:00
PiratesApiEvents.load_some_map_chunks_random_order ( destination_index , fraction ) --random order is good for maze world
2021-10-13 10:21:53 +02:00
end
end
elseif memory.boat . state == Boats.enum_state . LANDED then
2022-05-14 00:35:12 +02:00
local fraction = Common.fraction_of_map_loaded_at_sea + ( 1 - Common.fraction_of_map_loaded_at_sea ) * memory.loadingticks / Common.map_loading_ticks_onisland
2021-10-13 10:21:53 +02:00
if fraction > 1 then
memory.loadingticks = nil
else
2022-05-29 13:36:27 +02:00
PiratesApiEvents.load_some_map_chunks ( destination_index , fraction )
2021-10-13 10:21:53 +02:00
end
end
end
end
function Public . crowsnest_steer ( tickinterval )
local memory = Memory.get_crew_memory ( )
2022-02-24 21:39:03 +02:00
if memory.game_lost then return end
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
if memory.boat and memory.boat . state == Structures.Boats . enum_state.ATSEA_SAILING and memory.game_lost == false and memory.boat . crowsneststeeringchests then
local leftchest , rightchest = memory.boat . crowsneststeeringchests.left , memory.boat . crowsneststeeringchests.right
if leftchest and leftchest.valid and rightchest and rightchest.valid then
local inv_left = leftchest.get_inventory ( defines.inventory . chest )
local inv_right = rightchest.get_inventory ( defines.inventory . chest )
local count_left = inv_left.get_item_count ( " rail-signal " )
local count_right = inv_right.get_item_count ( " rail-signal " )
if count_left >= 100 and count_right < 100 and memory.overworldy > - 24 then
if Overworld.try_overworld_move_v2 { x = 0 , y = - 24 } then
2022-03-04 19:57:58 +02:00
local force = memory.force
2022-05-29 13:36:27 +02:00
Common.notify_force ( force , { ' pirates.steer_left ' } )
2021-10-13 10:21:53 +02:00
inv_left.remove ( { name = " rail-signal " , count = 100 } )
end
return
elseif count_right >= 100 and count_left < 100 and memory.overworldy < 24 then
if Overworld.try_overworld_move_v2 { x = 0 , y = 24 } then
2022-03-04 19:57:58 +02:00
local force = memory.force
2022-05-29 13:36:27 +02:00
Common.notify_force ( force , { ' pirates.steer_right ' } )
2021-10-13 10:21:53 +02:00
inv_right.remove ( { name = " rail-signal " , count = 100 } )
end
return
end
end
end
end
function Public . silo_update ( tickinterval )
local memory = Memory.get_crew_memory ( )
local destination = Common.current_destination ( )
if destination.type == Surfaces.enum . ISLAND then
2022-03-13 20:19:59 +02:00
local dynamic_data = destination.dynamic_data
local silos = dynamic_data.rocketsilos
2021-10-13 10:21:53 +02:00
2022-03-13 20:19:59 +02:00
if silos then
2022-02-24 21:39:03 +02:00
local silo = silos [ 1 ]
2022-03-13 20:19:59 +02:00
if silo and silo.valid then
if dynamic_data.silocharged then
if not dynamic_data.rocketlaunched then
silo.launch_rocket ( )
2021-10-13 10:21:53 +02:00
end
2022-03-13 20:19:59 +02:00
else
local p = silo.position
2022-03-19 23:20:55 +02:00
2022-03-13 20:19:59 +02:00
local e = dynamic_data.energychargedinsilosincelastcheck or 0
dynamic_data.energychargedinsilosincelastcheck = 0
2022-03-19 23:20:55 +02:00
2022-03-13 20:19:59 +02:00
dynamic_data.rocketsiloenergyconsumed = dynamic_data.rocketsiloenergyconsumed + e
2022-03-19 23:20:55 +02:00
2022-03-13 20:19:59 +02:00
dynamic_data.rocketsiloenergyconsumedwithinlasthalfsecond = e
2022-03-19 23:20:55 +02:00
2022-03-13 20:19:59 +02:00
if memory.enemy_force_name then
local ef = memory.enemy_force
if ef and ef.valid then
local extra_evo = Balance.evolution_per_full_silo_charge ( ) * e / dynamic_data.rocketsiloenergyneeded
Common.increment_evo ( extra_evo )
dynamic_data.evolution_accrued_silo = dynamic_data.evolution_accrued_silo + extra_evo
end
end
2022-03-19 23:20:55 +02:00
2022-03-13 20:19:59 +02:00
local pollution = e / 1000000 * Balance.silo_total_pollution ( ) / Balance.silo_energy_needed_MJ ( )
2022-03-19 23:20:55 +02:00
2022-03-13 20:19:59 +02:00
if p and pollution then
game.pollution_statistics . on_flow ( ' rocket-silo ' , pollution )
if not memory.floating_pollution then memory.floating_pollution = 0 end
2022-03-19 23:20:55 +02:00
2022-06-04 16:23:18 +02:00
-- Eventually I want to reformulate pollution not to pull from the map directly, but to pull from pollution_statistics. Previously all the silo pollution went to the map, but this causes a lag ~1-2 minutes. So as a compromise, let's send some to floating_pollution directly, and some to the map:
2022-06-04 16:23:51 +02:00
memory.floating_pollution = memory.floating_pollution + 3 * pollution / 4
game.surfaces [ destination.surface_name ] . pollute ( p , pollution / 4 )
2022-03-14 14:44:30 +02:00
2022-05-29 13:36:27 +02:00
if memory.overworldx >= 0 and dynamic_data.rocketsiloenergyconsumed >= 0.25 * dynamic_data.rocketsiloenergyneeded and ( not dynamic_data.parrot_silo_warned ) then
2022-03-14 14:44:30 +02:00
dynamic_data.parrot_silo_warned = true
2022-05-31 01:11:03 +02:00
local spawnerscount = Common.spawner_count ( game.surfaces [ destination.surface_name ] )
2022-05-29 17:27:04 +02:00
if spawnerscount > 0 then
Common.parrot_speak ( memory.force , { ' pirates.parrot_silo_warning ' } )
end
2022-03-14 14:44:30 +02:00
elseif dynamic_data.rocketsiloenergyconsumed >= dynamic_data.rocketsiloenergyneeded and ( not ( silo.rocket_parts == 100 ) ) and ( dynamic_data.silocharged == false ) and ( not memory.game_lost ) then
2022-03-13 20:19:59 +02:00
-- silo.energy = 0
silo.rocket_parts = 100
dynamic_data.silocharged = true
2022-03-19 23:20:55 +02:00
2022-03-13 20:19:59 +02:00
if CoreData.rocket_silo_death_causes_loss then
-- become immune after launching
silo.destructible = false
end
2022-03-04 19:57:58 +02:00
end
2021-10-13 10:21:53 +02:00
end
end
end
end
end
end
function Public . slower_boat_tick ( tickinterval )
local memory = Memory.get_crew_memory ( )
2022-02-24 21:39:03 +02:00
if memory.game_lost then return end
2021-10-13 10:21:53 +02:00
local destination = Common.current_destination ( )
if memory.boat . state == Boats.enum_state . LEAVING_DOCK then
memory.boat . speed = Math.min ( memory.boat . speed + 40 / tickinterval , 12 )
end
local p = memory.boat . position
2022-02-28 18:36:46 +02:00
if p and ( not ( destination.subtype and destination.subtype == IslandsCommon.enum . RADIOACTIVE ) ) and destination.surface_name and game.surfaces [ destination.surface_name ] and game.surfaces [ destination.surface_name ] . valid then --no locomotive pollute on radioactive islands
2021-10-13 10:21:53 +02:00
local pollution = Balance.boat_passive_pollution_per_minute ( destination.dynamic_data . timer ) / 3600 * tickinterval
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
game.surfaces [ destination.surface_name ] . pollute ( p , pollution )
game.pollution_statistics . on_flow ( ' locomotive ' , pollution )
end
if memory.enemyboats then
for i = 1 , # memory.enemyboats do
local b = memory.enemyboats [ i ]
2022-03-19 23:20:55 +02:00
2022-03-15 20:50:19 +02:00
-- if b.landing_time and destination.dynamic_data.timer and destination.dynamic_data.timer >= b.landing_time and b.spawner and b.spawner.valid then
-- -- if b.landing_time and destination.dynamic_data.timer and destination.dynamic_data.timer >= b.landing_time + 3 and b.spawner and b.spawner.valid then
-- b.spawner.destructible = true
-- b.landing_time = nil
-- end
2021-10-13 10:21:53 +02:00
end
end
end
function Public . LOS_tick ( tickinterval )
local memory = Memory.get_crew_memory ( )
local destination = Common.current_destination ( )
2022-03-04 19:57:58 +02:00
local force = memory.force
2021-10-13 10:21:53 +02:00
if not destination.surface_name then return end
local surface = game.surfaces [ destination.surface_name ]
if memory.boat and memory.boat . state == Boats.enum_state . APPROACHING or memory.boat . state == Boats.enum_state . LANDED or memory.boat . state == Boats.enum_state . RETREATING then
local p = memory.boat . position
local BoatData = Boats.get_scope ( memory.boat ) . Data
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
force.chart ( surface , { { p.x - BoatData.width / 2 - 70 , p.y - 80 } , { p.x - BoatData.width / 2 + 70 , p.y + 80 } } )
end
2022-03-14 14:44:30 +02:00
if CoreData.rocket_silo_death_causes_loss or ( destination.static_params and destination.static_params . base_cost_to_undock and destination.static_params . base_cost_to_undock [ ' launch_rocket ' ] and destination.static_params . base_cost_to_undock [ ' launch_rocket ' ] == true ) then
2022-03-11 18:46:02 +02:00
local silos = destination.dynamic_data . rocketsilos
if silos and silos [ 1 ] and silos [ 1 ] . valid then
local p = silos [ 1 ] . position
force.chart ( surface , { { p.x - 4 , p.y - 4 } , { p.x + 4 , p.y + 4 } } )
end
2021-10-13 10:21:53 +02:00
end
end
2022-03-12 00:53:36 +02:00
function Public . minimap_jam ( tickinterval )
2022-03-04 19:57:58 +02:00
local memory = Memory.get_crew_memory ( )
2022-03-14 23:38:44 +02:00
if memory.overworldx == Common.maze_minimap_jam_league and memory.boat and memory.boat . state == Boats.enum_state . LANDED then
2022-03-13 03:44:32 +02:00
local destination = Common.current_destination ( )
if destination.type == Surfaces.enum . ISLAND and destination.subtype == Surfaces.Island . enum.MAZE then
if not destination.surface_name then return end
local surface = game.surfaces [ destination.surface_name ]
local force = memory.force
force.clear_chart ( surface )
end
2022-03-04 19:57:58 +02:00
end
2022-03-13 03:44:32 +02:00
2022-03-04 19:57:58 +02:00
end
2021-10-13 10:21:53 +02:00
-- function Public.crewtick_handle_delayed_tasks(tickinterval)
-- local memory = Memory.get_crew_memory()
-- for _, task in pairs(memory.buffered_tasks) do
-- if not (memory.game_lost) then
-- if task == Delay.enum.PAINT_CROWSNEST then
-- Surfaces.Crowsnest.crowsnest_surface_delayed_init()
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
-- elseif task == Delay.enum.PLACE_DOCK_JETTY_AND_BOATS then
-- Surfaces.Dock.place_dock_jetty_and_boats()
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
-- local destination = Common.current_destination()
2022-03-07 20:41:42 +02:00
-- ShopDock.create_dock_markets(game.surfaces[destination.surface_name], Surfaces.Dock.Data.markets_position)
2021-10-13 10:21:53 +02:00
-- end
-- end
-- end
-- Delay.clear_buffer()
-- Delay.move_tasks_to_buffer()
-- end
2022-05-30 17:51:08 +02:00
function Public . Kraken_Destroyed_Backup_check ( tickinterval ) -- a server became stuck when the kraken spawner entity disappeared but the kraken_die had not fired, and I'm not sure why, so this is a backup checker for that case
2022-03-07 11:50:25 +02:00
local memory = Memory.get_crew_memory ( )
local boat = memory.boat
2022-03-19 23:20:55 +02:00
2022-03-07 11:50:25 +02:00
if boat and boat.surface_name and boat.state and boat.state == Boats.enum_state . ATSEA_LOADING_MAP then
if ( memory.active_sea_enemies and memory.active_sea_enemies . krakens and # memory.active_sea_enemies . krakens > 0 ) then
local surface = game.surfaces [ boat.surface_name ]
local some_spawners_should_be_alive = false
2022-03-07 20:54:58 +02:00
for i = 1 , Kraken.kraken_slots do
2022-03-07 11:50:25 +02:00
if memory.active_sea_enemies . krakens [ i ] then
local kraken_data = memory.active_sea_enemies . krakens [ i ]
2022-03-13 03:44:32 +02:00
if kraken_data.step and kraken_data.step >= 3 then
2022-03-07 11:50:25 +02:00
some_spawners_should_be_alive = true
end
end
end
local but_none_are = some_spawners_should_be_alive and # surface.find_entities_flitered { name = ' biter-spawner ' , force = memory.enemy_force_name } == 0
if but_none_are then
2022-03-07 20:54:58 +02:00
for i = 1 , Kraken.kraken_slots do
2022-03-07 11:50:25 +02:00
if memory.active_sea_enemies . krakens [ i ] then
Kraken.kraken_die ( i )
end
end
end
end
end
end
2021-10-13 10:21:53 +02:00
function Public . quest_progress_tick ( tickinterval )
local memory = Memory.get_crew_memory ( )
2022-02-24 21:39:03 +02:00
if memory.game_lost then return end
2021-10-13 10:21:53 +02:00
local destination = Common.current_destination ( )
2022-03-13 20:19:59 +02:00
local dynamic_data = destination.dynamic_data
2021-10-13 10:21:53 +02:00
2022-03-13 20:19:59 +02:00
if dynamic_data.quest_type then
if dynamic_data.quest_type == Quest.enum . TIME and ( not dynamic_data.quest_complete ) and dynamic_data.quest_progress > 0 and dynamic_data.quest_progressneeded ~= 1 then
dynamic_data.quest_progress = dynamic_data.quest_progress - tickinterval / 60
end
2022-03-19 23:20:55 +02:00
2022-03-13 20:19:59 +02:00
if dynamic_data.quest_type == Quest.enum . RESOURCEFLOW and ( not dynamic_data.quest_complete ) then
local force = memory.force
if not ( force and force.valid and dynamic_data.quest_params ) then return end
dynamic_data.quest_progress = force.item_production_statistics . get_flow_count { name = dynamic_data.quest_params . item , input = true , precision_index = defines.flow_precision_index . five_seconds , count = false }
Quest.try_resolve_quest ( )
end
2022-03-19 23:20:55 +02:00
2022-03-13 20:19:59 +02:00
if dynamic_data.quest_type == Quest.enum . RESOURCECOUNT and ( not dynamic_data.quest_complete ) then
local force = memory.force
if not ( force and force.valid and dynamic_data.quest_params ) then return end
dynamic_data.quest_progress = force.item_production_statistics . get_flow_count { name = dynamic_data.quest_params . item , input = true , precision_index = defines.flow_precision_index . one_thousand_hours , count = true } - dynamic_data.quest_params . initial_count
Quest.try_resolve_quest ( )
end
2021-10-13 10:21:53 +02:00
end
end
function Public . silo_insta_update ( )
local memory = Memory.get_crew_memory ( )
2022-02-24 21:39:03 +02:00
if memory.game_lost then return end
2021-10-13 10:21:53 +02:00
2022-03-13 03:44:32 +02:00
local destination = Common.current_destination ( )
2022-03-13 20:19:59 +02:00
local dynamic_data = destination.dynamic_data
2022-03-13 03:44:32 +02:00
2022-03-13 20:19:59 +02:00
local silos = dynamic_data.rocketsilos
2022-03-19 23:20:55 +02:00
2022-03-03 02:19:20 +02:00
if silos and silos [ 1 ] and silos [ 1 ] . valid then --need the first silo to be alive in order to charge any others
2022-03-13 20:19:59 +02:00
if dynamic_data.silocharged then
2022-02-24 21:39:03 +02:00
for i , silo in ipairs ( silos ) do
2022-03-28 01:40:32 +02:00
if silo and silo.valid then --sometimes theyre overwritten by other structures e.g. market
silo.energy = silo.electric_buffer_size
end
2022-02-24 21:39:03 +02:00
end
2021-10-13 10:21:53 +02:00
else
2022-02-24 21:39:03 +02:00
for i , silo in ipairs ( silos ) do
2022-03-28 01:40:32 +02:00
if silo and silo.valid then --sometimes theyre overwritten by other structures e.g. market
local e = silo.energy - 1
local e2 = dynamic_data.rocketsiloenergyneeded - dynamic_data.rocketsiloenergyconsumed
if e > 0 and e2 > 0 then
local absorb = Math.min ( e , e2 )
dynamic_data.energychargedinsilosincelastcheck = dynamic_data.energychargedinsilosincelastcheck + absorb
silo.energy = silo.energy - absorb
if dynamic_data.rocketsilochargedbools and ( not dynamic_data.rocketsilochargedbools [ i ] ) then
dynamic_data.rocketsilochargedbools [ i ] = true
local inv = silo.get_inventory ( defines.inventory . assembling_machine_input )
inv.insert { name = ' rocket-control-unit ' , count = 10 }
inv.insert { name = ' low-density-structure ' , count = 10 }
inv.insert { name = ' rocket-fuel ' , count = 10 }
end
else
silo.energy = 0
2022-02-24 21:39:03 +02:00
end
2021-10-13 10:21:53 +02:00
end
end
end
end
end
-- function Public.parrot_tick(tickinterval)
-- Parrot.parrot_tick()
-- end
function Public . update_recentcrewmember_list ( tickinterval )
local memory = Memory.get_crew_memory ( )
-- don't update this unless someone specifically becomes spectator or is planked:
-- for i = 1, #memory.crewplayerindices do
-- local s = memory.crewplayerindices[i]
-- if s then
-- memory.tempbanned_from_joining_data[s] = game.tick
-- end
-- end
-- for k, v in pairs(memory.tempbanned_from_joining_data or {}) do
-- if v <= game.tick - Common.ban_from_rejoining_crew_ticks then
-- memory.tempbanned_from_joining_data[k] = nil
-- end
-- end
end
-- function Public.globaltick_handle_delayed_tasks(tickinterval)
-- local global_memory = Memory.get_global_memory()
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
-- for _, task in pairs(global_memory.global_buffered_tasks) do
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
-- if task == Delay.global_enum.PLACE_LOBBY_JETTY_AND_BOATS then
-- Surfaces.Lobby.place_lobby_jetty_and_boats()
-- elseif task == Delay.global_enum.ADMIN_GO2 then
-- Delay.global_add(Delay.global_enum.ADMIN_GO3)
-- elseif task == Delay.global_enum.ADMIN_GO3 then
-- Memory.set_working_id(1)
-- local memory = Memory.get_crew_memory()
-- Overworld.ensure_generated_up_to_x(Crowsnest.Data.visibilitywidth/2)
-- memory.currentdestination_index = 1
-- Surfaces.create_surface(Common.current_destination())
-- Delay.global_add(Delay.global_enum.ADMIN_GO4)
-- elseif task == Delay.global_enum.ADMIN_GO4 then
-- Memory.set_working_id(1)
-- local memory = Memory.get_crew_memory()
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
-- Progression.go_from_starting_dock_to_first_destination()
-- memory.mapbeingloadeddestination_index = 1
-- memory.loadingticks = 0
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
-- end
-- end
-- Delay.global_clear_buffer()
-- Delay.global_move_tasks_to_buffer()
-- end
function Public . update_player_guis ( tickinterval )
2022-06-15 23:00:18 +02:00
-- local global_memory = Memory.get_global_memory()
2021-10-13 10:21:53 +02:00
local players = game.connected_players
for _ , player in pairs ( players ) do
2022-06-15 23:00:18 +02:00
local crew_id = Common.get_id_from_force_name ( player.force . name )
2021-10-13 10:21:53 +02:00
Memory.set_working_id ( crew_id )
Gui.update_gui ( player )
end
end
function Public . update_players_second ( )
local global_memory = Memory.get_global_memory ( )
local connected_players = game.connected_players
local playerindex_to_time_played_continuously = { }
2022-03-01 17:57:23 +02:00
local playerindex_to_captainhood_priority = { }
2021-10-13 10:21:53 +02:00
for playerindex , time in pairs ( global_memory.playerindex_to_time_played_continuously ) do
local player = game.players [ playerindex ]
if player and Common.validate_player ( player ) then
-- port over
playerindex_to_time_played_continuously [ playerindex ] = time
end
end
2022-03-01 17:57:23 +02:00
for playerindex , time in pairs ( global_memory.playerindex_to_captainhood_priority ) do
2021-10-13 10:21:53 +02:00
local player = game.players [ playerindex ]
if player and Common.validate_player ( player ) then
-- port over
2022-03-01 17:57:23 +02:00
playerindex_to_captainhood_priority [ playerindex ] = time
2021-10-13 10:21:53 +02:00
end
end
for _ , player in pairs ( connected_players ) do
2022-06-15 23:00:18 +02:00
local crew_id = Common.get_id_from_force_name ( player.force . name )
2022-03-01 23:59:48 +02:00
Memory.set_working_id ( crew_id )
2021-10-13 10:21:53 +02:00
if player.afk_time < Common.afk_time then
playerindex_to_time_played_continuously [ player.index ] = playerindex_to_time_played_continuously [ player.index ] or 0
playerindex_to_time_played_continuously [ player.index ] = playerindex_to_time_played_continuously [ player.index ] + 1
2022-03-01 23:59:48 +02:00
if Common.is_captain ( player ) then
playerindex_to_captainhood_priority [ player.index ] = 0
else
playerindex_to_captainhood_priority [ player.index ] = playerindex_to_captainhood_priority [ player.index ] or 0
2022-03-19 23:20:55 +02:00
2022-03-01 23:59:48 +02:00
playerindex_to_captainhood_priority [ player.index ] = playerindex_to_captainhood_priority [ player.index ] + 1
end
2021-10-13 10:21:53 +02:00
else
2022-03-01 23:59:48 +02:00
playerindex_to_time_played_continuously [ player.index ] = 0
playerindex_to_captainhood_priority [ player.index ] = 0
2021-10-13 10:21:53 +02:00
end
end
2022-03-01 17:57:23 +02:00
global_memory.playerindex_to_captainhood_priority = playerindex_to_captainhood_priority
2021-10-13 10:21:53 +02:00
global_memory.playerindex_to_time_played_continuously = playerindex_to_time_played_continuously
local afk_player_indices = { }
for _ , player in pairs ( connected_players ) do
if player.afk_time >= Common.afk_time then
afk_player_indices [ # afk_player_indices + 1 ] = player.index
end
end
global_memory.afk_player_indices = afk_player_indices
-- after updating tables:
for _ , index in pairs ( afk_player_indices ) do
local player = game.players [ index ]
2022-06-15 23:00:18 +02:00
local crew_id = Common.get_id_from_force_name ( player.force . name )
2022-03-01 23:59:48 +02:00
Memory.set_working_id ( crew_id )
Roles.afk_player_tick ( player )
2021-10-13 10:21:53 +02:00
end
end
2022-06-08 15:26:49 +02:00
function Public . update_alert_sound_frequency_tracker ( )
local memory = Memory.get_crew_memory ( )
if memory.seconds_until_alert_sound_can_be_played_again > 0 then
memory.seconds_until_alert_sound_can_be_played_again = memory.seconds_until_alert_sound_can_be_played_again - 1
2022-06-15 23:00:18 +02:00
memory.seconds_until_alert_sound_can_be_played_again = Math.max ( 0 , memory.seconds_until_alert_sound_can_be_played_again )
end
end
function Public . check_for_cliff_explosives_in_hold_wooden_chests ( )
local memory = Memory.get_crew_memory ( )
local input_chests = memory.hold_surface_destroyable_wooden_chests
if not input_chests then return end
for i , chest in ipairs ( input_chests ) do
if chest and chest.valid then
local item_count = chest.get_item_count ( ' cliff-explosives ' )
if item_count and item_count > 0 then
local surface = chest.surface
local explosion = {
name = ' wooden-chest-explosion ' ,
position = chest.position
}
local remnants = {
name = ' wooden-chest-remnants ' ,
position = chest.position
}
chest.destroy ( )
surface.create_entity ( explosion )
surface.create_entity ( remnants )
table.fast_remove ( memory.hold_surface_destroyable_wooden_chests , i )
end
end
2022-06-08 15:26:49 +02:00
end
end
2021-10-13 10:21:53 +02:00
2022-07-02 17:42:22 +02:00
-- Code taken from Mountain fortress
local function equalise_fluid_storage_pair ( storage1 , storage2 )
if not storage1.valid then
return
end
if not storage2.valid then
return
end
local source_fluid = storage1.fluidbox [ 1 ]
if not source_fluid then
return
end
local target_fluid = storage2.fluidbox [ 1 ]
local source_fluid_amount = source_fluid.amount
local amount
if target_fluid then
amount = source_fluid_amount - ( ( target_fluid.amount + source_fluid_amount ) * 0.5 )
else
amount = source_fluid.amount * 0.5
end
if amount <= 0 then
return
end
local inserted_amount = storage2.insert_fluid ( { name = source_fluid.name , amount = amount , temperature = source_fluid.temperature } )
if inserted_amount > 0 then
storage1.remove_fluid ( { name = source_fluid.name , amount = inserted_amount } )
end
end
-- This function assumes that there is equal amount of special storage tanks on deck and every hold.
-- NOTE: This function only equalises adjacent storage tank pairs. That is "Deck - 1st Hold" and "Nth Hold - (N+1)th Hold" pairs
function Public . equalise_fluid_storages ( )
local memory = Memory.get_crew_memory ( )
local boat = memory.boat
if boat.upstairs_fluid_storages and boat.downstairs_fluid_storages then
-- Iterate every chain of together connected storages from deck and all holds
for i = 1 , # boat.upstairs_fluid_storages do
local storages = { }
storages [ 1 ] = boat.upstairs_fluid_storages [ i ]
for j = 1 , memory.hold_surface_count do
storages [ j + 1 ] = boat.downstairs_fluid_storages [ j ] [ i ]
end
for j = 2 , # storages do
equalise_fluid_storage_pair ( storages [ j ] , storages [ j - 1 ] )
equalise_fluid_storage_pair ( storages [ j - 1 ] , storages [ j ] )
end
end
end
end
2021-10-13 10:21:53 +02:00
return Public