1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2025-09-16 09:06:21 +02:00

move in pirates folders

This commit is contained in:
danielmartin0
2021-10-13 09:21:53 +01:00
parent aef46f2d0e
commit 4da8094a0b
95 changed files with 25372 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

BIN
locale/.DS_Store vendored Normal file

Binary file not shown.

44
locale/en/pirates.cfg Normal file
View File

@@ -0,0 +1,44 @@
[pirates]
softmod_info_header_before_version_number==== Pirate Ship v
softmod_info_header_after_version_number= ===
softmod_info_body_1=Ahoy, pirate. If you're not in a crew — click 'Play'.
softmod_info_game_description_1=Game Description
softmod_info_game_description_2=Set sail. Collect resources and build up the ship in order to survive as many leagues as possible. The ship moves with code magic. To upgrade the ship, visit a dock. Each crew has a captain, who can perform actions such as making the boat leave early.\n\nGame progression is significantly slowed down the smaller the crew.\n\n[font=default-bold]Win condition:[/font] Travel 1000 leagues. [font=default-bold]Lose condition:[/font] A cannon or silo is destroyed.
softmod_info_bugs_1=Known issues
softmod_info_bugs_2=- Circuit connections don't survive when the ship teleports between surfaces.
softmod_info_new_players_1=For New Players
softmod_info_new_players_2=Try asking the captain what you can help with, or just mine resources and bring them to the ship.
softmod_info_tips_1=Features of the game that are hard to work out alone
softmod_info_tips_2=• Resources granted to the ship appear in the captain's cabin.\n• After the first island, the ship makes ore over time.\n• Charging a silo launches a rocket. This makes gold and coin, but also pollution and evo.\n• Charging a silo drains power from everything else on its network.\n• Once a silo has launched a rocket, biters will ignore it.\n• If X marks the spot, use inserters to dig.\n• You can steer the boat from the crow's nest by placing 100 rail signals in one of the blue boxes.\n• Labs producitivity increases with each league.\n• To launch a second parallel run, you need a fifth of the server's pirates to endorse it.\n• Time increase in evolution, and passive pollution, are both proportional to the number of remaining nests. However, destroying a nest will immediately jump evolution by roughly the amount it 'would have' made had it survived. \n• At Abandoned Labs, biters don't care if you emit pollution. They only care how long you stay.
softmod_info_updates_1=Development
softmod_info_updates_2=After more than a year on and off development, Pirate Ship is released. Not everything made it into 1.0. We don't have a 'city' in the lobby with a practice boat, nor 'biter forts' on the top lane, 'maze wurld', localisation to other languages, nor pvp. But for now, it is time to enjoy and tweak 1.0.
softmod_info_credits_1=Credits
softmod_info_credits_2=Softmod designed and written by thesixthroc. Comfy codebase and help from Gerkiz, Hanakocz and Mew @ Comfy Industries (https://getcomfy.eu). Most island structure blueprints contributed by Mattisso.\n\n"Those white gloves. I'll never forget them 'till the day I die." - Dr. John
softmod_info_credits_2_old=Softmod designed and written by thesixthroc. Comfy codebase help from Gerkiz, Hanakocz and Mew @ Comfy Industries (https://getcomfy.eu). Most island structure blueprints were contributed by Mattisso. Gold sprite by Clint Bellanger. Parrot sprites by @pixelthen.\n\n"Those white gloves. I'll never forget them 'till the day I die." - Dr. John
softmod_info_body_promote=by thesixthroc
softmod_info_body_promote_old2=patreon.com/thesixthroc
softmod_info_body_clicky=Click to dismiss.
softmod_info_body_some_old_stuff="Those white gloves. I'll never forget them 'till the day I die." - Dr. John
proposal_displayform=__1__ — __2__
run_displayform= __2__
crewmember_displayform=[color=__2__,__3__,__4__]__5__[/color] [color=1,1,1]__6__[/color]
capacity_tooltip=Capacity. Sets the maximum number of crewmembers allowed.\n\n(Unlike in Beta, the capacity option does not affect pollution and evo; instead, the number of non-afk crewmates does.)
difficulty_tooltip=Difficulty.\n\nHigher difficulties have higher pollution and evo, higher biter damage, lower gold loot, but higher chest loot, along with small effects on the time per island, quest requirements, and silo position.\n\nDifficulty also determines the material the ship is made out of.
mode_tooltip=Mode.
auto_undock_tooltip=The maximum time to stay at this location.\n\nOnce this time is reached, the boat undocks automatically. The captain can choose to leave earlier.
atsea_loading_tooltip=The next destination is loading.
leave_anytime_tooltip=The captain chooses when to undock the ship.
resources_needed_tooltip_1=At the next destination, these resources will be needed in order to undock early.
resources_needed_tooltip_2=The captain can undock early, but only if enough resources have been stored in the captain's cabin.
resources_needed_tooltip_3=The captain can only undock if enough resources are stored in the captain's cabin.

BIN
maps/.DS_Store vendored Normal file

Binary file not shown.

BIN
maps/pirates/.DS_Store vendored Normal file

Binary file not shown.

810
maps/pirates/ai.lua Normal file
View File

@@ -0,0 +1,810 @@
local Memory = require 'maps.pirates.memory'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local inspect = require 'utils.inspect'.inspect
local Structures = require 'maps.pirates.structures.structures'
local Boats = require 'maps.pirates.structures.boats.boats'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Islands = require 'maps.pirates.surfaces.islands.islands'
local Sea = require 'maps.pirates.surfaces.sea.sea'
local Crew = require 'maps.pirates.crew'
local Quest = require 'maps.pirates.quest'
local Public = {}
local function fake_boat_target()
local memory = Memory.get_crew_memory()
if memory.boat and memory.boat.position then
return {valid = true, position = {x = memory.boat.position.x - 60, y = memory.boat.position.y} or nil, name = 'boatarea'}
end
end
-- fff 283 discussed pollution mechanics: https://factorio.com/blog/post/fff-283
local side_attack_target_names = {
'character',
'pumpjack',
'radar',
'burner-mining-drill',
'electric-mining-drill',
'nuclear-reactor',
'boiler',
'oil-refinery',
'centrifuge',
}
--=== Tick Actions
function Public.Tick_actions(tickinterval)
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
if (not destination.type) or (not destination.type == Surfaces.enum.ISLAND) then return end
if (not memory.boat.state) or (not (memory.boat.state == Boats.enum_state.LANDED or memory.boat.state == Boats.enum_state.RETREATING)) then return end
if (memory.gamelost or memory.gamewon) or (not destination.dynamic_data.timeratlandingtime) or destination.dynamic_data.timer < destination.dynamic_data.timeratlandingtime + Common.seconds_after_landing_to_enable_AI then return end
if memory.boat.state == Boats.enum_state.LANDED then
local ef = game.forces[memory.enemy_force_name]
local extra_evo = tickinterval/60 * Balance.evolution_per_second()
ef.evolution_factor = ef.evolution_factor + extra_evo
destination.dynamic_data.evolution_accrued_time = destination.dynamic_data.evolution_accrued_time + extra_evo
end
-- if destination.subtype and destination.subtype == Islands.enum.RED_DESERT then return end -- This was a hack to stop biter boats causing attacks, but, it has the even worse effect of stopping all floating_pollution gathering.
local minute_cycle = {-- even seconds only
[2] = Public.eat_up_fraction_of_all_pollution_wrapped,
[4] = Public.try_rogue_attack,
[6] = Public.poke_script_groups,
[12] = Public.try_main_attack,
[16] = Public.poke_script_groups,
-- [18] = Public.try_secondary_attack, --commenting out: less attacks per minute, but stronger
[20] = Public.tell_biters_near_silo_to_attack_it,
[26] = Public.poke_script_groups,
[28] = Public.eat_up_fraction_of_all_pollution_wrapped,
[30] = Public.try_secondary_attack,
[36] = Public.poke_script_groups,
[46] = Public.poke_script_groups,
[50] = Public.tell_biters_near_silo_to_attack_it,
[52] = Public.create_mail_delivery_biters,
[56] = Public.poke_script_groups,
[58] = Public.poke_inactive_scripted_biters,
}
if minute_cycle[(game.tick / 60) % 60] then
minute_cycle[(game.tick / 60) % 60]()
end
end
function Public.eat_up_fraction_of_all_pollution_wrapped()
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Common.current_destination().surface_name]
Public.eat_up_fraction_of_all_pollution(surface, 0.05)
end
function Public.eat_up_fraction_of_all_pollution(surface, fraction_of_global_pollution)
local memory = Memory.get_crew_memory()
local enemy_force_name = memory.enemy_force_name
local pollution_available = memory.floating_pollution
local chunk_positions = {}
for i = 1, Math.ceil(surface.map_gen_settings.width/32),1 do
for j = 1, Math.ceil(surface.map_gen_settings.height/32),1 do
chunk_positions[#chunk_positions + 1] = {x = 16 + i * 32 - surface.map_gen_settings.width/2, y = 16 + j * 32 - surface.map_gen_settings.height/2}
end
end
for i = 1, #chunk_positions do
local p = chunk_positions[i]
local pollution = surface.get_pollution(p)
local pollution_to_eat = pollution * fraction_of_global_pollution
surface.pollute(p, - pollution_to_eat)
-- Radioactive world doesn't absorb map pollution:
if not (Common.current_destination().subtype and Common.current_destination().subtype == Islands.enum.RADIOACTIVE) then
pollution_available = pollution_available + pollution_to_eat
end
end
-- if _DEBUG then
-- game.print(string.format('ate %f pollution', pollution_available))
-- end
memory.floating_pollution = pollution_available
end
function Public.try_main_attack()
if Math.random(2) == 2 then return end
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Common.current_destination().surface_name]
local group = Public.spawn_group_of_scripted_biters(2/3, 6, 128)
local target = Public.generate_main_attack_target()
if not group or not group.valid or not target or not target.valid then return end
-- group.set_command(Public.attack_target(target))
Public.group_set_commands(group, Public.attack_target(target))
-- if _DEBUG then game.print(game.tick .. string.format(": sending main attack of %s units from {%f,%f} to %s", #group.members, group.position.x, group.position.y, target.name)) end
end
function Public.try_secondary_attack()
if Math.random(2) == 2 then return end
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Common.current_destination().surface_name]
local group = Public.spawn_group_of_scripted_biters(2/3, 12, 128)
if not (group and group.valid) then return end
local target
if Math.random(2) == 1 then
target = Public.generate_main_attack_target()
else
target = Public.generate_side_attack_target(surface, group.position)
end
if not group or not group.valid or not target or not target.valid then return end
-- group.set_command(Public.attack_target(target))
Public.group_set_commands(group, Public.attack_target(target))
-- if _DEBUG then game.print(game.tick .. string.format(": sending main attack of %s units from {%f,%f} to %s", #group.members, group.position.x, group.position.y, target.name)) end
end
function Public.try_rogue_attack()
if Math.random(2) == 2 then return end
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Common.current_destination().surface_name]
local group = Public.spawn_group_of_scripted_biters(1/2, 6, 128)
if not (group and group.valid) then return end
local target = Public.generate_side_attack_target(surface, group.position)
if not (target and target.valid) then return end
-- group.set_command(Public.attack_target(target))
Public.group_set_commands(group, Public.attack_target(target))
-- if _DEBUG then game.print(game.tick .. string.format(": sending rogue attack of %s units from {%f,%f} to %s", #group.members, group.position.x, group.position.y, target.name)) end
end
function Public.tell_biters_near_silo_to_attack_it()
-- careful with this function, you don't want to pull biters onto the silo before any aggro has happened
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local enemy_force_name = memory.enemy_force_name
-- don't do this too early
if destination.dynamic_data.timer < destination.dynamic_data.timeratlandingtime + Common.seconds_after_landing_to_enable_AI * 4 then return end
if not (destination.dynamic_data.rocketsilo and destination.dynamic_data.rocketsilo.valid and destination.dynamic_data.rocketsilo.destructible) then return end
local attackcommand = Public.attack_target_entity(destination.dynamic_data.rocketsilo)
if attackcommand then
surface.set_multi_command(
{
command = attackcommand,
unit_count = Math.random(1, Math.floor(1 + game.forces[enemy_force_name].evolution_factor * 100)),
force = enemy_force_name,
unit_search_distance = 10
}
)
end
end
function Public.poke_script_groups()
local memory = Memory.get_crew_memory()
for index, group in pairs(memory.scripted_unit_groups) do
local groupref = group.ref
if not groupref.valid or groupref.surface.index ~= game.surfaces[Common.current_destination().surface_name].index or #groupref.members < 1 then
memory.scripted_unit_groups[index] = nil
else
if groupref.state == defines.group_state.finished then
if Math.random(20) == 20 then
local command = Public.attack_obstacles(groupref.surface, {x = groupref.position.x, y = groupref.position.y})
groupref.set_command(command)
else
groupref.set_autonomous() --means go home, really
end
elseif group.state == defines.group_state.gathering then
groupref.start_moving()
-- elseif group.state == defines.group_state.wander_in_group then
-- groupref.set_autonomous() --means go home, really
end
end
end
end
function Public.poke_inactive_scripted_biters()
local memory = Memory.get_crew_memory()
for unit_number, biter in pairs(memory.scripted_biters) do
if Public.is_biter_inactive(biter) then
memory.scripted_biters[unit_number] = nil
if biter.entity and biter.entity.valid then
local target = Public.nearest_target()
if target and target.valid then
Public.group_set_commands(biter.entity, Public.attack_target(target))
end
end
end
end
end
function Public.create_mail_delivery_biters()
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Common.current_destination().surface_name]
local enemy_force_name = memory.enemy_force_name
local spawners = surface.find_entities_filtered{name = 'biter-spawner', force = enemy_force_name}
local try_how_many_groups = Math.min(Math.max(0, (#spawners - 8) / 100), 4)
for i = 1, try_how_many_groups do
if Math.random(2) == 1 then
local s1 = spawners[Math.random(#spawners)]
local far_spawners = {}
for j = 1, #spawners do
local s2 = spawners[i]
if not (i == j or Math.distance(s1.position, s2.position) < 250) then
far_spawners[#far_spawners + 1] = s2
end
end
if #far_spawners > 0 then
local s2 = far_spawners[Math.random(#far_spawners)]
memory.floating_pollution = memory.floating_pollution + 64
local units = Public.try_spawner_spend_fraction_of_available_pollution_on_biters(s1, 1/4, 4, 32, 'small-biter')
memory.floating_pollution = memory.floating_pollution - 64
if (not units) or (not #units) or (#units == 0) then return end
local start_p = surface.find_non_colliding_position('rocket-silo', s1.position, 256, 2) or s1.position
local unit_group = surface.create_unit_group({position = start_p, force = enemy_force_name})
for _, unit in pairs(units) do
unit_group.add_member(unit)
end
memory.scripted_unit_groups[unit_group.group_number] = {ref = unit_group, script_type = 'mail-delivery'}
Public.group_set_commands(unit_group, {
Public.move_to(s2.position),
Public.wander_around(),
})
-- game.print(string.format('%f biters delivering mail from %f, %f to %f, %f', #units, s1.position.x, s1.position.y, s2.position.x, s2.position.y))
end
end
end
end
--=== Spawn scripted biters
function Public.spawn_group_of_scripted_biters(fraction_of_floating_pollution, minimum_avg_units, maximum_units)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Common.current_destination().surface_name]
local enemy_force_name = memory.enemy_force_name
-- @TODO: bring this 512 constant out into a variable somewhere
if Public.get_scripted_biter_count() > 512 * memory.difficulty then
return nil
end
local spawner = Public.get_random_spawner(surface)
if not spawner then return end
local units = Public.try_spawner_spend_fraction_of_available_pollution_on_biters(spawner, fraction_of_floating_pollution, minimum_avg_units, maximum_units)
if (not units) or (not #units) or (#units == 0) then return end
local position = surface.find_non_colliding_position('rocket-silo', spawner.position, 256, 2) or spawner.position
local unit_group = surface.create_unit_group({position = position, force = enemy_force_name})
for _, unit in pairs(units) do
unit_group.add_member(unit)
end
memory.scripted_unit_groups[unit_group.group_number] = {ref = unit_group, script_type = 'attacker'}
return unit_group
end
function Public.try_spawner_spend_fraction_of_available_pollution_on_biters(spawner, fraction_of_floating_pollution, minimum_avg_units, maximum_units, enforce_type)
maximum_units = maximum_units or 256
local memory = Memory.get_crew_memory()
local surface = spawner.surface
local spawnerposition = spawner.position
local difficulty = memory.difficulty
local enemy_force_name = memory.enemy_force_name
local evolution = game.forces[enemy_force_name].evolution_factor
local units_created_count = 0
local units_created = {}
local pollution_available = memory.floating_pollution
local budget = fraction_of_floating_pollution * pollution_available
local initialbudget = budget
local base_pollution_cost_multiplier = 1
local destination = Common.current_destination()
if destination.dynamic_data then
local spawnerscount = Common.spawner_count(surface)
local initial_spawner_count = destination.dynamic_data.initial_spawner_count
if initial_spawner_count and initial_spawner_count > 0 then
if spawnerscount > 0 then
-- if Common.current_destination().subtype and Common.current_destination().subtype == Islands.enum.RADIOACTIVE then
-- -- destroying spawners doesn't do quite as much here:
-- base_pollution_cost_multiplier = (initial_spawner_count/spawnerscount)^(1/3)
-- else
-- base_pollution_cost_multiplier = (initial_spawner_count/spawnerscount)^(1/2)
-- end
-- base_pollution_cost_multiplier = (initial_spawner_count/spawnerscount)^(1/2)
-- Now directly proportional:
base_pollution_cost_multiplier = Math.min(1, initial_spawner_count/spawnerscount)
else
base_pollution_cost_multiplier = 1000000
end
end
end
if memory.overworldx == 0 then
-- @check this is right:
base_pollution_cost_multiplier = base_pollution_cost_multiplier * 3
end
base_pollution_cost_multiplier = base_pollution_cost_multiplier * Balance.scripted_biters_pollution_cost_multiplier()
if budget >= minimum_avg_units * Common.averageUnitPollutionCost(evolution) * base_pollution_cost_multiplier then
local function spawn(name2)
units_created_count = units_created_count + 1
local unittype_pollutioncost = CoreData.biterPollutionValues[name2] * base_pollution_cost_multiplier
local p = surface.find_non_colliding_position(name2, spawnerposition, 50, 2)
if not p then return end
local biter = surface.create_entity({name = name2, force = enemy_force_name, position = p})
units_created[#units_created + 1] = biter
memory.scripted_biters[biter.unit_number] = {entity = biter, created_at = game.tick}
pollution_available = pollution_available - unittype_pollutioncost
budget = budget - unittype_pollutioncost
-- flow statistics should count the number of biters generated, without factors for extra expenditure:
game.pollution_statistics.on_flow(name2, - CoreData.biterPollutionValues[name2] * Balance.scripted_biters_pollution_cost_multiplier())
return biter.unit_number
end
local mixed = (Math.random(2) == 1)
if mixed then
local whilesafety = 1000
local next_name = enforce_type or Common.get_random_unit_type(evolution)
while units_created_count < maximum_units and budget >= CoreData.biterPollutionValues[next_name] * base_pollution_cost_multiplier and #memory.scripted_biters < Common.total_max_biters and whilesafety > 0 do
whilesafety = whilesafety - 1
spawn(next_name)
next_name = enforce_type or Common.get_random_unit_type(evolution)
end
else
local name = enforce_type or Common.get_random_unit_type(evolution)
local whilesafety = 1000
while units_created_count < maximum_units and budget >= CoreData.biterPollutionValues[name] * base_pollution_cost_multiplier and #memory.scripted_biters < Common.total_max_biters and whilesafety > 0 do
whilesafety = whilesafety - 1
spawn(name)
end
end
memory.floating_pollution = pollution_available
end
return units_created
end
--=== Misc Functions
function Public.generate_main_attack_target()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local target = nil
local fractioncharged = 0
if (not destination.dynamic_data.rocketlaunched) and destination.dynamic_data.rocketsilo and destination.dynamic_data.rocketsilo.valid and destination.dynamic_data.rocketsilo.destructible and destination.dynamic_data.rocketsiloenergyconsumed and destination.dynamic_data.rocketsiloenergyneeded and destination.dynamic_data.rocketsiloenergyneeded > 0 then
fractioncharged = destination.dynamic_data.rocketsiloenergyconsumed / destination.dynamic_data.rocketsiloenergyneeded
end
local rng = Math.random()
if rng <= fractioncharged^(1/2) then
target = destination.dynamic_data.rocketsilo
else
target = fake_boat_target()
end
return target
end
function Public.generate_side_attack_target(surface, position)
local entities = surface.find_entities_filtered{name = side_attack_target_names}
if not entities then return end
if Math.random(20) >= #entities then return end
entities = Math.shuffle(entities)
entities = Math.shuffle_distancebiased(entities, position)
local weights = {}
for index, _ in pairs(entities) do
weights[#weights + 1] = 1 + Math.floor((#entities - index) / 2)
end
return Math.raffle(entities, weights)
end
function Public.nearest_target(surface, position)
local names = {'rocket-silo'}
for _, name in pairs(side_attack_target_names) do
names[#names + 1] = name
end
local entities = surface.find_entities_filtered{name = names}
local d = 9999
local nearest = nil
for i = 1, #entities do
local e = entities[i]
if e and e.valid and Math.distance(e.position, position) < d then
nearest = e
end
end
return nearest
end
-- function Public.try_spend_pollution(surface, position, amount, flow_statistics_source)
-- local memory = Memory.get_crew_memory()
-- local force_name = memory.force_name
-- flow_statistics_source = flow_statistics_source or 'medium-biter'
-- if not (position and surface and surface.valid) then return end
-- local pollution = surface.get_pollution(position)
-- if pollution > amount then
-- surface.pollute(position, -amount)
-- game.forces[force_name].pollution_statistics.on_flow(flow_statistics_source, -amount)
-- return true
-- end
-- return false
-- end
function Public.get_random_spawner(surface)
local memory = Memory.get_crew_memory()
local spawners = surface.find_entities_filtered({type = 'unit-spawner', force = memory.enemy_force_name})
if (not spawners) or (not spawners[1]) then return end
return spawners[Math.random(#spawners)]
end
function Public.is_biter_inactive(biter)
if (not biter.entity) or (not biter.entity.valid) then
return true
end
if game.tick - biter.created_at > 30*60*60 then
biter.entity.destroy()
return true
end
return false
end
function Public.get_scripted_biter_count()
local memory = Memory.get_crew_memory()
local count = 0
for k, biter in pairs(memory.scripted_biters) do
if biter.entity and biter.entity.valid then
count = count + 1
else
memory.scripted_biters[k] = nil
end
end
return count
end
-----------commands-----------
function Public.stop()
local command = {
type = defines.command.stop,
distraction = defines.distraction.stop
}
return command
end
function Public.move_to(position)
local command = {
type = defines.command.go_to_location,
destination = position,
distraction = defines.distraction.anything
}
return command
end
function Public.attack_target_entity(target)
if not target and target.valid then return end
local command = {
type = defines.command.attack,
target = target,
distraction = defines.distraction.by_anything
}
return command
end
function Public.attack_area(position, radius)
local command = {
type = defines.command.attack_area,
destination = position,
radius = radius or 25,
distraction = defines.distraction.by_anything
}
return command
end
function Public.attack_obstacles(surface, position)
local commands = {}
local obstacles = surface.find_entities_filtered {position = position, radius = 25, type = {'simple-entity', 'tree', 'simple-entity-with-owner'}, limit = 100}
if obstacles then
Math.shuffle(obstacles)
Math.shuffle_distancebiased(obstacles, position)
for i = 1, #obstacles, 1 do
if obstacles[i].valid then
commands[#commands + 1] = {
type = defines.command.attack,
target = obstacles[i],
distraction = defines.distraction.by_anything
}
end
end
end
commands[#commands + 1] = Public.move_to(position)
local command = {
type = defines.command.compound,
structure_type = defines.compound_command.return_last,
commands = commands
}
return command
end
function Public.wander_around(ticks_to_wait) --wander individually inside group radius
local command = {
type = defines.command.wander,
distraction = defines.distraction.anything,
ticks_to_wait = ticks_to_wait,
}
return command
end
function Public.group_set_commands(group, commands)
if #commands > 0 then
local command = {
type = defines.command.compound,
structure_type = defines.compound_command.return_last,
commands = commands
}
group.set_command(command)
end
end
function Public.attack_target(target)
if not target then return end
local commands
if target.name == 'boatarea' then
commands = {
Public.attack_area(target.position, 32),
Public.attack_area(target.position, 32),
}
else
commands = {
Public.attack_area(target.position, 8),
Public.attack_target_entity(target),
}
end
-- if Math.random(20) == 20 then
-- commands = {
-- Public.attack_obstacles(group.surface, {x = (group.position.x * 0.90 + target.position.x * 0.10), y = (group.position.y * 0.90 + target.position.y * 0.10)}),
-- attackcommand,
-- }
-- else
-- commands = {attackcommand}
-- end
return commands
end
--- small group of revenge biters ---
function Public.revenge_group(surface, p, target, type)
type = type or 'biter'
local memory = Memory.get_crew_memory()
local enemy_force_name = memory.enemy_force_name
local name, count
if type == 'biter' then
name = Common.get_random_biter_type(game.forces[memory.enemy_force_name].evolution_factor)
if name == 'small-biter' then
count = 6
elseif name == 'medium-biter' then
count = 3
elseif name == 'big-biter' then
count = 2
elseif name == 'behemoth-biter' then
count = 1
end
elseif type == 'spitter' then
name = Common.get_random_spitter_type(game.forces[memory.enemy_force_name].evolution_factor)
if name == 'small-spitter' then
count = 10
elseif name == 'medium-spitter' then
count = 6
elseif name == 'big-spitter' then
count = 4
elseif name == 'behemoth-spitter' then
count = 2
end
end
if (not (name and count and count>0)) then return end
local units = {}
for i = 1, count do
local p2 = surface.find_non_colliding_position('wooden-chest', p, 5, 0.5)
if p2 then
local biter = surface.create_entity({name = name, force = enemy_force_name, position = p})
-- local biter = surface.create_entity({name = name, force = enemy_force_name, position = p2})
units[#units + 1] = biter
end
end
if #units > 0 then
local unit_group = surface.create_unit_group({position = p, force = enemy_force_name})
for _, unit in pairs(units) do
unit_group.add_member(unit)
end
if target and target.valid then
Public.group_set_commands(unit_group, Public.attack_target(target))
end
unit_group.set_autonomous()
end
end
----------- biter raiding parties -----------
function Public.spawn_boat_biters(boat, max_evo)
-- max_evolution_bonus = max_evolution_bonus or 0.3
local memory = Memory.get_crew_memory()
local surface = game.surfaces[boat.surface_name]
local difficulty = memory.difficulty
local enemy_force_name = boat.force_name
-- local evolution = game.forces[enemy_force_name].evolution_factor
local p = {boat.position.x - 4.5, boat.position.y}
local units = {}
for i = 1, 12 do
local name = Common.get_random_unit_type(max_evo - i * 0.04)
-- local name = Common.get_random_unit_type(evolution + i/15 * max_evolution_bonus)
-- local name = Common.get_random_unit_type(evolution + 3 * i/100)
local p2 = surface.find_non_colliding_position('wooden-chest', p, 5, 0.5)
if p2 then
local biter = surface.create_entity({name = name, force = enemy_force_name, position = p2})
memory.scripted_biters[biter.unit_number] = {entity = biter, created_at = game.tick}
units[#units + 1] = biter
end
end
local target = Public.generate_main_attack_target()
if #units > 0 and target and target.valid then
local unit_group = surface.create_unit_group({position = p, 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'}
end
end
function Public.update_landing_party_unit_groups(boat, step_distance)
local memory = Memory.get_crew_memory()
-- move unit groups:
local group = boat.unit_group
local surface = game.surfaces[boat.surface_name]
if not (group and surface and surface.valid) then return end
local groupref = group.ref
if not (groupref and groupref.valid) then return end
local p2 = groupref.position
if not p2 then return end
local enemy_force_name = memory.enemy_force_name
local m = groupref.members
groupref.destroy()
local new_group = surface.create_unit_group({position = {x = p2.x + step_distance, y = p2.y}, force = enemy_force_name})
boat.unit_group = {ref = new_group, script_type = 'landing-party'}
for i = 1, #m do
local b = m[i]
new_group.add_member(b)
end
if boat.spawner and boat.spawner.valid then
new_group.set_command(Public.move_to(boat.spawner.position))
end
end
-- function Public.destroy_inactive_scripted_biters()
-- local memory = Memory.get_crew_memory()
-- local floating_pollution_accrued = 0
-- for unit_number, biter in pairs(memory.scripted_biters) do
-- if Public.is_biter_inactive(biter) then
-- memory.floating_pollution = memory.floating_pollution + CoreData.biterPollutionValues[biter.entity.name]
-- floating_pollution_accrued = floating_pollution_accrued + CoreData.biterPollutionValues[biter.entity.name]
-- memory.scripted_biters[unit_number] = nil
-- end
-- end
-- if _DEBUG and floating_pollution_accrued > 0 then game.print(game.tick .. string.format(":%f of spare pollution accrued", floating_pollution_accrued)) end
-- end
--=== Data
return Public

481
maps/pirates/balance.lua Normal file
View File

@@ -0,0 +1,481 @@
local Public = {}
local Math = require 'maps.pirates.math'
local Memory = require 'maps.pirates.memory'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
Public.base_extra_character_speed = 0.20
Public.technology_price_multiplier = 1
function Public.starting_boatEEIpower_production_MW()
-- return 3 * Math.sloped(Common.capacity_scale(), 1/2) / 2 --/2 as we have 2
return 3/2
end
function Public.starting_boatEEIelectric_buffer_size_MJ() --maybe needs to be at least the power_production
-- return 3 * Math.sloped(Common.capacity_scale(), 1/2) / 2 --/2 as we have 2
return 3/2
end
Public.EEI_stages = { --multipliers
1,2,5,8,12
}
function Public.scripted_biters_pollution_cost_multiplier()
return 1.33
end
Public.rocket_launch_coin_reward = 5000
function Public.onthefly_scaling_with_players_rule()
return (Common.activecrewcount()/10)^(1/2)
end
function Public.silo_base_est_time()
local T = Public.expected_time_on_island() * Public.onthefly_scaling_with_players_rule()^(1/3) --to undo some of the time scaling
local est_secs
if T > 0 then
est_secs = T/6
else
est_secs = 60 * 6
end
if Common.overworldx() == 0 then est_secs = 60 * 2 end
return est_secs
end
function Public.time_quest_seconds()
return 3 * Public.silo_base_est_time()
end
function Public.silo_energy_needed_MJ()
local est_secs = Public.silo_base_est_time()
local est_base_power = 2*Public.starting_boatEEIpower_production_MW() * (1 + 0.05 * (Common.overworldx()/40)^(7/3))
return est_secs * est_base_power * Math.sloped(Common.difficulty(), 1/3)
end
function Public.silo_total_pollution()
return (
280 * (Common.difficulty()^(1.5)) * Public.onthefly_scaling_with_players_rule()^(4/5) * (1 + 1 * (Common.overworldx()/40)^(1.75))
)
end
function Public.max_time_on_island_formula()
return 60 * (
(31 + 2 * (Common.overworldx()/40)^(1/3))
) / Public.onthefly_scaling_with_players_rule()^(1/2) / Math.sloped(Common.difficulty(), 1/4)
end
function Public.max_time_on_island()
if Common.overworldx() == 0 or ((Common.overworldx()/40) > 20 and (Common.overworldx()/40) < 25) then
return -1
else
return Math.ceil(Public.max_time_on_island_formula())
end
end
function Public.expected_time_on_island()
return 3/5 * Public.max_time_on_island_formula()
end
function Public.boat_passive_pollution_per_minute(time)
local boost = 1
local T = Public.max_time_on_island_formula()
if time and time >= 19/20 * T then
boost = 15
elseif time and time >= 9/10 * T then
boost = 8
elseif time and time >= 8/10 * T then
boost = 5
elseif time and time >= 6/10 * T then
boost = 3
elseif time and time >= 4/10 * T then
boost = 2
end
return boost * (
6 * Common.difficulty() * (Common.overworldx()/40)^(16/10) * (Public.onthefly_scaling_with_players_rule())^(1/2)
)
end
function Public.base_evolution()
local evo = (0.03 + 0.02 * (Common.overworldx()/40)) * Math.sloped(Common.difficulty(), 1/5)
if Common.overworldx()/40 == 0 then evo = 0 end
return evo
end
function Public.expected_time_evo()
return 0.14
end
function Public.evolution_per_second()
local destination = Common.current_destination()
local T = Public.expected_time_on_island() --always greater than 0
local rate = Public.expected_time_evo() / T
if Common.overworldx() == 0 then rate = 0 end
-- scale by biter nests remaining:
if destination and destination.dynamic_data then
local initial_spawner_count = destination.dynamic_data.initial_spawner_count
if initial_spawner_count and initial_spawner_count > 0 then
local surface = game.surfaces[destination.surface_name]
if surface and surface.valid then
rate = rate * Common.spawner_count(surface) / destination.dynamic_data.initial_spawner_count
end
end
end
return rate
end
function Public.evolution_per_biter_base_kill()
local destination = Common.current_destination()
if Common.overworldx() == 0 then return 0 end
if destination and destination.dynamic_data and destination.dynamic_data.timer and destination.dynamic_data.timer > 0 and destination.dynamic_data.initial_spawner_count and destination.dynamic_data.initial_spawner_count > 0 then
local initial_spawner_count = destination.dynamic_data.initial_spawner_count
local time = destination.dynamic_data.timer
local expected_time = Public.expected_time_on_island()
if time > expected_time then return 0
else
-- evo it 'would have' contributed:
return 1/initial_spawner_count * Public.expected_time_evo() * (expected_time - time)/expected_time
end
else
return 0
end
-- return 0.003 * Common.difficulty()
end
function Public.evolution_per_full_silo_charge()
return 0.09
end
function Public.bonus_enemy_unit_damage_to_humans()
local ret = 0.5
local diff = Common.difficulty()
if diff <= 0.5 then ret = 0.25 end
if diff > 1.5 then ret = 0.75 end
return ret
end
function Public.periodic_free_resources_per_x(x)
-- return {
-- {name = 'iron-plate', count = Math.ceil(6 * (Common.overworldx()/40)^(2/3) * Math.sloped(Common.capacity_scale(), 1/2))},
-- {name = 'copper-plate', count = Math.ceil(1 * (Common.overworldx()/40)^(2/3) * Math.sloped(Common.capacity_scale(), 1/2))},
-- }
return {}
end
function Public.periodic_free_resources_per_destination_5_seconds(x)
return {
{name = 'iron-ore', count = Math.ceil(5 * (Common.overworldx()/40)^(2/3))},
{name = 'copper-ore', count = Math.ceil(2 * (Common.overworldx()/40)^(2/3))},
}
end
function Public.class_resource_scale()
return 1 / Public.onthefly_scaling_with_players_rule()
end
function Public.biter_base_density_scale()
local p = Common.activecrewcount()
if p >= 10 then
return (Common.activecrewcount()/10)^(1/2)
else
return Math.max((Common.activecrewcount()/6)^(1/2), 0.6)
end
end
function Public.launch_gold_reward()
return Math.ceil(1000 * (1 + 0.5 * Common.overworldx()/400) / Math.sloped(Common.difficulty(), 1/4))
end
function Public.quest_reward_multiplier()
return 0.3 + 0.7 * Common.overworldx()/400
end
function Public.island_richness_avg_multiplier()
return (1.0 + 0.08 * Common.overworldx()/40)
end
function Public.resource_quest_multiplier()
return (1.0 + 0.1 * (Common.overworldx()/40)^(4/3)) * Math.sloped(Common.difficulty(), 1/2) * (Public.onthefly_scaling_with_players_rule())^(1/3)
end
function Public.apply_crew_buffs_per_x(force)
force.laboratory_productivity_bonus = force.laboratory_productivity_bonus + 10/100 * 1/40
end
function Public.class_cost()
return 10000
-- return Math.ceil(10000 / (Common.activecrewcount()/4)^(1/6))
end
Public.covered_first_appears_at = 40
Public.silo_max_hp = 10000
function Public.pistol_damage_multiplier() return 1.7 end
Public.kraken_spawns_base_extra_evo = 0.2
function Public.kraken_evo_increase_per_shot()
return 0
-- return 1/100 * 0.2
end
function Public.kraken_kill_reward()
return {{name = 'sulfuric-acid-barrel', count = 5}}
end
function Public.kraken_health()
return Math.ceil(2500 * Math.max(1, 1 + 0.1 * ((Common.overworldx()/40)^(13/10)-6)) * (Public.onthefly_scaling_with_players_rule()^(3/4)) * Math.sloped(Common.difficulty(), 1/2))
end
function Public.krakens_per_slot(overworldx)
local rng = Math.random()
if rng < 0.03 then
return 2
elseif rng < 0.25 then
return 1
else
return 0
end
end
function Public.krakens_per_free_slot(overworldx)
local rng = Math.random()
if rng < 0.075 then
return 2
elseif rng < 0.5 then
return 1
else
return 0
end
end
function Public.main_shop_cost_multiplier()
return 1
end
function Public.covered_entry_price_scale()
return (1 + 0.025 * (Common.overworldx()/40 - 1))
end
function Public.barter_decay_parameter()
return 0.95
end
-- function Public.island_otherresources_prospect_decay_parameter()
-- return 0.95
-- end
Public.research_buffs = {
-- these already give .1 productivity so we're adding .1 to get to 20%
-- ['mining-productivity-1'] = {['mining-drill-productivity-bonus'] = .1, ['character-mining-speed'] = .2, ['character-inventory-slots-bonus'] = 10},
-- ['mining-productivity-2'] = {['mining-drill-productivity-bonus'] = .1, ['character-mining-speed'] = .2, ['character-inventory-slots-bonus'] = 10},
-- ['mining-productivity-3'] = {['mining-drill-productivity-bonus'] = .1, ['character-mining-speed'] = .2, ['character-inventory-slots-bonus'] = 10},
-- ['mining-productivity-4'] = {['mining-drill-productivity-bonus'] = .1, ['character-mining-speed'] = .2, ['character-inventory-slots-bonus'] = 10},
}
-- function Public.flamers_nerfs_size(jumps) return 0.02 * jumps * difficulty_sloped(1/2) end
function Public.player_ammo_damage_modifiers() -- modifiers are fractional. bullet affects gun turrets, but flamethrower does not affect flamer turrets
local data = {
['artillery-shell'] = 0,
['biological'] = 0,
['bullet'] = 0.1,
['cannon-shell'] = 0,
['capsule'] = 0,
['electric'] = 0,
['flamethrower'] = 0, --these nerfs are elsewhere for finer control
['grenade'] = 0,
['landmine'] = 0,
['melee'] = 0, -- doesn't do anything apparently
['rocket'] = 0,
['shotgun-shell'] = 0
}
return data
end
function Public.player_turret_attack_modifiers()
local data = {
['gun-turret'] = 0,
['artillery-turret'] = 0,
['laser-turret'] = 0,
}
return data
end
function Public.player_gun_speed_modifiers()
local data = {
['artillery-shell'] = 0,
['biological'] = 0,
['bullet'] = 0,
['cannon-shell'] = 0,
['capsule'] = 0,
['electric'] = 0,
['flamethrower'] = 0, --these nerfs are elsewhere for finer control
['grenade'] = -0.25,
['landmine'] = 0,
['melee'] = 0, -- doesn't do anything
['rocket'] = 0,
['shotgun-shell'] = 0.1
}
return data
end
Public.starting_items_player = {['pistol'] = 1, ['firearm-magazine'] = 12, ['raw-fish'] = 1, ['iron-plate'] = 12, ['medium-electric-pole'] = 4}
Public.starting_items_player_late = {['pistol'] = 1, ['firearm-magazine'] = 5}
function Public.starting_items_crew_upstairs()
return {
{['steel-plate'] = 38},
{['stone-brick'] = 60},
{['grenade'] = 3},
{['solar-panel'] = 4},
{['shotgun'] = 2, ['shotgun-shell'] = 36},
{['raw-fish'] = 5},
}
end
function Public.starting_items_crew_downstairs()
return {
{['transport-belt'] = Math.random(500,600)},
{['inserter'] = Math.random(100,120)},
{['splitter'] = Math.random(40,48)},
{['storage-tank'] = 4},
{['medium-electric-pole'] = Math.random(15,21)},
{['loader'] = 5},
{['coin'] = 3000},
}
end
Public.covered1_entry_price_data_raw = { --watch out that the raw_materials chest can only hold e.g. 4.8 iron-plates
-- choose things that are easy to make at outposts
{1, 0, 1, false, {
price = {name = 'iron-stick', count = 1500},
raw_materials = {{name = 'iron-plate', count = 750}}}, {}},
{0.8, 0, 1, false, {
price = {name = 'copper-cable', count = 1500},
raw_materials = {{name = 'copper-plate', count = 750}}}, {}},
{1, 0, 0.3, true, {
price = {name = 'small-electric-pole', count = 800},
raw_materials = {{name = 'copper-plate', count = 400}}}, {}},
{1, 0.1, 1, false, {
price = {name = 'assembling-machine-1', count = 80},
raw_materials = {{name = 'iron-plate', count = 1760}, {name = 'copper-plate', count = 360}}}, {}},
{1, 0, 0.2, false, {
price = {name = 'burner-mining-drill', count = 200},
raw_materials = {{name = 'iron-plate', count = 1800}}}, {}},
{0.5, 0, 0.6, false, {
price = {name = 'burner-inserter', count = 300},
raw_materials = {{name = 'iron-plate', count = 900}}}, {}},
-- {1, 0, 1, false, {
-- price = {name = 'electronic-circuit', count = 800},
-- raw_materials = {{name = 'iron-plate', count = 800}, {name = 'copper-plate', count = 1200}}}, {}},
-- {1, 0, 1, false, {
-- price = {name = 'piercing-rounds-magazine', count = 100},
-- raw_materials = {{name = 'iron-plate', count = 400}, {name = 'copper-plate', count = 500}, {name = 'steel-plate', count = 100}}}, {}},
{1, 0.1, 1, false, {
price = {name = 'stone-furnace', count = 400},
raw_materials = {}}, {}},
{1, 0.5, 1, false, {
price = {name = 'advanced-circuit', count = 100},
raw_materials = {{name = 'iron-plate', count = 200}, {name = 'copper-plate', count = 500}, {name = 'plastic-bar', count = 200}}}, {}},
{1, -1, 1, true, {
price = {name = 'wooden-chest', count = 400},
raw_materials = {}}, {}},
{1, 0, 1, true, {
price = {name = 'iron-chest', count = 300},
raw_materials = {{name = 'iron-plate', count = 2400}}}, {}},
{1, 0, 2, true, {
price = {name = 'steel-chest', count = 200},
raw_materials = {{name = 'steel-plate', count = 1600}}}, {}},
}
function Public.covered1_entry_price_data()
local ret = {}
local data = Public.covered1_entry_price_data_raw
for i = 1, #data do
local data_item = data[i]
ret[#ret + 1] = {
weight = data_item[1],
game_completion_progress_min = data_item[2],
game_completion_progress_max = data_item[3],
scaling = data_item[4],
item = data_item[5],
map_subtypes = data_item[6],
}
end
return ret
end
function Public.covered1_entry_price()
local rng = Math.random()
local memory = Memory.get_crew_memory()
local overworldx = memory.overworldx or 0
local game_completion_progress = Math.sloped(Common.difficulty(),1/2) * Common.game_completion_progress()
local data = Public.covered1_entry_price_data()
local types, weights = {}, {}
for i = 1, #data, 1 do
table.insert(types, data[i].item)
local destination = Common.current_destination()
if not (data[i].map_subtypes and #data[i].map_subtypes > 0 and destination and destination.subtype and data[i].map_subtypes and (not Utils.contains(data[i].map_subtypes, destination.subtype))) then
if data[i].scaling then -- scale down weights away from the midpoint 'peak' (without changing the mean)
local midpoint = (data[i].game_completion_progress_max + data[i].game_completion_progress_min) / 2
local difference = (data[i].game_completion_progress_max - data[i].game_completion_progress_min)
table.insert(weights, data[i].weight * Math.max(0, 1 - (Math.abs(game_completion_progress - midpoint) / (difference / 2))))
else -- no scaling
if data[i].game_completion_progress_min <= game_completion_progress and data[i].game_completion_progress_max >= game_completion_progress then
table.insert(weights, data[i].weight)
else
table.insert(weights, 0)
end
end
end
end
local res = Utils.deepcopy(Math.raffle(types, weights))
res.price.count = Math.ceil(res.price.count * Public.covered_entry_price_scale())
for i, _ in pairs(res.raw_materials) do
res.raw_materials[i].count = Math.ceil(res.raw_materials[i].count * Public.covered_entry_price_scale())
end
return res
end
return Public

View File

@@ -0,0 +1,66 @@
local Memory = require 'maps.pirates.memory'
local Roles = require 'maps.pirates.roles.roles'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Loot = require 'maps.pirates.loot'
local inspect = require 'utils.inspect'.inspect
local Structures = require 'maps.pirates.structures.structures'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Boats = require 'maps.pirates.structures.boats.boats'
local Hold = require 'maps.pirates.surfaces.hold'
local Public = {}
-- September 2021: Reworking the game so that you start on a 'sloop with hold', but can customize the ship with upgrades.
-- I'm thinking these can start by simply being shop icons.
-- In the hold, we can extend the hold size by placing tiles. Perhaps the space that is extended could be random, as usual to dissuade repetitive builds.
-- For the deck, we don't really want to do that. It's probably safest to stick to things like upgrading the accumulator.
local enum = {
EXTRA_HOLD = 'extra_hold',
MORE_POWER = 'upgrade_power',
UNLOCK_MERCHANTS = 'unlock_merchants',
ROCKETS_FOR_SALE = 'rockets_for_sale',
}
Public.enum = enum
Public.List = {
enum.EXTRA_HOLD,
enum.MORE_POWER,
enum.UNLOCK_MERCHANTS,
enum.ROCKETS_FOR_SALE,
}
Public.crowsnest_display_form = {
[enum.EXTRA_HOLD] = 'Extra Hold',
[enum.MORE_POWER] = 'Power',
[enum.UNLOCK_MERCHANTS] = 'Merchants',
[enum.ROCKETS_FOR_SALE] = 'Rockets for Sale',
}
function Public.execute_upgade(upgrade_type)
local memory = Memory.get_crew_memory()
local boat = memory.boat
if upgrade_type == enum.EXTRA_HOLD then
Hold.add_another_hold_surface()
elseif upgrade_type == enum.MORE_POWER then
boat.EEI_stage = boat.EEI_stage + 1
Boats.update_EEIs(boat)
elseif upgrade_type == enum.UNLOCK_MERCHANTS then
memory.merchant_ships_unlocked = true
elseif upgrade_type == enum.ROCKETS_FOR_SALE then
memory.rockets_for_sale = true
end
end
return Public

703
maps/pirates/commands.lua Normal file
View File

@@ -0,0 +1,703 @@
local Color = require 'utils.color_presets'
local Server = require 'utils.server'
local Math = require 'maps.pirates.math'
local Ai = require 'maps.pirates.ai'
local Memory = require 'maps.pirates.memory'
local Gui = require 'maps.pirates.gui.gui'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local PlayerColors = require 'maps.pirates.player_colors'
local Utils = require 'maps.pirates.utils_local'
local Balance = require 'maps.pirates.balance'
local Crew = require 'maps.pirates.crew'
local Roles = require 'maps.pirates.roles.roles'
local Structures = require 'maps.pirates.structures.structures'
local Boats = require 'maps.pirates.structures.boats.boats'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Overworld = require 'maps.pirates.overworld'
local Islands = require 'maps.pirates.surfaces.islands.islands'
local Progression = require 'maps.pirates.progression'
local Crowsnest = require 'maps.pirates.surfaces.crowsnest'
local Hold = require 'maps.pirates.surfaces.hold'
local Interface = require 'maps.pirates.interface'
local Upgrades = require 'maps.pirates.boat_upgrades'
local Effects = require 'maps.pirates.effects'
local Kraken = require 'maps.pirates.surfaces.sea.kraken'
local inspect = require 'utils.inspect'.inspect
local simplex_noise = require 'utils.simplex_noise'.d2
local Token = require 'utils.token'
local Task = require 'utils.task'
local Highscore = require 'maps.pirates.highscore'
commands.add_command(
'ok',
'ok',
function(cmd)
local player = game.players[cmd.player_index]
if not Common.validate_player(player) then return end
local crew_id = tonumber(string.sub(game.players[cmd.player_index].force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
Roles.try_accept_captainhood(player)
end)
commands.add_command(
'ccolor',
'ccolor is an extension to the built-in /color command, with more colors.',
function(cmd)
local param = tostring(cmd.parameter)
local player_index = cmd.player_index
if player_index then
local player = game.players[player_index]
if player and player.valid then
if PlayerColors[param] then
player.color = PlayerColors[param]
game.print(player.name .. '\'s color is now ' .. param .. ' (via /ccolor).', PlayerColors[param])
else
player.print('Color not found.')
end
end
end
end)
local function allowed(param)
local Session = require 'utils.datastore.session_data'
local Color = require 'utils.color_presets'
local player = game.player
local trusted = Session.get_trusted_table()
local p
if player then
if player ~= nil then
p = player.print
if not trusted[player.name] then
if not player.admin then
p('[ERROR] Only admins and trusted weebs are allowed to run this command!', Color.fail)
return false
end
end
else
p = log
end
end
return true
end
local go_2 = Token.register(
function(data)
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
memory.mapbeingloadeddestination_index = 1
memory.loadingticks = 0
Progression.go_from_starting_dock_to_first_destination()
end
)
local go_1 = Token.register(
function(data)
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
Overworld.ensure_lane_generated_up_to(0, Crowsnest.Data.visibilitywidth/2)
Overworld.ensure_lane_generated_up_to(24, Crowsnest.Data.visibilitywidth/2)
Overworld.ensure_lane_generated_up_to(-24, Crowsnest.Data.visibilitywidth/2)
memory.currentdestination_index = 1
Surfaces.create_surface(Common.current_destination())
Task.set_timeout_in_ticks(60, go_2, {})
end
)
if _DEBUG then
commands.add_command(
'chnk',
'genchunk',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
for i = 0, 13 do
for j = 0, 13 do
Interface.event_on_chunk_generated({surface = game.player.surface, area = {left_top = {x = -7 * 32 + i * 32, y = -7 * 32 + j * 32}}})
end
end
game.print('chunks generated')
end
end)
commands.add_command(
'modi',
'setmodifiable',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Common.current_destination().surface_name]
local entities = surface.find_entities_filtered{position = game.player.position, radius = 500}
for _, e in pairs(entities) do
if e and e.valid then
-- e.force = game.forces[memory.force_name]
e.minable = true
e.destructible = true
e.rotatable = true
end
end
game.print('nearby entities made modifiable')
end
end)
commands.add_command(
'spd',
'speed',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
memory.boat.speed = 60
end
end)
commands.add_command(
'stp',
'stop',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
memory.boat.speed = 0
end
end)
commands.add_command(
'ret',
'retreat',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
Progression.retreat_from_island()
end
end)
commands.add_command(
'jump',
'jump',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
Overworld.try_overworld_move_v2({x = 40*10, y = 0})
end
end)
commands.add_command(
'advu',
'advanceup',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
Overworld.try_overworld_move_v2{x = 0, y = -24}
end
end)
commands.add_command(
'advd',
'advancedown',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
Overworld.try_overworld_move_v2{x = 0, y = 24}
end
end)
commands.add_command(
'rms',
'rms',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local rms = 0
local n = 100000
local seed = Math.random(n^2)
for i = 1,n do
local noise = simplex_noise(i, 7.11, seed)
rms = rms + noise^2
end
rms = rms/n
game.print(rms)
end
end)
commands.add_command(
'pro',
'pro',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local global_memory = Memory.get_global_memory()
local proposal = {
capacity_option = 3,
difficulty_option = 2,
-- mode_option = 'left',
endorserindices = { 2 },
name = "TestRun"
}
global_memory.crewproposals[#global_memory.crewproposals + 1] = proposal
end
end)
commands.add_command(
'go',
'go',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local proposal = {
capacity_option = 3,
difficulty_option = 2,
-- mode_option = 'left',
endorserindices = { 1 },
name = "AdminRun"
}
Memory.set_working_id(1)
Crew.initialise_crew(proposal)
Crew.initialise_crowsnest() --contains a Task
local memory = Memory.get_crew_memory()
local boat = Utils.deepcopy(Surfaces.Lobby.StartingBoats[memory.id])
for _, player in pairs(game.connected_players) do
player.teleport({x = -30, y = boat.position.y}, game.surfaces[boat.surface_name])
end
Progression.set_off_from_starting_dock()
-- local memory = Memory.get_crew_memory()
-- local boat = Utils.deepcopy(Surfaces.Lobby.StartingBoats[memory.id])
-- memory.boat = boat
-- boat.dockedposition = boat.position
-- boat.decksteeringchests = {}
-- boat.crowsneststeeringchests = {}
Task.set_timeout_in_ticks(120, go_1, {})
end
end)
commands.add_command(
'tim',
'tim',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
Common.current_destination().dynamic_data.timer = 88
game.print('time set to 88 seconds')
end
end)
commands.add_command(
'lev',
'lev',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
Progression.go_from_currentdestination_to_sea()
end
end)
commands.add_command(
'gld',
'gld',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
memory.gold = memory.gold + 20000
end
end)
commands.add_command(
'bld',
'bld',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
memory.classes_table = {[1] = 1}
end
end)
commands.add_command(
'fsh',
'fsh',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
memory.classes_table = {[1] = 2}
end
end)
commands.add_command(
'sct',
'sct',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
memory.classes_table = {[1] = 3}
end
end)
commands.add_command(
'sam',
'sam',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
memory.classes_table = {[1] = 4}
end
end)
commands.add_command(
'mrc',
'mrc',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
memory.classes_table = {[1] = 5}
end
end)
commands.add_command(
'rad',
'rad',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
Islands.spawn_enemy_boat(Boats.enum.RAFT)
local boat = memory.enemyboats[1]
Ai.spawn_boat_biters(boat, 0.89)
game.print('enemy boat spawned')
end
end)
commands.add_command(
'hld',
'hld',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
Upgrades.execute_upgade(Upgrades.enum.EXTRA_HOLD)
end
end)
commands.add_command(
'pwr',
'pwr',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
Upgrades.execute_upgade(Upgrades.enum.MORE_POWER)
end
end)
commands.add_command(
'krk',
'krk',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Memory.set_working_id(1)
local memory = Memory.get_crew_memory()
Kraken.try_spawn_kraken()
end
end)
commands.add_command(
'1',
'1',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
game.speed = 1
end
end)
commands.add_command(
'4',
'4',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
game.speed = 4
end
end)
commands.add_command(
'8',
'8',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
game.speed = 8
end
end)
commands.add_command(
'16',
'16',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
game.speed = 16
end
end)
commands.add_command(
'32',
'32',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
game.speed = 32
end
end)
commands.add_command(
'64',
'64',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
game.speed = 64
end
end)
commands.add_command(
'ef1',
'ef1',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Common.current_destination().surface_name]
Effects.worm_movement_effect(surface, {x = -45, y = 0}, false, true)
end
end)
commands.add_command(
'ef2',
'ef2',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Common.current_destination().surface_name]
Effects.worm_movement_effect(surface, {x = -45, y = 0}, false, false)
end
end)
commands.add_command(
'ef3',
'ef3',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Common.current_destination().surface_name]
Effects.worm_movement_effect(surface, {x = -45, y = 0}, true, false)
end
end)
commands.add_command(
'ef4',
'ef4',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Common.current_destination().surface_name]
Effects.worm_emerge_effect(surface, {x = -45, y = 0})
end
end)
commands.add_command(
'ef5',
'ef5',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Common.current_destination().surface_name]
Effects.biters_emerge(surface, {x = -30, y = 0})
end
end)
commands.add_command(
'emoji',
'emoji',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
Server.to_discord_embed_raw(CoreData.comfy_emojis.monkas)
end
end)
commands.add_command(
'maxcrews3',
'maxcrews3',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local global_memory = Memory.get_global_memory()
global_memory.active_crews_cap = 3
end
end)
commands.add_command(
'maxcrews2',
'maxcrews2',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local global_memory = Memory.get_global_memory()
global_memory.active_crews_cap = 2
end
end)
commands.add_command(
'maxcrews1',
'maxcrews1',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local global_memory = Memory.get_global_memory()
global_memory.active_crews_cap = 1
end
end)
commands.add_command(
'mincapacitysetting3',
'mincapacitysetting3',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local global_memory = Memory.get_global_memory()
global_memory.minimum_capacity_slider_value = 3
end
end)
commands.add_command(
'mincapacitysetting2',
'mincapacitysetting2',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local global_memory = Memory.get_global_memory()
global_memory.minimum_capacity_slider_value = 2
end
end)
commands.add_command(
'mincapacitysetting1',
'mincapacitysetting1',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local global_memory = Memory.get_global_memory()
global_memory.minimum_capacity_slider_value = 1
end
end)
commands.add_command(
'score',
'score',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
local crew_id = tonumber(string.sub(game.player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
game.print('faking a highscore...')
Highscore.write_score(memory.secs_id, 'fakers', 0, 40, CoreData.version_float, 1, 8)
end
end)
commands.add_command(
'scrget',
'scrget',
function(cmd)
local param = tostring(cmd.parameter)
if allowed(param) then
game.print('running Highscore.load_in_scores()')
Highscore.load_in_scores()
end
end)
end

899
maps/pirates/common.lua Normal file
View File

@@ -0,0 +1,899 @@
local Math = require 'maps.pirates.math'
local Utils = require 'maps.pirates.utils_local'
local CoreData = require 'maps.pirates.coredata'
local Memory = require 'maps.pirates.memory'
local inspect = require 'utils.inspect'.inspect
local simplex_noise = require 'utils.simplex_noise'.d2
local perlin_noise = require 'utils.perlin_noise'
local Public = {}
Public.active_crews_cap = 2
Public.minimum_capacity_slider_value = 1
Public.boat_steps_at_a_time = 1
Public.seconds_after_landing_to_enable_AI = 45
Public.boat_default_starting_distance_from_shore = 22
-- Public.mapedge_distance_from_boat_starting_position = 136
Public.mapedge_distance_from_boat_starting_position = 272 -- to accommodate horseshoe
Public.deepwater_distance_from_leftmost_shore = 32
Public.lobby_spawnpoint = {x = -72, y = -8}
Public.fraction_of_map_loaded_atsea = 1
Public.map_loading_ticks_atsea = 90 * 60
Public.map_loading_ticks_onisland = 2 * 60 * 60
Public.loading_interval = 5
Public.minimum_ore_placed_per_tile = 10
Public.total_max_biters = 2048
Public.ban_from_rejoining_crew_ticks = 45 * 60 --to prevent observing map and rejoining
Public.afk_time = 60 * 60 * 4.5
Public.afk_warning_time = 60 * 60 * 4
-- Public.mainshop_rate_limit_ticks = 11
function Public.ore_real_to_abstract(amount)
return amount/1500
end
function Public.ore_abstract_to_real(amount)
return Math.ceil(amount*1500)
end
function Public.oil_real_to_abstract(amount)
return amount/(8000)
end
function Public.oil_abstract_to_real(amount)
return Math.ceil(amount*8000)
end
function Public.difficulty() return Memory.get_crew_memory().difficulty end
function Public.capacity() return Memory.get_crew_memory().capacity end
-- function Public.mode() return Memory.get_crew_memory().mode end
function Public.overworldx() return Memory.get_crew_memory().overworldx end
function Public.game_completion_progress() return Public.overworldx()/CoreData.victory_x end
function Public.capacity_scale()
local capacity = Public.capacity()
if not capacity then --e.g. for EE wattage on boats not owned by a crew
return 1
elseif capacity <= 1 then
return 0.5
elseif capacity <= 4 then
return 0.75
elseif capacity <= 8 then
return 1
elseif capacity <= 16 then
return 1.3
else
return 1.5
end
end
function Public.activecrewcount()
local global_memory = Memory.get_global_memory()
local memory = Memory.get_crew_memory()
if memory.id == 0 then return 0 end
local count = 0
for _, id in pairs(memory.crewplayerindices) do
local player = game.players[id]
if player and player.valid and not Utils.contains(global_memory.afk_player_indices, player.index) then
count = count + 1
end
end
return count
end
function Public.notify_game(message, color_override)
color_override = color_override or CoreData.colors.notify_game
game.print('>> ' .. message, color_override)
end
function Public.notify_force(force, message, color_override)
color_override = color_override or CoreData.colors.notify_force
force.print('>> ' .. message, color_override)
end
function Public.notify_force_light(force, message, color_override)
color_override = color_override or CoreData.colors.notify_force_light
force.print('>> ' .. message, color_override)
end
function Public.notify_lobby(message, color_override)
color_override = color_override or CoreData.colors.notify_lobby
game.forces['player'].print('>> ' .. message, color_override)
end
function Public.notify_player(player, message, color_override)
color_override = color_override or CoreData.colors.notify_player
player.print('>> ' .. message, color_override)
end
function Public.parrot_speak(force, message)
force.print('Parrot: ' .. message, CoreData.colors.parrot)
end
function Public.parrot_whisper(player, message)
player.print('Parrot (whisper): ' .. message, CoreData.colors.parrot)
end
function Public.flying_text(surface, position, text)
surface.create_entity(
{
name = 'flying-text',
position = {position.x - 0.7, position.y - 3.05},
text = text,
}
)
end
function Public.flying_text_small(surface, position, text)
surface.create_entity(
{
name = 'flying-text',
position = {position.x - 0.06, position.y - 1.5},
text = text,
}
)
end
function Public.give(player, stacks, spill_position, spill_surface)
-- stack elements of form {name = '', count = '', color = {r = , g = , b = }}
-- to just spill on the ground, pass player and nill and give a position and surface directly
spill_position = spill_position or player.position
spill_surface = spill_surface or player.surface
local text1 = ''
local text2 = ''
local stacks2 = stacks
table.sort(stacks2, function(a,b) return a.name < b.name end)
if not (spill_surface and spill_surface.valid) then return end
local inv
if player then
inv = player.get_inventory(defines.inventory.character_main)
if not inv then return end
end
for j = 1, #stacks2 do
local stack = stacks2[j]
local itemname, itemcount, flying_text_color = stack.name, stack.count or 1, stack.color or (CoreData.colors[stack.name] or {r = 1, g = 1, b = 1})
local itemcount_remember = itemcount
if not itemname then return end
if itemcount > 0 then
if player then
local a = inv.insert{name = itemname, count = itemcount}
itemcount = itemcount - a
if itemcount >= 50 then
for i = 1, Math.floor(itemcount / 50), 1 do
local e = spill_surface.create_entity{name = 'item-on-ground', position = spill_position, stack = {name = itemname, count = 50}}
if e and e.valid then
e.to_be_looted = true
end
itemcount = itemcount - 50
end
end
if itemcount > 0 then
if itemcount < 5 then
spill_surface.spill_item_stack(spill_position, {name = itemname, count = itemcount}, true)
else
local e = spill_surface.create_entity{name = 'item-on-ground', position = spill_position, stack = {name = itemname, count = itemcount}}
if e and e.valid then
e.to_be_looted = true
end
end
end
else
local e = spill_surface.create_entity{name = 'item-on-ground', position = spill_position, stack = {name = itemname, count = itemcount}}
if e and e.valid then
e.to_be_looted = true
end
end
end
text1 = text1 .. '[color=1,1,1]'
if itemcount_remember > 0 then
text1 = text1 .. '+'
text1 = text1 .. itemcount_remember .. '[/color] [item=' .. itemname .. ']'
else
text1 = text1 .. '-'
text1 = text1 .. -itemcount_remember .. '[/color] [item=' .. itemname .. ']'
end
if inv then
if #stacks2 > 1 then
text2 = text2 .. '[color=' .. flying_text_color.r .. ',' .. flying_text_color.g .. ',' .. flying_text_color.b .. ']' .. inv.get_item_count(itemname) .. '[/color]'
else
text2 = '[color=' .. flying_text_color.r .. ',' .. flying_text_color.g .. ',' .. flying_text_color.b .. '](' .. inv.get_item_count(itemname) .. ')[/color]'
end
if j < #stacks2 then
text2 = text2 .. ', '
end
end
if j < #stacks2 then
text1 = text1 .. ', '
end
end
if text2 ~= '' then
if #stacks2 > 1 then
text2 = '(' .. text2 .. ')'
end
Public.flying_text(spill_surface, spill_position, text1 .. ' [font=count-font]' .. text2 .. '[/font]')
else
Public.flying_text(spill_surface, spill_position, text1)
end
end
function Public.current_destination()
local memory = Memory.get_crew_memory()
if memory.currentdestination_index then
return memory.destinations[memory.currentdestination_index]
else
return CoreData.fallthrough_destination
end
end
function Public.query_sufficient_resources_to_leave()
local memory = Memory.get_crew_memory()
local boat = memory.boat
local destination = Public.current_destination()
if not (boat and destination) then return end
local cost = destination.static_params.cost_to_leave
if not cost then return true end
local sufficient = true
for name, count in pairs(cost) do
local stored = (memory.boat.stored_resources and memory.boat.stored_resources[name]) or 0
if stored < count then
sufficient = false
end
end
return sufficient
end
function Public.update_boat_stored_resources()
local memory = Memory.get_crew_memory()
local boat = memory.boat
if not memory.boat.stored_resources then return end
local input_chests = boat.input_chests
if not input_chests then return end
for i, chest in ipairs(input_chests) do
local inv = chest.get_inventory(defines.inventory.chest)
local contents = inv.get_contents()
local item_type = CoreData.cost_items[i].name
local count = contents[item_type] or 0
memory.boat.stored_resources[item_type] = count
end
end
function Public.spend_stored_resources(to_spend)
to_spend = to_spend or {}
local memory = Memory.get_crew_memory()
local boat = memory.boat
if not memory.boat.stored_resources then return end
local input_chests = boat.input_chests
if not input_chests then return end
for i, chest in ipairs(input_chests) do
local inv = chest.get_inventory(defines.inventory.chest)
local item_type = CoreData.cost_items[i].name
local to_spend_i = to_spend[item_type] or 0
if to_spend_i > 0 then
inv.remove{name = item_type, count = to_spend_i}
end
end
Public.update_boat_stored_resources()
end
function Public.new_healthbar(id, text, target_entity, max_health, health, size)
health = health or max_health
size = size or 0.5
text = text or false
local memory = Memory.get_crew_memory()
local render1 = rendering.draw_sprite(
{
sprite = 'virtual-signal/signal-white',
tint = {0, 200, 0},
x_scale = size * 15,
y_scale = size,
render_layer = 'light-effect',
target = target_entity,
target_offset = {0, -2.5},
surface = target_entity.surface,
}
)
local render2
if text then
render2 = rendering.draw_text(
{
color = {255, 255, 255},
scale = 2,
render_layer = 'light-effect',
target = target_entity,
target_offset = {0, -4},
surface = target_entity.surface,
alignment = 'center'
}
)
end
local new_healthbar = {
health = max_health,
max_health = max_health,
render1 = render1,
render2 = render2,
id = id,
}
memory.healthbars[target_entity.unit_number] = new_healthbar
Public.update_healthbar_rendering(new_healthbar, health)
return new_healthbar
end
function Public.update_healthbar_rendering(new_healthbar, health)
local max_health = new_healthbar.max_health
local render1 = new_healthbar.render1
local render2 = new_healthbar.render2
if health > 0 then
local m = health / max_health
local x_scale = rendering.get_y_scale(render1) * 15
rendering.set_x_scale(render1, x_scale * m)
rendering.set_color(render1, {Math.floor(255 - 255 * m), Math.floor(200 * m), 0})
if render2 then
rendering.set_text(render2, string.format('HP: %d/%d',Math.ceil(health),Math.ceil(max_health)))
end
else
rendering.destroy(render1)
if render2 then
rendering.destroy(render2)
end
end
end
function Public.spawner_count(surface)
local memory = Memory.get_crew_memory()
local spawners = surface.find_entities_filtered({type = 'unit-spawner', force = memory.enemy_force_name})
local spawnerscount = #spawners or 0
return spawnerscount
end
function Public.create_poison_clouds(surface, position)
local random_angles = {Math.rad(Math.random(359)), Math.rad(Math.random(359))}
surface.create_entity({name = 'poison-cloud', position = {x = position.x, y = position.y}})
surface.create_entity({name = 'poison-cloud', position = {x = position.x + 12 * Math.cos(random_angles[1]), y = position.y + 12 * Math.sin(random_angles[1])}})
surface.create_entity({name = 'poison-cloud', position = {x = position.x + 12 * Math.cos(random_angles[2]), y = position.y + 12 * Math.sin(random_angles[2])}})
end
function Public.crew_get_crew_members()
local memory = Memory.get_crew_memory()
if memory.id == 0 then return {} end
local playerlist = {}
for _, id in pairs(memory.crewplayerindices) do
local player = game.players[id]
if player and player.valid then playerlist[#playerlist + 1] = player end
end
return playerlist
end
function Public.crew_get_crew_members_and_spectators()
local memory = Memory.get_crew_memory()
if memory.id == 0 then return {} end
local playerlist = {}
for _, id in pairs(memory.crewplayerindices) do
local player = game.players[id]
if player and player.valid then playerlist[#playerlist + 1] = player end
end
for _, id in pairs(memory.spectatorplayerindices) do
local player = game.players[id]
if player and player.valid then playerlist[#playerlist + 1] = player end
end
return playerlist
end
function Public.crew_get_nonafk_crew_members()
local global_memory = Memory.get_global_memory()
local memory = Memory.get_crew_memory()
if memory.id == 0 then return {} end
local playerlist = {}
for _, id in pairs(memory.crewplayerindices) do
local player = game.players[id]
if player and player.valid and not Utils.contains(global_memory.afk_player_indices, player.index) then
playerlist[#playerlist + 1] = player
end
end
return playerlist
end
function Public.destroy_decoratives_in_area(surface, area, offset)
local area2 = {{area[1][1] + offset.x, area[1][2] + offset.y}, {area[2][1] + offset.x, area[2][2] + offset.y}}
surface.destroy_decoratives{area = area2}
end
function Public.can_place_silo_setup(surface, p, build_check_type_name)
Public.ensure_chunks_at(surface, p, 0.2)
build_check_type_name = build_check_type_name or 'manual'
local build_check_type = defines.build_check_type[build_check_type_name]
local s = surface.can_place_entity{name = 'rocket-silo', position = p, build_check_type = build_check_type}
return s
end
function Public.ensure_chunks_at(surface, pos, radius) --WARNING: THIS DOES NOT PLAY NICELY WITH DELAYED TASKS. log(inspect{global_memory.working_id}) was observed to vary before and after this function.
local global_memory = Memory.get_global_memory()
if surface and surface.valid then
surface.request_to_generate_chunks(pos, radius)
surface.force_generate_chunk_requests() --WARNING: THIS DOES NOT PLAY NICELY WITH DELAYED TASKS. log(inspect{global_memory.working_id}) was observed to vary before and after this function.
end
end
function Public.default_map_gen_settings(width, height, seed)
width = width or 512
height = height or 512
seed = seed or Math.random(1, 1000000)
local map_gen_settings = {
['seed'] = seed,
['width'] = width,
['height'] = height,
['water'] = 0,
--FIXME: Back when this was at x=2000, a crash was caused once by a player spawning at x=2000. So there will be a crash in future under unknown circumstances if there is no space at x=0,y=0.
['starting_points'] = {{x = 0, y = 0}},
['cliff_settings'] = {cliff_elevation_interval = 0, cliff_elevation_0 = 0},
['default_enable_all_autoplace_controls'] = true,
['autoplace_settings'] = {
['entity'] = {treat_missing_as_default = false},
['tile'] = {treat_missing_as_default = true},
['decorative'] = {treat_missing_as_default = true},
},
['property_expression_names'] = {},
}
return map_gen_settings
end
function Public.build_from_blueprint(bp_string, surface, pos, force, flipped)
flipped = flipped or false
local bp_entity = game.surfaces['nauvis'].create_entity{name = 'item-on-ground', position = {x = 158.5, y = 158.5}, stack = 'blueprint'}
bp_entity.stack.import_stack(bp_string)
local direction = flipped and defines.direction.south or defines.direction.north
local entities = bp_entity.stack.build_blueprint{surface = surface, force = force, position = {x = pos.x, y = pos.y}, force_build = true, skip_fog_of_war = false, direction = direction}
bp_entity.destroy()
local rev_entities = {}
for _, e in pairs(entities) do
if e and e.valid then
local collisions, revived_entity = e.silent_revive()
rev_entities[#rev_entities + 1] = revived_entity
end
end
-- once again, to revive wagons:
for _, e in pairs(entities) do
if e and e.valid and e.type and e.type == 'entity-ghost' then
local collisions, revived_entity = e.silent_revive()
rev_entities[#rev_entities + 1] = revived_entity
if revived_entity and revived_entity.valid and revived_entity.name == 'locomotive' then
revived_entity.color = {255, 106, 52}
revived_entity.get_inventory(defines.inventory.fuel).insert({name = 'wood', count = 16})
revived_entity.operable = false
end
end
end
return rev_entities
end
function Public.build_small_loco(surface, pos, force, color)
local p1 = {x = pos.x, y = pos.y}
local p2 = {x = pos.x, y = pos.y -2}
local p3 = {x = pos.x, y = pos.y + 2}
local es = {}
es[1] = surface.create_entity({name = 'straight-rail', position = p1, force = force, create_build_effect_smoke = false})
es[2] = surface.create_entity({name = 'straight-rail', position = p2, force = force, create_build_effect_smoke = false})
es[3] = surface.create_entity({name = 'straight-rail', position = p3, force = force, create_build_effect_smoke = false})
es[4] = surface.create_entity({name = 'locomotive', position = p1, force = force, create_build_effect_smoke = false})
for _, e in pairs(es) do
if e and e.valid then
e.destructible = false
e.minable = false
e.rotatable = false
e.operable = false
end
end
if es[4] and es[4].valid then
es[4].color = color
es[4].get_inventory(defines.inventory.fuel).insert({name = 'wood', count = 16})
end
end
function Public.tile_positions_from_blueprint(bp_string, offset)
local bp_entity = game.surfaces['nauvis'].create_entity{name = 'item-on-ground', position = {x = 158.5, y = 158.5}, stack = 'blueprint'}
bp_entity.stack.import_stack(bp_string)
local bp_tiles = bp_entity.stack.get_blueprint_tiles()
local positions = {}
if bp_tiles then
for _, tile in pairs(bp_tiles) do
positions[#positions + 1] = {x = tile.position.x + offset.x, y = tile.position.y + offset.y}
end
end
bp_entity.destroy()
return positions
end
function Public.tile_positions_from_blueprint_arrayform(bp_string, offset)
local bp_entity = game.surfaces['nauvis'].create_entity{name = 'item-on-ground', position = {x = 158.5, y = 158.5}, stack = 'blueprint'}
bp_entity.stack.import_stack(bp_string)
local bp_tiles = bp_entity.stack.get_blueprint_tiles()
local positions = {}
if bp_tiles then
for _, tile in pairs(bp_tiles) do
local x = tile.position.x+ offset.x
local y = tile.position.y + offset.y
if not positions[x] then positions[x] = {} end
positions[x][y] = true
end
end
bp_entity.destroy()
return positions
end
function Public.entity_positions_from_blueprint(bp_string, offset)
local bp_entity = game.surfaces['nauvis'].create_entity{name = 'item-on-ground', position = {x = 158.5, y = 158.5}, stack = 'blueprint'}
bp_entity.stack.import_stack(bp_string)
local es = bp_entity.stack.get_blueprint_entities()
local positions = {}
if es then
for _, e in pairs(es) do
positions[#positions + 1] = {x = e.position.x + offset.x, y = e.position.y + offset.y}
end
end
bp_entity.destroy()
return positions
end
function Public.get_random_unit_type(evolution)
-- approximating graphs from https://wiki.factorio.com/Enemies
local r = Math.random()
if Math.random(5) == 1 then
if r < 1 - 1/0.15*(evolution - 0.25) then
return 'small-biter'
elseif r < 1 - 1/0.3*(evolution - 0.4) then
return 'small-spitter'
elseif r < 1 - 0.85/0.5*(evolution - 0.5) then
return 'medium-spitter'
elseif r < 1 - 0.4/0.1*(evolution - 0.9) then
return 'big-spitter'
else
return 'behemoth-spitter'
end
else
if r < 1 - 1/0.4*(evolution - 0.2) then
return 'small-biter'
elseif r < 1 - 0.8/0.5*(evolution - 0.5) then
return 'medium-biter'
elseif r < 1 - 0.4/0.1*(evolution - 0.9) then
return 'big-biter'
else
return 'behemoth-biter'
end
end
end
function Public.get_random_biter_type(evolution)
-- approximating graphs from https://wiki.factorio.com/Enemies
local r = Math.random()
if r < 1 - 1/0.4*(evolution - 0.2) then
return 'small-biter'
elseif r < 1 - 0.8/0.5*(evolution - 0.5) then
return 'medium-biter'
elseif r < 1 - 0.4/0.1*(evolution - 0.9) then
return 'big-biter'
else
return 'behemoth-biter'
end
end
function Public.get_random_spitter_type(evolution)
-- approximating graphs from https://wiki.factorio.com/Enemies
local r = Math.random()
if r < 1 - 1/0.3*(evolution - 0.4) then
return 'small-spitter'
elseif r < 1 - 0.85/0.5*(evolution - 0.5) then
return 'medium-spitter'
elseif r < 1 - 0.4/0.1*(evolution - 0.9) then
return 'big-spitter'
else
return 'behemoth-spitter'
end
end
function Public.get_random_worm_type(evolution)
-- custom
local r = Math.random()
if r < 1 - 1/0.7*(evolution + 0.1) then
return 'small-worm-turret'
elseif r < 1 - 0.8/0.8*(evolution - 0.2) then
return 'medium-worm-turret'
elseif r < 1 - 0.4/0.4*(evolution - 0.6) then
return 'big-worm-turret'
else
return 'behemoth-worm-turret'
end
end
function Public.maximumUnitPollutionCost(evolution)
if evolution < 0.2 then return 4
elseif evolution < 0.5 then return 20
elseif evolution < 0.9 then return 80
else return 400
end
end
function Public.averageUnitPollutionCost(evolution)
local sum_biters = 0
local f1 = Math.slopefromto(1 - 1/0.4*(evolution - 0.2), 0, 1)
local f2 = Math.slopefromto(1 - 0.8/0.5*(evolution - 0.5), 0, 1)
local f3 = Math.slopefromto(1 - 0.4/0.1*(evolution - 0.9), 0, 1)
sum_biters = sum_biters + 4 * f1
sum_biters = sum_biters + 20 * (f2 - f1)
sum_biters = sum_biters + 80 * (f3 - f2)
sum_biters = sum_biters + 400 * (1 - f3)
local sum_spitters = 0
local f1 = Math.slopefromto(1 - 1/0.15*(evolution - 0.25), 0, 1)
local f2 = Math.slopefromto(1 - 1/0.3*(evolution - 0.4), 0, 1)
local f3 = Math.slopefromto(1 - 0.85/0.5*(evolution - 0.5), 0, 1)
local f4 = Math.slopefromto(1 - 0.4/0.1*(evolution - 0.9), 0, 1)
sum_spitters = sum_spitters + 4 * f1
sum_spitters = sum_spitters + 4 * (f2 - f1)
sum_spitters = sum_spitters + 12 * (f3 - f2)
sum_spitters = sum_spitters + 30 * (f4 - f3)
sum_spitters = sum_spitters + 200 * (1 - f4)
return (5 * sum_biters + sum_spitters)/6
end
function Public.orthog_positions_in_orthog_area(area)
local positions = {}
for y = area[1][2] + 0.5, area[2][2] - 0.5, 1 do
for x = area[1][1] + 0.5, area[2][1] - 0.5, 1 do
positions[#positions + 1] = {x = x, y = y}
end
end
return positions
end
function Public.tileslist_add_area_offset(tiles_list_to_add_to, area, offset, tile_type)
for _, p in pairs(Public.orthog_positions_in_orthog_area(area)) do
tiles_list_to_add_to[#tiles_list_to_add_to + 1] = {name = tile_type, position = {x = offset.x + p.x, y = offset.y + p.y}}
end
end
function Public.central_positions_within_area(area, offset)
local offsetx = offset.x or 0
local offsety = offset.y or 0
local xr1, xr2, yr1, yr2 = offsetx + Math.ceil(area[1][1] - 0.5), offsetx + Math.floor(area[2][1] + 0.5), offsety + Math.ceil(area[1][2] - 0.5), offsety + Math.floor(area[2][2] + 0.5)
local positions = {}
for y = yr1 + 0.5, yr2 - 0.5, 1 do
for x = xr1 + 0.5, xr2 - 0.5, 1 do
positions[#positions + 1] = {x = x, y = y}
end
end
return positions
end
function Public.tiles_from_area(tiles_list_to_add_to, area, offset, tile_type)
for _, p in pairs(Public.central_positions_within_area(area, offset)) do
tiles_list_to_add_to[#tiles_list_to_add_to + 1] = {name = tile_type, position = {x = p.x, y = p.y}}
end
end
function Public.tiles_horizontally_flipped(tiles, x_to_flip_about)
local tiles2 = {}
for _, t in pairs(tiles) do
local t2 = Utils.deepcopy(t)
t2.position = {x = 2 * x_to_flip_about - t2.position.x, y = t2.position.y}
tiles2[#tiles2 + 1] = t2
end
return tiles2
end
function Public.validate_player(player)
local ret = false
if player and player.valid and player.connected and game.players[player.name] then
ret = true
end
if not ret and _DEBUG then
log('player validation fail: ' .. (player.name or 'noname'))
end
return ret
end
function Public.validate_player_and_character(player)
local ret = Public.validate_player(player)
ret = ret and player.character and player.character.valid
return ret
end
function Public.give_reward_items(items)
local memory = Memory.get_crew_memory()
local boat = memory.boat
if not boat then return end
local surface_name = boat.surface_name
if not surface_name then return end
local surface = game.surfaces[surface_name]
if not (surface and surface.valid) then return end
local chest = boat.output_chest
if not (chest and chest.valid) then return end
local inventory = chest.get_inventory(defines.inventory.chest)
for _, i in pairs(items) do
if not (i.count and i.count>0) then return end
local inserted = inventory.insert{name = i.name, count = Math.ceil(i.count)}
if i.count - inserted > 0 then
local chest2 = boat.backup_output_chest
if not (chest2 and chest2.valid) then return end
local inventory2 = chest2.get_inventory(defines.inventory.chest)
local inserted2 = inventory2.insert{name = i.name, count = Math.ceil(i.count - inserted)}
if i.count - inserted - inserted2 > 0 then
local force = game.forces[memory.force_name]
if not (force and force.valid) then return end
Public.notify_force(force, 'Warning: captain\'s cabin chests are full!')
end
end
end
end
function Public.init_game_settings(technology_price_multiplier)
global.friendly_fire_history = {}
global.landfill_history = {}
global.mining_history = {}
game.difficulty_settings.technology_price_multiplier = technology_price_multiplier
game.map_settings.enemy_evolution.pollution_factor = 0
game.map_settings.enemy_evolution.time_factor = 0
game.map_settings.enemy_evolution.destroy_factor = 0
game.map_settings.max_expansion_distance = 4
game.map_settings.unit_group.min_group_gathering_time = 60 * 5
game.map_settings.unit_group.max_group_gathering_time = 60 * 210
game.map_settings.unit_group.max_wait_time_for_late_members = 60 * 15
game.map_settings.unit_group.member_disown_distance = 5000
game.map_settings.unit_group.max_group_radius = 70
game.map_settings.unit_group.min_group_radius = 0.5 --seems to govern biter 'attack area' stopping distance
-- (0,2) for a symmetric search:
game.map_settings.path_finder.goal_pressure_ratio = -0.1 --small pressure for stupid paths
game.map_settings.path_finder.fwd2bwd_ratio = 2
game.map_settings.max_failed_behavior_count = 2
game.map_settings.path_finder.max_work_done_per_tick = 20000
game.map_settings.path_finder.short_cache_min_algo_steps_to_cache = 100
game.map_settings.path_finder.cache_accept_path_start_distance_ratio = 0.1
game.map_settings.enemy_expansion.enabled = true
-- game.map_settings.enemy_expansion.max_expansion_cooldown = 3600
-- game.map_settings.enemy_expansion.min_expansion_cooldown = 3600
-- game.map_settings.enemy_expansion.settler_group_max_size = 8
-- game.map_settings.enemy_expansion.settler_group_min_size = 16
-- game.map_settings.enemy_expansion.max_expansion_distance = 9
-- could turn off default AI attacks:
game.map_settings.pollution.enemy_attack_pollution_consumption_modifier = 1
--
game.map_settings.pollution.enabled = true
game.map_settings.pollution.expected_max_per_chunk = 120
game.map_settings.pollution.min_to_show_per_chunk = 10
game.map_settings.pollution.min_pollution_to_damage_trees = 20
game.map_settings.pollution.pollution_per_tree_damage = 0.2
game.map_settings.pollution.max_pollution_to_restore_trees = 0.04
game.map_settings.pollution.pollution_restored_per_tree_damage = 0.01
game.map_settings.pollution.pollution_with_max_forest_damage = 80
game.map_settings.pollution.ageing = 0.1
game.map_settings.pollution.diffusion_ratio = 0.035
--
-- game.forces.neutral.character_inventory_slots_bonus = 500
game.forces.enemy.evolution_factor = 0
end
return Public

226
maps/pirates/coredata.lua Normal file
View File

@@ -0,0 +1,226 @@
local Math = require 'maps.pirates.math'
local inspect = require 'utils.inspect'.inspect
local Public = {}
Public.scenario_id_name = 'pirates'
Public.version_string = '1.0.1.5'
Public.version_float = 1.015
Public.victory_x = 1000
Public.lobby_surface_name = '000-000-Lobby'
Public.colors = {
coal = {r=0.5, g=0.5, b=0.5},
wood = {r=204, g=158, b=67},
stone = {r=230, g=220, b=190},
coin = {r=242, g=193, b=97},
['raw-fish'] = {r=0, g=237, b=170},
['iron-plate'] = {r=170, g=180, b=190},
['iron-ore'] = {r=170, g=180, b=190},
['copper-plate'] = {r=219, g=149, b=96},
['copper-ore'] = {r=219, g=149, b=96},
notify_player = {r=255, g=231, b=46},
notify_game = {r=249, g=103, b=56},
notify_lobby = {r=249, g=153, b=56},
notify_force = {r=249, g=153, b=56},
notify_force_light = {r=255, g=220, b=161},
parrot = {r=87, g=255, b=148},
notify_victory = {r=84, g=249, b=84},
notify_gameover = {r=249, g=84, b=84},
renderingtext_green = {r=88, g=219, b=88},
renderingtext_yellow = {r=79, g=136, b=209},
}
Public.static_boat_floor = 'brown-refined-concrete'
Public.moving_boat_floor = 'lab-dark-2'
Public.world_concrete_tile = 'black-refined-concrete'
Public.walkway_tile = 'orange-refined-concrete'
Public.landing_tile = 'red-refined-concrete'
Public.enemy_landing_tile = 'purple-refined-concrete'
Public.overworld_loading_tile = 'yellow-refined-concrete'
Public.overworld_presence_tile = 'green-refined-concrete'
Public.kraken_tile = 'pink-refined-concrete'
Public.enemy_units = {
'small-biter',
'small-spitter',
'medium-biter',
'medium-spitter',
'big-biter',
'big-spitter',
'behemoth-biter',
'behemoth-spitter',
}
Public.water_tile_names = {'water', 'deepwater', 'water-green', 'deepwater-green'}
Public.edgemost_tile_names = {'sand-1'}
Public.tiles_that_conflict_with_resource_layer = {'water', 'deepwater', 'water-green', 'deepwater-green', 'water-shallow', 'water-mud', 'out-of-map'}
Public.tiles_that_conflict_with_resource_layer_extended = {'water', 'deepwater', 'water-green', 'deepwater-green', 'water-shallow', 'water-mud', 'out-of-map', 'red-refined-concrete', 'brown-refined-concrete'}
Public.noworm_tile_names = {'red-refined-concrete', 'purple-refined-concrete', 'green-refined-concrete', 'orange-refined-concrete', 'brown-refined-concrete', 'lab-dark-2', 'sand-1', 'red-desert-3'}
Public.worm_solid_tile_names = {'black-refined-concrete', 'stone-path', 'concrete', 'refined-concrete', 'red-refined-concrete', 'purple-refined-concrete', 'brown-refined-concrete', 'lab-dark-2', 'sand-1', 'red-desert-3'}
Public.unteleportable_names = {'transport-belt', 'underground-belt', 'splitter', 'loader', 'fast-transport-belt', 'fast-underground-belt', 'fast-splitter', 'fast-loader', 'express-transport-belt', 'express-underground-belt', 'express-splitter', 'express-loader', 'pipe', 'pipe-to-ground', 'offshore-pump', 'chemical-plant', 'oil-refinery', 'flamethrower-turret', 'storage-tank', 'assembling-machine-2', 'assembling-machine-3', 'boiler', 'steam-engine', 'heat-exchanger', 'steam-turbine', 'pump', 'straight-rail', 'curved-rail', 'cargo-wagon', 'artillery-turret', 'electric-energy-interface', 'accumulator', 'linked-belt'}
Public.comfy_emojis = {
monkas = '<:monkas:555120573752279056>',
trashbin = '<:trashbin:835887736253710396>',
pogkot = '<:pogkot:763854655612518420>',
goldenobese = '<:goldenobese:491135683508043786>',
wut = '<:wut:493320605592977443>',
smolfish = '<:smolfish:673942701682589731>',
mjau = '<:mjau:789611417132073010>',
spurdo = '<:spurdo:669546779360100382>',
loops = '<:loops:783508194755346462>',
ree1 = '<:ree1:555118905090244618>',
derp = '<:derp:527570293850505266>',
doge = '<:doge:491152224681066496>',
yum1 = '<:yum1:740341272451219517>',
feel = '<:feel:491147760553164800>',
}
Public.capacity_options = {
{value = 4, icon = 'virtual-signal/signal-4', text = '4', text2 = '/4', text3 = '4'},
{value = 8, icon = 'virtual-signal/signal-8', text = '8', text2 = '/8', text3 = '8'},
{value = 999, icon = 'virtual-signal/signal-blue', text = 'Inf.', text2 = '', text3 = 'Inf'},
-- {value = 64, icon = 'item/storage-tank', text = '64'},
}
Public.difficulty_options = {
{value = 0.5, icon = 'item/firearm-magazine', text = 'Easy', associated_color = {50, 255, 50}},
{value = 1, icon = 'item/piercing-rounds-magazine', text = 'Normal', associated_color = {255, 255, 50}},
{value = 1.5, icon = 'item/uranium-rounds-magazine', text = 'Hard', associated_color = {255, 50, 50}},
{value = 3, icon = 'item/atomic-bomb', text = 'Nightmare', associated_color = {50, 10, 10}},
}
-- Public.mode_options = {
-- left = {value = 'speedrun', icon = 'achievement/watch-your-step', text = 'Speedrun'},
-- right = {value = 'infinity', icon = 'achievement/mass-production-1', text = 'Infinity'},
-- }
Public.daynightcycle_types = {
{displayname = 'Static', 0},
{displayname = 'Slow Cyclic', ticksperday = 100000},
{displayname = 'Cyclic', ticksperday = 60000},
{displayname = 'Fast Cyclic', ticksperday = 30000},
}
Public.ore_types = {
{name = 'iron-ore', sprite_name = 'entity/iron-ore'},
{name = 'copper-ore', sprite_name = 'entity/copper-ore'},
{name = 'coal', sprite_name = 'entity/coal'},
{name = 'stone', sprite_name = 'entity/stone'},
{name = 'uranium-ore', sprite_name = 'entity/uranium-ore'},
{name = 'crude-oil', sprite_name = 'entity/crude-oil'},
}
Public.cost_items = {
{name = 'small-lamp', display_name = 'Small lamp', sprite_name = 'item/small-lamp', color={r=255,g=0,b=0}},
{name = 'engine-unit', display_name = 'Engine unit', sprite_name = 'item/engine-unit', color={r=255,g=255,b=0}},
{name = 'advanced-circuit', display_name = 'Advanced circuit', sprite_name = 'item/advanced-circuit', color={r=0,g=0,b=255}},
{name = 'electric-engine-unit', display_name = 'Electric engine unit', sprite_name = 'item/electric-engine-unit', color={r=0,g=255,b=255}},
{name = 'uranium-235', display_name = 'Uranium-235', sprite_name = 'item/uranium-235', color={r=0,g=255,b=0}},
}
Public.fallthrough_destination = {
dynamic_data = {},
static_params = {},
type = 'Lobby',
surface_name = Public.lobby_surface_name,
}
-- hacked to make spitters 25% cheaper:
Public.biterPollutionValues = {
['behemoth-biter'] = 400,
['behemoth-spitter'] = 150,
['big-biter'] = 80,
['big-spitter'] = 22,
['medium-biter'] = 20,
['medium-spitter'] = 9,
['small-biter'] = 4,
['small-spitter'] = 3
}
-- base game:
-- Public.biterPollutionValues = {
-- ['behemoth-biter'] = 400,
-- ['behemoth-spitter'] = 200,
-- ['big-biter'] = 80,
-- ['big-spitter'] = 30,
-- ['medium-biter'] = 20,
-- ['medium-spitter'] = 12,
-- ['small-biter'] = 4,
-- ['small-spitter'] = 4
-- }
Public.loco_bp_1 = [[0eNqV0ttqwzAMBuB30bVTVufsVxljpKloBYkcbLdrCH73Oi6UMrxDLm3zf7KEFjgMF5wMsQO1APWaLaj3BSyduBvWOzdPCArI4QgCuBvX06B7PWpHVwQvgPiIN1B7L/4Mmo6Gl4j0HwKQHTnCR+F4mD/5Mh7QBDNVUsCkbYhoXusEJmsFzKCqAGtDgegej2/rj76J8il+aX1EzvozWpcwm10ZVbkrfcLJ/+u0vzvF07EuTOd0dlkc0k9NJpFyI1KnkGrrZJp0R/XWyUQnLEJcFfWykgKuaGxMyGZf1K2sC5nnTVl5fwdTR+VL]]
function Public.Dock_iconized_map()
local tiles = {}
for x = -15.5, 3.5 do
for y = -19.5, -0.5 do
if (y >-7 and y<-2 and x == -2.5)
or (y == -6.5 and x<2 and x>-6)
then
tiles[#tiles + 1] = {name = Public.walkway_tile, position = {x = x, y = y}}
elseif y > -3 + Math.abs(x+5)^2/20 then --'island'
if y > -0.5 and x<-3 and x>-7 then
tiles[#tiles + 1] = {name = 'grass-1', position = {x = x, y = y}}
elseif y > -3 + Math.abs(x+5)^2/10 then
tiles[#tiles + 1] = {name = 'dirt-3', position = {x = x, y = y}}
else
tiles[#tiles + 1] = {name = 'dry-dirt', position = {x = x, y = y}}
end
elseif y>-7 then
tiles[#tiles + 1] = {name = 'water', position = {x = x, y = y}}
end
end
end
return {
tiles = tiles,
entities = {},
}
end
function Public.Lobby_iconized_map()
local tiles, width, height = {}, 4,
20
for x = -100, width do
for y = -35.5, 35.5 do
local negx = width - x
local negxnoisy = negx + Math.random(3)-2
if negxnoisy >= 50 then
tiles[#tiles + 1] = {name = 'grass-3', position = {x = x, y = y}}
elseif negxnoisy >= 30 and (negxnoisy-30) >= Math.abs(y)^2/200 then
tiles[#tiles + 1] = {name = 'dirt-4', position = {x = x, y = y}}
elseif negxnoisy >= 15 and (negxnoisy-15) >= Math.abs(y)^2/150 then
tiles[#tiles + 1] = {name = 'dirt-2', position = {x = x, y = y}}
else
if negx >= 5 and (negx-5) >= Math.abs(y)^2/100 then
tiles[#tiles + 1] = {name = 'sand-2', position = {x = x, y = y}}
elseif (negx <= 8 and Math.abs(y)<1) or (negx < 1 and Math.abs(y)<3) then
tiles[#tiles + 1] = {name = Public.walkway_tile, position = {x = x, y = y}}
else
tiles[#tiles + 1] = {name = 'water', position = {x = x, y = y}}
end
end
end
end
return {
tiles = tiles,
entities = {},
}
end
return Public

827
maps/pirates/crew.lua Normal file
View File

@@ -0,0 +1,827 @@
local Balance = require 'maps.pirates.balance'
local inspect = require 'utils.inspect'.inspect
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Common = require 'maps.pirates.common'
local Parrot = require 'maps.pirates.parrot'
local CoreData = require 'maps.pirates.coredata'
local Server = require 'utils.server'
local Utils = require 'maps.pirates.utils_local'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Structures = require 'maps.pirates.structures.structures'
local Boats = require 'maps.pirates.structures.boats.boats'
local Crowsnest = require 'maps.pirates.surfaces.crowsnest'
local Hold = require 'maps.pirates.surfaces.hold'
local Lobby = require 'maps.pirates.surfaces.lobby'
local Cabin = require 'maps.pirates.surfaces.cabin'
local Roles = require 'maps.pirates.roles.roles'
local Token = require 'utils.token'
local Task = require 'utils.task'
local SurfacesCommon = require 'maps.pirates.surfaces.common'
local Public = {}
local enum = {
ADVENTURING = 'adventuring',
LEAVING_INITIAL_DOCK = 'leavinginitialdock'
}
Public.enum = enum
function Public.difficulty_vote(player_index, difficulty_id)
local memory = Memory.get_crew_memory()
local player = game.players[player_index]
if not (player and player.valid) then return end
local option = CoreData.difficulty_options[difficulty_id]
if not option then return end
Common.notify_force(game.forces[memory.force_name], player.name .. ' voted for difficulty ' .. option.text, option.associated_color)
if not (memory.difficulty_votes) then memory.difficulty_votes = {} end
memory.difficulty_votes[player_index] = difficulty_id
Public.update_difficulty()
end
function Public.update_difficulty()
local memory = Memory.get_crew_memory()
local vote_counts = {}
for _, difficulty_id in pairs(memory.difficulty_votes) do
if not vote_counts[difficulty_id] then
vote_counts[difficulty_id] = 1
else
vote_counts[difficulty_id] = vote_counts[difficulty_id] + 1
end
end
local modal_id = 1
local modal_count = 0
for difficulty_id, votes in pairs(vote_counts) do
if votes > modal_count or (votes == modal_count and difficulty_id < modal_id) then
modal_count = votes
modal_id = difficulty_id
end
end
if modal_id ~= memory.difficulty_option then
Common.notify_force(game.forces[memory.force_name], 'Difficulty changed to ' .. CoreData.difficulty_options[modal_id].text .. '.')
memory.difficulty_option = modal_id
memory.difficulty = CoreData.difficulty_options[modal_id].value
end
end
function Public.try_add_extra_time_at_sea(ticks)
local memory = Memory.get_crew_memory()
if not memory.extra_time_at_sea then memory.extra_time_at_sea = 0 end
if memory.extra_time_at_sea > 4*60*60 then return false end
-- if memory.boat and memory.boat.state and memory.boat.state == Boats.enum_state.ATSEA_LOADING_MAP then return false end
memory.extra_time_at_sea = memory.extra_time_at_sea + ticks
return true
end
function Public.try_lose(reason)
local memory = Memory.get_crew_memory()
if (not memory.game_lost) then
memory.game_lost = true
memory.crew_disband_tick = game.tick + 360
local playtimetext = Utils.time_longform((memory.age or 0)/60)
Server.to_discord_embed_raw(CoreData.comfy_emojis.trashbin .. '[' .. memory.name .. '] Game over — ' .. reason ..'. Playtime: ' .. playtimetext .. '.')
Common.notify_game('[' .. memory.name .. '] Game over — ' .. reason ..'. Playtime: [font=default-large-semibold]' .. playtimetext .. '[/font].', CoreData.colors.notify_gameover)
local force = game.forces[memory.force_name]
if not (force and force.valid) then return end
force.play_sound{path='utility/game_lost', volume_modifier=0.75}
end
end
function Public.choose_crew_members()
local global_memory = Memory.get_global_memory()
local memory = Memory.get_crew_memory()
local capacity = memory.capacity
local boat = memory.boat
-- if the boat is over capacity, should prefer original endorsers over everyone else:
local crew_members = {}
local crew_members_count = 0
for _, player in pairs(game.connected_players) do
if crew_members_count < capacity and player.surface.name == CoreData.lobby_surface_name and Boats.on_boat(boat, player.position) then
-- check if they were an endorser
local endorser = false
for _, index in pairs(memory.original_proposal.endorserindices) do
if player.index == index then endorser = true end
end
if endorser then
crew_members[player.index] = player
crew_members_count = crew_members_count + 1
end
end
end
if crew_members_count < capacity then
for _, player in pairs(game.connected_players) do
if crew_members_count < capacity and (not crew_members[player.index]) and player.surface.name == CoreData.lobby_surface_name and Boats.on_boat(boat, player.position) then
crew_members[player.index] = player
crew_members_count = crew_members_count + 1
end
end
end
for _, player in pairs(crew_members) do
player.force = game.forces[memory.force_name]
memory.crewplayerindices[#memory.crewplayerindices + 1] = player.index
end
return crew_members
end
function Public.join_spectators(player, crewid)
if crewid > 0 then
Memory.set_working_id(crewid)
local memory = Memory.get_crew_memory()
local force = game.forces[string.format('crew-%03d', crewid)]
if not (force and force.valid and Common.validate_player(player)) then return end
local surface = game.surfaces[CoreData.lobby_surface_name]
local adventuring = false
local spectating = false
if memory.crewstatus and memory.crewstatus == enum.ADVENTURING then
for _, playerindex in pairs(memory.crewplayerindices) do
if player.index == playerindex then adventuring = true end
end
for _, playerindex in pairs(memory.spectatorplayerindices) do
if player.index == playerindex then spectating = true end
end
end
if not spectating then
if adventuring then
local char = player.character
if char and char.valid then
local p = char.position
local surface_name = char.surface.name
local message = player.name .. ' left the crew'
if p then
Common.notify_force(force, message .. ' to become a spectator.' .. ' [gps=' .. Math.ceil(p.x) .. ',' .. Math.ceil(p.y) .. ',' .. surface_name ..']')
-- Server.to_discord_embed_raw(CoreData.comfy_emojis.feel .. '[' .. memory.name .. '] ' .. message)
end
player.set_controller{type = defines.controllers.spectator}
char.die(memory.force_name)
else
local message = player.name .. ' left the crew'
Common.notify_force(force, message .. ' to become a spectator.')
-- Server.to_discord_embed_raw(CoreData.comfy_emojis.feel .. '[' .. memory.name .. '] ' .. message)
player.set_controller{type = defines.controllers.spectator}
end
local c = surface.create_entity{name = 'character', position = surface.find_non_colliding_position('character', Common.lobby_spawnpoint, 32, 0.5) or Common.lobby_spawnpoint, force = 'player'}
player.associate_character(c)
player.set_controller{type = defines.controllers.spectator}
memory.crewplayerindices = Utils.ordered_table_with_values_removed(memory.crewplayerindices, player.index)
Roles.player_left_so_redestribute_roles(player)
else
Public.player_abandon_endorsements(player)
local c = player.character
player.set_controller{type = defines.controllers.spectator}
player.teleport(memory.spawnpoint, game.surfaces[Common.current_destination().surface_name])
player.force = force
player.associate_character(c)
Common.notify_force(force, player.name .. ' has joined as a spectator.')
Common.notify_lobby(player.name .. ' left the lobby to spectate ' .. memory.name .. '.')
end
memory.spectatorplayerindices[#memory.spectatorplayerindices + 1] = player.index
memory.tempbanned_from_joining_data[player.index] = game.tick
if #Common.crew_get_crew_members() == 0 then
memory.crew_disband_tick = game.tick + 10
end
if not (memory.difficulty_votes) then memory.difficulty_votes = {} end
memory.difficulty_votes[player.index] = nil
end
end
end
function Public.leave_spectators(player)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[CoreData.lobby_surface_name]
if not Common.validate_player(player) then return end
Common.notify_force(player.force, player.name .. ' stopped spectating and returned to the lobby.')
local chars = player.get_associated_characters()
if #chars > 0 then
player.teleport(chars[1].position, surface)
player.set_controller{type = defines.controllers.character, character = chars[1]}
else
player.set_controller{type = defines.controllers.god}
player.teleport(surface.find_non_colliding_position('character', Common.lobby_spawnpoint, 32, 0.5) or Common.lobby_spawnpoint, surface)
player.create_character()
end
memory.spectatorplayerindices = Utils.ordered_table_with_values_removed(memory.spectatorplayerindices, player.index)
if #Common.crew_get_crew_members() == 0 then
Public.disband_crew()
end
player.force = 'player'
end
function Public.join_crew(player, crewid)
if crewid then
Memory.set_working_id(crewid)
local memory = Memory.get_crew_memory()
if not Common.validate_player(player) then return end
local startsurface = game.surfaces[CoreData.lobby_surface_name]
local boat = memory.boat
local surface
if boat and boat.surface_name and game.surfaces[boat.surface_name] and game.surfaces[boat.surface_name].valid then
surface = game.surfaces[boat.surface_name]
else
surface = game.surfaces[Common.current_destination().surface_name]
end
local adventuring = false
local spectating = false
if memory.crewstatus and memory.crewstatus == enum.ADVENTURING then
for _, playerindex in pairs(memory.crewplayerindices) do
if player.index == playerindex then adventuring = true end
end
for _, playerindex in pairs(memory.spectatorplayerindices) do
if player.index == playerindex then spectating = true end
end
end
if spectating then
local chars = player.get_associated_characters()
for _, char in pairs(chars) do
char.destroy()
end
player.teleport(surface.find_non_colliding_position('character', memory.spawnpoint, 32, 0.5) or memory.spawnpoint, surface)
player.set_controller{type = defines.controllers.god}
player.create_character()
memory.spectatorplayerindices = Utils.ordered_table_with_values_removed(memory.spectatorplayerindices, player.index)
else
Public.player_abandon_endorsements(player)
player.force = game.forces[string.format('crew-%03d', memory.id)]
player.teleport(surface.find_non_colliding_position('character', memory.spawnpoint, 32, 0.5) or memory.spawnpoint, surface)
end
local message = player.name .. ' has joined the crew.'
Common.notify_force(player.force, message)
-- Server.to_discord_embed_raw(CoreData.comfy_emojis.yum1 .. '[' .. memory.name .. '] ' .. message)
Common.notify_lobby(player.name .. ' left the lobby to join ' .. memory.name .. '.')
memory.crewplayerindices[#memory.crewplayerindices + 1] = player.index
-- don't give them items if they've been in the crew recently:
if not (memory.tempbanned_from_joining_data and memory.tempbanned_from_joining_data[player.index] and game.tick < memory.tempbanned_from_joining_data[player.index] + 8 * Common.ban_from_rejoining_crew_ticks) then
for item, amount in pairs(Balance.starting_items_player_late) do
player.insert({name = item, count = amount})
end
end
if #Common.crew_get_crew_members() == 1 and memory.crew_disband_tick then
memory.crew_disband_tick = nil --to prevent disbanding the crew after saving the game (booting everyone) and loading it again (joining the crew as the only member)
end
end
end
function Public.leave_crew(player)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[CoreData.lobby_surface_name]
if not Common.validate_player(player) then return end
local char = player.character
player.set_controller{type = defines.controllers.god}
if char and char.valid then
local p = char.position
local surface_name = char.surface.name
local message = player.name .. ' left the crew.'
if p then
Common.notify_force(player.force, message .. ' [gps=' .. Math.ceil(p.x) .. ',' .. Math.ceil(p.y) .. ',' .. surface_name ..']')
-- Server.to_discord_embed_raw(CoreData.comfy_emojis.feel .. '[' .. memory.name .. '] ' .. message)
end
char.die(memory.force_name)
else
local message = player.name .. ' left the crew.'
Common.notify_force(player.force, message)
-- Server.to_discord_embed_raw(CoreData.comfy_emojis.feel .. '[' .. memory.name .. '] ' .. message)
end
player.teleport(surface.find_non_colliding_position('character', Common.lobby_spawnpoint, 32, 0.5) or Common.lobby_spawnpoint, surface)
player.force = 'player'
player.create_character()
memory.crewplayerindices = Utils.ordered_table_with_values_removed(memory.crewplayerindices, player.index)
-- setting it to this won't ban them from rejoining, it just affects the loot they spawn in with:
memory.tempbanned_from_joining_data[player.index] = game.tick - Common.ban_from_rejoining_crew_ticks
if not (memory.difficulty_votes) then memory.difficulty_votes = {} end
memory.difficulty_votes[player.index] = nil
if #Common.crew_get_crew_members() == 0 then
memory.crew_disband_tick = game.tick + 10
else
Roles.player_left_so_redestribute_roles(player)
end
end
function Public.get_unaffiliated_players()
local global_memory = Memory.get_global_memory()
local playerlist = {}
for _, player in pairs(game.connected_players) do
local found = false
for _, id in pairs(global_memory.crew_active_ids) do
Memory.set_working_id(id)
for _, player2 in pairs(Common.crew_get_crew_members_and_spectators()) do
if player == player2 then found = true end
end
end
if not found then playerlist[#playerlist + 1] = player end
end
return playerlist
end
function Public.disband_crew(donotprint)
local global_memory = Memory.get_global_memory()
local memory = Memory.get_crew_memory()
if not memory.name then return end
local id = memory.id
local players = Common.crew_get_crew_members_and_spectators()
for _,player in pairs(players) do
if player.controller_type == defines.controllers.editor then player.toggle_map_editor() end
player.force = 'player'
end
if (not donotprint) then
local message = '[' .. memory.name .. '] Disbanded after ' .. Utils.time_longform((memory.real_age or 0)/60) .. '.'
Common.notify_game(message)
Server.to_discord_embed_raw(CoreData.comfy_emojis.monkas .. message)
-- if memory.game_won then
-- game.print({'chronosphere.message_game_won_restart'}, {r=0.98, g=0.66, b=0.22})
-- end
end
Public.reset_crew_and_enemy_force(id)
local lobby = game.surfaces[CoreData.lobby_surface_name]
for _, player in pairs(players) do
if player.character then
player.character.destroy()
player.character = nil
end
player.set_controller({type=defines.controllers.god})
if player.get_associated_characters() and #player.get_associated_characters() == 1 then
local char = player.get_associated_characters()[1]
player.teleport(char.position, char.surface)
player.set_controller({type=defines.controllers.character, character=char})
else
local pos = lobby.find_non_colliding_position('character', Common.lobby_spawnpoint, 32, 0.5) or Common.lobby_spawnpoint
player.teleport(pos, lobby)
player.create_character()
end
end
if memory.sea_name then
local seasurface = game.surfaces[memory.sea_name]
if seasurface then game.delete_surface(seasurface) end
end
for i = 1, memory.hold_surface_count do
local holdname = Hold.get_hold_surface_name(i)
if game.surfaces[holdname] then
game.delete_surface(game.surfaces[holdname])
end
end
local cabinname = Cabin.get_cabin_surface_name()
if game.surfaces[cabinname] then
game.delete_surface(game.surfaces[cabinname])
end
local s = Hold.get_hold_surface(1)
if s and s.valid then
log('hold failed to delete')
end
s = Cabin.get_cabin_surface()
if s and s.valid then
log(inspect(cabinname))
log('cabin failed to delete')
end
local crowsnestname = SurfacesCommon.encode_surface_name(memory.id, 0, Surfaces.enum.CROWSNEST, nil)
if game.surfaces[crowsnestname] then game.delete_surface(game.surfaces[crowsnestname]) end
for _, destination in pairs(memory.destinations) do
if game.surfaces[destination.surface_name] then game.delete_surface(game.surfaces[destination.surface_name]) end
end
global_memory.crew_memories[id] = nil
for k, idd in pairs(global_memory.crew_active_ids) do
if idd == id then table.remove(global_memory.crew_active_ids, k) end
end
Lobby.place_starting_dock_showboat(id)
end
function Public.generate_new_crew_id()
local global_memory = Memory.get_global_memory()
if not global_memory.crew_memories[1] then return 1
elseif not global_memory.crew_memories[2] then return 2
elseif not global_memory.crew_memories[3] then return 3
else return end
end
function Public.player_abandon_proposal(player)
local global_memory = Memory.get_global_memory()
for k, proposal in pairs(global_memory.crewproposals) do
if proposal.endorserindices and proposal.endorserindices[1] and proposal.endorserindices[1] == player.index then
proposal.endorserindices[k] = nil
Common.notify_lobby('Proposal ' .. proposal.name .. ' retracted.')
-- Server.to_discord_embed(message)
global_memory.crewproposals[k] = nil
end
end
end
function Public.player_abandon_endorsements(player)
local global_memory = Memory.get_global_memory()
for k, proposal in pairs(global_memory.crewproposals) do
for k2, i in pairs(proposal.endorserindices) do
if i == player.index then
proposal.endorserindices[k2] = nil
if #proposal.endorserindices == 0 then
Common.notify_lobby('Proposal ' .. proposal.name .. ' abandoned.')
-- Server.to_discord_embed(message)
global_memory.crewproposals[k] = nil
end
end
end
end
end
local crowsnest_delayed = Token.register(
function(data)
Crowsnest.crowsnest_surface_delayed_init()
end
)
function Public.initialise_crowsnest()
Crowsnest.create_crowsnest_surface()
Task.set_timeout_in_ticks(5, crowsnest_delayed, {})
end
function Public.initialise_crowsnest_1()
Crowsnest.create_crowsnest_surface()
end
function Public.initialise_crowsnest_2()
Crowsnest.crowsnest_surface_delayed_init()
end
function Public.initialise_crew(accepted_proposal)
local global_memory = Memory.get_global_memory()
local new_id = Public.generate_new_crew_id()
global_memory.crew_active_ids[#global_memory.crew_active_ids + 1] = new_id
Memory.reset_crew_memory(new_id)
Memory.set_working_id(new_id)
local memory = Memory.get_crew_memory()
local secs = Server.get_current_time()
if not secs then secs = 0 end
memory.secs_id = secs
memory.id = new_id
memory.force_name = string.format('crew-%03d', new_id)
memory.enemy_force_name = string.format('enemy-%03d', new_id)
memory.delayed_tasks = {}
memory.buffered_tasks = {}
memory.crewplayerindices = {}
memory.spectatorplayerindices = {}
memory.tempbanned_from_joining_data = {}
memory.destinations = {}
memory.hold_surface_count = 1
memory.speed_boost_characters = {}
memory.original_proposal = accepted_proposal
memory.name = accepted_proposal.name
memory.difficulty_option = accepted_proposal.difficulty_option
memory.capacity_option = accepted_proposal.capacity_option
-- memory.mode_option = accepted_proposal.mode_option
memory.difficulty = CoreData.difficulty_options[accepted_proposal.difficulty_option].value
memory.capacity = CoreData.capacity_options[accepted_proposal.capacity_option].value
-- memory.mode = CoreData.mode_options[accepted_proposal.mode_option].value
memory.destinationsvisited_indices = {}
memory.gold = 0
memory.captain_accrued_time_data = {}
memory.classes_table = {}
memory.spare_classes = {}
memory.healthbars = {}
memory.overworld_krakens = {}
memory.kraken_stream_registrations = {}
memory.overworldx = 0
memory.overworldy = 0
memory.seaname = SurfacesCommon.encode_surface_name(memory.id, 0, SurfacesCommon.enum.SEA, enum.DEFAULT)
local surface = game.surfaces[CoreData.lobby_surface_name]
memory.spawnpoint = Common.lobby_spawnpoint
local crew_force = game.forces[string.format('crew-%03d', new_id)]
crew_force.set_spawn_position(memory.spawnpoint, surface)
local message = '[' .. accepted_proposal.name .. '] Launched.'
Common.notify_game(message)
Server.to_discord_embed_raw(CoreData.comfy_emojis.pogkot .. message .. ' Difficulty: ' .. CoreData.difficulty_options[memory.difficulty_option].text .. ', Capacity: ' .. CoreData.capacity_options[memory.capacity_option].text3 .. '.')
game.surfaces[CoreData.lobby_surface_name].play_sound{path='utility/new_objective', volume_modifier=0.75}
memory.boat = global_memory.lobby_boats[new_id]
local boat = memory.boat
boat.dockedposition = boat.position
boat.speed = 0
boat.cannonscount = 2
end
function Public.summon_crew(tickinterval)
local memory = Memory.get_crew_memory()
local boat = memory.boat
local print = false
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 (not Boats.on_boat(boat, player.position)) then
player.teleport(memory.spawnpoint)
print = true
end
end
if print then
Common.notify_force(game.forces[memory.force_name], 'Crew summoned.')
end
end
function Public.reset_crew_and_enemy_force(id)
local crew_force = game.forces[string.format('crew-%03d', id)]
local enemy_force = game.forces[string.format('enemy-%03d', id)]
local ancient_friendly_force = game.forces[string.format('ancient-friendly-%03d', id)]
local ancient_enemy_force = game.forces[string.format('ancient-hostile-%03d', id)]
crew_force.reset()
enemy_force.reset()
ancient_friendly_force.reset()
ancient_enemy_force.reset()
ancient_enemy_force.set_turret_attack_modifier('gun-turret', 0.2)
enemy_force.reset_evolution()
for _, tech in pairs(crew_force.technologies) do
crew_force.set_saved_technology_progress(tech, 0)
end
local lobby = game.surfaces[CoreData.lobby_surface_name]
crew_force.set_spawn_position(Common.lobby_spawnpoint, lobby)
enemy_force.ai_controllable = true
crew_force.set_friend('player', true)
game.forces['player'].set_friend(crew_force, true)
crew_force.set_friend(ancient_friendly_force, true)
ancient_friendly_force.set_friend(crew_force, true)
enemy_force.set_friend(ancient_friendly_force, true)
ancient_friendly_force.set_friend(enemy_force, true)
enemy_force.set_friend(ancient_enemy_force, true)
ancient_enemy_force.set_friend(enemy_force, true)
-- enemy_force.set_friend(environment_force, true)
-- environment_force.set_friend(enemy_force, true)
-- environment_force.set_friend(ancient_enemy_force, true)
-- ancient_enemy_force.set_friend(environment_force, true)
-- environment_force.set_friend(ancient_friendly_force, true)
-- ancient_friendly_force.set_friend(environment_force, true)
-- maybe make these dependent on map... it could be slower to mine on poor maps, so that players jump more often rather than getting every last drop
crew_force.mining_drill_productivity_bonus = 1
-- crew_force.mining_drill_productivity_bonus = 1.25
crew_force.manual_mining_speed_modifier = 3
crew_force.character_inventory_slots_bonus = 10
crew_force.character_running_speed_modifier = Balance.base_extra_character_speed
crew_force.laboratory_productivity_bonus = 0
crew_force.ghost_time_to_live = 9 * 60 * 60
for k, v in pairs(Balance.player_ammo_damage_modifiers()) do
crew_force.set_ammo_damage_modifier(k, v)
end
for k, v in pairs(Balance.player_gun_speed_modifiers()) do
crew_force.set_gun_speed_modifier(k, v)
end
for k, v in pairs(Balance.player_turret_attack_modifiers()) do
crew_force.set_turret_attack_modifier(k, v)
end
crew_force.technologies['circuit-network'].researched = true
crew_force.technologies['uranium-processing'].researched = true
crew_force.technologies['kovarex-enrichment-process'].researched = true
crew_force.technologies['gun-turret'].researched = true
crew_force.technologies['electric-energy-distribution-1'].researched = true
crew_force.technologies['electric-energy-distribution-2'].researched = true
crew_force.technologies['advanced-material-processing'].researched = true
crew_force.technologies['advanced-material-processing-2'].researched = true
crew_force.technologies['solar-energy'].researched = true
crew_force.technologies['inserter-capacity-bonus-1'].researched = true
crew_force.technologies['inserter-capacity-bonus-2'].researched = true
-- note: some of these are overwritten after tech researched!!!!!!! like pistol
crew_force.recipes['pistol'].enabled = false
crew_force.recipes['centrifuge'].enabled = false
crew_force.recipes['flamethrower-turret'].enabled = true
crew_force.recipes['locomotive'].enabled = false
crew_force.recipes['car'].enabled = false
crew_force.recipes['cargo-wagon'].enabled = false
-- crew_force.recipes['underground-belt'].enabled = false
-- crew_force.recipes['fast-underground-belt'].enabled = false
-- crew_force.recipes['express-underground-belt'].enabled = false
crew_force.technologies['land-mine'].enabled = false
crew_force.technologies['landfill'].enabled = false
crew_force.technologies['cliff-explosives'].enabled = false
crew_force.technologies['rail-signals'].enabled = false
crew_force.technologies['logistic-system'].enabled = false
crew_force.technologies['tank'].enabled = false
crew_force.technologies['rocketry'].enabled = false
crew_force.technologies['artillery'].enabled = false
crew_force.technologies['destroyer'].enabled = false
crew_force.technologies['spidertron'].enabled = false
crew_force.technologies['atomic-bomb'].enabled = false
crew_force.technologies['explosive-rocketry'].enabled = false
crew_force.technologies['artillery-shell-range-1'].enabled = false
crew_force.technologies['artillery-shell-speed-1'].enabled = false
crew_force.technologies['worker-robots-storage-1'].enabled = false
crew_force.technologies['worker-robots-storage-2'].enabled = false
crew_force.technologies['worker-robots-storage-3'].enabled = false
crew_force.technologies['research-speed-1'].enabled = false
crew_force.technologies['research-speed-2'].enabled = false
crew_force.technologies['research-speed-3'].enabled = false
crew_force.technologies['research-speed-4'].enabled = false
crew_force.technologies['research-speed-5'].enabled = false
crew_force.technologies['research-speed-6'].enabled = false
crew_force.technologies['follower-robot-count-1'].enabled = false
crew_force.technologies['follower-robot-count-2'].enabled = false
crew_force.technologies['follower-robot-count-3'].enabled = false
crew_force.technologies['follower-robot-count-4'].enabled = false
crew_force.technologies['follower-robot-count-5'].enabled = false
crew_force.technologies['follower-robot-count-6'].enabled = false
crew_force.technologies['follower-robot-count-7'].enabled = false
crew_force.technologies['inserter-capacity-bonus-3'].enabled = false
crew_force.technologies['inserter-capacity-bonus-4'].enabled = false
crew_force.technologies['inserter-capacity-bonus-5'].enabled = false
crew_force.technologies['inserter-capacity-bonus-6'].enabled = false
crew_force.technologies['inserter-capacity-bonus-7'].enabled = false
crew_force.technologies['refined-flammables-3'].enabled = false
crew_force.technologies['refined-flammables-4'].enabled = false
crew_force.technologies['refined-flammables-5'].enabled = false
crew_force.technologies['refined-flammables-6'].enabled = false
crew_force.technologies['steel-axe'].enabled = false
crew_force.technologies['concrete'].enabled = false
crew_force.technologies['nuclear-power'].enabled = false
crew_force.technologies['effect-transmission'].enabled = false
crew_force.technologies['gate'].enabled = false
crew_force.technologies['productivity-module-2'].enabled = false
crew_force.technologies['productivity-module-3'].enabled = false
crew_force.technologies['speed-module'].enabled = false
crew_force.technologies['speed-module-2'].enabled = false
crew_force.technologies['speed-module-3'].enabled = false
crew_force.technologies['effectivity-module'].enabled = false
crew_force.technologies['effectivity-module-2'].enabled = false
crew_force.technologies['effectivity-module-3'].enabled = false
crew_force.technologies['automation-3'].enabled = false
crew_force.technologies['rocket-control-unit'].enabled = false
crew_force.technologies['rocket-silo'].enabled = false
crew_force.technologies['space-science-pack'].enabled = false
crew_force.technologies['mining-productivity-4'].enabled = false
crew_force.technologies['worker-robots-speed-6'].enabled = false
crew_force.technologies['energy-weapons-damage-7'].enabled = false
crew_force.technologies['physical-projectile-damage-7'].enabled = false
crew_force.technologies['refined-flammables-7'].enabled = false
crew_force.technologies['stronger-explosives-7'].enabled = false
crew_force.technologies['logistics-3'].enabled = false
crew_force.technologies['coal-liquefaction'].enabled = false
crew_force.technologies['nuclear-fuel-reprocessing'].enabled = false
crew_force.technologies['railway'].enabled = false
crew_force.technologies['automated-rail-transportation'].enabled = false
crew_force.technologies['braking-force-1'].enabled = false
crew_force.technologies['braking-force-2'].enabled = false
crew_force.technologies['braking-force-3'].enabled = false
crew_force.technologies['braking-force-4'].enabled = false
crew_force.technologies['braking-force-5'].enabled = false
crew_force.technologies['braking-force-6'].enabled = false
crew_force.technologies['braking-force-7'].enabled = false
crew_force.technologies['fluid-wagon'].enabled = false
crew_force.technologies['production-science-pack'].enabled = false
crew_force.technologies['utility-science-pack'].enabled = false
crew_force.technologies['modular-armor'].enabled = false
crew_force.technologies['power-armor'].enabled = false
crew_force.technologies['solar-panel-equipment'].enabled = false
crew_force.technologies['personal-roboport-equipment'].enabled = false
crew_force.technologies['personal-laser-defense-equipment'].enabled = false
crew_force.technologies['night-vision-equipment'].enabled = false
crew_force.technologies['energy-shield-equipment'].enabled = false
crew_force.technologies['belt-immunity-equipment'].enabled = false
crew_force.technologies['exoskeleton-equipment'].enabled = false
crew_force.technologies['battery-equipment'].enabled = false
crew_force.technologies['fusion-reactor-equipment'].enabled = false
crew_force.technologies['power-armor-mk2'].enabled = false
crew_force.technologies['energy-shield-mk2-equipment'].enabled = false
crew_force.technologies['personal-roboport-mk2-equipment'].enabled = false
crew_force.technologies['battery-mk2-equipment'].enabled = false
crew_force.technologies['discharge-defense-equipment'].enabled = false
crew_force.technologies['distractor'].enabled = false
crew_force.technologies['military-4'].enabled = false
crew_force.technologies['uranium-ammo'].enabled = false
end
return Public

122
maps/pirates/effects.lua Normal file
View File

@@ -0,0 +1,122 @@
local Math = require 'maps.pirates.math'
local Memory = require 'maps.pirates.memory'
local inspect = require 'utils.inspect'.inspect
local Token = require 'utils.token'
local Task = require 'utils.task'
local Public = {}
function Public.worm_movement_effect(surface, position, solid_ground, big_bool)
if not (surface and surface.valid) then return end
if solid_ground then big_bool = false end
local number, rmax, particles, sound
if big_bool then
number = 80
rmax = 4
particles = {'huge-rock-stone-particle-big', 'huge-rock-stone-particle-medium', 'red-desert-1-stone-particle-medium'}
-- sound = 'utility/build_blueprint_large'
sound = 'utility/build_blueprint_large'
else
number = 40
rmax = 2.5
particles = {'huge-rock-stone-particle-medium', 'red-desert-1-stone-particle-medium', 'red-desert-1-stone-particle-small'}
sound = 'utility/build_blueprint_medium'
end
if solid_ground then
particles = {'refined-concrete-stone-particle-medium', 'refined-concrete-stone-particle-small'}
sound = 'utility/build_blueprint_small'
end
local function p(r, theta) return {x = position.x + r*Math.sin(theta), y = position.y + r*Math.cos(theta)} end
for i=1,number do
local r = rmax * Math.sqrt(Math.random())
local theta = Math.random()*6.283
local name = particles[Math.random(#particles)]
local _p = p(r,theta)
surface.create_particle{name = name, position = _p, movement = {0/10, 0/10}, height = 0, vertical_speed = 0.02 + Math.sqrt(rmax - r)*rmax/50, frame_speed = 1}
if i<=5 then
surface.play_sound{path = sound, position = _p, override_sound_type = 'walking', volume_modifier=0.75}
end
end
end
function Public.worm_emerge_effect(surface, position)
if not (surface and surface.valid) then return end
if position then
local function p(r, theta) return {x = position.x + r*Math.sin(theta), y = position.y + r*Math.cos(theta)} end
for theta=0,6,0.5 do
local r = 3
surface.create_entity{name = 'blood-explosion-huge', position = p(r,theta), color={1,1,1}}
end
end
end
function Public.biters_emerge(surface, position)
if not (surface and surface.valid) then return end
surface.create_entity{name = 'spitter-spawner-die', position = position}
end
function Public.kraken_effect_1(surface, position, angle)
if not (surface and surface.valid) then return end
local r = 9
local p = {position.x + r*Math.sin(angle), position.y + r*Math.cos(angle)}
surface.create_entity{name = 'blood-explosion-huge', position = p, color={1,1,1}}
end
function Public.kraken_effect_2(surface, position)
if not (surface and surface.valid) then return end
surface.create_entity{name = 'blood-explosion-big', position = position, color={1,1,1}}
end
local kraken_effect_3_token =
Token.register(
function(data)
Public.kraken_effect_3(data.surface, data.position, data.r)
end
)
function Public.kraken_effect_3(surface, position, r)
r = r or 3
if not (surface and surface.valid) then return end
for theta=0,6.283,6.283/32 do
local p = {position.x + r*Math.sin(theta), position.y + r*Math.cos(theta)}
surface.create_entity{name = 'water-splash', position = p, color={1,1,1}}
end
local rmax = 100
if r < rmax then
Task.set_timeout_in_ticks(4, kraken_effect_3_token, {surface = surface, position = position, r = r + 2})
end
end
function Public.kraken_effect_4(surface, position)
if not (surface and surface.valid) then return end
local r = 6
for theta=0,6.283,6.283/32 do
local p = {position.x + r*Math.sin(theta), position.y + r*Math.cos(theta)}
surface.create_entity{name = 'blood-explosion-big', position = p, color={1,1,1}}
end
end
function Public.kraken_effect_5(surface, position)
if not (surface and surface.valid) then return end
local r = 6
for theta=0,6.283,6.283/32 do
local p = {position.x + r*Math.sin(theta), position.y + r*Math.cos(theta)}
surface.create_entity{name = 'blood-explosion-huge', position = p, color={1,1,1}}
end
end
return Public

View File

@@ -0,0 +1,662 @@
--this adds a button that stashes/sorts your inventory into nearby chests in some kind of intelligent way - mewmew
-- modified by gerkiz
-- modified by roc
local Global = require 'utils.global'
local Event = require 'utils.event'
local BottomFrame = require 'comfy_panel.bottom_frame'
local Common = require 'maps.pirates.common'
local floor = math.floor
local print_color = {r = 120, g = 255, b = 0}
local this = {
floating_text_y_offsets = {},
whitelist = {},
insert_into_furnace = false,
insert_into_wagon = false,
bottom_button = false,
small_radius = 2
}
local Public = {}
Global.register(
this,
function(t)
this = t
end
)
local function create_floaty_text(surface, position, name, count)
if this.floating_text_y_offsets[position.x .. '_' .. position.y] then
this.floating_text_y_offsets[position.x .. '_' .. position.y] = this.floating_text_y_offsets[position.x .. '_' .. position.y] - 0.5
else
this.floating_text_y_offsets[position.x .. '_' .. position.y] = 0
end
surface.create_entity(
{
name = 'flying-text',
position = {
position.x,
position.y + this.floating_text_y_offsets[position.x .. '_' .. position.y]
},
text = {'', '-', count, ' ', game.item_prototypes[name].localised_name},
color = {r = 255, g = 255, b = 255}
}
)
end
local function chest_is_valid(chest, inventory)
if chest.type == 'cargo-wagon' then
local t = {}
local chest_inventory = chest.get_inventory(defines.inventory.cargo_wagon)
inventory = inventory.get_contents()
for index = 1, 40 do
if chest_inventory.get_filter(index) ~= nil then
local n = chest_inventory.get_filter(index)
if inventory[n] then
if (t[n] and t[n].valid) then
t[n].count = inventory[n]
else
t[n] = {count = inventory[n], valid = true}
end
end
end
end
if not next(t) then
return false, {}
end
return true, t
end
for _, e in pairs(
chest.surface.find_entities_filtered(
{
type = {'inserter', 'loader'},
area = {{chest.position.x - 1, chest.position.y - 1}, {chest.position.x + 1, chest.position.y + 1}}
}
)
) do
if e.name ~= 'long-handed-inserter' then
if e.position.x == chest.position.x then
if e.direction == 0 or e.direction == 4 then
return false
end
end
if e.position.y == chest.position.y then
if e.direction == 2 or e.direction == 6 then
return false
end
end
end
end
local i1 = chest.surface.find_entity('long-handed-inserter', {chest.position.x - 2, chest.position.y})
if i1 then
if i1.direction == 2 or i1.direction == 6 then
return false
end
end
local i2 = chest.surface.find_entity('long-handed-inserter', {chest.position.x + 2, chest.position.y})
if i2 then
if i2.direction == 2 or i2.direction == 6 then
return false
end
end
local i3 = chest.surface.find_entity('long-handed-inserter', {chest.position.x, chest.position.y - 2})
if i3 then
if i3.direction == 0 or i3.direction == 4 then
return false
end
end
local i4 = chest.surface.find_entity('long-handed-inserter', {chest.position.x, chest.position.y + 2})
if i4 then
if i4.direction == 0 or i4.direction == 4 then
return false
end
end
return true
end
local function sort_entities_by_distance(position, entities)
local t = {}
local distance
local index
local size_of_entities = #entities
if size_of_entities < 2 then
return
end
for _, entity in pairs(entities) do
distance = (entity.position.x - position.x) ^ 2 + (entity.position.y - position.y) ^ 2
index = floor(distance) + 1
if not t[index] then
t[index] = {}
end
table.insert(t[index], entity)
end
local i = 0
for _, range in pairs(t) do
for _, entity in pairs(range) do
i = i + 1
entities[i] = entity
end
end
end
local function get_nearby_chests(player, a, furnace, wagon)
local r = player.force.character_reach_distance_bonus + 10
local r_square = r * r
local chests = {}
local size_of_chests = 0
local area = {{player.position.x - r, player.position.y - r}, {player.position.x + r, player.position.y + r}}
area = a or area
local container_type = {'container', 'logistic-container'}
local containers = {}
local i = 0
if furnace then
container_type = {'furnace'}
end
if wagon then
container_type = {'cargo-wagon'}
end
for _, e in pairs(player.surface.find_entities_filtered({type = container_type, area = area, force = player.force})) do
if e.operable == true and ((player.position.x - e.position.x) ^ 2 + (player.position.y - e.position.y) ^ 2) <= r_square then
i = i + 1
containers[i] = e
end
end
if #containers <= 0 then
if is_mod_loaded('Krastorio2') then
for _, e in pairs(player.surface.find_entities_filtered({type = 'assembling-machine', area = area, force = player.force})) do
if ((player.position.x - e.position.x) ^ 2 + (player.position.y - e.position.y) ^ 2) <= r_square then
i = i + 1
containers[i] = e
end
end
end
end
sort_entities_by_distance(player.position, containers)
for _, entity in pairs(containers) do
size_of_chests = size_of_chests + 1
chests[size_of_chests] = entity
end
return chests
end
local function does_inventory_contain_item_type(inventory, item_subgroup)
for name, _ in pairs(inventory.get_contents()) do
local t = game.item_prototypes[name]
if t and t.subgroup.name == item_subgroup then
return true
end
end
return false
end
local function insert_item_into_chest(player_inventory, chests, filtered_chests, name, count, furnace, wagon)
local container = {
['container'] = true,
['logistic-container'] = true
}
local try = 0
local to_insert = floor(count / #chests)
local variate = count % #chests
local chests_available = #chests
local tries = #chests
::retry::
--Attempt to store into furnaces.
if furnace then -- items
for _, chest in pairs(chests) do
local chest_inventory
if chest.type == 'assembling-machine' then
chest_inventory = chest.get_inventory(defines.inventory.assembling_machine_input)
else
chest_inventory = chest.get_inventory(defines.inventory.furnace_source)
end
local amount = to_insert
if variate > 0 then
amount = amount + 1
variate = variate - 1
end
if amount <= 0 then
return
end
if chest_inventory then
if (chest.type == 'furnace' or chest.type == 'assembling-machine') then
if name == 'stone' then
local valid_to_insert = (amount % 2 == 0)
if valid_to_insert then
if chest_inventory.can_insert({name = name, count = amount}) then
local inserted_count = chest_inventory.insert({name = name, count = amount})
player_inventory.remove({name = name, count = inserted_count})
create_floaty_text(chest.surface, chest.position, name, inserted_count)
count = count - inserted_count
if count <= 0 then
return
end
end
else
try = try + 1
if try <= tries then
chests_available = chests_available - 1
to_insert = floor(count / chests_available)
variate = count % chests_available
goto retry
end
end
else
if chest_inventory.can_insert({name = name, count = amount}) then
local inserted_count = chest_inventory.insert({name = name, count = amount})
player_inventory.remove({name = name, count = inserted_count})
create_floaty_text(chest.surface, chest.position, name, inserted_count)
count = count - inserted_count
if count <= 0 then
return
end
end
end
end
end
end
to_insert = floor(count / #chests)
variate = count % #chests
for _, chest in pairs(chests) do -- fuel
if chest.type == 'furnace' or chest.type == 'assembling-machine' then
local amount = to_insert
if variate > 0 then
amount = amount + 1
variate = variate - 1
end
if amount <= 0 then
return
end
local chest_inventory = chest.get_inventory(defines.inventory.chest)
if chest_inventory and chest_inventory.can_insert({name = name, count = amount}) then
local inserted_count = chest_inventory.insert({name = name, count = amount})
player_inventory.remove({name = name, count = inserted_count})
create_floaty_text(chest.surface, chest.position, name, inserted_count)
count = count - inserted_count
if count <= 0 then
return
end
end
end
end
end
-- Attempt to load filtered cargo wagon
if wagon then
for _, chest in pairs(chests) do
if chest.type == 'cargo-wagon' then
local chest_inventory = chest.get_inventory(defines.inventory.cargo_wagon)
if chest_inventory and chest_inventory.can_insert({name = name, count = count}) then
local inserted_count = chest_inventory.insert({name = name, count = count})
player_inventory.remove({name = name, count = inserted_count})
create_floaty_text(chest.surface, chest.position, name, inserted_count)
count = count - inserted_count
if count <= 0 then
return
end
end
end
end
end
--Attempt to store in chests that already have the same item.
for _, chest in pairs(chests) do
if container[chest.type] then
local chest_inventory = chest.get_inventory(defines.inventory.chest)
if chest_inventory and chest_inventory.can_insert({name = name, count = count}) then
if chest_inventory.find_item_stack(name) then
local inserted_count = chest_inventory.insert({name = name, count = count})
player_inventory.remove({name = name, count = inserted_count})
create_floaty_text(chest.surface, chest.position, name, inserted_count)
count = count - inserted_count
if count <= 0 then
return
end
end
end
end
end
--Attempt to store in empty chests.
for _, chest in pairs(filtered_chests) do
if container[chest.type] then
local chest_inventory = chest.get_inventory(defines.inventory.chest)
if chest_inventory and chest_inventory.can_insert({name = name, count = count}) then
if chest_inventory.is_empty() then
local inserted_count = chest_inventory.insert({name = name, count = count})
player_inventory.remove({name = name, count = inserted_count})
create_floaty_text(chest.surface, chest.position, name, inserted_count)
count = count - inserted_count
if count <= 0 then
return
end
end
end
end
end
--Attempt to store in chests with same item subgroup.
local item_subgroup = game.item_prototypes[name].subgroup.name
if item_subgroup then
for _, chest in pairs(filtered_chests) do
if container[chest.type] then
local chest_inventory = chest.get_inventory(defines.inventory.chest)
if chest_inventory and chest_inventory.can_insert({name = name, count = count}) then
if does_inventory_contain_item_type(chest_inventory, item_subgroup) then
local inserted_count = chest_inventory.insert({name = name, count = count})
player_inventory.remove({name = name, count = inserted_count})
create_floaty_text(chest.surface, chest.position, name, inserted_count)
count = count - inserted_count
if count <= 0 then
return
end
end
end
end
end
end
--Attempt to store in mixed chests.
for _, chest in pairs(filtered_chests) do
if container[chest.type] then
local chest_inventory = chest.get_inventory(defines.inventory.chest)
if chest_inventory.can_insert({name = name, count = count}) then
local inserted_count = chest_inventory.insert({name = name, count = count})
player_inventory.remove({name = name, count = inserted_count})
create_floaty_text(chest.surface, chest.position, name, inserted_count)
count = count - inserted_count
if count <= 0 then
return
end
end
end
end
end
local priority = {
['coal'] = 1,
['iron-ore'] = 2,
['copper-ore'] = 3,
['stone'] = 4
}
local function switch_key_val(tbl)
local t = {}
for name, count in pairs(tbl) do
if priority[name] then
t[#t + 1] = {name = name, count = count, priority = priority[name]}
else
t[#t + 1] = {name = name, count = count}
end
end
table.sort(
t,
function(a, b)
if a.priority and b.priority then
return a.priority > b.priority
end
end
)
return t
end
local function auto_stash(player, event)
local button = event.button
local ctrl = event.control
local shift = event.shift
if not player.character then
Common.notify_player(player, 'It seems that you are not in the realm of the living.', print_color)
return
end
if not player.character.valid then
Common.notify_player(player, 'It seems that you are not in the realm of the living.', print_color)
return
end
local inventory = player.get_inventory(defines.inventory.character_main)
if inventory.is_empty() then
Common.notify_player(player, 'Inventory is empty.', print_color)
return
end
local chests
local r = this.small_radius
local area = {{player.position.x - r, player.position.y - r}, {player.position.x + r, player.position.y + r}}
if ctrl then
if button == defines.mouse_button_type.right and this.insert_into_furnace then
chests = get_nearby_chests(player, nil, true, false)
end
elseif shift then
if button == defines.mouse_button_type.right and this.insert_into_wagon or button == defines.mouse_button_type.left and this.insert_into_wagon then
chests = get_nearby_chests(player, area, false, true)
end
else
chests = get_nearby_chests(player)
end
if not chests or not chests[1] then
Common.notify_player(player, 'No valid nearby containers found.', print_color)
return
end
local filtered_chests = {}
local filtered_allowed
for _, e in pairs(chests) do
local is_valid, t = chest_is_valid(e, inventory)
filtered_allowed = t
if is_valid then
filtered_chests[#filtered_chests + 1] = e
end
end
this.floating_text_y_offsets = {}
local hotbar_items = {}
for i = 1, 100, 1 do
local prototype = player.get_quick_bar_slot(i)
if prototype then
hotbar_items[prototype.name] = true
end
end
local getIndexInventory = switch_key_val(inventory.get_contents())
for i = #getIndexInventory, 1, -1 do
local name = getIndexInventory[i].name
local count = getIndexInventory[i].count
local is_resource = this.whitelist[name]
if not inventory.find_item_stack(name).grid and not hotbar_items[name] then
if ctrl and this.insert_into_furnace then
if button == defines.mouse_button_type.right then
if is_resource then
insert_item_into_chest(inventory, chests, filtered_chests, name, count, true, false)
end
end
elseif shift and this.insert_into_wagon then
if button == defines.mouse_button_type.right then
if is_resource then
insert_item_into_chest(inventory, chests, filtered_chests, name, count, false, true)
end
end
if button == defines.mouse_button_type.left then
if filtered_allowed and filtered_allowed[name] and filtered_allowed[name].valid then
local c = filtered_allowed[name].count
insert_item_into_chest(inventory, chests, filtered_chests, name, c, false, true)
end
end
elseif button == defines.mouse_button_type.right then
if is_resource then
insert_item_into_chest(inventory, chests, filtered_chests, name, count)
end
elseif button == defines.mouse_button_type.left then
insert_item_into_chest(inventory, chests, filtered_chests, name, count)
end
end
end
local c = this.floating_text_y_offsets
for k, _ in pairs(c) do
this.floating_text_y_offsets[k] = nil
end
end
local function create_gui_button(player)
if player.gui.top.auto_stash then
return
end
local tooltip
if this.insert_into_furnace and this.insert_into_wagon then
tooltip =
'Sort your inventory into nearby chests.\nLMB: Everything, excluding quickbar items.\nRMB: Only ores to nearby chests, excluding quickbar items.\nCTRL+RMB: Fill nearby furnaces.\nSHIFT+LMB: Everything onto filtered slots to wagon.\nSHIFT+RMB: Only ores to wagon'
elseif this.insert_into_furnace then
tooltip =
'Sort your inventory into nearby chests.\nLMB: Everything, excluding quickbar items.\nRMB: Only ores to nearby chests, excluding quickbar items.\nCTRL+RMB: Fill nearby furnaces.'
elseif this.insert_into_wagon then
tooltip =
'Sort your inventory into nearby chests.\nLMB: Everything, excluding quickbar items.\nRMB: Only ores to nearby chests, excluding quickbar items.\nSHIFT+LMB: Everything onto filtered slots to wagon.\nSHIFT+RMB: Only ores to wagon'
else
tooltip = 'Sort your inventory into nearby chests.\nLMB: Everything, excluding quickbar items.\nRMB: Only ores to nearby chests, excluding quickbar items.'
end
if this.bottom_button then
local data = BottomFrame.get('bottom_quickbar_button')
-- save it for later use
data.tooltip = tooltip
data.sprite = 'item/wooden-chest'
if data[player.index] then
data = data[player.index]
if data.frame and data.frame.valid then
data.frame.sprite = 'item/wooden-chest'
data.frame.tooltip = tooltip
end
end
else
local b =
player.gui.top.add(
{
type = 'sprite-button',
sprite = 'item/wooden-chest',
name = 'auto_stash',
tooltip = tooltip
}
)
b.style.font_color = {r = 0.11, g = 0.8, b = 0.44}
b.style.font = 'heading-1'
b.style.minimal_height = 40
b.style.maximal_width = 40
b.style.minimal_width = 38
b.style.maximal_height = 38
b.style.padding = 1
b.style.margin = 0
end
end
local function do_whitelist()
local resources = game.entity_prototypes
local items = game.item_prototypes
this.whitelist = {}
for k, _ in pairs(resources) do
if resources[k] and resources[k].type == 'resource' and resources[k].mineable_properties then
if resources[k].mineable_properties.products[1] then
local r = resources[k].mineable_properties.products[1].name
this.whitelist[r] = true
elseif resources[k].mineable_properties.products[2] then
local r = resources[k].mineable_properties.products[2].name
this.whitelist[r] = true
end
end
end
for k, _ in pairs(items) do
if items[k] and items[k].group.name == 'resource-refining' then
local r = items[k].name
this.whitelist[r] = true
end
end
end
local function on_player_joined_game(event)
if is_loaded('maps.biter_battles_v2.main') then
return
end
create_gui_button(game.players[event.player_index])
end
local function on_gui_click(event)
if not event.element then
return
end
if not event.element.valid then
return
end
local player = game.players[event.player_index]
local name = 'auto_stash'
if this.bottom_button then
local data = BottomFrame.get('bottom_quickbar_button')
if data[player.index] then
data = data[player.index]
name = data.name
end
end
if event.element.name == name then
auto_stash(player, event)
end
end
function Public.insert_into_furnace(value)
if value then
this.insert_into_furnace = value
else
this.insert_into_furnace = false
end
end
function Public.insert_into_wagon(value)
if value then
this.insert_into_wagon = value
else
this.insert_into_wagon = false
end
end
function Public.bottom_button(value)
if value then
this.bottom_button = value
else
this.bottom_button = false
end
end
Event.on_configuration_changed(do_whitelist)
Event.on_init(do_whitelist)
Event.add(defines.events.on_player_joined_game, on_player_joined_game)
Event.add(defines.events.on_gui_click, on_gui_click)
return Public

377
maps/pirates/gui/common.lua Normal file
View File

@@ -0,0 +1,377 @@
local Memory = require 'maps.pirates.memory'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local inspect = require 'utils.inspect'.inspect
local Crew = require 'maps.pirates.crew'
local Progression = require 'maps.pirates.progression'
local Structures = require 'maps.pirates.structures.structures'
local Shop = require 'maps.pirates.shop.shop'
local memory = require 'maps.pirates.memory'
local Public = {}
Public.bold_font_color = {255, 230, 192}
Public.default_font_color = {1, 1, 1}
Public.section_header_font_color = {r=0.40, g=0.80, b=0.60}
Public.subsection_header_font_color = {229, 255, 242}
Public.friendly_font_color = {240, 200, 255}
Public.sufficient_font_color = {66, 220, 124}
Public.insufficient_font_color = {1, 0.62, 0.19}
Public.achieved_font_color = {255, 230, 192}
Public.rage_font_color_1 = {1, 1, 1}
Public.rage_font_color_2 = {1, 0.5, 0.1}
Public.rage_font_color_3 = {1, 0.1, 0.05}
Public.default_window_positions = {
runs = {x = 10, y = 48},
crew = {x = 40, y = 48},
progress = {x = 250, y = 48},
shop = {x = 468, y = 48},
minimap = {x = 10, y = 48},
}
function Public.new_window(player, name)
local global_memory = Memory.get_global_memory()
local gui_memory = global_memory.player_gui_memories[player.index]
local flow, flow2, flow3, flow4
flow = player.gui.screen.add{
type = 'frame',
name = name .. '_piratewindow',
direction = 'vertical'
}
if gui_memory and gui_memory[name] and gui_memory[name].position then
flow.location = gui_memory[name].position
else
flow.location = Public.default_window_positions[name]
end
flow.style = 'map_details_frame'
flow.style.minimal_width = 210
flow.style.natural_width = 210
flow.style.maximal_width = 270
flow.style.minimal_height = 80
flow.style.natural_height = 80
flow.style.maximal_height = 680
flow.style.padding = 10
return flow
end
function Public.update_gui_memory(player, namespace, key, value)
local global_memory = Memory.get_global_memory()
if not global_memory.player_gui_memories[player.index] then
global_memory.player_gui_memories[player.index] = {}
end
local gui_memory = global_memory.player_gui_memories[player.index]
if not gui_memory[namespace] then
gui_memory[namespace] = {}
end
gui_memory[namespace][key] = value
end
function Public.flow_add_floating_sprite_button(flow1, button_name, width)
width = width or 40
local flow2, flow3
flow2 = flow1.add({
name = button_name .. '_frame',
type = 'frame',
})
flow2.style.height = 40
flow2.style.margin = 0
flow2.style.padding = -3
flow2.style.width = width
flow3 = flow2.add({
name = button_name,
type = 'sprite-button',
})
flow3.style.height = 40
flow3.style.width = width
-- flow3.style.padding = -4
return flow3
end
function Public.flow_add_shop_item(flow, name)
local flow2, flow3, flow4
local shop_data_1 = Shop.main_shop_data_1
local shop_data_2 = Shop.main_shop_data_2
local trade_data = shop_data_1[name] or shop_data_2[name]
if not trade_data then return end
flow2 = flow.add({
name = name,
type = 'flow',
direction = 'horizontal',
})
flow2.style.top_margin = 3
flow2.style.horizontal_align = 'center'
flow2.style.vertical_align = 'center'
flow2.tooltip = trade_data.tooltip
for k, v in pairs(trade_data.what_you_get_sprite_buttons) do
flow3 = flow2.add({
type = 'sprite-button',
name = k,
sprite = k,
enabled = false,
})
flow3.style.minimal_height = 40
flow3.style.maximal_height = 40
if v == false then
flow3.number = nil
else
flow3.number = v
end
flow3.tooltip = trade_data.tooltip
end
flow3 = flow2.add({
type = 'label',
name = 'for',
caption = 'for'
})
flow3.style.font = 'default-large'
flow3.style.font_color = Public.default_font_color
flow3.tooltip = trade_data.tooltip
for k, v in pairs(trade_data.base_cost) do
flow3 = flow2.add({
name = 'cost_' .. k,
type = 'sprite-button',
enabled = false,
})
flow3.style.minimal_height = 40
flow3.style.maximal_height = 40
flow3.tooltip = trade_data.tooltip
if k == 'gold' then
flow3.sprite = 'item/sulfur'
elseif k == 'iron_plates' then
flow3.sprite = 'item/iron-plate'
elseif k == 'copper_plates' then
flow3.sprite = 'item/copper-plate'
end
end
flow3 = flow2.add({
name = 'spacing',
type = 'flow',
direction = 'horizontal',
})
flow3.style.horizontally_stretchable = true
flow3 = flow2.add({
type = 'sprite-button',
name = 'buy_button',
caption = 'Buy'
})
flow3.style.font = 'default-large'
flow3.style.font_color = Public.default_font_color
flow3.style.height = 32
flow3.style.width = 50
flow3.style.padding = 0
flow3.style.margin = 0
return flow2
end
function Public.flow_add_section(flow, name, caption)
local flow2, flow3
flow2 = flow.add({
name = name,
type = 'flow',
direction = 'vertical',
})
flow2.style.bottom_margin = 5
flow3 = flow2.add({
type = 'label',
name = 'header',
caption = caption
})
flow3.style.font = 'heading-2'
flow3.style.font_color = Public.section_header_font_color
flow3.style.maximal_width = 300
-- flow3.style.maximal_width = 220
-- flow3.style.single_line = false
flow3 = flow2.add({
name = 'body',
type = 'flow',
direction = 'vertical',
})
flow3.style.left_margin = 5
return flow3
end
function Public.flow_add_subpanel(flow, name)
local flow2
flow2 = flow.add({
name = name,
type = 'frame',
direction = 'vertical',
})
flow2.style = 'subpanel_frame'
flow2.style.natural_width = 100
flow2.style.top_padding = -2
flow2.style.top_margin = -8
return flow2
end
function Public.flow_add_close_button(flow, close_button_name)
local flow2, flow3, flow4
flow2 = flow.add({
name = 'close_button_flow',
type = 'flow',
direction = 'vertical',
})
flow2.style.top_margin = -3
flow2.style.bottom_margin = -3
flow3 = flow2.add{type="flow", name='hflow', direction="horizontal"}
flow3.style.vertical_align = 'center'
flow4 = flow3.add{type="flow", name='spacing', direction="horizontal"}
flow4.style.horizontally_stretchable = true
flow4 = flow3.add({
type = 'button',
name = close_button_name,
caption = 'Close',
})
flow4.style = 'back_button'
flow4.style.minimal_width = 90
flow4.style.font = 'default-bold'
flow4.style.height = 28
flow4.style.horizontal_align = 'center'
return flow3
end
function Public.playercrew_status_table(player_index)
local global_memory = Memory.get_global_memory()
local memory = Memory.get_crew_memory()
--*** PLAYER STATUS ***--
local ret = {
adventuring = false,
spectating = false,
endorsing = false,
proposing = false,
sloops_full = false,
needs_more_capacity = false,
needs_more_endorsers = false,
leaving = false,
}
if memory.crewstatus == Crew.enum.ADVENTURING then
for _, playerindex in pairs(memory.crewplayerindices) do
if player_index == playerindex then ret.adventuring = true end
end
for _, playerindex in pairs(memory.spectatorplayerindices) do
if player_index == playerindex then ret.spectating = true end
end
end
if memory.crewstatus == nil then
for _, crewid in pairs(global_memory.crew_active_ids) do
if global_memory.crew_memories[crewid].crewstatus == Crew.enum.LEAVING_INITIAL_DOCK then
for _, endorser_index in pairs(global_memory.crew_memories[crewid].original_proposal.endorserindices) do
if endorser_index == player_index then ret.leaving = true end
end
end
end
for _, proposal in pairs(global_memory.crewproposals) do
if #proposal.endorserindices > 0 and proposal.endorserindices[1] == player_index then
ret.proposing = true
if #global_memory.crew_active_ids >= 3 then
ret.sloops_full = true
else
if global_memory.active_crews_cap > 1 and #global_memory.crew_active_ids == (global_memory.active_crews_cap - 1) and not ((global_memory.crew_memories[1] and global_memory.crew_memories[1].capacity >= 16) or (global_memory.crew_memories[2] and global_memory.crew_memories[2].capacity >= 16) or (global_memory.crew_memories[3] and global_memory.crew_memories[3].capacity >= 16)) and not (CoreData.capacity_options[proposal.capacity_option].value >= 16) then
ret.needs_more_capacity = true
else
if proposal.endorserindices and #global_memory.crew_active_ids > 0 and #proposal.endorserindices < Math.min(4, Math.ceil((#game.connected_players or 0)/5)) then
ret.needs_more_endorsers = true
end
end
end
end
for _, i in pairs(proposal.endorserindices) do
if player_index == i then ret.endorsing = true end
end
end
end
return ret
end
function Public.update_listbox(listbox, table)
-- pass a table of strings of the form {'locale', unique_id, ...}
-- remove any that shouldn't be there
local marked_for_removal = {}
for index, item in pairs(listbox.items) do
local exists = false
for _, i in pairs(table) do
if tostring(i[2]) == item[2] then
exists = true
end
end
if exists == false then
marked_for_removal[#marked_for_removal + 1] = index
end
end
for i = #marked_for_removal, 1, -1 do
listbox.remove_item(marked_for_removal[i])
end
local indexalreadyat
for _, i in pairs(table) do
local contained = false
for index, item in pairs(listbox.items) do
if tostring(i[2]) == item[2] then
contained = true
indexalreadyat = index
end
end
if contained then
listbox.set_item(indexalreadyat, i)
else
listbox.add_item(i)
end
end
end
return Public

530
maps/pirates/gui/crew.lua Normal file
View File

@@ -0,0 +1,530 @@
local Memory = require 'maps.pirates.memory'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Roles = require 'maps.pirates.roles.roles'
local Classes = require 'maps.pirates.roles.classes'
local Crew = require 'maps.pirates.crew'
local Progression = require 'maps.pirates.progression'
local Structures = require 'maps.pirates.structures.structures'
local inspect = require 'utils.inspect'.inspect
local Boats = require 'maps.pirates.structures.boats.boats'
local GuiCommon = require 'maps.pirates.gui.common'
local CoreData = require 'maps.pirates.coredata'
local Server = require 'utils.server'
local Public = {}
local window_name = 'crew'
function Public.toggle_window(player)
local memory = Memory.get_crew_memory()
local flow, flow2, flow3, flow4, flow5, flow6
--*** OVERALL FLOW ***--
if player.gui.screen[window_name .. '_piratewindow'] then player.gui.screen[window_name .. '_piratewindow'].destroy() return end
if not memory.id then return end
flow = GuiCommon.new_window(player, window_name)
flow.caption = 'Crew'
--*** RUN AGE ***--
flow2 = flow.add({
name = 'crew_age',
type = 'label',
})
flow2.style.left_margin = 5
flow2.style.top_margin = 0
flow2.style.bottom_margin = -3
flow2.style.single_line = true
flow2.style.maximal_width = 200
flow2.style.font = 'default'
--*** RUN DIFFICULTY ***--
flow2 = flow.add({
name = 'crew_difficulty',
type = 'label',
})
flow2.style.left_margin = 5
flow2.style.top_margin = -3
flow2.style.bottom_margin = 0
flow2.style.single_line = false
flow2.style.maximal_width = 190
flow2.style.font = 'default'
--*** MEMBERSHIP BUTTONS ***--
flow2 = flow.add({
name = 'membership_buttons',
type = 'flow',
direction = 'horizontal',
})
flow3 = flow2.add({
name = 'leave_crew',
type = 'button',
caption = 'Quit Crew',
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
flow3 = flow2.add({
name = 'leave_spectators',
type = 'button',
caption = 'Return to Lobby',
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
flow3 = flow2.add({
name = 'spectator_join_crew',
type = 'button',
caption = 'Join Crew',
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
flow3 = flow2.add({
name = 'crewmember_join_spectators',
type = 'button',
caption = 'Spectate',
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
--*** MEMBERS AND SPECTATORS ***--
flow2 = GuiCommon.flow_add_section(flow, 'members', 'Crew Members')
flow3 = flow2.add({
name = 'members_listbox',
type = 'list-box',
})
flow3.style.margin = 2
flow3.style.maximal_height = 400
flow3 = flow2.add({
name = 'class_renounce',
type = 'button',
caption = 'Renounce Class',
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
flow2 = GuiCommon.flow_add_section(flow, 'spectators', 'Spectators')
flow3 = flow2.add({
name = 'spectators_listbox',
type = 'list-box',
})
flow3.style.margin = 2
flow3.style.maximal_height = 150
--*** DIFFICULTY VOTE ***--
flow2 = GuiCommon.flow_add_section(flow, 'difficulty_vote', 'Vote for Difficulty')
for i, o in ipairs(CoreData.difficulty_options) do
flow3 = flow2.add({
name = 'difficulty_option_' .. i,
type = 'button',
caption = o.text,
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
end
--*** SPARE CLASSES ***--
flow2 = GuiCommon.flow_add_section(flow, 'spare_classes', 'Spare Classes')
flow3 = flow2.add({
name = 'list',
type = 'label',
})
flow3.style.left_margin = 5
flow3.style.top_margin = -3
flow3.style.bottom_margin = -3
flow3.style.single_line = false
flow3.style.maximal_width = 160
flow3.style.font = 'default-dropdown'
flow3 = flow2.add({
name = 'assign_flow',
type = 'flow',
direction = 'vertical',
})
flow3.style.top_margin = 3
for _, c in ipairs(Classes.Class_List) do
flow4 = flow3.add({
name = 'assign_class_' .. c,
type = 'button',
caption = 'Give class: ' .. Classes.display_form[c],
})
flow4.style.minimal_width = 95
flow4.style.font = 'default-bold'
flow4.style.font_color = {r=0.10, g=0.10, b=0.10}
end
for _, c in ipairs(Classes.Class_List) do
flow4 = flow3.add({
name = 'selfassign_class_' .. c,
type = 'button',
caption = 'Take class: ' .. Classes.display_form[c],
})
flow4.style.minimal_width = 95
flow4.style.font = 'default-bold'
flow4.style.font_color = {r=0.10, g=0.10, b=0.10}
end
--*** CAPTAIN's ACTIONS ***--
flow2 = GuiCommon.flow_add_section(flow, 'captain', 'Captain\'s Actions')
flow3 = flow2.add({
name = 'capn_disband_crew',
type = 'button',
caption = 'Disband Crew',
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
flow3 = flow2.add({
name = 'capn_disband_are_you_sure',
type = 'button',
caption = 'Are you sure?',
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
flow3 = flow2.add({
name = 'capn_renounce',
type = 'button',
caption = 'Renounce Captainhood',
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
flow3 = flow2.add({
name = 'capn_pass',
type = 'button',
caption = 'Pass Title To',
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
flow3 = flow2.add({
name = 'capn_plank',
type = 'button',
caption = 'Plank (Make Spectator)',
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
flow3 = flow2.add({
name = 'line',
type = 'line',
})
flow3.style.width = 50
flow3.style.left_margin = 20
flow3.style.top_margin = 4
flow3.style.bottom_margin = 4
flow3 = flow2.add({
name = 'capn_undock_normal',
type = 'button',
caption = 'Undock Boat',
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
flow3 = flow2.add({
name = 'capn_summon_crew',
type = 'button',
caption = 'Summon Crew to Ship',
})
flow3.style.minimal_width = 95
flow3.style.font = 'default-bold'
flow3.style.font_color = {r=0.10, g=0.10, b=0.10}
--
GuiCommon.flow_add_close_button(flow, window_name .. '_piratebutton')
end
function Public.update(player)
if not player.gui.screen[window_name .. '_piratewindow'] then return end
local flow = player.gui.screen[window_name .. '_piratewindow']
local memory = Memory.get_crew_memory()
local playercrew_status = GuiCommon.playercrew_status_table(player.index)
local destination = Common.current_destination()
--*** WHAT TO SHOW ***--
flow.difficulty_vote.visible = memory.overworldx and memory.overworldx == 0
flow.members.body.class_renounce.visible = memory.classes_table and memory.classes_table[player.index]
flow.spare_classes.visible = memory.spare_classes and #memory.spare_classes > 0
local any_button = false
for _, c in pairs(Classes.Class_List) do
if memory.spare_classes and Utils.contains(memory.spare_classes, c) and (not (player.controller_type == defines.controllers.spectator)) then
if (memory.playerindex_captain and player.index == memory.playerindex_captain) and memory.crewplayerindices and #memory.crewplayerindices > 1 then
if flow.members.body.members_listbox.selected_index ~= 0 and (not (memory.classes_table[tonumber(flow.members.body.members_listbox.get_item(flow.members.body.members_listbox.selected_index)[2])])) then
flow.spare_classes.body.assign_flow['assign_class_' .. c].visible = true
any_button = true
else
flow.spare_classes.body.assign_flow['assign_class_' .. c].visible = false
end
else
flow.spare_classes.body.assign_flow['assign_class_' .. c].visible = false
if (not memory.classes_table[player.index]) then
flow.spare_classes.body.assign_flow['selfassign_class_' .. c].visible = true
any_button = true
else
flow.spare_classes.body.assign_flow['selfassign_class_' .. c].visible = false
end
end
else
flow.spare_classes.body.assign_flow['assign_class_' .. c].visible = false
flow.spare_classes.body.assign_flow['selfassign_class_' .. c].visible = false
end
end
flow.spare_classes.body.assign_flow.visible = any_button
flow.captain.visible = (memory.playerindex_captain and player.index == memory.playerindex_captain)
flow.captain.body.capn_pass.visible = flow.members.body.members_listbox.selected_index ~= 0 and tonumber(flow.members.body.members_listbox.get_item(flow.members.body.members_listbox.selected_index)[2]) ~= player.index
flow.captain.body.capn_plank.visible = flow.captain.body.capn_pass.visible
flow.captain.body.capn_undock_normal.visible = memory.boat and memory.boat.state and ((memory.boat.state == Boats.enum_state.LANDED) or (memory.boat.state == Boats.enum_state.APPROACHING) or (memory.boat.state == Boats.enum_state.DOCKED))
flow.captain.body.capn_summon_crew.visible = false
-- flow.captain.body.capn_summon_crew.visible = memory.boat and memory.boat.state and (memory.boat.state == Boats.enum_state.RETREATING or memory.boat.state == Boats.enum_state.LEAVING_DOCK)
flow.captain.body.capn_disband_are_you_sure.visible = memory.disband_are_you_sure_ticks and memory.disband_are_you_sure_ticks[player.index] and memory.disband_are_you_sure_ticks[player.index] > game.tick - 60*2
flow.captain.body.capn_disband_crew.visible = not flow.captain.body.capn_disband_are_you_sure.visible
flow.members.visible = true
flow.spectators.visible = (#memory.spectatorplayerindices > 0)
-- flow.crew_age.visible = true
-- -- flow.crew_age.visible = memory.mode and memory.mode == 'speedrun'
-- flow.crew_difficulty.visible = true
local count = 0
if playercrew_status.spectating then
for _, v in pairs(memory.crewplayerindices) do
if Common.validate_player(game.players[v]) then count = count + 1 end
end
end
flow.membership_buttons.spectator_join_crew.visible = playercrew_status.spectating and (not (count >= memory.capacity))
flow.membership_buttons.leave_crew.visible = playercrew_status.adventuring
flow.membership_buttons.crewmember_join_spectators.visible = playercrew_status.adventuring
flow.membership_buttons.leave_spectators.visible = playercrew_status.spectating
flow.membership_buttons.spectator_join_crew.visible = flow.membership_buttons.spectator_join_crew.visible and (not (memory.tempbanned_from_joining_data[player.index] and game.tick < memory.tempbanned_from_joining_data[player.index] + Common.ban_from_rejoining_crew_ticks))
--== UPDATE CONTENT ==--
if memory.id then
flow.caption = memory.name
flow.crew_age.caption = 'Age: ' .. Utils.time_mediumform((memory.age or 0)/60)
flow.crew_difficulty.caption = 'Difficulty: ' .. CoreData.difficulty_options[memory.difficulty_option].text
if flow.spare_classes.visible then
local str = ''
for i, c in ipairs(memory.spare_classes) do
if i>1 then str = str .. ', ' end
str = str .. Classes.display_form[c]
end
str = str .. '.'
flow.spare_classes.body.list.caption = str
end
end
if flow.members.visible then
local wrappedcrew = {}
for _, index in pairs(memory.crewplayerindices) do
local player2 = game.players[index]
local tag_text = Roles.tag_text(player2)
wrappedcrew[#wrappedcrew + 1] = {'pirates.crewmember_displayform', index, player2.color.r, player2.color.g, player2.color.b, player2.name, tag_text}
end
GuiCommon.update_listbox(flow.members.body.members_listbox, wrappedcrew)
flow.members.header.caption = 'Crew Members (' .. (#memory.crewplayerindices or 0) .. ')'
end
if flow.spectators.visible then
local wrappedspectators = {}
for _, index in pairs(memory.spectatorplayerindices) do
local player2 = game.players[index]
wrappedspectators[#wrappedspectators + 1] = {'pirates.crewmember_displayform', index, player2.color.r, player2.color.g, player2.color.b, player2.name, ''}
end
GuiCommon.update_listbox(flow.spectators.body.spectators_listbox, wrappedspectators)
end
if flow.captain.body.capn_undock_normal.visible then
flow.captain.body.capn_undock_normal.enabled = (memory.boat.state == Boats.enum_state.LANDED) and Common.query_sufficient_resources_to_leave()
end
end
function Public.click(event)
local player = game.players[event.element.player_index]
local eventname = event.element.name
if not player.gui.screen[window_name .. '_piratewindow'] then return end
local flow = player.gui.screen[window_name .. '_piratewindow']
local memory = Memory.get_crew_memory()
if eventname == 'crewmember_join_spectators' then
Crew.join_spectators(player, memory.id)
return
end
if eventname == 'leave_spectators' then
Crew.leave_spectators(player)
return
end
if eventname == 'spectator_join_crew' then
Crew.join_crew(player, memory.id)
return
end
if eventname == 'leave_crew' then
Crew.leave_crew(player)
return
end
if string.sub(eventname, 1, 13) and string.sub(eventname, 1, 13) == 'assign_class_' then
local other_id = tonumber(flow.members.body.members_listbox.get_item(flow.members.body.members_listbox.selected_index)[2])
Roles.assign_class(other_id, tonumber(string.sub(eventname, 14, -1)))
return
end
if string.sub(eventname, 1, 17) and string.sub(eventname, 1, 17) == 'selfassign_class_' then
Roles.assign_class(player.index, tonumber(string.sub(eventname, 18, -1)), true)
return
end
if string.sub(eventname, 1, 18) and string.sub(eventname, 1, 18) == 'difficulty_option_' then
Crew.difficulty_vote(player.index, tonumber(string.sub(eventname, 19, -1)))
return
end
if eventname == 'capn_undock_normal' then
--double check:
if (memory.playerindex_captain and player.index == memory.playerindex_captain) then
if memory.boat.state == Boats.enum_state.DOCKED then
Progression.undock_from_dock()
else
Progression.try_retreat_from_island()
end
end
return
end
if eventname == 'capn_summon_crew' then
--double check:
if (memory.playerindex_captain and player.index == memory.playerindex_captain) then
Crew.summon_crew()
end
return
end
if eventname == 'class_renounce' then
Roles.try_renounce_class(player)
return
end
if eventname == 'capn_renounce' then
Roles.renounce_captainhood(player)
return
end
if eventname == 'capn_disband_crew' then
--double check:
if (memory.playerindex_captain and player.index == memory.playerindex_captain) then
if not memory.disband_are_you_sure_ticks then memory.disband_are_you_sure_ticks = {} end
memory.disband_are_you_sure_ticks[player.index] = game.tick
end
return
end
if eventname == 'capn_disband_are_you_sure' then
--double check:
if (memory.playerindex_captain and player.index == memory.playerindex_captain) then
local force = game.forces[memory.force_name]
if force and force.valid then
local message = player.name .. ' disbanded ' .. memory.name .. ', after ' .. Utils.time_longform((memory.real_age or 0)/60) .. '.'
Common.notify_game(message)
Server.to_discord_embed_raw(CoreData.comfy_emojis.trashbin .. '[' .. memory.name .. '] ' .. message)
end
Crew.disband_crew(true)
end
return
end
if eventname == 'capn_pass' then
local other_id = tonumber(flow.members.body.members_listbox.get_item(flow.members.body.members_listbox.selected_index)[2])
Roles.pass_captainhood(player, game.players[other_id])
return
end
if eventname == 'capn_plank' then
local other_id = tonumber(flow.members.body.members_listbox.get_item(flow.members.body.members_listbox.selected_index)[2])
Common.notify_force(player.force, string.format("%s has planked %s!", player.name, game.players[other_id].name))
Crew.join_spectators(game.players[other_id], memory.id)
memory.tempbanned_from_joining_data[other_id] = game.tick + 60 * 120
return
end
end
return Public

113
maps/pirates/gui/evo.lua Normal file
View File

@@ -0,0 +1,113 @@
local Common = require 'maps.pirates.common'
local Balance = require 'maps.pirates.balance'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local inspect = require 'utils.inspect'.inspect
local Boats = require 'maps.pirates.structures.boats.boats'
local Memory = require 'maps.pirates.memory'
local Kraken = require 'maps.pirates.surfaces.sea.kraken'
local Public = {}
local GuiCommon = require 'maps.pirates.gui.common'
-- local button_sprites = {
-- ['small-biter'] = 0,
-- ['medium-biter'] = 0.2,
-- ['small-spitter'] = 0.25,
-- ['medium-spitter'] = 0.4,
-- ['big-spitter'] = 0.5,
-- ['big-biter'] = 0.501,
-- ['behemoth-spitter'] = 0.9,
-- ['behemoth-biter'] = 0.901
-- }
local function get_evolution_percentage()
local memory = Memory.get_crew_memory()
if (not memory.enemy_force_name) then return 0 end
local value = Math.floor(game.forces[memory.enemy_force_name].evolution_factor * 1000) * 0.001
-- if value < 0.001 then
-- -- 0.00 won't be shown on the button as value
-- return 0.001
-- end
return value
end
-- local function get_alien_name(evolution_factor)
-- local last_match = 'fish'
-- for name, alien_threshold in pairs(button_sprites) do
-- if evolution_factor == alien_threshold then
-- return name
-- end
-- -- next alien evolution_factor isn't reached
-- if alien_threshold > evolution_factor then
-- return last_match
-- end
-- -- surpassed this alien evolution_factor
-- if alien_threshold < evolution_factor then
-- last_match = name
-- end
-- end
-- return last_match
-- end
function Public.update(player)
local memory = Memory.get_crew_memory()
local pirates_flow = player.gui.top
local button = pirates_flow.evo_piratebutton_frame.evo_piratebutton
if button and button.valid then
local evolution_factor = get_evolution_percentage()
local evo = evolution_factor
-- local current_alien = get_alien_name(evolution_factor)
-- local sprite = 'entity/' .. current_alien
-- if evolution_factor == 0 or (memory.boat and (memory.boat.state == Boats.enum_state.ATSEA_SAILING or memory.boat.state == Boats.enum_state.ATSEA_LOADING_MAP)) then
-- button.number = 0
-- button.tooltip = 'Local biter evolution\n\n0'
-- else
local destination = Common.current_destination()
local evolution_base
local evolution_time
local evolution_silo
local evolution_nests
if memory.boat and memory.boat.state and (memory.boat.state == Boats.enum_state.ATSEA_SAILING or memory.boat.state == Boats.enum_state.ATSEA_LOADING_MAP) then
evolution_base = evo
-- here Kraken.kraken_slots
local krakens = false
if memory.active_sea_enemies and memory.active_sea_enemies.krakens then
for i = 1, Kraken.kraken_slots do
if memory.active_sea_enemies.krakens[i] then krakens = true break end
end
end
if krakens then --@FIXME: somehow this isn't triggering?
button.tooltip = string.format('Local biter evolution\n\nBase: %.2f\nKraken: %.2f\nTotal: %.2f', evolution_base, Balance.kraken_spawns_base_extra_evo, Balance.kraken_spawns_base_extra_evo + evo)
button.number = Balance.kraken_spawns_base_extra_evo + evo
else
button.tooltip = string.format('Local biter evolution\n\nBase: %.2f\nTotal: %.2f', evolution_base, evo)
button.number = evo
end
else
evolution_base = (destination and destination.dynamic_data and destination.dynamic_data.evolution_accrued_leagues) or 0
evolution_time = (destination and destination.dynamic_data and destination.dynamic_data.evolution_accrued_time) or 0
evolution_nests = (destination and destination.dynamic_data and destination.dynamic_data.evolution_accrued_nests) or 0
evolution_silo = (destination and destination.dynamic_data and destination.dynamic_data.evolution_accrued_silo) or 0
button.tooltip = string.format('Local biter evolution\n\nLeagues: %.2f\nTime: %.2f\nNests: %.2f\nSilo: %.2f\nTotal: %.2f', evolution_base, evolution_time, evolution_nests, evolution_silo, evo)
button.number = evo
end
-- end
-- if sprite then
-- button.sprite = spritem
-- end
end
end
return Public

904
maps/pirates/gui/gui.lua Normal file
View File

@@ -0,0 +1,904 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local GuiEvo = require 'maps.pirates.gui.evo'
local GuiProgress = require 'maps.pirates.gui.progress'
local GuiRuns = require 'maps.pirates.gui.runs'
local GuiCrew = require 'maps.pirates.gui.crew'
local GuiShop = require 'maps.pirates.gui.shop'
local GuiMinimap = require 'maps.pirates.gui.minimap'
local GuiInfo = require 'maps.pirates.gui.info'
local Quest = require 'maps.pirates.quest'
local Balance = require 'maps.pirates.balance'
local inspect = require 'utils.inspect'.inspect
local GuiCommon = require 'maps.pirates.gui.common'
local Boats = require 'maps.pirates.structures.boats.boats'
local Hold = require 'maps.pirates.surfaces.hold'
local Cabin = require 'maps.pirates.surfaces.cabin'
local Crowsnest = require 'maps.pirates.surfaces.crowsnest'
local Progression = require 'maps.pirates.progression'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Public = {}
Public.progress = require 'maps.pirates.gui.progress'
Public.runs = require 'maps.pirates.gui.runs'
Public.crew = require 'maps.pirates.gui.crew'
Public.shop = require 'maps.pirates.gui.shop'
Public.minimap = require 'maps.pirates.gui.minimap'
Public.info = require 'maps.pirates.gui.info'
local function create_gui(player)
local flowleft, flow1, flow2, flow3, flow4, tooltip
flow1 = player.gui.top
flow2 = GuiCommon.flow_add_floating_sprite_button(flow1, 'info_piratebutton')
flow2.caption = '?'
flow2.style.font = 'debug'
flow2.tooltip = 'Notes and updates on Pirate Ship'
flow2.style.font_color = {r=1, g=1, b=1}
flow2.style.hovered_font_color = {r=1, g=1, b=1}
flow2.style.clicked_font_color = {r=1, g=1, b=1}
flow2.parent.style.left_padding = -6
flow2 = GuiCommon.flow_add_floating_sprite_button(flow1, 'runs_piratebutton', 80)
flow2.caption = 'Play'
flow2.tooltip = 'Play\n\nView the ongoing runs, and make proposals.'
flow2.style.font = 'debug'
flow2.style.font_color = {r=1, g=1, b=1}
flow2.style.hovered_font_color = {r=1, g=1, b=1}
flow2.style.clicked_font_color = {r=1, g=1, b=1}
flow2.parent.style.width = 73
flow2.parent.style.left_padding = -6
-- optional use of left gui:
-- flowleft = player.gui.left
-- flow2 = GuiCommon.flow_add_floating_sprite_button(flowleft, 'crew_piratebutton')
-- flow2.sprite = 'utility/spawn_flag'
flow2 = GuiCommon.flow_add_floating_sprite_button(flow1, 'crew_piratebutton')
flow2.sprite = 'utility/spawn_flag'
-- flow2 = GuiCommon.flow_add_floating_sprite_button(flow1, 'lives_piratebutton')
-- flow2.tooltip = 'Lives\n\nWhen a silo is destroyed before its rocket is launched, you lose a life.\n\nLosing all your lives is one way to lose the game.'
-- flow2.mouse_button_filter = {'middle'}
-- flow2 = GuiCommon.flow_add_floating_sprite_button(flow1, 'distance_travelled_piratebutton')
-- flow2.tooltip = 'Leagues travelled in the overworld\n\nCrews progress through the game by travelling in the overworld. Travel ' .. CoreData.victory_x/40 .. ' leagues = victory.'
-- flow2.sprite = 'item/rail'
-- flow2.mouse_button_filter = {'middle'}
-- flow2 = GuiCommon.flow_add_floating_sprite_button(flow1, 'destination_piratebutton')
-- flow2.tooltip = 'Location window\n\nWhere am I?'
-- flow2.sprite = 'item/landfill'
flow2 = GuiCommon.flow_add_floating_sprite_button(flow1, 'progress_piratebutton')
flow2.tooltip = 'Progress\n\nTravel ' .. CoreData.victory_x .. ' leagues = victory.'
flow2.sprite = 'item/rail'
flow2 = GuiCommon.flow_add_floating_sprite_button(flow1, 'shop_piratebutton')
flow2.tooltip = 'Gold/Shop\n\nGold is a shared crew resource, spent by the captain in the shop to obtain useful items and upgrades.'
flow2.sprite = 'item/sulfur'
flow2 = GuiCommon.flow_add_floating_sprite_button(flow1, 'evo_piratebutton')
flow2.sprite = 'entity/small-biter'
flow2.mouse_button_filter = {'middle'}
flow2.show_percent_for_small_numbers = true
flow2 = GuiCommon.flow_add_floating_sprite_button(flow1, 'minimap_piratebutton')
flow2.tooltip = 'View the outside world.'
flow2.sprite = 'utility/map'
flow2 = flow1.add({
name = 'covering_line_frame',
type = 'frame',
})
flow2.style.minimal_width = 40
flow2.style.natural_width = 40
flow2.style.minimal_height = 40
flow2.style.maximal_height = 40
flow2.style.left_padding = 3
flow2.style.right_padding = 3
flow3 = flow2.add({
name = 'covering_line',
type = 'line',
direction = 'horizontal',
})
flow3.style.top_margin = 9
flow3.style.minimal_width = 320
flow3.style.maximal_width = 320
tooltip = {'pirates.auto_undock_tooltip'}
flow2 = flow1.add({
name = 'time_remaining_frame',
type = 'frame',
})
flow2.style.minimal_width = 100
flow2.style.natural_width = 100
flow2.style.minimal_height = 40
flow2.style.maximal_height = 40
flow2.style.left_padding = 4
flow2.style.right_padding = 4
flow2.style.top_padding = 3
flow2.tooltip = tooltip
flow3 = flow2.add({
name = 'time_remaining_label_1',
type = 'label',
caption = 'Max Time:'
})
flow3.style.font = 'default-large-semibold'
flow3.style.font_color = GuiCommon.bold_font_color
flow3.tooltip = tooltip
flow3 = flow2.add({
name = 'time_remaining_label_2',
type = 'label',
})
flow3.style.left_margin = 2
flow3.style.font = 'default-large'
flow3.style.font_color = GuiCommon.default_font_color
flow3.tooltip = tooltip
-- flow3 = flow2.add({
-- name = 'rage_table',
-- type = 'table',
-- column_count = 5,
-- })
-- flow3.style.top_margin = 6
-- flow3.style.left_margin = 4
-- for i = 1, 6 do
-- flow4 = flow3.add({type = 'progressbar', name = 'bar_' .. i, value = 0.5})
-- flow4.style.width = 18
-- flow4.style.height = 5
-- end
flow2 = flow1.add({
name = 'cost_frame',
type = 'frame',
})
flow2.style.minimal_width = 100
flow2.style.natural_width = 100
flow2.style.minimal_height = 40
flow2.style.maximal_height = 40
flow2.style.left_padding = 4
flow2.style.right_padding = 4
flow2.style.top_padding = 3
flow3 = flow2.add({
name = 'cost_label_1',
type = 'label',
})
flow3.style.font = 'default-large-semibold'
flow3.style.font_color = GuiCommon.bold_font_color
flow3 = flow2.add({
name = 'cost_label_2',
type = 'label',
})
flow3.style.font = 'default-large'
flow3.style.font_color = GuiCommon.default_font_color
flow3 = flow2.add({type = 'table', name = 'cost_table', column_count = 5})
for i = 1, 5 do
flow4 = flow3.add({type = 'sprite-button', name = 'cost_' .. i, number = 0})
-- flow4.mouse_button_filter = {'middle'}
flow4.enabled = false
flow4.style.top_margin = -6
flow4.style.right_margin = -6
flow4.style.maximal_height = 38
flow4.visible = false
end
flow3.style.right_margin = -3
flow2 = flow1.add({
name = 'silo_frame',
type = 'frame',
})
flow2.style.minimal_width = 80
flow2.style.natural_width = 80
flow2.style.minimal_height = 40
flow2.style.maximal_height = 40
flow2.style.left_padding = 4
flow2.style.right_padding = 4
flow2.style.top_padding = 3
flow3 = flow2.add({
name = 'silo_label_1',
type = 'label',
})
flow3.style.font = 'default-large-semibold'
flow3.style.font_color = Common.bold_font_color
flow3.style.right_margin = 2
flow3 = flow2.add({
type = 'progressbar',
name = 'silo_progressbar',
value = 0,
})
flow3.style.top_margin = 9
flow3.style.right_margin = 2
flow3.style.width = 72
flow3.style.height = 11
flow3 = flow2.add({
name = 'silo_label_2',
type = 'label',
})
flow3.style.font = 'default-large-semibold'
flow3.style.font_color = GuiCommon.default_font_color
flow3.style.right_margin = 2
-- flow3 = flow2.add({
-- type = 'sprite',
-- name = 'silo_charging_indicator',
-- })
-- flow3.tooltip = tooltip
-- old font color: {r=0.33, g=0.66, b=0.9}
flow2 = flow1.add({
name = 'quest_frame',
type = 'frame',
})
flow2.style.minimal_width = 80
flow2.style.natural_width = 80
flow2.style.minimal_height = 40
flow2.style.maximal_height = 40
flow2.style.left_padding = 4
flow2.style.right_padding = 4
flow2.style.top_padding = 3
flow3 = flow2.add({
name = 'quest_label_1',
type = 'label',
})
flow3.style.font = 'default-large-semibold'
flow3.style.font_color = GuiCommon.bold_font_color
flow3.style.right_margin = 2
flow3 = flow2.add({
name = 'quest_label_2',
type = 'label',
})
flow3.style.font = 'default-large'
flow3.style.font_color = Common.default_font_color
flow3 = flow2.add({
name = 'quest_label_3',
type = 'label',
})
-- flow3.style.font = 'default-large'
flow3.style.font = 'default-large-semibold'
flow3.style.left_margin = -4
flow3.style.right_margin = -4
flow3.style.font_color = Common.default_font_color
flow3 = flow2.add({
name = 'quest_label_4',
type = 'label',
})
flow3.style.font = 'default-large'
flow3.style.font_color = Common.default_font_color
-- spontaneous inside view of the hold:
flow1 = player.gui.left
flow2 = flow1.add({
name = 'undock_shortcut_button',
type = 'sprite-button',
enabled = false,
})
flow2.style.minimal_width = 80
flow2.style.natural_width = 80
flow2.style.maximal_width = 150
flow2.style.minimal_height = 40
flow2.style.maximal_height = 40
flow2.style.left_margin = 1
flow2.style.top_margin = 1
flow2.style.left_padding = 4
flow2.style.right_padding = 4
flow2.style.top_padding = 3
flow2.style.font = 'default-large-semibold'
flow2.style.font_color = GuiCommon.default_font_color
flow2 =
flow1.add(
{
type = 'camera',
name = 'spontaneous_camera',
position = {x=0,y=0},
}
)
flow2.visible = false
flow2.style.margin = 8
-- flow2.style.minimal_height = 64
-- flow2.style.minimal_width = 64
-- flow2.style.maximal_height = 640
-- flow2.style.maximal_width = 640
end
function Public.update_gui(player)
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local flow1, flow1b, flow2, flow3
local pirates_flow = player.gui.top
if not pirates_flow.info_piratebutton_frame then create_gui(player) end
if memory.id and memory.id ~= 0 then
pirates_flow.crew_piratebutton_frame.crew_piratebutton.tooltip = 'Crew\n\nPerform crew actions.'
pirates_flow.crew_piratebutton_frame.crew_piratebutton.mouse_button_filter = {'left','right'}
else
pirates_flow.crew_piratebutton_frame.crew_piratebutton.tooltip = 'Crew\n\nYou\'re a free agent, so there\'s nothing to do here.'
pirates_flow.crew_piratebutton_frame.crew_piratebutton.mouse_button_filter = {'middle'}
if player.gui.screen['crew_piratewindow'] then
player.gui.screen['crew_piratewindow'].destroy()
end
end
GuiEvo.update(player)
GuiProgress.update(player)
GuiRuns.update(player)
GuiCrew.update(player)
GuiShop.update(player)
GuiMinimap.update(player)
GuiInfo.update(player)
-- local lives = memory.lives or 1
-- local button = pirates_flow.lives_piratebutton_frame.lives_piratebutton
-- if lives == 1 then
-- button.sprite = 'item/effectivity-module'
-- button.number = 1
-- elseif lives == 2 then
-- button.sprite = 'item/effectivity-module-2'
-- button.number = 2
-- elseif lives == 3 then
-- button.sprite = 'item/effectivity-module-3'
-- button.number = 3
-- end
pirates_flow.shop_piratebutton_frame.shop_piratebutton.number = (memory.gold or 0)
pirates_flow.progress_piratebutton_frame.progress_piratebutton.number = (memory.overworldx or 0)
-- pirates_flow.destination_piratebutton_frame.destination_piratebutton.number = memory.destinationsvisited_indices and #memory.destinationsvisited_indices or 0
--== State-checking bools ==--
local in_crowsnest_bool = string.sub(player.surface.name, 9, 17) == 'Crowsnest'
local in_hold_bool = string.sub(player.surface.name, 9, 12) == 'Hold'
local in_cabin_bool = string.sub(player.surface.name, 9, 13) == 'Cabin'
local onmap_bool = destination.surface_name and (player.surface.name == destination.surface_name or (memory.boat and memory.boat.surface_name and
memory.boat.surface_name == destination.surface_name and (in_crowsnest_bool or in_hold_bool or in_cabin_bool)
))
local eta_bool = destination.dynamic_data.time_remaining and destination.dynamic_data.time_remaining > 0 and onmap_bool
local retreating_bool = memory.boat and memory.boat.state and memory.boat.state == Boats.enum_state.RETREATING and onmap_bool
local approaching_bool = memory.boat and memory.boat.state and memory.boat.state == Boats.enum_state.APPROACHING
local atsea_sailing_bool = memory.boat and memory.boat.state and memory.boat.state == Boats.enum_state.ATSEA_SAILING
local landed_bool = memory.boat and memory.boat.state and memory.boat.state == Boats.enum_state.LANDED
local quest_bool = (destination.dynamic_data.quest_type ~= nil) and onmap_bool
local silo_bool = destination.dynamic_data.rocketsilo and destination.dynamic_data.rocketsilo.valid and onmap_bool
local charged_bool = destination.dynamic_data.silocharged
local launched_bool = destination.dynamic_data.rocketlaunched
local captain_bool = (memory.playerindex_captain and player.index == memory.playerindex_captain)
local atsea_loading_bool = memory.boat and memory.boat.state and memory.boat.state == Boats.enum_state.ATSEA_LOADING_MAP and memory.loadingticks
local character_on_deck_bool = player.character and player.character.position and memory.boat and memory.boat.position and memory.boat.surface_name and player.surface.name and player.surface.name == memory.boat.surface_name
local on_deck_standing_near_loco_bool = character_on_deck_bool and Boats.get_scope(memory.boat) and Math.distance(player.character.position, Math.vector_sum(memory.boat.position, Boats.get_scope(memory.boat).Data.loco_pos)) < 3
local on_deck_standing_near_cabin_bool = character_on_deck_bool and Boats.get_scope(memory.boat) and Math.distance(player.character.position, Math.vector_sum(memory.boat.position, Boats.get_scope(memory.boat).Data.cabin_car)) < 2.5
local on_deck_standing_near_crowsnest_bool = character_on_deck_bool and Boats.get_scope(memory.boat) and Math.distance(player.character.position, Math.vector_sum(memory.boat.position, Boats.get_scope(memory.boat).Data.crowsnest_center)) < 2.7
local cost_bool = destination.static_params.cost_to_leave and (not atsea_sailing_bool) and (not retreating_bool)
local approaching_dock = destination.type == Surfaces.enum.DOCK and memory.boat.state == Boats.enum_state.APPROACHING
local leaving_dock = destination.type == Surfaces.enum.DOCK and memory.boat.state == Boats.enum_state.LEAVING_DOCK
local leave_anytime_bool = (landed_bool and not (eta_bool or cost_bool))
--== Update Gui ==--
flow1 = pirates_flow.cost_frame
if cost_bool then
flow1.visible = true
local tooltip, caption
if atsea_loading_bool then
caption = 'Next escape cost:'
tooltip = {'pirates.resources_needed_tooltip_1'}
elseif (not eta_bool) then
caption = 'For escape:'
tooltip = {'pirates.resources_needed_tooltip_3'}
else
caption = 'For early escape:'
tooltip = {'pirates.resources_needed_tooltip_2'}
end
flow1.cost_label_1.caption = caption
flow1.tooltip = tooltip
flow1.cost_label_1.tooltip = tooltip
flow1.cost_table.tooltip = tooltip
local costs = destination.static_params.cost_to_leave
for i = 1, #CoreData.cost_items do
local item_name = CoreData.cost_items[i].name
if costs[item_name] then
local stored = (memory.boat.stored_resources and memory.boat.stored_resources[item_name]) or 0
flow1.cost_table['cost_' .. i].sprite = CoreData.cost_items[i].sprite_name
flow1.cost_table['cost_' .. i].number = Math.max(costs[item_name] - stored, 0)
flow1.cost_table['cost_' .. i].tooltip = CoreData.cost_items[i].display_name
flow1.cost_table['cost_' .. i].visible = true
else
flow1.cost_table['cost_' .. i].visible = false
end
end
flow1.cost_label_2.visible = false
-- local total_rage = time_rage + silo_rage
-- flow1.rage_label_2.caption = total_rage .. '/10'
-- if total_rage <= 4 then
-- flow1.rage_label_2.style.font_color = GuiCommon.rage_font_color_1
-- flow1.rage_label_2.style.font = 'default-large'
-- elseif total_rage <= 7 then
-- flow1.rage_label_2.style.font_color = GuiCommon.rage_font_color_2
-- flow1.rage_label_2.style.font = 'default-large-semibold'
-- else
-- flow1.rage_label_2.style.font_color = GuiCommon.rage_font_color_3
-- flow1.rage_label_2.style.font = 'default-dialog-button'
-- end
-- -- flow1.rage_table.bar_1.value = time_rage >= 1 and 1 or 0
-- -- flow1.rage_table.bar_2.value = time_rage >= 2 and 1 or 0
-- -- flow1.rage_table.bar_3.value = time_rage >= 3 and 1 or 0
-- -- flow1.rage_table.bar_4.value = time_rage >= 4 and 1 or 0
-- -- flow1.rage_table.bar_5.value = silo_rage >= 1 and 1 or 0
-- -- flow1.rage_table.bar_6.value = silo_rage >= 2 and 1 or 0
else
flow1.visible = false
end
flow1 = player.gui.left.undock_shortcut_button
if captain_bool and landed_bool and (not memory.captain_acceptance_timer) then
flow1.visible = true
local enabled = Common.query_sufficient_resources_to_leave()
flow1.enabled = enabled
if enabled then
flow1.tooltip = ''
else
flow1.tooltip = 'Store more resources in the captain\'s cabin before leaving.'
end
elseif captain_bool and destination and destination.type and destination.type == Surfaces.enum.DOCK and (not (memory.boat.state and memory.boat.state == Boats.enum_state.LEAVING_DOCK)) then
flow1.visible = true
flow1.enabled = memory.boat and memory.boat.state and memory.boat.state == Boats.enum_state.DOCKED
flow1.tooltip = ''
else
flow1.visible = false
end
if flow1.visible then
if (not memory.undock_shortcut_are_you_sure_data) then memory.undock_shortcut_are_you_sure_data = {} end
if memory.undock_shortcut_are_you_sure_data[player.index] and memory.undock_shortcut_are_you_sure_data[player.index] > game.tick - 60 * 4 then
flow1.caption = 'Are you sure?'
else
flow1.caption = 'Undock'
end
end
flow1 = pirates_flow.time_remaining_frame
if atsea_loading_bool or eta_bool or retreating_bool or leave_anytime_bool then
flow1.visible = true
flow1.time_remaining_label_1.visible = true
if retreating_bool then
flow1.time_remaining_label_2.visible = false
local tooltip = 'Probably time to board...'
flow1.tooltip = tooltip
flow1.time_remaining_label_1.tooltip = tooltip
flow1.time_remaining_label_2.tooltip = tooltip
flow1.time_remaining_label_1.caption = 'RETURN TO SHIP'
elseif eta_bool then
flow1.time_remaining_label_2.visible = true
local tooltip = {'pirates.auto_undock_tooltip'}
flow1.tooltip = tooltip
flow1.time_remaining_label_1.tooltip = tooltip
flow1.time_remaining_label_2.tooltip = tooltip
local passive_eta = destination.dynamic_data.time_remaining
flow1.time_remaining_label_1.caption = 'Auto-undock:'
flow1.time_remaining_label_2.caption = Utils.standard_string_form_of_time_in_seconds(passive_eta)
elseif atsea_loading_bool then
flow1.time_remaining_label_2.visible = true
local tooltip = {'pirates.atsea_loading_tooltip'}
flow1.tooltip = tooltip
flow1.time_remaining_label_1.tooltip = tooltip
flow1.time_remaining_label_2.tooltip = tooltip
local eta_ticks = Common.map_loading_ticks_atsea + (memory.extra_time_at_sea or 0) - memory.loadingticks
flow1.time_remaining_label_1.caption = 'Arriving in'
flow1.time_remaining_label_2.caption = Utils.standard_string_form_of_time_in_seconds(eta_ticks / 60)
elseif leave_anytime_bool then
flow1.time_remaining_label_2.visible = true
local tooltip = {'pirates.leave_anytime_tooltip'}
flow1.tooltip = tooltip
flow1.time_remaining_label_1.tooltip = tooltip
flow1.time_remaining_label_2.tooltip = tooltip
flow1.time_remaining_label_1.caption = 'Undock:'
flow1.time_remaining_label_2.caption = 'Anytime'
end
else
flow1.visible = false
end
flow1 = pirates_flow.silo_frame
local active_eta
if silo_bool then
flow1.visible = true
if charged_bool then
if launched_bool then
local tooltip = 'The rocket has launched, and this is the reward.'
flow1.tooltip = tooltip
flow1.silo_label_1.tooltip = tooltip
flow1.silo_label_2.visible = false
flow1.silo_progressbar.visible = false
-- flow1.silo_label_1.caption = string.format('[achievement=there-is-no-spoon]: +%.0f[item=sulfur]', destination.dynamic_data.rocketgoldreward)
flow1.silo_label_1.caption = string.format('Launch: %.0f[item=sulfur] , ' .. Balance.rocket_launch_coin_reward .. '[item=coin]', destination.dynamic_data.rocketgoldreward)
flow1.silo_label_1.style.font_color = GuiCommon.achieved_font_color
else
local tooltip = 'The rocket is launching...'
flow1.tooltip = tooltip
flow1.silo_label_1.tooltip = tooltip
flow1.silo_progressbar.tooltip = tooltip
flow1.silo_label_1.caption = 'Charge:'
flow1.silo_label_1.style.font_color = Common.bold_font_color
flow1.silo_label_2.visible = false
flow1.silo_progressbar.visible = true
flow1.silo_progressbar.value = 1
end
else
flow1.silo_label_1.caption = 'Charge:'
flow1.silo_label_1.style.font_color = Common.bold_font_color
flow1.silo_label_2.visible = true
flow1.silo_progressbar.visible = true
local consumed = destination.dynamic_data.rocketsiloenergyconsumed
local needed = destination.dynamic_data.rocketsiloenergyneeded
local recent = (destination.dynamic_data.rocketsiloenergyconsumedwithinlasthalfsecond * 2)
flow1.silo_progressbar.value = consumed/needed
local tooltip = string.format('Rocket silo charge\n\nCharge the silo to launch a rocket, gaining both gold and coins.\n\nCurrent charge: %.1f', consumed / 1000000000) .. '/' .. Math.floor(needed / 100000000)/10 .. ' GJ'
flow1.tooltip = tooltip
flow1.silo_label_1.tooltip = tooltip
flow1.silo_label_2.tooltip = tooltip
flow1.silo_progressbar.tooltip = tooltip
if recent ~= 0 then
active_eta = (needed - consumed) / recent
flow1.silo_label_2.caption = Utils.standard_string_form_of_time_in_seconds(active_eta)
if active_eta >= destination.dynamic_data.time_remaining then
flow1.silo_label_2.style.font_color = GuiCommon.insufficient_font_color
else
flow1.silo_label_2.style.font_color = GuiCommon.sufficient_font_color
end
else
flow1.silo_label_2.caption = ''
flow1.silo_label_2.style.font_color = GuiCommon.insufficient_font_color
end
end
else
flow1.visible = false
end
flow1 = pirates_flow.quest_frame
if quest_bool then
flow1.visible = true
local quest_type = destination.dynamic_data.quest_type or nil
local quest_params = destination.dynamic_data.quest_params or {}
local quest_reward = destination.dynamic_data.quest_reward or nil
local quest_progress = destination.dynamic_data.quest_progress or 0
local quest_progressneeded = destination.dynamic_data.quest_progressneeded or 0
local quest_complete = destination.dynamic_data.quest_complete or false
if quest_type then
local tooltip = ''
if quest_complete then
tooltip = 'The quest is complete, and this is the reward.'
flow1.quest_label_1.caption = 'Quest: ' .. quest_reward.display_amount .. ' ' .. quest_reward.display_sprite
flow1.quest_label_2.visible = false
flow1.quest_label_3.visible = false
flow1.quest_label_4.visible = false
elseif quest_progress < quest_progressneeded then
flow1.quest_label_1.caption = 'Quest:'
flow1.quest_label_2.visible = true
flow1.quest_label_3.visible = true
flow1.quest_label_4.visible = true
-- defaults, to be overwritten:
flow1.quest_label_2.caption = string.format('%s ', Quest.quest_icons[quest_type])
flow1.quest_label_3.caption = string.format('%.0f/%.0f', quest_progress, quest_progressneeded)
flow1.quest_label_3.style.font_color = GuiCommon.insufficient_font_color
flow1.quest_label_4.caption = string.format(' for %s', quest_reward.display_sprite)
flow1.quest_label_4.style.font_color = Common.default_font_color
end
if quest_type == Quest.enum.TIME then
if tooltip == '' then tooltip = 'Quest: Time\n\nLaunch a rocket before the countdown completes for a bonus.' end
if quest_progress >= 0 then
flow1.quest_label_3.caption = string.format('%.0fm%.0fs', Math.floor(quest_progress / 60), quest_progress % 60)
if active_eta then
if active_eta < quest_progress - 35 then --35 is roughly the number of seconds between charge and launch
flow1.quest_label_3.style.font_color = GuiCommon.sufficient_font_color
else
flow1.quest_label_3.style.font_color = GuiCommon.insufficient_font_color
end
else
if charged_bool and quest_progress > 35 then
flow1.quest_label_3.style.font_color = GuiCommon.sufficient_font_color
else
flow1.quest_label_3.style.font_color = GuiCommon.insufficient_font_color
end
end
else
flow1.quest_label_3.caption = string.format('Fail')
flow1.quest_label_3.style.font_color = GuiCommon.insufficient_font_color
end
elseif quest_type == Quest.enum.WORMS then
if tooltip == '' then tooltip = 'Quest: Worms\n\nKill enough worms for a bonus.' end
elseif quest_type == Quest.enum.FIND then
if tooltip == '' then tooltip = 'Quest: Find\n\nFind the ghosts for a bonus.' end
elseif quest_type == Quest.enum.RESOURCEFLOW then
if tooltip == '' then tooltip = 'Quest: Resource Flow\n\nAchieve a production rate of a particular item for a bonus.' end
-- out of date:
if quest_progressneeded/60 % 1 == 0 then
flow1.quest_label_2.caption = string.format('%s %.1f/%.0f /s', '[item=' .. quest_params.item .. ']', quest_progress/60, quest_progressneeded/60)
flow1.quest_label_3.caption = string.format(' for %s', quest_reward.display_sprite)
else
flow1.quest_label_2.caption = string.format('%s %.1f/%.1f /s', '[item=' .. quest_params.item .. ']', quest_progress/60, quest_progressneeded/60)
flow1.quest_label_3.caption = string.format(' for %s', quest_reward.display_sprite)
end
elseif quest_type == Quest.enum.RESOURCECOUNT then
if tooltip == '' then tooltip = 'Quest: Item Production\n\nProduce a particular number of items for a bonus.' end
flow1.quest_label_2.caption = string.format('%s ', '[item=' .. quest_params.item .. ']')
elseif quest_type == Quest.enum.NODAMAGE then
if tooltip == '' then tooltip = 'Quest: No Damage\n\nLaunch a rocket without the silo taking damage.' end
if (memory.boat and memory.boat.state == Boats.enum_state.APPROACHING) or (destination.dynamic_data.rocketsilo and destination.dynamic_data.rocketsilo.valid and destination.dynamic_data.rocketsilohp == destination.dynamic_data.rocketsilomaxhp) then
flow1.quest_label_3.caption = string.format('OK')
flow1.quest_label_3.style.font_color = GuiCommon.sufficient_font_color
else
flow1.quest_label_3.caption = string.format('Fail')
flow1.quest_label_3.style.font_color = GuiCommon.insufficient_font_color
end
end
flow1.tooltip = tooltip
flow1.quest_label_1.tooltip = tooltip
flow1.quest_label_2.tooltip = tooltip
flow1.quest_label_3.tooltip = tooltip
end
else
flow1.visible = false
end
flow1 = pirates_flow.covering_line_frame
if not eta_bool and not retreating_bool and not quest_bool and not silo_bool and not atsea_loading_bool and not cost_bool and not leave_anytime_bool then
flow1.visible = true
else
flow1.visible = false
end
if in_hold_bool then
pirates_flow.minimap_piratebutton_frame.visible = true
else
pirates_flow.minimap_piratebutton_frame.visible = false
end
flow1 = player.gui.left.spontaneous_camera
flow1.visible = false
if on_deck_standing_near_loco_bool then
flow1.visible = true
flow1.surface_index = Hold.get_hold_surface(1).index
flow1.zoom = 0.18
flow1.style.minimal_height = 268
flow1.style.minimal_width = 532
flow1.position = {x=0,y=0}
elseif on_deck_standing_near_cabin_bool then
flow1.visible = true
flow1.surface_index = Cabin.get_cabin_surface().index
flow1.zoom = 0.468
flow1.style.minimal_height = 416
flow1.style.minimal_width = 260
flow1.position = {x=0,y=-1.3}
elseif on_deck_standing_near_crowsnest_bool then
flow1.visible = true
flow1.surface_index = Crowsnest.get_crowsnest_surface().index
flow1.zoom = 0.21
flow1.style.minimal_height = 384
flow1.style.minimal_width = 384
flow1.position = {x=memory.overworldx,y=memory.overworldy}
elseif in_cabin_bool or in_crowsnest_bool then
flow1.visible = true
flow1.surface_index = game.surfaces[memory.boat.surface_name].index
flow1.zoom = 0.09
flow1.style.minimal_height = 312
flow1.style.minimal_width = 312
local position = memory.boat.position
if (destination and destination.type and destination.type == Surfaces.enum.ISLAND and memory.boat.surface_name and memory.boat.surface_name == destination.surface_name and destination.static_params and destination.static_params.boat_starting_xposition) then
-- nicer viewing position:
position = {x = destination.static_params.boat_starting_xposition + 50, y = destination.static_params.boat_starting_yposition or 0}
end
flow1.position = position
end
end
local function on_gui_click(event)
if not event then return end
if not event.element then return end
if not event.element.valid then return end
local player = game.players[event.element.player_index]
local crew_id = tonumber(string.sub(player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
if string.sub(event.element.name, -13, -1) and string.sub(event.element.name, -13, -1) == '_piratebutton' then
local name = string.sub(event.element.name, 1, -14)
local player = game.players[event.element.player_index]
if Public[name] then
Public[name].toggle_window(player)
Public[name].update(player)
end
elseif event.element.name and event.element.name == 'undock_shortcut_button' then
local memory = Memory.get_crew_memory()
--double check:
if (memory.playerindex_captain and player.index == memory.playerindex_captain) then
if (not memory.undock_shortcut_are_you_sure_data) then memory.undock_shortcut_are_you_sure_data = {} end
if memory.undock_shortcut_are_you_sure_data[player.index] and memory.undock_shortcut_are_you_sure_data[player.index] > game.tick - 60 * 4 then
if memory.boat.state == Boats.enum_state.DOCKED then
Progression.undock_from_dock()
else
Progression.try_retreat_from_island()
end
else
memory.undock_shortcut_are_you_sure_data[player.index] = game.tick
end
end
else
GuiRuns.click(event)
GuiCrew.click(event)
GuiShop.click(event)
GuiMinimap.click(event)
GuiInfo.click(event)
end
end
local function on_gui_location_changed(event)
if (not event and event.element and event.element.valid) then return end
if string.sub(event.element.name, -13, -1) and string.sub(event.element.name, -13, -1) == '_piratewindow' then
local name = string.sub(event.element.name, 1, -14)
local player = game.players[event.element.player_index]
GuiCommon.update_gui_memory(player, name, 'position', event.element.location)
end
end
local event = require 'utils.event'
event.add(defines.events.on_gui_click, on_gui_click)
event.add(defines.events.on_gui_location_changed, on_gui_location_changed)
return Public

210
maps/pirates/gui/info.lua Normal file
View File

@@ -0,0 +1,210 @@
local Memory = require 'maps.pirates.memory'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Lobby = require 'maps.pirates.surfaces.lobby'
local inspect = require 'utils.inspect'.inspect
local Boats = require 'maps.pirates.structures.boats.boats'
local GuiCommon = require 'maps.pirates.gui.common'
local Public = {}
local window_name = 'info'
function Public.toggle_window(player)
local flow, flow2, flow3, flow4, flow5, sections
if player.gui.screen[window_name .. '_piratewindow'] then player.gui.screen[window_name .. '_piratewindow'].destroy() return end
flow = player.gui.screen.add{
type = 'tabbed-pane',
name = window_name .. '_piratewindow',
direction = 'vertical'
}
flow.location = {x = 90, y = 90}
flow.selected_tab_index = 1
flow.style = 'frame_tabbed_pane'
flow.style.width = 410
flow.style.height = 420
flow2 = Public.flow_add_info_tab(flow, 'Info')
flow4 = flow2.parent.header_flow_1.header_flow_2
flow5 = flow4.add{type = "label", caption = {"pirates.softmod_info_body_1"}}
flow5.style.font_color = GuiCommon.friendly_font_color
flow5.style.single_line = false
flow5.style.font = 'debug'
flow5.style.bottom_margin = 16
Public.flow_add_info_sections(flow2, {'game_description'})
flow2 = Public.flow_add_info_tab(flow, 'Updates')
Public.flow_add_info_sections(flow2, {'updates', 'bugs'})
flow2 = Public.flow_add_info_tab(flow, 'Tips')
Public.flow_add_info_sections(flow2, {'new_players', 'tips'})
flow2 = Public.flow_add_info_tab(flow, 'Credits')
Public.flow_add_info_sections(flow2, {'credits'})
end
function Public.flow_add_info_sections(flow, sections_list)
local flow2
for j = 1, #sections_list do
local i = sections_list[j]
flow2 = flow.add{type = "label", caption = {"pirates.softmod_info_" .. i .. "_1"}}
flow2.style.font_color = GuiCommon.friendly_font_color
flow2.style.single_line = false
flow2.style.font = 'heading-3'
flow2.style.bottom_margin = -4
flow2 = flow.add{type = "label", caption = {"pirates.softmod_info_" .. i .. "_2"}}
flow2.style.font_color = GuiCommon.friendly_font_color
flow2.style.single_line = false
flow2.style.font = 'default'
flow2.style.bottom_margin = 12
flow2.style.left_margin = 8
end
end
function Public.flow_add_info_tab(flow, tab_name)
local tab, contents, ret, flow3, flow4, flow5
tab = flow.add{type='tab', caption=tab_name}
tab.style = 'frame_tab'
contents = flow.add({
type = 'frame',
direction = 'vertical',
})
contents.style.vertically_stretchable = true
contents.style.width = 410
contents.style.natural_height = 2000
contents.style.top_margin = -8
contents.style.bottom_margin = -12
contents.style.left_margin = -7
contents.style.right_margin = -11
flow3 = contents.add({
type = 'flow',
name = 'header_flow_1',
direction = 'horizontal',
})
flow3.style.horizontally_stretchable = true
flow3.style.horizontal_align = 'center'
flow4 = flow3.add({
type = 'flow',
name = 'header_flow_2',
direction = 'vertical',
})
flow4.style.horizontally_stretchable = true
flow4.style.horizontal_align = 'center'
flow5 = flow4.add{type = "label", caption = {"", {"pirates.softmod_info_header_before_version_number"}, CoreData.version_string, {"pirates.softmod_info_header_after_version_number"}}}
flow5.style.font_color = GuiCommon.friendly_font_color
flow5.style.font = 'heading-1'
flow5.style.bottom_margin = 2
flow5 = flow4.add{type = "label", caption = {"pirates.softmod_info_body_promote"}}
flow5.style.font_color = GuiCommon.friendly_font_color
flow5.style.single_line = false
flow5.style.font = 'default-small'
flow5.style.top_margin = -12
flow5.style.bottom_margin = 8
ret = contents.add({
type = 'flow',
name = 'main_flow_1',
direction = 'vertical',
})
ret.style.horizontally_stretchable = true
flow3 = contents.add({
type = 'flow',
direction = 'vertical',
})
flow3.style.vertically_stretchable = true
flow3.style.horizontally_stretchable = true
flow3 = contents.add({
type = 'flow',
direction = 'horizontal',
})
flow3.style.horizontally_stretchable = true
flow3.style.horizontal_align = 'center'
flow4 = flow3.add{type = "label", caption = {"pirates.softmod_info_body_clicky"}}
flow4.style.font_color = GuiCommon.friendly_font_color
flow4.style.single_line = false
flow4.style.font = 'default'
flow4.style.bottom_margin = 4
flow4.style.top_margin = 3
flow.add_tab(tab, contents)
return ret
end
function Public.click(event)
local player = game.players[event.element.player_index]
local name = 'info'
local element = event.element
local eventtype = element.type
if not player.gui.screen[window_name .. '_piratewindow'] then return end
local memory = Memory.get_crew_memory()
if eventtype ~= 'tab' and (
element.name == (window_name .. '_piratewindow') or
(element.parent and element.parent.name == (window_name .. '_piratewindow')) or
(element.parent and element.parent.parent and element.parent.parent.name == (window_name .. '_piratewindow')) or
(element.parent and element.parent.parent and element.parent.parent.parent and element.parent.parent.parent.name == (window_name .. '_piratewindow')) or
(element.parent and element.parent.parent and element.parent.parent.parent and element.parent.parent.parent.parent and element.parent.parent.parent.parent.name == (window_name .. '_piratewindow')) or
(element.parent and element.parent.parent and element.parent.parent.parent and element.parent.parent.parent.parent and element.parent.parent.parent.parent.parent and element.parent.parent.parent.parent.parent.name == (window_name .. '_piratewindow'))
) then
Public.toggle_window(player)
end
end
function Public.update(player)
if not player.gui.screen[window_name .. '_piratewindow'] then return end
local flow = player.gui.screen[window_name .. '_piratewindow']
local flow2 = flow
-- warning, if you make these too small, it loses 'Click to dismiss.'
if flow2.selected_tab_index == 1 then
flow2.style.height = 390
elseif flow2.selected_tab_index == 2 then
flow2.style.height = 320
elseif flow2.selected_tab_index == 3 then
flow2.style.height = 620
elseif flow2.selected_tab_index == 4 then
flow2.style.height = 280
end
end
return Public

View File

@@ -0,0 +1,244 @@
local Memory = require 'maps.pirates.memory'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Roles = require 'maps.pirates.roles.roles'
local Crew = require 'maps.pirates.crew'
local Progression = require 'maps.pirates.progression'
local Structures = require 'maps.pirates.structures.structures'
local inspect = require 'utils.inspect'.inspect
local Boats = require 'maps.pirates.structures.boats.boats'
local GuiCommon = require 'maps.pirates.gui.common'
local Public = {}
local window_name = 'minimap'
local default_zoom = 0.1
local default_size = 320
function Public.toggle_window(player)
local flow, flow2, flow3, flow4, flow5, flow6
local window = player.gui.screen[window_name .. '_piratewindow']
if window then
local switch_state = window.close_button_flow.hflow.switch_auto_map.switch_state
local auto_map = true
if switch_state == 'right' then
auto_map = false
end
GuiCommon.update_gui_memory(player, window_name, 'auto_map', auto_map)
window.destroy()
return
end -- else:
flow = GuiCommon.new_window(player, window_name)
flow.caption = 'Outside View'
flow.style.maximal_width = 800
local memory = Memory.get_crew_memory()
local global_memory = Memory.get_global_memory()
local gui_memory = global_memory.player_gui_memories[player.index]
local auto_map
if gui_memory and gui_memory[window_name] then
auto_map = gui_memory[window_name].auto_map
else
auto_map = true
end
local switch_state = 'right'
if auto_map then
switch_state = 'left'
end
if not (memory.boat and memory.boat.position and memory.boat.surface_name) then return end
local position = memory.boat.position
local destination = Common.current_destination()
if (destination and destination.type and destination.type == Surfaces.enum.ISLAND and destination.static_params and destination.static_params.boat_starting_xposition) then
-- nicer viewing position:
position = {x = destination.static_params.boat_starting_xposition + 50, y = destination.static_params.boat_starting_yposition or 0}
end
local zoom
if gui_memory and gui_memory[window_name] and gui_memory[window_name].zoom then
zoom = gui_memory[window_name].zoom
else
zoom = default_zoom
end
local size
if gui_memory and gui_memory[window_name] and gui_memory[window_name].size then
size = gui_memory[window_name].size
else
size = default_size
end
local element = flow['camera']
if not element then
element =
flow.add(
{
type = 'camera',
name = 'camera',
position = position,
surface_index = game.surfaces[memory.boat.surface_name].index,
zoom = zoom,
tooltip = 'LMB: Zoom in.\nRMB: Zoom out.\nMMB: Scale window.'
}
)
element.style.margin = 1
element.style.minimal_height = size
element.style.minimal_width = size
element.style.maximal_height = size
element.style.maximal_width = size
end
flow2 = GuiCommon.flow_add_close_button(flow, window_name .. '_piratebutton')
flow2.add(
{
type = 'switch',
name = 'switch_auto_map',
index = 1,
allow_none_state = false,
switch_state = switch_state,
left_label_caption = 'Auto Show Map — On',
right_label_caption = 'Off'
}
)
end
function Public.update(player)
local flow, flow2, flow3, flow4, flow5, flow6
local memory = Memory.get_crew_memory()
if not player.gui.screen[window_name .. '_piratewindow'] then return end
flow = player.gui.screen[window_name .. '_piratewindow']
local element = flow['camera']
if element then
local position = memory.boat.position
local destination = Common.current_destination()
if (destination and destination.type and destination.type == Surfaces.enum.ISLAND and memory.boat.surface_name and memory.boat.surface_name == destination.surface_name and destination.static_params and destination.static_params.boat_starting_xposition) then
-- nicer viewing position:
position = {x = destination.static_params.boat_starting_xposition + 50, y = destination.static_params.boat_starting_yposition or 0}
end
if position then
element.position = position
end
if memory.boat.surface_name and game.surfaces[memory.boat.surface_name] and game.surfaces[memory.boat.surface_name].valid then
element.surface_index = game.surfaces[memory.boat.surface_name].index
end
end
end
function Public.click(event)
local player = game.players[event.element.player_index]
local eventname = event.element.name
if not player.gui.screen[window_name .. '_piratewindow'] then return end
local flow = player.gui.screen[window_name .. '_piratewindow']
-- local memory = Memory.get_crew_memory()
-- local shop_data = Shop.main_shop_data
-- if eventname == 'buy_button' then
-- Shop.main_shop_try_purchase(event.element.parent.name)
-- end
if eventname ~= 'camera' then return end
local zoom = default_zoom
local size = default_size
local global_memory = Memory.get_global_memory()
local gui_memory = global_memory.player_gui_memories[player.index]
if gui_memory and gui_memory[window_name] then
zoom = gui_memory[window_name].zoom or default_zoom
size = gui_memory[window_name].size or default_size
end
if event.button == defines.mouse_button_type.right then
if zoom == 0.15 then
zoom = 0.11
elseif zoom == 0.11 then
zoom = 0.07
else
zoom = 0.04
end
event.element.zoom = zoom
end
if event.button == defines.mouse_button_type.left then
if zoom == 0.04 then
zoom = 0.07
elseif zoom == 0.07 then
zoom = 0.11
else
zoom = 0.15
end
event.element.zoom = zoom
end
if event.button == defines.mouse_button_type.middle then
if size == 320 then
size = 420
elseif size == 420 then
size = 520
elseif size == 520 then
size = 250
else
size = 320
end
event.element.style.minimal_height = size
event.element.style.minimal_width = size
event.element.style.maximal_height = size
event.element.style.maximal_width = size
end
GuiCommon.update_gui_memory(player, window_name, 'zoom', zoom)
GuiCommon.update_gui_memory(player, window_name, 'size', size)
end
local function on_player_changed_surface(event)
local player = game.players[event.player_index]
if not Common.validate_player_and_character(player) then
return
end
local window = player.gui.screen[window_name .. '_piratewindow']
local from_hold_bool = string.sub(game.surfaces[event.surface_index].name, 9, 12) == 'Hold'
local to_hold_bool = string.sub(player.surface.name, 9, 12) == 'Hold'
if from_hold_bool and (not to_hold_bool) then
if window then
Public.toggle_window(player)
end
elseif to_hold_bool and (not from_hold_bool) then
local global_memory = Memory.get_global_memory()
local gui_memory = global_memory.player_gui_memories[player.index]
if (gui_memory and gui_memory[window_name] and gui_memory[window_name].auto_map) or (not gui_memory) or (gui_memory and (not gui_memory[window_name])) then --if no gui memory exists for this, default to opening the minimap
Public.toggle_window(player)
end
end
end
local event = require 'utils.event'
event.add(defines.events.on_player_changed_surface, on_player_changed_surface)
return Public

View File

@@ -0,0 +1,170 @@
local Memory = require 'maps.pirates.memory'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Lobby = require 'maps.pirates.surfaces.lobby'
local inspect = require 'utils.inspect'.inspect
local Boats = require 'maps.pirates.structures.boats.boats'
local GuiCommon = require 'maps.pirates.gui.common'
local Public = {}
local window_name = 'progress'
function Public.toggle_window(player)
if player.gui.screen[window_name .. '_piratewindow'] then player.gui.screen[window_name .. '_piratewindow'].destroy() return end
local flow, flow2, flow3
flow = GuiCommon.new_window(player, window_name)
flow.caption = 'Progress'
flow2 = GuiCommon.flow_add_section(flow, 'distance_travelled', 'Distance Travelled:')
flow3 = flow2.add({
name = 'leagues',
type = 'label',
})
flow3.style.left_margin = 5
flow3.style.top_margin = -3
flow3.style.bottom_margin = -3
flow3.style.single_line = false
flow3.style.maximal_width = 160
flow3.style.font = 'default-dropdown'
flow2 = GuiCommon.flow_add_section(flow, 'current_location', 'Current location: ')
-- flow3 = flow2.add({
-- name = 'location_name',
-- type = 'label',
-- })
-- flow3.style.left_margin = 5
-- flow3.style.top_margin = -3
-- flow3.style.bottom_margin = -3
-- flow3.style.single_line = false
-- flow3.style.maximal_width = 160
-- flow3.style.font = 'default-dropdown'
flow3 = flow2.add({type = 'label', name = 'hidden_ores_yes', caption = 'Hidden ores detected:'})
flow3 = flow2.add({type = 'table', name = 'hidden_ores_yes_table', column_count = 3})
flow3.style.left_margin = 5
flow3.style.bottom_margin = 4
for _, ore in ipairs(CoreData.ore_types) do
flow3.add({type = 'sprite-button', name = ore.name, sprite = ore.sprite_name, enabled = false, number = 0})
end
flow3 = flow2.add({type = 'label', name = 'hidden_ores_no', caption = 'Hidden ores detected: None'})
-- flow3 = flow2.add({type = 'label', name = 'daynight', caption = ''})
flow3 = flow2.add({type = 'label', name = 'patch_size', caption = ''})
flow3.style.top_margin = -3
flow3 = flow2.add({type = 'label', name = 'daynight', caption = ''})
flow3.style.top_margin = -3
-- flow2 = GuiCommon.flow_add_section(flow, 'departure_items', 'Resources needed for departure:')
-- flow3.style.bottom_margin = -2
-- flow3 = flow2.add({type = 'table', name = 'needed', column_count = 4})
-- flow3.style.left_margin = 5
-- for _, item in ipairs(CoreData.departure_items) do
-- flow3.add({type = 'sprite-button', name = item.name, sprite = item.sprite_name, enabled = false, number = 0})
-- end
GuiCommon.flow_add_close_button(flow, window_name .. '_piratebutton')
return
end
function Public.update(player)
if not player.gui.screen[window_name .. '_piratewindow'] then return end
local flow = player.gui.screen[window_name .. '_piratewindow']
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local type = destination.type
local subtype = destination.subtype
local scope = Surfaces.get_scope(destination)
local name
if scope then
name = (destination and destination.static_params and destination.static_params.name) and destination.static_params.name or scope.Data.display_name
else
name = Lobby.Data.display_name
end
flow.current_location.header.caption = string.format('Current location: %s', name)
flow.distance_travelled.body.leagues.caption = string.format('%d leagues', memory.overworldx or 0)
-- local daynighttype
-- if destination.static_params and destination.static_params.daynightcycletype then
-- daynighttype = destination.static_params.daynightcycletype
-- else
-- daynighttype = 1
-- end
-- flow.current_location.body.daynight.caption = string.format('Day/night cycle: %s', CoreData.daynightcycle_types[daynighttype].displayname)
if destination.static_params and destination.static_params.radius_squared_modifier then
local radius_squared_modifier = destination.static_params.radius_squared_modifier
flow.current_location.body.patch_size.visible = true
if radius_squared_modifier <= 0.65 then
flow.current_location.body.patch_size.caption = 'Patch sizing: ' .. 'Nano'
elseif radius_squared_modifier <= 0.85 then
flow.current_location.body.patch_size.caption = 'Patch sizing: ' .. 'Small'
elseif radius_squared_modifier <= 1.5 then
flow.current_location.body.patch_size.caption = 'Patch sizing: ' .. 'Normal'
else
flow.current_location.body.patch_size.caption = 'Patch sizing: ' .. 'Large'
end
else
flow.current_location.body.patch_size.visible = false
end
-- if destination.static_params and destination.static_params.daynightcycletype then
-- flow.current_location.body.daynight.visible = true
-- local daynightcycletype = destination.static_params.daynightcycletype
-- flow.current_location.body.daynight.caption = 'Daynight cycle: ' .. CoreData.daynightcycle_types[daynightcycletype].displayname
-- else
-- flow.current_location.body.daynight.visible = false
-- end
local daynightcycletype = destination.static_params.daynightcycletype or 1
flow.current_location.body.daynight.caption = 'Time of day: ' .. CoreData.daynightcycle_types[daynightcycletype].displayname
local ores
-- if destination.static_params and destination.static_params.abstract_ore_amounts then ores = destination.static_params.abstract_ore_amounts end
if destination.dynamic_data and destination.dynamic_data.hidden_ore_remaining_abstract then ores = destination.dynamic_data.hidden_ore_remaining_abstract end
if ores then
flow.current_location.body.hidden_ores_yes.visible = true
flow.current_location.body.hidden_ores_yes_table.visible = true
flow.current_location.body.patch_size.visible = true
flow.current_location.body.hidden_ores_no.visible = false
for _, ore in ipairs(CoreData.ore_types) do
if ores[ore.name] then
flow.current_location.body.hidden_ores_yes_table[ore.name].number = Math.ceil(ores[ore.name])
else
flow.current_location.body.hidden_ores_yes_table[ore.name].number = 0
end
end
else
flow.current_location.body.hidden_ores_yes.visible = false
flow.current_location.body.hidden_ores_yes_table.visible = false
flow.current_location.body.patch_size.visible = false
flow.current_location.body.hidden_ores_no.visible = true
end
end
return Public

666
maps/pirates/gui/runs.lua Normal file
View File

@@ -0,0 +1,666 @@
local Memory = require 'maps.pirates.memory'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Roles = require 'maps.pirates.roles.roles'
local Crew = require 'maps.pirates.crew'
local Progression = require 'maps.pirates.progression'
local Structures = require 'maps.pirates.structures.structures'
local inspect = require 'utils.inspect'.inspect
local Boats = require 'maps.pirates.structures.boats.boats'
local GuiCommon = require 'maps.pirates.gui.common'
local Server = require 'utils.server'
local Public = {}
local window_name = 'runs'
local function flow_add_proposal_slider(flow, name, displayname, indices_count, starting_index, tooltip)
local flow2, flow3, flow4
flow2 = flow.add({
name = name,
type = 'flow',
direction = 'vertical',
})
flow2.style.horizontal_align = 'left'
flow2.style.width = 130
flow3 = flow2.add({
type = 'label',
caption = displayname,
})
flow3.style.font = 'heading-3'
flow3.style.height = 20
flow3.style.margin = 0
flow3.style.padding = 0
flow3.style.top_padding = -4
flow3.style.bottom_margin = 0
flow3.style.font_color = GuiCommon.subsection_header_font_color
flow3.tooltip = tooltip
flow3 = flow2.add({
name = name,
type = 'flow',
direction = 'vertical',
})
flow3.style.horizontal_align = 'center'
flow3.style.width = 130
flow4 = flow3.add({
name = 'slider',
type = 'slider',
value_step = 1,
minimum_value = 1,
maximum_value = indices_count,
value = starting_index,
discrete_values = true,
discrete_slider = true,
})
flow4.style.width = 100
flow4.style.margin = 0
flow4.tooltip = tooltip
flow4 = flow3.add({
name = 'readoff_text',
type = 'label',
caption = '',
})
flow4.style.font = 'default-listbox'
flow4.style.height = 20
flow4.style.margin = 0
flow4.style.padding = 0
flow4.style.top_padding = 0
flow4.style.bottom_margin = 16
flow4.tooltip = tooltip
flow2 = flow.add({
name = name .. '_readoff_icon',
type = 'sprite-button',
enabled = false,
})
flow2.style.width = 48
flow2.style.height = 48
flow2.tooltip = tooltip
return flow2
end
local function flow_add_proposal_switch(flow, name, displayname, starting_position, tooltip)
local flow2, flow3, flow4
flow2 = flow.add({
name = name,
type = 'flow',
direction = 'vertical',
})
flow2.style.horizontal_align = 'left'
flow2.style.width = 130
flow3 = flow2.add({
type = 'label',
caption = displayname,
})
flow3.style.font = 'heading-3'
flow3.style.height = 20
flow3.style.margin = 0
flow3.style.padding = 0
flow3.style.top_padding = -4
flow3.style.bottom_margin = 0
flow3.style.font_color = GuiCommon.subsection_header_font_color
flow3.tooltip = tooltip
flow3 = flow2.add({
name = name,
type = 'flow',
direction = 'vertical',
})
flow3.style.horizontal_align = 'center'
flow3.style.width = 130
flow4 = flow3.add({
name = 'switch',
type = 'switch',
switch_state = starting_position,
})
-- flow4.style.width = 80
-- flow4.style.height = 40
flow4.style.margin = 0
flow4.tooltip = tooltip
flow4 = flow3.add({
name = 'readoff_text',
type = 'label',
caption = '',
})
flow4.style.font = 'default-listbox'
flow4.style.height = 20
flow4.style.margin = 0
flow4.style.padding = 0
flow4.style.top_padding = 0
flow4.style.bottom_margin = 16
flow4.tooltip = tooltip
flow2 = flow.add({
name = name .. '_readoff_icon',
type = 'sprite-button',
enabled = false,
})
flow2.style.width = 48
flow2.style.height = 48
flow2.tooltip = tooltip
return flow2
end
function Public.toggle_window(player)
local flow, flow2, flow3, flow4, flow5, flow6, flow7
--*** OVERALL FLOW ***--
if player.gui.screen[window_name .. '_piratewindow'] then player.gui.screen[window_name .. '_piratewindow'].destroy() return end
flow = GuiCommon.new_window(player, window_name)
flow.caption = 'Play'
--*** ONGOING RUNS ***--
flow2 = GuiCommon.flow_add_section(flow, 'ongoing_runs', 'Ongoing Runs')
flow3 = flow2.add({
name = 'helpful_tip',
type = 'label',
caption = 'To join a run, first select it in the table below.',
})
flow3.style.font_color = {r=0.90, g=0.90, b=0.90}
flow3.style.single_line = false
flow3.style.maximal_width = 160
flow3 = flow2.add({
name = 'ongoing_runs_listbox',
type = 'list-box',
})
flow3.style.margin = 2
flow3.style.horizontally_stretchable = true
flow3 = flow2.add({
name = 'flow_buttons',
type = 'flow',
direction = 'horizontal',
})
flow4 = flow3.add({
name = 'join_spectators',
type = 'button',
caption = 'Spectate',
})
flow4.style.minimal_width = 95
flow4.style.font = 'default-bold'
flow4.style.font_color = {r=0.10, g=0.10, b=0.10}
flow4 = flow3.add({
name = 'join_crew',
type = 'button',
caption = 'Join Crew',
})
flow4.style.minimal_width = 95
flow4.style.font = 'default-bold'
flow4.style.font_color = {r=0.10, g=0.10, b=0.10}
flow4 = flow3.add({
name = 'leave_spectators',
type = 'button',
caption = 'Return to Lobby',
})
flow4.style.minimal_width = 95
flow4.style.font = 'default-bold'
flow4.style.font_color = {r=0.10, g=0.10, b=0.10}
flow3 = flow2.add({
name = 'wait_to_join',
type = 'label',
})
flow3.style.left_margin = 5
flow3 = flow2.add({
name = 'leaving_prompt',
type = 'label',
caption = 'Hop on board.',
})
flow3.style.left_margin = 5
-- PROPOSALS --
flow2 = GuiCommon.flow_add_section(flow, 'proposals', 'Proposals')
flow3 = flow2.add({
name = 'proposals_listbox',
type = 'list-box',
})
flow3.style.margin = 2
flow3 = flow2.add({
name = 'flow_buttons',
type = 'flow',
direction = 'horizontal',
})
flow4 = flow3.add({
name = 'endorse_proposal',
type = 'button',
caption = 'Endorse Proposal',
})
flow4.style.minimal_width = 150
flow4.style.font = 'default-bold'
flow4.style.font_color = {r=0.10, g=0.10, b=0.10}
flow4.style.bottom_margin = 9
flow4 = flow3.add({
name = 'retract_endorsement',
type = 'button',
caption = 'Retract Endorsement',
})
flow4.style.minimal_width = 150
flow4.style.font = 'default-bold'
flow4.style.font_color = {r=0.10, g=0.10, b=0.10}
flow4.style.bottom_margin = 9
flow4 = flow3.add({
name = 'abandon_proposal',
type = 'button',
caption = 'Abandon Proposal',
})
flow4.style.minimal_width = 150
flow4.style.font = 'default-bold'
flow4.style.font_color = {r=0.10, g=0.10, b=0.10}
flow4.style.bottom_margin = 9
-- PROPOSAL MAKER --
flow3 = GuiCommon.flow_add_subpanel(flow2, 'proposal_maker')
flow4 = flow3.add({
name = 'body',
type = 'flow',
direction = 'vertical',
})
flow4.style.horizontal_align = 'center'
flow4.style.vertical_align = 'center'
flow5 = flow4.add({
type = 'label',
caption = 'Run name',
})
flow5.style.font = 'heading-3'
flow5 = flow4.add({
name = 'namefield',
type = 'textfield',
caption = 'Name',
text = '',
})
flow5.style.width = 150
flow5.style.height = 24
flow5.style.top_margin = -3
flow5.style.bottom_margin = 3
flow5 = flow4.add({
name = 'options',
type = 'table',
column_count = 2,
})
flow5.style.width = 200
flow5.style.margin = 0
flow_add_proposal_slider(flow5, 'capacity', 'Capacity', #CoreData.capacity_options, 3, {'pirates.capacity_tooltip'})
-- flow_add_proposal_slider(flow5, 'difficulty', 'Difficulty', #CoreData.difficulty_options, 2, {'pirates.difficulty_tooltip'})
-- flow_add_proposal_switch(flow5, 'mode', 'Mode', 'left', {'pirates.mode_tooltip'})
-- flow5 = flow4.add({
-- name = 'proposal_cant_do_infinity_mode',
-- type = 'label',
-- caption = 'Infinity mode isn\'t available at the moment.',
-- })
-- flow5.style.single_line = false
-- flow5.style.maximal_width = 200
flow5 = flow4.add({
name = 'proposal_disabled_low_crew_caps',
type = 'label',
caption = 'This capacity setting isn\'t available at the moment.',
})
flow5.style.single_line = false
flow5.style.maximal_width = 200
flow5 = flow4.add({
name = 'propose_crew',
type = 'button',
caption = 'Propose',
})
flow4.style.minimal_width = 75
flow4.style.font = 'default-bold'
flow4.style.font_color = {r=0.10, g=0.10, b=0.10}
-- LAUNCH YOUR PROPOSAL --
flow3 = flow2.add({
name = 'flow_proposal_launch',
type = 'flow',
direction = 'vertical',
})
flow4 = flow3.add({
name = 'proposal_insufficient_endorsers',
type = 'label',
caption = 'Gather support from more pirates.',
})
flow4 = flow3.add({
name = 'proposal_insufficient_player_capacity',
type = 'label',
caption = "Can't launch; at least one run needs high player capacity.",
})
flow4 = flow3.add({
name = 'proposal_insufficient_sloops',
type = 'label',
caption = 'No sloops available. Join an existing run instead.',
})
flow4 = flow3.add({
name = 'launch_crew',
type = 'button',
caption = 'Launch run',
})
flow4.style.minimal_width = 150
flow4.style.font = 'default-bold'
flow4.style.font_color = {r=0.10, g=0.10, b=0.10}
GuiCommon.flow_add_close_button(flow, window_name .. '_piratebutton')
end
function Public.update(player)
local global_memory = Memory.get_global_memory()
local memory = Memory.get_crew_memory()
if not player.gui.screen['runs_piratewindow'] then return end
local flow = player.gui.screen['runs_piratewindow']
local playercrew_status = GuiCommon.playercrew_status_table(player.index)
if not playercrew_status then return end
--*** WHAT TO SHOW ***--
flow.ongoing_runs.visible = (#global_memory.crew_active_ids > 0)
if flow.ongoing_runs.visible then
local bool1 = (not playercrew_status.leaving) and (not playercrew_status.adventuring) and (not playercrew_status.spectating) and (flow.ongoing_runs.body.ongoing_runs_listbox.selected_index ~= 0)
local selected_joinable_bool = false
local crewid
if bool1 then
crewid = tonumber((flow.ongoing_runs.body.ongoing_runs_listbox.get_item(flow.ongoing_runs.body.ongoing_runs_listbox.selected_index))[2])
selected_joinable_bool = bool1 and crewid and (global_memory.crew_memories[crewid].crewstatus == Crew.enum.ADVENTURING)
end
flow.ongoing_runs.body.helpful_tip.visible = not (playercrew_status.leaving or playercrew_status.adventuring or playercrew_status.spectating)
flow.ongoing_runs.body.flow_buttons.visible = selected_joinable_bool or playercrew_status.spectating
flow.ongoing_runs.body.flow_buttons.join_spectators.visible = selected_joinable_bool
flow.ongoing_runs.body.flow_buttons.leave_spectators.visible = playercrew_status.spectating
flow.ongoing_runs.body.flow_buttons.join_crew.visible = selected_joinable_bool and (not (crewid and global_memory.crew_memories[crewid] and (global_memory.crew_memories[crewid].crewstatus == Crew.enum.LEAVING_INITIAL_DOCK or #global_memory.crew_memories[crewid].crewplayerindices >= global_memory.crew_memories[crewid].capacity or (global_memory.crew_memories[crewid].tempbanned_from_joining_data and global_memory.crew_memories[crewid].tempbanned_from_joining_data[player.index] and game.tick < global_memory.crew_memories[crewid].tempbanned_from_joining_data[player.index] + Common.ban_from_rejoining_crew_ticks))))
flow.ongoing_runs.body.wait_to_join.visible = selected_joinable_bool and crewid and global_memory.crew_memories[crewid] and (global_memory.crew_memories[crewid].tempbanned_from_joining_data and global_memory.crew_memories[crewid].tempbanned_from_joining_data[player.index] and game.tick < global_memory.crew_memories[crewid].tempbanned_from_joining_data[player.index] + Common.ban_from_rejoining_crew_ticks) and (not (global_memory.crew_memories[crewid].crewstatus == Crew.enum.LEAVING_INITIAL_DOCK or #global_memory.crew_memories[crewid].crewplayerindices >= global_memory.crew_memories[crewid].capacity))
if flow.ongoing_runs.body.wait_to_join.visible then
flow.ongoing_runs.body.wait_to_join.caption = 'Wait to join... ' .. Math.ceil(((global_memory.crew_memories[crewid].tempbanned_from_joining_data[player.index] - (game.tick - Common.ban_from_rejoining_crew_ticks)))/60)
end
if not selected_joinable_bool then flow.ongoing_runs.body.ongoing_runs_listbox.selected_index = 0 end
flow.ongoing_runs.body.leaving_prompt.visible = playercrew_status.leaving
end
flow.proposals.visible = (memory.crewstatus == nil and not playercrew_status.leaving)
if flow.proposals.visible then
if playercrew_status.proposing then
flow.proposals.body.proposals_listbox.selected_index = 0
flow.proposals.body.proposals_listbox.selected_index = 0
end
flow.proposals.body.proposals_listbox.visible = (not playercrew_status.leaving) and (#global_memory.crewproposals > 0)
flow.proposals.body.flow_buttons.endorse_proposal.visible = (not playercrew_status.leaving) and (not playercrew_status.endorsing) and (#global_memory.crewproposals > 0) and flow.proposals.body.proposals_listbox.selected_index ~= 0
flow.proposals.body.flow_buttons.abandon_proposal.visible = (not playercrew_status.leaving) and playercrew_status.endorsing and playercrew_status.endorsing and playercrew_status.proposing and (#global_memory.crewproposals > 0)
flow.proposals.body.flow_buttons.retract_endorsement.visible = (not playercrew_status.leaving) and playercrew_status.endorsing and (not playercrew_status.proposing) and (#global_memory.crewproposals > 0)
flow.proposals.body.proposal_maker.visible = (not playercrew_status.leaving) and (not playercrew_status.endorsing)
flow.proposals.body.flow_proposal_launch.proposal_insufficient_sloops.visible = playercrew_status.sloops_full
flow.proposals.body.flow_proposal_launch.proposal_insufficient_player_capacity.visible = playercrew_status.needs_more_capacity
flow.proposals.body.flow_proposal_launch.proposal_insufficient_endorsers.visible = playercrew_status.needs_more_endorsers
-- flow.proposals.body.proposal_maker.body.proposal_cant_do_infinity_mode.visible = (flow.proposals.body.proposal_maker.body.options.mode.mode.switch.switch_state == 'right')
-- flow.proposals.body.proposal_maker.body.proposal_disabled_low_crew_caps.visible = false
flow.proposals.body.proposal_maker.body.proposal_disabled_low_crew_caps.visible = (flow.proposals.body.proposal_maker.body.options.capacity.capacity.slider.slider_value < global_memory.minimum_capacity_slider_value)
flow.proposals.body.proposal_maker.body.propose_crew.visible = (flow.proposals.body.proposal_maker.body.proposal_disabled_low_crew_caps.visible == false)
-- flow.proposals.body.proposal_maker.body.propose_crew.visible = (flow.proposals.body.proposal_maker.body.proposal_cant_do_infinity_mode.visible == false) and (flow.proposals.body.proposal_maker.body.proposal_disabled_low_crew_caps.visible == false)
flow.proposals.body.flow_proposal_launch.launch_crew.visible = (playercrew_status.proposing and not (playercrew_status.sloops_full or playercrew_status.needs_more_capacity or playercrew_status.needs_more_endorsers))
end
--*** UPDATE CONTENT ***--
if flow.ongoing_runs.visible then
local wrappedmemories = {}
for _, mem in pairs(global_memory.crew_memories) do
local count = 0
if mem.crewstatus and mem.crewstatus == Crew.enum.LEAVING_INITIAL_DOCK then
count = Boats.players_on_boat_count(mem.boat)
elseif mem.crewplayerindices then
count = #mem.crewplayerindices
end
wrappedmemories[#wrappedmemories + 1] = {'pirates.run_displayform', mem.id, mem.name .. ', ' .. CoreData.difficulty_options[mem.difficulty_option].text .. ', [item=light-armor]' .. count .. CoreData.capacity_options[mem.capacity_option].text2 .. ', [item=rail] ' .. (mem.overworldx or 0)}
-- wrappedmemories[#wrappedmemories + 1] = {'pirates.run_displayform', mem.id, mem.name, Utils.spritepath_to_richtext(CoreData.difficulty_options[mem.difficulty_option].icon), count, CoreData.capacity_options[mem.capacity_option].text2, ' [item=rail] ', mem.overworldx or 0}
end
GuiCommon.update_listbox(flow.ongoing_runs.body.ongoing_runs_listbox, wrappedmemories)
end
if flow.proposals.visible then
local wrappedproposals = {}
for _, proposal in pairs(global_memory.crewproposals) do
wrappedproposals[#wrappedproposals + 1] = {'pirates.proposal_displayform', proposal.name, Utils.spritepath_to_richtext(CoreData.capacity_options[proposal.capacity_option].icon)}
-- wrappedproposals[#wrappedproposals + 1] = {'pirates.proposal_displayform', proposal.name, Utils.spritepath_to_richtext(CoreData.difficulty_options[proposal.difficulty_option].icon), Utils.spritepath_to_richtext(CoreData.capacity_options[proposal.capacity_option].icon)}
end
GuiCommon.update_listbox(flow.proposals.body.proposals_listbox, wrappedproposals)
end
-- update proposal maker
if flow.proposals.body.proposal_maker.visible then
local capacity_slider_value = flow.proposals.body.proposal_maker.body.options.capacity.capacity.slider.slider_value
for i, opt in pairs(CoreData.capacity_options) do
if capacity_slider_value == i then
flow.proposals.body.proposal_maker.body.options.capacity.capacity.readoff_text.caption = opt.text
flow.proposals.body.proposal_maker.body.options.capacity_readoff_icon.sprite = opt.icon
end
end
if flow.proposals.body.proposal_maker.body.options.capacity.capacity.readoff_text.caption == '' then flow.proposals.body.proposal_maker.body.options.capacity.capacity.readoff_text.caption = 'No limit' end
-- local difficulty_slider_value = flow.proposals.body.proposal_maker.body.options.difficulty.difficulty.slider.slider_value
-- for i, opt in pairs(CoreData.difficulty_options) do
-- if difficulty_slider_value == i then
-- flow.proposals.body.proposal_maker.body.options.difficulty.difficulty.readoff_text.caption = opt.text
-- flow.proposals.body.proposal_maker.body.options.difficulty_readoff_icon.sprite = opt.icon
-- end
-- end
-- local mode_switch_state = flow.proposals.body.proposal_maker.body.options.mode.mode.switch.switch_state
-- for i, opt in pairs(CoreData.mode_options) do
-- if mode_switch_state == i then
-- flow.proposals.body.proposal_maker.body.options.mode.mode.readoff_text.caption = opt.text
-- flow.proposals.body.proposal_maker.body.options.mode_readoff_icon.sprite = opt.icon
-- end
-- end
end
end
function Public.click(event)
local player = game.players[event.element.player_index]
local eventname = event.element.name
if not player.gui.screen[window_name .. '_piratewindow'] then return end
local flow = player.gui.screen[window_name .. '_piratewindow']
local global_memory = Memory.get_global_memory()
local memory = Memory.get_crew_memory()
if eventname == 'join_spectators' then
local listbox = flow.ongoing_runs.body.ongoing_runs_listbox
Crew.join_spectators(player, tonumber(listbox.get_item(listbox.selected_index)[2]))
return
end
if eventname == 'leave_spectators' then
Crew.leave_spectators(player)
return
end
if eventname == 'join_crew' then
local listbox = flow.ongoing_runs.body.ongoing_runs_listbox
Crew.join_crew(player, tonumber(listbox.get_item(listbox.selected_index)[2]))
return
end
if eventname == 'propose_crew' then
local proposal_name = flow.proposals.body.proposal_maker.body.namefield.text
-- local proposal_name = string.sub(flow.proposals.body.proposal_maker.body.namefield.text, 1, 30)
local capacity_option = flow.proposals.body.proposal_maker.body.options.capacity.capacity.slider.slider_value
local difficulty_option = 2
-- local difficulty_option = flow.proposals.body.proposal_maker.body.options.difficulty.difficulty.slider.slider_value
-- local mode_option = flow.proposals.body.proposal_maker.body.options.mode.mode.switch.switch_state
if (not proposal_name) or (proposal_name == '') then proposal_name = 'NoName' end
-- make name unique
-- local unique, changed = true, false
-- local check_unique = function(name)
-- unique = true
-- for _, proposal in pairs(global_memory.crewproposals) do
-- if name == proposal.name then
-- unique = false
-- changed = true
-- break
-- end
-- end
-- end
-- local i = 0
-- check_unique()
-- while i < 10 and not unique do
-- check_unique(proposal_name .. i)
-- i = i + 1
-- end
-- if not unique then return end
-- if changed then proposal_name = proposal_name .. i end
local unique = true
for _, proposal in pairs(global_memory.crewproposals) do
if proposal_name == proposal.name then
unique = false
break
end
end
if not unique then return end
local proposal = {
name = proposal_name,
difficulty_option = difficulty_option,
capacity_option = capacity_option,
-- mode_option = mode_option,
endorserindices = {player.index},
}
global_memory.crewproposals[#global_memory.crewproposals + 1] = proposal
local message = player.name .. ' proposed the run ' .. proposal_name .. ' (capacity ' .. CoreData.capacity_options[capacity_option].text3 .. ').'
-- local message = player.name .. ' proposed the run ' .. proposal_name .. ' (difficulty ' .. CoreData.difficulty_options[difficulty_option].text .. ', capacity ' .. CoreData.capacity_options[capacity_option].text3 .. ').'
Common.notify_lobby(message)
return
end
if eventname == 'endorse_proposal' then
local lb = flow.proposals.body.proposals_listbox
local index = lb.selected_index
if index ~= 0 then
local name2 = lb.get_item(lb.selected_index)[2]
for _, proposal in pairs(global_memory.crewproposals) do
if proposal.name == name2 and #proposal.endorserindices < CoreData.capacity_options[proposal.capacity_option].value then
proposal.endorserindices[#proposal.endorserindices + 1] = player.index
end
end
end
return
end
if eventname == 'abandon_proposal' then
Crew.player_abandon_proposal(player)
Crew.player_abandon_endorsements(player)
return
end
if eventname == 'retract_endorsement' then
Crew.player_abandon_endorsements(player)
return
end
if eventname == 'launch_crew' then
for k, proposal in pairs(global_memory.crewproposals) do
if #global_memory.crew_active_ids < global_memory.active_crews_cap then
if #proposal.endorserindices > 0 and proposal.endorserindices[1] == player.index then
Crew.initialise_crew(proposal)
global_memory.crewproposals[k] = nil
Progression.set_off_from_starting_dock()
return
end
else
Common.notify_player(player, 'The number of concurrent runs on the server is currently capped at ' .. global_memory.active_crews_cap .. '.')
end
end
end
end
return Public

167
maps/pirates/gui/shop.lua Normal file
View File

@@ -0,0 +1,167 @@
local Memory = require 'maps.pirates.memory'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Roles = require 'maps.pirates.roles.roles'
local Crew = require 'maps.pirates.crew'
local Shop = require 'maps.pirates.shop.shop'
local Progression = require 'maps.pirates.progression'
local Structures = require 'maps.pirates.structures.structures'
local inspect = require 'utils.inspect'.inspect
local Boats = require 'maps.pirates.structures.boats.boats'
local GuiCommon = require 'maps.pirates.gui.common'
local Public = {}
local window_name = 'shop'
function Public.toggle_window(player)
local flow, flow2, flow3, flow4, flow5, flow6
local shop_data_1 = Shop.main_shop_data_1
local shop_data_2 = Shop.main_shop_data_2
if player.gui.screen[window_name .. '_piratewindow'] then player.gui.screen[window_name .. '_piratewindow'].destroy() return end
flow = GuiCommon.new_window(player, window_name)
flow.caption = 'Shop'
flow2 = flow.add({
name = 'trades',
type = 'flow',
direction = 'vertical',
})
flow2.style.top_margin = 3
flow2.style.bottom_margin = 3
flow2.style.horizontal_align = 'center'
flow2.style.vertical_align = 'center'
for k, _ in pairs(shop_data_1) do
flow3 = GuiCommon.flow_add_shop_item(flow2, k)
end
flow3 = flow2.add({
name = 'line_1',
type = 'line',
})
flow3.style.width = 100
for k, _ in pairs(shop_data_2) do
flow3 = GuiCommon.flow_add_shop_item(flow2, k)
end
flow2 = GuiCommon.flow_add_close_button(flow, window_name .. '_piratebutton')
flow3 = flow2.add({
name = 'tospend',
type = 'sprite-button',
sprite = 'item/sulfur',
index = 1,
enabled = false,
})
end
function Public.update(player)
local flow, flow2, flow3, flow4, flow5, flow6
local memory = Memory.get_crew_memory()
local shop_data = Utils.nonrepeating_join_dict(Shop.main_shop_data_1, Shop.main_shop_data_2)
local shop_data_1 = Shop.main_shop_data_1
local shop_data_2 = Shop.main_shop_data_2
local availability_data = memory.mainshop_availability_bools
if not player.gui.screen[window_name .. '_piratewindow'] then return end
flow = player.gui.screen[window_name .. '_piratewindow']
--*** WHAT TO SHOW ***--
if memory.gold then
flow.close_button_flow.hflow.tospend.number = memory.gold
flow.close_button_flow.hflow.tospend.tooltip = string.format('The crew has %01d gold.', memory.gold)
else
flow.close_button_flow.hflow.tospend.number = 0
flow.close_button_flow.hflow.tospend.tooltip = string.format('The crew has %01d gold.', 0)
end
if memory.crewstatus == Crew.enum.ADVENTURING then
flow.trades.visible = true
else
flow.trades.visible = false
end
local anything_in_shop_1 = false
for k, _ in pairs(shop_data_1) do
if availability_data and availability_data[k] == true then
flow.trades[k].visible = true
anything_in_shop_1 = true
if player.index == memory.playerindex_captain then
flow.trades[k].buy_button.visible = true
else
flow.trades[k].buy_button.visible = false
end
else
flow.trades[k].visible = false
end
end
flow.trades.line_1.visible = anything_in_shop_1
for k, _ in pairs(shop_data_2) do
if availability_data and availability_data[k] == true then
flow.trades[k].visible = true
if player.index == memory.playerindex_captain then
flow.trades[k].buy_button.visible = true
else
flow.trades[k].buy_button.visible = false
end
else
flow.trades[k].visible = false
end
end
--*** UPDATE CONTENT ***--
local multiplier = Balance.main_shop_cost_multiplier()
for k, v in pairs(shop_data) do
for k2, v2 in pairs(v.base_cost) do
if v2 == false then
flow.trades[k]['cost_' .. k2].number = nil
else
flow.trades[k]['cost_' .. k2].number = multiplier * v2
end
end
end
end
function Public.click(event)
local player = game.players[event.element.player_index]
local eventname = event.element.name
if not player.gui.screen[window_name .. '_piratewindow'] then return end
local flow = player.gui.screen[window_name .. '_piratewindow']
local memory = Memory.get_crew_memory()
if eventname == 'buy_button' then
Shop.main_shop_try_purchase(event.element.parent.name)
end
end
return Public

558
maps/pirates/highscore.lua Normal file
View File

@@ -0,0 +1,558 @@
-- Adapted from mountain_fortress_v3 highscores.lua
local Event = require 'utils.event'
local Global = require 'utils.global'
local Server = require 'utils.server'
local Math = require 'maps.pirates.math'
local Token = require 'utils.token'
local Tabs = require 'comfy_panel.main'
local Core = require 'utils.core'
local inspect = require 'utils.inspect'.inspect
local SpamProtection = require 'utils.spam_protection'
local Memory = require 'maps.pirates.memory'
local Utils = require 'maps.pirates.utils_local'
local module_name = 'Highscore'
local score_dataset = 'highscores'
local score_key = 'pirate_ship_scores'
local score_key_debug = 'pirate_ship_scores_debug'
local score_key_modded = 'pirate_ship_scores_modded'
local Public = {}
local insert = table.insert
local this = {
score_table = {player = {}},
sort_by = {}
}
Global.register(
this,
function(t)
this = t
end
)
local function sort_list(method, column_name, score_list)
local comparators = {
['ascending'] = function(a, b)
return a[column_name] < b[column_name]
end,
['descending'] = function(a, b)
return a[column_name] > b[column_name]
end
}
Utils.stable_sort(score_list, comparators[method])
-- table.sort(score_list, comparators[method])
return score_list
end
local function saved_scores_trim(scores)
-- the goal here is to trim away highscores so we don't have too many.
local completion_times = {}
local leagues_travelled = {}
local completion_times_mediump_latestv = {}
local leagues_travelled_mediump_latestv = {}
local completion_times_hard = {}
local leagues_travelled_hard = {}
local completion_times_nightmare = {}
local leagues_travelled_nightmare = {}
local completion_times_latestv = {}
local leagues_travelled_latestv = {}
local versions = {}
for _, score in pairs(scores) do
if score.version and score.version > 0 then
versions[#versions + 1] = score.version
end
if score.completion_time and score.completion_time > 0 then
completion_times[#completion_times + 1] = score.completion_time
end
if score.leagues_travelled and score.leagues_travelled > 0 then
leagues_travelled[#leagues_travelled + 1] = score.leagues_travelled
end
if score.difficulty and score.difficulty >= 1.5 then
if score.completion_time and score.completion_time > 0 then
completion_times_hard[#completion_times_hard + 1] = score.completion_time
end
if score.leagues_travelled and score.leagues_travelled > 0 then
leagues_travelled_hard[#leagues_travelled_hard + 1] = score.leagues_travelled
end
end
if score.difficulty and score.difficulty >= 3 then
if score.completion_time and score.completion_time > 0 then
completion_times_nightmare[#completion_times_nightmare + 1] = score.completion_time
end
if score.leagues_travelled and score.leagues_travelled > 0 then
leagues_travelled_nightmare[#leagues_travelled_nightmare + 1] = score.leagues_travelled
end
end
end
local latest_version = 0
for _, v in pairs(versions) do
if v > latest_version then latest_version = v end
end
for _, score in pairs(scores) do
if score.version and score.version == latest_version then
if score.completion_time and score.completion_time > 0 then
completion_times_latestv[#completion_times_latestv + 1] = score.completion_time
end
if score.leagues_travelled and score.leagues_travelled > 0 then
leagues_travelled_latestv[#leagues_travelled_latestv + 1] = score.leagues_travelled
end
if score.difficulty and score.difficulty >= 1 then
if score.completion_time and score.completion_time > 0 then
completion_times_mediump_latestv[#completion_times_mediump_latestv + 1] = score.completion_time
end
if score.leagues_travelled and score.leagues_travelled > 0 then
leagues_travelled_mediump_latestv[#leagues_travelled_mediump_latestv + 1] = score.leagues_travelled
end
end
end
end
table.sort(completion_times)
table.sort(leagues_travelled)
table.sort(completion_times_mediump_latestv)
table.sort(leagues_travelled_mediump_latestv)
table.sort(completion_times_hard)
table.sort(leagues_travelled_hard)
table.sort(completion_times_nightmare)
table.sort(leagues_travelled_nightmare)
table.sort(completion_times_latestv)
table.sort(leagues_travelled_latestv)
local completion_times_cutoff = #completion_times > 8 and completion_times[8] or 9999999
local completion_times_mediump_latestv_cutoff = #completion_times_mediump_latestv > 5 and completion_times_mediump_latestv[5] or 9999999
local completion_times_hard_cutoff = #completion_times_hard > 5 and completion_times_hard[5] or 9999999
local completion_times_nightmare_cutoff = #completion_times_hard > 3 and completion_times_hard[3] or 9999999
local completion_times_latestv_cutoff = #completion_times_latestv > 8 and completion_times_latestv[8] or 9999999
local leagues_travelled_cutoff = #leagues_travelled > 8 and leagues_travelled[-8] or 0
local leagues_travelled_mediump_latestv_cutoff = #leagues_travelled_mediump_latestv > 5 and leagues_travelled_mediump_latestv[-5] or 0
local leagues_travelled_hard_cutoff = #leagues_travelled_hard > 5 and leagues_travelled_hard[-5] or 0
local leagues_travelled_nightmare_cutoff = #leagues_travelled_hard > 3 and leagues_travelled_hard[-3] or 0
local leagues_travelled_latestv_cutoff = #leagues_travelled_latestv > 8 and leagues_travelled_latestv[-8] or 0
-- log(inspect{completion_times_cutoff,completion_times_mediump_latestv_cutoff,completion_times_hard_cutoff,completion_times_latestv_cutoff,leagues_travelled_cutoff,leagues_travelled_mediump_latestv_cutoff,leagues_travelled_hard_cutoff,leagues_travelled_latestv_cutoff})
local delete = {}
for secs_id, score in pairs(scores) do
local include = false
if completion_times_cutoff and score.completion_time and score.completion_time < completion_times_cutoff then include = true
elseif completion_times_mediump_latestv_cutoff and score.completion_time and score.completion_time < completion_times_mediump_latestv_cutoff and score.version == latest_version and score.difficulty >= 1 then include = true
elseif completion_times_hard_cutoff and score.completion_time and score.completion_time < completion_times_hard_cutoff and score.difficulty >= 1.5 then include = true
elseif completion_times_nightmare_cutoff and score.completion_time and score.completion_time < completion_times_nightmare_cutoff and score.difficulty >=3 then include = true
elseif completion_times_latestv_cutoff and score.completion_time and score.completion_time < completion_times_latestv_cutoff and score.version == latest_version then include = true
elseif leagues_travelled_cutoff and score.leagues_travelled and score.leagues_travelled > leagues_travelled_cutoff then include = true
elseif leagues_travelled_mediump_latestv_cutoff and score.leagues_travelled and score.leagues_travelled > leagues_travelled_mediump_latestv_cutoff and score.version == latest_version and score.difficulty >= 1 then include = true
elseif leagues_travelled_hard_cutoff and score.leagues_travelled and score.leagues_travelled > leagues_travelled_hard_cutoff and score.difficulty >= 1.5 then include = true
elseif leagues_travelled_nightmare_cutoff and score.leagues_travelled and score.leagues_travelled > leagues_travelled_nightmare_cutoff and score.difficulty >= 3 then include = true
elseif leagues_travelled_latestv_cutoff and score.leagues_travelled and score.leagues_travelled > leagues_travelled_latestv_cutoff and score.version == latest_version then include = true
end
if not include then delete[#delete + 1] = secs_id end
end
-- log(inspect(delete))
for _, secs_id in pairs(delete) do
scores[secs_id] = nil
end
return scores
end
local function local_highscores_write_stats(crew_secs_id, name, captain_name, completion_time, leagues_travelled, version, difficulty, capacity)
if not this.score_table['player'] then this.score_table['player'] = {} end
if not this.score_table['player'].runs then this.score_table['player'].runs = {} end
local t = this.score_table['player']
if t then
-- if name then
-- t.name = name
-- end
-- if version then
-- t.version = version
-- end
-- if completion_time then
-- t.completion_time = completion_time
-- end
-- if leagues_travelled then
-- t.leagues_travelled = leagues_travelled
-- end
-- if difficulty then
-- t.difficulty = difficulty
-- end
-- if capacity then
-- t.capacity = capacity
-- end
if crew_secs_id then
t.runs[crew_secs_id] = {name = name, captain_name = captain_name, version = version, completion_time = completion_time, leagues_travelled = leagues_travelled, difficulty = difficulty, capacity = capacity}
-- log(inspect(t))
saved_scores_trim(t.runs)
end
end
this.score_table['player'] = t
-- log(inspect(t))
end
local load_in_scores =
Token.register(
function(data)
local value = data.value
if not this.score_table['player'] then
this.score_table['player'] = {}
end
this.score_table['player'] = value
end
)
function Public.load_in_scores()
local secs = Server.get_current_time()
-- if secs then game.print('secs2: ' .. secs) else game.print('secs: false') end
if not secs then
return
else
-- FULL CLEAN task (erases everything...):
-- server_set_data(score_dataset, score_key, {})
if is_game_modded() then
Server.try_get_data(score_dataset, score_key_modded, load_in_scores)
elseif _DEBUG then
Server.try_get_data(score_dataset, score_key_debug, load_in_scores)
else
Server.try_get_data(score_dataset, score_key, load_in_scores)
end
end
end
function Public.write_score(crew_secs_id, name, captain_name, completion_time, leagues_travelled, version, difficulty, capacity)
local secs = Server.get_current_time()
-- if secs then game.print('secs1: ' .. secs) else game.print('secs: false') end
if not secs then
return
else
local_highscores_write_stats(crew_secs_id, name, captain_name, completion_time, leagues_travelled, version, difficulty, capacity)
if is_game_modded() then
Server.set_data(score_dataset, score_key_modded, this.score_table['player'])
elseif _DEBUG then
Server.set_data(score_dataset, score_key_debug, this.score_table['player'])
else
Server.set_data(score_dataset, score_key, this.score_table['player'])
end
end
end
local function on_init()
local secs = Server.get_current_time()
if not secs then
local_highscores_write_stats() --just to init tables presumably
return
end
end
local sorting_symbol = {ascending = '', descending = ''}
local function get_saved_scores_for_displaying()
local score_data = this.score_table['player']
local score_list = {}
if score_data and score_data.runs then
for _, score in pairs(score_data.runs or {}) do
insert(
score_list,
{
name = score and score.name,
captain_name = score and score.captain_name,
completion_time = score and score.completion_time or 99999,
leagues_travelled = score and score.leagues_travelled or 0,
version = score and score.version or 0,
difficulty = score and score.difficulty or 0,
capacity = score and score.capacity or 0,
}
)
end
else
score_list[#score_list + 1] = {
name = 'Nothing here yet',
captain_name = '',
completion_time = 0,
leagues_travelled = 0,
version = 0,
difficulty = 0,
capacity = 0,
}
end
return score_list
end
local function score_gui(data)
local player = data.player
local frame = data.frame
frame.clear()
local columnwidth = 96
-- local flow = frame.add {type = 'flow'}
-- local sFlow = flow.style
-- sFlow.horizontally_stretchable = true
-- sFlow.horizontal_align = 'center'
-- sFlow.vertical_align = 'center'
-- local stats = flow.add {type = 'label', caption = 'Highest score so far:'}
-- local s_stats = stats.style
-- s_stats.font = 'heading-1'
-- s_stats.font_color = {r = 0.98, g = 0.66, b = 0.22}
-- s_stats.horizontal_align = 'center'
-- s_stats.vertical_align = 'center'
-- -- Global stats : rockets, biters kills
-- add_global_stats(frame)
-- -- Separator
-- local line = frame.add {type = 'line'}
-- line.style.top_margin = 8
-- line.style.bottom_margin = 8
-- Score per player
local t = frame.add {type = 'table', column_count = 7}
-- Score headers
local headers = {
{name = '_name', caption = 'Crew'},
{name = '_captain_name', caption = 'Captain'},
{column = 'completion_time', name = '_completion_time', caption = 'Completion'},
{column = 'leagues_travelled', name = '_leagues_travelled', caption = 'Leagues'},
{column = 'version', name = '_version', caption = 'Version'},
{column = 'difficulty', name = '_difficulty', caption = 'Difficulty'},
{column = 'capacity', name = '_capacity', caption = 'Capacity'},
}
local sorting_pref = this.sort_by[player.index] or {}
for _, header in ipairs(headers) do
local cap = header.caption
log(header.caption)
-- Add sorting symbol if any
if header.column and sorting_pref[1] and sorting_pref[1].column == header.column then
local symbol = sorting_symbol[sorting_pref[1].method]
cap = symbol .. cap
end
-- Header
local label =
t.add {
type = 'label',
caption = cap,
name = header.name
}
label.style.font = 'default-listbox'
label.style.font_color = {r = 0.98, g = 0.66, b = 0.22} -- yellow
label.style.minimal_width = columnwidth
label.style.horizontal_align = 'right'
end
-- Score list
local score_list = get_saved_scores_for_displaying()
-- log(inspect(score_list))
for i = #sorting_pref, 1, -1 do
local sort = sorting_pref[i]
if sort then
score_list = sort_list(sort.method, sort.column, score_list)
end
end
-- New pane for scores (while keeping headers at same position)
local scroll_pane =
frame.add(
{
type = 'scroll-pane',
name = 'score_scroll_pane',
direction = 'vertical',
horizontal_scroll_policy = 'never',
vertical_scroll_policy = 'auto'
}
)
scroll_pane.style.maximal_height = 400
t = scroll_pane.add {type = 'table', column_count = 7}
-- Score entries
for _, entry in pairs(score_list) do
local p = {color = {r = Math.random(1, 255), g = Math.random(1, 255), b = Math.random(1, 255)}}
-- local p
-- if not (entry and entry.name) then
-- p = {color = {r = random(1, 255), g = random(1, 255), b = random(1, 255)}}
-- else
-- p = game.players[entry.name]
-- if not p then
-- p = {color = {r = random(1, 255), g = random(1, 255), b = random(1, 255)}}
-- end
-- end
local special_color = {
r = p.color.r * 0.6 + 0.4,
g = p.color.g * 0.6 + 0.4,
b = p.color.b * 0.6 + 0.4,
a = 1,
}
local n = entry.completion_time > 0 and Utils.time_mediumform(entry.completion_time or 0) or 'N/A'
local l = entry.leagues_travelled > 0 and entry.leagues_travelled or 'N/A'
local v = entry.version > 0 and entry.version or 'N/A'
local d = entry.difficulty > 0 and entry.difficulty or 'N/A'
local c = entry.capacity > 0 and entry.capacity or 'N/A'
local line = {
{caption = entry.name, color = special_color},
{caption = entry.captain_name or '?'},
{caption = tostring(n)},
{caption = tostring(l)},
{caption = tostring(v)},
{caption = tostring(d)},
{caption = tostring(c)},
}
local default_color = {r = 0.9, g = 0.9, b = 0.9}
for _, column in ipairs(line) do
local label =
t.add {
type = 'label',
caption = column.caption,
color = column.color or default_color,
}
label.style.font = 'default'
label.style.minimal_width = columnwidth
label.style.maximal_width = columnwidth
label.style.horizontal_align = 'right'
end -- foreach column
end -- foreach entry
end
local score_gui_token = Token.register(score_gui)
local function on_gui_click(event)
if not event then
return
end
if not event.element then
return
end
if not event.element.valid then
return
end
local player = game.players[event.element.player_index]
local frame = Tabs.comfy_panel_get_active_frame(player)
if not frame then
return
end
if frame.name ~= module_name then
return
end
local is_spamming = SpamProtection.is_spamming(player, nil, 'HighScore Gui Click')
if is_spamming then
return
end
local name = event.element.name
-- Handles click on a score header
local element_to_column = {
['_version'] = 'version',
['_completion_time'] = 'completion_time',
['_leagues_travelled'] = 'leagues_travelled',
['_difficulty'] = 'difficulty',
['_capacity'] = 'capacity',
}
local column = element_to_column[name]
if column then
--@TODO: Extend
local sorting_pref = this.sort_by[player.index]
local found = false
local new_method = 'descending'
for i, sort in ipairs(sorting_pref) do
if sort.column == column.column then
found = true
if sort.method == 'descending' then new_method = 'ascending' end
end
end
if found then
--remove this and shuffle everything before it up by 1:
for j = i, 2, -1 do
sorting_pref[j] = Utils.deepcopy(sorting_pref[j-1]) --deepcopy just as I'm slightly unsure about refernces here
end
else
--prepend:
for j = #sorting_pref + 1, 2, -1 do
sorting_pref[j] = Utils.deepcopy(sorting_pref[j-1]) --deepcopy just as I'm slightly unsure about refernces here
end
end
sorting_pref[1] = {column = column, method = new_method}
score_gui({player = player, frame = frame})
return
end
end
local function on_player_joined_game(event)
local player = game.players[event.player_index]
if player.index and this.sort_by and (not this.sort_by[player.index]) then
this.sort_by[player.index] = {{method = 'ascending', column = 'completion_time'}, {method = 'descending', column = 'leagues_travelled'}, {method = 'descending', column = 'version'}, {method = 'descending', column = 'difficulty'}}
end
end
local function on_player_left_game(event)
local player = game.players[event.player_index]
if this.sort_by[player.index] then
this.sort_by[player.index] = nil
end
end
Server.on_data_set_changed(
score_dataset,
function(data)
local key
if is_game_modded() then
key = score_key_modded
elseif _DEBUG then
key = score_key_debug
else
key = score_key
end
if data.key == key then
if data.value then
this.score_table['player'] = data.value
end
end
end
)
Tabs.add_tab_to_gui({name = module_name, id = score_gui_token, admin = false, only_server_sided = false})
Event.on_init(on_init)
Event.add(defines.events.on_player_left_game, on_player_left_game)
Event.add(defines.events.on_player_joined_game, on_player_joined_game)
Event.add(defines.events.on_gui_click, on_gui_click)
Event.add(Server.events.on_server_started, Public.load_in_scores)
return Public

BIN
maps/pirates/images/.DS_Store vendored Normal file

Binary file not shown.

1430
maps/pirates/interface.lua Normal file

File diff suppressed because it is too large Load Diff

338
maps/pirates/loot.lua Normal file
View File

@@ -0,0 +1,338 @@
local Math = require 'maps.pirates.math'
local Memory = require 'maps.pirates.memory'
local Balance = require 'maps.pirates.balance'
local CoreData = require 'maps.pirates.coredata'
local Common = require 'maps.pirates.common'
local inspect = require 'utils.inspect'.inspect
local Public = {}
-- @TODO: rewrite in terms of more sensible raffle
function Public.buried_treasure_loot()
local ret
local rng = Math.random(1000)
if rng <= 150 then
ret = {name = 'steel-plate', count = 150}
elseif rng <= 200 then
ret = {name = 'construction-robot', count = 15}
elseif rng <= 330 then
ret = {name = 'electronic-circuit', count = 150}
elseif rng <= 400 then
ret = {name = 'advanced-circuit', count = 40}
elseif rng <= 530 then
ret = {name = 'crude-oil-barrel', count = 10}
elseif rng <= 600 then
ret = {name = 'effectivity-module-3', count = 3}
elseif rng <= 730 then
ret = {name = 'effectivity-module-2', count = 6}
elseif rng <= 800 then
ret = {name = 'plastic-bar', count = 60}
elseif rng <= 860 then
ret = {name = 'chemical-science-pack', count = 15}
elseif rng <= 930 then
ret = {name = 'assembling-machine-3', count = 2}
elseif rng <= 995 then
ret = {name = 'solar-panel', count = 7}
else
ret = {name = 'modular-armor', count = 1}
end
return ret
end
Public.chest_loot_data_raw = {
-- pirate-ship specific loot, which dominates:
{20, -1, 0.5, true, 'splitter', 4, 12},
-- {20, -1, 0.5, true, 'underground-belt', 4, 12},
{40, -0.5, 0.5, true, 'firearm-magazine', 10, 48},
{60, -1, 1, true, 'piercing-rounds-magazine', 4, 16},
{20, 0, 1, false, 'assembling-machine-2', 1, 3},
{20, 0, 1, false, 'solar-panel', 2, 5},
{40, -1, 1, true, 'speed-module', 1, 3},
{40, 0, 1, true, 'speed-module-2', 1, 3},
{40, 0, 2, true, 'speed-module-3', 1, 3},
{4, -1, 1, true, 'effectivity-module', 1, 3},
{4, 0, 1, true, 'effectivity-module-2', 1, 3},
{4, 0, 2, true, 'effectivity-module-3', 1, 3},
{10, 0, 1, false, 'uranium-rounds-magazine', 3, 6},
{10, 0, 1, false, 'fast-transport-belt', 6, 24},
-- {10, 0, 1, false, 'fast-underground-belt', 2, 5},
{10, 0, 1, false, 'fast-splitter', 2, 5},
{12, 0, 1, false, 'artillery-shell', 1, 1},
{40, 0, 1, false, 'rail-signal', 10, 30},
{40, 0, 1, false, 'medium-electric-pole', 2, 5},
{2, 0.2, 1, false, 'electric-engine-unit', 1, 1},
{4, 0, 2, true, 'rocket-launcher', 1, 1},
{8, 0, 2, true, 'rocket', 16, 32},
-- copying over most of those i made for chronotrain:
--always there (or normally always there):
{4, 0, 1, false, 'pistol', 1, 2},
{1, 0, 1, false, 'gun-turret', 2, 4},
{6, 0, 1, false, 'grenade', 2, 12},
{4, 0, 1, false, 'stone-wall', 12, 50},
-- {4, 0, 1, false, 'gate', 14, 32}, --can beat biters with them
{1, 0, 1, false, 'radar', 1, 2},
{3, 0, 1, false, 'small-lamp', 8, 32},
{2, 0, 1, false, 'electric-mining-drill', 2, 4},
{3, 0, 1, false, 'long-handed-inserter', 4, 16},
{0.5, 0, 1, false, 'filter-inserter', 2, 12},
{0.2, 0, 1, false, 'stack-filter-inserter', 2, 6},
{0.2, 0, 1, false, 'slowdown-capsule', 2, 4},
{0.2, 0, 1, false, 'destroyer-capsule', 2, 4},
{0.2, 0, 1, false, 'defender-capsule', 2, 4},
{0.2, 0, 1, false, 'distractor-capsule', 2, 4},
-- {0.25, 0, 1, false, 'rail', 50, 100},
-- {0.25, 0, 1, false, 'uranium-rounds-magazine', 1, 4},
{1, 0.15, 1, false, 'pump', 1, 2},
{2, 0.15, 1, false, 'pumpjack', 1, 3},
{0.02, 0.15, 1, false, 'oil-refinery', 1, 2},
{3, 0, 1, false, 'effectivity-module', 1, 4},
{3, 0, 1, false, 'speed-module', 1, 4},
{3, 0, 1, false, 'productivity-module', 1, 4},
--shotgun meta:
{10, -0.2, 0.4, true, 'shotgun-shell', 12, 24},
{5, 0, 0.4, true, 'shotgun', 1, 1},
{3, 0.4, 1.2, true, 'piercing-shotgun-shell', 4, 9},
{2, 0.4, 1.2, true, 'combat-shotgun', 1, 1},
--modular armor meta:
{0.7, 0.25, 1, true, 'modular-armor', 1, 1},
-- {0.4, 0.5, 1, true, 'power-armor', 1, 1},
-- {0.5, -1,3, true, "power-armor-mk2", 1, 1},
{3, 0.1, 1, true, 'solar-panel-equipment', 1, 2},
{2, 0.1, 1, true, 'battery-equipment', 1, 1},
{1.6, 0.2, 1, true, 'energy-shield-equipment', 1, 2},
{0.8, 0.1, 1, true, 'night-vision-equipment', 1, 1},
{0.4, 0.5, 1.5, true, 'personal-laser-defense-equipment', 1, 1},
--loader meta:
{0.25, 0, 0.2, false, 'loader', 1, 2},
{0.25, 0.2, 0.6, false, 'fast-loader', 1, 2},
{0.25, 0.6, 1, false, 'express-loader', 1, 2},
--science meta:
{8, -0.5, 0.5, true, 'automation-science-pack', 4, 32},
{8, -0.6, 0.6, true, 'logistic-science-pack', 4, 32},
{6, -0.1, 1, true, 'military-science-pack', 8, 32},
{6, 0.2, 1.4, true, 'chemical-science-pack', 16, 32},
-- {6, 0.3, 1.5, true, 'production-science-pack', 16, 32},
{4, 0.4, 1.5, true, 'utility-science-pack', 16, 32},
-- {10, 0.5, 1.5, true, 'space-science-pack', 16, 32},
--early-game:
--{3, -0.1, 0.2, false, "railgun-dart", 2, 4},
-- {3, -0.1, 0.1, true, 'wooden-chest', 8, 40},
{5, -0.1, 0.1, true, 'burner-inserter', 8, 20},
{1, -0.2, 0.2, true, 'offshore-pump', 1, 3},
{3, -0.2, 0.2, true, 'boiler', 3, 6},
{3, 0, 0.1, true, 'lab', 1, 3},
{3, -0.2, 0.2, true, 'steam-engine', 2, 4},
-- {3, -0.2, 0.2, true, 'burner-mining-drill', 2, 4},
{2, 0, 0.1, false, 'submachine-gun', 1, 1},
{3, 0, 0.3, true, 'iron-chest', 8, 40},
{4, 0, 0.1, false, 'light-armor', 1, 1},
{4, -0.3, 0.3, true, 'inserter', 8, 16},
{8, -0.3, 0.3, true, 'small-electric-pole', 16, 32},
{6, -0.4, 0.4, true, 'stone-furnace', 8, 16},
-- {1, -0.3, 0.3, true, 'underground-belt', 3, 10},
{1, -0.3, 0.3, true, 'splitter', 1, 5},
{1, -0.3, 0.3, true, 'assembling-machine-1', 2, 4},
{5, -0.8, 0.8, true, 'transport-belt', 15, 100},
--mid-game:
--{6, 0.2, 0.5, false, "railgun-dart", 4, 8},
{5, -0.2, 0.7, true, 'pipe', 30, 50},
{1, -0.2, 0.7, true, 'pipe-to-ground', 4, 8},
{5, -0.2, 0.7, true, 'iron-gear-wheel', 20, 80},
{5, -0.2, 0.7, true, 'copper-cable', 30, 100},
{5, -0.2, 0.7, true, 'electronic-circuit', 15, 100},
{4, -0.1, 0.8, true, 'fast-transport-belt', 10, 60},
-- {4, -0.1, 0.8, true, 'fast-underground-belt', 3, 10},
{4, -0.1, 0.8, true, 'fast-splitter', 1, 5},
{2, 0, 0.6, true, 'storage-tank', 2, 6},
{2, 0, 0.5, true, 'heavy-armor', 1, 1},
{3, 0, 0.7, true, 'steel-plate', 15, 100},
-- {8, 0, 0.9, true, 'piercing-rounds-magazine', 10, 64},
-- {4, 0.2, 0.6, true, 'engine-unit', 8, 16},
{4, 0, 1, true, 'fast-inserter', 2, 12},
{5, 0, 1, true, 'steel-furnace', 4, 8},
{5, 0, 1, true, 'assembling-machine-2', 2, 4},
{5, 0, 1, true, 'medium-electric-pole', 6, 20},
{5, 0, 1, true, 'accumulator', 4, 8},
{5, 0, 1, true, 'solar-panel', 3, 6},
{8, 0, 1, true, 'steel-chest', 8, 16},
{3, 0.2, 1, true, 'chemical-plant', 1, 3},
--late-game:
--{9, 0.5, 0.8, false, "railgun-dart", 8, 16},
-- {5, 0, 1.2, true, 'land-mine', 16, 32},
{4, 0.2, 1.2, true, 'lubricant-barrel', 4, 10},
{1, 0.2, 1.2, true, 'battery', 10, 50},
{5, 0.2, 1.8, true, 'explosive-rocket', 16, 32},
{4, 0.2, 1.4, true, 'advanced-circuit', 15, 100},
{3, 0.2, 1.8, true, 'stack-inserter', 4, 8},
{3, 0.2, 1.4, true, 'big-electric-pole', 4, 8},
{2, 0.3, 1, true, 'rocket-fuel', 4, 10},
{5, 0.4, 0.7, true, 'cannon-shell', 16, 32},
{5, 0.4, 0.8, true, 'explosive-cannon-shell', 16, 32},
{5, 0.2, 1.8, true, 'cluster-grenade', 8, 16},
-- {5, 0.2, 1.4, true, 'construction-robot', 5, 25},
-- {2, 0.25, 1.75, true, 'logistic-robot', 5, 25},
{2, 0.25, 1.75, true, 'substation', 2, 4},
{3, 0.25, 1.75, true, 'assembling-machine-3', 2, 4},
{3, 0.25, 1.75, true, 'express-transport-belt', 10, 60},
-- {3, 0.25, 1.75, true, 'express-underground-belt', 2, 6},
{3, 0.25, 1.75, true, 'express-splitter', 1, 3},
{3, 0.25, 1.75, true, 'electric-furnace', 2, 4},
{3, 0.25, 1.75, true, 'laser-turret', 1, 4},
-- {4, 0.4, 1.6, true, 'processing-unit', 30, 200},
{2, 0.6, 1.4, true, 'roboport', 1, 1},
-- super late-game:
--{9, 0.8, 1.2, false, "railgun-dart", 12, 20},
-- {1, 0.9, 1.1, true, 'power-armor-mk2', 1, 1},
-- {1, 0.8, 1.2, true, 'fusion-reactor-equipment', 1, 1}
--{2, 0, 1, , "computer", 1, 1},
--{1, 0.2, 1, , "railgun", 1, 1},
--{1, 0.9, 1, , "personal-roboport-mk2-equipment", 1, 1},
}
function Public.chest_loot_data()
local ret = {}
local loot_data = Public.chest_loot_data_raw
for i = 1, #loot_data do
local loot_data_item = loot_data[i]
ret[#ret + 1] = {
weight = loot_data_item[1],
game_completion_progress_min = loot_data_item[2],
game_completion_progress_max = loot_data_item[3],
scaling = loot_data_item[4],
name = loot_data_item[5],
min_count = loot_data_item[6],
max_count = loot_data_item[7],
map_subtype = loot_data_item[8]
}
end
return ret
end
function Public.wooden_chest_loot()
local memory = Memory.get_crew_memory()
local overworldx = memory.overworldx or 0
local num = Math.random(1,3)
return Public.chest_loot(num, 40/100 * Math.sloped(Common.difficulty(),1/2) * Common.game_completion_progress())
end
function Public.iron_chest_loot()
local memory = Memory.get_crew_memory()
local overworldx = memory.overworldx or 0
local num = Math.random(3,4)
local loot = Public.chest_loot(num, 5/100 + 40/100 * Math.sloped(Common.difficulty(),1/2) * Common.game_completion_progress())
loot[#loot + 1] = {name = 'coin', count = Math.random(1,1500)}
return loot
end
function Public.covered_wooden_chest_loot()
local memory = Memory.get_crew_memory()
local overworldx = memory.overworldx or 0
local num = 2
local loot = Public.chest_loot(num, 20/100 + 40/100 * Math.sloped(Common.difficulty(),1/2) * Common.game_completion_progress())
return loot
end
function Public.stone_furnace_loot()
return {
{name = 'coal', count = 50},
}
end
function Public.storage_tank_fluid_loot(force_crude_oil)
local ret
local rng = Math.random(10)
if force_crude_oil then
ret = {name = 'crude-oil', amount = Math.random(3000, 15000)}
elseif rng < 6 then
ret = {name = 'crude-oil', amount = Math.random(1000, 5000)}
elseif rng == 7 then
ret = {name = 'heavy-oil', amount = Math.random(1000, 4000)}
elseif rng == 8 then
ret = {name = 'lubricant', amount = Math.random(1000, 2000)}
else
ret = {name = 'petroleum-gas', amount = Math.random(1000, 4000)}
end
return ret
end
function Public.swamp_storage_tank_fluid_loot()
local ret
ret = {name = 'sulfuric-acid', amount = Math.random(500, 1500)}
return ret
end
function Public.roboport_bots_loot()
return {
{name = 'logistic-robot', count = 5},
}
-- construction robots
end
function Public.chest_loot(number_of_items, game_completion_progress)
local ret = {}
local rng = Math.random()
local memory = Memory.get_crew_memory()
-- if rng < 20/100 then
-- ret = {
-- {name = 'iron-plate', count = 50},
-- }
-- elseif rng < 40/100 then
-- ret = {
-- {name = 'copper-plate', count = 50},
-- }
-- else
-- ret = {
-- {name = 'coal', count = 50},
-- }
-- end
local loot_data = Public.chest_loot_data()
local loot_types, loot_weights = {}, {}
for i = 1, #loot_data, 1 do
table.insert(loot_types, {['name'] = loot_data[i].name, ['min_count'] = loot_data[i].min_count, ['max_count'] = loot_data[i].max_count})
local destination = Common.current_destination()
if not (destination and destination.subtype and loot_data[i].map_subtype and loot_data[i].map_subtype == destination.subtype) then
if loot_data[i].scaling then -- scale down weights away from the midpoint 'peak' (without changing the mean)
local midpoint = (loot_data[i].game_completion_progress_max + loot_data[i].game_completion_progress_min) / 2
local difference = (loot_data[i].game_completion_progress_max - loot_data[i].game_completion_progress_min)
table.insert(loot_weights, loot_data[i].weight * Math.max(0, 1 - (Math.abs(game_completion_progress - midpoint) / (difference / 2))))
else -- no scaling
if loot_data[i].game_completion_progress_min <= game_completion_progress and loot_data[i].game_completion_progress_max >= game_completion_progress then
table.insert(loot_weights, loot_data[i].weight)
else
table.insert(loot_weights, 0)
end
end
end
end
for _ = 1, number_of_items do
local loot = Math.raffle(loot_types, loot_weights)
local low = Math.max(1, Math.ceil(loot.min_count))
local high = Math.max(1, Math.ceil(loot.max_count))
local _count = Math.random(low, high)
local lucky = Math.random(1, 180)
if lucky == 1 then --lucky
_count = _count * 3
elseif lucky <= 10 then
_count = _count * 2
end
ret[#ret + 1] = {name = loot.name, count = _count}
end
return ret
end
return Public

335
maps/pirates/main.lua Normal file
View File

@@ -0,0 +1,335 @@
-- require 'modules.biters_yield_coins'
require 'modules.biter_noms_you'
require 'modules.no_deconstruction_of_neutral_entities'
local Server = require 'utils.server'
local inspect = require 'utils.inspect'.inspect
-- local Modifers = require 'player_modifiers'
local BottomFrame = require 'comfy_panel.bottom_frame'
local Autostash = require 'maps.pirates.from_comfy.autostash'
local TickFunctions = require 'maps.pirates.tick_functions'
local ClassTickFunctions = require 'maps.pirates.tick_functions_classes'
local Commands = require 'maps.pirates.commands'
local Math = require 'maps.pirates.math'
local Memory = require 'maps.pirates.memory'
local Gui = require 'maps.pirates.gui.gui'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local Balance = require 'maps.pirates.balance'
local Crew = require 'maps.pirates.crew'
local Roles = require 'maps.pirates.roles.roles'
local Structures = require 'maps.pirates.structures.structures'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Interface = require 'maps.pirates.interface'
local Boats = require 'maps.pirates.structures.boats.boats'
local Progression = require 'maps.pirates.progression'
local Ai = require 'maps.pirates.ai'
local Ores = require 'maps.pirates.ores'
local Quest = require 'maps.pirates.quest'
local Parrot = require 'maps.pirates.parrot'
local Shop = require 'maps.pirates.shop.shop'
local Upgrades = require 'maps.pirates.boat_upgrades'
local Token = require 'utils.token'
local Task = require 'utils.task'
local Public = {}
-- parrot from https://elthen.itch.io/2d-pixel-art-parrot-sprites
local jetty_delayed = Token.register(
function(data)
Surfaces.Lobby.place_lobby_jetty_and_boats()
end
)
local function on_init()
Memory.global_reset_memory()
local global_memory = Memory.get_global_memory()
game.reset_time_played()
-- local spectator = game.create_force('spectator')
-- local spectator_permissions = game.permissions.create_group('spectator')
-- spectator_permissions.set_allows_action(defines.input_action.start_walking,false)
Autostash.insert_into_furnace(true)
-- Autostash.insert_into_wagon(true)
Autostash.bottom_button(true)
BottomFrame.reset()
BottomFrame.activate_custom_buttons(true)
BottomFrame.bottom_right(true)
local mgs = game.surfaces['nauvis'].map_gen_settings
mgs.width = 16
mgs.height = 16
game.surfaces['nauvis'].map_gen_settings = mgs
game.surfaces['nauvis'].clear()
game.create_surface('piratedev1', Common.default_map_gen_settings(100, 100))
game.surfaces['nauvis'].clear()
Common.init_game_settings(Balance.technology_price_multiplier)
global_memory.active_crews_cap = Common.active_crews_cap
global_memory.minimum_capacity_slider_value = Common.minimum_capacity_slider_value
Surfaces.Lobby.create_starting_dock_surface()
local lobby = game.surfaces[CoreData.lobby_surface_name]
game.forces.player.set_spawn_position(Common.lobby_spawnpoint, lobby)
game.forces.player.character_running_speed_modifier = Balance.base_extra_character_speed
local environment_force = game.create_force('environment')
local player_force = game.forces.player
for id = 1, 3, 1 do
local crew_force = game.create_force(string.format('crew-%03d', id))
local enemy_force = game.create_force(string.format('enemy-%03d', id))
local ancient_friendly_force = game.create_force(string.format('ancient-friendly-%03d', id))
local ancient_enemy_force = game.create_force(string.format('ancient-hostile-%03d', id))
Crew.reset_crew_and_enemy_force(id)
crew_force.research_queue_enabled = true
end
-- Delay.global_add(Delay.global_enum.PLACE_LOBBY_JETTY_AND_BOATS)
Task.set_timeout_in_ticks(2, jetty_delayed, {})
end
local event = require 'utils.event'
event.on_init(on_init)
local function crew_tick()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local tick = game.tick
TickFunctions.boat_movement_tick(5) --arguments are tick intervals
-- TickFunctions.parrot_tick(5)
if tick % 10 == 0 then
TickFunctions.prevent_disembark(10)
TickFunctions.prevent_unbarreling_off_ship(10)
end
if memory.age and memory.overworldx and memory.overworldx > 0 then
memory.age = memory.age + 5
end
if memory.real_age then
memory.real_age = memory.real_age + 5
end
if tick % 60 == 0 then
TickFunctions.captain_warn_afk(60)
end
if tick % Common.loading_interval == 0 then
TickFunctions.loading_update(Common.loading_interval)
end
if tick % 5 == 0 then
TickFunctions.quest_progress_tick(5)
end
if tick % 10 == 0 then
TickFunctions.shop_ratelimit_tick(10)
end
if tick % 30 == 0 then
TickFunctions.silo_update(30)
end
if tick % 10 == 0 then
TickFunctions.pick_up_tick(10)
end
if tick % 60 == 0 then
if memory.boat and memory.boat.state == Structures.Boats.enum_state.ATSEA_SAILING then
TickFunctions.crowsnest_natural_move(120)
end
end
if tick % 60 == 15 or tick % 60 == 45 then
if memory.boat and memory.boat.state == Structures.Boats.enum_state.ATSEA_SAILING then
TickFunctions.overworld_check_collisions(120)
end
end
if tick % 60 == 30 then
if memory.boat and memory.boat.state == Structures.Boats.enum_state.ATSEA_SAILING then
TickFunctions.crowsnest_steer(120)
end
end
if tick % 60 == 0 then
TickFunctions.slower_boat_tick(60)
end
if tick % 10 == 0 then
TickFunctions.update_boat_stored_resources(10)
end
if tick % 15 == 0 then
TickFunctions.covered_requirement_check(15)
end
if tick % 30 == 0 then
TickFunctions.buried_treasure_check(30)
end
if tick % 60 == 0 then
TickFunctions.raft_raids(60)
end
if tick % 30 == 0 then
TickFunctions.place_cached_structures(30)
end
if tick % 240 == 0 then
TickFunctions.check_all_spawners_dead(240)
end
if tick % 60 == 0 then
if destination.dynamic_data.timer then
destination.dynamic_data.timer = destination.dynamic_data.timer + 1
end
if memory.captain_acceptance_timer then
memory.captain_acceptance_timer = memory.captain_acceptance_timer - 1
if memory.captain_acceptance_timer == 0 then
Roles.assign_captain_based_on_priorities()
end
end
if memory.captain_accrued_time_data and memory.playerindex_captain then
if (not memory.captain_accrued_time_data[memory.playerindex_captain]) then memory.captain_accrued_time_data[memory.playerindex_captain] = 0 end
memory.captain_accrued_time_data[memory.playerindex_captain] = memory.captain_accrued_time_data[memory.playerindex_captain] + 1
end
if destination.dynamic_data.time_remaining and destination.dynamic_data.time_remaining > 0 then
destination.dynamic_data.time_remaining = destination.dynamic_data.time_remaining - 1
if destination.dynamic_data.time_remaining == 0 then
if memory.boat and memory.boat.surface_name then
local surface_name_decoded = Surfaces.SurfacesCommon.decode_surface_name(memory.boat.surface_name)
local type = surface_name_decoded.type
if type == Surfaces.enum.ISLAND then
Progression.retreat_from_island()
elseif type == Surfaces.enum.DOCK then
Progression.undock_from_dock()
end
end
end
end
end
if tick % 300 == 0 then
TickFunctions.periodic_free_resources(300)
end
if tick % 30 == 0 then
ClassTickFunctions.update_character_properties(30)
end
if tick % 360 == 0 then
ClassTickFunctions.Builder_and_Shoreman_rewards_tick(360)
end
if tick % 120 == 0 then
Ai.Tick_actions(120)
end
if tick % 240 == 0 then
TickFunctions.LOS_tick(240)
end
if tick % 300 == 0 then
TickFunctions.update_recentcrewmember_list(300)
end
if tick % 1800 == 0 then
TickFunctions.transfer_pollution(1800)
end
-- if tick % (60*60*60) == 0 then
-- Parrot.parrot_say_tip()
-- end
if memory.crew_disband_tick then
if memory.crew_disband_tick < tick then
memory.crew_disband_tick = nil
Crew.disband_crew()
end
return
end
end
local function global_tick()
local global_memory = Memory.get_global_memory()
local tick = game.tick
if tick % 60 == 0 then
TickFunctions.update_players_second()
end
if tick % 30 == 0 then
for _, player in pairs(game.connected_players) do
-- figure out which crew this is about:
local crew_id = tonumber(string.sub(player.force.name, -3, -1)) or 0
Memory.set_working_id(crew_id)
Roles.update_tags(player)
end
end
for _, id in pairs(global_memory.crew_active_ids) do
Memory.set_working_id(id)
crew_tick()
end
TickFunctions.update_player_guis(5)
end
event.on_nth_tick(5, global_tick)
local function instatick()
local global_memory = Memory.get_global_memory()
for _, id in pairs(global_memory.crew_active_ids) do
Memory.set_working_id(id)
TickFunctions.silo_insta_update()
end
end
event.on_nth_tick(1, instatick)
----- FOR BUGFIXING HARD CRASHES (segfaults) ------
-- often, segfaults are due to an error during chunk generation
-- to help debug, comment this out, and instead use the command /chnk to generate some chunks manually
event.add(defines.events.on_chunk_generated, Interface.event_on_chunk_generated)
local gMeta = getmetatable(_ENV)
if not gMeta then
gMeta = {}
setmetatable(_ENV, gMeta)
end
gMeta.__newindex = function(_, n, v)
log('Desync warning: attempt to write to undeclared var ' .. n)
global[n] = v
end
gMeta.__index = function(_, n)
return global[n]
end
return Public

134
maps/pirates/math.lua Normal file
View File

@@ -0,0 +1,134 @@
local Public = {}
Public.random = math.random
Public.randomseed = math.randomseed
Public.sqrt = math.sqrt
Public.min = math.min
Public.max = math.max
Public.rad = math.rad
Public.floor = math.floor
Public.abs = math.abs
Public.ceil = math.ceil
Public.log = math.log
Public.atan = math.atan
Public.sin = math.sin
Public.cos = math.cos
Public.pi = math.pi
Public.deg = math.deg
Public.round = math.round
--- SCALING CURVES ---
function Public.sloped(x, slope)
return 1 + ((x - 1) * slope)
end
-- SLOPE GUIDE
-- slope 1 -> {0.25, 0.50, 0.75, 1.00, 1.50, 3.00, 5.00}
-- slope 4/5 -> {0.40, 0.60, 0.80, 1.00, 1.40, 2.60, 4.20}
-- slope 3/5 -> {0.55, 0.70, 0.85, 1.00, 1.30, 2.20, 3.40}
-- slope 2/5 -> {0.70, 0.80, 0.90, 1.00, 1.20, 1.80, 2.40}
-- EXPONENT GUIDE
-- exponent 1 -> {0.25, 0.50, 0.75, 1.00, 1.50, 3.00, 5.00}
-- exponent 1.5 -> {0.13, 0.35, 0.65, 1.00, 1.84, 5.20, 11.18}
-- exponent 2 -> {0.06, 0.25, 0.56, 1.00, 2.25, 9.00, 25.00}
-- exponent -1.2 -> {5.28, 2.30, 1.41, 1.00, 0.61, 0.27, 0.14}
function Public.sgn(number)
return number > 0 and 1 or (number == 0 and 0 or -1)
end
function Public.length(vec)
return Public.sqrt(vec.x * vec.x + vec.y * vec.y)
end
function Public.slopefromto(x, from, to)
return Public.max(0,Public.min(1,
(x - from) / (to - from)
))
end
function Public.distance(vec1, vec2)
local vecx = vec2.x - vec1.x
local vecy = vec2.y - vec1.y
return Public.sqrt(vecx * vecx + vecy * vecy)
end
function Public.vector_sum(vec1, vec2)
return {x = vec1.x + vec2.x, y = vec1.y + vec2.y}
end
function Public.shuffle(tbl)
local size = #tbl
for i = size, 2, -1 do
local rand = Public.random(size)
tbl[i], tbl[rand] = tbl[rand], tbl[i]
end
return tbl
end
local function is_closer(pos1, pos2, pos)
return ((pos1.x - pos.x) ^ 2 + (pos1.y - pos.y) ^ 2) < ((pos2.x - pos.x) ^ 2 + (pos2.y - pos.y) ^ 2)
end
function Public.shuffle_distancebiased(tbl, position)
local size = #tbl
for i = size, 1, -1 do
local rand = Public.random(i)
if is_closer(tbl[i].position, tbl[rand].position, position) and i > rand then
tbl[i], tbl[rand] = tbl[rand], tbl[i]
end
end
return tbl
end
function Public.raffle(values, weights) --arguments of the form {[a] = A, [b] = B, ...} and {[a] = a_weight, [b] = b_weight, ...} or just {a,b,c,...} and {1,2,3...}
local total_weight = 0
for k,w in pairs(weights) do
assert(values[k])
if w > 0 then
total_weight = total_weight + w
end
-- negative weights treated as zero
end
assert(total_weight > 0)
local cumulative_probability = 0
local rng = Public.random()
for k,v in pairs(values) do
assert(weights[k])
cumulative_probability = cumulative_probability + (weights[k] / total_weight)
if rng <= cumulative_probability then
return v
end
end
end
function Public.raffle2(table) --arguments of the form {v1 = w1, v2 = w2, ...}
local total_weight = 0
for k,w in pairs(table) do
if w > 0 then
total_weight = total_weight + w
end
-- negative weights treated as zero
end
assert(total_weight > 0)
local cumulative_probability = 0
local rng = Public.random()
for k,v in pairs(table) do
cumulative_probability = cumulative_probability + v/total_weight
if rng <= cumulative_probability then
return k
end
end
end
return Public

155
maps/pirates/memory.lua Normal file
View File

@@ -0,0 +1,155 @@
local Global = require 'utils.global'
local CoreData = require 'maps.pirates.coredata'
local pirates_global_memory = {}
local Public = {}
-- register only this
Global.register(
pirates_global_memory,
function(tbl)
pirates_global_memory = tbl
end
)
function Public.global_reset_memory()
for k, _ in pairs(pirates_global_memory) do
pirates_global_memory[k] = nil
end
pirates_global_memory.config = {}
pirates_global_memory.afk_player_indices = {}
pirates_global_memory.playerindex_to_time_played_continuously = {}
pirates_global_memory.playerindex_to_priority = {}
pirates_global_memory.player_gui_memories = {}
pirates_global_memory.offline_players = {}
pirates_global_memory.crew_memories = {}
pirates_global_memory.crew_active_ids = {}
pirates_global_memory.working_id = nil --should only ever be nil, 1, 2 or 3
pirates_global_memory.lobby_boats = {}
pirates_global_memory.active_crews_cap = nil
pirates_global_memory.crew_capacity_min = nil
pirates_global_memory.crewproposals = {}
pirates_global_memory.global_delayed_tasks = {}
pirates_global_memory.global_buffered_tasks = {}
end
function Public.reset_crew_memory(id) --also serves as a dev reference of memory entries
pirates_global_memory.crew_memories[id] = {}
local memory = pirates_global_memory.crew_memories[id]
memory.secs_id = nil
memory.id = nil
memory.age = nil
memory.real_age = nil
memory.completion_time = nil
memory.force_name = nil
memory.enemy_force_name = nil
memory.original_proposal = nil
memory.name = nil
memory.difficulty_option = nil
memory.capacity_option = nil
-- memory.mode_option = nil
memory.difficulty = nil
memory.capacity = nil
-- memory.mode = nil
memory.destinations = nil
memory.currentdestination_index = nil
memory.hold_surface_count = nil
memory.merchant_ships_unlocked = nil
memory.boat = nil
memory.crewplayerindices = nil
memory.spectatorplayerindices = nil
memory.tempbanned_from_joining_data = nil
memory.playerindex_captain = nil
memory.captain_accrued_time_data = nil
memory.speed_boost_characters = nil
memory.enemyboats = nil
memory.overworld_krakens = nil
memory.active_sea_enemies = nil
memory.kraken_stream_registrations = nil
memory.mainshop_availability_bools = nil
memory.delayed_tasks = nil
memory.buffered_tasks = nil
memory.game_lost = false
memory.game_won = false
memory.crew_disband_tick = nil
memory.destinationsvisited_indices = nil
memory.overworldx = nil
memory.overworldy = nil
memory.mapbeingloadeddestination_index = nil
memory.loadingticks = nil
memory.gold = nil
memory.spawnpoint = nil
memory.scripted_biters = nil
memory.scripted_unit_groups = nil
memory.floating_pollution = nil
end
function Public.fallthrough_crew_memory() --could make this a metatable
return {
id = 0,
difficulty = 1,
force_name = 'player',
boat = {},
destinations = {},
spectatorplayerindices = {},
crewplayerindices = {},
--[[boat = {
type = nil,
state = nil,
speed = nil,
speedticker1 = nil,
speedticker2 = nil,
speedticker3 = nil,
stored_resources = {},
position = nil, --the far right edge of the boat
decksteeringchests = nil,
crowsneststeeringchests = nil,
cannons = nil,
EEI = nil,
EEIpower_production = nil,
EEIelectric_buffer_size = nil,
dockedposition = nil,
surface_name = nil,
}]]
}
end
function Public.get_crew_memory()
if pirates_global_memory.working_id and pirates_global_memory.working_id > 0 then
return pirates_global_memory.crew_memories[pirates_global_memory.working_id] or Public.fallthrough_crew_memory()
else
return Public.fallthrough_crew_memory()
end
end
function Public.get_global_memory()
return pirates_global_memory
end
function Public.set_working_id(id)
pirates_global_memory.working_id = id
end
return Public

BIN
maps/pirates/noise_pregen/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,29 @@
local Public = {}
Public.encoding = [[!#$%&'()*+'-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ/^_`abcdefghijklmnopqrstuvwxyz{}|~]]
Public.encoding_length = 91
Public.enc = {}
Public.dec = {}
for i=1,Public.encoding_length do
Public.enc[i]=Public.encoding:sub(i,i)
Public.dec[Public.encoding:sub(i,i)]=i
end
Public.island1 = {}
Public.island1.Data = require 'maps.pirates.noise_pregen.perlinwavelength100boxsize1000octaves5gain0p8lacunity2lengthpower1rms0p05423'
Public.island1.upperscale = 100
Public.island1.boxsize = 1000
Public.island1.wordlength = 5
Public.island1.factor = 0.1925/0.05423
Public.forest1 = {}
Public.forest1.Data = require 'maps.pirates.noise_pregen.simplexwavelength100boxsize1000octaves5gain0p65lacunity2lengthpower1p2rms0p06243'
Public.forest1.upperscale = 100
Public.forest1.boxsize = 1000
Public.forest1.wordlength = 5
Public.forest1.factor = 0.1925/0.06243
return Public

File diff suppressed because one or more lines are too long

215
maps/pirates/ores.lua Normal file
View File

@@ -0,0 +1,215 @@
local Balance = require 'maps.pirates.balance'
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local CoreData = require 'maps.pirates.coredata'
local inspect = require 'utils.inspect'.inspect
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local simplex_noise = require 'utils.simplex_noise'.d2
local Public = {}
function Public.try_ore_spawn(surface, realp, source_name, density_bonus)
density_bonus = density_bonus or 0
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local choices = destination.dynamic_data.hidden_ore_remaining_abstract
if choices and Utils.length(choices) > 0 then
local choices_possible = {}
local choices_to_prioitise = {}
for k, v in pairs(choices) do
if v>0 then choices_possible[k] = v end
if (not destination.dynamic_data.ore_types_spawned[k]) then
choices_to_prioitise[#choices_to_prioitise + 1] = k
end
end
if Utils.length(choices_possible) > 0 then
local choice
if Utils.length(choices_to_prioitise) > 0 then
choice = choices_to_prioitise[Math.random(Utils.length(choices_to_prioitise))]
else
choice = Math.raffle2(choices_possible)
end
local placed
if choice == 'crude-oil' then
placed = (3000 * (1 + 9 * Math.slopefromto(choices[choice], 1, 8))) * (0.6 + Math.random()) --3000 is 1%
placed = Math.min(placed, Common.oil_abstract_to_real(choices[choice]))
local tile = surface.get_tile(realp)
if (not (tile and tile.name and Utils.contains(CoreData.tiles_that_conflict_with_resource_layer_extended, tile.name))) then
surface.create_entity{name = 'crude-oil', amount = placed, position = realp}
else
placed = 0
end
else
local real_amount = Math.max(Common.minimum_ore_placed_per_tile, Common.ore_abstract_to_real(choices[choice]))
local density = (density_bonus + 23 + 4 * Math.random()) -- not too big, and not too much variation; it makes players have to stay longer
local radius_squared = (destination.static_params and destination.static_params.radius_squared_modifier or 1) * (9 + 39 * Math.slopefromto(Common.ore_abstract_to_real(choices[choice]), 800, 20000)) * (0.6 + Math.random())
if source_name == 'rock-huge' then
radius_squared = radius_squared * 1.5
end
placed = Public.draw_noisy_ore_patch(surface, realp, choice, real_amount, radius_squared, density)
end
if placed then
choices[choice] = Math.max(0, choices[choice] - Common.ore_real_to_abstract(placed))
if placed > 0 and not destination.dynamic_data.ore_types_spawned[choice] then
destination.dynamic_data.ore_types_spawned[choice] = true
end
return true
end
end
end
return false
end
function Public.draw_noisy_ore_patch(surface, position, name, budget, radius_squared, density, forced, flat)
flat = flat or true
budget = budget or 999999999
forced = forced or false
local amountplaced = 0
local radius = Math.sqrt(radius_squared)
position = {x = Math.ceil(position.x) - 0.5, y = Math.ceil(position.y) - 0.5}
if not position then return 0 end
if not name then return 0 end
if not surface then return 0 end
if not radius then return 0 end
if not density then return 0 end
local mixed_ore_raffle = {
'iron-ore', 'iron-ore', 'iron-ore', 'copper-ore', 'copper-ore', 'coal', 'stone'
}
local seed = surface.map_gen_settings.seed
local function try_draw_at_relative_position(x, y, strength)
local absx = x + position.x
local absy = y + position.y
local absp = {x = absx, y = absy}
local amount_to_place_here = Math.min(density * strength, budget - amountplaced)
if amount_to_place_here >= Common.minimum_ore_placed_per_tile then
if name == 'mixed' then
local noise = simplex_noise(x * 0.005, y * 0.005, seed) + simplex_noise(x * 0.01, y * 0.01, seed) * 0.3 + simplex_noise(x * 0.05, y * 0.05, seed) * 0.2
local i = (Math.floor(noise * 100) % #mixed_ore_raffle) + 1
name = mixed_ore_raffle[i]
end
local entity = {name = name, position = absp, amount = amount_to_place_here}
-- local area = {{absx - 0.05, absy - 0.05}, {absx + 0.05, absy + 0.05}}
local area2 = {{absx - 0.1, absy - 0.1}, {absx + 0.1, absy + 0.1}}
local area3 = {{absx - 2, absy - 2}, {absx + 2, absy + 2}}
local preexisting_ores = surface.find_entities_filtered{area = area2, type = 'resource'}
local added
if #preexisting_ores >= 1 then
local addedbool = false
for _, ore in pairs(preexisting_ores) do
if ore.name == name then
ore.amount = ore.amount + amount_to_place_here
amountplaced = amountplaced + amount_to_place_here
addedbool = true
break
end
end
if not addedbool then
added = surface.create_entity(entity)
end
else
local tile = surface.get_tile(absp)
local silos = surface.find_entities_filtered{area=area3, name='rocket-silo'}
if #silos == 0 and (not (tile and tile.name and Utils.contains(CoreData.tiles_that_conflict_with_resource_layer_extended, tile.name))) then
if forced then
surface.destroy_decoratives{area = area2}
for _, tree in pairs(surface.find_entities_filtered{area=area2, type='tree'}) do
tree.destroy()
end
added = surface.create_entity(entity)
else
local pos2 = surface.find_non_colliding_position(name, absp, 10, 1, true)
pos2 = pos2 or absp
entity = {name = name, position = pos2, amount = amount_to_place_here}
surface.destroy_decoratives{area = area2}
if pos2 and surface.can_place_entity(entity) then
added = surface.create_entity(entity)
end
end
end
end
if added and added.valid then
amountplaced = amountplaced + amount_to_place_here
end
end
end
local spiral_layer = 0
local outwards_spiral_x = 0
local outwards_spiral_y = 0
local whilesafety = 0
while whilesafety < 10000 and spiral_layer < radius * 2 do
whilesafety = whilesafety + 1
local distance_to_center = Math.sqrt(outwards_spiral_x^2 + outwards_spiral_y^2)
local noise
if distance_to_center > 0 then
noise = 0.99 * simplex_noise((position.x + outwards_spiral_x/distance_to_center) * 1/3, (position.y + outwards_spiral_y/distance_to_center) * 1/3, seed) * simplex_noise((position.x + outwards_spiral_x/distance_to_center) * 1/9, (position.y + outwards_spiral_y/distance_to_center) * 1/9, seed+100)
else
noise = 0.99 * simplex_noise((position.x) * 1/3, (position.y) * 1/3, seed) * simplex_noise((position.x) * 1/9, (position.y) * 1/9, seed+100)
end
local radius_noisy = radius * (1 + noise)
if distance_to_center < radius_noisy then
local strength
if flat then
strength = 1
else
strength = (3/2) * (1 - (distance_to_center/radius_noisy)^2)
end
try_draw_at_relative_position(outwards_spiral_x, outwards_spiral_y, strength)
end
if outwards_spiral_x == 0 and outwards_spiral_y >= spiral_layer then
outwards_spiral_x = outwards_spiral_x + 1
spiral_layer = spiral_layer + 1
elseif outwards_spiral_x > 0 and outwards_spiral_y > 0 then
outwards_spiral_x = outwards_spiral_x + 1
outwards_spiral_y = outwards_spiral_y - 1
elseif outwards_spiral_x > 0 and outwards_spiral_y <= 0 then
outwards_spiral_x = outwards_spiral_x - 1
outwards_spiral_y = outwards_spiral_y - 1
elseif outwards_spiral_x <= 0 and outwards_spiral_y < 0 then
outwards_spiral_x = outwards_spiral_x - 1
outwards_spiral_y = outwards_spiral_y + 1
elseif outwards_spiral_x < 0 and outwards_spiral_y >= 0 then
outwards_spiral_x = outwards_spiral_x + 1
outwards_spiral_y = outwards_spiral_y + 1
end
end
return amountplaced
end
return Public

636
maps/pirates/overworld.lua Normal file
View File

@@ -0,0 +1,636 @@
local Public = {}
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Server = require 'utils.server'
local Structures = require 'maps.pirates.structures.structures'
local Boats = require 'maps.pirates.structures.boats.boats'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Crowsnest = require 'maps.pirates.surfaces.crowsnest'
local Dock = require 'maps.pirates.surfaces.dock'
local Islands = require 'maps.pirates.surfaces.islands.islands'
local Sea = require 'maps.pirates.surfaces.sea.sea'
local Crew = require 'maps.pirates.crew'
local Roles = require 'maps.pirates.roles.roles'
local Classes = require 'maps.pirates.roles.classes'
local Quest = require 'maps.pirates.quest'
local Parrot = require 'maps.pirates.parrot'
local Hold = require 'maps.pirates.surfaces.hold'
local Cabin = require 'maps.pirates.surfaces.cabin'
local Shop = require 'maps.pirates.shop.shop'
local Upgrades = require 'maps.pirates.boat_upgrades'
local Kraken = require 'maps.pirates.surfaces.sea.kraken'
local Highscore = require 'maps.pirates.highscore'
local infront_positions = {}
for x = -6, -3 do
for y = - 3, 3 do
infront_positions[#infront_positions + 1] = {x = x, y = y}
end
end
local interior_positions = {}
for x = 1, 14 do
for y = - 3, 3 do
interior_positions[#interior_positions + 1] = {x = x, y = y}
end
end
function Public.generate_overworld_destination(p)
-- be careful not to call any Balance functions that depend on overworldx, as this is called earlier
local memory = Memory.get_crew_memory()
local macrop = {x = p.x/40, y = p.y/24}
local type, subtype
local island_subtype_raffle = {'none', 'none', Surfaces.Island.enum.STANDARD, Surfaces.Island.enum.STANDARD_VARIANT, Surfaces.Island.enum.RED_DESERT, Surfaces.Island.enum.HORSESHOE}
if macrop.x >= 6 then island_subtype_raffle[#island_subtype_raffle + 1] = Surfaces.Island.enum.WALKWAYS end
if macrop.x >= 16 then island_subtype_raffle[#island_subtype_raffle + 1] = Surfaces.Island.enum.SWAMP end
if macrop.x >= 16 then island_subtype_raffle[#island_subtype_raffle + 1] = 'none' end
if macrop.x >= 26 then island_subtype_raffle[#island_subtype_raffle + 1] = Surfaces.Island.enum.RADIOACTIVE end
if macrop.x == 0 then
if macrop.y == 0 then
type = Surfaces.enum.ISLAND
subtype = Surfaces.Island.enum.FIRST
if _DEBUG then
-- Edit this to force a type/subtype in debug:
-- subtype = Surfaces.Island.enum.WALKWAYS
-- type = Surfaces.enum.DOCK
-- subtype = nil
end
elseif macrop.y == 1 then
type = Surfaces.enum.DOCK
else
type = nil
end
elseif macrop.x == 1 then
type = Surfaces.enum.ISLAND
subtype = Surfaces.Island.enum.HORSESHOE
elseif macrop.x == 2 then
type = Surfaces.enum.ISLAND
subtype = Surfaces.Island.enum.STANDARD_VARIANT
elseif macrop.y == 1 and (((macrop.x % 4) == 3 and macrop.x ~= 15) or macrop.x == 14) then --avoid x=15 because radioactive is there
type = Surfaces.enum.DOCK
elseif macrop.x == 5 then --biter boats appear
type = Surfaces.enum.ISLAND
subtype = Surfaces.Island.enum.STANDARD
elseif macrop.x == 9 then --just before krakens
type = Surfaces.enum.ISLAND
subtype = Surfaces.Island.enum.HORSESHOE
elseif macrop.x == 10 then --krakens appear
type = nil
elseif macrop.x == 12 then --just after krakens, but dock is here too, so there's a choice
type = Surfaces.enum.ISLAND
subtype = Surfaces.Island.enum.SWAMP
elseif macrop.x == 15 or macrop.x == 23 or (macrop.x > 25 and macrop.x % 10 == 0) then
type = Surfaces.enum.ISLAND
subtype = Surfaces.Island.enum.RADIOACTIVE
elseif macrop.x == 20 then --electric engines needed here
type = Surfaces.enum.ISLAND
subtype = Surfaces.Island.enum.WALKWAYS
elseif macrop.x == 24 then
type = Surfaces.enum.ISLAND
subtype = Surfaces.Island.enum.SWAMP
elseif macrop.x == 25 then
type = nil --finish line
else
type = Surfaces.enum.ISLAND
subtype = island_subtype_raffle[Math.random(#island_subtype_raffle)]
if subtype == 'none' then
type = nil
subtype = nil
end
end
-- if _DEBUG and ((macrop.x > 0 and macrop.x < 25)) and type ~= Surfaces.enum.DOCK then
-- type = nil
-- subtype = nil
-- end
if type == Surfaces.enum.ISLAND then
local scope = Surfaces[Surfaces.enum.ISLAND][subtype]
local playercount = Common.activecrewcount()
local static_params = Utils.deepcopy(scope.Data.static_params_default)
local cost_to_leave, scheduled_raft_raids, class_for_sale
local normal_costitems = {'small-lamp', 'engine-unit', 'advanced-circuit', 'electric-engine-unit'}
local base_cost_0 = {
['small-lamp'] = (macrop.x-3)*25,
}
local base_cost_1 = {
['small-lamp'] = (macrop.x-3)*25,
['engine-unit'] = (macrop.x-7)*15,
}
local base_cost_2 = {
['small-lamp'] = (macrop.x-3)*25,
['engine-unit'] = (macrop.x-7)*15,
['advanced-circuit'] = (macrop.x-10)*10,
}
local base_cost_3 = {
['small-lamp'] = (macrop.x-3)*25,
['engine-unit'] = (macrop.x-7)*15,
['advanced-circuit'] = (macrop.x-10)*10,
['electric-engine-unit'] = (macrop.x-16)*10,
}
local base_cost_4 = {
['small-lamp'] = (macrop.x-3)*25,
['engine-unit'] = (macrop.x-7)*15,
['advanced-circuit'] = (macrop.x-10)*10,
['electric-engine-unit'] = (macrop.x-16)*10,
}
if macrop.x <= 4 then
cost_to_leave = nil
elseif macrop.x <= 8 then
cost_to_leave = base_cost_0
elseif macrop.x <= 15 then
cost_to_leave = base_cost_1
elseif macrop.x == 18 then --a super small amount of electric-engine-unit on a relatively early level so that they see they need lubricant
cost_to_leave = {
['small-lamp'] = (macrop.x-3)*25,
['engine-unit'] = (macrop.x-7)*15,
['electric-engine-unit'] = 2,
}
elseif macrop.x <= 19 then
cost_to_leave = base_cost_2
elseif macrop.x < 25 then
cost_to_leave = base_cost_3
else
cost_to_leave = base_cost_4
local delete = normal_costitems[Math.random(#normal_costitems)]
cost_to_leave[delete] = nil
end
-- override:
if subtype == Surfaces.Island.enum.RADIOACTIVE then
cost_to_leave = {
['uranium-235'] = Math.ceil(80 + macrop.x),
}
end
static_params.cost_to_leave = cost_to_leave
class_for_sale = Classes.Class_List[Math.random(#Classes.Class_List)]
static_params.class_for_sale = class_for_sale
local max_evo = 0.85
if Common.difficulty() < 1 then max_evo = 0.68 end
if p.x > 200 then
scheduled_raft_raids = {}
local times = {600, 360, 215, 210, 120, 30, 10, 5}
for i = 1, #times do
local t = times[i]
if Math.random(7) == 1 and #scheduled_raft_raids < 6 then
scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = t, max_evo = max_evo}
-- scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = t, max_bonus_evolution = 0.52}
end
end
elseif p.x == 200 then
local times
if playercount <= 2 then
times = {1, 5, 10, 15}
elseif playercount <= 7 then
times = {1, 5, 10, 15, 20}
elseif playercount <= 15 then
times = {1, 5, 10, 15, 20, 25}
else
times = {1, 5, 10, 15, 20, 25, 30, 35}
end
scheduled_raft_raids = {}
for _, t in pairs(times) do
-- scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = t, max_bonus_evolution = 0.62}
scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = t, max_evo = max_evo}
end
end
static_params.scheduled_raft_raids = scheduled_raft_raids
local ores_multiplier = Balance.island_richness_avg_multiplier()
if macrop.x == 0 then ores_multiplier = 1 end
local base_ores = scope.Data.base_ores()
local rngs = {}
local rngsum = 0
local rngcount = 0
for k, _ in pairs(base_ores) do
local rng = 2*Math.random()
-- local rng = 1 + ((2*Math.random() - 1)^3) --lower variances
rngs[k] = rng
rngsum = rngsum + rng
rngcount = rngcount + 1
end
local abstract_ore_amounts = {}
for k, v in pairs(base_ores) do
local rng = rngs[k] / (rngsum/rngcount) --average of 1
if macrop.x == 0 then rng = 1 end
abstract_ore_amounts[k] = ores_multiplier * v * rng
end
static_params.abstract_ore_amounts = abstract_ore_amounts
static_params.radius_squared_modifier = (Math.sqrt(0.5) + 1 * Math.random())^2
if macrop.x == 0 then static_params.radius_squared_modifier = 1 end
static_params.discord_emoji = scope.Data.discord_emoji
local rng = 0.5 + 1 * Math.random()
static_params.starting_treasure_maps = Math.ceil((static_params.base_starting_treasure_maps or 0) * rng)
static_params.starting_wood = Math.ceil(static_params.base_starting_wood or 1000)
static_params.starting_rock_material = Math.ceil(static_params.base_starting_rock_material or 300) * Balance.island_richness_avg_multiplier()
rng = 0.5 + 1 * Math.random()
static_params.starting_treasure = Math.ceil((static_params.base_starting_treasure or 1000) * Balance.island_richness_avg_multiplier() * rng)
static_params.name = scope.Data.display_names[Math.random(#scope.Data.display_names)]
local dest = Surfaces.initialise_destination{
static_params = static_params,
type = type,
subtype = subtype,
overworld_position = p,
}
Crowsnest.draw_destination(dest)
elseif type == Surfaces.enum.DOCK then
local boat_for_sale_type
-- if macrop.x == 3 then
-- boat_for_sale_type = Boats.enum.CUTTER
-- elseif macrop.x == 7 or macrop.x == 0 then
-- boat_for_sale_type = Boats.enum.SLOOP_WITH_HOLD
-- end
boat_for_sale_type = Boats.enum.SLOOP
local upgrade_for_sale
if macrop.x == 0 then
upgrade_for_sale = nil
elseif macrop.x == 3 then
upgrade_for_sale = Upgrades.enum.MORE_POWER
elseif macrop.x == 7 then
upgrade_for_sale = Upgrades.enum.EXTRA_HOLD
elseif macrop.x % 16 < 8 then
upgrade_for_sale = Upgrades.enum.MORE_POWER
else
upgrade_for_sale = Upgrades.enum.EXTRA_HOLD
end --upgrades like UNLOCK_MERCHANTS will slot themselves in when necessary, due to .overwrite_a_dock_upgrade()
local static_params = Utils.deepcopy(Dock.Data.static_params_default)
static_params.upgrade_for_sale = upgrade_for_sale
static_params.boat_for_sale_type = boat_for_sale_type
static_params.name = Dock.Data.display_names[Math.random(#Dock.Data.display_names)]
local dest = Surfaces.initialise_destination{
static_params = static_params,
type = type,
subtype = subtype,
overworld_position = {x = p.x, y = 36},
}
Crowsnest.draw_destination(dest)
-- renderings e.g. for docks
local surface = Crowsnest.get_crowsnest_surface()
local x = Crowsnest.platformrightmostedge + dest.overworld_position.x
local y = dest.overworld_position.y
if dest.static_params.upgrade_for_sale then
local display_form = Upgrades.crowsnest_display_form[dest.static_params.upgrade_for_sale]
local price = Shop.main_shop_data_1[dest.static_params.upgrade_for_sale].base_cost.gold
dest.dynamic_data.crowsnest_rendering_1 = rendering.draw_text{
text = display_form .. ': ' .. price,
surface = surface,
target = {x = x + 4, y = y - 4.55},
color = CoreData.colors.renderingtext_green,
scale = 7,
font = 'default-game',
alignment = 'right',
visible = false,
}
dest.dynamic_data.crowsnest_rendering_2 = rendering.draw_sprite{
sprite = 'item/sulfur',
surface = surface,
target = {x = x + 7, y = y - 1.75},
x_scale = 6,
y_scale = 6,
visible = false,
}
end
end
--== krakens ==--
local kraken_count = 0
local position_candidates
if type == nil then
kraken_count = Balance.krakens_per_free_slot(macrop.x)
position_candidates = interior_positions
elseif type ~= Surfaces.enum.DOCK then
kraken_count = Balance.krakens_per_slot(macrop.x)
position_candidates = infront_positions
end
-- override:
if macrop.x < 10 then
kraken_count = 0
elseif macrop.x == 10 then
kraken_count = 1
end
if position_candidates then
local positions_placed = {}
local whilesafety = 0
while whilesafety < 10 and (#positions_placed < Math.min(kraken_count, 10)) do
local p_chosen, p_kraken
local whilesafety2 = 0
while whilesafety2 < 50 and ((not p_kraken) or Utils.contains(positions_placed, p_chosen)) do
p_chosen = position_candidates[Math.random(#position_candidates)]
p_kraken = Utils.psum{p_chosen, p}
whilesafety2 = whilesafety2 + 1
end
Crowsnest.draw_kraken(p_kraken)
positions_placed[#positions_placed + 1] = p_kraken
memory.overworld_krakens[#memory.overworld_krakens + 1] = p_kraken
whilesafety = whilesafety + 1
end
-- game.print(#positions_placed .. ' krakens placed for' .. macrop.x .. ', ' .. macrop.y)
end
end
function Public.ensure_lane_generated_up_to(lane_yvalue, x)
-- make sure lane_yvalue=0 is painted first
local memory = Memory.get_crew_memory()
local highest_x = memory['greatest_overworldx_generated_for_' .. lane_yvalue] or -40
local whilesafety = 0
while whilesafety < 10 and highest_x < x do
whilesafety = whilesafety + 1
highest_x = highest_x + 32 + 7 + 1 -- should be at least maximum island size plus crowsnest platform size plus 1
if lane_yvalue == 0 then
Crowsnest.paint_water_between_overworld_positions(highest_x + 32 + 7 + 1, highest_x + 32 + 7 + 1 + 40)
-- a little hack that we're updating this here rather than Crowsnest, due to the dependency on Shop to avoid a loop... almost finished 1.0, so too late to need to figure out how to restructure things!
for _, dest in pairs(memory.destinations) do
if dest.static_params.upgrade_for_sale then
if dest.dynamic_data.crowsnest_rendering_1 and rendering.is_valid(dest.dynamic_data.crowsnest_rendering_1) then
local display_form = Upgrades.crowsnest_display_form[dest.static_params.upgrade_for_sale]
local price = Shop.main_shop_data_1[dest.static_params.upgrade_for_sale].base_cost.gold
rendering.set_text(dest.dynamic_data.crowsnest_rendering_1, display_form .. ': ' .. price)
end
end
end
Crowsnest.update_destination_renderings()
end
Public.generate_overworld_destination{x = highest_x, y = lane_yvalue}
end
memory['greatest_overworldx_generated_for_' .. lane_yvalue] = highest_x
end
function Public.is_position_free_to_move_to(p)
local memory = Memory.get_crew_memory()
local ret = true
for _, destination_data in pairs(memory.destinations) do
if p.x >= destination_data.overworld_position.x + 1 and p.x <= destination_data.overworld_position.x + destination_data.iconized_map_width + Crowsnest.platformwidth - 1 and p.y >= destination_data.overworld_position.y - destination_data.iconized_map_width/2 - Crowsnest.platformheight/2 + 1 and p.y <= destination_data.overworld_position.y + destination_data.iconized_map_width/2 + Crowsnest.platformheight/2 - 1 then
ret = false
break
end
end
return ret
end
function Public.check_for_kraken_collisions()
local memory = Memory.get_crew_memory()
local krakens = memory.overworld_krakens
for i, k in ipairs(krakens) do
local relativex = Crowsnest.platformrightmostedge + k.x - memory.overworldx
local relativey = k.y - memory.overworldy
if (relativex <= 3.5 and relativex >= -3.5 and relativey >= -4 and relativey <= 4) then
Kraken.try_spawn_kraken()
memory.overworld_krakens = Utils.ordered_table_with_index_removed(krakens, i)
end
end
end
function Public.check_for_destination_collisions()
local memory = Memory.get_crew_memory()
-- if memory.overworldx > CoreData.victory_x - 10 then return end
-- to avoid crashing into the finish line...
for _, destination_data in pairs(memory.destinations) do
local relativex = Crowsnest.platformrightmostedge + destination_data.overworld_position.x - memory.overworldx
local relativey = destination_data.overworld_position.y - memory.overworldy
if (relativex == 4 and relativey + destination_data.iconized_map_height/2 >= -3.5 and relativey - destination_data.iconized_map_height/2 <= 3.5) then
--or (relativey - destination_data.iconized_map.height/2 == 5 and (relativex >= -3.5 or relativex <= 4.5)) or (relativey + destination_data.iconized_map.height/2 == -4 and (relativex >= -3.5 or relativex <= 4.5))
Surfaces.create_surface(destination_data)
local index = destination_data.destination_index
if destination_data.type == Surfaces.enum.ISLAND then
Crowsnest.paint_around_destination(index, CoreData.overworld_loading_tile)
end
if memory.overworldx == 600 then
Parrot.parrot_radioactive_tip_1()
elseif memory.overworldx == 800 then
Parrot.parrot_800_tip()
end
Surfaces.clean_up(Common.current_destination())
memory.loadingticks = 0
memory.mapbeingloadeddestination_index = index
memory.currentdestination_index = index
memory.boat.state = Boats.enum_state.ATSEA_LOADING_MAP
local destination = Common.current_destination()
local name = destination.static_params.name and destination.static_params.name or 'NameNotFound'
local message = '[' .. memory.name .. '] Loading destination ' .. (memory.destinationsvisited_indices and (#memory.destinationsvisited_indices + 1) or 0) .. ', ' .. name .. '.'
Common.notify_game(message)
if memory.overworldx == 40*5 then Parrot.parrot_boats_warning() end
return true
end
end
return false
end
function Public.try_overworld_move_v2(vector) --islands stay, crowsnest moves
local memory = Memory.get_crew_memory()
if memory.game_lost or (memory.victory_pause_until_tick and game.tick < memory.victory_pause_until_tick) then return end
if memory.victory_continue_message then
memory.victory_continue_message = false
local message = 'The run now continues on \'Freeplay\'.'
Common.notify_force(game.forces[memory.force_name], message, CoreData.colors.notify_victory)
end
Public.ensure_lane_generated_up_to(0, memory.overworldx + Crowsnest.Data.visibilitywidth)
Public.ensure_lane_generated_up_to(24, memory.overworldx + Crowsnest.Data.visibilitywidth)
Public.ensure_lane_generated_up_to(-24, memory.overworldx + Crowsnest.Data.visibilitywidth)
Public.overwrite_a_dock_upgrade()
if not Public.is_position_free_to_move_to{x = memory.overworldx + vector.x, y = memory.overworldy+ vector.y} then
if _DEBUG then log(string.format('can\'t move by ' .. vector.x .. ', ' .. vector.y)) end
return false
else
Crowsnest.move_crowsnest(vector.x, vector.y)
if vector.x > 0 then
-- crew bonus resources per x:
local crew = Common.crew_get_crew_members()
for _, player in pairs(crew) do
if Common.validate_player_and_character(player) then
local player_index = player.index
if memory.classes_table and memory.classes_table[player_index] and memory.classes_table[player_index] == Classes.enum.MERCHANT then
Common.flying_text_small(player.surface, player.position, '[color=0.97,0.9,0.2]+[/color]')
Common.give_reward_items{{name = 'coin', count = 40 * vector.x}}
end
end
end
-- other freebies:
for i=1,vector.x do
Common.give_reward_items(Balance.periodic_free_resources_per_x())
Balance.apply_crew_buffs_per_x(game.forces[memory.force_name])
end
end
if memory.overworldx >= CoreData.victory_x and (not (memory.game_lost or memory.game_won)) then
memory.completion_time = Math.ceil((memory.age or 0)/60)
local speedrun_time = (memory.age or 0)/60
local speedrun_time_str = Utils.time_longform(speedrun_time)
memory.game_won = true
-- memory.crew_disband_tick = game.tick + 1200
local message = '[' .. memory.name .. '] Victory, on v' .. CoreData.version_string .. ', ' .. CoreData.difficulty_options[memory.difficulty_option].text .. ', cap ' .. CoreData.capacity_options[memory.capacity_option].text3 .. '. Playtime: '
Server.to_discord_embed_raw(CoreData.comfy_emojis.goldenobese .. message .. speedrun_time_str)
game.play_sound{path='utility/game_won', volume_modifier=0.9}
Common.notify_game(message .. '[font=default-large-semibold]' .. speedrun_time_str .. '[/font]', CoreData.colors.notify_victory)
memory.victory_pause_until_tick = game.tick + 60*5
memory.victory_continue_message = true
end
if memory.overworldx % 40 == 0 then
local modal_captain = nil
local modal_captain_time = 0
for player, time in pairs(memory.captain_accrued_time_data) do
if time > modal_captain_time then
modal_captain_time = time
modal_captain = player
end
end
Highscore.write_score(memory.secs_id, memory.name, modal_captain, memory.completion_time or 0, memory.overworldx, CoreData.version_float, memory.difficulty, memory.capacity)
end
return true
end
end
function Public.overwrite_a_dock_upgrade()
local memory = Memory.get_crew_memory()
if (memory.overworldx % (40*8)) == (40*4-1) then -- pick a point that _must_ be visited, i.e. right before a destination
if (memory.overworldx) == (40*4-1) then -- LEAVE A GAP at x=40*11, because we haven't developed an upgrade to put there yet
for _, dest in pairs(memory.destinations) do
if dest.type == Surfaces.enum.DOCK then
if dest.overworld_position.x == memory.overworldx + 1 + (40*7) then
dest.static_params.upgrade_for_sale = Upgrades.enum.MORE_POWER
end
end
end
else
local upgrade_to_overwrite_with
if not memory.dock_overwrite_variable then memory.dock_overwrite_variable = 1 end
local possible_overwrites = {}
if (not memory.merchant_ships_unlocked) then
possible_overwrites[#possible_overwrites + 1] = Upgrades.enum.UNLOCK_MERCHANTS
end
if (not memory.rockets_for_sale) then
possible_overwrites[#possible_overwrites + 1] = Upgrades.enum.ROCKETS_FOR_SALE
end
if #possible_overwrites > 0 then
if memory.dock_overwrite_variable > #possible_overwrites then memory.dock_overwrite_variable = 1 end
upgrade_to_overwrite_with = possible_overwrites[memory.dock_overwrite_variable]
-- bump the variable up, but only if the list hasn't reduced in length. use a second variable to track this:
if memory.dock_overwrite_variable_2 and memory.dock_overwrite_variable_2 == #possible_overwrites then
memory.dock_overwrite_variable = memory.dock_overwrite_variable + 1
end
memory.dock_overwrite_variable_2 = #possible_overwrites
end
if upgrade_to_overwrite_with then
for _, dest in pairs(memory.destinations) do
if dest.type == Surfaces.enum.DOCK then
if dest.overworld_position.x == memory.overworldx + 1 + (40*7) then
dest.static_params.upgrade_for_sale = upgrade_to_overwrite_with
end
end
end
end
end
end
end
return Public

303
maps/pirates/parrot.lua Normal file
View File

@@ -0,0 +1,303 @@
local Math = require 'maps.pirates.math'
local Memory = require 'maps.pirates.memory'
local inspect = require 'utils.inspect'.inspect
local Token = require 'utils.token'
local CoreData = require 'maps.pirates.coredata'
local Task = require 'utils.task'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Public = {}
local enum = {
IDLE_FLY = 'idle_fly',
FLY = 'fly',
TIP_FLYING_1 = 'tip_flying_1',
TIP_FLYING_2 = 'tip_flying_2',
TIP_LANDED_1 = 'tip_landed_1',
TIP_LANDED_2 = 'tip_landed_2',
TIP_SQUAWK = 'tip_squawk',
}
Public.enum = enum
local parrot_tip_interval = 15*60
Public.framecounts = {
idle_fly = 5,
fly = 8,
fly_right = 8,
squawk = 6,
freak = 2,
walk = 8,
chill = 1,
}
-- local parrot_tips = {
-- "Why not buy the map designer a coffee! ko-fi.com/thesixthroc!",
-- "Why not buy the map designer a coffee! ko-fi.com/thesixthroc!",
-- "Make suggestions at getcomfy.eu/discord!",
-- "To launch a second run, you need a fifth of the server's pirates to endorse it!",
-- "Resources granted to the ship appear in the captain's cabin!",
-- "On each island after the first, the ship generates ore!",
-- "Charge the silo to launch a rocket!",
-- "Launching rockets makes gold and coin!",
-- "Charging silos makes pollution and evo!",
-- "The number of non-afk crewmembers affects pollution, evo and maximum stay time!",
-- "Once a silo has launched a rocket, biters will ignore it!",
-- "Charging a silo drains power from everything else on the network...",
-- "You can steer the boat from the crow's nest by placing 100 rail signals in one of the blue boxes!",
-- "When you visit a dock, the shop is updated with special trades!",
-- "Labs produce more research the further you've travelled!",
-- "On radioactive islands, biters don\'t care if you emit pollution! They only care how long you stay...",
-- "If X marks the spot - use inserters to dig!",
-- }
function Public.parrot_0()
local memory = Memory.get_crew_memory()
Common.parrot_speak(game.forces[memory.force_name], 'We can wait here for as long as we like.')
end
function Public.parrot_40()
local memory = Memory.get_crew_memory()
Common.parrot_speak(game.forces[memory.force_name], 'Market! Market!')
end
function Public.parrot_80()
local memory = Memory.get_crew_memory()
Common.parrot_speak(game.forces[memory.force_name], 'Let\'s build out the ship!')
end
function Public.parrot_boats_warning()
local memory = Memory.get_crew_memory()
Common.parrot_speak(game.forces[memory.force_name], '200 leagues? I think we\'re being chased...')
end
function Public.parrot_kraken_warning()
local memory = Memory.get_crew_memory()
Common.parrot_speak(game.forces[memory.force_name], '400 leagues? What are those pink things I see up ahead...')
end
function Public.parrot_radioactive_tip_1()
local memory = Memory.get_crew_memory()
Common.parrot_speak(game.forces[memory.force_name], '600 leagues? We\'ll need uranium-235 to push away from this island...')
end
function Public.parrot_radioactive_tip_2()
local memory = Memory.get_crew_memory()
Common.parrot_speak(game.forces[memory.force_name], 'Oo, our ship is making sulfuric acid...')
end
function Public.parrot_800_tip()
local memory = Memory.get_crew_memory()
Common.parrot_speak(game.forces[memory.force_name], '800 leagues? The resources needed to leave will get a bit harder now...')
end
function Public.parrot_overstay_tip()
local memory = Memory.get_crew_memory()
Common.parrot_speak(game.forces[memory.force_name], 'We\'ve been here quite a while! Check the evo...')
end
-- function Public.parrot_say_tip()
-- local memory = Memory.get_crew_memory()
-- local crew_force = game.forces[memory.force_name]
-- local tip = parrot_tips[Math.random(#parrot_tips)]
-- Common.parrot_speak(crew_force, tip)
-- end
-- function Public.parrot_tick()
-- local memory = Memory.get_crew_memory()
-- if not (memory.boat and memory.boat.surface_name) then return end
-- local surface = game.surfaces[memory.boat.surface_name]
-- if not surface and surface.valid then return end
-- local destination = Common.current_destination()
-- if destination.dynamic_data and destination.dynamic_data.timer and destination.dynamic_data.timer == Math.ceil(Balance.expected_time_on_island()) and (not destination.dynamic_data.parrot_gave_overstay_tip) then
-- destination.dynamic_data.parrot_gave_overstay_tip = true
-- local spawners = surface.find_entities_filtered({type = 'unit-spawner', force = memory.enemy_force_name})
-- local spawnerscount = #spawners or 0
-- if spawnerscount > 0 then --check biter bases actually exist
-- Public.parrot_overstay_tip()
-- end
-- end
-- local boat = memory.boat
-- local parrot = boat.parrot
-- local frame = parrot.frame
-- local render = parrot.render
-- local render_name = parrot.render_name
-- local state = parrot.state
-- local state_counter = parrot.state_counter or parrot_tip_interval*60/5
-- local resting_position_relative_to_boat = parrot.resting_position_relative_to_boat
-- local position_relative_to_boat = parrot.position_relative_to_boat
-- local sprite_extra_offset = boat.parrot.sprite_extra_offset
-- local text_extra_offset = boat.parrot.text_extra_offset
-- local real_position = Utils.psum{position_relative_to_boat, boat.position}
-- if state == enum.IDLE_FLY then
-- local ate_fish
-- if boat.state and boat.state == 'landed' and state_counter >= parrot_tip_interval*60/5 then
-- local nearby_characters = surface.find_entities_filtered{position = real_position, radius = 4, name = 'character'}
-- local nearby_characters_count = #nearby_characters
-- if nearby_characters_count > 0 then
-- 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
-- local player = nearby_characters[j].player
-- local inv = player.get_inventory(defines.inventory.character_main)
-- if inv and inv.get_item_count('raw-fish') >= 2 then
-- Common.give(player, {{name = 'raw-fish', count = -2, color = CoreData.colors.fish}})
-- ate_fish = true
-- break
-- end
-- end
-- j = j + 1
-- end
-- end
-- end
-- state_counter = state_counter + 1
-- if ate_fish then
-- Common.parrot_speak(game.forces[memory.force_name], 'Tasty...')
-- local p1 = {x = boat.position.x - 15 - Math.random(35), y = boat.position.y - 8 + Math.random(15)}
-- local p2 = surface.find_non_colliding_position('stone-furnace', p1, 6, 0.5)
-- parrot.spot_to_fly_from = position_relative_to_boat
-- local real_fly_to = p2 or p1
-- parrot.spot_to_fly_to = {x = real_fly_to.x - boat.position.x, y = real_fly_to.y - boat.position.y}
-- parrot.fly_distance = Math.distance(parrot.spot_to_fly_from, parrot.spot_to_fly_to)
-- state = enum.TIP_FLYING_1
-- state_counter = 0
-- else
-- if game.tick % 10 == 0 then
-- frame = frame + 1
-- end
-- if boat.speed and boat.speed > 0 then
-- state = enum.FLY
-- end
-- end
-- elseif state == enum.TIP_FLYING_1 then
-- if boat.speed and boat.speed > 0 then
-- state_counter = 0
-- state = enum.IDLE_FLY
-- position_relative_to_boat = resting_position_relative_to_boat
-- else
-- if game.tick % 10 == 0 then
-- frame = frame + 1
-- end
-- if state_counter < parrot.fly_distance then
-- position_relative_to_boat = Utils.interpolate(parrot.spot_to_fly_from, parrot.spot_to_fly_to, state_counter/parrot.fly_distance)
-- state_counter = state_counter + 0.5
-- else
-- state_counter = 0
-- state = enum.TIP_LANDED_1
-- end
-- end
-- elseif state == enum.TIP_LANDED_1 then
-- if boat.speed and boat.speed > 0 then
-- state_counter = 0
-- state = enum.IDLE_FLY
-- position_relative_to_boat = resting_position_relative_to_boat
-- else
-- if state_counter < 20 then
-- state_counter = state_counter + 1
-- else
-- state_counter = 0
-- state = enum.TIP_SQUAWK
-- end
-- end
-- elseif state == enum.TIP_SQUAWK then
-- if boat.speed and boat.speed > 0 then
-- state_counter = 0
-- state = enum.IDLE_FLY
-- position_relative_to_boat = resting_position_relative_to_boat
-- else
-- if state_counter == 0 then
-- Public.parrot_say_tip()
-- end
-- if state_counter < 18 then
-- if game.tick % 15 == 0 then
-- frame = frame + 1
-- end
-- state_counter = state_counter + 1
-- else
-- state_counter = 0
-- state = enum.TIP_LANDED_2
-- end
-- end
-- elseif state == enum.TIP_LANDED_2 then
-- if boat.speed and boat.speed > 0 then
-- state_counter = 0
-- state = enum.IDLE_FLY
-- position_relative_to_boat = resting_position_relative_to_boat
-- else
-- if state_counter < 20 then
-- state_counter = state_counter + 1
-- else
-- state_counter = 0
-- state = enum.TIP_FLYING_2
-- local hold = parrot.spot_to_fly_to
-- parrot.spot_to_fly_to = parrot.spot_to_fly_from
-- parrot.spot_to_fly_from = hold
-- end
-- end
-- elseif state == enum.TIP_FLYING_2 then
-- if boat.speed and boat.speed > 0 then
-- state_counter = 0
-- state = enum.IDLE_FLY
-- position_relative_to_boat = resting_position_relative_to_boat
-- else
-- if game.tick % 10 == 0 then
-- frame = frame + 1
-- end
-- if state_counter < parrot.fly_distance then
-- position_relative_to_boat = Utils.interpolate(parrot.spot_to_fly_from, parrot.spot_to_fly_to, state_counter/parrot.fly_distance)
-- state_counter = state_counter + 0.5
-- else
-- state_counter = 0
-- state = enum.IDLE_FLY
-- end
-- end
-- elseif state == enum.FLY then
-- if game.tick % 10 == 0 then
-- frame = frame + 1
-- end
-- if (not boat.speed) or (boat.speed == 0) then state = enum.IDLE_FLY end
-- end
-- local sprite_name = state
-- if state == enum.TIP_FLYING_1 then sprite_name = 'fly' end
-- if state == enum.TIP_FLYING_2 then sprite_name = 'fly_right' end
-- if state == enum.TIP_LANDED_1 or state == enum.TIP_LANDED_2 then sprite_name = 'chill' end
-- if state == enum.TIP_SQUAWK then sprite_name = 'squawk' end
-- if frame > Public.framecounts[sprite_name] then frame = 1 end
-- parrot.state = state
-- parrot.frame = frame
-- parrot.state_counter = state_counter
-- parrot.position_relative_to_boat = position_relative_to_boat
-- rendering.set_sprite(render, "file/parrot/parrot_" .. sprite_name .. "_" .. frame .. ".png")
-- rendering.set_target(render, rendering.get_target(render).entity, Utils.psum{sprite_extra_offset, position_relative_to_boat})
-- rendering.set_visible(render, true)
-- rendering.set_target(render_name, rendering.get_target(render_name).entity, Utils.psum{text_extra_offset, position_relative_to_boat})
-- rendering.set_visible(render_name, true)
-- end
return Public

View File

@@ -0,0 +1,871 @@
--scraped and tidied from https://en.wikipedia.org/wiki/Lists_of_colors by thesixthroc
return {
["absolute zero"] = {r = 0., g = 0.28, b = 0.73},
["acid green"] = {r = 0.69, g = 0.75, b = 0.1},
["aero"] = {r = 0.49, g = 0.73, b = 0.91},
["aero blue"] = {r = 0.75, g = 0.91, b = 0.84},
["african violet"] = {r = 0.7, g = 0.52, b = 0.75},
["air superiority blue"] = {r = 0.45, g = 0.63, b = 0.76},
["alabaster"] = {r = 0.93, g = 0.92, b = 0.88},
["alice blue"] = {r = 0.94, g = 0.97, b = 1.},
["alloy orange"] = {r = 0.77, g = 0.38, b = 0.06},
["almond"] = {r = 0.94, g = 0.87, b = 0.8},
["amaranth"] = {r = 0.9, g = 0.17, b = 0.31},
["amaranth pink"] = {r = 0.95, g = 0.61, b = 0.73},
["amaranth purple"] = {r = 0.67, g = 0.15, b = 0.31},
["amaranth red"] = {r = 0.83, g = 0.13, b = 0.18},
["amazon"] = {r = 0.23, g = 0.48, b = 0.34},
["amber"] = {r = 1., g = 0.75, b = 0.},
["amethyst"] = {r = 0.6, g = 0.4, b = 0.8},
["android green"] = {r = 0.24, g = 0.86, b = 0.53},
["antique brass"] = {r = 0.8, g = 0.58, b = 0.46},
["antique bronze"] = {r = 0.4, g = 0.36, b = 0.12},
["antique fuchsia"] = {r = 0.57, g = 0.36, b = 0.51},
["antique ruby"] = {r = 0.52, g = 0.11, b = 0.18},
["antique white"] = {r = 0.98, g = 0.92, b = 0.84},
["ao"] = {r = 0., g = 0.5, b = 0.},
["apple green"] = {r = 0.55, g = 0.71, b = 0.},
["apricot"] = {r = 0.98, g = 0.81, b = 0.69},
["aqua"] = {r = 0., g = 1., b = 1.},
["aquamarine"] = {r = 0.5, g = 1., b = 0.83},
["arctic lime"] = {r = 0.82, g = 1., b = 0.08},
["army green"] = {r = 0.29, g = 0.33, b = 0.13},
["artichoke"] = {r = 0.56, g = 0.59, b = 0.47},
["arylide yellow"] = {r = 0.91, g = 0.84, b = 0.42},
["ash gray"] = {r = 0.7, g = 0.75, b = 0.71},
["asparagus"] = {r = 0.53, g = 0.66, b = 0.42},
["atomic tangerine"] = {r = 1., g = 0.6, b = 0.4},
["auburn"] = {r = 0.65, g = 0.16, b = 0.16},
["aureolin"] = {r = 0.99, g = 0.93, b = 0.},
["avocado"] = {r = 0.34, g = 0.51, b = 0.01},
["azure"] = {r = 0., g = 0.5, b = 1.},
["baby blue"] = {r = 0.54, g = 0.81, b = 0.94},
["baby blue eyes"] = {r = 0.63, g = 0.79, b = 0.95},
["baby pink"] = {r = 0.96, g = 0.76, b = 0.76},
["baby powder"] = {r = 1., g = 1., b = 0.98},
["baker-miller pink"] = {r = 1., g = 0.57, b = 0.69},
["banana"] = {r = 0.98, g = 0.91, b = 0.71},
["barbie pink"] = {r = 0.85, g = 0.09, b = 0.52},
["barn red"] = {r = 0.49, g = 0.04, b = 0.01},
["battleship grey"] = {r = 0.52, g = 0.52, b = 0.51},
["beau blue"] = {r = 0.74, g = 0.83, b = 0.9},
["beaver"] = {r = 0.62, g = 0.51, b = 0.44},
["beige"] = {r = 0.96, g = 0.96, b = 0.86},
["b'dazzled blue"] = {r = 0.18, g = 0.35, b = 0.58},
["big dip o’ruby"] = {r = 0.61, g = 0.15, b = 0.26},
["bisque"] = {r = 1., g = 0.89, b = 0.77},
["bistre"] = {r = 0.24, g = 0.17, b = 0.12},
["bistre brown"] = {r = 0.59, g = 0.44, b = 0.09},
["bitter lemon"] = {r = 0.79, g = 0.88, b = 0.05},
["bitter lime"] = {r = 0.75, g = 1., b = 0.},
["bittersweet"] = {r = 1., g = 0.44, b = 0.37},
["bittersweet shimmer"] = {r = 0.75, g = 0.31, b = 0.32},
["black"] = {r = 0., g = 0., b = 0.},
["black bean"] = {r = 0.24, g = 0.05, b = 0.01},
["black chocolate"] = {r = 0.11, g = 0.09, b = 0.07},
["black coffee"] = {r = 0.23, g = 0.18, b = 0.18},
["black coral"] = {r = 0.33, g = 0.38, b = 0.44},
["black olive"] = {r = 0.23, g = 0.24, b = 0.21},
["black shadows"] = {r = 0.75, g = 0.69, b = 0.7},
["blanched almond"] = {r = 1., g = 0.92, b = 0.8},
["blast-off bronze"] = {r = 0.65, g = 0.44, b = 0.39},
["bleu de france"] = {r = 0.19, g = 0.55, b = 0.91},
["blizzard blue"] = {r = 0.67, g = 0.9, b = 0.93},
["blond"] = {r = 0.98, g = 0.94, b = 0.75},
["blood red"] = {r = 0.4, g = 0., b = 0.},
["blue"] = {r = 0., g = 0., b = 1.},
["blue bell"] = {r = 0.64, g = 0.64, b = 0.82},
["blue-gray"] = {r = 0.4, g = 0.6, b = 0.8},
["blue-green"] = {r = 0.05, g = 0.6, b = 0.73},
["blue jeans"] = {r = 0.36, g = 0.68, b = 0.93},
["blue sapphire"] = {r = 0.07, g = 0.38, b = 0.5},
["blue-violet"] = {r = 0.54, g = 0.17, b = 0.89},
["blue yonder"] = {r = 0.31, g = 0.45, b = 0.65},
["bluetiful"] = {r = 0.24, g = 0.41, b = 0.91},
["blush"] = {r = 0.87, g = 0.36, b = 0.51},
["bole"] = {r = 0.47, g = 0.27, b = 0.23},
["bone"] = {r = 0.89, g = 0.85, b = 0.79},
["bottle green"] = {r = 0., g = 0.42, b = 0.31},
["brandy"] = {r = 0.53, g = 0.25, b = 0.25},
["brick red"] = {r = 0.8, g = 0.25, b = 0.33},
["bright green"] = {r = 0.4, g = 1., b = 0.},
["bright lilac"] = {r = 0.85, g = 0.57, b = 0.94},
["bright maroon"] = {r = 0.76, g = 0.13, b = 0.28},
["bright navy blue"] = {r = 0.1, g = 0.45, b = 0.82},
["bright yellow"] = {r = 1., g = 0.67, b = 0.11},
["brilliant rose"] = {r = 1., g = 0.33, b = 0.64},
["brink pink"] = {r = 0.98, g = 0.38, b = 0.5},
["british racing green"] = {r = 0., g = 0.26, b = 0.15},
["bronze"] = {r = 0.8, g = 0.5, b = 0.2},
["brown"] = {r = 0.53, g = 0.33, b = 0.04},
["brown sugar"] = {r = 0.69, g = 0.43, b = 0.3},
["brunswick green"] = {r = 0.11, g = 0.3, b = 0.24},
["bud green"] = {r = 0.48, g = 0.71, b = 0.38},
["buff"] = {r = 1., g = 0.78, b = 0.5},
["burgundy"] = {r = 0.5, g = 0., b = 0.13},
["burlywood"] = {r = 0.87, g = 0.72, b = 0.53},
["burnished brown"] = {r = 0.63, g = 0.48, b = 0.45},
["burnt orange"] = {r = 0.8, g = 0.33, b = 0.},
["burnt sienna"] = {r = 0.91, g = 0.45, b = 0.32},
["burnt umber"] = {r = 0.54, g = 0.2, b = 0.14},
["byzantine"] = {r = 0.74, g = 0.2, b = 0.64},
["byzantium"] = {r = 0.44, g = 0.16, b = 0.39},
["cadet"] = {r = 0.33, g = 0.41, b = 0.45},
["cadet blue"] = {r = 0.37, g = 0.62, b = 0.63},
["cadet grey"] = {r = 0.57, g = 0.64, b = 0.69},
["cadmium green"] = {r = 0., g = 0.42, b = 0.24},
["cadmium orange"] = {r = 0.93, g = 0.53, b = 0.18},
["cadmium red"] = {r = 0.89, g = 0., b = 0.13},
["cadmium yellow"] = {r = 1., g = 0.96, b = 0.},
["café au lait"] = {r = 0.65, g = 0.48, b = 0.36},
["café noir"] = {r = 0.29, g = 0.21, b = 0.13},
["cambridge blue"] = {r = 0.64, g = 0.76, b = 0.68},
["camel"] = {r = 0.76, g = 0.6, b = 0.42},
["cameo pink"] = {r = 0.94, g = 0.73, b = 0.8},
["canary"] = {r = 1., g = 1., b = 0.6},
["canary yellow"] = {r = 1., g = 0.94, b = 0.},
["candy apple red"] = {r = 1., g = 0.03, b = 0.},
["candy pink"] = {r = 0.89, g = 0.44, b = 0.48},
["capri"] = {r = 0., g = 0.75, b = 1.},
["caput mortuum"] = {r = 0.35, g = 0.15, b = 0.13},
["cardinal"] = {r = 0.77, g = 0.12, b = 0.23},
["caribbean green"] = {r = 0., g = 0.8, b = 0.6},
["carmine"] = {r = 0.59, g = 0., b = 0.09},
["carnation pink"] = {r = 1., g = 0.65, b = 0.79},
["carnelian"] = {r = 0.7, g = 0.11, b = 0.11},
["carolina blue"] = {r = 0.34, g = 0.63, b = 0.83},
["carrot orange"] = {r = 0.93, g = 0.57, b = 0.13},
["castleton green"] = {r = 0., g = 0.34, b = 0.25},
["catawba"] = {r = 0.44, g = 0.21, b = 0.26},
["cedar chest"] = {r = 0.79, g = 0.35, b = 0.29},
["celadon"] = {r = 0.67, g = 0.88, b = 0.69},
["celadon blue"] = {r = 0., g = 0.48, b = 0.65},
["celadon green"] = {r = 0.18, g = 0.52, b = 0.49},
["celeste"] = {r = 0.7, g = 1., b = 1.},
["celtic blue"] = {r = 0.14, g = 0.42, b = 0.81},
["cerise"] = {r = 0.87, g = 0.19, b = 0.39},
["cerulean"] = {r = 0., g = 0.48, b = 0.65},
["cerulean blue"] = {r = 0.16, g = 0.32, b = 0.75},
["cerulean frost"] = {r = 0.43, g = 0.61, b = 0.76},
["cg blue"] = {r = 0., g = 0.48, b = 0.65},
["cg red"] = {r = 0.88, g = 0.24, b = 0.19},
["champagne"] = {r = 0.97, g = 0.91, b = 0.81},
["champagne pink"] = {r = 0.95, g = 0.87, b = 0.81},
["charcoal"] = {r = 0.21, g = 0.27, b = 0.31},
["charleston green"] = {r = 0.14, g = 0.17, b = 0.17},
["charm pink"] = {r = 0.9, g = 0.56, b = 0.67},
["chartreuse"] = {r = 0.87, g = 1., b = 0.},
["cherry blossom pink"] = {r = 1., g = 0.72, b = 0.77},
["chestnut"] = {r = 0.58, g = 0.27, b = 0.21},
["chili red"] = {r = 0.89, g = 0.24, b = 0.16},
["china pink"] = {r = 0.87, g = 0.44, b = 0.63},
["china rose"] = {r = 0.66, g = 0.32, b = 0.43},
["chinese red"] = {r = 0.67, g = 0.22, b = 0.12},
["chinese violet"] = {r = 0.52, g = 0.38, b = 0.53},
["chinese yellow"] = {r = 1., g = 0.7, b = 0.},
["chocolate"] = {r = 0.48, g = 0.25, b = 0.},
["chocolate cosmos"] = {r = 0.35, g = 0.07, b = 0.1},
["chrome yellow"] = {r = 1., g = 0.65, b = 0.},
["cinereous"] = {r = 0.6, g = 0.51, b = 0.48},
["cinnabar"] = {r = 0.89, g = 0.26, b = 0.2},
["cinnamon satin"] = {r = 0.8, g = 0.38, b = 0.49},
["citrine"] = {r = 0.89, g = 0.82, b = 0.04},
["citron"] = {r = 0.62, g = 0.66, b = 0.12},
["claret"] = {r = 0.5, g = 0.09, b = 0.2},
["cobalt blue"] = {r = 0., g = 0.28, b = 0.67},
["cocoa brown"] = {r = 0.82, g = 0.41, b = 0.12},
["coffee"] = {r = 0.44, g = 0.31, b = 0.22},
["columbia blue"] = {r = 0.73, g = 0.85, b = 0.92},
["congo pink"] = {r = 0.97, g = 0.51, b = 0.47},
["cool grey"] = {r = 0.55, g = 0.57, b = 0.67},
["copper"] = {r = 0.72, g = 0.45, b = 0.2},
["copper penny"] = {r = 0.68, g = 0.44, b = 0.41},
["copper red"] = {r = 0.8, g = 0.43, b = 0.32},
["copper rose"] = {r = 0.6, g = 0.4, b = 0.4},
["coquelicot"] = {r = 1., g = 0.22, b = 0.},
["coral"] = {r = 1., g = 0.5, b = 0.31},
["coral pink"] = {r = 0.97, g = 0.51, b = 0.47},
["cordovan"] = {r = 0.54, g = 0.25, b = 0.27},
["corn"] = {r = 0.98, g = 0.93, b = 0.36},
["cornell red"] = {r = 0.7, g = 0.11, b = 0.11},
["cornflower blue"] = {r = 0.39, g = 0.58, b = 0.93},
["cornsilk"] = {r = 1., g = 0.97, b = 0.86},
["cosmic cobalt"] = {r = 0.18, g = 0.18, b = 0.53},
["cosmic latte"] = {r = 1., g = 0.97, b = 0.91},
["coyote brown"] = {r = 0.51, g = 0.38, b = 0.24},
["cotton candy"] = {r = 1., g = 0.74, b = 0.85},
["cream"] = {r = 1., g = 0.99, b = 0.82},
["crimson"] = {r = 0.86, g = 0.08, b = 0.24},
["crystal"] = {r = 0.65, g = 0.85, b = 0.87},
["cultured"] = {r = 0.96, g = 0.96, b = 0.96},
["cyan"] = {r = 0., g = 1., b = 1.},
["cyber grape"] = {r = 0.35, g = 0.26, b = 0.49},
["cyber yellow"] = {r = 1., g = 0.83, b = 0.},
["cyclamen"] = {r = 0.96, g = 0.44, b = 0.63},
["dark blue-gray"] = {r = 0.4, g = 0.4, b = 0.6},
["dark brown"] = {r = 0.4, g = 0.26, b = 0.13},
["dark byzantium"] = {r = 0.36, g = 0.22, b = 0.33},
["dark cornflower blue"] = {r = 0.15, g = 0.26, b = 0.55},
["dark cyan"] = {r = 0., g = 0.55, b = 0.55},
["dark electric blue"] = {r = 0.33, g = 0.41, b = 0.47},
["dark goldenrod"] = {r = 0.72, g = 0.53, b = 0.04},
["dark green"] = {r = 0., g = 0.2, b = 0.13},
["dark jungle green"] = {r = 0.1, g = 0.14, b = 0.13},
["dark khaki"] = {r = 0.74, g = 0.72, b = 0.42},
["dark lava"] = {r = 0.28, g = 0.24, b = 0.2},
["dark liver"] = {r = 0.33, g = 0.29, b = 0.31},
["dark magenta"] = {r = 0.55, g = 0., b = 0.55},
["dark moss green"] = {r = 0.29, g = 0.36, b = 0.14},
["dark olive green"] = {r = 0.33, g = 0.42, b = 0.18},
["dark orange"] = {r = 1., g = 0.55, b = 0.},
["dark orchid"] = {r = 0.6, g = 0.2, b = 0.8},
["dark pastel green"] = {r = 0.01, g = 0.75, b = 0.24},
["dark purple"] = {r = 0.19, g = 0.1, b = 0.2},
["dark red"] = {r = 0.55, g = 0., b = 0.},
["dark salmon"] = {r = 0.91, g = 0.59, b = 0.48},
["dark sea green"] = {r = 0.56, g = 0.74, b = 0.56},
["dark sienna"] = {r = 0.24, g = 0.08, b = 0.08},
["dark sky blue"] = {r = 0.55, g = 0.75, b = 0.84},
["dark slate blue"] = {r = 0.28, g = 0.24, b = 0.55},
["dark slate gray"] = {r = 0.18, g = 0.31, b = 0.31},
["dark spring green"] = {r = 0.09, g = 0.45, b = 0.27},
["dark turquoise"] = {r = 0., g = 0.81, b = 0.82},
["dark violet"] = {r = 0.58, g = 0., b = 0.83},
["dartmouth green"] = {r = 0., g = 0.44, b = 0.24},
["davy's grey"] = {r = 0.33, g = 0.33, b = 0.33},
["deep cerise"] = {r = 0.85, g = 0.2, b = 0.53},
["deep champagne"] = {r = 0.98, g = 0.84, b = 0.65},
["deep chestnut"] = {r = 0.73, g = 0.31, b = 0.28},
["deep jungle green"] = {r = 0., g = 0.29, b = 0.29},
["deep pink"] = {r = 1., g = 0.08, b = 0.58},
["deep saffron"] = {r = 1., g = 0.6, b = 0.2},
["deep sky blue"] = {r = 0., g = 0.75, b = 1.},
["deep space sparkle"] = {r = 0.29, g = 0.39, b = 0.42},
["deep taupe"] = {r = 0.49, g = 0.37, b = 0.38},
["denim"] = {r = 0.08, g = 0.38, b = 0.74},
["denim blue"] = {r = 0.13, g = 0.26, b = 0.71},
["desert"] = {r = 0.76, g = 0.6, b = 0.42},
["desert sand"] = {r = 0.93, g = 0.79, b = 0.69},
["dim gray"] = {r = 0.41, g = 0.41, b = 0.41},
["dodger blue"] = {r = 0.12, g = 0.56, b = 1.},
["dogwood rose"] = {r = 0.84, g = 0.09, b = 0.41},
["drab"] = {r = 0.59, g = 0.44, b = 0.09},
["duke blue"] = {r = 0., g = 0., b = 0.61},
["dutch white"] = {r = 0.94, g = 0.87, b = 0.73},
["earth yellow"] = {r = 0.88, g = 0.66, b = 0.37},
["ebony"] = {r = 0.33, g = 0.36, b = 0.31},
["ecru"] = {r = 0.76, g = 0.7, b = 0.5},
["eerie black"] = {r = 0.11, g = 0.11, b = 0.11},
["eggplant"] = {r = 0.38, g = 0.25, b = 0.32},
["eggshell"] = {r = 0.94, g = 0.92, b = 0.84},
["egyptian blue"] = {r = 0.06, g = 0.2, b = 0.65},
["eigengrau"] = {r = 0.09, g = 0.09, b = 0.11},
["electric blue"] = {r = 0.49, g = 0.98, b = 1.},
["electric green"] = {r = 0., g = 1., b = 0.},
["electric indigo"] = {r = 0.44, g = 0., b = 1.},
["electric lime"] = {r = 0.8, g = 1., b = 0.},
["electric purple"] = {r = 0.75, g = 0., b = 1.},
["electric violet"] = {r = 0.56, g = 0., b = 1.},
["emerald"] = {r = 0.31, g = 0.78, b = 0.47},
["eminence"] = {r = 0.42, g = 0.19, b = 0.51},
["english green"] = {r = 0.11, g = 0.3, b = 0.24},
["english lavender"] = {r = 0.71, g = 0.51, b = 0.58},
["english red"] = {r = 0.67, g = 0.29, b = 0.32},
["english vermillion"] = {r = 0.8, g = 0.28, b = 0.29},
["english violet"] = {r = 0.34, g = 0.24, b = 0.36},
["erin"] = {r = 0., g = 1., b = 0.25},
["eton blue"] = {r = 0.59, g = 0.78, b = 0.64},
["fallow"] = {r = 0.76, g = 0.6, b = 0.42},
["falu red"] = {r = 0.5, g = 0.09, b = 0.09},
["fandango"] = {r = 0.71, g = 0.2, b = 0.54},
["fandango pink"] = {r = 0.87, g = 0.32, b = 0.52},
["fashion fuchsia"] = {r = 0.96, g = 0., b = 0.63},
["fawn"] = {r = 0.9, g = 0.67, b = 0.44},
["feldgrau"] = {r = 0.3, g = 0.36, b = 0.33},
["fern green"] = {r = 0.31, g = 0.47, b = 0.26},
["field drab"] = {r = 0.42, g = 0.33, b = 0.12},
["fiery rose"] = {r = 1., g = 0.33, b = 0.44},
["firebrick"] = {r = 0.7, g = 0.13, b = 0.13},
["fire engine red"] = {r = 0.81, g = 0.13, b = 0.16},
["fire opal"] = {r = 0.91, g = 0.36, b = 0.29},
["flame"] = {r = 0.89, g = 0.35, b = 0.13},
["flax"] = {r = 0.93, g = 0.86, b = 0.51},
["flirt"] = {r = 0.64, g = 0., b = 0.43},
["floral white"] = {r = 1., g = 0.98, b = 0.94},
["fluorescent blue"] = {r = 0.08, g = 0.96, b = 0.93},
["forest green"] = {r = 0., g = 0.27, b = 0.13},
["french beige"] = {r = 0.65, g = 0.48, b = 0.36},
["french bistre"] = {r = 0.52, g = 0.43, b = 0.3},
["french blue"] = {r = 0., g = 0.45, b = 0.73},
["french fuchsia"] = {r = 0.99, g = 0.25, b = 0.57},
["french lilac"] = {r = 0.53, g = 0.38, b = 0.56},
["french lime"] = {r = 0.62, g = 0.99, b = 0.22},
["french mauve"] = {r = 0.83, g = 0.45, b = 0.83},
["french pink"] = {r = 0.99, g = 0.42, b = 0.62},
["french raspberry"] = {r = 0.78, g = 0.17, b = 0.28},
["french rose"] = {r = 0.96, g = 0.29, b = 0.54},
["french sky blue"] = {r = 0.47, g = 0.71, b = 1.},
["french violet"] = {r = 0.53, g = 0.02, b = 0.81},
["frostbite"] = {r = 0.91, g = 0.21, b = 0.65},
["fuchsia"] = {r = 1., g = 0., b = 1.},
["fuchsia purple"] = {r = 0.8, g = 0.22, b = 0.48},
["fuchsia rose"] = {r = 0.78, g = 0.26, b = 0.46},
["fulvous"] = {r = 0.89, g = 0.52, b = 0.},
["fuzzy wuzzy"] = {r = 0.53, g = 0.26, b = 0.12},
["gainsboro"] = {r = 0.86, g = 0.86, b = 0.86},
["gamboge"] = {r = 0.89, g = 0.61, b = 0.06},
["generic viridian"] = {r = 0., g = 0.5, b = 0.4},
["ghost white"] = {r = 0.97, g = 0.97, b = 1.},
["glaucous"] = {r = 0.38, g = 0.51, b = 0.71},
["glossy grape"] = {r = 0.67, g = 0.57, b = 0.7},
["go green"] = {r = 0., g = 0.67, b = 0.4},
["gold"] = {r = 0.65, g = 0.49, b = 0.},
["gold fusion"] = {r = 0.52, g = 0.46, b = 0.31},
["golden brown"] = {r = 0.6, g = 0.4, b = 0.08},
["golden poppy"] = {r = 0.99, g = 0.76, b = 0.},
["golden yellow"] = {r = 1., g = 0.87, b = 0.},
["goldenrod"] = {r = 0.85, g = 0.65, b = 0.13},
["gotham green"] = {r = 0., g = 0.34, b = 0.25},
["granite gray"] = {r = 0.4, g = 0.4, b = 0.4},
["granny smith apple"] = {r = 0.66, g = 0.89, b = 0.63},
["grey"] = {r = 0.75, g = 0.75, b = 0.75},
["gray"] = {r = 0.75, g = 0.75, b = 0.75},
["green"] = {r = 0., g = 1., b = 0.},
["green-blue"] = {r = 0.07, g = 0.39, b = 0.71},
["green-cyan"] = {r = 0., g = 0.6, b = 0.4},
["green lizard"] = {r = 0.65, g = 0.96, b = 0.2},
["green sheen"] = {r = 0.43, g = 0.68, b = 0.63},
["green-yellow"] = {r = 0.68, g = 1., b = 0.18},
["grullo"] = {r = 0.66, g = 0.6, b = 0.53},
["gunmetal"] = {r = 0.16, g = 0.2, b = 0.22},
["han blue"] = {r = 0.27, g = 0.42, b = 0.81},
["han purple"] = {r = 0.32, g = 0.09, b = 0.98},
["hansa yellow"] = {r = 0.91, g = 0.84, b = 0.42},
["harlequin"] = {r = 0.25, g = 1., b = 0.},
["harvest gold"] = {r = 0.85, g = 0.57, b = 0.},
["heat wave"] = {r = 1., g = 0.48, b = 0.},
["heliotrope"] = {r = 0.87, g = 0.45, b = 1.},
["heliotrope gray"] = {r = 0.67, g = 0.6, b = 0.66},
["hollywood cerise"] = {r = 0.96, g = 0., b = 0.63},
["honeydew"] = {r = 0.94, g = 1., b = 0.94},
["honolulu blue"] = {r = 0., g = 0.43, b = 0.69},
["hooker's green"] = {r = 0.29, g = 0.47, b = 0.42},
["hot magenta"] = {r = 1., g = 0.11, b = 0.81},
["hot pink"] = {r = 1., g = 0.41, b = 0.71},
["hunter green"] = {r = 0.21, g = 0.37, b = 0.23},
["iceberg"] = {r = 0.44, g = 0.65, b = 0.82},
["icterine"] = {r = 0.99, g = 0.97, b = 0.37},
["illuminating emerald"] = {r = 0.19, g = 0.57, b = 0.47},
["imperial red"] = {r = 0.93, g = 0.16, b = 0.22},
["inchworm"] = {r = 0.7, g = 0.93, b = 0.36},
["independence"] = {r = 0.3, g = 0.32, b = 0.43},
["india green"] = {r = 0.07, g = 0.53, b = 0.03},
["indian red"] = {r = 0.8, g = 0.36, b = 0.36},
["indian yellow"] = {r = 0.89, g = 0.66, b = 0.34},
["indigo"] = {r = 0.29, g = 0., b = 0.51},
["indigo dye"] = {r = 0., g = 0.25, b = 0.42},
["international klein blue"] = {r = 0.07, g = 0.04, b = 0.56},
["international orange"] = {r = 0.75, g = 0.21, b = 0.17},
["iris"] = {r = 0.35, g = 0.31, b = 0.81},
["irresistible"] = {r = 0.7, g = 0.27, b = 0.42},
["isabelline"] = {r = 0.96, g = 0.94, b = 0.93},
["italian sky blue"] = {r = 0.7, g = 1., b = 1.},
["ivory"] = {r = 1., g = 1., b = 0.94},
["jade"] = {r = 0., g = 0.66, b = 0.42},
["japanese carmine"] = {r = 0.62, g = 0.16, b = 0.2},
["japanese violet"] = {r = 0.36, g = 0.2, b = 0.34},
["jasmine"] = {r = 0.97, g = 0.87, b = 0.49},
["jazzberry jam"] = {r = 0.65, g = 0.04, b = 0.37},
["jet"] = {r = 0.2, g = 0.2, b = 0.2},
["jonquil"] = {r = 0.96, g = 0.79, b = 0.09},
["june bud"] = {r = 0.74, g = 0.85, b = 0.34},
["jungle green"] = {r = 0.16, g = 0.67, b = 0.53},
["kelly green"] = {r = 0.3, g = 0.73, b = 0.09},
["keppel"] = {r = 0.23, g = 0.69, b = 0.62},
["key lime"] = {r = 0.91, g = 0.96, b = 0.55},
["khaki"] = {r = 0.94, g = 0.9, b = 0.55},
["kobe"] = {r = 0.53, g = 0.18, b = 0.09},
["kobi"] = {r = 0.91, g = 0.62, b = 0.77},
["kobicha"] = {r = 0.42, g = 0.27, b = 0.14},
["kombu green"] = {r = 0.21, g = 0.26, b = 0.19},
["ksu purple"] = {r = 0.31, g = 0.15, b = 0.51},
["languid lavender"] = {r = 0.84, g = 0.79, b = 0.87},
["lapis lazuli"] = {r = 0.15, g = 0.38, b = 0.61},
["laser lemon"] = {r = 1., g = 1., b = 0.4},
["laurel green"] = {r = 0.66, g = 0.73, b = 0.62},
["lava"] = {r = 0.81, g = 0.06, b = 0.13},
["lavender"] = {r = 0.71, g = 0.49, b = 0.86},
["lavender blue"] = {r = 0.8, g = 0.8, b = 1.},
["lavender blush"] = {r = 1., g = 0.94, b = 0.96},
["lavender gray"] = {r = 0.77, g = 0.76, b = 0.82},
["lawn green"] = {r = 0.49, g = 0.99, b = 0.},
["lemon"] = {r = 1., g = 0.97, b = 0.},
["lemon chiffon"] = {r = 1., g = 0.98, b = 0.8},
["lemon curry"] = {r = 0.8, g = 0.63, b = 0.11},
["lemon glacier"] = {r = 0.99, g = 1., b = 0.},
["lemon meringue"] = {r = 0.96, g = 0.92, b = 0.75},
["lemon yellow"] = {r = 1., g = 0.96, b = 0.31},
["liberty"] = {r = 0.33, g = 0.35, b = 0.65},
["light blue"] = {r = 0.68, g = 0.85, b = 0.9},
["light coral"] = {r = 0.94, g = 0.5, b = 0.5},
["light cornflower blue"] = {r = 0.58, g = 0.8, b = 0.92},
["light cyan"] = {r = 0.88, g = 1., b = 1.},
["light french beige"] = {r = 0.78, g = 0.68, b = 0.5},
["light goldenrod yellow"] = {r = 0.98, g = 0.98, b = 0.82},
["light gray"] = {r = 0.83, g = 0.83, b = 0.83},
["light green"] = {r = 0.56, g = 0.93, b = 0.56},
["light orange"] = {r = 1., g = 0.85, b = 0.69},
["light periwinkle"] = {r = 0.77, g = 0.8, b = 0.88},
["light pink"] = {r = 1., g = 0.71, b = 0.76},
["light salmon"] = {r = 1., g = 0.63, b = 0.48},
["light sea green"] = {r = 0.13, g = 0.7, b = 0.67},
["light sky blue"] = {r = 0.53, g = 0.81, b = 0.98},
["light slate gray"] = {r = 0.47, g = 0.53, b = 0.6},
["light steel blue"] = {r = 0.69, g = 0.77, b = 0.87},
["light yellow"] = {r = 1., g = 1., b = 0.88},
["lilac"] = {r = 0.78, g = 0.64, b = 0.78},
["lilac luster"] = {r = 0.68, g = 0.6, b = 0.67},
["lime"] = {r = 0.75, g = 1., b = 0.},
["lime green"] = {r = 0.2, g = 0.8, b = 0.2},
["lincoln green"] = {r = 0.1, g = 0.35, b = 0.02},
["linen"] = {r = 0.98, g = 0.94, b = 0.9},
["lion"] = {r = 0.76, g = 0.6, b = 0.42},
["liseran purple"] = {r = 0.87, g = 0.44, b = 0.63},
["little boy blue"] = {r = 0.42, g = 0.63, b = 0.86},
["liver"] = {r = 0.4, g = 0.3, b = 0.28},
["liver chestnut"] = {r = 0.6, g = 0.45, b = 0.34},
["livid"] = {r = 0.4, g = 0.6, b = 0.8},
["macaroni and cheese"] = {r = 1., g = 0.74, b = 0.53},
["madder lake"] = {r = 0.8, g = 0.2, b = 0.21},
["magenta"] = {r = 1., g = 0., b = 1.},
["magenta haze"] = {r = 0.62, g = 0.27, b = 0.46},
["magic mint"] = {r = 0.67, g = 0.94, b = 0.82},
["magnolia"] = {r = 0.95, g = 0.91, b = 0.84},
["mahogany"] = {r = 0.75, g = 0.25, b = 0.},
["maize"] = {r = 0.98, g = 0.93, b = 0.36},
["majorelle blue"] = {r = 0.38, g = 0.31, b = 0.86},
["malachite"] = {r = 0.04, g = 0.85, b = 0.32},
["manatee"] = {r = 0.59, g = 0.6, b = 0.67},
["mandarin"] = {r = 0.95, g = 0.48, b = 0.28},
["mango"] = {r = 0.99, g = 0.75, b = 0.01},
["mango tango"] = {r = 1., g = 0.51, b = 0.26},
["mantis"] = {r = 0.45, g = 0.76, b = 0.4},
["mardi gras"] = {r = 0.53, g = 0., b = 0.52},
["marigold"] = {r = 0.92, g = 0.64, b = 0.13},
["maroon"] = {r = 0.69, g = 0.19, b = 0.38},
["mauve"] = {r = 0.88, g = 0.69, b = 1.},
["mauve taupe"] = {r = 0.57, g = 0.37, b = 0.43},
["mauvelous"] = {r = 0.94, g = 0.6, b = 0.67},
["maximum blue"] = {r = 0.28, g = 0.67, b = 0.8},
["maximum blue green"] = {r = 0.19, g = 0.75, b = 0.75},
["maximum blue purple"] = {r = 0.67, g = 0.67, b = 0.9},
["maximum green"] = {r = 0.37, g = 0.55, b = 0.19},
["maximum green yellow"] = {r = 0.85, g = 0.9, b = 0.31},
["maximum purple"] = {r = 0.45, g = 0.2, b = 0.5},
["maximum red"] = {r = 0.85, g = 0.13, b = 0.13},
["maximum red purple"] = {r = 0.65, g = 0.23, b = 0.47},
["maximum yellow"] = {r = 0.98, g = 0.98, b = 0.22},
["maximum yellow red"] = {r = 0.95, g = 0.73, b = 0.29},
["may green"] = {r = 0.3, g = 0.57, b = 0.25},
["maya blue"] = {r = 0.45, g = 0.76, b = 0.98},
["medium aquamarine"] = {r = 0.4, g = 0.87, b = 0.67},
["medium blue"] = {r = 0., g = 0., b = 0.8},
["medium candy apple red"] = {r = 0.89, g = 0.02, b = 0.17},
["medium carmine"] = {r = 0.69, g = 0.25, b = 0.21},
["medium champagne"] = {r = 0.95, g = 0.9, b = 0.67},
["medium orchid"] = {r = 0.73, g = 0.33, b = 0.83},
["medium purple"] = {r = 0.58, g = 0.44, b = 0.86},
["medium sea green"] = {r = 0.24, g = 0.7, b = 0.44},
["medium slate blue"] = {r = 0.48, g = 0.41, b = 0.93},
["medium spring green"] = {r = 0., g = 0.98, b = 0.6},
["medium turquoise"] = {r = 0.28, g = 0.82, b = 0.8},
["medium violet-red"] = {r = 0.78, g = 0.08, b = 0.52},
["mellow apricot"] = {r = 0.97, g = 0.72, b = 0.47},
["mellow yellow"] = {r = 0.97, g = 0.87, b = 0.49},
["melon"] = {r = 1., g = 0.73, b = 0.68},
["metallic gold"] = {r = 0.83, g = 0.69, b = 0.22},
["metallic seaweed"] = {r = 0.04, g = 0.49, b = 0.55},
["metallic sunburst"] = {r = 0.61, g = 0.49, b = 0.22},
["mexican pink"] = {r = 0.89, g = 0., b = 0.49},
["middle blue"] = {r = 0.49, g = 0.83, b = 0.9},
["middle blue green"] = {r = 0.55, g = 0.85, b = 0.8},
["middle blue purple"] = {r = 0.55, g = 0.45, b = 0.75},
["middle grey"] = {r = 0.55, g = 0.53, b = 0.5},
["middle green"] = {r = 0.3, g = 0.55, b = 0.34},
["middle green yellow"] = {r = 0.67, g = 0.75, b = 0.38},
["middle purple"] = {r = 0.85, g = 0.51, b = 0.71},
["middle red"] = {r = 0.9, g = 0.56, b = 0.45},
["middle red purple"] = {r = 0.65, g = 0.33, b = 0.33},
["middle yellow"] = {r = 1., g = 0.92, b = 0.},
["middle yellow red"] = {r = 0.93, g = 0.69, b = 0.46},
["midnight"] = {r = 0.44, g = 0.15, b = 0.44},
["midnight blue"] = {r = 0.1, g = 0.1, b = 0.44},
["midnight green"] = {r = 0., g = 0.29, b = 0.33},
["mikado yellow"] = {r = 1., g = 0.77, b = 0.05},
["mimi pink"] = {r = 1., g = 0.85, b = 0.91},
["mindaro"] = {r = 0.89, g = 0.98, b = 0.53},
["ming"] = {r = 0.21, g = 0.45, b = 0.49},
["minion yellow"] = {r = 0.96, g = 0.86, b = 0.31},
["mint"] = {r = 0.24, g = 0.71, b = 0.54},
["mint cream"] = {r = 0.96, g = 1., b = 0.98},
["mint green"] = {r = 0.6, g = 1., b = 0.6},
["misty moss"] = {r = 0.73, g = 0.71, b = 0.47},
["misty rose"] = {r = 1., g = 0.89, b = 0.88},
["mode beige"] = {r = 0.59, g = 0.44, b = 0.09},
["morning blue"] = {r = 0.55, g = 0.64, b = 0.6},
["moss green"] = {r = 0.54, g = 0.6, b = 0.36},
["mountain meadow"] = {r = 0.19, g = 0.73, b = 0.56},
["mountbatten pink"] = {r = 0.6, g = 0.48, b = 0.55},
["msu green"] = {r = 0.09, g = 0.27, b = 0.23},
["mulberry"] = {r = 0.77, g = 0.29, b = 0.55},
["mustard"] = {r = 1., g = 0.86, b = 0.35},
["myrtle green"] = {r = 0.19, g = 0.47, b = 0.45},
["mystic"] = {r = 0.84, g = 0.32, b = 0.51},
["mystic maroon"] = {r = 0.68, g = 0.26, b = 0.47},
["nadeshiko pink"] = {r = 0.96, g = 0.68, b = 0.78},
["naples yellow"] = {r = 0.98, g = 0.85, b = 0.37},
["navajo white"] = {r = 1., g = 0.87, b = 0.68},
["navy blue"] = {r = 0., g = 0., b = 0.5},
["neon blue"] = {r = 0.27, g = 0.4, b = 1.},
["neon carrot"] = {r = 1., g = 0.64, b = 0.26},
["neon green"] = {r = 0.22, g = 1., b = 0.08},
["neon fuchsia"] = {r = 1., g = 0.25, b = 0.39},
["new york pink"] = {r = 0.84, g = 0.51, b = 0.5},
["nickel"] = {r = 0.45, g = 0.45, b = 0.45},
["non-photo blue"] = {r = 0.64, g = 0.87, b = 0.93},
["nyanza"] = {r = 0.91, g = 1., b = 0.86},
["ocean blue"] = {r = 0.31, g = 0.26, b = 0.71},
["ocean green"] = {r = 0.28, g = 0.75, b = 0.57},
["ochre"] = {r = 0.8, g = 0.47, b = 0.13},
["old burgundy"] = {r = 0.26, g = 0.19, b = 0.18},
["old gold"] = {r = 0.81, g = 0.71, b = 0.23},
["old lace"] = {r = 0.99, g = 0.96, b = 0.9},
["old lavender"] = {r = 0.47, g = 0.41, b = 0.47},
["old mauve"] = {r = 0.4, g = 0.19, b = 0.28},
["old rose"] = {r = 0.75, g = 0.5, b = 0.51},
["old silver"] = {r = 0.52, g = 0.52, b = 0.51},
["olive"] = {r = 0.5, g = 0.5, b = 0.},
["olive drab"] = {r = 0.42, g = 0.56, b = 0.14},
["olive green"] = {r = 0.71, g = 0.7, b = 0.36},
["olivine"] = {r = 0.6, g = 0.73, b = 0.45},
["onyx"] = {r = 0.21, g = 0.22, b = 0.22},
["opal"] = {r = 0.66, g = 0.76, b = 0.74},
["opera mauve"] = {r = 0.72, g = 0.52, b = 0.65},
["orange"] = {r = 1., g = 0.5, b = 0.},
["orange peel"] = {r = 1., g = 0.62, b = 0.},
["orange-red"] = {r = 1., g = 0.41, b = 0.12},
["orange soda"] = {r = 0.98, g = 0.36, b = 0.24},
["orange-yellow"] = {r = 0.96, g = 0.74, b = 0.12},
["orchid"] = {r = 0.85, g = 0.44, b = 0.84},
["orchid pink"] = {r = 0.95, g = 0.74, b = 0.8},
["outer space"] = {r = 0.18, g = 0.22, b = 0.23},
["outrageous orange"] = {r = 1., g = 0.43, b = 0.29},
["oxblood"] = {r = 0.29, g = 0., b = 0.},
["oxford blue"] = {r = 0., g = 0.13, b = 0.28},
["ou crimson red"] = {r = 0.52, g = 0.09, b = 0.09},
["pacific blue"] = {r = 0.11, g = 0.66, b = 0.79},
["pakistan green"] = {r = 0., g = 0.4, b = 0.},
["palatinate purple"] = {r = 0.41, g = 0.16, b = 0.38},
["pale aqua"] = {r = 0.74, g = 0.83, b = 0.9},
["pale cerulean"] = {r = 0.61, g = 0.77, b = 0.89},
["pale dogwood"] = {r = 0.93, g = 0.48, b = 0.61},
["pale pink"] = {r = 0.98, g = 0.85, b = 0.87},
["pale purple"] = {r = 0.98, g = 0.9, b = 0.98},
["pale silver"] = {r = 0.79, g = 0.75, b = 0.73},
["pale spring bud"] = {r = 0.93, g = 0.92, b = 0.74},
["pansy purple"] = {r = 0.47, g = 0.09, b = 0.29},
["paolo veronese green"] = {r = 0., g = 0.61, b = 0.49},
["papaya whip"] = {r = 1., g = 0.94, b = 0.84},
["paradise pink"] = {r = 0.9, g = 0.24, b = 0.38},
["parchment"] = {r = 0.95, g = 0.91, b = 0.82},
["paris green"] = {r = 0.31, g = 0.78, b = 0.47},
["pastel pink"] = {r = 0.87, g = 0.65, b = 0.64},
["patriarch"] = {r = 0.5, g = 0., b = 0.5},
["payne's grey"] = {r = 0.33, g = 0.41, b = 0.47},
["peach"] = {r = 1., g = 0.9, b = 0.71},
["peach puff"] = {r = 1., g = 0.85, b = 0.73},
["pear"] = {r = 0.82, g = 0.89, b = 0.19},
["pearly purple"] = {r = 0.72, g = 0.41, b = 0.64},
["periwinkle"] = {r = 0.8, g = 0.8, b = 1.},
["permanent geranium lake"] = {r = 0.88, g = 0.17, b = 0.17},
["persian blue"] = {r = 0.11, g = 0.22, b = 0.73},
["persian green"] = {r = 0., g = 0.65, b = 0.58},
["persian indigo"] = {r = 0.2, g = 0.07, b = 0.48},
["persian orange"] = {r = 0.85, g = 0.56, b = 0.35},
["persian pink"] = {r = 0.97, g = 0.5, b = 0.75},
["persian plum"] = {r = 0.44, g = 0.11, b = 0.11},
["persian red"] = {r = 0.8, g = 0.2, b = 0.2},
["persian rose"] = {r = 1., g = 0.16, b = 0.64},
["persimmon"] = {r = 0.93, g = 0.35, b = 0.},
["pewter blue"] = {r = 0.55, g = 0.66, b = 0.72},
["phlox"] = {r = 0.87, g = 0., b = 1.},
["phthalo blue"] = {r = 0., g = 0.06, b = 0.54},
["phthalo green"] = {r = 0.07, g = 0.21, b = 0.14},
["picotee blue"] = {r = 0.18, g = 0.15, b = 0.53},
["pictorial carmine"] = {r = 0.76, g = 0.04, b = 0.31},
["piggy pink"] = {r = 0.99, g = 0.87, b = 0.9},
["pine green"] = {r = 0., g = 0.47, b = 0.44},
["pine tree"] = {r = 0.16, g = 0.18, b = 0.14},
["pink"] = {r = 1., g = 0.75, b = 0.8},
["pink flamingo"] = {r = 0.99, g = 0.45, b = 0.99},
["pink lace"] = {r = 1., g = 0.87, b = 0.96},
["pink lavender"] = {r = 0.85, g = 0.7, b = 0.82},
["pink sherbet"] = {r = 0.97, g = 0.56, b = 0.65},
["pistachio"] = {r = 0.58, g = 0.77, b = 0.45},
["platinum"] = {r = 0.9, g = 0.89, b = 0.89},
["plum"] = {r = 0.56, g = 0.27, b = 0.52},
["plump purple"] = {r = 0.35, g = 0.27, b = 0.7},
["polished pine"] = {r = 0.36, g = 0.64, b = 0.58},
["pomp and power"] = {r = 0.53, g = 0.38, b = 0.56},
["popstar"] = {r = 0.75, g = 0.31, b = 0.38},
["portland orange"] = {r = 1., g = 0.35, b = 0.21},
["powder blue"] = {r = 0.69, g = 0.88, b = 0.9},
["princeton orange"] = {r = 0.96, g = 0.5, b = 0.15},
["process yellow"] = {r = 1., g = 0.94, b = 0.},
["prune"] = {r = 0.44, g = 0.11, b = 0.11},
["prussian blue"] = {r = 0., g = 0.19, b = 0.33},
["psychedelic purple"] = {r = 0.87, g = 0., b = 1.},
["puce"] = {r = 0.8, g = 0.53, b = 0.6},
["pullman brown"] = {r = 0.39, g = 0.25, b = 0.09},
["pumpkin"] = {r = 1., g = 0.46, b = 0.09},
["purple"] = {r = 0.38, g = 0., b = 0.5},
["purple mountain majesty"] = {r = 0.59, g = 0.47, b = 0.71},
["purple navy"] = {r = 0.31, g = 0.32, b = 0.5},
["purple pizzazz"] = {r = 1., g = 0.31, b = 0.85},
["purple plum"] = {r = 0.61, g = 0.32, b = 0.71},
["purpureus"] = {r = 0.6, g = 0.31, b = 0.68},
["queen blue"] = {r = 0.26, g = 0.42, b = 0.58},
["queen pink"] = {r = 0.91, g = 0.8, b = 0.84},
["quick silver"] = {r = 0.65, g = 0.65, b = 0.65},
["quinacridone magenta"] = {r = 0.56, g = 0.23, b = 0.35},
["radical red"] = {r = 1., g = 0.21, b = 0.37},
["raisin black"] = {r = 0.14, g = 0.13, b = 0.14},
["rajah"] = {r = 0.98, g = 0.67, b = 0.38},
["raspberry"] = {r = 0.89, g = 0.04, b = 0.36},
["raspberry glace"] = {r = 0.57, g = 0.37, b = 0.43},
["raspberry rose"] = {r = 0.7, g = 0.27, b = 0.42},
["raw sienna"] = {r = 0.84, g = 0.54, b = 0.35},
["raw umber"] = {r = 0.51, g = 0.4, b = 0.27},
["razzle dazzle rose"] = {r = 1., g = 0.2, b = 0.8},
["razzmatazz"] = {r = 0.89, g = 0.15, b = 0.42},
["razzmic berry"] = {r = 0.55, g = 0.31, b = 0.52},
["rebecca purple"] = {r = 0.4, g = 0.2, b = 0.6},
["red"] = {r = 1., g = 0., b = 0.},
["red-orange"] = {r = 1., g = 0.33, b = 0.29},
["red-purple"] = {r = 0.89, g = 0., b = 0.47},
["red salsa"] = {r = 0.99, g = 0.23, b = 0.29},
["red-violet"] = {r = 0.78, g = 0.08, b = 0.52},
["redwood"] = {r = 0.64, g = 0.35, b = 0.32},
["resolution blue"] = {r = 0., g = 0.14, b = 0.53},
["rhythm"] = {r = 0.47, g = 0.46, b = 0.59},
["rich black"] = {r = 0., g = 0.04, b = 0.07},
["rifle green"] = {r = 0.27, g = 0.3, b = 0.22},
["robin egg blue"] = {r = 0., g = 0.8, b = 0.8},
["rocket metallic"] = {r = 0.54, g = 0.5, b = 0.5},
["rojo spanish red"] = {r = 0.66, g = 0.07, b = 0.},
["roman silver"] = {r = 0.51, g = 0.54, b = 0.59},
["rose"] = {r = 1., g = 0., b = 0.5},
["rose bonbon"] = {r = 0.98, g = 0.26, b = 0.62},
["rose dust"] = {r = 0.62, g = 0.37, b = 0.44},
["rose ebony"] = {r = 0.4, g = 0.28, b = 0.27},
["rose madder"] = {r = 0.89, g = 0.15, b = 0.21},
["rose pink"] = {r = 1., g = 0.4, b = 0.8},
["rose pompadour"] = {r = 0.93, g = 0.48, b = 0.61},
["rose quartz"] = {r = 0.67, g = 0.6, b = 0.66},
["rose red"] = {r = 0.76, g = 0.12, b = 0.34},
["rose taupe"] = {r = 0.56, g = 0.36, b = 0.36},
["rose vale"] = {r = 0.67, g = 0.31, b = 0.32},
["rosewood"] = {r = 0.4, g = 0., b = 0.04},
["rosso corsa"] = {r = 0.83, g = 0., b = 0.},
["rosy brown"] = {r = 0.74, g = 0.56, b = 0.56},
["royal blue"] = {r = 0., g = 0.14, b = 0.4},
["royal purple"] = {r = 0.47, g = 0.32, b = 0.66},
["royal yellow"] = {r = 0.98, g = 0.85, b = 0.37},
["ruber"] = {r = 0.81, g = 0.27, b = 0.46},
["rubine red"] = {r = 0.82, g = 0., b = 0.34},
["ruby"] = {r = 0.88, g = 0.07, b = 0.37},
["ruby red"] = {r = 0.61, g = 0.07, b = 0.12},
["rufous"] = {r = 0.66, g = 0.11, b = 0.03},
["russet"] = {r = 0.5, g = 0.27, b = 0.11},
["russian green"] = {r = 0.4, g = 0.57, b = 0.4},
["russian violet"] = {r = 0.2, g = 0.09, b = 0.3},
["rust"] = {r = 0.72, g = 0.25, b = 0.05},
["rusty red"] = {r = 0.85, g = 0.17, b = 0.26},
["sacramento state green"] = {r = 0.02, g = 0.22, b = 0.15},
["saddle brown"] = {r = 0.55, g = 0.27, b = 0.07},
["safety orange"] = {r = 1., g = 0.47, b = 0.},
["safety yellow"] = {r = 0.93, g = 0.82, b = 0.01},
["saffron"] = {r = 0.96, g = 0.77, b = 0.19},
["sage"] = {r = 0.74, g = 0.72, b = 0.54},
["st. patrick's blue"] = {r = 0.14, g = 0.16, b = 0.48},
["salmon"] = {r = 0.98, g = 0.5, b = 0.45},
["salmon pink"] = {r = 1., g = 0.57, b = 0.64},
["sand"] = {r = 0.76, g = 0.7, b = 0.5},
["sand dune"] = {r = 0.59, g = 0.44, b = 0.09},
["sandy brown"] = {r = 0.96, g = 0.64, b = 0.38},
["sap green"] = {r = 0.31, g = 0.49, b = 0.16},
["sapphire"] = {r = 0.06, g = 0.32, b = 0.73},
["sapphire blue"] = {r = 0., g = 0.4, b = 0.65},
["satin sheen gold"] = {r = 0.8, g = 0.63, b = 0.21},
["scarlet"] = {r = 1., g = 0.14, b = 0.},
["schauss pink"] = {r = 1., g = 0.57, b = 0.69},
["school bus yellow"] = {r = 1., g = 0.85, b = 0.},
["screamin' green"] = {r = 0.4, g = 1., b = 0.4},
["sea green"] = {r = 0.18, g = 0.55, b = 0.34},
["seal brown"] = {r = 0.2, g = 0.08, b = 0.08},
["seashell"] = {r = 1., g = 0.96, b = 0.93},
["selective yellow"] = {r = 1., g = 0.73, b = 0.},
["sepia"] = {r = 0.44, g = 0.26, b = 0.08},
["shadow"] = {r = 0.54, g = 0.47, b = 0.36},
["shadow blue"] = {r = 0.47, g = 0.55, b = 0.65},
["shamrock green"] = {r = 0., g = 0.62, b = 0.38},
["sheen green"] = {r = 0.56, g = 0.83, b = 0.},
["shimmering blush"] = {r = 0.85, g = 0.53, b = 0.58},
["shiny shamrock"] = {r = 0.37, g = 0.65, b = 0.47},
["shocking pink"] = {r = 0.99, g = 0.06, b = 0.75},
["sienna"] = {r = 0.53, g = 0.18, b = 0.09},
["silver"] = {r = 0.75, g = 0.75, b = 0.75},
["silver chalice"] = {r = 0.67, g = 0.67, b = 0.67},
["silver pink"] = {r = 0.77, g = 0.68, b = 0.68},
["silver sand"] = {r = 0.75, g = 0.76, b = 0.76},
["sinopia"] = {r = 0.8, g = 0.25, b = 0.04},
["sizzling red"] = {r = 1., g = 0.22, b = 0.33},
["sizzling sunrise"] = {r = 1., g = 0.86, b = 0.},
["skobeloff"] = {r = 0., g = 0.45, b = 0.45},
["sky blue"] = {r = 0.53, g = 0.81, b = 0.92},
["sky magenta"] = {r = 0.81, g = 0.44, b = 0.69},
["slate blue"] = {r = 0.42, g = 0.35, b = 0.8},
["slate gray"] = {r = 0.44, g = 0.5, b = 0.56},
["slimy green"] = {r = 0.16, g = 0.59, b = 0.09},
["smitten"] = {r = 0.78, g = 0.25, b = 0.53},
["smoky black"] = {r = 0.06, g = 0.05, b = 0.03},
["snow"] = {r = 1., g = 0.98, b = 0.98},
["solid pink"] = {r = 0.54, g = 0.22, b = 0.26},
["sonic silver"] = {r = 0.46, g = 0.46, b = 0.46},
["space cadet"] = {r = 0.11, g = 0.16, b = 0.32},
["spanish bistre"] = {r = 0.5, g = 0.46, b = 0.2},
["spanish blue"] = {r = 0., g = 0.44, b = 0.72},
["spanish carmine"] = {r = 0.82, g = 0., b = 0.28},
["spanish gray"] = {r = 0.6, g = 0.6, b = 0.6},
["spanish green"] = {r = 0., g = 0.57, b = 0.31},
["spanish orange"] = {r = 0.91, g = 0.38, b = 0.},
["spanish pink"] = {r = 0.97, g = 0.75, b = 0.75},
["spanish red"] = {r = 0.9, g = 0., b = 0.15},
["spanish sky blue"] = {r = 0., g = 1., b = 1.},
["spanish violet"] = {r = 0.3, g = 0.16, b = 0.51},
["spanish viridian"] = {r = 0., g = 0.5, b = 0.36},
["spring bud"] = {r = 0.65, g = 0.99, b = 0.},
["spring frost"] = {r = 0.53, g = 1., b = 0.16},
["spring green"] = {r = 0., g = 1., b = 0.5},
["star command blue"] = {r = 0., g = 0.48, b = 0.72},
["steel blue"] = {r = 0.27, g = 0.51, b = 0.71},
["steel pink"] = {r = 0.8, g = 0.2, b = 0.8},
["steel teal"] = {r = 0.37, g = 0.54, b = 0.55},
["stil de grain yellow"] = {r = 0.98, g = 0.85, b = 0.37},
["straw"] = {r = 0.89, g = 0.85, b = 0.44},
["strawberry"] = {r = 0.98, g = 0.31, b = 0.33},
["strawberry blonde"] = {r = 1., g = 0.58, b = 0.38},
["sugar plum"] = {r = 0.57, g = 0.31, b = 0.46},
["sunglow"] = {r = 1., g = 0.8, b = 0.2},
["sunray"] = {r = 0.89, g = 0.67, b = 0.34},
["sunset"] = {r = 0.98, g = 0.84, b = 0.65},
["super pink"] = {r = 0.81, g = 0.42, b = 0.66},
["sweet brown"] = {r = 0.66, g = 0.22, b = 0.19},
["syracuse orange"] = {r = 0.83, g = 0.27, b = 0.},
["tan"] = {r = 0.82, g = 0.71, b = 0.55},
["tangerine"] = {r = 0.95, g = 0.52, b = 0.},
["tango pink"] = {r = 0.89, g = 0.44, b = 0.48},
["tart orange"] = {r = 0.98, g = 0.3, b = 0.27},
["taupe"] = {r = 0.28, g = 0.24, b = 0.2},
["taupe gray"] = {r = 0.55, g = 0.52, b = 0.54},
["tea green"] = {r = 0.82, g = 0.94, b = 0.75},
["tea rose"] = {r = 0.97, g = 0.51, b = 0.47},
["teal"] = {r = 0., g = 0.5, b = 0.5},
["teal blue"] = {r = 0.21, g = 0.46, b = 0.53},
["telemagenta"] = {r = 0.81, g = 0.2, b = 0.46},
["tawny"] = {r = 0.8, g = 0.34, b = 0.},
["terra cotta"] = {r = 0.89, g = 0.45, b = 0.36},
["thistle"] = {r = 0.85, g = 0.75, b = 0.85},
["thulian pink"] = {r = 0.87, g = 0.44, b = 0.63},
["tickle me pink"] = {r = 0.99, g = 0.54, b = 0.67},
["tiffany blue"] = {r = 0.04, g = 0.73, b = 0.71},
["timberwolf"] = {r = 0.86, g = 0.84, b = 0.82},
["titanium yellow"] = {r = 0.93, g = 0.9, b = 0.},
["tomato"] = {r = 1., g = 0.39, b = 0.28},
["tropical rainforest"] = {r = 0., g = 0.46, b = 0.37},
["true blue"] = {r = 0., g = 0.45, b = 0.81},
["trypan blue"] = {r = 0.11, g = 0.02, b = 0.7},
["tufts blue"] = {r = 0.24, g = 0.56, b = 0.87},
["tumbleweed"] = {r = 0.87, g = 0.67, b = 0.53},
["turquoise"] = {r = 0.25, g = 0.88, b = 0.82},
["turquoise blue"] = {r = 0., g = 1., b = 0.94},
["turquoise green"] = {r = 0.63, g = 0.84, b = 0.71},
["turtle green"] = {r = 0.54, g = 0.6, b = 0.36},
["tuscan"] = {r = 0.98, g = 0.84, b = 0.65},
["tuscan brown"] = {r = 0.44, g = 0.31, b = 0.22},
["tuscan red"] = {r = 0.49, g = 0.28, b = 0.28},
["tuscan tan"] = {r = 0.65, g = 0.48, b = 0.36},
["tuscany"] = {r = 0.75, g = 0.6, b = 0.6},
["twilight lavender"] = {r = 0.54, g = 0.29, b = 0.42},
["tyrian purple"] = {r = 0.4, g = 0.01, b = 0.24},
["ua blue"] = {r = 0., g = 0.2, b = 0.67},
["ua red"] = {r = 0.85, g = 0., b = 0.3},
["ultramarine"] = {r = 0.07, g = 0.04, b = 0.56},
["ultramarine blue"] = {r = 0.25, g = 0.4, b = 0.96},
["ultra pink"] = {r = 1., g = 0.44, b = 1.},
["ultra red"] = {r = 0.99, g = 0.42, b = 0.52},
["umber"] = {r = 0.39, g = 0.32, b = 0.28},
["unbleached silk"] = {r = 1., g = 0.87, b = 0.79},
["united nations blue"] = {r = 0.36, g = 0.57, b = 0.9},
["university of pennsylvania red"] = {r = 0.65, g = 0., b = 0.13},
["unmellow yellow"] = {r = 1., g = 1., b = 0.4},
["up forest green"] = {r = 0., g = 0.27, b = 0.13},
["up maroon"] = {r = 0.48, g = 0.07, b = 0.07},
["upsdell red"] = {r = 0.68, g = 0.13, b = 0.16},
["uranian blue"] = {r = 0.69, g = 0.86, b = 0.96},
["usafa blue"] = {r = 0., g = 0.31, b = 0.6},
["van dyke brown"] = {r = 0.4, g = 0.26, b = 0.16},
["vanilla"] = {r = 0.95, g = 0.9, b = 0.67},
["vanilla ice"] = {r = 0.95, g = 0.56, b = 0.66},
["vegas gold"] = {r = 0.77, g = 0.7, b = 0.35},
["venetian red"] = {r = 0.78, g = 0.03, b = 0.08},
["verdigris"] = {r = 0.26, g = 0.7, b = 0.68},
["vermilion"] = {r = 0.89, g = 0.26, b = 0.2},
["veronica"] = {r = 0.63, g = 0.13, b = 0.94},
["violet"] = {r = 0.56, g = 0., b = 1.},
["violet-blue"] = {r = 0.2, g = 0.29, b = 0.7},
["violet-red"] = {r = 0.97, g = 0.33, b = 0.58},
["viridian"] = {r = 0.25, g = 0.51, b = 0.43},
["viridian green"] = {r = 0., g = 0.59, b = 0.6},
["vivid burgundy"] = {r = 0.62, g = 0.11, b = 0.21},
["vivid sky blue"] = {r = 0., g = 0.8, b = 1.},
["vivid tangerine"] = {r = 1., g = 0.63, b = 0.54},
["vivid violet"] = {r = 0.62, g = 0., b = 1.},
["volt"] = {r = 0.8, g = 1., b = 0.},
["warm black"] = {r = 0., g = 0.26, b = 0.26},
["wheat"] = {r = 0.96, g = 0.87, b = 0.7},
["white"] = {r = 1., g = 1., b = 1.},
["wild blue yonder"] = {r = 0.64, g = 0.68, b = 0.82},
["wild orchid"] = {r = 0.83, g = 0.44, b = 0.64},
["wild strawberry"] = {r = 1., g = 0.26, b = 0.64},
["wild watermelon"] = {r = 0.99, g = 0.42, b = 0.52},
["windsor tan"] = {r = 0.65, g = 0.33, b = 0.01},
["wine"] = {r = 0.45, g = 0.18, b = 0.22},
["wine dregs"] = {r = 0.4, g = 0.19, b = 0.28},
["winter sky"] = {r = 1., g = 0., b = 0.49},
["wintergreen dream"] = {r = 0.34, g = 0.53, b = 0.49},
["wisteria"] = {r = 0.79, g = 0.63, b = 0.86},
["wood brown"] = {r = 0.76, g = 0.6, b = 0.42},
["xanadu"] = {r = 0.45, g = 0.53, b = 0.47},
["xanthic"] = {r = 0.93, g = 0.93, b = 0.04},
["xanthous"] = {r = 0.95, g = 0.71, b = 0.18},
["yale blue"] = {r = 0., g = 0.21, b = 0.42},
["yellow"] = {r = 1., g = 1., b = 0.},
["yellow-green"] = {r = 0.6, g = 0.8, b = 0.2},
["yellow orange"] = {r = 1., g = 0.68, b = 0.26},
["yellow sunshine"] = {r = 1., g = 0.97, b = 0.},
["yinmn blue"] = {r = 0.18, g = 0.31, b = 0.56},
["zaffre"] = {r = 0., g = 0.08, b = 0.66},
["zomp"] = {r = 0.22, g = 0.65, b = 0.56},
}

View File

@@ -0,0 +1,531 @@
local Public = {}
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Structures = require 'maps.pirates.structures.structures'
local Boats = require 'maps.pirates.structures.boats.boats'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Crowsnest = require 'maps.pirates.surfaces.crowsnest'
local Server = require 'utils.server'
local Dock = require 'maps.pirates.surfaces.dock'
local Islands = require 'maps.pirates.surfaces.islands.islands'
local Sea = require 'maps.pirates.surfaces.sea.sea'
local Crew = require 'maps.pirates.crew'
local Roles = require 'maps.pirates.roles.roles'
local Parrot = require 'maps.pirates.parrot'
local Quest = require 'maps.pirates.quest'
local Shop = require 'maps.pirates.shop.shop'
local Overworld = require 'maps.pirates.overworld'
local Hold = require 'maps.pirates.surfaces.hold'
local Cabin = require 'maps.pirates.surfaces.cabin'
local Upgrades = require 'maps.pirates.boat_upgrades'
local Task = require 'utils.task'
local Token = require 'utils.token'
local ShopMini = require 'maps.pirates.shop.minimarket'
function Public.set_off_from_starting_dock()
local memory = Memory.get_crew_memory()
if memory.game_lost then return end
memory.crewstatus = Crew.enum.LEAVING_INITIAL_DOCK
memory.boat.state = Boats.enum_state.LEAVING_DOCK
Boats.place_boat(memory.boat, CoreData.moving_boat_floor, false, false)
Common.current_destination().type = Surfaces.enum.LOBBY
memory.mapbeingloadeddestination_index = 1 -- whatever the index of the first island is
memory.loadingticks = 0
local surface = game.surfaces[CoreData.lobby_surface_name]
local p = Utils.psum{memory.boat.position, Boats.get_scope(memory.boat).Data.crewname_rendering_position}
memory.boat.rendering_crewname_text = rendering.draw_text{
text = memory.name,
-- render_layer = '125', --does nothing
surface = surface,
target = p,
color = CoreData.colors.renderingtext_yellow,
scale = 8,
font = 'default-game',
alignment = 'left'
}
end
function Public.go_from_starting_dock_to_first_destination()
local memory = Memory.get_crew_memory()
local boat = memory.boat
local crew_members = Crew.choose_crew_members()
local crew_members_count = #memory.crewplayerindices
if crew_members_count > 0 then
memory.crewstatus = Crew.enum.ADVENTURING
local message = '[' .. memory.name .. '] Crew members: '
local b = false
for _, index in pairs(memory.crewplayerindices) do
if game.players[index] and game.players[index].name then
if b == true then
message = message .. ', '
else b = true end
message = message .. game.players[index].name
end
end
message = message .. '.'
Server.to_discord_embed_raw(CoreData.comfy_emojis.pogkot .. message)
Roles.assign_captain_based_on_priorities()
for _, player in pairs(crew_members) do
Crew.player_abandon_endorsements(player)
for item, amount in pairs(Balance.starting_items_player) do
player.insert({name = item, count = amount})
end
end
boat.stored_resources = {}
Shop.initialise_main_shop()
Hold.create_hold_surface(1)
Cabin.create_cabin_surface()
local items = Balance.starting_items_crew_upstairs()
Boats.place_random_obstacle_boxes(boat, 6, items, 0)
-- go:
Public.progress_to_destination(1) --index of first destination
boat.EEI_stage = 1
Boats.update_EEIs(boat)
if Common.difficulty() == 1 then
Boats.upgrade_chests(boat, 'iron-chest')
Hold.upgrade_chests(1, 'iron-chest')
Crowsnest.upgrade_chests('iron-chest')
elseif Common.difficulty() > 1 then
Boats.upgrade_chests(boat, 'steel-chest')
Hold.upgrade_chests(1, 'steel-chest')
Crowsnest.upgrade_chests('steel-chest')
end
memory.age = 0
memory.real_age = 0
else
Boats.destroy_boat(boat)
Crew.disband_crew()
end
end
local place_dock_jetty_and_boats = Token.register(
function(data)
local memory = Memory.get_crew_memory()
if memory.game_lost then return end
Surfaces.Dock.place_dock_jetty_and_boats()
local destination = Common.current_destination()
ShopMini.create_minimarket(game.surfaces[destination.surface_name], Surfaces.Dock.Data.market_position)
end
)
function Public.progress_to_destination(destination_index)
local memory = Memory.get_crew_memory()
local global_memory = Memory.get_global_memory()
if memory.game_lost then return end
local boat = memory.boat
local oldsurface = game.surfaces[boat.surface_name]
local old_type = Surfaces.SurfacesCommon.decode_surface_name(oldsurface.name).type
local destination_data = memory.destinations[destination_index]
local static_params = destination_data.static_params
local type = destination_data.type
local subtype = destination_data.subtype
local newsurface_name = Surfaces.SurfacesCommon.encode_surface_name(memory.id, destination_index, type, subtype)
local newsurface = game.surfaces[newsurface_name]
local initial_boatspeed, starting_boatposition
if type == Surfaces.enum.ISLAND then --moved from overworld generation, so that it updates properly
local covered1_requirement = Balance.covered1_entry_price()
destination_data.dynamic_data.covered1_requirement = covered1_requirement
end
if type == Surfaces.enum.DOCK then
local BoatData = Boats.get_scope(boat).Data
starting_boatposition = Utils.snap_coordinates_for_rails({x = Dock.Data.playerboat_starting_xcoord, y = Dock.Data.top_boat_bottom - BoatData.height/2})
-- starting_boatposition = {x = -destination_data.static_params.width/2 + BoatData.width + 10, y = Dock.Data.top_boat_bottom - BoatData.height/2}
Common.current_destination().dynamic_data.time_remaining = 180
-- memory.mainshop_availability_bools.sell_iron = true
memory.mainshop_availability_bools.buy_iron = true
memory.mainshop_availability_bools.buy_copper = true
-- memory.mainshop_availability_bools.buy_fast_loader = true
-- memory.mainshop_availability_bools.sell_copper = true
local boat_for_sale_type = Common.current_destination().static_params.boat_for_sale_type
if boat_for_sale_type then
if boat_for_sale_type == Boats.enum.CUTTER then
memory.mainshop_availability_bools.new_boat_cutter = true
elseif boat_for_sale_type == Boats.enum.CUTTER_WITH_HOLD then
memory.mainshop_availability_bools.new_boat_cutter_with_hold = true
elseif boat_for_sale_type == Boats.enum.SLOOP_WITH_HOLD then
memory.mainshop_availability_bools.new_boat_sloop_with_hold = true
end
end
local upgrade_for_sale = Common.current_destination().static_params.upgrade_for_sale
if upgrade_for_sale then
for _, u in pairs(Upgrades.List) do
if upgrade_for_sale == u then
memory.mainshop_availability_bools[u] = true
end
end
end
-- Delay.add(Delay.enum.PLACE_DOCK_JETTY_AND_BOATS)
Task.set_timeout_in_ticks(2, place_dock_jetty_and_boats, {})
else
starting_boatposition = {x = static_params.boat_starting_xposition, y = static_params.boat_starting_yposition or 0}
end
-- if oldsurface.name == CoreData.lobby_surface_name then
-- initial_boatspeed = 3
-- else
-- initial_boatspeed = 1.5
-- end
initial_boatspeed = 1.4
boat.speed = initial_boatspeed
boat.state = destination_data.init_boat_state
boat.dockedposition = nil
memory.enemyboats = {}
local old_water = 'deepwater'
if old_type == Surfaces.enum.LOBBY or old_type == Surfaces.enum.DOCK then old_water = 'water' end
Boats.teleport_boat(boat, newsurface_name, starting_boatposition, CoreData.moving_boat_floor, old_water)
if old_type == Surfaces.enum.LOBBY then
Crowsnest.draw_extra_bits()
end
Crowsnest.paint_around_destination(destination_index, CoreData.overworld_presence_tile)
if memory.loadingticks then memory.loadingticks = -120 end
if old_type == Surfaces.enum.SEA then
game.delete_surface(oldsurface)
end
memory.destinationsvisited_indices[#memory.destinationsvisited_indices + 1] = destination_index
memory.currentdestination_index = destination_index
local destination = Common.current_destination()
destination.dynamic_data.timer = 0
destination.dynamic_data.timeratlandingtime = nil
memory.extra_time_at_sea = 0
if old_type == Surfaces.enum.SEA or old_type == Surfaces.enum.CHANNEL or old_type == Surfaces.enum.DOCK then
-- move over anyone who was left behind, such as dead and spectating players
for _, player in pairs(game.connected_players) do
if type == Surfaces.enum.ISLAND and player.controller_type == defines.controllers.spectator then
if player.surface == oldsurface then --avoid moving players in hold etc
-- put them at a nice viewing position:
player.teleport({x = memory.spawnpoint.x + 120, y = memory.spawnpoint.y}, newsurface)
end
elseif player.surface == oldsurface then
player.teleport(memory.spawnpoint, newsurface)
end
end
end
Surfaces.destination_on_arrival(Common.current_destination())
end
function Public.check_for_end_of_boat_movement(boat)
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local collided = Boats.collision_infront(boat)
local approaching_island = boat.state == Boats.enum_state.APPROACHING and destination.type == Surfaces.enum.ISLAND
local retreating_island = boat.state == Boats.enum_state.RETREATING and destination.type == Surfaces.enum.ISLAND
local approaching_dock = destination.type == Surfaces.enum.DOCK and boat.state == Boats.enum_state.APPROACHING
local leaving_dock = destination.type == Surfaces.enum.DOCK and boat.state == Boats.enum_state.LEAVING_DOCK
--=== Collision
if approaching_island and collided then
boat.state = Boats.enum_state.LANDED
boat.speed = 0
boat.dockedposition = boat.position
game.surfaces[boat.surface_name].play_sound{path = "utility/axe_fighting"}
game.surfaces[boat.surface_name].play_sound{path = "utility/axe_fighting"}
end
--=== Enemy
if boat.force_name == memory.enemy_force_name then
if approaching_island then
if collided then
boat.landing_time = destination.dynamic_data.timer
Boats.place_landingtrack(boat, CoreData.enemy_landing_tile)
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
elseif boat.spawner and boat.spawner.valid and boat.spawner.destructible then
local boat2 = Utils.deepcopy(boat)
boat2.position = {x = boat.position.x + 5, y = boat.position.y}
if Boats.collision_infront(boat2) then
boat.spawner.destructible = false
end
end
end
--=== Friendly
elseif boat.force_name == memory.force_name then
if approaching_island and collided then
Surfaces.destination_on_crewboat_hits_shore(destination)
return true
elseif retreating_island and boat.position.x < ((boat.dockedposition.x or 999) - Boats.get_scope(boat).Data.width - 2 * Boats.get_scope(boat).Data.rightmost_gate_position - 8) then
Public.go_from_currentdestination_to_sea()
return true
elseif approaching_dock and boat.position.x + Boats.get_scope(boat).Data.rightmost_gate_position >= Dock.Data.rightmostgate_stopping_xposition then
boat.state = Boats.enum_state.DOCKED
boat.speed = 0
boat.dockedposition = boat.position
destination.dynamic_data.timeratlandingtime = destination.dynamic_data.timer
Boats.place_boat(boat, CoreData.static_boat_floor, false, false)
return true
elseif leaving_dock and boat.position.x >= game.surfaces[boat.surface_name].map_gen_settings.width/2 - 2 then
memory.mainshop_availability_bools.new_boat_cutter = false
memory.mainshop_availability_bools.new_boat_cutter_with_hold = false
memory.mainshop_availability_bools.new_boat_sloop_with_hold = false
-- memory.mainshop_availability_bools.sell_iron = false
memory.mainshop_availability_bools.buy_iron = false
memory.mainshop_availability_bools.buy_copper = false
-- memory.mainshop_availability_bools.buy_fast_loader = false
-- memory.mainshop_availability_bools.sell_copper = false
memory.mainshop_availability_bools.extra_hold = false
memory.mainshop_availability_bools.upgrade_power = false
memory.mainshop_availability_bools.unlock_merchants = false
memory.mainshop_availability_bools.rockets_for_sale = false
Public.go_from_currentdestination_to_sea()
return true
--=== Fallthrough right-hand side
elseif destination.type == Surfaces.enum.ISLAND and boat.position.x >= game.surfaces[boat.surface_name].map_gen_settings.width/2 - 10 then
Public.go_from_currentdestination_to_sea()
return true
end
end
return false
end
function Public.try_retreat_from_island() -- Assumes the cost can be paid
local memory = Memory.get_crew_memory()
if memory.game_lost then return end
local destination = Common.current_destination()
local captain_index = memory.playerindex_captain
local captain = game.players[captain_index]
if captain and Common.validate_player(captain) and destination.dynamic_data.timeratlandingtime and destination.dynamic_data.timer < destination.dynamic_data.timeratlandingtime + 30 then
Common.notify_player(captain, 'Can\'t depart in the first 30 seconds.')
else
local cost = destination.static_params.cost_to_leave
-- if cost and (not destination.dynamic_data.rocketlaunched) then
-- local gold = memory.gold
-- local captain_index = memory.playerindex_captain
-- if not (gold and captain_index) then return end
-- local captain = game.players[captain_index]
-- if not Common.validate_player_and_character(captain) then return end
-- local captain_inv = captain.get_inventory(defines.inventory.character_main)
-- if not captain_inv then return end
-- local can_buy = true
-- if cost.name == 'gold' then
-- can_buy = gold >= cost.count
-- else
-- can_buy = captain_inv.get_item_count(cost.name) >= cost.count
-- end
-- if can_buy then
-- if cost.name == 'gold' then
-- memory.gold = memory.gold - cost.count
-- else
-- captain_inv.remove{name=cost.name, count=cost.count}
-- end
-- Public.retreat_from_island()
-- else
-- Common.notify_player(captain, 'Can\'t afford it.')
-- end
-- else
-- Public.retreat_from_island()
-- end
if cost then
Common.spend_stored_resources(cost)
end
Public.retreat_from_island()
end
end
function Public.retreat_from_island()
local memory = Memory.get_crew_memory()
local boat = memory.boat
if boat.state and boat.state == Boats.enum_state.RETREATING then return end
boat.state = Boats.enum_state.RETREATING
boat.speed = 1
Boats.place_boat(boat, CoreData.moving_boat_floor, false, false)
local force = game.forces[memory.force_name]
if not (force and force.valid) then return end
Common.notify_force_light(force,'[font=heading-1]Boat undocked.[/font]')
if memory.overworldx == 40*9 then Parrot.parrot_kraken_warning() end
end
function Public.undock_from_dock()
local memory = Memory.get_crew_memory()
local boat = memory.boat
local destination = Common.current_destination()
boat.state = Boats.enum_state.LEAVING_DOCK
destination.dynamic_data.time_remaining = -1
Boats.place_boat(boat, CoreData.moving_boat_floor, false, false)
memory.mainshop_availability_bools.new_boat_cutter = false
memory.mainshop_availability_bools.new_boat_cutter_with_hold = false
memory.mainshop_availability_bools.new_boat_sloop_with_hold = false
local force = game.forces[memory.force_name]
if not (force and force.valid) then return end
Common.notify_force_light(force,'Leaving the dock.')
end
function Public.go_from_currentdestination_to_sea()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
if memory.game_lost then return end
local oldsurface = game.surfaces[destination.surface_name]
Sea.ensure_sea_surface()
local seaname = memory.sea_name
local boat = memory.boat
local new_boatposition = Utils.snap_coordinates_for_rails({x = Boats.get_scope(memory.boat).Data.width / 2, y = 0})
Boats.teleport_boat(boat, seaname, new_boatposition, CoreData.static_boat_floor, 'water')
memory.boat.state = Boats.enum_state.ATSEA_SAILING
memory.boat.speed = 0
memory.boat.position = new_boatposition
memory.boat.surface_name = seaname
memory.loadingticks = nil
memory.mapbeingloadeddestination_index = nil
local d = destination.iconized_map_width + Crowsnest.platformwidth
Crowsnest.paint_around_destination(destination.destination_index, 'deepwater')
Overworld.try_overworld_move_v2{x = d, y = 0}
local players_marooned_count = 0
for _, player in pairs(game.connected_players) do
if (player.surface == oldsurface and player.character and player.character.valid) then
players_marooned_count = players_marooned_count + 1
end
end
if players_marooned_count == 0 then
Surfaces.clean_up(destination)
end
end
return Public

381
maps/pirates/quest.lua Normal file
View File

@@ -0,0 +1,381 @@
local Memory = require 'maps.pirates.memory'
local Roles = require 'maps.pirates.roles.roles'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Loot = require 'maps.pirates.loot'
local inspect = require 'utils.inspect'.inspect
local Public = {}
local enum = {
TIME = 'Time',
FIND = 'Find',
NODAMAGE = 'No_Damage',
RESOURCEFLOW = 'Resource_Flow',
RESOURCECOUNT = 'Resource_Count',
WORMS = 'Worms',
}
Public.enum = enum
Public.quest_icons = {
[enum.TIME] = '[img=utility.time_editor_icon]',
[enum.NODAMAGE] = '[item=stone-wall]',
[enum.WORMS] = '[entity=small-worm-turret]',
[enum.FIND] = '[img=utility.ghost_time_to_live_modifier_icon]',
[enum.RESOURCEFLOW] = '',
[enum.RESOURCECOUNT] = '',
}
function Public.quest_reward()
local ret
local multiplier = Balance.quest_reward_multiplier()
local rng = Math.random()
if rng <= 0.3 then
ret = {name = 'iron-plate', count = Math.ceil(2000 * multiplier), display_sprite = '[item=iron-plate]', display_amount = string.format('%.0fk', 2 * multiplier)}
elseif rng <= 0.5 then
ret = {name = 'copper-plate', count = Math.ceil(2000 * multiplier), display_sprite = '[item=copper-plate]', display_amount = string.format('%.0fk', 2 * multiplier)}
elseif rng <= 0.7 then
ret = {name = 'solid-fuel', count = Math.ceil(500 * multiplier), display_sprite = '[item=solid-fuel]', display_amount = string.format('%.0f', Math.ceil(350 * multiplier))}
elseif rng <= 0.9 then
ret = {name = 'coin', count = Math.ceil(10000 * multiplier), display_sprite = '[item=coin]', display_amount = string.format('%.0f', Math.ceil(10000 * multiplier))}
else
ret = {name = 'piercing-rounds-magazine', count = Math.ceil(250 * multiplier), display_sprite = '[item=piercing-rounds-magazine]', display_amount = string.format('%.0f', Math.ceil(200 * (multiplier^(3/2))))}
end
return ret
end
function Public.initialise_random_quest()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
destination.dynamic_data.quest_complete = false
if destination.destination_index == 2 then return end
local rng = Math.random(10)
if rng == 1 then
Public.initialise_nodamage_quest()
elseif rng <= 3 then
Public.initialise_worms_quest()
elseif rng <= 5 then
Public.initialise_time_quest()
elseif rng <= 7 then
Public.initialise_find_quest()
elseif rng <= 10 then
Public.initialise_resourcecount_quest()
-- Public.initialise_resourceflow_quest()
end
-- Public.initialise_time_quest()
end
function Public.initialise_time_quest()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
destination.dynamic_data.quest_type = enum.TIME
destination.dynamic_data.quest_reward = Public.quest_reward()
destination.dynamic_data.quest_progress = Balance.time_quest_seconds()
destination.dynamic_data.quest_progressneeded = 9999999
return true
end
function Public.initialise_find_quest()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
-- @FIXME: Magic numbers
if destination.subtype and destination.subtype == '1' or destination.subtype == '5' or destination.subtype == '6' then
destination.dynamic_data.quest_type = enum.FIND
destination.dynamic_data.quest_reward = Public.quest_reward()
destination.dynamic_data.quest_progress = 0
destination.dynamic_data.quest_progressneeded = 1
return true
else
Public.initialise_random_quest() --@FIXME: mild danger of loop
return false
end
end
function Public.initialise_nodamage_quest()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
if not destination and destination.dynamic_data and destination.dynamic_data.rocketsilomaxhp then return end
destination.dynamic_data.quest_type = enum.NODAMAGE
destination.dynamic_data.quest_reward = Public.quest_reward()
destination.dynamic_data.quest_progress = 0
destination.dynamic_data.quest_progressneeded = destination.dynamic_data.rocketsilomaxhp
return true
end
function Public.initialise_resourceflow_quest()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
if not destination and destination.dynamic_data and destination.dynamic_data.rocketsilomaxhp then return end
destination.dynamic_data.quest_type = enum.RESOURCEFLOW
destination.dynamic_data.quest_reward = Public.quest_reward()
destination.dynamic_data.quest_progress = 0
local generated_flow_quest = Public.generate_flow_quest()
destination.dynamic_data.quest_params = {item = generated_flow_quest.item}
local progressneeded_before_rounding = generated_flow_quest.base_rate * Balance.resource_quest_multiplier()
destination.dynamic_data.quest_progressneeded = Math.ceil(progressneeded_before_rounding/10)*10
return true
end
function Public.initialise_resourcecount_quest()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
if not destination and destination.dynamic_data and destination.dynamic_data.rocketsilomaxhp then return end
destination.dynamic_data.quest_type = enum.RESOURCECOUNT
destination.dynamic_data.quest_reward = Public.quest_reward()
destination.dynamic_data.quest_progress = 0
local generated_production_quest = Public.generate_resourcecount_quest()
destination.dynamic_data.quest_params = {item = generated_production_quest.item}
local force = game.forces[memory.force_name]
if force and force.valid then
destination.dynamic_data.quest_params.initial_count = force.item_production_statistics.get_flow_count{name = generated_production_quest.item, input = true, precision_index = defines.flow_precision_index.one_thousand_hours, count = true}
end
local progressneeded_before_rounding = generated_production_quest.base_rate * Balance.resource_quest_multiplier() * Common.difficulty()
destination.dynamic_data.quest_progressneeded = Math.ceil(progressneeded_before_rounding/10)*10
return true
end
function Public.initialise_worms_quest()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
if not (destination.surface_name and game.surfaces[destination.surface_name]) then return end
local surface = game.surfaces[destination.surface_name]
local worms = surface.find_entities_filtered{type = 'turret'}
local count = 0
for i = 1, #worms do
local w = worms[i]
if w.destructible then count = count + 1 end
end
local needed = Math.ceil(
1 + 9 * Math.slopefromto(count, 0, 20) + 10 * Math.slopefromto(count, 20, 70)
)
if Common.difficulty() < 1 then needed = Math.max(1, needed - 3) end
if Common.difficulty() > 1 then needed = Math.max(1, needed + 2) end
if needed >= 5 then
destination.dynamic_data.quest_type = enum.WORMS
destination.dynamic_data.quest_reward = Public.quest_reward()
destination.dynamic_data.quest_progress = 0
destination.dynamic_data.quest_progressneeded = needed
return true
else
Public.initialise_random_quest() --@FIXME: mild danger of loop
return false
end
end
function Public.try_resolve_quest()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
if destination.dynamic_data.quest_type and destination.dynamic_data.quest_progress and destination.dynamic_data.quest_progressneeded and destination.dynamic_data.quest_progress >= destination.dynamic_data.quest_progressneeded and (not destination.dynamic_data.quest_complete) then
local force = game.forces[memory.force_name]
if not (force and force.valid) then return end
Common.notify_force(force,'Quest complete! Granted ' .. destination.dynamic_data.quest_reward.display_amount .. ' ' .. destination.dynamic_data.quest_reward.display_sprite)
local name = destination.dynamic_data.quest_reward.name
local count = destination.dynamic_data.quest_reward.count
-- destination.dynamic_data.quest_type = nil
-- destination.dynamic_data.quest_reward = nil
-- destination.dynamic_data.quest_progress = nil
-- destination.dynamic_data.quest_progressneeded = nil
destination.dynamic_data.quest_complete = true
local boat = memory.boat
if not boat then return end
local surface_name = boat.surface_name
if not surface_name then return end
local surface = game.surfaces[surface_name]
if not (surface and surface.valid) then return end
local chest = boat.output_chest
if not chest and chest.valid then return end
local inventory = chest.get_inventory(defines.inventory.chest)
local inserted = inventory.insert{name = name, count = count}
if inserted < count then
Common.notify_force(force,'There wasn\'t space in the cabin for all of your reward.')
end
end
end
-- Public.flow_quest_data_raw = {
-- {0.2, 0, 1, false, 'submachine-gun', 3 * 12},
-- {1, 0, 1, false, 'electronic-circuit', 3 * 120},
-- {0.2, 0.1, 1, false, 'big-electric-pole', 1 * 120},
-- {0.4, 0.2, 1, false, 'engine-unit', 3 * 6},
-- -- {1, 0.5, 1, false, 'advanced-circuit', 1 * 10},
-- -- {0.3, 0.8, 1, false, 'electric-engine-unit', 1 * 6},
-- }
-- function Public.flow_quest_data()
-- local ret = {}
-- local data = Public.flow_quest_data_raw
-- for i = 1, #data do
-- local datum = data[i]
-- ret[#ret + 1] = {
-- weight = datum[1],
-- game_completion_progress_min = datum[2],
-- game_completion_progress_max = datum[3],
-- scaling = datum[4],
-- item = datum[5],
-- base_rate = datum[6],
-- }
-- end
-- return ret
-- end
function Public.generate_flow_quest()
local memory = Memory.get_crew_memory()
local game_completion_progress = Common.game_completion_progress()
local data = Public.flow_quest_data()
local v, w = {}, {}
for i = 1, #data, 1 do
table.insert(v, {item = data[i].item, base_rate = data[i].base_rate})
local destination = Common.current_destination()
if not (destination and destination.subtype and data[i].map_subtype and data[i].map_subtype == destination.subtype) then
if data[i].scaling then -- scale down weights away from the midpoint 'peak' (without changing the mean)
local midpoint = (data[i].game_completion_progress_max + data[i].game_completion_progress_min) / 2
local difference = (data[i].game_completion_progress_max - data[i].game_completion_progress_min)
table.insert(w, data[i].weight * Math.max(0, 1 - (Math.abs(game_completion_progress - midpoint) / (difference / 2))))
else -- no scaling
if data[i].game_completion_progress_min <= game_completion_progress and data[i].game_completion_progress_max >= game_completion_progress then
table.insert(w, data[i].weight)
else
table.insert(w, 0)
end
end
end
end
return Math.raffle(v, w)
end
Public.resourcecount_quest_data_raw = {
{0.8, 0, 1, false, 'iron-gear-wheel', 2400},
{1, 0, 1, false, 'electronic-circuit', 1200},
{1, 0, 1, false, 'transport-belt', 900},
-- {0.1, 0, 1, false, 'red-wire', 500},
{0.4, 0, 1, false, 'empty-barrel', 600},
{0.3, 0, 0.2, false, 'splitter', 500},
{0.3, 0.2, 1, false, 'fast-splitter', 250},
{0.4, 0.3, 1, false, 'big-electric-pole', 250},
-- {1, 0.5, 1, false, 'advanced-circuit', 1 * 10},
-- {0.3, 0.8, 1, false, 'electric-engine-unit', 1 * 6},
}
function Public.resourcecount_quest_data()
local ret = {}
local data = Public.resourcecount_quest_data_raw
for i = 1, #data do
local datum = data[i]
ret[#ret + 1] = {
weight = datum[1],
game_completion_progress_min = datum[2],
game_completion_progress_max = datum[3],
scaling = datum[4],
item = datum[5],
base_rate = datum[6],
}
end
return ret
end
function Public.generate_resourcecount_quest()
local memory = Memory.get_crew_memory()
local game_completion_progress = Common.game_completion_progress()
local data = Public.resourcecount_quest_data()
local v, w = {}, {}
for i = 1, #data, 1 do
table.insert(v, {item = data[i].item, base_rate = data[i].base_rate})
local destination = Common.current_destination()
if not (destination and destination.subtype and data[i].map_subtype and data[i].map_subtype == destination.subtype) then
if data[i].scaling then -- scale down weights away from the midpoint 'peak' (without changing the mean)
local midpoint = (data[i].game_completion_progress_max + data[i].game_completion_progress_min) / 2
local difference = (data[i].game_completion_progress_max - data[i].game_completion_progress_min)
table.insert(w, data[i].weight * Math.max(0, 1 - (Math.abs(game_completion_progress - midpoint) / (difference / 2))))
else -- no scaling
if data[i].game_completion_progress_min <= game_completion_progress and data[i].game_completion_progress_max >= game_completion_progress then
table.insert(w, data[i].weight)
else
table.insert(w, 0)
end
end
end
end
return Math.raffle(v, w)
end
return Public

View File

@@ -0,0 +1,233 @@
-- data:extend(
-- {
-- {
-- type='map-settings',
-- name='map-settings',
-- pollution=
-- {
-- enabled=true,
-- -- these are values for 60 ticks (1 simulated second)
-- --
-- -- amount that is diffused to neighboring chunk
-- -- (possibly repeated for other directions as well)
-- diffusion_ratio=0.02,
-- -- this much PUs must be on the chunk to start diffusing
-- min_to_diffuse=15,
-- -- constant modifier a percentage of 1 - the pollution eaten by a chunks tiles
-- ageing=1,
-- -- anything bigger than this is visualised as this value
-- expected_max_per_chunk=150,
-- -- anything lower than this (but > 0) is visualised as this value
-- min_to_show_per_chunk=50,
-- min_pollution_to_damage_trees = 60,
-- pollution_with_max_forest_damage = 150,
-- pollution_per_tree_damage = 50,
-- pollution_restored_per_tree_damage = 10,
-- max_pollution_to_restore_trees = 20,
-- enemy_attack_pollution_consumption_modifier = 1
-- },
-- enemy_evolution=
-- {
-- enabled=true,
-- -- percentual increase in the evolve factor for every second (60 ticks)
-- time_factor = 0.000004,
-- -- percentual increase in the evolve factor for every destroyed spawner
-- destroy_factor = 0.002,
-- -- percentual increase in the evolve factor for 1 pollution unit
-- pollution_factor = 0.0000009
-- },
-- enemy_expansion=
-- {
-- enabled = true,
-- -- Distance in chunks from the furthest base around.
-- -- This prevents expansions from reaching too far into the
-- -- player's territory
-- max_expansion_distance = 7,
-- friendly_base_influence_radius = 2,
-- enemy_building_influence_radius = 2,
-- -- A candidate chunk's score is given as follows:
-- -- player = 0
-- -- for neighbour in all chunks within enemy_building_influence_radius from chunk:
-- -- player += number of player buildings on neighbour
-- -- * building_coefficient
-- -- * neighbouring_chunk_coefficient^distance(chunk, neighbour)
-- --
-- -- base = 0
-- -- for neighbour in all chunk within friendly_base_influence_radius from chunk:
-- -- base += num of enemy bases on neighbour
-- -- * other_base_coefficient
-- -- * neighbouring_base_chunk_coefficient^distance(chunk, neighbour)
-- --
-- -- score(chunk) = 1 / (1 + player + base)
-- --
-- -- The iteration is over a square region centered around the chunk for which the calculation is done,
-- -- and includes the central chunk as well. distance is the Manhattan distance, and ^ signifies exponentiation.
-- building_coefficient = 0.1,
-- other_base_coefficient = 2.0,
-- neighbouring_chunk_coefficient = 0.5,
-- neighbouring_base_chunk_coefficient = 0.4,
-- -- A chunk has to have at most this much percent unbuildable tiles for it to be considered a candidate.
-- -- This is to avoid chunks full of water to be marked as candidates.
-- max_colliding_tiles_coefficient = 0.9,
-- -- Size of the group that goes to build new base (in game this is multiplied by the
-- -- evolution factor).
-- settler_group_min_size = 5,
-- settler_group_max_size = 20,
-- -- Ticks to expand to a single
-- -- position for a base is used.
-- --
-- -- cooldown is calculated as follows:
-- -- cooldown = lerp(max_expansion_cooldown, min_expansion_cooldown, -e^2 + 2 * e),
-- -- where lerp is the linear interpolation function, and e is the current evolution factor.
-- min_expansion_cooldown = 4 * 3600,
-- max_expansion_cooldown = 60 * 3600
-- },
-- unit_group=
-- {
-- -- pollution triggered group waiting time is a random time between min and max gathering time
-- min_group_gathering_time = 3600,
-- max_group_gathering_time = 10 * 3600,
-- -- after the gathering is finished the group can still wait for late members,
-- -- but it doesn't accept new ones anymore
-- max_wait_time_for_late_members = 2 * 3600,
-- -- limits for group radius (calculated by number of numbers)
-- max_group_radius = 30.0,
-- min_group_radius = 5.0,
-- -- when a member falls behind the group he can speedup up till this much of his regular speed
-- max_member_speedup_when_behind = 1.4,
-- -- When a member gets ahead of its group, it will slow down to at most this factor of its speed
-- max_member_slowdown_when_ahead = 0.6,
-- -- When members of a group are behind, the entire group will slow down to at most this factor of its max speed
-- max_group_slowdown_factor = 0.3,
-- -- If a member falls behind more than this times the group radius, the group will slow down to max_group_slowdown_factor
-- max_group_member_fallback_factor = 3,
-- -- If a member falls behind more than this time the group radius, it will be removed from the group.
-- member_disown_distance = 10,
-- tick_tolerance_when_member_arrives = 60,
-- -- Maximum number of automatically created unit groups gathering for attack at any time.
-- max_gathering_unit_groups = 30,
-- -- Maximum size of an attack unit group. This only affects automatically-created unit groups;
-- -- manual groups created through the API are unaffected.
-- max_unit_group_size = 200
-- },
-- steering=
-- {
-- default=
-- {
-- -- not including the radius of the unit
-- radius = 1.2,
-- separation_force = 0.005,
-- separation_factor = 1.2,
-- force_unit_fuzzy_goto_behavior = false
-- },
-- moving=
-- {
-- radius = 3,
-- separation_force = 0.01,
-- separation_factor = 3,
-- -- used only for special 'to look good' purposes (like in trailer)
-- force_unit_fuzzy_goto_behavior = false
-- }
-- },
-- path_finder=
-- {
-- -- defines whether we prefer forward (>1) or backward (<-1) or symmetrical (1) search
-- fwd2bwd_ratio = 1,
-- -- when comparing nodes in open which one to check next
-- -- heuristic value is multiplied by this ratio
-- -- the higher the number the more is the search directed directly towards the goal
-- goal_pressure_ratio = 2,
-- -- How many nodes can be expanded at most per tick.
-- max_steps_worked_per_tick = 1000,
-- -- How much work each patfinding job is allowed to do per tick.
-- max_work_done_per_tick = 8000,
-- -- path cache setings
-- use_path_cache = true,
-- -- number of elements in the cache
-- short_cache_size = 5,
-- long_cache_size = 25,
-- -- minimal distance to goal for path to be searched in short path cache
-- short_cache_min_cacheable_distance = 10,
-- -- minimal number of algorithm steps for path to be inserted into the short path cache
-- short_cache_min_algo_steps_to_cache = 50,
-- -- minimal distance to goal for path to be searched in long path cache
-- long_cache_min_cacheable_distance = 30,
-- -- when searching for connection to path cache path, search at most for this number of steps times the initial estimate
-- cache_max_connect_to_cache_steps_multiplier = 100,
-- -- when looking for path from cache make sure it doesn't start too far from requested start in relative distance terms
-- cache_accept_path_start_distance_ratio = 0.2,
-- -- when looking for path from cache make sure it doesn't end too far from requested end
-- -- this is typically higher than accept value for the start because the end target can be moving
-- cache_accept_path_end_distance_ratio = 0.15,
-- -- Same as cache_accept_path_start_distance_ratio, but used for negative cache queries
-- negative_cache_accept_path_start_distance_ratio = 0.3,
-- -- Same as cache_accept_path_end_distance_ratio, but used for negative cache queries
-- negative_cache_accept_path_end_distance_ratio = 0.3,
-- -- when assigning rating to the best path this * start distances is considered
-- cache_path_start_distance_rating_multiplier = 10,
-- -- when assigning rating to the best path this * end distances is considered
-- -- this is typically higher than value for the start to achieve better path end quality
-- cache_path_end_distance_rating_multiplier = 20,
-- -- somewhere along the path is stuck enemy we need to avoid
-- -- this is mainly to handle situations when units have arrived and are attacking the target
-- -- then units further in the back will use this and run around the target
-- stale_enemy_with_same_destination_collision_penalty = 30,
-- -- if there is a moving unit further than this we don't really care
-- ignore_moving_enemy_collision_distance = 5,
-- -- enemy is not moving/or is too close and has different destination
-- enemy_with_different_destination_collision_penalty = 30,
-- -- simplification for now - collision with everything else is this
-- general_entity_collision_penalty = 10,
-- -- collision penalty for successors of positions that require destroy to reach
-- general_entity_subsequent_collision_penalty = 3,
-- -- Collision penalty for collisions in the extended bounding box but outside the entity's actual bounding box
-- extended_collision_penalty = 3,
-- -- uptil this amount any client will be served by the path finder (no estimate on the path length)
-- max_clients_to_accept_any_new_request = 10,
-- -- from max_clients_to_accept_any_new_request till this one only those that have a short estimate will be served
-- max_clients_to_accept_short_new_request = 100,
-- -- this is the 'threshold' to decide what is short and what is not
-- direct_distance_to_consider_short_request = 100,
-- -- if a short request takes more than this many steps, it will be rescheduled as a long request
-- short_request_max_steps = 1000,
-- -- How many steps will be allocated to short requests each tick, as a ratio of all available steps per tick
-- short_request_ratio = 0.5,
-- -- absolute minimum of steps that will be performed for every path find request no matter what
-- min_steps_to_check_path_find_termination = 2000,
-- -- if the amount of steps is higher than this times estimate of start to goal then path finding is terminated
-- start_to_goal_cost_multiplier_to_terminate_path_find = 2000.0,
-- -- When the number of waiting clients exceeds certain values, the per-tick work limit will be increased by the
-- -- given multiplier. overload_levels gives the threshold values, overload_multipliers gives the multipliers.
-- -- overload_levels and overload_multipliers must be the same length.
-- overload_levels = {0, 100, 500},
-- overload_multipliers = {2, 3, 4}
-- },
-- -- If a behavior fails this many times, the enemy (or enemy group)
-- -- is destroyed.
-- -- This solves biters stuck within their own base.
-- max_failed_behavior_count = 3,
-- -- These can't be changed through game.map_settings - you must use game.difficulty_settings
-- difficulty_settings =
-- {
-- recipe_difficulty = defines.difficulty_settings.recipe_difficulty.normal,
-- technology_difficulty = defines.difficulty_settings.technology_difficulty.normal,
-- technology_price_multiplier = 1,
-- research_queue_setting = 'after-victory'
-- }
-- }
-- })

View File

@@ -0,0 +1,52 @@
local Balance = require 'maps.pirates.balance'
local inspect = require 'utils.inspect'.inspect
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local CoreData = require 'maps.pirates.coredata'
local Server = require 'utils.server'
local Public = {}
local enum = {
DECKHAND = 1,
FISHERMAN = 2,
SCOUT = 3,
SAMURAI = 4,
MERCHANT = 5,
SHORESMAN = 6,
BOATSWAIN = 7,
}
Public.enum = enum
Public.Class_List = {
enum.DECKHAND,
enum.FISHERMAN,
enum.SCOUT,
enum.SAMURAI,
enum.MERCHANT,
enum.SHORESMAN,
enum.BOATSWAIN,
}
Public.display_form = {
[enum.DECKHAND] = 'Deckhand',
[enum.FISHERMAN] = 'Fisherman',
[enum.SCOUT] = 'Scout',
[enum.SAMURAI] = 'Samurai',
[enum.MERCHANT] = 'Merchant',
[enum.SHORESMAN] = 'Shoresman',
[enum.BOATSWAIN] = 'Boatswain',
}
Public.explanation = {
[enum.DECKHAND] = 'They move faster and generate iron ore for the ship whilst onboard above deck, but move slower offboard.',
[enum.FISHERMAN] = 'They fish at greater distance.',
[enum.SCOUT] = 'They are faster, but frail and deal much less damage.',
[enum.SAMURAI] = 'They are tough, and when they have no weapon equipped they fight well by melee, but poorly otherwise.',
[enum.MERCHANT] = 'They generate 40 coins per league, but they are frail.',
[enum.SHORESMAN] = 'They move slightly faster and generate iron ore for the ship whilst offboard, but move slower onboard.',
[enum.BOATSWAIN] = 'They move faster and generate lots of ore for the ship whilst onboard below deck, but move slower offboard.',
}
return Public

View File

@@ -0,0 +1,258 @@
local Balance = require 'maps.pirates.balance'
local inspect = require 'utils.inspect'.inspect
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local CoreData = require 'maps.pirates.coredata'
local Server = require 'utils.server'
local Classes = require 'maps.pirates.roles.classes'
local Public = {}
--== Roles — General ==--
function Public.tag_text(player)
local memory = Memory.get_crew_memory()
local tags = {}
if memory.id ~= 0 and memory.playerindex_captain and player.index == memory.playerindex_captain then
tags[#tags + 1] = "Cap'n"
elseif player.controller_type == defines.controllers.spectator then
tags[#tags + 1] = 'Spectating'
end
if memory.classes_table and memory.classes_table[player.index] then
if not str == '' then str = str .. ' ' end
tags[#tags + 1] = Classes.display_form[memory.classes_table[player.index]]
end
local str = ''
for i, t in ipairs(tags) do
if i>1 then str = str .. ', ' end
str = str .. t
end
if (not (str == '')) then str = '[' .. str .. ']' end
return str
end
function Public.update_tags(player)
local str = Public.tag_text(player)
player.tag = str
end
function Public.try_accept_captainhood(player)
local memory = Memory.get_crew_memory()
local captain_index = memory.playerindex_captain
if not (player.index == captain_index) then
Common.notify_player(player, 'You\'re not the captain.')
else
if memory.captain_acceptance_timer then
memory.captain_acceptance_timer = nil
local force = player.force
if force and force.valid then
local message = (player.name .. ' accepted the role of captain.')
Common.notify_force(force, message)
Server.to_discord_embed_raw(CoreData.comfy_emojis.derp .. '[' .. memory.name .. '] ' .. message)
end
else
Common.notify_player(player, 'You\'re not temporary, so you don\'t need to accept.')
end
end
end
function Public.player_left_so_redestribute_roles(player)
local memory = Memory.get_crew_memory()
-- we can assume #Common.crew_get_crew_members() > 0
if player and player.index and player.index == memory.playerindex_captain then
Public.assign_captain_based_on_priorities()
end
Public.try_renounce_class(player, "A %s class is now spare.")
end
function Public.renounce_captainhood(player)
local global_memory = Memory.get_global_memory()
local memory = Memory.get_crew_memory()
if #Common.crew_get_crew_members() == 1 then
Common.notify_player(player, 'But you\'re the only crew member...')
else
local force = game.forces[memory.force_name]
global_memory.playerindex_to_priority[player.index] = nil
if force and force.valid then
local message = (player.name .. ' renounces their title of captain.')
Common.notify_force(force, message)
Server.to_discord_embed_raw(CoreData.comfy_emojis.ree1 .. '[' .. memory.name .. '] ' .. message)
end
Public.assign_captain_based_on_priorities(player.index)
end
end
function Public.assign_class(player_index, class, self_assigned)
local memory = Memory.get_crew_memory()
if not memory.classes_table then memory.classes_table = {} end
if Utils.contains(memory.spare_classes, class) then -- verify that one is spare
memory.classes_table[player_index] = class
local force = game.forces[memory.force_name]
if force and force.valid then
local message
if self_assigned then
message = '%s took the spare class %s. ([font=scenario-message-dialog]%s[/font])'
Common.notify_force_light(force,string.format(message, game.players[player_index].name, Classes.display_form[memory.classes_table[player_index]], Classes.explanation[memory.classes_table[player_index]]))
else
message = 'A spare %s class was given to %s. [font=scenario-message-dialog](%s)[/font]'
Common.notify_force_light(force,string.format(message, Classes.display_form[memory.classes_table[player_index]], game.players[player_index].name, Classes.explanation[memory.classes_table[player_index]]))
end
end
memory.spare_classes = Utils.ordered_table_with_single_value_removed(memory.spare_classes, class)
end
end
function Public.try_renounce_class(player, override_message)
local memory = Memory.get_crew_memory()
local force = game.forces[memory.force_name]
if force and force.valid then
if player and player.index and memory.classes_table and memory.classes_table[player.index] then
if force and force.valid then
if override_message then
Common.notify_force_light(force,string.format(override_message, Classes.display_form[memory.classes_table[player.index]]))
else
Common.notify_force_light(force,string.format('%s gave up the class %s.', player.name, Classes.display_form[memory.classes_table[player.index]]))
end
end
memory.spare_classes[#memory.spare_classes + 1] = memory.classes_table[player.index]
memory.classes_table[player.index] = nil
end
end
end
function Public.pass_captainhood(player, player_to_pass_to)
local global_memory = Memory.get_global_memory()
local memory = Memory.get_crew_memory()
memory.playerindex_captain = player_to_pass_to.index
global_memory.playerindex_to_priority[player_to_pass_to.index] = nil
memory.captain_acceptance_timer = nil
local force = game.forces[memory.force_name]
if not (force and force.valid) then return end
local message = string.format("%s has passed their captainhood to %s.", player.name, player_to_pass_to.name)
Common.notify_force(force, message)
Server.to_discord_embed_raw(CoreData.comfy_emojis.spurdo .. '[' .. memory.name .. '] ' .. message)
end
function Public.afk_player_tick(player)
local global_memory = Memory.get_global_memory()
local memory = Memory.get_crew_memory()
if player.index == memory.playerindex_captain and #Common.crew_get_nonafk_crew_members() > 0 then
local force = game.forces[memory.force_name]
if force and force.valid then
local message = string.format(player.name .. ' was afk.')
Common.notify_force(force, message)
Server.to_discord_embed_raw(CoreData.comfy_emojis.loops .. '[' .. memory.name .. '] ' .. message)
end
if #Common.crew_get_nonafk_crew_members() == 1 then --don't need to bounce it around
local new_cap_index = Common.crew_get_nonafk_crew_members()[1].index
global_memory.playerindex_to_priority[new_cap_index] = nil
memory.playerindex_captain = new_cap_index
else
Public.assign_captain_based_on_priorities()
end
end
end
function Public.assign_captain_based_on_priorities(excluded_player_index)
excluded_player_index = excluded_player_index or nil
local global_memory = Memory.get_global_memory()
local memory = Memory.get_crew_memory()
local crew_members = memory.crewplayerindices
if not (crew_members and #crew_members > 0) then return end
local only_found_afk_players = true
local best_priority_so_far = -1
local captain_index = nil
local captain_name = nil
for _, player_index in pairs(crew_members) do
local player = game.players[player_index]
if Common.validate_player(player) and not (player.index == excluded_player_index) then
local player_active = Utils.contains(Common.crew_get_nonafk_crew_members(), player)
-- prefer non-afk players:
if only_found_afk_players or player_active then
only_found_afk_players = player_active
local player_priority = global_memory.playerindex_to_priority[player_index]
if player_priority and player_priority > best_priority_so_far then
best_priority_so_far = player_priority
captain_index = player_index
captain_name = player.name
end
end
end
end
local force = game.forces[memory.force_name]
if not (force and force.valid) then return end
if not captain_index then
captain_index = crew_members[1]
captain_name = game.players[captain_index].name
Common.notify_force(force,'Looking for a suitable captain...')
end
global_memory.playerindex_to_priority[captain_index] = nil
memory.playerindex_captain = captain_index
if #Common.crew_get_crew_members() > 1 then
local messages = {
"would you like to be captain?",
"would you like to be captain?",
"captain?",
"is it your turn to be captain?",
}
local message = captain_name .. ', ' .. messages[Math.random(#messages)]
Common.notify_force_light(force, message .. ' If yes say /ok')
-- Server.to_discord_embed_raw('[' .. memory.name .. ']' .. CoreData.comfy_emojis.spurdo .. ' ' .. message)
memory.captain_acceptance_timer = 72 --tuned
end
end
return Public

View File

@@ -0,0 +1,84 @@
local Memory = require 'maps.pirates.memory'
local Roles = require 'maps.pirates.roles.roles'
local Classes = require 'maps.pirates.roles.classes'
local Crew = require 'maps.pirates.crew'
local Boats = require 'maps.pirates.structures.boats.boats'
local Dock = require 'maps.pirates.surfaces.dock'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local inspect = require 'utils.inspect'.inspect
local Upgrades = require 'maps.pirates.boat_upgrades'
local Public = {}
local enum = {
TIME = 'Time',
}
Public.enum = enum
Public.offers_loaders = {
{price = {{'coin', 1000}}, offer = {type = 'give-item', item = 'loader', count = 1}},
{price = {{'coin', 2000}}, offer = {type = 'give-item', item = 'fast-loader', count = 1}},
{price = {{'coin', 3000}}, offer = {type = 'give-item', item = 'express-loader', count = 1}},
}
Public.offers_default = {
{price = {{'coin', 1000}}, offer = {type = 'give-item', item = 'copper-plate', count = 200}},
{price = {{'coin', 1000}}, offer = {type = 'give-item', item = 'iron-plate', count = 200}},
}
Public.offers_rockets = {
{price = {{'coin', 200}, {'electronic-circuit', 50}}, offer = {type = 'give-item', item = 'rocket-launcher', count = 1}},
{price = {{'coin', 1000}, {'explosives', 20}, {'electronic-circuit', 20}}, offer = {type = 'give-item', item = 'rocket', count = 20}},
}
function Public.market_generate_coin_offers(how_many)
local memory = Memory.get_crew_memory()
local ret = {}
local offerscopy = Utils.deepcopy(Public.offers_default)
local loaderoffers = Public.offers_loaders
local game_completion_progress = Common.game_completion_progress()
if game_completion_progress < 0.2 then
ret[#ret + 1] = loaderoffers[1]
elseif game_completion_progress < 0.6 then
ret[#ret + 1] = loaderoffers[2]
else
ret[#ret + 1] = loaderoffers[3]
end
local toaddcount = how_many
while toaddcount>0 and #offerscopy > 0 do
local index = Math.random(#offerscopy)
local toadd = offerscopy[index]
ret[#ret + 1] = toadd
for i = index, #offerscopy - 1 do
offerscopy[i] = offerscopy[i+1]
end
offerscopy[#offerscopy] = nil
toaddcount = toaddcount - 1
end
if memory.rockets_for_sale then
for _, o in ipairs(Public.offers_rockets) do
ret[#ret + 1] = o
end
end
return ret
end
return Public

View File

@@ -0,0 +1,62 @@
local Memory = require 'maps.pirates.memory'
local Roles = require 'maps.pirates.roles.roles'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Loot = require 'maps.pirates.loot'
local inspect = require 'utils.inspect'.inspect
local Hold = require 'maps.pirates.surfaces.hold'
local Public = {}
function Public.generate_merchant_trades(market)
local memory = Memory.get_crew_memory()
if market and market.valid then
market.add_market_item{price={{'pistol', 1}}, offer={type = 'give-item', item = 'coin', count = 500}}
local game_completion_progress = Common.game_completion_progress()
if game_completion_progress <= 1 then
market.add_market_item{price = {{'coin', 12000}, {'raw-fish', 100}}, offer = {type = 'give-item', item = 'modular-armor', count = 1}}
market.add_market_item{price = {{'coin', 6000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'battery-equipment', count = 1}}
market.add_market_item{price = {{'coin', 400}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'solar-panel-equipment', count = 1}}
market.add_market_item{price = {{'coin', 1000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'night-vision-equipment', count = 1}}
market.add_market_item{price = {{'coin', 2000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'energy-shield-equipment', count = 1}}
market.add_market_item{price = {{'coin', 1000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'personal-roboport-equipment', count = 1}}
else
market.add_market_item{price = {{'coin', 18000}, {'raw-fish', 100}}, offer = {type = 'give-item', item = 'modular-armor', count = 1}}
market.add_market_item{price = {{'coin', 12000}, {'raw-fish', 100}}, offer = {type = 'give-item', item = 'power-armor', count = 1}}
market.add_market_item{price = {{'coin', 6000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'battery-equipment', count = 1}}
market.add_market_item{price = {{'coin', 2000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'energy-shield-equipment', count = 1}}
market.add_market_item{price = {{'coin', 1000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'personal-roboport-equipment', count = 1}}
market.add_market_item{price = {{'coin', 10000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'battery-mk2-equipment', count = 1}}
market.add_market_item{price = {{'coin', 400}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'solar-panel-equipment', count = 1}}
market.add_market_item{price = {{'coin', 6000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'fusion-reactor-equipment', count = 1}}
market.add_market_item{price = {{'coin', 1000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'night-vision-equipment', count = 1}}
market.add_market_item{price = {{'coin', 5000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'energy-shield-mk2-equipment', count = 1}}
market.add_market_item{price = {{'coin', 4000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'personal-roboport-mk2-equipment', count = 1}}
market.add_market_item{price = {{'coin', 8000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'exoskeleton-equipment', count = 1}}
market.add_market_item{price = {{'coin', 10000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'personal-laser-defense', count = 1}}
-- else
-- market.add_market_item{price = {{'coin', 18000}, {'raw-fish', 100}}, offer = {type = 'give-item', item = 'power-armor', count = 1}}
-- market.add_market_item{price = {{'coin', 24000}, {'raw-fish', 100}}, offer = {type = 'give-item', item = 'power-armor-mk2', count = 1}}
-- market.add_market_item{price = {{'coin', 10000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'battery-mk2-equipment', count = 1}}
-- market.add_market_item{price = {{'coin', 400}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'solar-panel-equipment', count = 1}}
-- market.add_market_item{price = {{'coin', 6000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'fusion-reactor-equipment', count = 1}}
-- market.add_market_item{price = {{'coin', 1000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'night-vision-equipment', count = 1}}
-- market.add_market_item{price = {{'coin', 5000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'energy-shield-mk2-equipment', count = 1}}
-- market.add_market_item{price = {{'coin', 4000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'personal-roboport-mk2-equipment', count = 1}}
-- market.add_market_item{price = {{'coin', 8000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'exoskeleton-equipment', count = 1}}
-- market.add_market_item{price = {{'coin', 10000}, {'raw-fish', 10}}, offer = {type = 'give-item', item = 'personal-laser-defense', count = 1}}
end
end
end
return Public

View File

@@ -0,0 +1,83 @@
local Memory = require 'maps.pirates.memory'
local Roles = require 'maps.pirates.roles.roles'
local Classes = require 'maps.pirates.roles.classes'
local Crew = require 'maps.pirates.crew'
local Boats = require 'maps.pirates.structures.boats.boats'
local Dock = require 'maps.pirates.surfaces.dock'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local inspect = require 'utils.inspect'.inspect
local Upgrades = require 'maps.pirates.boat_upgrades'
local Public = {}
Public.market_barters = {
{price = {{'iron-plate', 300}}, offer = {type = 'give-item', item = 'copper-plate', count = 500}},
{price = {{'copper-plate', 300}}, offer = {type = 'give-item', item = 'iron-plate', count = 500}},
--repeating these:
{price = {{'iron-plate', 300}}, offer = {type = 'give-item', item = 'copper-plate', count = 500}},
{price = {{'copper-plate', 300}}, offer = {type = 'give-item', item = 'iron-plate', count = 500}},
{price = {{'steel-plate', 50}}, offer = {type = 'give-item', item = 'copper-plate', count = 500}},
{price = {{'steel-plate', 50}}, offer = {type = 'give-item', item = 'iron-plate', count = 500}},
{price = {{'raw-fish', 50}}, offer = {type = 'give-item', item = 'coal', count = 600}},
{price = {{'raw-fish', 50}}, offer = {type = 'give-item', item = 'iron-plate', count = 600}},
{price = {{'raw-fish', 50}}, offer = {type = 'give-item', item = 'copper-plate', count = 600}},
{price = {{'raw-fish', 50}}, offer = {type = 'give-item', item = 'steel-plate', count = 100}},
{price = {{'wood', 200}}, offer = {type = 'give-item', item = 'coin', count = 25}},
--TODO: add more complex trades
}
function Public.minimarket_generate_barters(how_many)
local ret = {}
local barterscopy = Utils.deepcopy(Public.market_barters)
local toaddcount = how_many
while toaddcount>0 and #barterscopy > 0 do
local index = Math.random(#barterscopy)
local toadd = barterscopy[index]
ret[#ret + 1] = toadd
for i = index, #barterscopy - 1 do
barterscopy[i] = barterscopy[i+1]
end
barterscopy[#barterscopy] = nil
toaddcount = toaddcount - 1
end
return ret
end
function Public.create_minimarket(surface, p)
local memory = Memory.get_crew_memory()
if not (surface and p) then return end
local entity = {name = 'market', position = p}
if surface.can_place_entity(entity) then
local e = surface.create_entity(entity)
if e and e.valid then
e.minable = false
e.rotatable = false
e.destructible = false
local barters = Public.minimarket_generate_barters(4)
for _, barter in pairs(barters) do
local offer = barter
e.add_market_item(offer)
end
end
end
end
return Public

380
maps/pirates/shop/shop.lua Normal file
View File

@@ -0,0 +1,380 @@
local Memory = require 'maps.pirates.memory'
local Roles = require 'maps.pirates.roles.roles'
local Classes = require 'maps.pirates.roles.classes'
local Crew = require 'maps.pirates.crew'
local Boats = require 'maps.pirates.structures.boats.boats'
local Dock = require 'maps.pirates.surfaces.dock'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local inspect = require 'utils.inspect'.inspect
local Upgrades = require 'maps.pirates.boat_upgrades'
local Public = {}
Public.main_shop_data_1 = {
new_boat_cutter = {
tooltip = 'Purchase a cutter for 3000 gold.',
what_you_get_sprite_buttons = {['utility/spawn_flag'] = false},
base_cost = {gold = 3000},
},
new_boat_sloop_with_hold = {
tooltip = 'Purchase a sloop (with hold) for 3500 gold.',
what_you_get_sprite_buttons = {['utility/spawn_flag'] = false},
base_cost = {gold = 3500},
},
new_boat_cutter_with_hold = {
tooltip = 'Purchase a cutter (with hold) for 5000 gold.',
what_you_get_sprite_buttons = {['utility/spawn_flag'] = false},
base_cost = {gold = 5000},
},
buy_iron = {
tooltip = 'Purchase 500 iron plates for 250 gold.',
what_you_get_sprite_buttons = {['item/iron-plate'] = 250},
base_cost = {gold = 300},
},
buy_copper = {
tooltip = 'Purchase 500 copper plates for 250 gold.',
what_you_get_sprite_buttons = {['item/copper-plate'] = 250},
base_cost = {gold = 300},
},
-- sell_iron = {
-- tooltip = 'Purchase 200 gold for 2000 iron plates.',
-- what_you_get_sprite_buttons = {['item/sulfur'] = 200},
-- base_cost = {iron_plates = 2000},
-- },
-- sell_copper = {
-- tooltip = 'Purchase 100 gold for 2500 copper plates',
-- what_you_get_sprite_buttons = {['item/sulfur'] = 100},
-- base_cost = {copper_plates = 2500},
-- },
[Upgrades.enum.MORE_POWER] = {
tooltip = 'Upgrade the ship\'s power for 2000 gold.',
what_you_get_sprite_buttons = {['utility/status_working'] = false},
base_cost = {gold = 2000},
},
[Upgrades.enum.EXTRA_HOLD] = {
tooltip = 'Upgrade the ship\'s hold for 4000 gold.',
what_you_get_sprite_buttons = {['item/steel-chest'] = false},
base_cost = {gold = 4000},
},
[Upgrades.enum.ROCKETS_FOR_SALE] = {
tooltip = 'Unlock rockets for sale at covered-up markets, for 4000 gold.',
what_you_get_sprite_buttons = {['item/rocket-launcher'] = false},
base_cost = {gold = 4000},
},
[Upgrades.enum.UNLOCK_MERCHANTS] = {
tooltip = 'Unlock merchant ships for 5000 gold.',
what_you_get_sprite_buttons = {['entity/market'] = false},
base_cost = {gold = 5000},
},
}
Public.main_shop_data_2 = {
rail_signal = {
tooltip = '100 signals to steer the boat for 159 gold.',
what_you_get_sprite_buttons = {['item/rail-signal'] = 100},
base_cost = {gold = 150},
},
artillery_shell = {
tooltip = '10 cannon shells for 1500 gold.',
what_you_get_sprite_buttons = {['item/artillery-shell'] = 10},
base_cost = {gold = 1500},
},
artillery_remote = {
tooltip = 'An artillery targeting remote for 2000 gold.',
what_you_get_sprite_buttons = {['item/artillery-targeting-remote'] = 1},
base_cost = {gold = 2000},
},
extra_time = {
tooltip = 'Relax at sea for an extra minute for 50 gold. (Increases the next destination\'s loading time.)',
what_you_get_sprite_buttons = {['utility/time_editor_icon'] = 60},
base_cost = {gold = 50},
},
-- buy_fast_loader = {
-- tooltip = 'A fast loader for 500 gold.',
-- what_you_get_sprite_buttons = {['item/fast-loader'] = 1},
-- base_cost = {gold = 500},
-- },
uranium_ore = {
tooltip = '10 green rocks for 800 gold.',
what_you_get_sprite_buttons = {['item/uranium-238'] = 10},
base_cost = {gold = 800},
},
}
function Public.initialise_main_shop()
local memory = Memory.get_crew_memory()
memory.mainshop_availability_bools = {
uranium_ore = true,
rail_signal = true,
artillery_shell = true,
artillery_remote = true,
extra_time = true,
new_boat_sloop_with_hold = false,
new_boat_cutter_with_hold = false,
new_boat_cutter = false,
buy_iron = false,
-- sell_iron = false,
-- buy_fast_loader = true,
-- sell_copper = false,
}
end
function Public.main_shop_try_purchase(name)
local memory = Memory.get_crew_memory()
local shop_data_1 = Public.main_shop_data_1
local shop_data_2 = Public.main_shop_data_2
local trade_data = shop_data_1[name] or shop_data_2[name]
if not trade_data then return end
local gold = memory.gold
local captain_index = memory.playerindex_captain
if not (gold and captain_index) then return end
local captain = game.players[captain_index]
if not Common.validate_player_and_character(captain) then return end
local captain_inv = captain.get_inventory(defines.inventory.character_main)
if not captain_inv then return end
local multiplier = Balance.main_shop_cost_multiplier()
local can_buy = true
-- local rate_limit_ok = not (memory.mainshop_rate_limit_ticker and memory.mainshop_rate_limit_ticker > 0)
local rate_limit_ok = true
local enough_gold = true
local enough_iron_plates = true
local enough_copper_plates = true
local iron_plates_got = nil
local copper_plates_got = nil
-- local able_to_buy_boats = memory.boat.state == Boats.enum_state.DOCKED --disabled for now
local able_to_buy_boats = false
-- local able_to_buy_boats = (memory.boat.state == Boats.enum_state.DOCKED or memory.boat.state == Boats.enum_state.APPROACHING) --problem with this if you buy whilst approaching, the original one no longer moves
for k, v in pairs(trade_data.base_cost) do
if k == 'gold' then
enough_gold = (gold >= v * multiplier)
elseif k == 'iron_plates' then
iron_plates_got = captain_inv.get_item_count('iron-plate')
enough_iron_plates = iron_plates_got >= v * multiplier
elseif k == 'copper_plates' then
copper_plates_got = captain_inv.get_item_count('copper-plate')
enough_copper_plates = copper_plates_got >= v * multiplier
end
end
can_buy = rate_limit_ok and enough_gold and enough_iron_plates and enough_copper_plates
if name == 'new_boat_sloop_with_hold' or name == 'new_boat_cutter_with_hold' or name == 'new_boat_cutter' then can_buy = can_buy and able_to_buy_boats end
-- potential TODO: prevent the captain from buying things whilst marooned?
if can_buy then
for k, v in pairs(trade_data.base_cost) do
if k == 'gold' then
memory.gold = memory.gold - v * multiplier
elseif k == 'iron_plates' then
captain_inv.remove{name="iron-plate", count=v * multiplier}
elseif k == 'copper_plates' then
captain_inv.remove{name="copper-plate", count=v * multiplier}
end
end
local force = game.forces[memory.force_name]
if not (force and force.valid) then return end
local gotamount
if name == 'uranium_ore' then
gotamount = trade_data.what_you_get_sprite_buttons['item/uranium-238']
Common.give(captain, {{name = 'uranium-238', count = gotamount}})
Common.notify_force_light(force,string.format('%s is buying green rocks...', captain.name))
elseif name == 'extra_time' then
local success = Crew.try_add_extra_time_at_sea(60 * 60)
if success then
Common.notify_force_light(force,string.format('%s is buying extra time at sea...', captain.name))
else
Common.notify_player(captain, string.format('Can\'t buy more time than this.', captain.name))
-- refund:
memory.gold = memory.gold + trade_data.base_cost.gold * multiplier
end
elseif name == 'rail_signal' then
gotamount = trade_data.what_you_get_sprite_buttons['item/rail-signal']
Common.give(captain, {{name = 'rail-signal', count = gotamount}})
Common.notify_force_light(force,string.format('%s is buying signals...', captain.name))
elseif name == 'artillery_shell' then
gotamount = trade_data.what_you_get_sprite_buttons['item/artillery-shell']
Common.give(captain, {{name = 'artillery-shell', count = gotamount}})
Common.notify_force_light(force,string.format('%s is buying cannon shells...', captain.name))
elseif name == 'artillery_remote' then
gotamount = trade_data.what_you_get_sprite_buttons['item/artillery-targeting-remote']
Common.give(captain, {{name = 'artillery-targeting-remote', count = gotamount}})
Common.notify_force_light(force,string.format('%s is buying an artillery targeting remote...', captain.name))
elseif name == 'new_boat_cutter' or name == 'new_boat_cutter_with_hold' or name == 'new_boat_sloop_with_hold' then
Dock.execute_boat_purchase()
Common.notify_force_light(force,string.format('[font=heading-1]%s bought a %s.[/font]', captain.name, Boats[Common.current_destination().static_params.boat_for_sale_type].Data.display_name))
elseif name == Upgrades.enum.MORE_POWER then
Upgrades.execute_upgade(Upgrades.enum.MORE_POWER)
Common.notify_force_light(force,string.format('[font=heading-1]%s upgraded the ship\'s power.[/font]', captain.name))
memory.mainshop_availability_bools[name] = false
elseif name == Upgrades.enum.EXTRA_HOLD then
Upgrades.execute_upgade(Upgrades.enum.EXTRA_HOLD)
Common.notify_force_light(force,string.format('[font=heading-1]%s upgraded the ship\'s hold.[/font]', captain.name))
memory.mainshop_availability_bools[name] = false
elseif name == Upgrades.enum.UNLOCK_MERCHANTS then
Upgrades.execute_upgade(Upgrades.enum.UNLOCK_MERCHANTS)
Common.notify_force_light(force,string.format('[font=heading-1]%s unlocked merchant ships.[/font]', captain.name))
memory.mainshop_availability_bools[name] = false
elseif name == Upgrades.enum.ROCKETS_FOR_SALE then
Upgrades.execute_upgade(Upgrades.enum.ROCKETS_FOR_SALE)
Common.notify_force_light(force,string.format('[font=heading-1]%s unlocked the sale of rockets at covered-up markets.[/font]', captain.name))
memory.mainshop_availability_bools[name] = false
elseif name == 'sell_iron' then
gotamount = trade_data.what_you_get_sprite_buttons['item/sulfur']
Common.give(captain, {{name = 'gold', count = gotamount}})
Common.notify_force_light(force,string.format('%s is selling iron...', captain.name))
elseif name == 'buy_iron' then
gotamount = trade_data.what_you_get_sprite_buttons['item/iron-plate']
Common.give_reward_items{{name = 'iron-plate', count = gotamount}}
Common.notify_force_light(force,string.format('%s is buying iron...', captain.name))
elseif name == 'buy_copper' then
gotamount = trade_data.what_you_get_sprite_buttons['item/copper-plate']
Common.give_reward_items{{name = 'copper-plate', count = gotamount}}
Common.notify_force_light(force,string.format('%s is buying copper...', captain.name))
-- elseif name == 'buy_fast_loader' then
-- gotamount = trade_data.what_you_get_sprite_buttons['item/fast-loader']
-- Common.give(captain, {{name = 'fast-loader', count = gotamount}})
-- Common.notify_force_light(force,string.format('%s bought a fast loader...', captain.name))
elseif name == 'sell_copper' then
gotamount = trade_data.what_you_get_sprite_buttons['item/sulfur']
Common.give(captain, {{name = 'gold', count = gotamount}})
Common.notify_force_light(force,string.format('%s is selling copper...', captain.name))
end
-- memory.mainshop_rate_limit_ticker = Common.mainshop_rate_limit_ticks
else
-- play sound?
if rate_limit_ok == false then
Common.notify_player(captain, 'Shop rate limit exceeded.')
end
if enough_gold == false then
Common.notify_player(captain, 'Not enough gold.')
end
if enough_iron_plates == false then
Common.notify_player(captain, 'Not enough iron plates.')
end
if enough_copper_plates == false then
Common.notify_player(captain, 'Not enough copper plates.')
end
if (name == 'new_boat_cutter' or name == 'new_boat_sloop_with_hold' or name == 'new_boat_cutter_with_hold') and (not able_to_buy_boats) then
Common.notify_player(captain, 'Not able to purchase ships right now.')
end
end
end
function Public.event_on_market_item_purchased(event)
local player_index, market, offer_index = event.player_index, event.market, event.offer_index
local player = game.players[player_index]
if not (market and market.valid and offer_index and Common.validate_player(player)) then return end
local crew_id = tonumber(string.sub(player.force.name, -3, -1)) or nil
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
local alloffers = market.get_market_items()
local this_offer = alloffers[offer_index]
local type = this_offer.offer.type
local price = this_offer.price
local inv = player.get_inventory(defines.inventory.character_main)
-- Here - check for BARTER vs CLASS PURCHASE vs STATIC
-- Class purchase is purchase for 'nothing'
-- Static is purchase via gold
-- Barter is otherwise
if type == 'nothing' then
local force = player.force
local destination = Common.current_destination()
-- check if they have a role already - renounce it if so
if memory.classes_table and memory.classes_table[player.index] then
Roles.try_renounce_class(player)
end
memory.classes_table[player.index] = destination.static_params.class_for_sale
if force and force.valid then
Common.notify_force_light(force,string.format('%s is now a %s. ([font=scenario-message-dialog]%s[/font])', player.name, Classes.display_form[memory.classes_table[player.index]], Classes.explanation[memory.classes_table[player.index]]))
end
if destination.dynamic_data and destination.dynamic_data.market_class_offer_rendering then
rendering.destroy(destination.dynamic_data.market_class_offer_rendering)
end
market.remove_market_item(offer_index)
else
if (price and price[1] and price[1].name and (price[1].name == 'pistol')) then
if not inv then return end
local flying_text_color = {r = 255, g = 255, b = 255}
local text1 = '[color=1,1,1]+' .. this_offer.offer.count .. '[/color] [item=' .. alloffers[offer_index].offer.item .. ']'
local text2 = '[color=' .. flying_text_color.r .. ',' .. flying_text_color.g .. ',' .. flying_text_color.b .. '](' .. inv.get_item_count(alloffers[offer_index].offer.item) .. ')[/color]'
Common.flying_text(player.surface, player.position, text1 .. ' [font=count-font]' .. text2 .. '[/font]')
else
if not inv then return end
local flying_text_color = {r = 255, g = 255, b = 255}
local text1 = '[color=1,1,1]+' .. this_offer.offer.count .. '[/color] [item=' .. alloffers[offer_index].offer.item .. ']'
local text2 = '[color=' .. flying_text_color.r .. ',' .. flying_text_color.g .. ',' .. flying_text_color.b .. '](' .. inv.get_item_count(this_offer.offer.item) .. ')[/color]'
Common.flying_text(player.surface, player.position, text1 .. ' [font=count-font]' .. text2 .. '[/font]')
alloffers[offer_index].offer.count = Math.max(Math.floor(alloffers[offer_index].offer.count * Balance.barter_decay_parameter()),1)
market.clear_market_items()
for _, offer in pairs(alloffers) do
market.add_market_item(offer)
end
end
if (price and price[1]) then
-- if (price and price[1] and price[1].name and ((price[1].name ~= 'coin' and price[1].name ~= 'pistol') or price[2])) then
if price[2] then
local fish = price[2].name
if fish == 'raw-fish' then fish = 'fish' end
Common.notify_force_light(player.force, player.name .. ' is trading away ' .. price[1].name .. ' and ' .. fish .. ' to get ' .. this_offer.offer.item .. '...')
else
Common.notify_force_light(player.force, player.name .. ' is trading away ' .. price[1].name .. ' to get ' .. this_offer.offer.item .. '...')
end
end
end
end
return Public

BIN
maps/pirates/structures/.DS_Store vendored Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
local Public = {}
Public.display_name = 'merchant_1'
Public.tile_areas = {
{{-30,-6},{-5,5}},
{{-5,-5},{-4,4}},
{{-4,-4},{-3,3}},
{{-3,-3},{-2,2}},
{{-2,-2},{-1,1}},
{{-1,-1},{0,0}},
}
Public.width = 30
Public.height = 11
Public.entities = {
static = {
pos = { x = -17, y = -0.5},
bp_str = [[0eNqdmd1uozAUhN/F16TCNrYhr7KqVvmxskgEIkK2G1V594W0aquGwWd6iQpfx0dzju3Jq9o2l3jq63ZQ61d1bjen1dCtDn29n57/qbVxmbqqtda3TNW7rj2r9a/xxfrQbprpleF6imqt6iEeVabazXF6eum6fWxXuz/xPKjpw3YfR5a+PWcqtkM91PGNc3+4/m4vx23sxxfmCZk6defxo659F6Wf3lU9udste8CYD8y2PqxiE3dDX+9Wp66JjyxzJ9lRZRvrw59td+knbVVmTOb98wzeClXmyyoLEmPmMU6IsctqvBBjljFBiHHLmFKIKZYx1QfmfNw0TcoK7kulv9nBZLqc84LOhUrDslIttb5PcIyQUyU4UpOXCY7U5TrR01rqc51oOy11uk50jJZ6XSd6RpecTT94Mz6dxtasTyt21WDcGKnhdaLFjXjYJ5rcUONeu/l5PzV4Fuxc7cxnL5yHGBsoNCRKJ+6FxLAw4l5ITAvjv6ysa+PqZbTfAgYtLAgLVCU4pZBTJjhisyemoBWbPTEGrdTsJjEGrXS+m8QYtNIBbxJj0EpdbRJj0EpdbRIDwXryZGUBJ5CcAnBKdvYiQZWsXd2yniKXYYoERnPDA2EMhwG1KT79vOmHumlif10Nl76PC4dYf99A93U/bhn3v/o5MntQd0ChIzkecDx55ER6AslBekryyIn0VCQH6HE5eXRFHE1ywLqcEe5qLsGxJAetqxByioQeR3KQHi/k+IQedlwHwClJTgk4FdlfQI/Pyb5AHNbPiGO4XQiUx1tuF0IY1s1oVY7bhpAcz2dPOn+8jPgKXEY86/IKCGVdPt2rZ0E/DFnuvG/rHqsX8rlVh/yHV+TZ/4JqGzR7UAPFDYbOGEB1g/3B5fbRUGP9xtrORwOhIK+3UCvZQqh45KUUyglsmowyTbpVEKhis1oUj+ZsWotAms1rEciwiS0CWTZQRaCCTVQRyLGRKgJ5NlNFoECHqohU0qkqItEBIyJVOZ2rIpKms0pEMnRYiUiWDgERqaBTQERydF6GSJ4OzBAp0IkZIpV0ZIZIFZ2Zocg/z+nUDKI0nZvdUc/Z26+26y+/AWfqb+zP909MqYtQmVBYX1SmvN3+A/EBuBE=]],
},}
Public.market_pos = {x = -8.5, y = 0.5}
Public.landingtrack = {
offset = {x = -24, y = -10.5},
bp = [[0eNqV3M1u20YYRuF74VoB8g7J+dGtFFm4tpAKcCTDVn+CwPdeu2aLblrwWQo4psg5M5vz0fox/fz46+np+Xy5Tccf08vl7unT7frp6/P54f3zH9NxLofp+3QseT1M5/vr5WU6/vQGnr9e7h7fkdv3p9N0nM6307fpMF3uvr1/+v16fThdPt3/cnq5Te9/eHk4vV0rr18O0+38ePq4yNP15Xw7Xy/bN3180efXf67y9m33z6fb6e0K/wFH4CLwLPBC91yJbkR3ogct304zs2icReMsGmfROIvGmTTOpHEmjTNpnEnjIhoX0biIxkU0LqJxIY0LaVxI40IaF9K4isZVNK6icRWNq2hcSeNKGlfSuJLGlTRW0VhFYxWNVTRW0VhJYyWNlTRW0lhJYxONTTQ20dhEYxONjTQ20thIYyONjTR20dhFYxeNXTR20dhJYyeNnTR20thJ4xCNQzQO0ThE4xCNgzQO0jhI4yCNgzTms3jc6BBdiJ6JXuy+q+HN8G74sFXcqygkNCQ0JDQkNCQ0JjQmNCY0JjQmlNJOqO2E4k6o7oTyTqzvxAJPrPDEEk+s8YQiT6jyhDJPqPOEQk+s9MRST6z1xGJPrPaEck+o94SCT6j4hJJPrPnEok+s+sSyT6z7hMJPqPyE0k+o/YTiT6z+xPJPrP/EAlCsAIUSUKgBhSJQqAKFMlCsA8VCUKwExVJQrAWFYlCoBoVyUKgHhYJQrAjFklCsCcWiUKwKhbJQqAuFwlCoDIXS0Eav9pSIV8Ob4d3wYYr2+qf6FMpPof4UClChArXRK9HV1sRuJXYvwZtphnfDh/nf+y4FBbRCAa1QQCsU0AoFtI1eia5EN1tBe8zYc8YeNPakwUfthg/bXHt3LnXFQl2xUFcs1BULdcWNXomuRDeiu623LWFsDWOLGFvF2DLG1jG4kMN27t5jYa/p2Xt69qKevalnr+oVOkSFDlGhQ1ToEH3Qw+yYnpifmKCYoZiimKOYpJilmKbdJ5TifKE4XyjOF4rzheL8Rq9EV6Ib0Z3oYXZQptmM6Yz5jAmNGY0pjTmNSY1Z3X2gadxSaNxSaNxSaNyy0SvRlehGdCd6mB2UaTZjOmM+Y0JjRmNKY05jUncfUZpxFZpxFZpxbfRKdCW6Ed2JtvXefYpWO0WrnaLVTtFqp2i1U2QzzmIzzmIzzkKzv0Kzv41eia5EN6JtTQbRuzd6tY1ebaNX2+jVNnq1jW6z32Kz30Jjy41eia5E2313ogfRu/dis73YbC8224vN9mKzvWhj60JD0Y22azeiO9GD6N3bpdt26bZdum2XbtvF5taFBpcb3YjuRA+idxsdZnSY0WFGbfw704huozvRg+i9i/43HsOL4Xv/UZpGOhs9iN69LrF1sfHSTCF9o3ffunX3+f8i4JfDx28vHP/1Sw6H6bfT88tfFyg9SxulLXNdRumvr38Cd8bxwA==]],
}
return Public

View File

@@ -0,0 +1,9 @@
local Data = require 'maps.pirates.structures.boats.merchant_1.data'
local Public = {}
Public.Data = require 'maps.pirates.structures.boats.merchant_1.data'
return Public

View File

@@ -0,0 +1,45 @@
local Public = {}
Public.display_name = 'raft'
Public.tile_areas = {
{{-9,-4},{0,5}},
}
Public.width = 9
Public.height = 9
Public.spawn_point = {x = -4, y = 0.5}
Public.right_gate_tile_areas = {
{{-78,18},{-72,19}},
{{-31,18},{-25,19}},
}
Public.left_gate_tile_areas = {
{{-78,-18},{-72,-17}},
{{-31,-18},{-25,-17}},
}
Public.leftmost_gate_position = -78
Public.rightmost_gate_position = -25
Public.areas_infront = {
{{0,-4},{1,5}},
}
Public.areas_behind = {
{{-10,-4},{-9,5}},
}
Public.areas_offright = {
{{-9,5},{0,6}},
}
Public.areas_offleft = {
{{-9,-5},{0,-4}},
}
Public.entities = {
inaccessible = {
pos = { x = -9, y = 0},
bp_str = [[0eNqV08sOwiAQBdB/mTU1ltIXv2KMqXZSSdqhKfhoDP9uQRcmsmF5k7mHWQwvOI83nBdFFuQLDHVzZnU2LKr3+QkyZ7CCbB0DddFkQB62MTVQN/oBu84IEpTFCRhQN/n00LpHyi5XNBZ8kXr0kjsyQLLKKvw4Iawnuk1nXMJTMYHBrM1W0vRdab8rw1L5rnSO/TE8kdnHmSKRKeKMSGR4nCkTmTLOVImMiDN1IlPHmSaRqeJMm8g0ntluMVyt/PkBDO64mFDgTS7qlteiqETLG+fekGkHZg==]],
},
}
Public.landingtrack = {
offset = {x = 4, y = -7},
bp = [[0eNqV2M1qwkAYheF7mXWE+eZ/civFhdVBBjQJSSwVyb3XVBddtMV3JYHjBJ85m+NNvZ8uZRhrN6v2pqZuN2zmfnMc62F9/lStmEZd7x9+aVTd992k2rd7sB673WmNzNehqFbVuZxVo7rdeX265/ZjmYtav9QdynrOsm3UXE/lccDQT3Wuffd8y+b5Gr38dsafcWFxA0+neQvz7tW8MBxhOMJwBOIIxBGIoxmOZjia4WiIoyGOZjgZ2WREk5FMZjCZuWTGkhBLQiwJsSTGkhhLYiwRsUTEEhFLZCyRsUTGEhBLQCwBsQTGEhhLYCwesXjE4hGLZyyesXjG4hCLQywOsTjG4hiLYywWsVjEYhHLI21Rmv1Kj9IBpSNKJ5TO7HbgZbLbFHadwu7z5dqyWcJWCRslBtXWoNoaVFuDamtQbQ2qrUG1Nay2htUWbkY4GeliZJuITSK2iFBtBdVWUG0F1VZQbQXVVlBthdVWWG3pmod79Z/abpvHv0btj/+gGvVRxun7AJPExWyiDc5pa5blC6gg570=]],
}
return Public

View File

@@ -0,0 +1,9 @@
local Data = require 'maps.pirates.structures.boats.raft.data'
local Public = {}
Public.Data = require 'maps.pirates.structures.boats.raft.data'
return Public

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,9 @@
local Data = require 'maps.pirates.structures.boats.sloop.data'
local Public = {}
Public.Data = require 'maps.pirates.structures.boats.sloop.data'
return Public

Binary file not shown.

View File

@@ -0,0 +1,19 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Public = {}
local enum = {
MATTISSO = 'MATTISSO',
ROC = 'ROC',
}
Public[enum.MATTISSO] = require 'maps.pirates.structures.island_structures.mattisso.mattisso'
Public[enum.ROC] = require 'maps.pirates.structures.island_structures.roc.roc'
Public.enum = enum
return Public

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,43 @@
local Data = require 'maps.pirates.structures.island_structures.mattisso.data'
local Public = {}
Public.refuel_station = {}
Public.refuel_station.Data = Data.refuel_station
Public.small_crashed_ship = {}
Public.small_crashed_ship.Data = Data.small_crashed_ship
Public.small_basic_factory = {}
Public.small_basic_factory.Data = Data.small_basic_factory
Public.small_early_enemy_outpost = {}
Public.small_early_enemy_outpost.Data = Data.small_early_enemy_outpost
Public.small_nuclear_powerplant = {}
Public.small_nuclear_powerplant.Data = Data.small_nuclear_powerplant
Public.small_market_outpost = {}
Public.small_market_outpost.Data = Data.small_market_outpost
-- second lot:
Public.small_abandoned_refinery = {}
Public.small_abandoned_refinery.Data = Data.small_abandoned_refinery
Public.small_roboport_base = {}
Public.small_roboport_base.Data = Data.small_roboport_base
Public.small_solar_base = {}
Public.small_solar_base.Data = Data.small_solar_base
Public.small_mining_base = {}
Public.small_mining_base.Data = Data.small_mining_base
Public.small_primitive_mining_base = {}
Public.small_primitive_mining_base.Data = Data.small_primitive_mining_base
Public.small_oilrig_base = {}
Public.small_oilrig_base.Data = Data.small_oilrig_base
-- third lot:
Public.small_radioactive_lab = {}
Public.small_radioactive_lab.Data = Data.small_radioactive_lab
Public.small_radioactive_centrifuge = {}
Public.small_radioactive_centrifuge.Data = Data.small_radioactive_centrifuge
Public.small_radioactive_reactor = {}
Public.small_radioactive_reactor.Data = Data.small_radioactive_reactor
Public.uranium_miners = {}
Public.uranium_miners.Data = Data.uranium_miners
return Public

View File

@@ -0,0 +1,152 @@
local Public = {}
local CoreData = require 'maps.pirates.coredata'
Public.shelter1 = {
name = 'shelter1',
width = 18,
height = 18,
components = {
{
type = 'static',
force = 'environment',
offset = {x = 0, y = 0},
bp_string = [[0eNqV1t1qhDAQBeB3metYzL/6KqUUtxuWgEbRbFtZfPca24tCOyRztSskHzlh4OQBl+Hu5sWHCN0D1tDPVZyq2+Kv6fsTOm4YbOlnZ+DfprBC93ws9LfQD2lJ3GYHHfjoRmAQ+jF9rXEKrvrohwHStnB1SdpfGLgQffTuWzk/ttdwHy9uORb8t5/BPK3Hlin8HKiyT/o8Uvqz7+wPI8oYk2FkGaMyjCpjdIbRZYzMMKaIySm2SMlFaoqU3P22RUpuZnhdxORmhlNHWCOOIDoGcSTtdjBG0RgslSamkohjiI5CHEuLhTENjcFStbRUyGlETWOQ0whOCoUpgqRgkSQtEjLFQtEYZIqFJmXCFENSsEiW1nVYYza0m8GYllaZWPHWtMrEGE6rTIwRpMrEFEmqTExRpMrEFNoAY4ohNeapHO+/853Y/Xp1Mnh3y3puEA1XthVWWqt5rfb9C+jHZns=]],
},
{
type = 'tiles',
tile_name = CoreData.world_concrete_tile,
offset = {x = 0, y = 0},
bp_string = [[0eNqV2t1qGkEYBuB7mWOF+Z/UWyk5sMkSFswquv0JwXtvTErpSUufoyCMa9CHj+H93tfw5fB1Op3nZQ2713BZ9qftetw+nefH2+sfYZf6Jrzc/lw3YX44Lpew+/x2cH5a9ofbkfXlNIVdmNfpOWzCsn++vbqsx2Xaft8fDuH2tuVxuj3per8J63yYPh5xOl7mdT4uvz5ne/f+Odu76++nvH3aw3lap7dn/PX4sOPdjjc7Xu14sePZjic6Hum0Pdv+cftW7Cu339Ow/K/EYc6HOR/mfJjzYc6HOR/mfJjzQc4HOR/kfJDzQc4HOR/kfJDzbs67Oe/mvJvzbs67Oe/mvJvzTs47Oe/kvJPzTs47Oe/kvJPzZs6bOW/mvJnzZs6bOW/mvJnzRs4bOW/kvJHzRs4bOW/kvJHzas6rOa/mvJrzas6rOa/mvJrzSs4rOa/kvJLzSs4rOa/kvJLzYs6LOS/mvJjzYs6LOS/mvJjzQs4LOS/kvJDzQs4LOS/kvJDzbM6zOc/mPJvzbM6zOc/mPJvzTM4zOc/kPJPzTM4zOc/kPJPzZM6TOU/mPJnzZM6TOU/mPJnzRM4TOU/kPJHzRM4TOU/kPInzSMwjKY+EPJLxSMQjCY8EPJLvKLyj6I6CO4rtKLSjyI4CO4prG982vW142+y20W2T2wa3zW0a2zS1aWjTzKaRTRObBjbNa7t+2+3bLt9297art9287eJt9266dtOtmy7ddOemKzfduOnCTfdti08sPbHwxLITi04sObHgxHITik0oNaHQhDITikwoMaHAhPISi78t/bbw27Jvi74t+bbg23Jvir0p9abQmzJvirwp8abAm/JuW1/a9tKWl7a7tNWlbS5tcWl7S1pb0taSlpa0s6SVJW0saWFJ+0qrn1j7xMon1j2x6ok1T6x4Yr0Tqp1Q64RKJ9Q5ocoJNU6ocEJ9E6sPWnvQyoPWHbTqoDUHrThovUGqDVJrkEqD1BmkyiA1Bqkw+I++4P3mozG++6N/vgnfpvPl/e35LtXxKY8yRkuxXq8/AdUS1bk=]],
},
},
}
Public.shelter2 = {
name = 'shelter2',
width = 44,
height = 44,
components = {
{
type = 'tiles',
tile_name = 'red-desert-2',
offset = {x = 0, y = 0},
bp_string = [[0eNqd3dFu4zYahuF78XEC+JVkSZxbWfRg2hqFgUwSJOnuFkXufZPW07Mu/PSomIL0aERJPwjye/j74ceHX8/PL5fHt8OX3w+vj1+f79+e7n95ufz8+ef/Hr4s093ht8//vN8dLj89Pb4evvzro+Hll8evD59N3n57Ph++HC5v52+Hu8Pj12+ff3p9e3o83//n68PD4bPb48/nj1/q/Ye7w9vl4fznTzw/vV7eLk+P17/nfuqPv+j+9P7Xz3z8dT+9nN/OHz/y9+0XbD9j+wnbZ+2P1hx/HS8e783Nt/74563Zsf2G7Vdsf8L2+u+dsf2E7bP2R2uOv44Xj/cGbz2OLD44tz6Xjes4HbHDwPY7ttd/wIrtT9h+wfYztp90wKw9Di/+Ol483hu89Tiy+ODgc4mP/c1v1X59CibtkHY4Ygf9J+zYfsP2K7Y/YfsF28/YnkfY2uPw4q/jxeO9wVuPI4sPDj6X+NjjW6Vv7e2fhe36lM3aYdIOfElH7DCw/Y7tN2y/YvsTtl+wvQ4xj7C1x+HFX8eLx3uDtx5HFh8cfC7xsce3St9a/Szc/t1Zr0/loh1m7cCXlHY4YoeB7Xdsv2H7FdufsL2OsQ4xj7C1x+HFX8eLx3uDtx5HFh8cfC7xsce3St9a/Szod+f2D9vp+hSftMOiHfiSJu2Qdjhih4Htd2y/YfsV2+sg6xjrEPMIW3scXvx1vHi8N3jrcWTxwcHnEh97fKv0rdXPgn539MN2+5dzuT71q3Y4aQe+pFk7TNoh7XDEDgPb79h+w/Y6yjrIOsY6xDzC1h6HF38dLx7vDd56HFl8cPC5xMce3yp9a/WzoN8d/bDpl/P2T/N8fUs27bBqB76kRTvM2mHSDmmHI3YY2H7H9jrMOso6yDrGOsQ8wtYehxd/HS8e7w3eehxZfHDwucTHHt8qfWv1s6DfHf2w6ZdTP823f/un61u1a4dNO/AlnbTDoh1m7TBph7TDETsMbK/jrMOso6yDrGOsQ8wjbO1xePHX8eLx3uCtx5HFBwefS3zs8a3St1Y/C/rd0Q+bfjn106zf/tuLS1q+0vKVlq+0fKXlKy1faflKy1davsLyFZavsHyF5QtjJGGMJIyRhDGSMEaSxUiyGEkWI8liJFmM5NocRxYfHHwu8bHHt0rfWv0s6HdHP2z65dRPs377by8u3xM2Qzvs2oEvadUOJ+2waIdZO0zaIe1wxA460DrOOsw6yjrIOsY6xDzC1h6HF38dLx7vDd56HFl8cPC5xMce3yp9a/WzoN8d/bDpl1M/zfrt1+Jyc/UaWB4HVseBxXFgbRxYGgdWxoGFcWBdHFgWNYiKOVSMoWIKFUOomEHFCComUDGAivlTi59a+tTCp5Y9teipJU8teGq5U4udWup0WAUcVgCH1b9h5W9Y9RtW/IbVvmGlb1jl+x4cPVr7myvljpVyx0q5Y6XcsVLuWCl3rJSazdZotiazMZiNuWyMZWMqG0PZmMnGSDYmsjGQbXlsi2NbGtvC2JbFtii2JbEtiG05bIthYwobQ9i7VcrdKuVulXK3SrlbpdytUu7/pFLeXPg2LKwbFtYNC+uGhXXDwrphYd2wsKoloJSASgIKCaAjgIwAKgKICKAhgIQACgIICKAfYHyA6QGGB5gdYHSAyQEGB5gbYGyAqQGIBqAZgGTAZoV1s8K6WWHdrLBuVlg3K6ybFdYVC+uKhXXFwrpiYV2xsK5YWJWmUJlCYQp1KZSlQJUCUQo0KZCkQJECQQr0KJCjQI3CMAqzKIyiMInCIApzKIyhMIXCEAozKJCgQIECAQr0J1YrrKsV1tUK62qFdbXCulph/U4khO2P1l6v5+Z/7gkL8QkLscIl6pYoW6JqiaIlapYgWYJiCYIl6JUgV4JaCWIlaJUgVWJSiUEl5pQYU2JKiSElZpQYUWJCiQEl6JMgT4I6CeIkaJOcrBCfrBCfrBCfrBCf/kkhvrmuLli3F6zbC9btBev2gnVbkRo1apSoUaFGgRr1aZSnQZ0GcRq0aZCmQZkGYRp0aZClQZXGUBozaYykMZHGQBrzaIyjMY3GMBqzaJCiQYkGIRp0aJChQYVmsbq9WN1erG4vVrcXq9sz1u0Z6/aMdXvGuq1ekHJBqgUpFqRWkFJBKgUpFIROEDJBqAQhEoRGEBJBKAQhEIQ+kPFApgMZDmQ2kNFAJgMZDGQukLFApgIhCoQmEJJAKAIhCIQeEHJAs9Xt2er2bHV7tro9Yd2esG5PWLdVVlJYSV0lZZVUVVJUSU0lJZVUVEJQCT0l5JRQU0JMCS0lpJRQUkJIyRwlY5RMUTJEyQwlI5RMUDJAyfwk45NQT0I8Ce0kpJNQTkI4Cd0kZJMmq9uT1e3J6nZYt8O6nRobSmyosKHAhvoaymuorqG4htoaSmugrIGwBroayGqgqoGoBpoaSGqgqGGghnkaxmmYpmGYhlkaRmmYpGGQhjkayGigooGIBhoaSGigoIGABvoZVrezuh3V7aOV7aNVbYSxkMVCFAtJLASxkMNCDAspLISwkMEyBMsILAOwjL8y/MroK4OvjL0y9IrIKwKviLsi7IqoK4KuiLki5IqIKwKujLcy3MpoK4OtjLUy1MpIKwOtjLM6Ujk+UjXGSTTOoXEKjTNonEDj/Bmnzzh7xskzzp1x6owzZ5s427zZps02a7ZJs82ZbcpsM2abMNN8mabLNFumyTLNlWmqTDNlmijTPJmmyTZLtkmyzZFtimwzZJsg2/zYpsc2O7bJsc2NcSkaV6JxIRrXoXEZGlehcREa16BxCRpXoHEBGtefbfnZVp9t8dnWnm3p2VaebeHZ1p1t2ZlWnWnRmdacacmZVpxpwZnWm2m5mVababHZ1pptqdlWmm2h2daZbZnZVpltkdnWmG2J2VaYcUM37ufG7dy4mxs3c+NebtzKjTu5cSM37uPGbdy4i9s2cdsebtvCbTu4bQO37d+27du2e9s2b9Pebdq6TTu3aeM27dumbdu0a5s2bdOebdqybTu2bcO27de27dq2W9s2a9tebduqbTu1baO27dPGWDSmojEUjZlojERjIhoD0ZiHxjg0pqExDI1ZaItCWxLagtCWg7YYtKWgLQRtGWiLQFMCmgLQlH+m+DOlnyn8TNlnij5T8pmCz5Z7ttizpZ4t9GyZZ4s8W+LZAs+Wd7a4s6WdEQtDKwypMJTCEApDJwyZMFTCEAlDIwyJMBPCDAgzH8x4MNPBDAczG8xoMJPBCAYjF4xYMFLBCAUjE4xIMBLBCAQjD8w4MNPADAMzC8woMJPADAIzB8wYMFPAkLlG5RqRazSukbhG4RqBa/StkbdG3Rpxa7OtjbY22dpga3OtjbU21dpQazOtibQm0ZpAa/KsibMmzZowa7KsibImydoga3OsjbE2xdoQazOsjbA2wdoAa/Or8cAlPG8Jj1vC05bwsCU8awmPWsKTlvCgJTxnCY9ZslOW7JAlO2PJjliyE5bsgCU7X8mOV7LTlehwJTpbiY5WopOV6GAlOleJjlWiU5XoUCU6U8mOVLITlexAJTtPyY5TstOU7DAlO0vJjlKyk5TwKF88yRcP8sVzfPEYXzzFFw/xxTN88QhfPMHXDvC183vt+F47vdcO77Wze+3oXju51w7upXN76dheOrWXDu2lM3vpyF46sZcO7KXzeum4Xjut1w7rtbN67aheO6nXDuq1c3rtmF47pXdYTRtW04bVtGE1bVhNG1bThtW0YTVtWE0bVtMG1bRBNW1QTRtU0wbVtEE1bVBNG1TTBtW0ITVtSE0bUtOG1LQhNW1ITRtS04bUtCE1bUhNG1TTBtW0QTVtUE0bVNMG1bRBNW1QTRsWIEV0KFSHQnYodIdCeCiUh0J6KLSHQnwo04cyfijzhzKAKBOIMoIoM4gyhChTiCKGKHKIIogokogiiiiyiCKMKNKIIo4o8ogykCgTiTKSKDOJMpQoU4kylihziVKBRwkeNXgU4VGFRxkedXgU4lGJByketHgQ40GNBzke9HgQ5EGRB0keM3kM5TGVx1gec3kM5jGZx2ges3kM50GdB3ke9HkQ6EGhB4keNHoQ6UFfJgRmQmEmJGZCYyZEZkJlJmRmMmcmg2YyaSajZjJrJsNmMm0m42YybyYCZyJxJiJnInMmQmcidSZiZyJ3JoJnInkmo2cyeybDZzJ9JuNnMn8mA2hC3iT0TULgJBROQuIkNE5C5CRTTjLmJHNOMugkk04y6iSzTjLsJNNOIu4k8k4i8CQSTyLyJDJPIvQkUk8i9iRyTzL4JJNPMvoks08y/CTTT0L+IvQvQgAjFDBCAiM0MDIEI1MwMgYjczAyCCOTMDIKI7MwMgwj0jAiDiPyMCIQIxIxIhIjMjEiFCNSMSIWI3MxMhgjkzEyGiOzMULuIPQOQvAgFA9C8iAzDzL0IFMPMvYgcw8y+CCTDzL6ILMPIvwg0g8i/iDyDyIAIRIQIgIhMhAiBCFSEDIGIXMQMgghkxDCtHoYVw/z6mFgPUusZ5H1LLOehdaz1HoWW89y61lwPUuuR9H1KLsehdej9HoUX4/y61GAPUqwRxH2KMOehdizFHsWYw/TwGEcOMwDZ4HgLBGcRYKzTHAWCs5SwVksOMsFZ8HgKBkcRYOjbHAUDo7SwVE8OMoHRwHhKCEcRYSzjHAWEg7jkFkeMgtEZonILBKZZSKzUGSWisxikVkuMgpGRsnIKBoZZSOjcGSUjozikVE+MgpIRgnJLICVJbCyCFaWwcpCWFkKK4thZTmsKIgVJbGiKFaUxYrCWFEaK4pjRXmsybISk2UlJstKTJaVmCwrMVFWYqKsxERZiYmyEtP/yUr8cHe4vJ2/ffy/Hx9+PT+/XB7fDneHf59fXv/oP+0t25i2edtOHZf39/8BhLbmiQ==]]
},
{
type = 'tiles',
tile_name = CoreData.world_concrete_tile,
offset = {x = 0, y = 0},
bp_string = [[0eNqd3c1uG0cQhdF3mTUJVDX7b/QqgReyNTEIUJRA0UkMQ+8eypGzCxCdlWHYTYKl4adC9b23fiyfT9+258vxfF3ufiwv5/vn/fVp//VyfHj7+1/LXS275fvbH6+75fjl6fyy3P12+4/Hr+f709t/uX5/3pa75XjdHpfdcr5/fPvby/XpvO3/vD+dlrdj54ft9kr5+mm3XI+n7Z+XeH56OV6PT+f399mX/PlG+8Prvy9z2X4/nreH/e1tv1y263Z7sf8+V/Bc2rmwY/huH/5wgcUMLGZgMcOKGVbMoGLmasX8dU7fL+1c2DF8tw9/uInFnFjMicWcVsxpxZxWzIHFHFjMgcUcVsxhxRxWzI7F7FjMjsXsVsxuxexWzIbFbFjMhsVsVsxmxWxWzIrFrFjMisWsVsxqxaxWzAMW84DFPGAxD1bMgxXzYMUs7x+OD6YeDDy44rmJ5wae63iu4bmK5w54jp8YO4ePC74bfjisJf7o8EnBBxO/B/i1w2+5UuXjGEsFZyo4U8GZCM5EcCaCMxGcieBMBCcOuhIHXYmDrrRBV9qgK23Q9X4Ma4k/OnxS8MHE7wF+7fBbrlT5OMZCwRkKzlBwBoIzEJyB4AwEZyA4A8GJQ+3EoXbiUDttqJ021E4caoeBMwycYeAMA2cYOMPAGQbOQHCGgXNFbq6IzRWpuRo0V2PmashcjZirAXM1XuK1Fd5a4aWV3VnZlZXdWK0EypU4uRImV6LkSpBciZErIXI1Qq4GyImAnAjIiYCcBshpgJwGyGmAnAbIaYDEq2i8icaLaLuHtmtou4WeBMhJgJwEyEmAnATISYCcBMhpgJwGyIGAHAjIgYAcBshhgBwGyGGAHAbIYYBEeQmqS1BcYtoSk5aYsmQQIAcBchAgBwFyECAHAXIQIIcBchggOwKyIyA7ArIbILsBshsguwGyGyC7ARIlY6gYQ8GY6cVMLmZqsU6A7ATIToDsBMhOgOwEyE6A7AbIboBsCMiGgGwIyGaAbAbIZoBsBshmgGwGSJSBogoURaCmATUJqClAGwGyESAbAbIRIBsBshEgGwGyGSCbAbIiICsCsiIgqwGyGiCrAbIaIKsBshogUdqNym4Udpuu22TdpuquBMhKgKwEyEqArATISoCsBMhqgKwGyF8ifD0Xdi5XPDfx3MBzHc81PFfx3AHPFTyHz0vi84KPCz4t+LDgs4KPCj4p+KDoc0LH7CGx97IPZlW0H5k9H/Yw2pNvXzP7TiNBEFjIR8Qx0h9/2eDvNvxVir+5sVH4cF9SsA8q2AcV7IMK9kEF+6CCfVDBPqhgH1SwD1K/pdot1W2JZkv0WqLVEp2WaLREnyXaLNFliSZL81iaxdIclmawNH+l2SvNXWnmSvNWmrUSnZVorCzWBxXrg4r1QcX6oGJ9ULE+qFgfVKwPKtYHJfZBiX1QYh+U2Acl9kGJfVBiH5TYByX2QWyfVhOgegDRAogOQDQAov8P7X/o/kPzH3r/0Ppnzj8z/pnvz2x/5voz0595/szyZ44/M/yh3w990tYHpfVBaX1QWh+U1gel9UFpfVBaH5TUB4W1QWFdUFgTFNYDhbVAYR1QWAMU1v+EtT+YgYAJCJh/YOkHln1gyQeWe2CpB5Z5YIkHlndgaQeUdUBJB5RzQCkHlHFACQeUb0DpBpRtQMkGlmtgqQZBXU5QkxPU4wS1OEEdTlCDE9TfBLU3Qd0NDnlwxoMjHpzw4IAH5zs43sHpDg53cLaDox2c7Nhgx+Y6NtaxqY4NdWymYyMdm+jYQIfmOTTOoWkODXNolkOjHJrk0CCH5jg0xrEpjg1xbIZjIxyb4NgAx+Y3Nr6x6Y0Nb2x2g1IeVPKgkAd1PCjjQRUPinhQw4MSHlTwoIAH9Tsm3zH1jol3TLtj0h1T7phwx3Q7Jtsh1Q6JdkizQ5IdUuyQYIf0OiTXIbUOiXVMq2NSHVPqmFDHdDom0zGVjol0TKNjEh1T6KBxB307aNsx146ZdsyzY5Ydc+yYYcf8OmbXMbcOmXXIq0NWHXLqkFGHfDpk0yGXDpl0yKNjFh1z6KC1H539aOw3X7/Z+s3Vb6Z+8/Sbpd8c/WboNz8/2fnJzU9mfvLyk5WfnPxk5CcfP9n4ycVvJn7z8GMIFGZAYQSUJUBZAJTlP1n8k6U/WfiTZT9Z9JMlP1HwE+U+UewTpT5R6BNlPlHkEyU+UeAT5T1Z3JOlPWFcKKaFYlioZYVaVKglhVpQqOWEWkyopYRaSKhlhFJEKCWEUkAo5YNSPCilg1I4KGWDUjQoJYNaMKjlgmKwPObKY6y8pcpbqLxlylukvCXKW6C85clbnLylyVOYPGXJU5Q8JclTkDzlyFOMPKXIU4g8ZchbhLwlyOMKItxAhAuIbP+QrR+y7UO2fMh2D9nqIds8ZIuHbO8QrR2irUO0dIh2DtHKIdo4RAuHaN8QrRuibUO2bMh2DeGyStxViasqbVOlLaq0PZW2ptK2VNqSSttRaSsqbUMlLaik/ZS0npK2U9JyStpNSaspaTMlLaakvZS2ltK2Uuq6c912rsvOcdc5rjrHTee46Bz3nOOac9xyjkvOcce5rTi3Dee24Nz2m9t6c9tubsvNbbe5rTa3zea42Bz3mqe6BdUuqH5BNAyiYxAtg+gZRNMgugbRNoi+QTQOmnPQrIPmHTTzoLkHzT5o/kEzEJqD0CyE6CFEE6H5UNKMKGlOlCQrSpIXJcmMkqZvThM4pymckyTOSRrnJJFzmjoyTR6Zpo9MEkgmKSSTJJJp2qo0cVWauipJXpWkr0oSWKUpM9KkGWnajCRxRpI6I0mekXavm3axm3azm3S1m3S3m3S5m3YrlHYtlHYvlHQxlHQzlHQ1lDZTThsqp02Vk8bKSXPlpMFysTlUsTlUsTlUoTlUoTlU+R9zqE+75XjdHm//9vn0bXu+HM/XZbf8sV1efr5OmVnHWsZhjJZRX1//Bgu6MZo=]],
},
{
type = 'static',
force = 'environment',
offset = {x = 0, y = 0},
bp_string = [[0eNqVmtFq20AQRf9ln+Wg1e5qtf6VEorTiGJwZBM7bUPwv9dOSlqoLzPnKQisw155dD2ZO2/hYfcyH563yyms38Jx2RxWp/3q+/P28Xr9K6zz0IXX659zF7bf9ssxrL9cPrj9vmx214+cXg9zWIftaX4KXVg2T9er42m/zKufm90uXG9bHucLKZ7vuzAvp+1pO39Q3i9evy4vTw/z8+UDt+7vwmF/vNyyX/4caDXclfcjrYb+rpzP3X+cAXJiu81JLo6JyQyjVBWqarrNGSmn3uZU+HQEZoIYoapRVeNtTuwpqAhQhMIUZ4AcJSxRYVmAMgUlASpQmeKMkKOE+Sp6FftPUhSkyUmKJslZ15MFGpx13UyQ06VHE+S06WqCnJWdTZCzsosJwl49CBA2a3UiZ20nE0T9WnEa5IgnlHx1bepKvrI2v/rkq2qzFpOvqM2XI/lq2nxbk6+kTftIvoo2/Sz5Ctp22OQraNv0U8OmLzq93FOS6jwjfEiKM9CHrZQlqky0ezlTkGg/c4HSFGeEHCWsUmGi38u4BxENaG5QmeCUHnKEsBKpMNHvlYGCRANaElSmOBlylDBv+/HpaeLHtTjbjzhZIG9VNwvkrerRAnnduhqg0WvW2QJ567pYIG9dJwvkdevBAmG3ViDq1orjdGvzCTm7EPMBOZsQ86t3erVVi9Xp1dbLUZ0NiPW2VmcDYvlQdTq1ZUPVOdOzDLZSp1YcatSKQ31acSbororToN0LztRDb1WcCM1ecahFKw51aMWhBq040J8VZmS2qjCVubzCTMxUFaYxjxeY1jNLVZjIHF5hoDErDPRlhYG2rDAFvg2in28j5Ih+vsFZh8JMDKNU0TmHCjZ6OuaQkQ0cc0gOHHNIYXTKURWI2vKkQNCXJQdOOaQwOuVoCkSnHGoyFXs45pCgCOccSlqkcw6ZIcUBBlualFiKpEGZ5VoaVFiKpEEjy7U0qLIUSYMmlmtpEAzHJWiA4bgKbaI3REzmiVg6rg/Edj30eTKKozSnoBhJc0YUa2lORTGS5kwo1tKchmIkyXHGh6afOeND22ET7EE0CO57yO2KBPc95HpFYvsemsP2PbSwCoWpfs8ZIf4FyRUdFopLjjNANIVluJGndrxihit5assrZujTksOW8rQwuOmhdgRjhpseakswZraXpzls0eND2H33sQi6/mettAs/5ufj+x3DdDleG2qqtVz+uTmffwPQ9nqN]],
},
},
}
Public.lonely_storage_tank = {
name = 'lonely_storage_tank',
width = 4,
height = 6,
components = {
{
type = 'static_destructible',
force = 'ancient-friendly',
offset = {x = 0, y = 0},
bp_string = [[0eNqFkVsKwjAQRfcy34m0aWs1WxGRqEMJ2klIUrFI9m5axQdW/QoD9xxuZi6wPXZonaYA8gKelOXB8Mbp/TCfQRYMepDzyEDvDHmQqxTTDanjEAi9RZCgA7bAgFQ7TD4YpxrkQdEBBpD2mEx5XDNACjpovHnGod9Q127RpcDDYLvWJp81PoUN3avwfFaNbbiIkX3gYrrApya7a9I75SmeNXT63fcaYpov//HZb776w7/haaXj8uXLIRmc0PkREIu8rJeiLuq6yrMyxiu0uZ7v]],
},
},
}
Public.swamp_lonely_storage_tank = {
name = 'swamp_lonely_storage_tank',
width = 3,
height = 3,
components = {
{
type = 'static_destructible',
force = 'ancient-friendly',
offset = {x = 0, y = 0},
bp_string = [[0eNptj80KwjAQhN9lz4nYH9uaVxGR1C4l2G5KshVLybubRA8ePC0DM9/O7NBPKy7OEIPawZNeJFs5OjMk/QJVCdhANUGAuVvyoC7RZkbSUzLwtiAoMIwzCCA9J+XZOj2iZE0PSEEaMJKKcBWAxIYNfjhZbDda5x5dNPwnCFisjyFL30ryeDjlVvGGBM3v1c8UAU90PifKrqjbc9nWVVOfyy6EN3scTtM=]],
},
},
}
Public.covered1 = {
name = 'covered1',
width = 17,
height = 15,
components = {
{
type = 'tiles',
tile_name = 'orange-refined-concrete',
offset = {x = -9, y = -8},
bp_string = [[0eNqVmMGKwjAURf8l6wreJG2S/srgwtEgAW1L7Qwj0n8fqy5m4YBnJcKxHrxc7sOr+Tx+5WEs3WTaqzl322E19avDWPbL+x/TKlXmcnsJc2XKru/Opv24geXQbY8LMl2GbFpTpnwylem2p+XdjduNecpm+VC3z8tz5k1lpnLMjwcM/blMpe+e37K+f8l6fvWEf2AR2BLYEdgTuCZwQ+BA4EjghEJhEaIMhUIUSlEoRqEc9WaQIh0Q6YBIB0Q6INIBkQ6IdECkAyIdEOmAUAeEOiDUAaEOCHVAqANCHbCkA5Z0wCJri6wdsXbE2iFrh6w9sfbE2iNrj6xrYl0T6xpZ18i6IdYNsW6QdYOsA7EOxDog64CsI7GOxDoi64isE7FOxDoh68RuFnS4C13uYseW4LXFzi12b8GJZBspNJJCKyk2k2I7KTSUQkspNpViWyk0lkJrKTaXYnspNJhCiyk2mWKbKTSaQqspNptiuyk0nELL+aQtoh2iPaJrRLNfMCA6IjqxdGCYLE2xOMXyFAtULNG3S4HuMqHD7ElbRDtEe0TXiGa/YEB0RHRi6cAwWZpicYrlKRaoWKKvS7GpHv+Tt3/+da/Mdx7P9wfYKB+SDd41Ptk4z7+pVIVy]],
},
{
type = 'tiles',
tile_name = 'green-refined-concrete',
offset = {x = -1, y = 2},
bp_string = [[0eNqV0tsKwjAMBuB3yXWF9bCDfRXxYm5lFLa2tFUco+9uO70QVDCXgS9/CMkGl/mqnNcmgtwgmN4doj1MXo+lvoNsCawg60RAD9YEkKfM9GT6uYC4OgUSdFQLEDD9UqrsBq+igtJkRpVTaDoTiHpWzwBng47amteMap8h0reED0wxmGEw33GFwRSDGQZzDP5zQYHBNQY3v3E+/P4e8u3VCNyUD3s766hoj6wVjPOublJ6AP6T06c=]],
},
{
type = 'tiles',
tile_name = 'out-of-map',
offset = {x = -7, y = -6},
bp_string = [[0eNqd2s1Kw0AUhuF7mXWEfnPO/OVWxEXVIIGaljaKIrl3G3XhQqWvqxA4nUDOs3qbt3C7exoOx3GaQ/8WTtP2cDXvrx6O4/16/xJ6pS68ni+2dGG820+n0F+fB8eHabtbR+bXwxD6MM7DY+jCtH1c785zd8dhHsL6o+l+WM9Zbrowj7vh84DD/jTO4376esrm4yGb5acTfhkWGY5k2Miwk+FEhjMZLmS4kuGGlsJWiHaoC5coYknEkoglEUsilkQsiVgSsSRiScSSkCUhS0KWIrEUiaVILEViKRJLkViKxFIkliKxFImliCxFZCkiS0YsGbFkxJIRS0YsGbFkxJIRS0YsGbFkyJIhS4YsObHkxJITS04sObHkxJITS04sObHkxJIjS44sObKUiKVELCViKRFLiVhKxFIilhKxlIilRCwlZCkhSwlZysRSJpYysZSJpUwsZWIpE0uZWMrEUiaWMrKUkaVCdBSioxAdhegoREchOgrRUYiOQnQUoqMgHQXpqERHJToq0VGJjkp0VKKjEh2V6KhERyU6KtJRkY5GdDSioxEdjehoREcjOhrR0VDVQSlWqMUKxVihGiuUY4V6rFCQ1eYf77ui6ca2A5d56TZZaGWllaVW1lpZbGW1leVW1ltZcGXFFSZX2FxRRhXqqEIhVaikCqVUoZYqFFOFaqpQThXqqWJBVayoCkVSoUoqlEmFOqlQKBUqpUKpVKiVCsVSoVoqlktl/5Fy8Z+CqJgKJVOhZioUTYWqqVA2FeqmQuFUqJwKpVOxdioWT/VXPb3pPr906L99N9GF5+F4+jggVnlpsbhlb7Euyzuk5qn3]],
},
{
type = 'static',
force = 'environment',
offset = {x = 0, y = 0},
bp_string = [[0eNqlmNtuozAQht/F11Ax+IR5lVW1Io0VIRGDwOw2qnj3hbKHSGVghr2KUODz2Hwe+PkQl2b0XV+HKMoPMYSqS2Ob3vr6uhy/ixJsIh7zj54SUb+1YRDlt/nE+haqZjklPjovSlFHfxeJCNV9ORpiG3z6s2oasVwWrn4hTa+J8CHWsfYr5fPg8T2M94vv5xO2rk9E1w7zJW34XVD2oteKXvQ0JV8gOQuSbUMkCQL7EEWC5PsQTYLIfYghQdQ+xJIgeh9SkCBmH+JIELsPgYxEKQ4oNGfdAeWftP696/0wpOO8Z/pb386/6cU3ccO+Z4eTP/uwHWM3RrE1CFHqA6uBpjUceA00seHAbKCpDQduA01uOLAbaHqD2W9h4HgYpJo8Y7VCjVCAVwyG4fVli1Aki2IQiuJNCStG8zBYNYY1J4dQLItSIJTifxqRe25EdUD6UM60G5mwzHgYZMaS+dKBbFnJ0xuw9w75Zf2btppvwM6qA1C6v2Q6j06UKT06U571y+NkE2NPCPsXKj+Fvda9f1v/zo/1lWe2iCWMuHPvHNkKd35iKqO7lyPDGMIwcKbFSHQBDWEBVc6UFrFNyTO1G0Lt+HIp3j5RSOWalWhQjGFlGhRjWakGxRSsXINiHCvZYBidsbINigFWukExOSveoBjJyjcohvj0OdJYa16GQTmGF2JQjuWlGJRT8GIMynG8HINxDPPlauW8JutnoPLpo1Iifvh+WJ9BBSjrcqukUS4vpukXJhD2Zw==]],
},
},
}
Public.covered1.red_chest = {x = 2, y = 5}
Public.covered1.blue_chest = {x = 2, y = 6}
Public.covered1.walls = {
{x = -8, y = -5},
{x = -8, y = -4},
{x = -8, y = -3},
{x = 8, y = -5},
{x = 8, y = -4},
{x = 8, y = -3},
}
Public.covered1b = {
name = 'covered1b',
width = 17,
height = 15,
components = {
{
type = 'tiles',
tile_name = 'orange-refined-concrete',
offset = {x = -7, y = -6},
bp_string = [[0eNqVmM1qg0AURt9l1gby3ev/q5QsbDMUwaiobROC797YlpJFaXtWInwzzmHO4rtew2P3Esep7ZdQX8PcN+NuGXbPU3vc3s+hVpaEy+3haxLap6GfQ/1wC7bPfdNtkeUyxlCHdomnkIS+OW1v8zL0cffWdF3YlvXHuO20Jn8ujOdxivO864bmGKe7xbYekrC0Xfz8/jjM7dIO/dch9x9n3K/f+9wO+jTFJYbtmz+GRcJGwk7CKQlnJJyTcEHCJQlX6FLYFaI71D8vUcQlEZdEXBJxScQlEZdEXBJxScQlEZeEXBJyScglIy4ZccmIS0ZcMuKSEZeMuGTEJSMuGXHJkEuGXDLkkhOXnLjkxCUnLjlxyYlLTlxy4pITl5y45MglRy45ciklLqXEpZS4lBKXUuJSRgAzApgRwIwAZgQwJ4A5AcwJYE4AcwJYEMCCABYEsCCABQEsCWBJAEsCWBLAkgBWBLAigBUBrAhghYo0GjuF5k6hwVNo8hQaPcUGIjYRsZGIzURsKEJVXairC5V1obYuVNeFSqRQixSqkUI9UqhICtUboX4jVHCEGo5+qTiH5PNPWX33wy4Jr3GaP9ZbqbSorEjNvczydX0HDBNakQ==]],
},
{
type = 'static',
force = 'ancient-friendly',
offset = {x = 0, y = 0},
bp_string = [[0eNqV1e9qwyAQAPB3uc+mRBOjyauMMdJFipBqiHZrKL77YsqgjPnvUzi4+0W543zAeb6JZZXKwvAAo8alsrq6rHLy8R0GTBFs+6dxCOSnVgaGtz1RXtQ4+xS7LQIGkFZcAYEarz4yVitRfY/zDL5MTcJLDiULxX1ZhTHVrMdJrC/FxL0jEMpKK8XzCEewfajb9bxnDvi/nyNYtNlLtPq9zel5nfpEnT/OH4RkIXUcabKQJo60WQiJIzQLYXGky0L6OMKyEB5HeF6LEz3u85REk3GdxyQ6hDPHNjEtOG9wcZtgmqL5bwNKW6R0AYUWKTSgdEUKDyisSGEBhRcpONSkvojpA5uuLjsMCTC4jMGe2Tf5sfWHl8cHwZdYzVFBOG5ZT1hLmobTzrkfNM8jsg==]],
},
},
}
Public.covered1b.market = {x = -2, y = -5}
Public.covered1b.steel_chest = {x = 1, y = -5}
Public.covered1b.wooden_chests = {
{x = -5, y = 1},
{x = -4, y = 3},
{x = -5, y = 5},
}
return Public

View File

@@ -0,0 +1,20 @@
local Data = require 'maps.pirates.structures.island_structures.roc.data'
local Public = {}
Public.shelter1 = {}
Public.shelter1.Data = Data.shelter1
Public.shelter2 = {}
Public.shelter2.Data = Data.shelter2
Public.covered1 = {}
Public.covered1.Data = Data.covered1
Public.covered1b = {}
Public.covered1b.Data = Data.covered1b
Public.lonely_storage_tank = {}
Public.lonely_storage_tank.Data = Data.lonely_storage_tank
Public.swamp_lonely_storage_tank = {}
Public.swamp_lonely_storage_tank.Data = Data.swamp_lonely_storage_tank
return Public

View File

@@ -0,0 +1,176 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local Loot = require 'maps.pirates.loot'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Public = {}
local enum = {
BOATS = 'Boats',
ISLANDSTRUCTURES = 'IslandStructures',
}
Public.enum = enum
Public[enum.BOATS] = require 'maps.pirates.structures.boats.boats'
Public[enum.ISLANDSTRUCTURES] = require 'maps.pirates.structures.island_structures.island_structures'
function Public.post_creation_process(special_name, components)
local destination = Common.current_destination()
for _, c in pairs(components) do
local type = c.type
local force_name = c.force_name
local force
if force_name then force = game.forces[force_name] end
if type == 'static' then
for _, e in pairs(c.built_entities) do
if e and e.valid then
e.destructible = false
e.minable = false
e.rotatable = false
end
end
elseif type == 'static_destructible' then
for _, e in pairs(c.built_entities) do
if e and e.valid then
e.minable = false
e.rotatable = false
end
end
elseif type == 'plain' then
for _, e in pairs(c.built_entities) do
--
end
elseif type == 'static_inoperable' then
for _, e in pairs(c.built_entities) do
if e and e.valid then
e.destructible = false
e.minable = false
e.rotatable = false
e.operable = false
end
end
elseif type == 'entities' then
for _, e in pairs(c.built_entities) do
if e and e.valid then
e.minable = false
e.rotatable = false
end
end
elseif type == 'entities_minable' then
for _, e in pairs(c.built_entities) do
--
end
end
for _, e in pairs(c.built_entities) do
if e and e.valid then
e.update_connections()
if e.name == 'iron-chest' then
local inv = e.get_inventory(defines.inventory.chest)
local loot = Loot.iron_chest_loot()
for i = 1, #loot do
local l = loot[i]
inv.insert(l)
end
elseif e.name == 'stone-furnace' then
local inv = e.get_inventory(defines.inventory.fuel)
local loot = Loot.stone_furnace_loot()
for i = 1, #loot do
local l = loot[i]
inv.insert(l)
end
elseif e.name == 'roboport' then
local inv = e.get_inventory(defines.inventory.roboport_robot)
local loot = Loot.roboport_bots_loot()
for i = 1, #loot do
local l = loot[i]
inv.insert(l)
end
elseif e.name == 'centrifuge' then
local inv = e.get_inventory(defines.inventory.assembling_machine_input)
e.set_recipe('kovarex-enrichment-process')
inv.insert{name = 'uranium-235', count = 20}
elseif e.name == 'gun-turret' and special_name == 'small_radioactive_centrifuge' then
local memory = Memory.get_crew_memory()
e.force = game.forces[memory.force_name]
elseif e.name == 'storage-tank' and special_name == 'lonely_storage_tank' then
e.insert_fluid(Loot.storage_tank_fluid_loot())
elseif e.name == 'storage-tank' and special_name == 'swamp_lonely_storage_tank' then
e.insert_fluid(Loot.swamp_storage_tank_fluid_loot())
elseif e.name == 'storage-tank' and special_name == 'small_oilrig_base' then
e.insert_fluid(Loot.storage_tank_fluid_loot(true))
end
if force_name and string.sub(force_name, 1, 15) and string.sub(force_name, 1, 15) == 'ancient-hostile' then
if e.name == 'gun-turret' then
-- TODO: make ammo type depend on x-coord
e.insert({name = "piercing-rounds-magazine", count = 64})
end
elseif force_name and string.sub(force_name, 1, 16) and string.sub(force_name, 1, 16) == 'ancient-friendly' then
if e.name == 'oil-refinery' then
e.set_recipe('advanced-oil-processing')
end
end
end
end
end
end
function Public.try_place(structureScope, specialsTable, left_top, areawidth, areaheight, placeability_function)
local structureData = structureScope.Data
local attempts = 6
local succeeded = false
while attempts > 0 and (not succeeded) do
attempts = attempts - 1
local structure_topleft = {
x = left_top.x + Math.random(areawidth + 1 - structureData.width) - 1,
y = left_top.y + Math.random(areaheight + 1 - structureData.height) - 1,
}
local structure_center = {
x = structure_topleft.x + structureData.width/2,
y = structure_topleft.y + structureData.height/2,
}
local structure_topright = {
x = structure_topleft.x + structureData.width,
y = structure_topleft.y,
}
local structure_bottomleft = {
x = structure_topleft.x,
y = structure_topleft.y + structureData.height,
}
local structure_bottomright = {
x = structure_topleft.x + structureData.width,
y = structure_topleft.y + structureData.height,
}
if placeability_function(structure_topleft) and placeability_function(structure_topright) and placeability_function(structure_bottomleft) and placeability_function(structure_bottomright) and placeability_function(structure_center) then
specialsTable[#specialsTable + 1] = {
position = structure_center,
components = structureData.components,
width = structureData.width,
height = structureData.height,
name = structureData.name,
}
succeeded = true
if _DEBUG then
log('structure_yes: ' .. structureData.name .. ' at ' .. structure_center.x .. ', ' .. structure_center.y)
end
else
-- if _DEBUG then
-- log('structure_no: ' .. structureData.name .. ' at ' .. structure_center.x .. ', ' .. structure_center.y)
-- end
end
end
end
return Public

View File

@@ -0,0 +1,256 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local SurfacesCommon = require 'maps.pirates.surfaces.common'
local Public = {}
local enum = {
DEFAULT = 'Default',
}
Public.enum = enum
Public.Data = {}
Public.Data.width = 16
Public.Data.height = 24
Public.Data.cabin_whitebelts_lrtp_order = {
{x = -5.5, y = -10.5, direction = defines.direction.north, type = 'input'},
{x = -4.5, y = -10.5, direction = defines.direction.north, type = 'input'},
{x = -3.5, y = -10.5, direction = defines.direction.north, type = 'input'},
{x = -5.5, y = 10.5, direction = defines.direction.south, type = 'output'},
{x = -4.5, y = 10.5, direction = defines.direction.south, type = 'output'},
{x = -3.5, y = 10.5, direction = defines.direction.south, type = 'output'},
}
Public.Data.car_pos = {x = 7, y = 0}
Public.Data.static_entities_bp = [[0eNqlmutu2kAQhd9lf5vIu94rr1JFFQlWaonYyDZtooh3L5c2ShOOd8/0JwI+ZmfP3Dy8qYfdod2PXT+r9Zua+s1+NQ+rp7Hbnl+/qLX2lXpVa2OPleoeh35S62+nD3ZP/WZ3/sj8um/VWnVz+6wq1W+ez69+DcO27VePP9ppVucv9tv2zDpW2a+2L/uxnabVPG76aT+M8+qh3X2EmON9pdp+7uauvRpzefH6vT88P7Tj6Vdum1Gp/TCdvjT0f0925y5Hq+/c8WzYJ4wpxNTLmKYQ0yxjbCHGLGNcIcYtY3whxi5jQiEmLGNiIcYvY1IhJi1jdF3IiRlOsY4zQtalStYZKetSLeuMmHWpmnVGzrpUzzqjRO3JaNeAE0iOAZyYS4gw1hAxsa4CIFOzIOAro0lfNYDDZmoLOA3tc5MhWjERndXRxCZjo/9C3A2b7emtG/nhHVSpbTe2j9c3T4Q/pXw4zPvDuVh//ZnAqgbZG1kQcmUiZeNAga9JjgccLRYLIhoxEZ21EcsPEa2YiE7txKkT2ejFRGRjoIkuYyNfMMIH4r/xfIufaL5n+LZm05CTpCGr2ewBbtAaFgQuzjZk+giAY0lOBBx5hUGWeXEaQsQgJqJTR3FAxs86NLf4SZxCgA9cecAEYOd7vHQ9CBdHhwvwr6PDBR2bDZcEOGy4aDRRO7EWIdKLxXhBZtXoAqmdG9gC8RR3ai7nEHp2QSRPDy9AP54dXjSYgjw7vWgwl3n5+AKRVi5EUyJE71ghGoEQPT3cg5HBs9O9BkOMj/K7QsgkvytbcleBLTg3sPm7CppOGuCyAl1ykGtDQ5OQTXTVAV1jcCwI9LFB3pxBpHy4uSDzSoysEr1EiXzRAQ6J/BMzcO2RrjqgjYp01QGNXfyPqoOQlnYXItGPh6G/6BIC+oZIPyBGS48ontMgMonvEiFTLZ57kAeTlj8aR1bSpQKS+FKBjsmWCgMazMSWCgO6weTlikO2yQd5iPyPzQlC8qsTtISp6VKAjNI1u+c2DSKxxQCT2G03JrELb0xid96YxK69MYndfGMSu/zGJHb/DUn0BhyT6B04RtFbcIyi9+AYRW/CMYpudq6o++r6D5z1h78CVepnO07XTjlqG5IJtvE2mXg8/gYLUs8x]]
Public.Data.operable_entities_bp = [[0eNqV1NtqxCAQBuB3mWtTVnP2VUopyWbYCskY1G0bFt+9MUthKW4a7xzw/xyN5gb9eMXZKHIgb2CpmzOns4tRQ6i/QfKKwQJSFJ6BOmuyIF/XiepC3RimuGVGkKAcTsCAuilUX1oPSNn5A62DEKQBg+XZv1FnOrKzNi7rcXwMC//GAMkpp/DexFYs73SdejSrHl+ewaztGtL0u6PTS7ntKQx8aOkPJFKhNu7kRx2+7xRHHbHvlEedfN+pkg+ax6E6GRJxqEmGijjUJkN5HOKn1I/2rCXOU6/RU0mkXoC7tL677Y3Kh58Fg080douIhhd1K+pC5HlTVt7/AARAZgM=]]
Public.Data.cabin_splitters = {
{x = -5, y = 7.5, direction = defines.direction.north, type = 1},
{x = -4, y = 6.5, direction = defines.direction.north, type = 1},
{x = -3, y = 5.5, direction = defines.direction.north, type = 1},
{x = -5, y = 5.5, direction = defines.direction.north, type = 2},
{x = -4, y = 4.5, direction = defines.direction.north, type = 2},
{x = -3, y = 3.5, direction = defines.direction.north, type = 2},
{x = -5, y = 3.5, direction = defines.direction.north, type = 3},
{x = -4, y = 2.5, direction = defines.direction.north, type = 3},
{x = -3, y = 1.5, direction = defines.direction.north, type = 3},
{x = -5, y = 1.5, direction = defines.direction.north, type = 4},
{x = -4, y = 0.5, direction = defines.direction.north, type = 4},
{x = -3, y = -0.5, direction = defines.direction.north, type = 4},
{x = -5, y = -0.5, direction = defines.direction.north, type = 5},
{x = -4, y = -1.5, direction = defines.direction.north, type = 5},
{x = -3, y = -2.5, direction = defines.direction.north, type = 5},
{x = -5, y = -2.5, direction = defines.direction.north, type = 6},
{x = -4, y = -3.5, direction = defines.direction.north, type = 6},
{x = -4, y = -8.5, direction = defines.direction.north, type = 6},
{x = -5, y = -9.5, direction = defines.direction.north, type = 6},
{x = -3, y = -7.5, direction = defines.direction.north, type = 7},
{x = 0.5, y = -7, direction = defines.direction.west, type = 7},
}
Public.Data.output_chest = {x = 3.5, y = -6.5}
Public.Data.backup_output_chest = {x = 3.5, y = -7.5}
Public.Data.input_chests = {
{x = 0.5, y = 4.5},
{x = 0.5, y = 2.5},
{x = 0.5, y = 0.5},
{x = 0.5, y = -1.5},
{x = 0.5, y = -3.5},
}
Public.Data.surfacename_rendering_pos = {x = -0.5, y = -15}
function Public.get_cabin_surface_name()
local memory = Memory.get_crew_memory()
return SurfacesCommon.encode_surface_name(memory.id, 1, SurfacesCommon.enum.CABIN, enum.DEFAULT)
end
function Public.get_cabin_surface()
local name = Public.get_cabin_surface_name()
if name then return game.surfaces[Public.get_cabin_surface_name()] end
end
function Public.create_cabin_surface()
local memory = Memory.get_crew_memory()
local boat = memory.boat
if not Public.get_cabin_surface() then
local width = Public.Data.width
local height = Public.Data.height
local map_gen_settings = Common.default_map_gen_settings(width, height)
map_gen_settings.autoplace_settings.decorative.treat_missing_as_default = false
local cabinname = Public.get_cabin_surface_name()
local surface = game.create_surface(cabinname, map_gen_settings)
surface.freeze_daytime = true
surface.daytime = 0
surface.show_clouds = false
-- more here
Common.ensure_chunks_at(surface, {x = 0, y = 0}, 3)
boat.cabin_whitebelts = {}
for _, b in ipairs(Public.Data.cabin_whitebelts_lrtp_order) do
local p = {x = b.x, y = b.y}
local e = surface.create_entity({name = 'linked-belt', position = p, force = boat.force_name, create_build_effect_smoke = false, direction = b.direction})
if e and e.valid then
e.destructible = false
e.minable = false
e.rotatable = false
e.operable = false
e.linked_belt_type = b.type
boat.cabin_whitebelts[#boat.cabin_whitebelts + 1] = e
end
end
boat.cabin_splitters = {}
for i, splitter in ipairs(Public.Data.cabin_splitters) do
local name = 'express-splitter'
local p = {x = splitter.x, y = splitter.y}
local priority, filter
if splitter.type <= 5 then
priority = 'right'
filter = game.item_prototypes[CoreData.cost_items[splitter.type].name]
elseif splitter.type == 6 then
priority = 'left'
elseif splitter.type == 7 then
priority = 'right'
filter = 'landfill'
end
local e = surface.create_entity({name = name, position = p, force = boat.force_name, create_build_effect_smoke = false, direction = splitter.direction})
if e and e.valid then
e.destructible = false
e.minable = false
e.rotatable = false
e.operable = false
if filter then e.splitter_filter = filter end
if priority then e.splitter_output_priority = priority end
boat.cabin_splitters[#boat.cabin_splitters + 1] = e
end
end
boat.input_chests = {}
for i, b in ipairs(Public.Data.input_chests) do
local p = {x = b.x, y = b.y}
local e = surface.create_entity({name = 'blue-chest', position = p, force = boat.force_name, create_build_effect_smoke = false})
if e and e.valid then
e.destructible = false
e.minable = false
e.rotatable = false
e.operable = false
boat.input_chests[#boat.input_chests + 1] = e
end
end
local p = {x = Public.Data.output_chest.x, y = Public.Data.output_chest.y}
local e = surface.create_entity({name = 'red-chest', position = p, force = boat.force_name, create_build_effect_smoke = false})
if e and e.valid then
e.destructible = false
e.minable = false
e.rotatable = false
e.operable = false
boat.output_chest = e
end
p = {x = Public.Data.backup_output_chest.x, y = Public.Data.backup_output_chest.y}
e = surface.create_entity({name = 'red-chest', position = p, force = boat.force_name, create_build_effect_smoke = false})
if e and e.valid then
e.destructible = false
e.minable = false
e.rotatable = false
e.operable = false
boat.backup_output_chest = e
end
local es = Common.build_from_blueprint(Public.Data.static_entities_bp, surface, {x=0, y=0}, boat.force_name)
for _, e2 in pairs(es) do
if e2 and e2.valid then
e2.destructible = false
e2.minable = false
e2.rotatable = false
e2.operable = false
end
end
local es2 = Common.build_from_blueprint(Public.Data.operable_entities_bp, surface, {x=4, y=0}, boat.force_name)
for _, e2 in pairs(es2) do
if e2 and e2.valid then
e2.destructible = false
e2.minable = false
e2.rotatable = false
end
end
local e = surface.create_entity({name = 'car', position = Public.Data.car_pos, force = boat.force_name, create_build_effect_smoke = false})
if e and e.valid then
e.get_inventory(defines.inventory.fuel).insert({name = 'wood', count = 16})
e.color = {148, 106, 52}
e.destructible = false
e.minable = false
e.rotatable = false
e.operable = false
end
rendering.draw_text{
text = 'Captain\'s Cabin',
surface = surface,
target = Public.Data.surfacename_rendering_pos,
color = CoreData.colors.renderingtext_yellow,
scale = 3.5,
font = 'default-game',
alignment = 'center'
}
end
end
function Public.connect_up_linked_belts_to_deck() --assumes both are in standard lrtd order
local memory = Memory.get_crew_memory()
local boat = memory.boat
if boat and boat.deck_whitebelts and #boat.deck_whitebelts > 0 and boat.cabin_whitebelts and #boat.cabin_whitebelts > 0 then
local connections = {
{1,7},
{2,8},
{3,9},
{4,10},
{5,11},
{6,12},
}
for _, c in pairs(connections) do
local b1 = boat.cabin_whitebelts[c[1]]
local b2 = boat.deck_whitebelts[c[2]]
b1.connect_linked_belts(b2)
end
end
end
function Public.terrain(args)
if args.p.x > Public.Data.width/2-1 and (args.p.y > 2 or args.p.y < -2) then
args.tiles[#args.tiles + 1] = {name = 'out-of-map', position = args.p}
else
args.tiles[#args.tiles + 1] = {name = CoreData.static_boat_floor, position = args.p}
end
return
end
function Public.chunk_structures(args)
return
end
return Public

View File

@@ -0,0 +1,33 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Structures = require 'maps.pirates.structures.structures'
local Boats = require 'maps.pirates.structures.boats.boats'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Public = {}
Public.Data = require 'maps.pirates.surfaces.channel.data'
Public.info = {
display_name = 'Channel'
}
function Public.terrain(args)
if (args.p.y>30 or args.p.y<-20) and args.p.x>-80 and args.p.x<80 then
args.tiles[#args.tiles + 1] = {name = 'sand-1', position = args.p}
else
args.tiles[#args.tiles + 1] = {name = 'deepwater', position = args.p}
end
end
function Public.chunk_structures(args)
return
end
return Public

View File

@@ -0,0 +1,16 @@
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Public = {}
Public.width = 384
Public.height = 384
Public.extra_water_on_left = 96
Public.noiseparams = {
}
return Public

View File

@@ -0,0 +1,68 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Public = {}
local enum = {
SEA = 'Sea',
ISLAND = 'Island',
CROWSNEST = 'Crowsnest',
LOBBY = 'Lobby',
HOLD = 'Hold',
CABIN = 'Cabin',
CHANNEL = 'Channel',
DOCK = 'Dock',
}
Public.enum = enum
function Public.encode_surface_name(crewid, destination_index, type, subtype) -- crewid=0 is shared surfaces
local str = ''
if subtype then
str = string.format('%03d-%03d-%s-%s', crewid, destination_index, type, subtype) --uses the fact that type and subtype resolve to strings
else
str = string.format('%03d-%03d-%s', crewid, destination_index, type)
end
return str
end
function Public.decode_surface_name(name)
local crewid = tonumber(string.sub(name, 1, 3))
local destination_index = tonumber(string.sub(name, 5, 7))
local type = nil
local subtype = nil
local substring = string.sub(name, 9, -1)
local pull = {}
for a, b in string.gmatch(substring, "(%w+)-(%w+)") do
pull[1] = a
pull[2] = b
end
if #pull == 0 then
type = substring
elseif #pull == 2 then
type = pull[1]
subtype = pull[2]
end
return {crewid = crewid, destination_index = destination_index, type = type, subtype = subtype}
end
function Public.fetch_iconized_map(destination)
local type = destination.type
if type == Public.enum.LOBBY then
return CoreData.Lobby_iconized_map()
elseif type == Public.enum.DOCK then
return CoreData.Dock_iconized_map()
else
return destination.iconized_map
end
end
return Public

View File

@@ -0,0 +1,392 @@
local Memory = require 'maps.pirates.memory'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local inspect = require 'utils.inspect'.inspect
local Token = require 'utils.token'
local SurfacesCommon = require 'maps.pirates.surfaces.common'
-- This file is logically a bit of a mess, because we changed from islands moving to the crowsnest platform moving.
local Public = {}
local enum = {
DEFAULT = 'Default',
}
Public.enum = enum
Public.Data = {}
Public.Data.chartingdistance = 130
Public.Data.visibilitywidth = 400
Public.Data.width = 10000 --minimap won't chart beyond this point
Public.Data.height = 72
Public.platformwidth = 7
Public.platformheight = 7
Public.platformrightmostedge = 4
Public.Data.chestspos = {
{x = -2.5, y = -3.5},
{x = -1.5, y = -3.5},
{x = -0.5, y = -3.5},
{x = 1.5, y = -3.5},
{x = 2.5, y = -3.5},
{x = 3.5, y = -3.5},
{x = -2.5, y = 3.5},
{x = -1.5, y = 3.5},
{x = -0.5, y = 3.5},
{x = 1.5, y = 3.5},
{x = 2.5, y = 3.5},
{x = 3.5, y = 3.5},
{x = -2.5, y = -2.5},
{x = -2.5, y = -1.5},
{x = -2.5, y = 1.5},
{x = -2.5, y = 2.5},
{x = 3.5, y = -2.5},
{x = 3.5, y = -1.5},
{x = 3.5, y = 1.5},
{x = 3.5, y = 2.5},
}
Public.Data.surfacename_rendering_pos = {x = 0.5, y = -6.1}
function Public.crowsnest_surface_name()
local memory = Memory.get_crew_memory()
return SurfacesCommon.encode_surface_name(memory.id, 0, SurfacesCommon.enum.CROWSNEST, nil)
end
function Public.get_crowsnest_surface()
local memory = Memory.get_crew_memory()
return game.surfaces[Public.crowsnest_surface_name()]
end
function Public.move_crowsnest(vectorx, vectory)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Public.crowsnest_surface_name()]
local old_area = {{memory.overworldx - 2.5, memory.overworldy - 3.5},{memory.overworldx + 3.5, memory.overworldy + 3.5}}
memory.overworldx = memory.overworldx + vectorx
memory.overworldy = memory.overworldy + vectory
local new_area = {{memory.overworldx - 2.5, memory.overworldy - 3.5},{memory.overworldx + 3.5, memory.overworldy + 3.5}}
local new_floor_positions = {}
local tiles1 = {}
for y = new_area[1][2], new_area[2][2], 1 do
for x = new_area[1][1], new_area[2][1], 1 do
if not new_floor_positions[x] then new_floor_positions[x] = {} end
new_floor_positions[x][y] = true
tiles1[#tiles1 + 1] = {name = CoreData.static_boat_floor, position = {x = x, y = y}}
end
end
surface.set_tiles(tiles1, true, true, true)
local entities_to_teleport = surface.find_entities_filtered{area = old_area}
for _, e in pairs(entities_to_teleport) do
e.teleport(vectorx, vectory)
end
local tiles2 = {}
for y = old_area[1][2], old_area[2][2], 1 do
for x = old_area[1][1], old_area[2][1], 1 do
if not (new_floor_positions[x] and new_floor_positions[x][y]) then
tiles2[#tiles2 + 1] = {name = 'deepwater', position = {x = x, y = y}}
end
end
end
surface.set_tiles(tiles2, true, true, true)
if memory.crowsnest_surfacename_rendering then
local p = rendering.get_target(memory.crowsnest_surfacename_rendering).position
rendering.set_target(memory.crowsnest_surfacename_rendering, {x = p.x + vectorx, y = p.y + vectory})
end
if vectorx ~= 0 then
local crew_force = game.forces[memory.force_name]
local area = {{memory.overworldx,-Public.Data.height/2},{memory.overworldx+Public.Data.chartingdistance,Public.Data.height/2}}
-- crew_force.clear_chart(surface)
crew_force.chart(surface, area)
end
end
function Public.update_destination_renderings()
local memory = Memory.get_crew_memory()
for _, dest in pairs(memory.destinations) do
local r1 = dest.dynamic_data.crowsnest_rendering_1
local r2 = dest.dynamic_data.crowsnest_rendering_2
if r1 and rendering.is_valid(r1) and r2 and rendering.is_valid(r2) then
if dest.overworld_position.x <= memory.overworldx+Public.Data.chartingdistance and dest.overworld_position.x >= memory.overworldx-Public.Data.chartingdistance then
rendering.set_visible(r1, true)
rendering.set_visible(r2, true)
else
rendering.set_visible(r1, false)
rendering.set_visible(r2, false)
end
end
end
end
function Public.draw_kraken(p)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Public.crowsnest_surface_name()]
surface.set_tiles({{name = CoreData.kraken_tile, position = {x = Public.platformrightmostedge + p.x, y = p.y}}}, true, true, true)
end
function Public.draw_destination(destination)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Public.crowsnest_surface_name()]
local tiles = {}
local entities = {}
local renderings = {}
local iconized_map = SurfacesCommon.fetch_iconized_map(destination)
if not iconized_map then iconized_map = destination.iconized_map end
local x = Public.platformrightmostedge + destination.overworld_position.x
local y = destination.overworld_position.y
for _, t in pairs(iconized_map.tiles) do
local t2 = Utils.deepcopy(t)
t2.position = {x = x + t.position.x, y = y + t.position.y}
tiles[#tiles+1] = t2
end
surface.set_tiles(tiles, true, true, true)
for _, e in pairs(iconized_map.entities) do
local e2 = Utils.deepcopy(e)
e2.position = {x = x + e.position.x, y = y + e.position.y}
if e2.source then e2.source = {x = e2.source.x + x, y = e2.source.y + y} end
if e2.target then e2.target = {x = e2.target.x + x, y = e2.target.y + y} end
surface.create_entity(e2)
end
-- Now we can destroy the iconized_map... right?
destination.iconized_map = nil
end
function Public.draw_extra_bits()
Public.draw_destination{
type = 'finish line',
seed = 0,
overworld_position = {x = CoreData.victory_x, y = 0},
static_params = {},
dynamic_data = {},
iconized_map = {
tiles = {},
entities = {
{name = 'electric-beam', position = {x = 0, y = 0}, source = {x = 0, y = -37}, target = {x = 0, y = 37}},
{name = 'electric-beam', position = {x = 0, y = 0}, source = {x = 0, y = -37}, target = {x = 0, y = 37}},
},
},
iconized_map_width = 2,
iconized_map_height = 2,
}
Public.draw_destination{
type = 'Lobby',
overworld_position = {x = -14, y = 0},
}
end
function Public.create_crowsnest_surface()
-- if not game.surfaces[crowsnest_surface_name()] then
local memory = Memory.get_crew_memory()
local map_gen_settings = Common.default_map_gen_settings(Public.Data.width, Public.Data.height)
game.create_surface(Public.crowsnest_surface_name(), map_gen_settings)
local surface = game.surfaces[Public.crowsnest_surface_name()]
surface.freeze_daytime = true
surface.daytime = 0
Common.ensure_chunks_at(surface, {x = 0, y = 0}, 15)
Public.paint_crowsnest_background_tiles()
-- end
memory.crowsnest_surfacename_rendering = rendering.draw_text{
text = 'Crow\'s Nest',
surface = surface,
target = Public.Data.surfacename_rendering_pos,
color = CoreData.colors.renderingtext_yellow,
scale = 2.5,
font = 'default-game',
alignment = 'center'
}
end
function Public.paint_water_between_overworld_positions(overworldx1, overworldx2)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Public.crowsnest_surface_name()]
Common.ensure_chunks_at(surface, {x = overworldx2, y = 0}, 10)
local tiles = {}
for y = -(Public.Data.height+32 - 1)/2, (Public.Data.height+32 - 1)/2, 1 do
for x = Public.platformrightmostedge + overworldx1, Public.platformrightmostedge + overworldx2 do
if y>= -(Public.Data.height - 1)/2 and y <= (Public.Data.height - 1)/2 then
tiles[#tiles + 1] = {name = 'deepwater', position = {x = x, y = y}}
else
tiles[#tiles + 1] = {name = 'out-of-map', position = {x = x, y = y}}
end
end
end
surface.set_tiles(tiles)
end
function Public.paint_crowsnest_background_tiles()
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Public.crowsnest_surface_name()]
local tiles = {}
for y = -(Public.Data.height+32 - 1)/2, (Public.Data.height+32 - 1)/2, 1 do
for x = -(Public.Data.visibilitywidth+32 - 1)/2, (Public.Data.visibilitywidth+32 - 1)/2, 1 do
if x <= 3.5 and x >= -2.5 and y <= 3.5 and y >= -3.5 then
tiles[#tiles + 1] = {name = CoreData.static_boat_floor, position = {x = x, y = y}}
elseif x>= -(Public.Data.visibilitywidth - 1)/2 and x <= (Public.Data.visibilitywidth - 1)/2 and y>= -(Public.Data.height - 1)/2 and y <= (Public.Data.height - 1)/2 then
tiles[#tiles + 1] = {name = 'deepwater', position = {x = x, y = y}}
else
tiles[#tiles + 1] = {name = 'out-of-map', position = {x = x, y = y}}
end
end
end
surface.set_tiles(tiles)
end
function Public.upgrade_chests(new_chest) --the fast replace doesn't work well on the '/go' tick, but that's okay
local memory = Memory.get_crew_memory()
local boat = memory.boat
local surface = Public.get_crowsnest_surface()
local ps = Public.Data.chestspos
for _, p in pairs(ps) do
local p2 = {x = p.x + memory.overworldx, y = p.y + memory.overworldy}
local es = surface.find_entities_filtered{name = 'wooden-chest', position = p2, radius = 0.05}
if es and #es == 1 then
es[1].minable = true
es[1].destructible = true
es[1].rotatable = true
-- es[1].operable = true
local e2 = surface.create_entity{name = new_chest, position = es[1].position, fast_replace = true, spill = false, force = boat.force_name}
e2.minable = false
e2.destructible = false
e2.rotatable = false
-- e2.operable = false
end
end
end
function Public.crowsnest_surface_delayed_init()
local memory = Memory.get_crew_memory()
local surface = game.surfaces[Public.crowsnest_surface_name()]
local force = game.forces[memory.force_name]
if not (surface and surface.valid) then log('crowsnest_surface_delayed_init called when crowsnest surface wasn\'t valid...') end
surface.destroy_decoratives{area = {{-3, -4},{4, 4}}}
local chestspos = Public.Data.chestspos
local steerchestspos = {
{x = 0.5, y = -3.5},
{x = 0.5, y = 3.5},
}
local carspos = {
{x = 3.3, y = 0},
{x = -2.3, y = 0},
}
for _, p in pairs(chestspos) do
local e = surface.create_entity({name = 'wooden-chest', position = p, force = force, create_build_effect_smoke = false})
if e and e.valid then
e.destructible = false
e.minable = false
e.rotatable = false
end
end
for _, p in pairs(steerchestspos) do
local e = surface.create_entity({name = 'blue-chest', position = p, force = force, create_build_effect_smoke = false})
if e and e.valid then
e.destructible = false
e.minable = false
e.rotatable = false
if not memory.boat.crowsneststeeringchests then
memory.boat.crowsneststeeringchests = {}
end
if p.y < 0 then
memory.boat.crowsneststeeringchests.left = e
else
memory.boat.crowsneststeeringchests.right = e
end
end
end
for _, p in pairs(carspos) do
local e = surface.create_entity({name = 'car', position = p, force = force, create_build_effect_smoke = false})
if e and e.valid then
e.get_inventory(defines.inventory.fuel).insert({name = 'wood', count = 16})
e.destructible = false
e.minable = false
e.rotatable = false
e.operable = false
end
end
end
function Public.paint_around_destination(id, tile_name)
local memory = Memory.get_crew_memory()
local destination_data = memory.destinations[id]
local surface = game.surfaces[Public.crowsnest_surface_name()]
local static_params = destination_data.static_params
local type = destination_data.type
local tiles = {}
if type == SurfacesCommon.enum.ISLAND then
for x = memory.overworldx + Public.platformrightmostedge + 0.5, memory.overworldx + Public.platformrightmostedge + destination_data.iconized_map_width - 0.5 do
tiles[#tiles+1] = {name = tile_name, position = {x = x, y = memory.overworldy + destination_data.iconized_map_height/2 - 0.5}}
tiles[#tiles+1] = {name = tile_name, position = {x = x, y = memory.overworldy - destination_data.iconized_map_height/2 + 0.5}}
end
for y = memory.overworldy + -destination_data.iconized_map_height/2 + 1.5, memory.overworldy + destination_data.iconized_map_height/2 - 1.5 do
tiles[#tiles+1] = {name = tile_name, position = {x = memory.overworldx + Public.platformrightmostedge + 0.5, y = y}}
tiles[#tiles+1] = {name = tile_name, position = {x = memory.overworldx + Public.platformrightmostedge + destination_data.iconized_map_width - 0.5, y = y}}
end
end
surface.set_tiles(tiles, true, true, true)
end
function Public.terrain(args) --blank since we do this manually
return
end
function Public.chunk_structures(args)
return
end
return Public

View File

@@ -0,0 +1,154 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Structures = require 'maps.pirates.structures.structures'
local Boats = require 'maps.pirates.structures.boats.boats'
local Common = require 'maps.pirates.common'
local Hold = require 'maps.pirates.surfaces.hold'
local Cabin = require 'maps.pirates.surfaces.cabin'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Public = {}
Public.Data = {}
Public.Data.display_names = {'Dock'}
Public.Data.discord_emoji = CoreData.comfy_emojis.smolfish
Public.Data.width = 296
Public.Data.height = 98
Public.Data.top_boat_bottom = -7
Public.Data.bottom_boat_top = 5
Public.Data.playerboat_starting_xcoord = 35
Public.Data.static_params_default = {
starting_time_of_day = 0,
daynightcycletype = 1,
width = Public.Data.width,
height = Public.Data.height,
}
Public.PurchaseableBoats = {
[Boats.enum.SLOOP] = {
type = Boats.enum.SLOOP,
position = Utils.snap_coordinates_for_rails({x = 24 - Boats[Boats.enum.SLOOP].Data.leftmost_gate_position, y = Public.Data.bottom_boat_top + Boats[Boats.enum.SLOOP].Data.height/2}),
},
-- [Boats.enum.CUTTER] = {
-- type = Boats.enum.CUTTER,
-- position = Utils.snap_coordinates_for_rails({x = 24 - Boats[Boats.enum.CUTTER].Data.leftmost_gate_position, y = Public.Data.bottom_boat_top + Boats[Boats.enum.CUTTER].Data.height/2}),
-- cannonscount = 4
-- },
-- [Boats.enum.CUTTER_WITH_HOLD] = {
-- type = Boats.enum.CUTTER_WITH_HOLD,
-- position = Utils.snap_coordinates_for_rails({x = 24 - Boats[Boats.enum.CUTTER_WITH_HOLD].Data.leftmost_gate_position, y = Public.Data.bottom_boat_top + Boats[Boats.enum.CUTTER_WITH_HOLD].Data.height/2}),
-- cannonscount = 4
-- },
-- [Boats.enum.SLOOP_WITH_HOLD] = {
-- type = Boats.enum.SLOOP_WITH_HOLD,
-- position = Utils.snap_coordinates_for_rails({x = 24 - Boats[Boats.enum.SLOOP_WITH_HOLD].Data.leftmost_gate_position, y = Public.Data.bottom_boat_top + Boats[Boats.enum.SLOOP_WITH_HOLD].Data.height/2}),
-- cannonscount = 2
-- },
}
Public.Data.market_position = {x = -7.5, y = 13.5}
-- FIXME:
Public.Data.rightmostgate_stopping_xposition = 49 -- not sure if this is right for all boat types
Public.Data.iconized_map_width = 4
Public.Data.iconized_map_height = 20
function Public.execute_boat_purchase()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
memory.boat = destination.dynamic_data.boat_for_sale
destination.dynamic_data.boat_for_sale = nil
Hold.connect_up_linked_belts_to_deck()
Cabin.connect_up_linked_belts_to_deck()
memory.mainshop_availability_bools.new_boat_cutter_with_hold = false
memory.mainshop_availability_bools.new_boat_sloop_with_hold = false
memory.mainshop_availability_bools.new_boat_cutter = false
end
function Public.place_dock_jetty_and_boats()
local memory = Memory.get_crew_memory()
local boat = memory.boat
local destination = Common.current_destination()
if not (boat and boat.surface_name) then return end
local surface = game.surfaces[boat.surface_name]
local offset = Public.Data.jetty_offset
local tiles = {}
for _, p in pairs(Common.tile_positions_from_blueprint(Public.Data.jetty_bp, offset)) do
tiles[#tiles + 1] = {name = CoreData.walkway_tile, position = p}
end
surface.set_tiles(tiles, true)
local boat_for_sale_type = destination.static_params.boat_for_sale_type
if boat_for_sale_type then
local boat2 = Utils.deepcopy(Public.PurchaseableBoats[boat_for_sale_type])
-- not needed whilst we're not buying boats:
-- boat2.dockedposition = boat2.position
-- boat2.state = Boats.enum_state.DOCKED
-- boat2.speed = 0
-- boat2.decksteeringchests = {}
-- boat2.questrewardchest = nil
-- boat2.hold_input_belts = boat.hold_input_belts
-- boat2.hold_output_belts = boat.hold_output_belts
-- boat2.crowsneststeeringchests = boat.crowsneststeeringchests
-- boat2.cannons = {}
-- boat2.speedticker1 = 0
-- boat2.speedticker2 = 1/3 * Common.boat_steps_at_a_time
-- boat2.speedticker3 = 2/3 * Common.boat_steps_at_a_time
boat2.force_name = boat.force_name
boat2.surface_name = boat.surface_name
Boats.place_boat(boat2, CoreData.static_boat_floor, true, true)
Boats.place_random_obstacle_boxes(boat2, 10, {}, 2)
destination.dynamic_data.boat_for_sale = boat2
end
-- for y = -3.5, 3.5 do
-- local e = surface.create_entity{name = 'stone-wall', position = {x = -68.5, y = y}, force = 'environment'}
-- e.destructible = false
-- e.minable = false
-- e.rotatable = false
-- e.operable = false
-- end
end
function Public.terrain(args)
local x, y = args.p.x, args.p.y
args.tiles[#args.tiles + 1] = {name = 'water', position = args.p}
local fishrng = Math.random(600)
if fishrng == 1 then
args.entities[#args.entities + 1] = {name = 'fish', position = args.p}
end
return
end
function Public.chunk_structures(args)
return
end
Public.Data.jetty_offset = {x = -40, y = -6}
Public.Data.jetty_bp = [[0eNqd3cuKXscVgNF3+ccKqPatqvQqwQNfGtMgy0Juhxijd49lK7Mk9MpQptyCXWB/65w61b8/vnv/69PHT88fXh7vfn/88uHbj397+flvP356/uHLn//5eLdWvHn89njX/fnN4/n7nz/88nj39z9WPv/44dv3X9a8/Pbx6fHu8fzy9NPjzePDtz99+dMf677/9PTy9PjyL3344enLD/r8zZvHy/P7p79+wMeff3l+ef75w9e/5u2ff0l+/k8/4b8sLlncsnhk8ZbFRxbf1y1eMrolo1syuiWjWzK6JaNbMrqQ0YWMLmR0IaMLGV3I6EJGlzK6lNGljC5ldCmjSxldyuhKRlcyupLRlYyuZHQloysZXcvoWkbXMrqW0bWMrmV0LaMbGd3I6EZGNzK6kdGNjG5kdFtGt2V0W0a3ZXRbRrdldFtGd2R0R0Z3ZHRHRndkdEdGd2R0V0Z3ZXRXRndldFdGd2V0l5KYOLHIE4tAsUgUi0ixyBTLUGGqMFaYKwwWJgujBdliES4W6WIRLxb5YhEwFgljETEWGWMRMhYpYxEzFjljETQWSWMRNRZZYxE2FmljETcWeWMROBaJYxE5FpljEToWqWMROxa5YxE8FsljET0W2WMRPhbpYxE/FvljEUAWCWQRQRYZZBFCFilkEUMWOWQRRBZJZBFFFllkEUYWaWQRRxZ5ZBFIFolkEUkWmSTIJEEmCTJJkEmCTBJkkiCTBJkkyCRBJgkySZBJgkwS9r7DXnjYGw975WHvPOylh731IJMEmSTIJEEmCTJJkEmCTBJkkiCTBJkkyCRBJgkySZBJgkwSZJIgkwSZJMgkQSYJMkmQSYJMEmSSIJMEmSTIJEEmCTJJkEmCTBJkkiCTBJkkyCRBJgkySZBJgkwSZJIgkwSZJMgkQSYJMkmQSYJMEmSSIJMEmSTJJEkmSTJJkkmSTJJkkiSTJJkkySRJJkkySZJJkkyS6/+Y4Hpry5ctD1tu+7lsQ5ft6LItXbanyzZ12a6G7WrYrobtatiuhu1q2K6G7WrYrobtauB/7WxX03Y1bVfTdjVtV9N2NW1X03Y1bVfTdrVsV8t2tWxXC/+Partatqtlu1q2q2W7Wrarbbvatqttu9q2q/3aXaXHmkmPNZMeayY91kx6rJn0WDPtNHdYhIVFWFiEhUVYWISFRVhYhIVFWFiEhUVYWISFRVhYhIVFWFiEhUVYWISFRVhYhIVFWFiEhUVYWISFRVhYhIVFWFiEhUVYWISFRVhYhIVFWFiEhUVYWISFRVhYhIVFWFiEhUVYWISFRVhYhIVFWFiE2Rdh9kmYfRNmH4XZV2H2WRi9Gf26+tURlhZhaRGWFmFpEZYWYWkRlhZhaRGWFmFpEZYWYWkRlhZhaRGWFmFpEZYWYWkRlhZhaRGWFmFpEZYWYWkRlhZhaRGWFmFpEZYWYWkRlhZhaRGWFmFpEZYWYWkRlhZhaRGWFmFpEZYWYWkRlhZhaRFGh6uSDlclHa5KOlyVdLgq6XBV0uGqr6tfHWFlEVYWYWURVhZhZRFWFmFlEVYWYWURVhZhZRFWFmFlEVYWYWURVhZhZRFWFmFlEVYWYWURVhZhZRFWFmFlEVYWYWURVhZhZRFWFmFlEVYWYWURVhZhZRFWFmFlEVYWYWURVhZhZRFWFmFlEVYWYXQ+O+l8dtL57KTz2Unns5POZyedz/66+tUR1hZhbRHWFmFtEdYWYW0R1hZhbRHWFmFtEdYWYW0R1hZhbRHWFmFtEdYWYW0R1hZhbRHWFmFtEdYWYW0R1hZhbRHWFmFtEdYWYW0R1hZhbRHWFmFtEdYWYW0R1hZhbRHWFmFtEdYWYW0R1hZhbRFGn3glfeKV9IlX0ideSZ94JX3ilfSJ19fVr46wsQgbi7CxCBuLsLEIG4uwsQgbi7CxCBuLsLEIG4uwsQgbi7CxCBuLsLEIG4uwsQgbi7CxCBuLsLEIG4uwsQgbi7CxCBuLsLEIG4uwsQgbi7CxCBuLsLEIG4uwsQgbi7CxCBuLsLEIG4uwsQgbizD6SjzpK/Gkr8STvhJP+ko86SvxpK/Ev65+dYRti7BtEbYtwrZF2LYI2xZh2yJsW4Rti7BtEbYtwrZF2LYI2xZh2yJsW4Rti7BtEbYtwrZF2LYI2xZh2yJsW4Rti7BtEbYtwrZF2LYI2xZh2yJsW4Rti7BtEbYtwrZF2LYI2xZh2yJsW4Rti7BtEbYtwrZFGF00k3TRTNJFM0kXzSRdNJN00UzSRTNfV786wo5F2LEIOxZhxyLsWIQdi7BjEXYswo5F2LEIOxZhxyLsWIQdi7BjEXYswo5F2LEIOxZhxyLsWIQdi7BjEXYswo5F2LEIOxZhxyLsWIQdi7BjEXYswo5F2LEIOxZhxyLsWIQdi7BjEXYswo5F2LEIOxZhxyKM7qpLuqsu6a66pLvqku6qS7qrLumuuqK76oruqiu6q67orrqiu+qK7qoruquu6K66orvqiu6qK7qrruiuuqK76oruqiu6aKboopmii2aKLpopumim6KKZootmir4SL/pKvOgr8aKvxIu+Ei/6Srzst4farw+13x9qv0DUfoOo/QpR+x2i9IlX0fnsovPZReezi85nF53PLjqfXXQ+u+hwVdHhqqLDVUWHq4oOVxUdrio6XFX0ZrTozWjRm9GiN6NFb0aL3owWvRkteqxZ9Fiz6LFm0WPNoseaRY81ix5rFpmkyCRFJikySZFJikxSZJImkzSZpMkkTSZpMkmTSZpM0mSSJpM0maTJJE0maTJJk0maTNJkkiaTNJmkySRNJmkySZNJmkzSZJImkzSZpMkkTSZpMkmTSZpM0mSSJpM0maTJJE0maTJJk0maTNJkkiaTNJmkySRNJmkySZNJmkzSZJImkzSZpMkkTSZpMkmTSZpM0mSSJpM0maTJJE0maTJJk0maTNJkkiaTNJmkySRNJmkySZNJhkwyZJIhkwyZZMgkQyYZMsmQSYZMMmSSIZMMmWTIJEMmGTLJkEmGTDJkkiGTDJlkyCRDJhkyyZBJhkwyZJIhkwyZZMgkQyYZMsmQSYZMMmSSIZMMmWTIJEMmGTLJkEmGTDJkkiGTDJlkyCRDJhkyyZBJhkwyZJIhkwyZZMgkQyYZMsmQSYZMMmSSIZMMmWTIJEMmGTLJkEmGTDJkkiGTDJlkyCRDJtlkkk0m2WSSTSbZZJJNJtlkkk0m2WSSTSbZZJJNJtlkkk0m2WSSTSbZZJJNJtlkkk0m2WSSTSbZZJJNJtlkkk0m2WSSTSbZZJJNJtlkkk0m2WSSTSbZZJJNJtlkkk0m2WSSTSbZZJJNJtlkkk0m2WSSTSbZZJJNJtlkkk0m2WSSTSbZZJJNJtlkkk0m2WSSTSbZZJJNJtlkkk0m2WSS/Vd/L1odtDppddHqptVDqzetPrT6lbtz3srufF0dtDppddHqptVDqzetPrT6tbuzaHcW7Q457ZDTDjntkNMOOe2Q0w457QTtTtDukAEPGfCQAQ8Z8JABDxnwkAFP0u4k7Q758pAvD/nykC8P+fKQLw/58hTtTtHukF0P2fWQXQ/Z9ZBdD9n1kF1P0+407Q65+JCLD7n4kIsPufiQiw+5+AztztDukLkPmfuQuQ+Z+5C5D5n7kLkPmfuQuQ+Z+5C5D5n7kLkPmfuQuQ+Z+5C5D5n7kLkPmfuQuQ+5+JCLD7n4kIsPufiQiw+5+JJdL9n1kl0v2fWSXS/Z9ZJdL/nyki8v+fKSLy/58pIvL/nykgEvGfCSAS8Z8JIBLxnwkgEvOe2S0y457ZLTLjntktMuOe2SpS5Z6pKlLlnqkqUuWeqSpS5555J3LnnnkncueeeSdy5555JJLpnkkkkumeSSSS6Z5JJJLpnkkkkumeSSSS6Z5JJJLpnkkkkumeSSSS6Z5JJJLpnkkkkumeSSSS6Z5JJJLpnkkkkumWS9JZT8e3nZ8rblY8u3LT+2/NWDXDbIZYNcNshlg1w2yGWDXDbIsEGGDTJskGGDDBtk2CDDBpk2yLRBpg0ybZBpg0wbZNogywZZNsiyQZYNsmyQZYMsG2TbINsG2TbItkG2DbJtkG2DHBvk2CDHBjk2yLFBjg1ybJDbBrltkNsGuW2Q2wa5bZDbBnlskMcGeWyQxwZ5bJDHBnlskNcGeW2Q1wZ5bZDXBnltkCabZbJZJptlslkmm2WyWSabZbJZJptlslkmm2WyWSabZbJZ/0M237x5PL88/fTHP/vu/a9PHz89f3h5vHn84+nTL3/+gDir9o1dOXXjfP78L4Hp6xE=]]
return Public

View File

@@ -0,0 +1,400 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local SurfacesCommon = require 'maps.pirates.surfaces.common'
local Public = {}
local enum = {
INITIAL = 'Initial',
SECONDARY = 'Secondary',
}
Public.enum = enum
Public.Data = {}
-- local enum_boat = Boats.enum
-- Public.enum_boat = enum_boat
Public.Data.width = 92
Public.Data.height = 46
Public.Data.loco_offset = {x = -2, y = 0}
-- Public.Data.loco_offset = {x = 18, y = 0}
-- Public.Data.display_name = 'Ship\'s Hold'
Public[enum.INITIAL] = {}
Public[enum.INITIAL].Data = {}
Public[enum.INITIAL].Data.hold_whitebelts_lrtp_order = {
{x = -19.5, y = -21.5, direction = defines.direction.north, type = 'output'},
{x = -18.5, y = -21.5, direction = defines.direction.north, type = 'output'},
{x = -17.5, y = -21.5, direction = defines.direction.north, type = 'output'},
{x = 17.5, y = -21.5, direction = defines.direction.north, type = 'output'},
{x = 18.5, y = -21.5, direction = defines.direction.north, type = 'output'},
{x = 19.5, y = -21.5, direction = defines.direction.north, type = 'output'},
{x = -44.5, y = -3.5, direction = defines.direction.west, type = 'output'},
{x = 44.5, y = -3.5, direction = defines.direction.east, type = 'output'},
{x = -44.5, y = -2.5, direction = defines.direction.west, type = 'output'},
{x = 44.5, y = -2.5, direction = defines.direction.east, type = 'output'},
{x = -44.5, y = 2.5, direction = defines.direction.west, type = 'input'},
{x = 44.5, y = 2.5, direction = defines.direction.east, type = 'input'},
{x = -44.5, y = 3.5, direction = defines.direction.west, type = 'input'},
{x = 44.5, y = 3.5, direction = defines.direction.east, type = 'input'},
{x = -19.5, y = 21.5, direction = defines.direction.south, type = 'input'},
{x = -18.5, y = 21.5, direction = defines.direction.south, type = 'input'},
{x = -17.5, y = 21.5, direction = defines.direction.south, type = 'input'},
{x = 17.5, y = 21.5, direction = defines.direction.south, type = 'output'},
{x = 18.5, y = 21.5, direction = defines.direction.south, type = 'output'},
{x = 19.5, y = 21.5, direction = defines.direction.south, type = 'output'},
}
Public[enum.SECONDARY] = {}
Public[enum.SECONDARY].Data = {}
Public[enum.SECONDARY].Data.hold_whitebelts_lrtp_order = {
{x = -44.5, y = -3.5, direction = defines.direction.west, type = 'output'},
{x = 44.5, y = -3.5, direction = defines.direction.east, type = 'output'},
{x = -44.5, y = -2.5, direction = defines.direction.west, type = 'output'},
{x = 44.5, y = -2.5, direction = defines.direction.east, type = 'output'},
{x = -44.5, y = 2.5, direction = defines.direction.west, type = 'input'},
{x = 44.5, y = 2.5, direction = defines.direction.east, type = 'input'},
{x = -44.5, y = 3.5, direction = defines.direction.west, type = 'input'},
{x = 44.5, y = 3.5, direction = defines.direction.east, type = 'input'},
}
Public.Data.boxes_bp = [[0eNqV3OtqI0cUBOB3md/you5z+jJ6lbAE71psBGvJWNokZtG7x5cQAkmpqn4a7GJafDrTmlL75/Ll+4/90/PheFl2P5fz8f7p7nK6+/Z8eHj7+c9lt9bN8rLssl83y+Hr6Xhedr+8/uLh2/H++9uvXF6e9stuOVz2j8tmOd4/vv30x+n0sD/eff1tf74sb394fNi/ZpXr582yP14Ol8P+I+f9h5dfjz8ev+yfX3/h/xM2y9Pp/PpHp+PfF1U+tfer2n5q1+vmPzFVjNnejgkxJm7HpBhTb8c0MSZvx3Qxpt2OGWJMvx0zxZhxO2YVY+btmLIVc1aSIzsmAosquZB3RFEtF6KwqJoLeVcU1XMhoIsquhDSRTVdCOqiqi6EdVFdFwK7qrALkV1V2ZXIrqrsyma9KrsS2VWe00R2VWVXIruqsiuRXVXZlciuquxKZFdVdiWyQ5VdiexQZQfbNaiyg8gOef9BZIcqO4jsUGUHkR2q7CCyQ5UdRHaosoPIDlV2ENmpyg4iO1XZSWSnKjuJ7FRlJ5Gdquxke3R5d01kpyo7iexUZSeRnarsJLJTlZ1EdlNlJ5HdVNmNyG6q7EZkN1V2Y5/2VNmNyG6q7EZkN/mTI5HdVNmNyG6q7EZkN1V2I7K7KrsR2V2V3YnsrsruRHZXZXciu6uyO5HdVdmdPRJRZXciu8tPRYjsrsruRHZXZXcie6iyO5E9VNmDyB6q7EFkD1X2ILKHKnsQ2UOVPYjsocoe7HGfKnsQ2UN+4kdkD1X2ILKnKnsQ2VOVPYnsqcqeRPZUZU8ie6qyJ5E9VdmTyJ6q7ElkT1X2ZI+yVdmTyJ7y02wie1VlTyJ7VWWvRPaqyl6J7DXMiqeCnDRzCshp7sLQBXU3CF3RMFeWIGeaOQFyVndhiUqarZsUKKmYa+soyG0cGwoKd23wktJNgtfUzMVNFNTNoIGChrs2mDTdJLi41Z0ksDzcmkkrCiru4mCSPbfx6tzJXSpKsmd3QUn29MZR/vyG63MneEETs7gzvKCJWewpDqOqPcbh+qo7xwuamtUd5AVNzWpPchxlj3K8PneWFzTvqjvMC5rB1Z7mOMoe53h97jyv8KsX7jwvaAzLHeU/5QKOqm7hgaN86TDKlo5fdVd6RXM4XOkV3RzClo6jbOl4fbZ0NIfTlV7RzSHtrQuOsvcueH32p040h9Pdu1R0c9Cby0YvqrszAUf50uECfenwqmzp6O7QbOnoltV86TDKlw7X50oP+DU/Wzq6OTT/GQuMsnfpeH3uLj3QHG72kxZ0c2j2Lh1Gdf9hC1pfd3fpgeZwd3fpgW4O3d674Ch774LX5+5dAk287u5dAo3hbk90HGVPdLw+d6IHmnjDneiBxvCwJzq+KHui46tyJ3rCr0m7Ez3QGB72RMcX5U90eFX2k3M08YY70RON4eE/PUdR057ocH3TneiJJt50J3qiMTztiY6j7ImO19fMk02Jhud0JzpOGub5Jpw0zSNOOGk1jyfBJLn8TJpUzENKOKmap6ZwUpgnlXBSmmencFJzDyvhqO4eoMJRwz2whKOme4gKR63uoSUUVeU6tCSNKu7BJRxV3cNUOCrcw0s4Kt0DVTiquQeYcFR3D1XhqOEeYsJR0z1YhaNW9yATjJLL0Uq1y/VopdrlfrRS7XI/Wql2uSCtVLvckAbVLjekQbXLDWlQ7XJFGlS73JEG1S53pEG1yx1pUO1ySRpUu9ySBtUut6RBtcstaVLtck2aVLvckybVLvekSbXLPWlS7XJRmlS73pRS7XpTSrXLTWlS7XJTmlS73JQ2ql2uShvVLneljWqXu9JGtctdaaPa5bK0Ue1yW9qodrktbVS73JY2ql2uSxvVLvelnWqX+9JOtct9aafa5b60U+1yX9qpdrkw7VS73Jh2ql1uTDvVLjemnWqXK9NOtcud6aDa5c50UO1yZzqodrk0HVS73JoOql1uTQfVLremgxKVa9NB3zhybzooUbk3HfSNI/emkxKVi9NJ3zhyczr5yz7dEz04yj5lBKPk6nSlL7vfnX5Efd58/Ae63b/+n91m+X3/fH7/kzpLjrWOjJ5rndfrX67iTLU=]]
Public.Data.boxes_bp_offset = {x = 0, y = 0}
Public.Data.surfacename_rendering_pos = {x = Public.Data.loco_offset.x, y = -Public.Data.height/2 - 5}
function Public.get_hold_surface_name(nth)
nth = nth or 1
local memory = Memory.get_crew_memory()
local subtype = (nth == 1) and enum.INITIAL or enum.SECONDARY
return SurfacesCommon.encode_surface_name(memory.id, nth, SurfacesCommon.enum.HOLD, subtype)
end
function Public.get_hold_surface(nth)
nth = nth or 1
local name = Public.get_hold_surface_name(nth)
if name then return game.surfaces[name] end
end
function Public.create_hold_surface(nth)
local memory = Memory.get_crew_memory()
local boat = memory.boat
local width = Public.Data.width
local height = Public.Data.height
local map_gen_settings = Common.default_map_gen_settings(width, height)
map_gen_settings.autoplace_settings.decorative.treat_missing_as_default = false
local holdname = Public.get_hold_surface_name(nth)
if not holdname then log(inspect{'holdname is nil? here some stuff:', memory.id, nth, SurfacesCommon.enum.HOLD}) end
local surface = game.create_surface(holdname, map_gen_settings)
surface.freeze_daytime = true
surface.daytime = 0
surface.show_clouds = false
surface.solar_power_multiplier = 0
-- more here
Common.ensure_chunks_at(surface, {x = 0, y = 0}, 5)
local subtype = nth == 1 and enum.INITIAL or enum.SECONDARY
local whitebelts_table, whitebelts_data
if (not boat.hold_whitebelts) then boat.hold_whitebelts = {} end
boat.hold_whitebelts[nth] = {}
whitebelts_table = boat.hold_whitebelts[nth]
if subtype == enum.INITIAL then
whitebelts_data = Public[enum.INITIAL].Data.hold_whitebelts_lrtp_order
elseif subtype == enum.SECONDARY then
whitebelts_data = Public[enum.SECONDARY].Data.hold_whitebelts_lrtp_order
end
for _, b in ipairs(whitebelts_data) do
local p = {x = b.x, y = b.y}
local e = surface.create_entity({name = 'linked-belt', position = p, force = boat.force_name, create_build_effect_smoke = false, direction = b.direction})
if e and e.valid then
e.destructible = false
e.minable = false
e.rotatable = false
e.operable = false
local type = b.type
if nth % 2 == 0 then
if type == 'input' then type = 'output' else type = 'input' end
end
e.linked_belt_type = type
whitebelts_table[#whitebelts_table + 1] = e
end
end
local boxes = Common.build_from_blueprint(Public.Data.boxes_bp, surface, Public.Data.boxes_bp_offset, boat.force_name)
for _, e in pairs(boxes) do
if e and e.valid then
e.destructible = false
e.minable = false
e.rotatable = false
end
end
Common.build_small_loco(surface, Public.Data.loco_offset, game.forces[memory.force_name], {255, 106, 52})
local items = subtype == enum.INITIAL and Balance.starting_items_crew_downstairs() or {}
Public.place_random_obstacle_boxes(nth, 0, items, 14)
if subtype == enum.SECONDARY then
if Common.difficulty() == 1 then
Public.upgrade_chests(nth, 'iron-chest')
elseif Common.difficulty() > 1 then
Public.upgrade_chests(nth, 'steel-chest')
end
Public.nth_hold_connect_linked_belts(nth)
end
if nth==1 then
memory.shiphold_rendering_1 = rendering.draw_text{
text = 'Ship\'s Hold',
surface = surface,
target = Public.Data.surfacename_rendering_pos,
color = CoreData.colors.renderingtext_yellow,
scale = 6,
font = 'default-game',
alignment = 'center'
}
else
if nth==2 then
if memory.shiphold_rendering_1 then
rendering.set_text(memory.shiphold_rendering_1, 'Ship\'s Hold: -1')
end
end
rendering.draw_text{
text = 'Ship\'s Hold: -' .. nth,
surface = surface,
target = Public.Data.surfacename_rendering_pos,
color = CoreData.colors.renderingtext_yellow,
scale = 6,
font = 'default-game',
alignment = 'center'
}
end
end
function Public.add_another_hold_surface()
local memory = Memory.get_crew_memory()
memory.hold_surface_count = memory.hold_surface_count + 1
Public.create_hold_surface(memory.hold_surface_count)
return memory.hold_surface_count
end
function Public.upgrade_chests(nth, new_chest)
local memory = Memory.get_crew_memory()
local boat = memory.boat
local surface = Public.get_hold_surface(nth)
local ps = Common.entity_positions_from_blueprint(Public.Data.boxes_bp, {x = -Public.Data.width/2 ,y = -Public.Data.height/2})
for _, p in pairs(ps) do
local es = surface.find_entities_filtered{name = 'wooden-chest', position = p, radius = 0.05}
if es and #es == 1 then
es[1].minable = true
es[1].destructible = true
es[1].rotatable = true
end
local e2 = surface.create_entity{name = new_chest, position = p, fast_replace = true, spill = false, force = boat.force_name}
e2.minable = false
e2.destructible = false
e2.rotatable = false
end
end
function Public.connect_up_linked_belts_to_deck() --assumes both are in standard lrtd order
local memory = Memory.get_crew_memory()
local boat = memory.boat
if boat and boat.deck_whitebelts and #boat.deck_whitebelts > 0 and boat.hold_whitebelts and boat.hold_whitebelts[1] and #boat.hold_whitebelts[1] > 0 then
local connections = {
{1,1},
{2,2},
{3,3},
{4,4},
{5,5},
{6,6},
{15,13},
{16,14},
{17,15},
{18,16},
{19,17},
{20,18},
}
for _, c in pairs(connections) do
local b1 = boat.hold_whitebelts[1][c[1]]
local b2 = boat.deck_whitebelts[c[2]]
b1.connect_linked_belts(b2)
end
end
end
function Public.nth_hold_connect_linked_belts(nth) --assumes both are in standard lrtd order
local memory = Memory.get_crew_memory()
local boat = memory.boat
if boat.hold_whitebelts and boat.hold_whitebelts[nth-1] and #boat.hold_whitebelts[nth-1] > 0 and boat.hold_whitebelts[nth] and #boat.hold_whitebelts[nth] > 0 then
local connections
if nth % 2 == 0 then
if nth == 2 then
connections = {
{5,11},
{6,12},
{7,13},
{8,14},
}
for _, c in pairs(connections) do
local b1 = boat.hold_whitebelts[nth][c[1]]
local b2 = boat.hold_whitebelts[nth-1][c[2]]
b1.connect_linked_belts(b2)
end
else
connections = {
{5,5},
{6,6},
{7,7},
{8,8},
}
for _, c in pairs(connections) do
local b1 = boat.hold_whitebelts[nth][c[1]]
local b2 = boat.hold_whitebelts[nth-1][c[2]]
b1.connect_linked_belts(b2)
end
end
connections = {
{1,7},
{2,8},
{3,9},
{4,10},
}
for _, c in pairs(connections) do
local b1 = boat.hold_whitebelts[nth][c[1]]
local b2 = boat.hold_whitebelts[1][c[2]]
b1.connect_linked_belts(b2)
end
else
connections = {
{1,1},
{2,2},
{3,3},
{4,4},
}
for _, c in pairs(connections) do
local b1 = boat.hold_whitebelts[nth][c[1]]
local b2 = boat.hold_whitebelts[nth-1][c[2]]
b1.connect_linked_belts(b2)
end
connections = {
{5,7},
{6,8},
{7,9},
{8,10},
}
for _, c in pairs(connections) do
local b1 = boat.hold_whitebelts[nth][c[1]]
local b2 = boat.hold_whitebelts[1][c[2]]
b1.connect_linked_belts(b2)
end
end
end
end
function Public.place_random_obstacle_boxes(nth, smallcount, contents, largecount)
contents = contents or {}
largecount = largecount or 0
local memory = Memory.get_crew_memory()
local surface = Public.get_hold_surface(nth)
if not surface then return end
local function boxposition()
local p1 = {x = -Public.Data.width/2 + Math.random(Public.Data.width), y = -Public.Data.height/2 + Math.random(Public.Data.height)}
local p2 = surface.find_non_colliding_position('rocket-silo', p1, 32, 4, true) or p1
return {x = p2.x, y = p2.y}
end
for i = 1, largecount do
local p = boxposition()
for j=1,4 do
local p2 = surface.find_non_colliding_position('wooden-chest', p, 5, 0.1, true)
local e = surface.create_entity{name = 'wooden-chest', position = p2, force = memory.force_name, create_build_effect_smoke = false}
e.destructible = false
e.minable = false
e.rotatable = false
if contents[i] and j==1 then
local inventory = e.get_inventory(defines.inventory.chest)
for name, count in pairs(contents[i]) do
inventory.insert{name = name, count = count}
end
end
end
end
local smallpositions = {}
for i = 1, smallcount do
smallpositions[i] = boxposition()
end
for i = 1, smallcount do
local p = smallpositions[i]
if p then
local e = surface.create_entity{name = 'wooden-chest', position = p, force = memory.force_name, create_build_effect_smoke = false}
e.destructible = false
e.minable = false
e.rotatable = false
end
end
end
function Public.terrain(args)
if args.p.x < Public.Data.width/2-5 and args.p.x > Public.Data.width/2-10 and args.p.y > Public.Data.height/2 - 2 then
args.tiles[#args.tiles + 1] = {name = 'water', position = args.p}
else
args.tiles[#args.tiles + 1] = {name = CoreData.static_boat_floor, position = args.p}
end
return
end
function Public.chunk_structures(args)
return
end
return Public

View File

@@ -0,0 +1,336 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Structures = require 'maps.pirates.structures.structures'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Ores = require 'maps.pirates.ores'
local inspect = require 'utils.inspect'.inspect
local Public = {}
local enum = {
STANDARD = '1',
FIRST = '2',
WALKWAYS = '3',
RED_DESERT = '4',
RADIOACTIVE = '5',
STANDARD_VARIANT = '6',
HORSESHOE = '7',
SWAMP = '8',
}
Public.enum = enum
function Public.place_water_tile(args)
if args.static_params and args.static_params.deepwater_terraingenframe_xposition and args.p.x <= args.static_params.deepwater_terraingenframe_xposition - 0.5
then
args.tiles[#args.tiles + 1] = {name = 'deepwater', position = args.p}
local fishrng = Math.random(800)
if fishrng == 800 then
args.entities[#args.entities + 1] = {name = 'fish', position = args.p}
end
return true
end
if not args.noise_generator['height'] then return end
local height_noise = args.noise_generator['height'](args.p)
if height_noise < 0 then
args.tiles[#args.tiles + 1] = {name = 'water', position = args.p}
local fishrng = Math.random(500)
if fishrng == 500 then
args.entities[#args.entities + 1] = {name = 'fish', position = args.p}
end
return true
end
return false
end
function Public.island_height_1(args)
local noise_name = 'height'
if not args.noise_generator[noise_name] then
args.noise_generator:addNoise(noise_name,
function(p)
local r2 = (p.x)^2 + (p.y)^2
local r = Math.sqrt(r2)
-- 'noise testing suite':
-- local height_noise
-- if args.noise_generator.forest then
-- height_noise = args.noise_generator.forest(p)
-- else return 0 end
-- local height_noise = args.noise_generator.height_background(p)
-- local height_noise = (
-- 1 - r/(args.noise_generator.radius{x = p.x/r, y = p.y/r})
-- )
local height_noise = (
1 - r/(args.noise_generator.radius{x = p.x/r, y = p.y/r})
) + args.noise_generator.height_background(p)
return height_noise
end)
end
return args.noise_generator[noise_name]
end
function Public.island_height_horseshoe(args)
local noise_name = 'height'
if not args.noise_generator[noise_name] then
args.noise_generator:addNoise(noise_name,
function(p)
local r12 = (p.x)^2 + (p.y)^2
local r1 = Math.sqrt(r12)
local offsetp = {x = p.x + 80, y = p.y}
local r22 = (offsetp.x)^2 + (offsetp.y)^2
local r2 = Math.sqrt(r22)
-- 'noise testing suite':
-- local height_noise
-- if args.noise_generator.forest then
-- height_noise = args.noise_generator.forest(p)
-- else return 0 end
-- local height_noise = args.noise_generator.height_background(p)
-- local height_noise = (
-- 1 - r/(args.noise_generator.radius{x = p.x/r, y = p.y/r})
-- )
local height_noise = (
1 - r1/(args.noise_generator.radius1{x = p.x/r1, y = p.y/r1})
) - Math.max(0,
1 - r2/(args.noise_generator.radius2{x = offsetp.x/r2, y = offsetp.y/r2})
) + args.noise_generator.height_background(p)
return height_noise
end)
end
return args.noise_generator[noise_name]
end
function Public.island_farness_1(args)
--on a scale from 0 to 1, how 'far' the point is from the boat dropoff point
if not args.static_params.width and args.static_params.islandcenter_position and args.static_params.terraingen_coordinates_offset then return end -- can only call after detailed static_params are generated
local noise_name = 'farness' --might as well remember as a noise just to memoize
if not args.noise_generator[noise_name] then
args.noise_generator:addNoise(noise_name,
function(p)
local island_width = args.static_params.width - 2*Math.abs(args.static_params.islandcenter_position.x)
local nexus_of_boredom = {x = args.static_params.terraingen_coordinates_offset.x + args.static_params.islandcenter_position.x - 2/5*island_width, y = args.static_params.terraingen_coordinates_offset.y + args.static_params.islandcenter_position.y}
local relativeradius2 = Math.distance(p, nexus_of_boredom)
local farness = Math.slopefromto(relativeradius2, island_width/12, island_width)
if p.x < nexus_of_boredom.x then
local num = Math.abs(nexus_of_boredom.y - p.y)
local denom = Math.abs(nexus_of_boredom.x - p.x)
if denom < 1 then denom = 1 end
farness = farness * Math.slopefromto(num/denom, 1, 5)
end
return farness
end)
end
return args.noise_generator[noise_name]
end
function Public.island_farness_horseshoe(args)
--on a scale from 0 to 1, how 'far' the point is from the boat dropoff point
--compared to first farness function this one is much more simply just distance from boat
if not args.static_params.width and args.static_params.islandcenter_position and args.static_params.terraingen_coordinates_offset then return end -- can only call after detailed static_params are generated
local noise_name = 'farness' --might as well remember as a noise just to memoize
if not args.noise_generator[noise_name] then
args.noise_generator:addNoise(noise_name,
function(p)
local island_width = args.static_params.width - 2*Math.abs(args.static_params.islandcenter_position.x)
local nexus_of_boredom = {x = args.static_params.terraingen_coordinates_offset.x + args.static_params.islandcenter_position.x - 1/6*island_width, y = args.static_params.terraingen_coordinates_offset.y + args.static_params.islandcenter_position.y}
local relativeradius2 = Math.distance(p, nexus_of_boredom)
local farness = Math.slopefromto(relativeradius2, island_width/12, 62/100*island_width)
return farness
end)
end
return args.noise_generator[noise_name]
end
function Public.enemies_1(args, spec, no_worms, worm_evo_bonus)
worm_evo_bonus = worm_evo_bonus or 0
for x = args.left_top.x, args.left_top.x + 31 do
for y = args.left_top.y, args.left_top.y + 31 do
local p = {x = x, y = y}
local spec2 = spec(p)
if spec2.placeable and Math.random() < spec2.density_perchunk/(32*32) then
local memory = Memory.get_crew_memory()
local enemy_force_name = memory.enemy_force_name
local rng = Math.random(10)
if rng >= 4 then
args.entities[#args.entities + 1] = {name = 'biter-spawner', position = p, force = enemy_force_name, indestructible = spec2.spawners_indestructible or false}
elseif rng >= 3 then
args.entities[#args.entities + 1] = {name = 'spitter-spawner', position = p, force = enemy_force_name, indestructible = spec2.spawners_indestructible or false}
elseif not no_worms then
local evolution = game.forces[enemy_force_name].evolution_factor + worm_evo_bonus
args.entities[#args.entities + 1] = {name = Common.get_random_worm_type(evolution + 0.05), position = p, force = enemy_force_name}
end
end
end
end
end
function Public.enemies_specworms_separate(args, spec)
for x = args.left_top.x, args.left_top.x + 31 do
for y = args.left_top.y, args.left_top.y + 31 do
local p = {x = x, y = y}
local spec2 = spec(p)
if spec2.placeable and Math.random() < spec2.spawners_density_perchunk/(32*32) then
local memory = Memory.get_crew_memory()
local enemy_force_name = memory.enemy_force_name
local rng = Math.random(10)
if rng >=8 then
args.entities[#args.entities + 1] = {name = 'spitter-spawner', position = p, force = enemy_force_name, indestructible = spec2.spawners_indestructible or false}
else
args.entities[#args.entities + 1] = {name = 'biter-spawner', position = p, force = enemy_force_name, indestructible = spec2.spawners_indestructible or false}
end
elseif spec2.placeable and Math.random() < spec2.worms_density_perchunk/(32*32) then
local memory = Memory.get_crew_memory()
local enemy_force_name = memory.enemy_force_name
local evolution = game.forces[enemy_force_name].evolution_factor
args.entities[#args.entities + 1] = {name = Common.get_random_worm_type(evolution + 0.05), position = p, force = enemy_force_name}
end
end
end
end
function Public.assorted_structures_1(args, spec)
local memory = Memory.get_crew_memory()
local overworldx = memory.overworldx or 0
local rng = Math.random()
local left_top = args.left_top
-- initial attempt, to avoid placing two structures too close to each other, is to divide up the map into 2x2 chonks, and spawn once in each
local bool1, bool2 = left_top.x % 64 < 32, left_top.y % 64 < 32
local all_four_chunks = {
{x = left_top.x, y = left_top.y},
{x = left_top.x + (bool1 and 32 or -32), y = left_top.y},
{x = left_top.x, y = left_top.y + (bool2 and 32 or -32)},
{x = left_top.x + (bool1 and 32 or -32), y = left_top.y + (bool2 and 32 or -32)},
}
local chunks_loaded = args.chunks_loaded
if not chunks_loaded[args.left_top.x] then chunks_loaded[args.left_top.x] = {} end
chunks_loaded[args.left_top.x][args.left_top.y] = true
local nearby_chunks_generated_count = 0
for i=1,4 do
if chunks_loaded[all_four_chunks[i].x] and chunks_loaded[all_four_chunks[i].x][all_four_chunks[i].y] then
nearby_chunks_generated_count = nearby_chunks_generated_count + 1
end
end
if nearby_chunks_generated_count == 4 then --should trigger only once per 4 chunks
local avgleft_top = {
x = (all_four_chunks[1].x + all_four_chunks[4].x)/2,
y = (all_four_chunks[1].y + all_four_chunks[4].y)/2,
}
local leftmost_topmost = {
x = avgleft_top.x - 16,
y = avgleft_top.y - 16,
}
local spec2 = spec{x = avgleft_top.x + 16, y = avgleft_top.y + 16}
if rng < spec2.chanceper4chunks then
local rng2 = Math.random()
local struct
if overworldx <= 120 then
if rng2 < 20/100 then
struct = Structures.IslandStructures.ROC.lonely_storage_tank
elseif rng2 < 40/100 then
struct = Structures.IslandStructures.MATTISSO.small_crashed_ship
elseif rng2 < 50/100 then
struct = Structures.IslandStructures.MATTISSO.small_oilrig_base
elseif rng2 < 60/100 then
struct = Structures.IslandStructures.MATTISSO.small_abandoned_refinery
elseif rng2 < 70/100 then
struct = Structures.IslandStructures.MATTISSO.small_mining_base
else
struct = Structures.IslandStructures.MATTISSO.small_primitive_mining_base
end
elseif overworldx <= 240 then
if rng2 < 30/100 then
struct = Structures.IslandStructures.ROC.lonely_storage_tank
elseif rng2 < 40/100 then
struct = Structures.IslandStructures.MATTISSO.small_crashed_ship
elseif rng2 < 50/100 then
struct = Structures.IslandStructures.MATTISSO.small_oilrig_base
elseif rng2 < 70/100 then
struct = Structures.IslandStructures.MATTISSO.small_abandoned_refinery
elseif rng2 < 80/100 then
struct = Structures.IslandStructures.MATTISSO.small_mining_base
else
struct = Structures.IslandStructures.MATTISSO.small_solar_base
end
else
if rng2 < 10/100 then
struct = Structures.IslandStructures.ROC.lonely_storage_tank
elseif rng2 < 20/100 then
struct = Structures.IslandStructures.MATTISSO.small_crashed_ship
elseif rng2 < 40/100 then
struct = Structures.IslandStructures.MATTISSO.small_oilrig_base
elseif rng2 < 50/100 then
struct = Structures.IslandStructures.MATTISSO.small_abandoned_refinery
elseif rng2 < 60/100 then
struct = Structures.IslandStructures.MATTISSO.small_mining_base
elseif rng2 < 80/100 then
struct = Structures.IslandStructures.MATTISSO.small_solar_base
else
struct = Structures.IslandStructures.MATTISSO.small_roboport_base
end
end
if struct then
Structures.try_place(struct, args.specials, leftmost_topmost, 64, 64, function(p) return spec(p).placeable end)
end
end
end
end
function Public.random_rock_1(p)
local rock_raffle = {'sand-rock-big','sand-rock-big','rock-big','rock-big','rock-big','rock-big','rock-huge','rock-huge'}
local s_rock_raffle = #rock_raffle
return {name = rock_raffle[Math.random(1, s_rock_raffle)], position = p}
end
return Public

View File

@@ -0,0 +1,71 @@
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Public = {}
Public.display_names = {'Fledgling Vale'}
Public.terraingen_frame_width = 325
Public.terraingen_frame_height = 325
Public.static_params_default = {
starting_time_of_day = 0,
daynightcycletype = 1,
boat_extra_distance_from_shore = 0,
-- boat_extra_distance_from_shore = 0.1 * Common.boat_default_starting_distance_from_shore,
default_decoratives = true,
base_starting_treasure = 2000,
base_starting_rock_material = 800,
base_starting_wood = 2400,
}
function Public.base_ores()
return {
['copper-ore'] = 2.0,
['iron-ore'] = 4.2,
['coal'] = 1.8,
['stone'] = 0.4,
}
end
local rscale = 125
Public.noiseparams = {
radius = {
type = 'simplex_2d',
normalised = false,
params = {
{wavelength = 0, amplitude = rscale * 1},
-- {wavelength = 2.5, amplitude = rscale * 0.1},
},
},
height_background = {
type = 'island1',
normalised = false,
params = {
-- {upperscale = 1000, amplitude = hscale * 200},
{upperscale = 600, amplitude = 0.15},
},
},
forest = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 70, amplitude = 1},
},
},
rock = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 120, amplitude = 1, seedfactor = 2},
},
},
}
return Public

View File

@@ -0,0 +1,118 @@
local ores = require "maps.pirates.ores"
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Structures = require 'maps.pirates.structures.structures'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Ores = require 'maps.pirates.ores'
local IslandsCommon = require 'maps.pirates.surfaces.islands.common'
local Hunt = require 'maps.pirates.surfaces.islands.hunt'
local Public = {}
Public.Data = require 'maps.pirates.surfaces.islands.first.data'
function Public.noises(args)
local ret = {}
ret.height = IslandsCommon.island_height_1(args)
ret.forest = args.noise_generator.forest
ret.forest_abs = function (p) return Math.abs(ret.forest(p)) end
ret.forest_abs_suppressed = function (p) return ret.forest_abs(p) - 1 * Math.slopefromto(ret.height(p), 0.35, 0.1) end
ret.rock = args.noise_generator.rock
ret.rock_abs = function (p) return Math.abs(ret.rock(p)) end
ret.farness = IslandsCommon.island_farness_1(args)
return ret
end
function Public.terrain(args)
local noises = Public.noises(args)
local p = args.p
if IslandsCommon.place_water_tile(args) then return end
if noises.height(p) < 0 then
args.tiles[#args.tiles + 1] = {name = 'water', position = args.p}
return
end
if noises.height(p) < 0.1 then
args.tiles[#args.tiles + 1] = {name = 'sand-1', position = args.p}
if args.specials and noises.farness(p) > 0.0001 and noises.farness(p) < 0.6 and Math.random(150) == 1 then
args.specials[#args.specials + 1] = {name = 'buried-treasure', position = args.p}
end
elseif noises.height(p) < 0.16 then
args.tiles[#args.tiles + 1] = {name = 'grass-4', position = args.p}
else
if noises.forest_abs_suppressed(p) > 0.5 and noises.rock(p) < 0.3 then
args.tiles[#args.tiles + 1] = {name = 'grass-3', position = args.p}
elseif noises.forest_abs_suppressed(p) > 0.2 and noises.rock(p) < 0.3 then
args.tiles[#args.tiles + 1] = {name = 'grass-2', position = args.p}
else
args.tiles[#args.tiles + 1] = {name = 'grass-1', position = args.p}
end
end
if noises.height(p) > 0.2 then
if noises.forest_abs(p) > 0.65 then
local treedensity = 0.4 * Math.slopefromto(noises.forest_abs_suppressed(p), 0.6, 0.85)
if noises.forest(p) > 0.87 then
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-01', position = args.p, visible_on_overworld = true} end
elseif noises.forest(p) < -1.4 then
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-03', position = args.p, visible_on_overworld = true} end
else
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-02', position = args.p, visible_on_overworld = true} end
end
end
end
if noises.forest_abs_suppressed(p) < 0.6 then
if noises.height(p) > 0.12 then
local rockdensity = 0.0018 * Math.slopefromto(noises.rock_abs(p), -0.15, 0.3)
local rockrng = Math.random()
if rockrng < rockdensity then
args.entities[#args.entities + 1] = IslandsCommon.random_rock_1(args.p)
elseif rockrng < rockdensity * 1.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-medium', position = args.p}
elseif rockrng < rockdensity * 2 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-small', position = args.p}
elseif rockrng < rockdensity * 2.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-tiny', position = args.p}
end
end
end
end
function Public.chunk_structures(args)
local spec = function(p)
local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
return {
placeable = noises.farness(p) > 0.4,
density_perchunk = 28 * Math.slopefromto(noises.farness(p), 0.4, 1)^2,
}
end
IslandsCommon.enemies_1(args, spec, false, 0.3)
end
function Public.break_rock(surface, p, entity_name)
return Ores.try_ore_spawn(surface, p, entity_name, 6)
end
function Public.generate_silo_position()
return Hunt.free_position_1()
end
return Public

View File

@@ -0,0 +1,92 @@
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Public = {}
Public.display_names = {'Horseshoe Keys'}
Public.terraingen_frame_width = 896
Public.terraingen_frame_height = 896
Public.static_params_default = {
starting_time_of_day = 0,
daynightcycletype = 1,
default_decoratives = true,
base_starting_treasure = 1000,
base_starting_rock_material = 800,
base_starting_wood = 1200,
base_starting_treasure_maps = 0,
}
function Public.base_ores()
return {
['copper-ore'] = 2.8,
['iron-ore'] = 3.1,
['coal'] = 1.8,
['stone'] = 1.0,
}
end
local rscale1 = 240
local rscale2 = 210
local hscale = 0.1
Public.noiseparams = {
radius1 = {
type = 'simplex_2d',
normalised = false,
params = {
{wavelength = 0, amplitude = rscale1 * 1},
{wavelength = 1.6, amplitude = rscale1 * 0.2},
},
},
radius2 = {
type = 'simplex_2d',
normalised = false,
params = {
{wavelength = 0, amplitude = rscale2 * 1},
{wavelength = 1.6, amplitude = rscale2 * 0.2},
},
},
height_background = {
type = 'island1',
normalised = false,
params = {
-- {upperscale = 1000, amplitude = hscale * 200},
{upperscale = 1600, amplitude = hscale * 1},
{upperscale = 80, amplitude = hscale * 0.1},
},
},
forest = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 90, amplitude = 1},
-- {upperscale = 0, amplitude = 0.15},
},
},
rock = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 110, amplitude = 1, seedfactor = 2},
},
},
mood = {
type = 'simplex_2d',
normalised = true,
params = {
{wavelength = 250, amplitude = 70},
{wavelength = 50, amplitude = 20},
},
},
}
return Public

View File

@@ -0,0 +1,141 @@
local ores = require "maps.pirates.ores"
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Structures = require 'maps.pirates.structures.structures'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Ores = require 'maps.pirates.ores'
local IslandsCommon = require 'maps.pirates.surfaces.islands.common'
local Hunt = require 'maps.pirates.surfaces.islands.hunt'
local Public = {}
Public.Data = require 'maps.pirates.surfaces.islands.horseshoe.data'
function Public.noises(args)
local ret = {}
ret.height = IslandsCommon.island_height_horseshoe(args)
ret.forest = args.noise_generator.forest
ret.forest_abs = function (p) return Math.abs(ret.forest(p)) end
ret.forest_abs_suppressed = function (p) return ret.forest_abs(p) - 2 * Math.slopefromto(ret.height(p), 0.2, 0.12) end
ret.rock = args.noise_generator.rock
ret.rock_abs = function (p) return Math.abs(ret.rock(p)) end
ret.mood = args.noise_generator.mood
ret.farness = IslandsCommon.island_farness_horseshoe(args)
return ret
end
function Public.terrain(args)
local noises = Public.noises(args)
local p = args.p
if IslandsCommon.place_water_tile(args) then return end
if noises.height(p) < 0 then
args.tiles[#args.tiles + 1] = {name = 'water', position = args.p}
return
end
if noises.height(p) < 0.05 then
args.tiles[#args.tiles + 1] = {name = 'sand-1', position = args.p}
if args.specials and noises.farness(p) > 0.02 and noises.farness(p) < 0.6 and Math.random(400) == 1 then
args.specials[#args.specials + 1] = {name = 'buried-treasure', position = args.p}
end
elseif noises.height(p) < 0.12 then
args.tiles[#args.tiles + 1] = {name = 'sand-2', position = args.p}
else
if noises.forest_abs_suppressed(p) > 0.3 and noises.rock(p) < -0.1 then
args.tiles[#args.tiles + 1] = {name = 'dirt-1', position = args.p}
else
if noises.mood(p) > 0.66 then
args.tiles[#args.tiles + 1] = {name = 'water-shallow', position = args.p}
else
args.tiles[#args.tiles + 1] = {name = 'sand-3', position = args.p}
end
end
end
if args.specials and noises.height(p) > 0 and Math.random(6000) == 1 then --but has lots of chests due to spawning anywhere
args.specials[#args.specials + 1] = {name = 'chest', position = args.p}
elseif noises.height(p) > 0.02 then
if noises.forest_abs_suppressed(p) > 0.58 then
local forest_noise = noises.forest(p)
local treedensity
if forest_noise > 0 then
treedensity = 0.5 * Math.slopefromto(noises.forest_abs_suppressed(p), 0.58, 0.75)
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-06', position = args.p, visible_on_overworld = true} end
elseif noises.forest_abs_suppressed(p) > 0.68 then
treedensity = 0.5 * Math.slopefromto(forest_noise, -0.7, -0.75)
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-08-brown', position = args.p, visible_on_overworld = true} end
end
end
end
if noises.forest_abs_suppressed(p) < 0.45 then
if noises.height(p) > 0.05 then
if noises.rock_abs(p) > 0.15 then
local rockdensity = 1/500 * Math.slopefromto(noises.rock_abs(p), 0.15, 0.5)
if noises.height(p) < 0.12 then rockdensity = rockdensity * 3 end
local rockrng = Math.random()
if rockrng < rockdensity then
args.entities[#args.entities + 1] = IslandsCommon.random_rock_1(args.p)
elseif rockrng < rockdensity * 1.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-medium', position = args.p}
elseif rockrng < rockdensity * 2 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-small', position = args.p}
elseif rockrng < rockdensity * 2.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-tiny', position = args.p}
end
end
end
end
end
function Public.chunk_structures(args)
local spec = function(p)
local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
return {
placeable = noises.farness(p) > 0.35,
spawners_indestructible = false,
-- spawners_indestructible = noises.farness(p) > 0.7,
density_perchunk = 10 * Math.slopefromto(noises.mood(p), 0.12, -0.18) * Math.slopefromto(noises.farness(p), 0.35, 1) * args.biter_base_density_scale,
}
end
IslandsCommon.enemies_1(args, spec)
-- local spec2 = function(p)
-- local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
-- return {
-- placeable = noises.height(p) >= 0 and noises.forest_abs_suppressed(p) < 0.3 + Math.max(0, 0.2 - noises.height(p)),
-- chanceper4chunks = 0.5 * Math.slopefromto(noises.farness(p), 0.1, 0.4) * Math.slopefromto(noises.mood(p), 0, 0.25),
-- }
-- end
-- IslandsCommon.assorted_structures_1(args, spec2)
end
function Public.break_rock(surface, p, entity_name)
return Ores.try_ore_spawn(surface, p, entity_name)
end
function Public.generate_silo_position()
return Hunt.free_position_1(0, 30)
end
return Public

View File

@@ -0,0 +1,324 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local IslandsCommon = require 'maps.pirates.surfaces.islands.common'
local inspect = require 'utils.inspect'.inspect
local Public = {}
-- two things to 'hunt':
-- treasure map for X
-- quest treasure
function Public.free_position_1(x_fractional_offset, x_absolute_offset)
x_absolute_offset = x_absolute_offset or 0
x_fractional_offset = x_fractional_offset or 0
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local boatposition = memory.boat.position
local island_center = destination.static_params.islandcenter_position
local difficulty_offset = (1 - Common.difficulty()) * 20 or 0
local p = {
x = Math.min(
Math.floor(boatposition.x + difficulty_offset + (island_center.x - boatposition.x) * 3/5) - 0.5,
Math.floor(boatposition.x + 175) - 0.5
) + (island_center.x - boatposition.x) * x_fractional_offset + x_absolute_offset,
y = Math.floor(boatposition.y + (island_center.y - boatposition.y) * 3/5) - 0.5
}
local tries = 0
local p_ret = nil
local p2 = nil
while p_ret == nil and tries < 80 do
p2 = {x = p.x + Math.random(-30, 0), y = p.y + Math.random(-70, 70)}
if p2.x >= boatposition.x+5 and Common.can_place_silo_setup(surface, p2) then p_ret = p2 end
tries = tries + 1
end
while p_ret == nil and tries < 240 do
p2 = {x = p.x + Math.random(-60, 10), y = p.y + Math.random(-90, 90)}
if p2.x >= boatposition.x+5 and Common.can_place_silo_setup(surface, p2) then p_ret = p2 end
tries = tries + 1
end
while p_ret == nil and tries < 560 do
p2 = {x = p.x + Math.random(-90, 20), y = p.y + Math.random(-130, 130)}
if p2.x >= boatposition.x+5 and Common.can_place_silo_setup(surface, p2) then p_ret = p2 end
tries = tries + 1
end
if _DEBUG then
if p_ret == nil then
log("No good position found after 500 tries")
p_ret = p
else
log(string.format("Position found after %f tries: %f, %f", tries, p_ret.x, p_ret.y))
end
end
Common.ensure_chunks_at(surface, p_ret, 1)
return p_ret
end
function Public.mid_farness_position_1(args, points_to_avoid)
points_to_avoid = points_to_avoid or {}
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local island_center = destination.static_params.islandcenter_position
local width = destination.static_params.width
local height = destination.static_params.height
local tries = 0
local p_ret = nil
local p2 = nil
while p_ret == nil and tries < 400 do
p2 = {x = island_center.x + Math.random(Math.ceil(-width/2), Math.ceil(width/2)), y = island_center.y + Math.random(Math.ceil(-height/2), Math.ceil(height/2))}
Common.ensure_chunks_at(surface, p2, 0.01)
local tile = surface.get_tile(p2)
if tile and tile.valid and tile.name then
if (not Utils.contains(CoreData.tiles_that_conflict_with_resource_layer, tile.name)) and (not Utils.contains(CoreData.edgemost_tile_names, tile.name)) then
local p3 = {x = p2.x + args.static_params.terraingen_coordinates_offset.x, y = p2.y + args.static_params.terraingen_coordinates_offset.y}
if IslandsCommon.island_farness_1(args)(p3) > 0.1 and IslandsCommon.island_farness_1(args)(p3) < 0.8 then
local allowed = true
for _, pa in pairs(points_to_avoid) do
if Math.distance({x = pa.x, y = pa.y}, p2) < pa.r then
allowed = false
end
end
if allowed then
p_ret = p2
end
end
end
end
tries = tries + 1
end
if _DEBUG then
if p_ret == nil then
log("No good position found after 500 tries")
-- p_ret = {x = 0, y = 0}
else
log(string.format("Position found after %f tries: %f, %f", tries, p_ret.x, p_ret.y))
end
end
return p_ret
end
function Public.close_position_1(args, points_to_avoid)
points_to_avoid = points_to_avoid or {}
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local island_center = destination.static_params.islandcenter_position
local width = destination.static_params.width
local height = destination.static_params.height
local tries = 0
local p_ret = nil
local p2 = nil
while p_ret == nil and tries < 1000 do
p2 = {x = island_center.x + Math.random(Math.ceil(-width/2), 0), y = island_center.y + Math.random(Math.ceil(-height/3), Math.ceil(height/3))}
Common.ensure_chunks_at(surface, p2, 0.01)
local tile = surface.get_tile(p2)
if tile and tile.valid and tile.name then
if (not Utils.contains(CoreData.tiles_that_conflict_with_resource_layer, tile.name)) and (not Utils.contains(CoreData.edgemost_tile_names, tile.name)) then
local p3 = {x = p2.x + args.static_params.terraingen_coordinates_offset.x, y = p2.y + args.static_params.terraingen_coordinates_offset.y}
if IslandsCommon.island_farness_1(args)(p3) > 0.06 and IslandsCommon.island_farness_1(args)(p3) < 0.16 then
local allowed = true
for _, pa in pairs(points_to_avoid) do
if Math.distance({x = pa.x, y = pa.y}, p2) < pa.r then
allowed = false
end
end
if allowed then
p_ret = p2
end
end
end
end
tries = tries + 1
end
if _DEBUG then
if p_ret == nil then
log("No good position found after 500 tries")
-- p_ret = {x = 0, y = 0}
else
log(string.format("Position found after %f tries: %f, %f", tries, p_ret.x, p_ret.y))
end
end
return p_ret
end
function Public.position_away_from_players_1(args, radius)
radius = radius or 60
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local island_center = destination.static_params.islandcenter_position
local width = destination.static_params.width
local height = destination.static_params.height
local tries = 0
local p_ret = nil
local p2 = nil
while p_ret == nil and tries < 500 do
p2 = {x = island_center.x + Math.random(Math.ceil(-width/2), Math.ceil(width/2)), y = island_center.y + Math.random(Math.ceil(-height/2), Math.ceil(height/2))}
Common.ensure_chunks_at(surface, p2, 0.01)
local p3 = {x = p2.x + args.static_params.terraingen_coordinates_offset.x, y = p2.y + args.static_params.terraingen_coordinates_offset.y}
local tile = surface.get_tile(p2)
if tile and tile.valid and tile.name then
if not Utils.contains(CoreData.tiles_that_conflict_with_resource_layer, tile.name) then
local nearby_characters = surface.find_entities_filtered{position = p2, radius = radius, name = 'character'}
if (not nearby_characters) or (#nearby_characters == 0) then
p_ret = p2
end
end
end
tries = tries + 1
end
if _DEBUG then
if p_ret == nil then
log("No good position found after 500 tries")
-- p_ret = {x = 0, y = 0}
else
log(string.format("Position found after %f tries: %f, %f", tries, p_ret.x, p_ret.y))
end
end
return p_ret
end
function Public.merchant_ship_position(args)
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local island_center = destination.static_params.islandcenter_position
local width = destination.static_params.width
local height = destination.static_params.height
local right_boundary = island_center.x + width/2
local to_try = {}
for i = -height/2, height/2, 10 do
to_try[#to_try + 1] = i
end
Math.shuffle(to_try)
local last_reasonable_position
local p_ret
for _, h in ipairs(to_try) do
local right_boundary_p = {x = right_boundary, y = h}
Common.ensure_chunks_at(surface, right_boundary_p, 10)
local i = 0
while i < 300 and (not p_ret) do
i = i + 1
local p2 = {x = right_boundary - i, y = h}
local tile = surface.get_tile(p2)
if i < 32 then
if not Utils.contains(CoreData.tiles_that_conflict_with_resource_layer, tile.name) then
break
end
else
if not Utils.contains(CoreData.tiles_that_conflict_with_resource_layer, tile.name) then
local area = {{p2.x - 40, p2.y - 11},{p2.x + 4, p2.y + 11}}
local spawners = surface.find_entities_filtered({type = 'unit-spawner', force = memory.enemy_force_name, area = area})
local worms = surface.find_entities_filtered({type = 'turret', force = memory.enemy_force_name, area = area})
if #spawners == 0 and #worms == 0 then
p_ret = p2
else
last_reasonable_position = p2
end
break
end
end
end
end
if _DEBUG then
if p_ret == nil then
log("No good position found for merchant ship")
-- p_ret = {x = 0, y = 0}
else
log(string.format("Merchant ship position found: %f, %f", p_ret.x, p_ret.y))
end
end
return p_ret or last_reasonable_position
end
return Public

View File

@@ -0,0 +1,357 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Structures = require 'maps.pirates.structures.structures'
local Boats = require 'maps.pirates.structures.boats.boats'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local IslandsCommon = require 'maps.pirates.surfaces.islands.common'
local Hunt = require 'maps.pirates.surfaces.islands.hunt'
local Ores = require 'maps.pirates.ores'
local Quest = require 'maps.pirates.quest'
local inspect = require 'utils.inspect'.inspect
local Token = require 'utils.token'
local Task = require 'utils.task'
local Public = {}
local enum = IslandsCommon.enum
Public.enum = enum
Public[enum.FIRST] = require 'maps.pirates.surfaces.islands.first.first'
Public[enum.STANDARD] = require 'maps.pirates.surfaces.islands.standard.standard'
Public[enum.STANDARD_VARIANT] = require 'maps.pirates.surfaces.islands.standard_variant.standard_variant'
Public[enum.WALKWAYS] = require 'maps.pirates.surfaces.islands.walkways.walkways'
Public[enum.RADIOACTIVE] = require 'maps.pirates.surfaces.islands.radioactive.radioactive'
Public[enum.RED_DESERT] = require 'maps.pirates.surfaces.islands.red_desert.red_desert'
Public[enum.HORSESHOE] = require 'maps.pirates.surfaces.islands.horseshoe.horseshoe'
Public[enum.SWAMP] = require 'maps.pirates.surfaces.islands.swamp.swamp'
Public['IslandsCommon'] = require 'maps.pirates.surfaces.islands.common'
local function render_silo_hp()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
destination.dynamic_data.rocketsilohptext = rendering.draw_text{
text = 'HP: ' .. destination.dynamic_data.rocketsilohp .. ' / ' .. destination.dynamic_data.rocketsilomaxhp,
surface = surface,
target = destination.dynamic_data.rocketsilo,
target_offset = {0, 4.5},
color = {0, 255, 0},
scale = 1.20,
font = 'default-game',
alignment = 'center',
scale_with_zoom = true
}
end
function Public.spawn_treasure_maps(destination, points_to_avoid)
points_to_avoid = points_to_avoid or {}
local memory = Memory.get_crew_memory()
local surface = game.surfaces[destination.surface_name]
if not surface and surface.valid then return end
local num = destination.static_params.starting_treasure_maps
if not destination.dynamic_data.treasure_maps then destination.dynamic_data.treasure_maps = {} end
local args = {
static_params = destination.static_params,
noise_generator = Utils.noise_generator({}, 0),
}
for i = 1, num do
local map = {}
local p = Hunt.mid_farness_position_1(args, points_to_avoid)
map.position = p
map.mapobject_rendering = rendering.draw_sprite{
surface = surface,
target = p,
sprite = 'utility/gps_map_icon',
render_layer = '125',
x_scale = 2.4,
y_scale = 2.4,
}
map.state = 'on_ground'
map.x_renderings = nil
map.buried_treasure_position = nil
destination.dynamic_data.treasure_maps[#destination.dynamic_data.treasure_maps + 1] = map
end
end
function Public.spawn_ghosts(destination, points_to_avoid)
points_to_avoid = points_to_avoid or {}
local memory = Memory.get_crew_memory()
local surface = game.surfaces[destination.surface_name]
if not surface and surface.valid then return end
if not (destination.dynamic_data and destination.dynamic_data.quest_type and destination.dynamic_data.quest_type == Quest.enum.FIND) then return end
local num = destination.dynamic_data.quest_progressneeded
if not destination.dynamic_data.ghosts then destination.dynamic_data.ghosts = {} end
local args = {
static_params = destination.static_params,
noise_generator = Utils.noise_generator({}, 0),
}
for i = 1, num do
local ghost = {}
local p = Hunt.mid_farness_position_1(args, points_to_avoid)
ghost.position = p
ghost.ghostobject_rendering = rendering.draw_sprite{
surface = surface,
target = p,
sprite = 'utility/ghost_time_to_live_modifier_icon',
render_layer = '125',
x_scale = 1,
y_scale = 1,
}
ghost.state = 'on_ground'
destination.dynamic_data.ghosts[#destination.dynamic_data.ghosts + 1] = ghost
end
end
function Public.spawn_covered(destination, points_to_avoid)
points_to_avoid = points_to_avoid or {}
local memory = Memory.get_crew_memory()
local surface = game.surfaces[destination.surface_name]
if not surface and surface.valid then return end
local args = {
static_params = destination.static_params,
noise_generator = Utils.noise_generator({}, 0),
}
local p
for i = 1, 1 do
p = Hunt.mid_farness_position_1(args, points_to_avoid)
local structureData = Structures.IslandStructures.ROC.covered1.Data
local special = {
position = p,
components = structureData.components,
width = structureData.width,
height = structureData.height,
name = structureData.name,
}
if not destination.dynamic_data.structures_waiting_to_be_placed then
destination.dynamic_data.structures_waiting_to_be_placed = {}
end
destination.dynamic_data.structures_waiting_to_be_placed[#destination.dynamic_data.structures_waiting_to_be_placed + 1] = {data = special, tick = game.tick}
local requirement = destination.dynamic_data.covered1_requirement.price
local rendering1 = rendering.draw_text{
surface = surface,
target = {x = p.x + 4, y = p.y + 6.85},
color = CoreData.colors.renderingtext_green,
scale = 1.5,
font = 'default-game',
alignment = 'right',
}
local rendering2 = rendering.draw_sprite{
sprite = 'item/' .. requirement.name,
surface = surface,
target = {x = p.x + 4.85, y = p.y + 7.5},
x_scale = 1.5,
y_scale = 1.5
}
destination.dynamic_data.covered_data = {
position = p,
state = 'covered',
requirement = requirement,
rendering1 = rendering1,
rendering2 = rendering2,
}
if _DEBUG then
log('covered position: ' .. p.x .. ', ' .. p.y)
end
end
return p
end
function Public.spawn_ores_on_shorehit(destination, points_to_avoid)
points_to_avoid = points_to_avoid or {}
local memory = Memory.get_crew_memory()
local surface = game.surfaces[destination.surface_name]
if not surface and surface.valid then return end
if not (destination.subtype and (destination.subtype == enum.STANDARD or destination.subtype == enum.STANDARD_VARIANT)) then return end
local ores = {'iron-ore', 'copper-ore', 'stone', 'coal'}
local args = {
static_params = destination.static_params,
noise_generator = Utils.noise_generator({}, 0),
}
for _, ore in pairs(ores) do
local p = Hunt.close_position_1(args, points_to_avoid)
if p then points_to_avoid[#points_to_avoid + 1] = {x=p.x, y=p.y, r=8} end
local amount = Common.ore_abstract_to_real(destination.static_params.abstract_ore_amounts[ore])
local placed = Ores.draw_noisy_ore_patch(surface, p, ore, amount, 10000, 30, true, true)
if placed > 0 and not destination.dynamic_data.ore_types_spawned[ore] then
destination.dynamic_data.ore_types_spawned[ore] = true
end
end
end
function Public.spawn_merchant_ship(destination)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[destination.surface_name]
if not surface and surface.valid then return end
local args = {
static_params = destination.static_params,
noise_generator = Utils.noise_generator({}, 0),
}
local p = Hunt.merchant_ship_position(args)
if p then
local boat = {
state = Boats.enum_state.LANDED,
type = Boats.enum.MERCHANT,
position = p,
force_name = 'environment',
surface_name = surface.name,
market = nil,
}
Boats.place_landingtrack(boat, CoreData.landing_tile, true)
Boats.place_boat(boat, CoreData.static_boat_floor, true, true, true, false)
destination.dynamic_data.merchant_market = boat.market
return boat.market
end
end
local silo_chart_tag = Token.register(
function(data)
local p_silo = data.p_silo
local surface_name = data.surface_name
local surface = game.surfaces[surface_name]
if not surface and surface.valid then return end
local memory = Memory.get_crew_memory()
if memory.game_lost then return end
local destination = Common.current_destination()
local force = game.forces[memory.force_name]
destination.dynamic_data.silo_chart_tag = force.add_chart_tag(surface, {icon = {type = 'item', name = 'rocket-silo'}, position = p_silo})
end
)
function Public.spawn_silo_setup()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local subtype = destination.subtype
local force = game.forces[memory.force_name]
local p_silo = Public[subtype].generate_silo_position()
-- log(string.format("placing silo at x=%f, y = %f", p_silo.x, p_silo.y))
local silo = surface.create_entity({name = 'rocket-silo', position = p_silo, force = force, create_build_effect_smoke = false})
if silo and silo.valid then
destination.dynamic_data.rocketsilo = silo
silo.minable = false
silo.rotatable = false
silo.operable = false
silo.auto_launch = true
local modulesinv = silo.get_module_inventory()
modulesinv.insert{name = 'productivity-module-3', count = 4}
end
-- local substation = surface.create_entity({name = 'substation', position = {x = p_silo.x - 8.5, y = p_silo.y - 0.5}, force = force, create_build_effect_smoke = false})
-- if substation and substation.valid then
-- substation.destructible = false
-- substation.minable = false
-- substation.rotatable = false
-- end
-- local eei = surface.create_entity({name = 'electric-energy-interface', position = {x = p_silo.x - 8.5, y = p_silo.y + 1.5}, force = force, create_build_effect_smoke = false})
-- if eei and eei.valid then
-- memory.islandeei = eei
-- eei.destructible = false
-- eei.minable = false
-- eei.rotatable = false
-- eei.operable = false
-- eei.electric_buffer_size = memory.islandeeijoulesperrocket / 100
-- eei.power_production = 0
-- eei.power_usage = 0
-- end
force.chart(surface, {{p_silo.x - 4, p_silo.y - 4},{p_silo.x + 4, p_silo.y + 4}})
Task.set_timeout_in_ticks(2, silo_chart_tag, {p_silo = p_silo, surface_name = destination.surface_name})
render_silo_hp()
return p_silo
end
function Public.spawn_enemy_boat(type)
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local offsets = {50, -50, 63, -63}
local enemyboats = memory.enemyboats
if enemyboats then
local boat = {
state = Boats.enum_state.APPROACHING,
type = type,
speed = 4.5,
position = {x = - surface.map_gen_settings.width/2 + 8.5, y = (memory.boat.dockedposition or memory.boat.position).y + offsets[Math.random(4)]},
force_name = memory.enemy_force_name,
surface_name = surface.name,
unit_group = nil,
spawner = nil,
}
enemyboats[#enemyboats + 1] = boat
Boats.place_boat(boat, CoreData.static_boat_floor, true, true)
local e = surface.create_entity({name = 'biter-spawner', force = boat.force_name, position = {boat.position.x - 3, boat.position.y}})
boat.spawner = e
return enemyboats[#enemyboats]
end
end
return Public

View File

@@ -0,0 +1,80 @@
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Public = {}
Public.display_names = {'Abandoned Labs'}
Public.terraingen_frame_width = 700
Public.terraingen_frame_height = 700
Public.static_params_default = {
starting_time_of_day = 0.45,
daynightcycletype = 2,
base_starting_treasure = 1000,
base_starting_rock_material = 1200,
base_starting_wood = 800,
base_starting_treasure_maps = 1,
}
function Public.base_ores() --here, just for the gui:
return {
['copper-ore'] = 1,
['coal'] = 1,
['uranium-ore'] = 7,
['stone'] = 5,
}
end
local rscale = 200
local hscale = 0.12
Public.noiseparams = {
radius = {
type = 'simplex_2d',
normalised = false,
params = {
{wavelength = 0, amplitude = rscale * 1},
{wavelength = 2.5, amplitude = rscale * 0.12},
},
},
height_background = {
type = 'island1',
normalised = false,
params = {
-- {upperscale = 1000, amplitude = hscale * 200},
{upperscale = 1600, amplitude = hscale * 1},
{upperscale = 80, amplitude = hscale * 0.1},
},
},
forest = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 180, amplitude = 1},
-- {upperscale = 0, amplitude = 0.15},
},
},
rock = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 110, amplitude = 1, seedfactor = 2},
},
},
ore = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 40, amplitude = 1, seedfactor = 3},
},
},
}
return Public

View File

@@ -0,0 +1,292 @@
local ores = require "maps.pirates.ores"
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Structures = require 'maps.pirates.structures.structures'
local Common = require 'maps.pirates.common'
local Effects = require 'maps.pirates.effects'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Ores = require 'maps.pirates.ores'
local IslandsCommon = require 'maps.pirates.surfaces.islands.common'
local Hunt = require 'maps.pirates.surfaces.islands.hunt'
local Public = {}
Public.Data = require 'maps.pirates.surfaces.islands.radioactive.data'
function Public.noises(args)
local ret = {}
ret.height = IslandsCommon.island_height_1(args)
ret.height_background = args.noise_generator.height_background
ret.forest = args.noise_generator.forest
ret.forest_abs = function (p) return Math.abs(ret.forest(p)) end
ret.forest_abs_suppressed = function (p) return ret.forest_abs(p) - 1 * Math.slopefromto(ret.height(p), 0.17, 0.11) end
ret.rock = args.noise_generator.rock
ret.ore = args.noise_generator.ore
ret.rock_abs = function (p) return Math.abs(ret.rock(p)) end
ret.farness = IslandsCommon.island_farness_1(args)
return ret
end
function Public.terrain(args)
local noises = Public.noises(args)
local p = args.p
if IslandsCommon.place_water_tile(args) then return end
if noises.height(p) < 0 then
args.tiles[#args.tiles + 1] = {name = 'water', position = args.p}
return
end
if noises.height(p) < 0.05 then
args.tiles[#args.tiles + 1] = {name = 'sand-1', position = args.p}
if args.specials and noises.farness(p) > 0.02 and noises.farness(p) < 0.6 and Math.random(500) == 1 then
args.specials[#args.specials + 1] = {name = 'buried-treasure', position = args.p}
end
elseif noises.height(p) < 0.33 then
args.tiles[#args.tiles + 1] = {name = 'sand-2', position = args.p}
elseif noises.height(p) < 0.35 then
args.tiles[#args.tiles + 1] = {name = 'dirt-5', position = args.p}
else
if noises.height_background(p) > 0.4 then
args.tiles[#args.tiles + 1] = {name = 'nuclear-ground', position = args.p}
else
args.tiles[#args.tiles + 1] = {name = 'dirt-4', position = args.p}
end
end
if noises.forest_abs_suppressed(p) > 1 then
local treedensity = 0.02 * Math.slopefromto(noises.forest_abs_suppressed(p), 1, 1.1)
if noises.forest(p) > 1.4 then
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'dead-grey-trunk', position = args.p, visible_on_overworld = true} end
elseif noises.forest(p) < -0.95 then
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'dry-tree', position = args.p, visible_on_overworld = true} end
end
end
if noises.forest_abs_suppressed(p) < 0.65 then
if noises.height(p) > 0.12 then
if noises.rock_abs(p) > 0.25 then
local rockdensity = 1/200 * Math.slopefromto(noises.rock_abs(p), 0.25, 0.6)
local rockrng = Math.random()
if rockrng < rockdensity then
args.entities[#args.entities + 1] = IslandsCommon.random_rock_1(args.p)
elseif rockrng < rockdensity * 1.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-medium', position = args.p}
elseif rockrng < rockdensity * 2 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-small', position = args.p}
elseif rockrng < rockdensity * 2.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-tiny', position = args.p}
end
end
end
end
if noises.forest_abs_suppressed(p) < 0.8 and noises.height(p) > 0.35 then
if noises.ore(p) > 1 then
args.entities[#args.entities + 1] = {name = 'uranium-ore', position = args.p, amount = 2000}
end
end
if noises.forest_abs_suppressed(p) < 0.8 and noises.height(p) < 0.35 and noises.height(p) > 0.05 then
if noises.ore(p) < -1.5 then
args.entities[#args.entities + 1] = {name = 'stone', position = args.p, amount = 1000}
elseif noises.ore(p) < 0.005 and noises.ore(p) > -0.005 then
if noises.ore(p) > 0 then
args.entities[#args.entities + 1] = {name = 'coal', position = args.p, amount = 100}
else
args.entities[#args.entities + 1] = {name = 'copper-ore', position = args.p, amount = 100}
end
end
end
end
function Public.chunk_structures(args)
local spec = function(p)
local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
return {
placeable = noises.farness(p) > 0.3,
-- we need some indestructible spawners, because otherwise you can clear, stay here forever, make infinite resources...
spawners_indestructible = noises.farness(p) > 0.63,
-- spawners_indestructible = false,
density_perchunk = 25 * Math.slopefromto(noises.farness(p), 0.3, 1)^2 * args.biter_base_density_scale,
}
end
IslandsCommon.enemies_1(args, spec, true)
end
function Public.spawn_structures()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local subtype = destination.subtype
local force = game.forces[memory.force_name]
local ancient_force = string.format('ancient-friendly-%03d', memory.id)
local ps = Public.structure_positions()
if not destination.dynamic_data.structures_waiting_to_be_placed then
destination.dynamic_data.structures_waiting_to_be_placed = {}
end
for i = 1, #ps do
local p = ps[i]
local structureData
if i == 1 then
structureData = Structures.IslandStructures.MATTISSO.small_radioactive_reactor.Data
elseif i==2 then
structureData = Structures.IslandStructures.MATTISSO.uranium_miners.Data
elseif i>2 and i<7 then
structureData = Structures.IslandStructures.MATTISSO.small_radioactive_centrifuge.Data
else
structureData = Structures.IslandStructures.MATTISSO.small_radioactive_lab.Data
end
local special = {
position = p,
components = structureData.components,
width = structureData.width,
height = structureData.height,
name = structureData.name,
}
destination.dynamic_data.structures_waiting_to_be_placed[#destination.dynamic_data.structures_waiting_to_be_placed + 1] = {data = special, tick = game.tick}
end
end
function Public.structure_positions()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local island_center = destination.static_params.islandcenter_position
local width = destination.static_params.width
local height = destination.static_params.height
local tries = 0
local ret = {{x = 0, y = 0}}
local max_exclusion_distance = 45
local maxtries = 2400
local args = {
static_params = destination.static_params,
noise_generator = Utils.noise_generator({}, 0),
}
while #ret < 8 and tries < maxtries do
local p2
if #ret == 1 then
p2 = {x = island_center.x + Math.random(-35, 10), y = island_center.y + Math.random(-40, 40)}
else
p2 = {x = island_center.x + Math.random(Math.ceil(-width/2), Math.ceil(width/2)), y = island_center.y + Math.random(Math.ceil(-height/2), Math.ceil(height/2))}
end
Common.ensure_chunks_at(surface, p2, 0.01)
local tile = surface.get_tile(p2)
if tile and tile.valid and tile.name then
if tile.name ~= 'sand-1' and tile.name ~= 'water' and tile.name ~= 'deepwater' then
local okay = true
local p3 = {x = p2.x + args.static_params.terraingen_coordinates_offset.x, y = p2.y + args.static_params.terraingen_coordinates_offset.y}
local farness = IslandsCommon.island_farness_1(args)(p3)
if (not okay) or (not (farness > 0.05 and farness < 0.55)) then
okay = false
end
local exclusion_distance = max_exclusion_distance * (maxtries - tries) / maxtries
if #ret == 1 then exclusion_distance = 15 * (maxtries - tries) / maxtries end
for _, p in pairs(ret) do
if (not okay) or Math.distance(p, p2) < exclusion_distance then
okay = false
end
end
if okay then
ret[#ret + 1] = p2
end
end
end
tries = tries + 1
end
if _DEBUG then
log('radioactive world locations took ' .. tries .. ' tries.')
end
if #ret < 8 then log('couldn\'t find four positions after 2400 tries') end
return ret
end
function Public.break_rock(surface, p, entity_name)
-- return Ores.try_ore_spawn(surface, p, entity_name)
end
local function radioactive_tick()
for _, id in pairs(Memory.get_global_memory().crew_active_ids) do
Memory.set_working_id(id)
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local tickinterval = 60
if destination.subtype == IslandsCommon.enum.RADIOACTIVE then
local ef = game.forces[memory.enemy_force_name]
-- faster evo (doesn't need difficulty scaling as higher difficulties have higher base evo):
local extra_evo = 0.25 * tickinterval/60 / Balance.expected_time_on_island() * Math.sloped(Common.difficulty(), 1/3)
ef.evolution_factor = ef.evolution_factor + extra_evo
if (not destination.dynamic_data.evolution_accrued_time) then
destination.dynamic_data.evolution_accrued_time = 0
end
destination.dynamic_data.evolution_accrued_time = destination.dynamic_data.evolution_accrued_time + extra_evo
-- faster pollute:
-- local pollution = 1000 * Common.difficulty() * tickinterval / 60
local pollution = 10 * (6 * Common.difficulty() * (Common.overworldx()/40)^(16/10) * (Balance.onthefly_scaling_with_players_rule())^(1/2)) / 3600 * tickinterval * (1 + 0.0004 * (destination.dynamic_data.timer or 0))
if not memory.floating_pollution then memory.floating_pollution = 0 end
memory.floating_pollution = memory.floating_pollution + pollution
game.pollution_statistics.on_flow('uranium-ore', pollution)
end
end
end
local event = require 'utils.event'
event.on_nth_tick(60, radioactive_tick)
return Public

View File

@@ -0,0 +1,90 @@
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Public = {}
Public.display_names = {'Sandworm Caldera'}
Public.discord_emoji = CoreData.comfy_emojis.mjau
Public.terraingen_frame_width = 700
Public.terraingen_frame_height = 700
Public.static_params_default = {
starting_time_of_day = 0,
daynightcycletype = 1,
solar_power_multiplier = 1,
default_decoratives = true,
base_starting_treasure = 0,
base_starting_rock_material = 8600,
base_starting_wood = 600,
}
function Public.base_ores() --here, just for the gui:
return {
['copper-ore'] = 5,
['iron-ore'] = 5,
['stone'] = 7,
}
end
local rscale = 180
local hscale = 0.16
Public.noiseparams = {
radius = {
type = 'simplex_2d',
normalised = false,
params = {
{wavelength = 0, amplitude = rscale * 1},
},
},
height_background = {
type = 'island1',
normalised = false,
params = {
-- {upperscale = 1000, amplitude = hscale * 200},
{upperscale = 1600, amplitude = hscale * 1},
{upperscale = 60, amplitude = hscale * 0.15},
},
},
forest = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 100, amplitude = 1},
},
},
ore = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 40, amplitude = 1, seedfactor = 2},
},
},
rock = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 120, amplitude = 1, seedfactor = 3},
},
},
mood = {
type = 'simplex_2d',
normalised = true,
params = {
{wavelength = 200, amplitude = 70},
},
},
}
return Public

View File

@@ -0,0 +1,426 @@
local ores = require "maps.pirates.ores"
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Structures = require 'maps.pirates.structures.structures'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Effects = require 'maps.pirates.effects'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Ores = require 'maps.pirates.ores'
local IslandsCommon = require 'maps.pirates.surfaces.islands.common'
local Hunt = require 'maps.pirates.surfaces.islands.hunt'
local Public = {}
Public.Data = require 'maps.pirates.surfaces.islands.red_desert.data'
function Public.noises(args)
local ret = {}
ret.height = IslandsCommon.island_height_1(args)
ret.height_background = args.noise_generator.height_background
ret.forest = args.noise_generator.forest
ret.forest_abs = function (p) return Math.abs(ret.forest(p)) end
ret.forest_abs_suppressed = function (p) return ret.forest_abs(p) - 1 * Math.slopefromto(ret.height(p), 0.17, 0.11) end
ret.rock = args.noise_generator.rock
ret.ore = args.noise_generator.ore
ret.rock_abs = function (p) return Math.abs(ret.rock(p)) end
ret.mood = args.noise_generator.mood
ret.farness = IslandsCommon.island_farness_1(args)
return ret
end
function Public.terrain(args)
local noises = Public.noises(args)
local p = args.p
if IslandsCommon.place_water_tile(args) then return end
if noises.height(p) < 0 then
args.tiles[#args.tiles + 1] = {name = 'water', position = args.p}
return
end
if noises.height(p) < 0.19 then
args.tiles[#args.tiles + 1] = {name = 'sand-1', position = args.p}
elseif noises.height(p) < 0.22 then
args.tiles[#args.tiles + 1] = {name = 'red-desert-3', position = args.p}
else
if noises.height_background(p) > 0.4 then
args.tiles[#args.tiles + 1] = {name = 'red-desert-2', position = args.p}
elseif noises.height_background(p) > -0.15 then
args.tiles[#args.tiles + 1] = {name = 'red-desert-1', position = args.p}
else
args.tiles[#args.tiles + 1] = {name = 'red-desert-0', position = args.p}
end
end
if noises.height(p) > 0.32 then
if noises.rock_abs(p) > 0.25 then
if noises.mood(p) < -0.5 then
local density = 0.003 * Math.slopefromto(noises.rock_abs(p), 0.25, 0.4)
local rng = Math.random()
if rng < density then
args.decoratives[#args.decoratives + 1] = {name = 'worms-decal', position = args.p}
end
end
if noises.mood(p) < 0.1 then
local rng = Math.random()
if rng < 0.0004 then
args.entities[#args.entities + 1] = {name = 'medium-remnants', position = args.p}
elseif rng < 0.0007 then
args.entities[#args.entities + 1] = {name = 'spidertron-remnants', position = args.p}
elseif rng < 0.001 then
args.entities[#args.entities + 1] = {name = 'medium-ship-wreck', position = args.p}
elseif rng < 0.0013 then
args.entities[#args.entities + 1] = {name = 'big-ship-wreck-2', position = args.p}
elseif rng < 0.0014 then
args.entities[#args.entities + 1] = {name = 'big-ship-wreck-1', position = args.p}
end
end
end
end
if noises.forest_abs_suppressed(p) > 0.85 then
local treedensity = 0.3 * Math.slopefromto(noises.forest_abs_suppressed(p), 0.85, 0.9)
if noises.forest(p) > 1.6 then
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'dry-hairy-tree', position = args.p, visible_on_overworld = true} end
elseif noises.forest(p) < -0.95 then
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'dead-tree-desert', position = args.p, visible_on_overworld = true} end
end
end
if noises.forest_abs_suppressed(p) < 0.65 then
if noises.height(p) > 0.15 then
if noises.rock_abs(p) > 0.25 then
local rockdensity = 1/200 * Math.slopefromto(noises.rock_abs(p), 0.25, 0.6)
local rockrng = Math.random()
if rockrng < rockdensity then
args.entities[#args.entities + 1] = IslandsCommon.random_rock_1(args.p)
elseif rockrng < rockdensity * 1.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-medium', position = args.p}
elseif rockrng < rockdensity * 2 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-small', position = args.p}
elseif rockrng < rockdensity * 2.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-tiny', position = args.p}
end
end
end
end
if noises.forest_abs_suppressed(p) < 0.8 and noises.mood(p) > -0.3 then
if noises.height(p) > 0.27 then
if noises.ore(p) > 1.5 then
args.entities[#args.entities + 1] = {name = 'copper-ore', position = args.p, amount = 20}
elseif noises.ore(p) < -1.5 then
args.entities[#args.entities + 1] = {name = 'iron-ore', position = args.p, amount = 20}
elseif noises.ore(p) < 0.041 and noises.ore(p) > -0.041 then
args.entities[#args.entities + 1] = {name = 'stone', position = args.p, amount = 10}
end
else
if noises.ore(p) > 2.2 then
args.entities[#args.entities + 1] = {name = 'copper-ore', position = args.p, amount = 10}
elseif noises.ore(p) < -2.2 then
args.entities[#args.entities + 1] = {name = 'iron-ore', position = args.p, amount = 10}
elseif noises.ore(p) < 0.010 and noises.ore(p) > -0.010 then
args.entities[#args.entities + 1] = {name = 'stone', position = args.p, amount = 5}
end
end
end
end
function Public.chunk_structures(args)
local rng = Math.random()
local left_top = args.left_top
local spec = function(p)
local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
return {
placeable = noises.height(p) > 0.05 and noises.mood(p) > -0.6 and noises.farness(p) > 0.1,
chanceper4chunks = 0.4,
}
end
-- initial attempt, to avoid placing two structures too close to each other, is to divide up the map into 2x2 chonks, and spawn once in each
local bool1, bool2 = left_top.x % 64 < 32, left_top.y % 64 < 32
local all_four_chunks = {
{x = left_top.x, y = left_top.y},
{x = left_top.x + (bool1 and 32 or -32), y = left_top.y},
{x = left_top.x, y = left_top.y + (bool2 and 32 or -32)},
{x = left_top.x + (bool1 and 32 or -32), y = left_top.y + (bool2 and 32 or -32)},
}
local chunks_loaded = args.chunks_loaded
if not chunks_loaded[args.left_top.x] then chunks_loaded[args.left_top.x] = {} end
chunks_loaded[args.left_top.x][args.left_top.y] = true
local nearby_chunks_generated_count = 0
for i=1,4 do
if chunks_loaded[all_four_chunks[i].x] and chunks_loaded[all_four_chunks[i].x][all_four_chunks[i].y] then
nearby_chunks_generated_count = nearby_chunks_generated_count + 1
end
end
if nearby_chunks_generated_count == 4 then --should trigger only once per 4 chunks
local avgleft_top = {
x = (all_four_chunks[1].x + all_four_chunks[4].x)/2,
y = (all_four_chunks[1].y + all_four_chunks[4].y)/2,
}
local leftmost_topmost = {
x = avgleft_top.x - 32,
y = avgleft_top.y - 32,
}
local spec2 = spec{x = avgleft_top.x + 16, y = avgleft_top.y + 16}
if rng < spec2.chanceper4chunks then
local rng2 = Math.random()
local struct
if rng2 < 28/100 then
struct = Structures.IslandStructures.ROC.shelter2
else
struct = Structures.IslandStructures.ROC.shelter1
end
if struct then
Structures.try_place(struct, args.specials, leftmost_topmost, 64, 64, function(p) return spec(p).placeable end)
end
end
end
end
function Public.break_rock(surface, p, entity_name)
-- return Ores.try_ore_spawn(surface, p, entity_name)
end
function Public.generate_silo_position()
return Hunt.free_position_1()
end
local function red_desert_tick()
for _, id in pairs(Memory.get_global_memory().crew_active_ids) do
Memory.set_working_id(id)
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
if destination.subtype == IslandsCommon.enum.RED_DESERT then
if memory.boat and memory.boat.surface_name and memory.boat.surface_name == destination.surface_name then
Public.underground_worms_ai()
if game.tick % 360 == 0 and destination.dynamic_data.timer and destination.dynamic_data.timer > 60 then
Public.custom_biter_ai()
end
end
end
end
end
local event = require 'utils.event'
event.on_nth_tick(30, red_desert_tick)
local worm_speed = 6.3 * 30/60
function Public.underground_worms_ai()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local player_force = game.forces[memory.force_name]
local enemy_force_name = memory.enemy_force_name
local evolution = game.forces[enemy_force_name].evolution_factor
if not destination.dynamic_data.worms_table then destination.dynamic_data.worms_table = {} end
local worms = destination.dynamic_data.worms_table
local indices_to_remove = {}
for i = #worms, 1, -1 do
local w = worms[i]
w.age = w.age + 1
-- despawn
if w.age > w.max_age then
indices_to_remove[#indices_to_remove + 1] = i
else
-- move
w.position = {x = w.position.x + worm_speed * w.direction.x, y = w.position.y + worm_speed * w.direction.y}
if w.chart_tag then w.chart_tag.destroy() end
local tile = surface.get_tile(w.position.x, w.position.y)
local on_land = tile and tile.valid and (not Utils.contains(CoreData.tiles_that_conflict_with_resource_layer, tile.name)) and (not Utils.contains(CoreData.noworm_tile_names, tile.name))
if on_land then
local solid_ground = (tile and tile.valid and Utils.contains(CoreData.worm_solid_tile_names, tile.name))
-- stomp
local big_bool = (w.age % 4 == 0)
Effects.worm_movement_effect(surface, w.position, solid_ground, big_bool)
w.chart_tag = player_force.add_chart_tag(surface, {icon = {type = 'virtual', name = 'signal-red'}, position = w.position})
if not solid_ground then
local nearby_characters = surface.find_entities_filtered{position = w.position, radius = 7, name = 'character'}
local character_outside = false
for j = 1, #nearby_characters do
local c = nearby_characters[j]
local t = surface.get_tile(c.position.x, c.position.y)
if not (t and t.valid and Utils.contains(CoreData.worm_solid_tile_names, t.name))
then
character_outside = true
break
end
end
if character_outside then
local type = Common.get_random_worm_type(evolution)
local emerge_position = surface.find_non_colliding_position(type, w.position, 3, 0.5)
if emerge_position then
local emerge_position_tile = surface.get_tile(emerge_position.x, emerge_position.y)
local can_emerge = (not solid_ground) and (not (tile and tile.valid and Utils.contains(CoreData.worm_solid_tile_names, emerge_position_tile.name)))
if can_emerge then
surface.create_entity{name = type, position = emerge_position, force = enemy_force_name}
Effects.worm_emerge_effect(surface, emerge_position)
indices_to_remove[#indices_to_remove + 1] = i
if w.chart_tag then w.chart_tag.destroy() end
end
end
end
end
end
end
end
for i = 1, #indices_to_remove do
local index = indices_to_remove[i]
for j = index, #worms-1 do
worms[j] = worms[j+1]
end
worms[#worms] = nil
end
local max_worms = 35
-- spawn worms
if game.tick % 210 == 0 then
if #worms < max_worms then
local island_center = destination.static_params.islandcenter_position
local r = Math.max(destination.static_params.width, destination.static_params.height)/2
local theta = Math.random()*5.75 - Math.pi/2+0.25
local p = {x = island_center.x + r*Math.sin(theta), y = island_center.y + r*Math.cos(theta)}
local theta2 = Math.random()*1.4-0.7
local d = {x = -Math.sin(theta+theta2), y = -Math.cos(theta+theta2)}
worms[#worms + 1] = {position = p, direction = d, age = 0, max_age = 2*r/worm_speed * Math.cos(theta2/2)}
end
end
end
function Public.custom_biter_ai()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local difficulty = memory.difficulty
local enemy_force_name = memory.enemy_force_name
local evolution = game.forces[enemy_force_name].evolution_factor
local fraction_of_floating_pollution = 1/2
local minimum_avg_units = 30
local maximum_units = 256
local pollution_available = memory.floating_pollution
local budget = fraction_of_floating_pollution * pollution_available
if budget >= minimum_avg_units * Common.averageUnitPollutionCost(evolution) then
local initialbudget = budget
local position = Hunt.position_away_from_players_1({static_params = destination.static_params}, 50)
local units_created_count = 0
local units_created = {}
local name = Common.get_random_unit_type(evolution)
local unittype_pollutioncost = CoreData.biterPollutionValues[name] * 1.1 * Balance.scripted_biters_pollution_cost_multiplier()
local function spawn(name)
units_created_count = units_created_count + 1
local p = surface.find_non_colliding_position(name, position, 50, 2)
if not p then return end
local biter = surface.create_entity({name = name, force = enemy_force_name, position = p})
units_created[#units_created + 1] = biter
memory.scripted_biters[biter.unit_number] = {entity = biter, created_at = game.tick}
return biter.unit_number
end
local whilesafety = 1000
while units_created_count < maximum_units and budget >= unittype_pollutioncost and #memory.scripted_biters < Common.total_max_biters and whilesafety > 0 do
whilesafety = whilesafety - 1
pollution_available = pollution_available - unittype_pollutioncost
budget = budget - unittype_pollutioncost
spawn(name)
end
game.pollution_statistics.on_flow(name, budget - initialbudget)
memory.floating_pollution = pollution_available
if (not units_created) or (not #units_created) or (#units_created == 0) then return end
Effects.biters_emerge(surface, position)
local position2 = surface.find_non_colliding_position('rocket-silo', position, 256, 2) or position
local unit_group = surface.create_unit_group({position = position2, force = enemy_force_name})
for _, unit in pairs(units_created) do
unit_group.add_member(unit)
end
memory.scripted_unit_groups[unit_group.group_number] = {ref = unit_group, script_type = 'burrowed'}
local target = {valid = true, position = {x = memory.boat.position.x - 60, y = memory.boat.position.y} or nil, name = 'boatarea'}
unit_group.set_command{
type = defines.command.attack_area,
destination = target.position,
radius = 30,
distraction = defines.distraction.by_anything
}
end
end
return Public

View File

@@ -0,0 +1,83 @@
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Public = {}
Public.display_names = {'Isle of Buried Treasure'}
Public.terraingen_frame_width = 896
Public.terraingen_frame_height = 896
Public.static_params_default = {
starting_time_of_day = 0,
daynightcycletype = 1,
default_decoratives = true,
base_starting_treasure = 1000,
base_starting_rock_material = 800,
base_starting_wood = 1200,
base_starting_treasure_maps = 6,
}
function Public.base_ores()
return {
['copper-ore'] = 2.4,
['iron-ore'] = 5.6,
['coal'] = 2.1,
['stone'] = 0.6,
}
end
local rscale = 250
local hscale = 0.1
Public.noiseparams = {
radius = {
type = 'simplex_2d',
normalised = false,
params = {
{wavelength = 0, amplitude = rscale * 1},
{wavelength = 1.6, amplitude = rscale * 0.3},
},
},
height_background = {
type = 'island1',
normalised = false,
params = {
-- {upperscale = 1000, amplitude = hscale * 200},
{upperscale = 1600, amplitude = hscale * 1},
{upperscale = 80, amplitude = hscale * 0.1},
},
},
forest = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 180, amplitude = 1},
-- {upperscale = 0, amplitude = 0.15},
},
},
rock = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 110, amplitude = 1, seedfactor = 2},
},
},
mood = {
type = 'simplex_2d',
normalised = true,
params = {
{wavelength = 250, amplitude = 70},
{wavelength = 50, amplitude = 20},
},
},
}
return Public

View File

@@ -0,0 +1,143 @@
local ores = require "maps.pirates.ores"
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Structures = require 'maps.pirates.structures.structures'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Ores = require 'maps.pirates.ores'
local IslandsCommon = require 'maps.pirates.surfaces.islands.common'
local Hunt = require 'maps.pirates.surfaces.islands.hunt'
local Public = {}
Public.Data = require 'maps.pirates.surfaces.islands.standard.data'
function Public.noises(args)
local ret = {}
ret.height = IslandsCommon.island_height_1(args)
ret.forest = args.noise_generator.forest
ret.forest_abs = function (p) return Math.abs(ret.forest(p)) end
ret.forest_abs_suppressed = function (p) return ret.forest_abs(p) - 1 * Math.slopefromto(ret.height(p), 0.17, 0.11) end
ret.rock = args.noise_generator.rock
ret.rock_abs = function (p) return Math.abs(ret.rock(p)) end
ret.mood = args.noise_generator.mood
ret.farness = IslandsCommon.island_farness_1(args)
return ret
end
function Public.terrain(args)
local noises = Public.noises(args)
local p = args.p
if IslandsCommon.place_water_tile(args) then return end
if noises.height(p) < 0 then
args.tiles[#args.tiles + 1] = {name = 'water', position = args.p}
return
end
if noises.height(p) < 0.05 then
args.tiles[#args.tiles + 1] = {name = 'sand-1', position = args.p}
if args.specials and noises.farness(p) > 0.02 and noises.farness(p) < 0.6 and Math.random(400) == 1 then
args.specials[#args.specials + 1] = {name = 'buried-treasure', position = args.p}
end
elseif noises.height(p) < 0.12 then
args.tiles[#args.tiles + 1] = {name = 'sand-2', position = args.p}
else
if noises.forest_abs_suppressed(p) > 0.3 and noises.rock(p) < 0.3 then
args.tiles[#args.tiles + 1] = {name = 'dry-dirt', position = args.p}
elseif noises.forest_abs_suppressed(p) > 0.15 and noises.rock(p) < 0.3 then
args.tiles[#args.tiles + 1] = {name = 'dirt-3', position = args.p}
else
args.tiles[#args.tiles + 1] = {name = 'dirt-2', position = args.p}
end
end
if noises.height(p) > 0.06 then
if noises.forest_abs_suppressed(p) > 0.5 then
if args.specials and noises.forest_abs_suppressed(p) < 0.75 and Math.random(2500) == 1 then
args.specials[#args.specials + 1] = {name = 'chest', position = args.p}
else
local forest_noise = noises.forest(p)
local treedensity = 0.7 * Math.slopefromto(noises.forest_abs_suppressed(p), 0.5, 0.7)
if forest_noise > 0 then
if noises.rock(p) > 0 then
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-06', position = args.p, visible_on_overworld = true} end
else
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-06-brown', position = args.p} end
end
elseif forest_noise < -1 then
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-03', position = args.p, visible_on_overworld = true} end
else
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-07', position = args.p} end
end
end
end
end
if noises.forest_abs_suppressed(p) < 0.45 then
if noises.height(p) > 0.12 then
if noises.rock_abs(p) > 0.22 then
local rockdensity = 1/600 * Math.slopefromto(noises.rock_abs(p), 0.22, 0.6) + 1/5 * Math.slopefromto(noises.rock_abs(p), 2.4, 2.6)
local rockrng = Math.random()
if rockrng < rockdensity then
args.entities[#args.entities + 1] = IslandsCommon.random_rock_1(args.p)
elseif rockrng < rockdensity * 1.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-medium', position = args.p}
elseif rockrng < rockdensity * 2 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-small', position = args.p}
elseif rockrng < rockdensity * 2.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-tiny', position = args.p}
end
end
end
end
end
function Public.chunk_structures(args)
local spec = function(p)
local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
return {
placeable = noises.farness(p) > 0.3,
-- spawners_indestructible = noises.farness(p) > 0.7,
spawners_indestructible = false,
density_perchunk = 30 * Math.slopefromto(noises.mood(p), 0.14, -0.1) * Math.slopefromto(noises.farness(p), 0.3, 1)^2 * args.biter_base_density_scale,
}
end
IslandsCommon.enemies_1(args, spec)
local spec2 = function(p)
local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
return {
placeable = noises.height(p) >= 0 and noises.forest_abs_suppressed(p) < 0.3 + Math.max(0, 0.2 - noises.height(p)),
chanceper4chunks = 0.5 * Math.slopefromto(noises.farness(p), 0.1, 0.4) * Math.slopefromto(noises.mood(p), 0, 0.25),
}
end
IslandsCommon.assorted_structures_1(args, spec2)
end
function Public.break_rock(surface, p, entity_name)
-- return Ores.try_ore_spawn(surface, p, entity_name)
end
function Public.generate_silo_position()
return Hunt.free_position_1()
end
return Public

View File

@@ -0,0 +1,83 @@
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Public = {}
Public.display_names = {'Secluded Dells'}
Public.terraingen_frame_width = 896
Public.terraingen_frame_height = 896
Public.static_params_default = {
starting_time_of_day = 0,
daynightcycletype = 1,
default_decoratives = true,
base_starting_treasure = 1000,
base_starting_rock_material = 800,
base_starting_wood = 1200,
base_starting_treasure_maps = 2,
}
function Public.base_ores()
return {
['copper-ore'] = 3.9,
['iron-ore'] = 3.9,
['coal'] = 2.1,
['stone'] = 1.7,
}
end
local rscale = 220
local hscale = 0.1
Public.noiseparams = {
radius = {
type = 'simplex_2d',
normalised = false,
params = {
{wavelength = 0, amplitude = rscale * 1},
{wavelength = 1.6, amplitude = rscale * 0.25},
},
},
height_background = {
type = 'island1',
normalised = false,
params = {
-- {upperscale = 1000, amplitude = hscale * 200},
{upperscale = 1600, amplitude = hscale * 1},
{upperscale = 80, amplitude = hscale * 0.1},
},
},
forest = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 90, amplitude = 1},
-- {upperscale = 0, amplitude = 0.15},
},
},
rock = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 110, amplitude = 1, seedfactor = 2},
},
},
mood = {
type = 'simplex_2d',
normalised = true,
params = {
{wavelength = 250, amplitude = 70},
{wavelength = 50, amplitude = 20},
},
},
}
return Public

View File

@@ -0,0 +1,143 @@
local ores = require "maps.pirates.ores"
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Structures = require 'maps.pirates.structures.structures'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Ores = require 'maps.pirates.ores'
local IslandsCommon = require 'maps.pirates.surfaces.islands.common'
local Hunt = require 'maps.pirates.surfaces.islands.hunt'
local Public = {}
Public.Data = require 'maps.pirates.surfaces.islands.standard_variant.data'
function Public.noises(args)
local ret = {}
ret.height = IslandsCommon.island_height_1(args)
ret.forest = args.noise_generator.forest
ret.forest_abs = function (p) return Math.abs(ret.forest(p)) end
ret.forest_abs_suppressed = function (p) return ret.forest_abs(p) - 1 * Math.slopefromto(ret.height(p), 0.17, 0.11) end
ret.rock = args.noise_generator.rock
ret.rock_abs = function (p) return Math.abs(ret.rock(p)) end
ret.mood = args.noise_generator.mood
ret.farness = IslandsCommon.island_farness_1(args)
return ret
end
function Public.terrain(args)
local noises = Public.noises(args)
local p = args.p
if IslandsCommon.place_water_tile(args) then return end
if noises.height(p) < 0 then
args.tiles[#args.tiles + 1] = {name = 'water', position = args.p}
return
end
if noises.height(p) < 0.05 then
args.tiles[#args.tiles + 1] = {name = 'sand-1', position = args.p}
if args.specials and noises.farness(p) > 0.02 and noises.farness(p) < 0.6 and Math.random(400) == 1 then
args.specials[#args.specials + 1] = {name = 'buried-treasure', position = args.p}
end
elseif noises.height(p) < 0.12 then
args.tiles[#args.tiles + 1] = {name = 'sand-2', position = args.p}
else
if noises.forest_abs_suppressed(p) > 0.3 and noises.rock(p) < 0.3 then
args.tiles[#args.tiles + 1] = {name = 'dirt-7', position = args.p}
elseif noises.forest_abs_suppressed(p) > 0.15 and noises.rock(p) < 0.3 then
args.tiles[#args.tiles + 1] = {name = 'grass-4', position = args.p}
else
args.tiles[#args.tiles + 1] = {name = 'grass-3', position = args.p}
end
end
if noises.height(p) > 0.06 then
if noises.forest_abs_suppressed(p) > 0.7 then
if args.specials and noises.forest_abs_suppressed(p) < 1 and Math.random(750) == 1 then -- high amounts of this
args.specials[#args.specials + 1] = {name = 'chest', position = args.p}
else
local forest_noise = noises.forest(p)
local treedensity = 0.7 * Math.slopefromto(noises.forest_abs_suppressed(p), 0.7, 0.75)
if forest_noise > 0 then
if noises.rock(p) > 0.05 then
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-08-red', position = args.p, visible_on_overworld = true} end
elseif noises.rock(p) < -0.05 then
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-09-brown', position = args.p} end
end
elseif forest_noise < -1.2 then
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-09', position = args.p, visible_on_overworld = true} end
else
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-02-red', position = args.p} end
end
end
end
end
if noises.forest_abs_suppressed(p) < 0.45 then
if noises.height(p) > 0.12 then
if noises.rock_abs(p) > 0.25 then
local rockdensity = 1/600 * Math.slopefromto(noises.rock_abs(p), 0.25, 0.6) + 1/5 * Math.slopefromto(noises.rock_abs(p), 2.4, 2.6)
local rockrng = Math.random()
if rockrng < rockdensity then
args.entities[#args.entities + 1] = IslandsCommon.random_rock_1(args.p)
elseif rockrng < rockdensity * 1.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-medium', position = args.p}
elseif rockrng < rockdensity * 2 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-small', position = args.p}
elseif rockrng < rockdensity * 2.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-tiny', position = args.p}
end
end
end
end
end
function Public.chunk_structures(args)
local spec = function(p)
local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
return {
placeable = noises.farness(p) > 0.3,
spawners_indestructible = false,
-- spawners_indestructible = noises.farness(p) > 0.7,
density_perchunk = 25 * Math.slopefromto(noises.mood(p), 0.16, -0.1) * Math.slopefromto(noises.farness(p), 0.3, 1)^2 * args.biter_base_density_scale,
}
end
IslandsCommon.enemies_1(args, spec)
local spec2 = function(p)
local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
return {
placeable = noises.height(p) >= 0 and noises.forest_abs_suppressed(p) < 0.3 + Math.max(0, 0.2 - noises.height(p)),
chanceper4chunks = 0.5 * Math.slopefromto(noises.farness(p), 0.1, 0.4) * Math.slopefromto(noises.mood(p), 0, 0.25),
}
end
IslandsCommon.assorted_structures_1(args, spec2)
end
function Public.break_rock(surface, p, entity_name)
-- return Ores.try_ore_spawn(surface, p, entity_name)
end
function Public.generate_silo_position()
return Hunt.free_position_1()
end
return Public

View File

@@ -0,0 +1,89 @@
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Public = {}
Public.display_names = {'Poisonous Fen'}
Public.terraingen_frame_width = 325
Public.terraingen_frame_height = 325
Public.static_params_default = {
starting_time_of_day = 0.4,
daynightcycletype = 1,
brightness_visual_weights = {0.1, 0.1, 0.1},
default_decoratives = true,
base_starting_treasure = 1000,
base_starting_rock_material = 800,
base_starting_wood = 1200,
base_starting_treasure_maps = 0,
}
function Public.base_ores()
return {
['copper-ore'] = 2.0,
['iron-ore'] = 2.0,
['coal'] = 3.4,
['stone'] = 0.5,
['crude-oil'] = 0.7,
}
end
local rscale = 170
Public.noiseparams = {
radius = {
type = 'simplex_2d',
normalised = false,
params = {
{wavelength = 0, amplitude = rscale * 1},
{wavelength = 2, amplitude = rscale * 0.2},
},
},
height_background = {
type = 'island1',
normalised = false,
params = {
-- {upperscale = 1000, amplitude = hscale * 200},
{upperscale = 600, amplitude = 0.1},
},
},
forest = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 70, amplitude = 1},
},
},
rock = {
type = 'forest1',
normalised = true,
params = {
{upperscale = 120, amplitude = 1, seedfactor = 2},
},
},
mood = {
type = 'simplex_2d',
normalised = true,
params = {
{wavelength = 250, amplitude = 70},
{wavelength = 50, amplitude = 20},
},
},
terrain = {
type = 'island1',
normalised = true,
params = {
{upperscale = 40, amplitude = 1, seedfactor = 2},
},
},
}
return Public

View File

@@ -0,0 +1,233 @@
local ores = require "maps.pirates.ores"
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Structures = require 'maps.pirates.structures.structures'
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Ores = require 'maps.pirates.ores'
local IslandsCommon = require 'maps.pirates.surfaces.islands.common'
local Hunt = require 'maps.pirates.surfaces.islands.hunt'
local Public = {}
Public.Data = require 'maps.pirates.surfaces.islands.swamp.data'
function Public.noises(args)
local ret = {}
ret.height = IslandsCommon.island_height_1(args)
ret.forest = args.noise_generator.forest
ret.forest_abs = function (p) return Math.abs(ret.forest(p)) end
ret.forest_abs_suppressed = function (p) return ret.forest_abs(p) - 1 * Math.slopefromto(ret.height(p), 0.35, 0.1) end
ret.terrain = args.noise_generator.terrain
ret.terrain_abs = function (p) return Math.abs(ret.terrain(p)) end
ret.rock = args.noise_generator.rock
ret.rock_abs = function (p) return Math.abs(ret.rock(p)) end
ret.mood = args.noise_generator.mood
ret.farness = IslandsCommon.island_farness_1(args)
return ret
end
function Public.terrain(args)
local noises = Public.noises(args)
local p = args.p
if IslandsCommon.place_water_tile(args) then return end
if noises.height(p) < 0 then
args.tiles[#args.tiles + 1] = {name = 'water', position = args.p}
return
end
local land = true
if noises.height(p) < 0.03 then
args.tiles[#args.tiles + 1] = {name = 'water-shallow', position = args.p}
land = false
-- elseif noises.height(p) < 0.07 then
-- args.tiles[#args.tiles + 1] = {name = 'grass-4', position = args.p}
else
if noises.terrain(p) < 0.4 then
args.tiles[#args.tiles + 1] = {name = 'grass-1', position = args.p}
elseif noises.terrain(p) < 0.55 then
args.tiles[#args.tiles + 1] = {name = 'grass-2', position = args.p}
else
args.tiles[#args.tiles + 1] = {name = 'water-mud', position = args.p}
land = false
end
end
if land then
if args.specials and Math.random(2500) == 1 then
args.specials[#args.specials + 1] = {name = 'chest', position = args.p}
else
if noises.forest_abs(p) > 0.15 then
local treedensity = 0.08 * Math.slopefromto(noises.forest_abs_suppressed(p), 0.15, 0.6) + 0.3 * Math.slopefromto(noises.forest_abs_suppressed(p), 0.65, 1.2)
if noises.forest(p) > 1.3 then
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-09-brown', position = args.p} end
else
if Math.random(1,100) < treedensity*100 then args.entities[#args.entities + 1] = {name = 'tree-08', position = args.p, visible_on_overworld = true} end
end
if noises.forest_abs_suppressed(p) < 0.7 then
if noises.height(p) > 0.12 then
if noises.rock_abs(p) > -0.15 then
local rockdensity = 1/600 * Math.slopefromto(noises.rock_abs(p), 0.22, 0.6) + 1/5 * Math.slopefromto(noises.rock_abs(p), 1.6, 1.8)
local rockrng = Math.random()
if rockrng < rockdensity then
args.entities[#args.entities + 1] = IslandsCommon.random_rock_1(args.p)
elseif rockrng < rockdensity * 1.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-medium', position = args.p}
elseif rockrng < rockdensity * 2 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-small', position = args.p}
elseif rockrng < rockdensity * 2.5 then
args.decoratives[#args.decoratives + 1] = {name = 'rock-tiny', position = args.p}
end
end
end
end
end
if noises.mood(p) > 0.3 then
local density = 0.001 * Math.slopefromto(noises.rock_abs(p), 0.25, 0.4)
local rng = Math.random()
if rng < density then
args.decoratives[#args.decoratives + 1] = {name = 'shroom-decal', position = args.p}
end
end
if noises.mood(p) < -0.3 then
local rng = Math.random()
if rng < 0.0015 then
args.decoratives[#args.decoratives + 1] = {name = 'lichen-decal', position = args.p}
end
end
local rng = Math.random()
if rng < 0.004 then
args.decoratives[#args.decoratives + 1] = {name = 'green-asterisk', position = args.p}
end
end
end
end
function Public.chunk_structures(args)
local spec = function(p)
local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
return {
placeable = noises.farness(p) > 0.3,
-- spawners_indestructible = noises.farness(p) > 0.75,
spawners_indestructible = false,
spawners_density_perchunk = 100 * Math.slopefromto(noises.mood(p), 0.7, 0.5) * Math.slopefromto(noises.farness(p), 0.35, 1)^2 * args.biter_base_density_scale,
worms_density_perchunk = 60 * Math.slopefromto(noises.mood(p), 0.7, 0.5) * Math.slopefromto(noises.farness(p), 0.25, 1)^2 * args.biter_base_density_scale,
}
end
IslandsCommon.enemies_specworms_separate(args, spec)
local spec2 = function(p)
local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
return {
placeable = noises.height(p) > 0.05,
chanceperchunk = 0.25 * Math.slopefromto(noises.farness(p), 0.05, 0.15),
}
end
Public.swamp_structures(args, spec2)
end
function Public.swamp_structures(args, spec)
local memory = Memory.get_crew_memory()
local overworldx = memory.overworldx or 0
local rng = Math.random()
local left_top = args.left_top
local spec2 = spec{x = left_top.x + 16, y = left_top.y + 16}
if rng < spec2.chanceperchunk then
local struct
struct = Structures.IslandStructures.ROC.swamp_lonely_storage_tank
if struct then
Structures.try_place(struct, args.specials, left_top, 64, 64, function(p) return spec(p).placeable end)
end
end
end
function Public.break_rock(surface, p, entity_name)
return Ores.try_ore_spawn(surface, p, entity_name)
end
function Public.generate_silo_position()
return Hunt.free_position_1()
end
local function swamp_tick()
for _, id in pairs(Memory.get_global_memory().crew_active_ids) do
Memory.set_working_id(id)
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
if destination.subtype == IslandsCommon.enum.SWAMP then
if memory.boat and memory.boat.surface_name and memory.boat.surface_name == destination.surface_name then
local surface = game.surfaces[destination.surface_name]
if not (surface and surface.valid) then return end
local island_center = destination.static_params.islandcenter_position
local width = destination.static_params.width
local height = destination.static_params.height
local area = width*height
local period = 5 * Math.ceil(7 / (area/(330*330)))
if game.tick % period == 0 then
local random_x = Math.random(island_center.x - width/2, island_center.x + width/2)
local random_y = Math.random(island_center.y - height/2, island_center.y + height/2)
local random_p = {x = random_x, y = random_y}
local tile = surface.get_tile(random_x, random_y)
if not (tile and tile.valid) then return end
if tile.name == 'water-mud' then
local nearby_characters = surface.find_entities_filtered{position = random_p, radius = 66, name = 'character'}
local nearby_characters_count = #nearby_characters
if nearby_characters_count >= 1 then
Common.create_poison_clouds(surface, random_p)
if Math.random(1, 3) == 1 then
local random_angles = {Math.rad(Math.random(359))}
Common.create_poison_clouds(surface, {x = random_x + 24 * Math.cos(random_angles[1]), y = random_y + 24 * Math.sin(random_angles[1])})
end
end
end
end
end
end
end
end
local event = require 'utils.event'
event.on_nth_tick(5, swamp_tick)
return Public

View File

@@ -0,0 +1,91 @@
local Common = require 'maps.pirates.common'
local Utils = require 'maps.pirates.utils_local'
local Math = require 'maps.pirates.math'
local Public = {}
Public.display_names = {'Frozen Pools'}
Public.terraingen_frame_width = 896
Public.terraingen_frame_height = 896
Public.static_params_default = {
starting_time_of_day = 0,
daynightcycletype = 3,
min_brightness = 0.3,
default_decoratives = false,
base_starting_rock_material = 800,
}
function Public.base_ores()
return {
['copper-ore'] = 1.7,
['iron-ore'] = 2.2,
['coal'] = 2.4,
['crude-oil'] = 4.4,
}
end
local rscale = 135
local hscale = 1/100
Public.noiseparams = {
radius = {
type = 'simplex_2d',
normalised = false,
params = {
{wavelength = 0, amplitude = rscale * 1.0},
{wavelength = 2.5, amplitude = rscale * 0.23},
},
},
height_background = {
type = 'simplex_2d',
normalised = false,
params = {
-- shape:
{wavelength = 1600, amplitude = hscale * 22},
{wavelength = 800, amplitude = hscale * 18},
{wavelength = 400, amplitude = hscale * 15},
{wavelength = 300, amplitude = hscale * 11},
{wavelength = 200, amplitude = hscale * 8},
{wavelength = 140, amplitude = hscale * 6},
{wavelength = 100, amplitude = hscale * 4},
-- edges:
{wavelength = 60, amplitude = hscale * 2.5},
{wavelength = 30, amplitude = hscale * 1.5},
{wavelength = 9, amplitude = hscale * 0.5}
},
},
walkways = {
type = 'simplex_2d',
normalised = false,
params = {
{wavelength = 300, amplitude = 15/100},
{wavelength = 65, amplitude = 90/100},
{wavelength = 7, amplitude = 5/100},
},
},
rock = {
type = 'simplex_2d',
normalised = true,
params = {
{wavelength = 100, amplitude = 80},
{wavelength = 50, amplitude = 20},
{wavelength = 6, amplitude = 20},
},
},
mood = {
type = 'simplex_2d',
normalised = true,
params = {
{wavelength = 250, amplitude = 70},
{wavelength = 50, amplitude = 20},
},
},
}
return Public

View File

@@ -0,0 +1,153 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Structures = require 'maps.pirates.structures.structures'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Data = require 'maps.pirates.surfaces.islands.walkways.data'
local Ores = require 'maps.pirates.ores'
local IslandsCommon = require 'maps.pirates.surfaces.islands.common'
local Hunt = require 'maps.pirates.surfaces.islands.hunt'
local Public = {}
Public.Data = require 'maps.pirates.surfaces.islands.walkways.data'
function Public.noises(args)
local ret = {}
ret.height = IslandsCommon.island_height_1(args)
ret.walkways = function (p) return Math.abs(args.noise_generator.walkways(p)) end
ret.rock = args.noise_generator.rock
ret.mood = args.noise_generator.mood
ret.farness = IslandsCommon.island_farness_1(args)
return ret
end
function Public.terrain(args)
local memory = Memory.get_crew_memory()
local noises = Public.noises(args)
local p = args.p
if IslandsCommon.place_water_tile(args) then return end
if noises.height(p) < 0.05 then
args.tiles[#args.tiles + 1] = {name = 'water-mud', position = p}
elseif noises.height(p) < 0.1 then
args.tiles[#args.tiles + 1] = {name = 'landfill', position = p}
if Math.random() < 1/50 then
args.decoratives[#args.decoratives + 1] = {name = 'brown-asterisk', position = p, amount = 1}
end
else
if noises.walkways(p) < 0.34 then
args.tiles[#args.tiles + 1] = {name = 'landfill', position = p}
if noises.walkways(p) <= 0.01 then
if Math.random(40) == 1 then
args.entities[#args.entities + 1] = {name = 'big-scorchmark-tintable', position = p}
end
elseif noises.walkways(p) <= 0.02 then
if Math.random(40) == 1 then
args.entities[#args.entities + 1] = {name = 'medium-scorchmark-tintable', position = p}
end
end
if Math.abs(noises.rock(p)) < 0.3 then
if Math.random() < 1/20 then
args.decoratives[#args.decoratives + 1] = {name = 'red-pita', position = p, amount = 1}
end
end
if noises.rock(p) > 0.2 then
if Math.random() < (0.25 - noises.walkways(p))/8 then
args.entities[#args.entities + 1] = IslandsCommon.random_rock_1(p)
end
elseif Math.random() < -(noises.rock(p) + 0.3)/2 then
args.decoratives[#args.decoratives + 1] = {name = 'red-croton', position = p, amount = 1}
end
else
args.tiles[#args.tiles + 1] = {name = 'water-shallow', position = p}
end
end
end
function Public.chunk_structures(args)
local spec = function(p)
local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
return {
placeable = noises.walkways(p) < 0.30,
density_perchunk = 20 * (noises.farness(p) - 0.1)^3 * args.biter_base_density_scale,
spawners_indestructible = true,
}
end
IslandsCommon.enemies_1(args, spec)
-- local spec2 = function(p)
-- local noises = Public.noises{p = p, noise_generator = args.noise_generator, static_params = args.static_params, seed = args.seed}
-- return {
-- placeable = noises.height(p) > 0.1 and noises.walkways(p) < 0.3,
-- chanceper4chunks = 1/2,
-- }
-- end
-- IslandsCommon.assorted_structures_1(args, spec2)
end
function Public.generate_silo_position()
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
local surface = game.surfaces[destination.surface_name]
local p_silo = Hunt.free_position_1(0.2)
local tiles = {}
for x = -6.5, 6.5, 1 do
for y = -6.5, 6.5, 1 do
tiles[#tiles + 1] = {name = CoreData.world_concrete_tile, position = {x = p_silo.x + x, y = p_silo.y + y}}
end
end
Common.ensure_chunks_at(surface, p_silo, 1)
surface.set_tiles(tiles, true)
return p_silo
end
function Public.break_rock(surface, p, entity_name)
return Ores.try_ore_spawn(surface, p, entity_name)
end
local function walkways_tick()
for _, id in pairs(Memory.get_global_memory().crew_active_ids) do
Memory.set_working_id(id)
local memory = Memory.get_crew_memory()
local destination = Common.current_destination()
if destination.subtype == IslandsCommon.enum.WALKWAYS then
for _, player in pairs(game.connected_players) do
if player.force.name == memory.force_name and player.surface == game.surfaces[destination.surface_name] and player.character and player.character.valid and game.surfaces[destination.surface_name].get_tile(player.position).name == 'water-shallow' then
player.character.damage(50, game.forces['environment'], 'fire')
if not (player.character and player.character.valid) then
Common.notify_force(player.force, player.name .. ' froze to death.')
end
end
end
end
end
end
local event = require 'utils.event'
event.on_nth_tick(90, walkways_tick)
return Public

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,286 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Structures = require 'maps.pirates.structures.structures'
local Token = require 'utils.token'
local Task = require 'utils.task'
local SurfacesCommon = require 'maps.pirates.surfaces.common'
local Effects = require 'maps.pirates.effects'
local Public = {}
local kraken_width = 31
local kraken_height = 31
local kraken_bps = {
[[0eNqd2tuOmzAQgOF38TWR8Nj4wKtUe5EmaIuUhSihh9Uq714IdtWLVpp/r1aRvh1mxgQYnA/z9fJ9uN7GaTH9h7lPx+thmQ+vt/G8ff5leuca8779eTRmPM3T3fRfVji+TsfLRpb362B6My7Dm2nMdHzbPv2c5/MwHU7fhvtitn+czsMayz5eGrOMl2EPcp3v4zLOUzmSfR7IhsefMOvhTrdhGdYQ/9HO6rTssSPSCelMtCDtWqSVPdkXVlqkE9LKKv2uEW6Rjkgri+xI2jt2BGeCbYs0iq1tSCA17tgTHAlGOWeCta0u2iKNMpGANOqfdtHjU3cEB4IjwVaQZrFRQwR1RLuQac/EIR2JFhRblN/fvGfCdCRaBGlllbYlJ2zREemEtLaFlbNctHfVypWXNmvJNaLogHRGWnsFr5xlrm66ZU0X1EVBd5/KA+OR8Yw4bIywUrUXjMod49rvqSOPQUVr73KVO8ZhMh3jgfHIeGI8I64+IR16BLAenQOerZJnq+TZKnm2Sp6tkmerxEbDylmpwkrVju4WzYdFe6QtC25h9I7xwHhkPDGeERe2psKSEZaM+gQr8yXSgrRjmbDgFkb3jHeMB8Yj44lx7QkT2RMhm6grd4x7xjvGA+ORce0yJTZzJLZMiTUysUYm1kj2xqFybSMza2RmubO3DtKSubNobeqVB8a1qaORWdi+jNjP5KLea7Fss4VN2CLkjUzRGWl1G9lMK2ymFYcKdahQNucVrh2vK1de7sSjQj0qlI1KhWuHQmHTiaAtI2F7RsIewgtXp452gorukGaZZKTVTWTPghI+00TtdCpoI0bQTkzRCemMtGWpqLvCnnYK1853lf+z1Jdm/wlF/9cPMhrzY7jdnwEkWR+zRO+Cz+sBH78BXJmyLg==]],
[[0eNqdmt2O2jAQRt/F19lVPPFfeJVqVbFgbSNBQJBti1Z59ybEqaoWtXN6hSKdDJ/HY/sbw4d5Pbzn86XrB7P5MNd+e34aTk9vl24/P383m6apzG3+GCvT7U791Ww+TWD31m8PMzLcztlsTDfko6lMvz3OT99Op33un3Zf8nUw84v9Pk+x7PhSmdwP3dDlJc794fa5fz++5ssEPI5QmfPpOr106osoG579XVb97Mex+iOOKOPUJcwc71GcRhmnkX8EcnRgc8RxTtfQHUqufkeXLxx/Rp4mZ3fJQzbz9z+EhcANgZ0OFg57HbxUaSCwVYZ2JPQCW4doJMQyJRHRSUd7kpIFjgRGMphoQUJEGTsQ2QHNTECDDEh2JLIjKr+IBrnQ4hGNlAhTosxJIglMaLUnlO6FFkF0g2jlntaSlLQoJQstNaK1J2RNdBdaK7zgWuV2OVRbRKu1FFwbXZCWhbY1wz3DA8O12ostsAwXhjcMdwz3DA8MjwxPDNdOk0ML1bG0M/9mmYGzzMFZZuEs83ArztKuPWFWnOVdWN6F5V1Y3rWOwXrSqFjknS0yzxa550K3iFbv7J5tpp4tU8+WqWfL1LNl6tkyZV3LirNpEjZNwqZJvQn4/1lIwjIj2swEcvlQaI9otRcIrNoDq/bAqj2wamfdq2Xt64qzOVWXQEQlENkWFlkNRFYDkdVAZDXAenvLmvsVTwxnk6qugYRqIKEzMrEzMrECS6wE2HWDZfcNKx4ZnhjO8t5o894iU4UuNAqtTiO70ii4dqBSE69Z6Ihoy4JrjcaKC8LVebHkcC90QLRluLZPWnHHcOU6EvSTi7DbmIKrpQuT3iDp7P6j4GrpDZPukHR2oSHsDkFYH77i2pGiTllYTyisJxTWtRVcmBh1HlG3IawfEObYC67eeiOSHtFeykyvMBcrzMVKQtITOkyZtRNm7QT5HfmL33mplj96bH7520hlvubL9f6+JOtiK9E1wbVTGz/+ALfE6PI=]],
[[0eNqdmctu4kAQRf+l10aiyv3kV0ZZMGBlLBEbgecRRfz7GOgezSZSnawipEP51u1HbuEP9/30czhfxmlxuw93nfbnzTJvXi/j8f75j9v1fefe739unRsP83R1u28rOL5O+9MdWd7Pg9u5cRneXOem/dv90+95Pg7T5vBjuC7u/sXpOKy15PbSuWU8Dc8i5/k6LuM8tSc9HiT+9q/M+rjDZViGtcRndEB0tNH+QXsCBwIjGUy0IiHKaidEZxsdiNmBmB2Qf5VOhNYe0ahJRV1a3Y7EwEh2a0QHMqK1icjtiNxODzoR2Npk+oIQ67LnB50JXAgsSIdVdSFCChJS0B4paGlkS3RX2iq84ioMVyMuTzFbhkeEK6tublWfYiCuDI8MTwwvCDcb2bNWWbYSFq6EpauGJ4Znhlt99+x4eLYjK94z3DM8MDwyPDE8I1yZM+b7+hmKekQXRJuPXmBbILAtENgWYJFYWCZueGY4812Z78p8V2akMiOVGanMSLUaGcnEJWhiEDQyVDohOiOaeWI+pZGdUjYbCRuOGs5sFOajMCPNOSayQBjZHRDZKU1sVdkw2HAoJjE8M9y6qpkdj8yMZBNnwyPDE8OtRhYWCAsLD4W1WtCq6hZl34YLwwPDrdrZWNvwwHAmRpkY66WnylpV1qp+RYz1Bm648eLQnvzTrrTZGDbVKptqK26dUBpuFeNJ9ql0QbS5UTYXKnsvoYFEwkpnRAsrbk0PiqKvouirLBEqS4QVt04nmshEUOmIaGHFhVWHjVrHMM1krlIWepSFHi3kBxBlqaThsLpneGC40Zi+xgxEK6KNtvSClMjnSl665+v33X8v8zv3a7hcH9/XLD4VTb6Pvqyb+fYX8FohZA==]],
[[0eNqV2dtq4zAQgOF30bUD0ehk+1WWXqSJ6BpSO8TeQyl599qxtOzFLsx/VQJf5NF0LI2UT/N6/ZFv92FcTP9p5vF0OyzT4e0+XLbPv03vXGM+tj+PxgznaZxN/22Fw9t4um5k+bhl05thye+mMePpffv0a5oueTycv+d5MdsXx0tex7KPl8YswzXvg9ymeViGaaxPej7IxsefYdbHne95yesQ/9ESdNo/NcKR4ESwRZpNUVDYoowkPLUnGI3cEtwRbFEc2lxHEkhEgexaPNLKsNMeyRHpRLQ27hZF0qKVYdfikFbG3e2RWKQj0SJIK2dpj3sownhEXJRpsZYFY1kwhXeIi7IUrbDYhcUuLHbHgincMx4Yj4wnxpU7hfUsM4U7xj3jgfHIeGIcJrJDXP02ebZweLREWtQvFK3dkyq3jLPQ1QUZWEEGVpCBFSTrvCpvGWf/VWGJFO3okTTGRQekI9IJ6RZpdTFGVoyRFWNkxci678phZli5CEuksEQKm6qwqcI3wx0Z166miS2+iS2+iRVwYgWcWAGzY1jlLeMd4sIyo72TsOxUWLll3DMeGIdTTYy3jHeIC8uM9tLBdqgL61gNsCN25YnxlnE2VW2vLEeSR2En+MoT4tq+vXLl+isWzZRdD1SeENdu2ZUrXyURVO3CbhMqT4hr3+vKtcE4NlV23i9c2/uIRxXmWejshF24tg8TdL0u6H5d2FFM2GFJ0IFGWCcurD2VRA5uRQek1a8d69gK1zbWwhqNwtWjs/20cO3oju1hju1hhcNgtCcUx3alwv89+kuz/7za//VjbWN+5vv8HEBa61Mnybvou3UZeXwB67xzTA==]]
}
Public.kraken_slots = 4
local kraken_positions = {
[1] = {first = {x = -40.5, y = -59.5}, second = {x = -15.5, y = -49.5}, third = {x = -32.5, y = -39.5}, final = {x = -24.5, y = -30.5},},
[2] = {first = {x = 28.5, y = -59.5}, second = {x = 10.5, y = -49.5}, third = {x = 30.5, y = -39.5}, final = {x = 13.5, y = -30.5},},
[3] = {first = {x = -40.5, y = 59.5}, second = {x = -15.5, y = 49.5}, third = {x = -32.5, y = 39.5}, final = {x = -24.5, y = 29.5},},
[4] = {first = {x = 28.5, y = 59.5}, second = {x = 10.5, y = 49.5}, third = {x = 30.5, y = 39.5}, final = {x = 13.5, y = 29.5},},
-- [1] = {first = {x = 96.5, y = 0.5}, second = {x = 81.5, y = 5.5}, third = {x = 66.5, y = -4.5}, final = {x = 51.5, y = 0.5},}
}
local kraken_tick_token =
Token.register(
function(data)
Public.kraken_tick(data.crew_id, data.kraken_id, data.step, data.substep)
end
)
function Public.kraken_tick(crew_id, kraken_id, step, substep)
Memory.set_working_id(crew_id)
local memory = Memory.get_crew_memory()
if not (memory.id and memory.id > 0) then return end --check if crew disbanded
if memory.game_lost then return end
local surface = game.surfaces[memory.sea_name]
local kraken_data = memory.active_sea_enemies.krakens[kraken_id]
if not kraken_data then return end --check if kraken died
if step == 1 then
if substep == 1 then
Effects.kraken_effect_3(surface, kraken_data.position, 10)
end
if substep < 32 then
Effects.kraken_effect_1(surface, kraken_data.position, substep/32 * 6.283)
Task.set_timeout_in_ticks(1, kraken_tick_token, {crew_id = crew_id, kraken_id = kraken_id, step = 1, substep = substep + 1})
else
Task.set_timeout_in_ticks(1, kraken_tick_token, {crew_id = crew_id, kraken_id = kraken_id, step = 2, substep = 1})
end
elseif step == 2 then
local p1 = kraken_positions[kraken_id].first
local p2 = kraken_positions[kraken_id].second
local p3 = kraken_positions[kraken_id].third
local p4 = kraken_positions[kraken_id].final
if substep <= 30 then
if substep < 5 then
Public.kraken_move(kraken_id, p1, substep % 4 + 1)
elseif substep < 10 then
Public.kraken_move(kraken_id, Utils.interpolate(p1, p2, (substep-5) / 5), substep % 4 + 1)
elseif substep < 15 then
Public.kraken_move(kraken_id, p2, substep % 4 + 1)
elseif substep < 20 then
Public.kraken_move(kraken_id, Utils.interpolate(p2, p3, (substep-15) / 5), substep % 4 + 1)
elseif substep < 25 then
Public.kraken_move(kraken_id, p3, substep % 4 + 1)
elseif substep <= 30 then
Public.kraken_move(kraken_id, Utils.interpolate(p3, p4, (substep-25) / 5), substep % 4 + 1)
end
Task.set_timeout_in_ticks(25, kraken_tick_token, {crew_id = crew_id, kraken_id = kraken_id, step = 2, substep = substep + 1})
else
Task.set_timeout_in_ticks(10, kraken_tick_token, {crew_id = crew_id, kraken_id = kraken_id, step = 3, substep = 1})
end
elseif step == 3 then
Public.kraken_move(kraken_id, kraken_data.position, substep % 4 + 1)
if substep % 4 == 0 then
local crewmembers = Common.crew_get_crew_members()
local p_can_fire_at = {}
for _, player in pairs(crewmembers) do
local p = player.position
if player.surface == surface then
-- if player.surface == surface and Public.on_boat(memory.boat, p) then
p_can_fire_at[#p_can_fire_at + 1] = p
end
end
if #p_can_fire_at > 0 then
local p_fire = p_can_fire_at[Math.random(#p_can_fire_at)]
local stream = surface.create_entity{
name = 'acid-stream-spitter-big',
position = kraken_data.position,
force = memory.enemy_force_name,
source = kraken_data.position,
target = p_fire,
max_range = 500,
speed = 0.1
}
memory.kraken_stream_registrations[#memory.kraken_stream_registrations + 1] = {number = script.register_on_entity_destroyed(stream), position = p_fire}
Effects.kraken_effect_4(surface, kraken_data.position)
end
end
if substep % 50 > 40 then
-- if substep % 70 == 69 then
-- Public.kraken_spawn_biters(kraken_id)
-- end
Task.set_timeout_in_ticks(5, kraken_tick_token, {crew_id = crew_id, kraken_id = kraken_id, step = 3, substep = substep + 1})
elseif substep % 50 > 30 then
Task.set_timeout_in_ticks(10, kraken_tick_token, {crew_id = crew_id, kraken_id = kraken_id, step = 3, substep = substep + 1})
else
Task.set_timeout_in_ticks(30, kraken_tick_token, {crew_id = crew_id, kraken_id = kraken_id, step = 3, substep = substep + 1})
end
end
end
local function on_entity_destroyed(event)
local registration_number = event.registration_number
local p
local memory
for i = 1,3 do
Memory.set_working_id(i)
memory = Memory.get_crew_memory()
if memory.kraken_stream_registrations then
for j, r in pairs(memory.kraken_stream_registrations) do
if r.number == registration_number then
p = r.position
memory.kraken_stream_registrations = Utils.ordered_table_with_index_removed(memory.kraken_stream_registrations, j)
break
end
end
end
if p then break end
end
if p then
local surface = game.surfaces[memory.sea_name]
if not surface and surface.valid then return end
local spits_here = surface.find_entities_filtered{position = p, radius = 0.5, name = 'acid-splash-fire-spitter-big'}
if spits_here and #spits_here > 0 then
for _, s in pairs(spits_here) do
if s.valid then s.destroy() end
end
end
local p2 = surface.find_non_colliding_position('small-biter', p, 10, 0.2)
if not p2 then return end
local name = Common.get_random_unit_type(game.forces[memory.enemy_force_name].evolution_factor + Balance.kraken_spawns_base_extra_evo)
surface.create_entity{name = name, position = p2, force = memory.enemy_force_name}
Effects.kraken_effect_2(surface, p2)
-- local evo_increase = Balance.kraken_evo_increase_per_shot()
-- memory.kraken_evo = memory.kraken_evo + evo_increase
-- game.forces[memory.enemy_force_name].evolution_factor = game.forces[memory.enemy_force_name].evolution_factor + evo_increase
end
end
function Public.try_spawn_kraken()
local memory = Memory.get_crew_memory()
local surface = game.surfaces[memory.sea_name]
if not (surface and surface.valid) then return end -- check sea still exists
if not memory.active_sea_enemies then memory.active_sea_enemies = {} end
if not memory.active_sea_enemies.krakens then memory.active_sea_enemies.krakens = {} end
local possible_slots = {}
for i = 1, Public.kraken_slots do
if not memory.active_sea_enemies.krakens[i] then
possible_slots[#possible_slots + 1] = i
end
end
if #possible_slots > 0 then
local kraken_id = possible_slots[Math.random(#possible_slots)]
-- if _DEBUG then game.print('spawning kraken in slot ' .. kraken_id) end
local p = kraken_positions[kraken_id].first
memory.active_sea_enemies.krakens[kraken_id] = {
state = 'submerged',
position = p,
max_health = Balance.kraken_health(),
spawner_entity = nil,
frame = nil,
}
Task.set_timeout_in_ticks(10, kraken_tick_token, {crew_id = memory.id, kraken_id = kraken_id, step = 1, substep = 1})
end
end
function Public.kraken_move(kraken_id, new_p, new_frame)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[memory.sea_name]
if not surface and surface.valid then return end -- check sea still exists
local kraken_data = memory.active_sea_enemies.krakens[kraken_id]
local kraken_tile = CoreData.kraken_tile
local old_p = kraken_data.position
local old_frame = kraken_data.frame
local new_p_2 = {x = Math.ceil(new_p.x), y = Math.ceil(new_p.y)}
local old_p_2 = {x = Math.ceil(old_p.x), y = Math.ceil(old_p.y)}
local new_tile_positions = Common.tile_positions_from_blueprint_arrayform(kraken_bps[new_frame], Utils.psum{new_p_2, {x = -16, y = -16}})
local old_tile_positions = {}
if old_frame then
old_tile_positions = Common.tile_positions_from_blueprint_arrayform(kraken_bps[old_frame], Utils.psum{old_p_2, {x = -16, y = -16}})
end
local new_tile_positions2 = Utils.exclude_position_arrays(new_tile_positions, old_tile_positions)
local tiles1 = {}
for x, xtab in pairs(new_tile_positions2) do
for y, _ in pairs(xtab) do
tiles1[#tiles1 + 1] = {name = kraken_tile, position = {x = x, y = y}}
end
end
surface.set_tiles(tiles1)
if kraken_data.spawner_entity and kraken_data.spawner_entity.valid then
kraken_data.spawner_entity.teleport(new_p_2.x - old_p_2.x, new_p_2.y - old_p_2.y)
else
kraken_data.spawner_entity = surface.create_entity{name = 'biter-spawner', position = new_p_2, force = memory.enemy_force_name}
Common.new_healthbar(kraken_id, true, kraken_data.spawner_entity, kraken_data.max_health)
end
if old_frame then --cleanup old tiles
local old_tile_positions2 = Utils.exclude_position_arrays(old_tile_positions, new_tile_positions)
local tiles2 = {}
for x, xtab in pairs(old_tile_positions2) do
for y, _ in pairs(xtab) do
tiles2[#tiles2 + 1] = {name = 'deepwater', position = {x = x, y = y}}
end
end
surface.set_tiles(tiles2, true, false)
end
kraken_data.position = new_p
kraken_data.frame = new_frame
end
function Public.kraken_die(kraken_id, unit_number)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[memory.sea_name]
if not surface and surface.valid then return end -- check sea still exists
local kraken_data = memory.active_sea_enemies.krakens[kraken_id]
if kraken_data.spawner_entity and kraken_data.spawner_entity.valid then
kraken_data.spawner_entity.destroy()
end
Effects.kraken_effect_5(surface, kraken_data.position)
local tiles2 = {}
for x = -16, 16 do
for y = -16, 16 do
tiles2[#tiles2 + 1] = {name = 'deepwater', position = Utils.psum{kraken_data.position, {x = x, y = y}}}
end
end
surface.set_tiles(tiles2, true, false)
memory.active_sea_enemies.krakens[kraken_id] = nil
local reward = Balance.kraken_kill_reward()
Common.give_reward_items(reward)
local force = game.forces[memory.force_name]
if not (force and force.valid) then return end
Common.notify_force_light(force,'Granted ' .. reward[1].count .. ' [item=sulfuric-acid-barrel]')
end
local event = require 'utils.event'
event.add(defines.events.on_entity_destroyed, on_entity_destroyed)
return Public

View File

@@ -0,0 +1,60 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Token = require 'utils.token'
local Task = require 'utils.task'
local Kraken = require 'maps.pirates.surfaces.sea.kraken'
local SurfacesCommon = require 'maps.pirates.surfaces.common'
local Public = {}
local enum = {
DEFAULT = 'Default',
}
Public.enum = enum
Public.Data = {}
Public.Data.width = 384
Public.Data.height = 384
function Public.ensure_sea_surface()
local memory = Memory.get_crew_memory()
local seaname = SurfacesCommon.encode_surface_name(memory.id, 0, SurfacesCommon.enum.SEA, enum.DEFAULT)
if not game.surfaces[seaname] then
local width = Public.Data.width
local height = Public.Data.height
local map_gen_settings = Common.default_map_gen_settings(width, height)
map_gen_settings.autoplace_settings.decorative.treat_missing_as_default = false
local surface = game.create_surface(seaname, map_gen_settings)
surface.freeze_daytime = true
surface.daytime = 0
surface.show_clouds = false
memory.sea_name = seaname
end
end
function Public.terrain(args)
args.tiles[#args.tiles + 1] = {name = 'deepwater', position = args.p}
local fishrng = Math.random(110)
if fishrng == 1 then
args.entities[#args.entities + 1] = {name = 'fish', position = args.p}
end
return
end
function Public.chunk_structures(args)
return
end
return Public

View File

@@ -0,0 +1,725 @@
local Memory = require 'maps.pirates.memory'
local Math = require 'maps.pirates.math'
local Balance = require 'maps.pirates.balance'
local Common = require 'maps.pirates.common'
local CoreData = require 'maps.pirates.coredata'
local Utils = require 'maps.pirates.utils_local'
local inspect = require 'utils.inspect'.inspect
local Boats = require 'maps.pirates.structures.boats.boats'
local Lobby = require 'maps.pirates.surfaces.lobby'
local Dock = require 'maps.pirates.surfaces.dock'
local Hold = require 'maps.pirates.surfaces.hold'
local Cabin = require 'maps.pirates.surfaces.cabin'
local Sea = require 'maps.pirates.surfaces.sea.sea'
local Islands = require 'maps.pirates.surfaces.islands.islands'
local Crowsnest = require 'maps.pirates.surfaces.crowsnest'
local Quest = require 'maps.pirates.quest'
local Parrot = require 'maps.pirates.parrot'
local ShopMerchants = require 'maps.pirates.shop.merchants'
local SurfacesCommon = require 'maps.pirates.surfaces.common'
local Server = require 'utils.server'
local Public = {}
local enum = SurfacesCommon.enum
Public.enum = enum
Public[enum.SEA] = require 'maps.pirates.surfaces.sea.sea'
Public[enum.ISLAND] = require 'maps.pirates.surfaces.islands.islands'
Public[enum.DOCK] = require 'maps.pirates.surfaces.dock'
Public[enum.CROWSNEST] = require 'maps.pirates.surfaces.crowsnest'
Public[enum.LOBBY] = require 'maps.pirates.surfaces.lobby'
Public[enum.HOLD] = require 'maps.pirates.surfaces.hold'
Public[enum.CABIN] = require 'maps.pirates.surfaces.cabin'
Public[enum.CHANNEL] = require 'maps.pirates.surfaces.channel.channel'
Public['SurfacesCommon'] = require 'maps.pirates.surfaces.common'
function Public.initialise_destination(o)
o = o or {}
local memory = Memory.get_crew_memory()
assert(memory.destinations, o.overworld_position)
local scope = Public.get_scope(o)
o.destination_index = #memory.destinations + 1 --assuming none are deleted
memory.destinations[o.destination_index] = o
o.dynamic_data = o.dynamic_data or {}
o.static_params = o.static_params or Utils.deepcopy(Public.get_scope(o).Data.static_params_default)
o.seed = o.seed or Math.random(1, 10000000)
o.iconized_map = o.iconized_map or {}
o.boat_extra_distance_from_shore = o.boat_extra_distance_from_shore or 0
o.surface_name = o.surface_name or SurfacesCommon.encode_surface_name(memory.id, o.destination_index, o.type, o.subtype)
o.dynamic_data.chunks_loaded = o.dynamic_data.chunks_loaded or {}
if o.type == enum.ISLAND then
o.init_boat_state = Boats.enum_state.APPROACHING
Public.generate_detailed_island_data(o)
elseif o.type == enum.DOCK then
o.init_boat_state = Boats.enum_state.APPROACHING
o.iconized_map_width = scope.Data.iconized_map_width
o.iconized_map_height = scope.Data.iconized_map_height
end
return o
end
function Public.get_scope(destination)
if destination.type then
if destination.subtype then
return Public[destination.type][destination.subtype]
else
return Public[destination.type]
end
else
return {}
end
end
function Public.on_surface_generation(destination)
local memory = Memory.get_crew_memory()
-- game.map_settings.pollution.enemy_attack_pollution_consumption_modifier = Balance.defaultai_attack_pollution_consumption_modifier()
-- Event_functions.flamer_nerfs()
if destination.type == enum.ISLAND then
local subtype = destination.subtype
destination.dynamic_data.rocketsilomaxhp = Balance.silo_max_hp
destination.dynamic_data.rocketsilohp = Balance.silo_max_hp
destination.dynamic_data.rocketsilonevercharged = true
destination.dynamic_data.rocketsiloenergyconsumed = 0
destination.dynamic_data.rocketsiloenergyconsumedwithinlasthalfsecond = 0
destination.dynamic_data.energychargedinsilosincelastcheck = 0
destination.dynamic_data.silocharged = false
destination.dynamic_data.rocketlaunched = false
if subtype ~= Islands.enum.STANDARD and subtype ~= Islands.enum.STANDARD_VARIANT and subtype ~= Islands.enum.RADIOACTIVE and subtype ~= Islands.enum.RED_DESERT then
destination.dynamic_data.hidden_ore_remaining_abstract = Utils.deepcopy(destination.static_params.abstract_ore_amounts)
end
destination.dynamic_data.wood_remaining = destination.static_params.starting_wood
destination.dynamic_data.rock_material_remaining = destination.static_params.starting_rock_material
destination.dynamic_data.treasure_remaining = destination.static_params.starting_treasure
destination.dynamic_data.ore_types_spawned = {}
destination.dynamic_data.buried_treasure = {}
elseif destination.type == enum.DOCK then
end
end
function Public.destination_on_arrival(destination)
local memory = Memory.get_crew_memory()
-- game.map_settings.pollution.enemy_attack_pollution_consumption_modifier = Balance.defaultai_attack_pollution_consumption_modifier()
-- Event_functions.flamer_nerfs()
memory.floating_pollution = 0
if destination.type == enum.ISLAND then
destination.dynamic_data.rocketsiloenergyneeded = Balance.silo_energy_needed_MJ() * 1000000
destination.dynamic_data.rocketgoldreward = Balance.launch_gold_reward()
if destination.subtype == Islands.enum.RADIOACTIVE then
destination.dynamic_data.time_remaining = -1
else
destination.dynamic_data.time_remaining = Math.ceil(Balance.max_time_on_island())
end
if destination.subtype ~= Islands.enum.FIRST and destination.subtype ~= Islands.enum.RADIOACTIVE then
Quest.initialise_random_quest()
else
-- if _DEBUG then
-- Quest.initialise_random_quest()
-- end
end
game.forces[memory.enemy_force_name].reset_evolution()
local base_evo = Balance.base_evolution()
game.forces[memory.enemy_force_name].evolution_factor = base_evo
destination.dynamic_data.evolution_accrued_leagues = base_evo
destination.dynamic_data.evolution_accrued_time = 0
destination.dynamic_data.evolution_accrued_nests = 0
destination.dynamic_data.evolution_accrued_silo = 0
memory.scripted_biters = {}
memory.scripted_unit_groups = {}
memory.floating_pollution = 0
if destination.subtype == Islands.enum.RADIOACTIVE then
Islands[Islands.enum.RADIOACTIVE].spawn_structures()
end
if destination and destination.surface_name and game.surfaces[destination.surface_name] and game.surfaces[destination.surface_name].valid and (not (destination.dynamic_data and destination.dynamic_data.initial_spawner_count)) then
--Note: This gives the wrong answer on the first island. Because the terrain hasn't finished generating yet.
destination.dynamic_data.initial_spawner_count = Common.spawner_count(game.surfaces[destination.surface_name])
end
-- -- invulnerable bases on islands 21-25
-- if memory.overworldx >= 21 and memory.overworldx < 25 then
-- local surface = game.surfaces[destination.surface_name]
-- if not (surface and surface.valid) then return end
-- local spawners = surface.find_entities_filtered({type = 'unit-spawner', force = memory.enemy_force_name})
-- for _, s in pairs(spawners) do
-- s.destructible = false
-- end
-- end
elseif destination.type == enum.DOCK then
-- -- kick players out of crow's nest
-- local crowsnestname = SurfacesCommon.encode_surface_name(memory.id, 0, enum.CROWSNEST, nil)
-- for _, player in pairs(game.connected_players) do
-- if player.surface.name == crowsnestname then
-- Public.player_exit_crows_nest(player, {x = 5, y = 0})
-- end
-- end
end
local name = destination.static_params.name and destination.static_params.name or 'NameNotFound'
local message = 'Approaching destination ' .. (memory.destinationsvisited_indices and #memory.destinationsvisited_indices or 0) .. ', ' .. name .. '.'
if not (#memory.destinationsvisited_indices and #memory.destinationsvisited_indices == 1) then --don't need to notify for the first island
Server.to_discord_embed_raw((destination.static_params.discord_emoji or CoreData.comfy_emojis.wut) .. '[' .. memory.name .. '] ' .. message)
end
if destination.static_params.name == 'Dock' then
message = message .. ' ' .. 'Extra trades are available in the shop.'
end
Common.notify_force(game.forces[memory.force_name], message)
if destination.type == enum.ISLAND then
local points_to_avoid = {}
if destination.subtype ~= Islands.enum.RADIOACTIVE then
local silo_position = Islands.spawn_silo_setup()
points_to_avoid[#points_to_avoid + 1] = {x = silo_position.x, y = silo_position.y, r = 22}
end
Islands.spawn_ores_on_shorehit(destination, points_to_avoid)
if memory.overworldx >= Balance.covered_first_appears_at or _DEBUG then
local covered = Islands.spawn_covered(destination, points_to_avoid)
points_to_avoid[#points_to_avoid + 1] = {x = covered.x, y = covered.y, r = 25}
end
Islands.spawn_treasure_maps(destination, points_to_avoid)
Islands.spawn_ghosts(destination, points_to_avoid)
end
end
function Public.destination_on_crewboat_hits_shore(destination)
local memory = Memory.get_crew_memory()
local boat = memory.boat
destination.dynamic_data.timeratlandingtime = Common.current_destination().dynamic_data.timer
Boats.place_landingtrack(boat, CoreData.landing_tile)
Boats.place_boat(boat, CoreData.static_boat_floor, false, false)
if destination.type == enum.ISLAND then
if memory.overworldx == 0 then
Parrot.parrot_0()
elseif memory.overworldx == 40 then
Parrot.parrot_40()
elseif memory.overworldx == 80 then
Parrot.parrot_80()
end
if destination.subtype == Islands.enum.RADIOACTIVE then
-- replace all miners, so that they sit on uranium properly:
local surface = game.surfaces[destination.surface_name]
local miners = surface.find_entities_filtered({name = 'electric-mining-drill'})
for _, m in pairs(miners) do
local direction = m.direction
local position = m.position
m.destroy()
surface.create_entity{name = 'electric-mining-drill', direction = direction, position = position}
end
Parrot.parrot_radioactive_tip_2()
end
if memory.merchant_ships_unlocked or _DEBUG then
Islands.spawn_merchant_ship(destination)
ShopMerchants.generate_merchant_trades(destination.dynamic_data.merchant_market)
end
end
end
function Public.generate_detailed_island_data(destination)
local scope = Public.get_scope(destination)
local frame_width = scope.Data.terraingen_frame_width
local frame_height = scope.Data.terraingen_frame_height
local boat_extra_distance_from_shore = destination.boat_extra_distance_from_shore
-- scale 1:32
local chunks_horizontal = 2 * Math.floor(frame_width/64)
local chunks_vertical = 2 * Math.floor(frame_height/64)
local entities = {}
local entitymap = {}
local tiles = {}
local tiles2 = {}
local leftboundary, rightboundary, topboundary, bottomboundary = chunks_horizontal/2 + 1, -chunks_horizontal/2 - 1, chunks_vertical/2 + 1, -chunks_vertical/2 - 1 -- reversed, because we'll iterate
-- local subtype = destination.subtype
local terrain_fn = scope.terrain
local noise_generator = Utils.noise_generator(scope.Data.noiseparams, destination.seed)
for y = -chunks_vertical/2, chunks_vertical/2 - 1, 1 do
for x = -chunks_horizontal/2, chunks_horizontal/2 - 1, 1 do
local macroposition = {x = x + 0.5, y = y + 0.5}
local chunk_frameposition_topleft = {x = x * 32, y = y * 32}
-- average over the chunk
local modalcounts = {}
for y2 = 5, 27, 11 do
for x2 = 5, 27, 11 do
local p2 = {x = chunk_frameposition_topleft.x + x2, y = chunk_frameposition_topleft.y + y2}
local tiles3, entities3 = {}, {}
terrain_fn{p = p2, noise_generator = noise_generator, static_params = destination.static_params, tiles = tiles3, entities = entities3, decoratives = {}, seed = destination.seed}
local tile = tiles3[1]
if modalcounts[tile.name] then
modalcounts[tile.name] = modalcounts[tile.name] + 1
else
modalcounts[tile.name] = 1
end
if y2 == 16 and x2 == 16 and #entities3 > 0 and entities3[1] and entities3[1].visible_on_overworld then
entitymap[macroposition] = entities3[1].name
end
end
end
local modaltile, max = 'hazard-concrete-left', 0
for k, v in pairs(modalcounts) do
if v > max then
modaltile, max = k, v
end
end
tiles[#tiles + 1] = {name = modaltile, position = macroposition}
if (not Utils.contains(CoreData.water_tile_names, modaltile)) then
leftboundary, rightboundary, topboundary, bottomboundary = Math.min(leftboundary, x), Math.max(rightboundary, x + 1), Math.min(topboundary, y), Math.max(bottomboundary, y + 1)
end
end
end
leftboundary, rightboundary, topboundary, bottomboundary = leftboundary - 1, rightboundary + 1, topboundary - 1, bottomboundary + 1 --push out by one step to get some water
-- construct image, and record where entities can be placed:
local positions_free_to_hold_resources = {}
for _, tile in pairs(tiles) do
local x = tile.position.x
local y = tile.position.y
if tile.name ~= 'water' and x >= leftboundary and x <= rightboundary and y >= topboundary and y <= bottomboundary then --nil represents water
--arrange image so that {0,0} is on the centre of the left edge:
local p = {x = x - leftboundary, y = y - (topboundary + bottomboundary)/2}
if (topboundary + bottomboundary)/2 % 1 ~= 0 then
p.y = p.y + 0.5 --adjust so that tiles land on half-integer positions
end
tiles2[#tiles2 + 1] = {name = tile.name, position = p}
if (not Utils.contains(CoreData.tiles_that_conflict_with_resource_layer, tile.name)) then
local ename = entitymap[tile.position]
if ename then
entities[#entities + 1] = {name = ename, position = p}
else
if (p.x + 2) % 4 <= 2 and (p.y) % 4 <= 2 then --for the ingame minimap, the ore texture checker only colors these squares
local nearby_es = {
entitymap[{x = tile.position.x + 1, y = tile.position.y}],
entitymap[{x = tile.position.x - 1, y = tile.position.y}],
entitymap[{x = tile.position.x, y = tile.position.y + 1}],
entitymap[{x = tile.position.x, y = tile.position.y - 1}],
}
if not (nearby_es[1] or nearby_es[2] or nearby_es[3] or nearby_es[4]) then
positions_free_to_hold_resources[#positions_free_to_hold_resources + 1] = p
-- if destination.destination_index == 3 then
-- game.print(p)
-- end
end
end
end
end
end
end
if #positions_free_to_hold_resources > 0 then
local orestoadd = {}
for k, v in pairs(destination.static_params.abstract_ore_amounts) do
local count = Math.ceil(v^(1/2))
if k == 'crude-oil' then
orestoadd[k] = {count = count, sizing_each = Common.oil_abstract_to_real(v)/count}
else
orestoadd[k] = {count = count, sizing_each = Common.ore_abstract_to_real(v)/count}
end
end
for k, v in pairs(orestoadd) do
for i = 1, v.count do
if #positions_free_to_hold_resources > 0 then
local random_index = Math.random(#positions_free_to_hold_resources)
local p = positions_free_to_hold_resources[random_index]
entities[#entities + 1] = {name = k, position = p, amount = v.sizing_each}
for j = random_index, #positions_free_to_hold_resources - 1 do
positions_free_to_hold_resources[j] = positions_free_to_hold_resources[j+1]
end
positions_free_to_hold_resources[#positions_free_to_hold_resources] = nil
end
end
end
end
-- get more precise understanding of left-hand shore
local xcorrection = 0
for ystep = -10, 10, 10 do
for xstep = 0,300,3 do
local x = leftboundary * 32 + 16 + xstep
local y = (topboundary*32 + bottomboundary*32)/2 + ystep
local tiles3 = {}
terrain_fn{p = {x = x, y = y}, noise_generator = noise_generator, static_params = destination.static_params, tiles = tiles3, entities = {}, decoratives = {}, seed = destination.seed}
local tile = tiles3[1]
if (not Utils.contains(CoreData.water_tile_names, tile.name)) then
xcorrection = Math.max(xcorrection, xstep + Math.abs(ystep))
break
end
end
end
-- if xcorrection == 0 then xcorrection = 300 end
local iconwidth, iconheight = rightboundary - leftboundary, bottomboundary - topboundary
iconwidth = iconwidth > 0 and iconwidth or 0 --make them 0 if negative
iconheight = iconheight > 0 and iconheight or 0
local extension_to_left = Math.ceil(Common.boat_default_starting_distance_from_shore + boat_extra_distance_from_shore + Common.mapedge_distance_from_boat_starting_position - xcorrection)
local terraingen_coordinates_offset = {x = (leftboundary*32 + rightboundary*32)/2 - extension_to_left/2, y = (topboundary*32 + bottomboundary*32)/2}
local width = rightboundary*32 - leftboundary*32 + extension_to_left
local height = bottomboundary*32 - topboundary*32
local deepwater_terraingenframe_xposition = leftboundary*32 - Common.deepwater_distance_from_leftmost_shore
local islandcenter_position = {x = extension_to_left/2, y = 0}
local deepwater_xposition = deepwater_terraingenframe_xposition - terraingen_coordinates_offset.x
-- -- must ceil this, because if it's a half integer big things will teleport badly:
-- local boat_starting_xposition = Math.ceil(- width/2 + Common.mapedge_distance_from_boat_starting_position)
-- worse, must make this even due to rails:
local boat_starting_xposition = 2*Math.ceil(
(- width/2 + Common.mapedge_distance_from_boat_starting_position)/2
)
destination.static_params.terraingen_coordinates_offset = terraingen_coordinates_offset
destination.static_params.width = width
destination.static_params.height = height
destination.static_params.islandcenter_position = islandcenter_position
destination.static_params.deepwater_xposition = deepwater_xposition
destination.static_params.deepwater_terraingenframe_xposition = deepwater_terraingenframe_xposition
destination.static_params.boat_starting_xposition = boat_starting_xposition
destination.iconized_map.tiles = tiles2
destination.iconized_map.entities = entities
destination.iconized_map_width = iconwidth
destination.iconized_map_height = iconheight
end
function Public.create_surface(destination)
local surface_name = destination.surface_name
if game.surfaces[surface_name] then return end
-- maybe can set width and height to be 0 here? if so, will need to change references to map_gen_settings.width elsewhere in code
-- local mgs = Utils.deepcopy(Common.default_map_gen_settings(
-- self.static_params.width or 512,
-- self.static_params.height or 512,
-- self.seed or Math.random(1, 1000000)
-- ))
local mgs = Utils.deepcopy(Common.default_map_gen_settings(
Math.max(0,destination.static_params.width) or 128,
Math.max(0,destination.static_params.height) or 128,
destination.seed or Math.random(1, 1000000)
))
--todo: put into static_params
mgs.autoplace_settings.decorative.treat_missing_as_default = destination.static_params.default_decoratives
local surface = game.create_surface(surface_name, mgs)
surface.solar_power_multiplier = destination.static_params.solar_power_multiplier or 1
surface.show_clouds = destination.static_params.clouds or false
surface.min_brightness = destination.static_params.min_brightness or 0
surface.brightness_visual_weights = destination.static_params.brightness_visual_weights or {1, 1, 1}
surface.daytime = destination.static_params.starting_time_of_day or 0
local daynightcycletype = destination.static_params.daynightcycletype or 1
local ticksperday = CoreData.daynightcycle_types[daynightcycletype].ticksperday or 0
if ticksperday == 0 then
surface.freeze_daytime = true
ticksperday = ticksperday + 1 -- avoid divide by zero
else
surface.freeze_daytime = false
end
surface.ticks_per_day = ticksperday
Public.on_surface_generation(destination)
end
function Public.clean_up(destination)
local memory = Memory.get_crew_memory()
local oldsurface = game.surfaces[destination.surface_name]
if not (oldsurface and oldsurface.valid) then return end
-- assuming sea is always default subtype:
local seasurface = game.surfaces[memory.sea_name]
Quest.try_resolve_quest()
destination.dynamic_data.quest_type = nil
destination.dynamic_data.quest_reward = nil
destination.dynamic_data.quest_progress = nil
destination.dynamic_data.quest_progressneeded = nil
destination.dynamic_data.quest_complete = nil
-- handle players that were left on the island
-- if there is more than one crew on a surface, this will need to be generalised
for _, player in pairs(game.connected_players) do
if (player.surface == oldsurface) then
if player.character and player.character.valid then player.character.die(game.forces[memory.force_name]) end
player.teleport(memory.spawnpoint, seasurface)
end
end
destination.dynamic_data = {}
memory.scripted_biters = nil
memory.scripted_unit_groups = nil
memory.floating_pollution = nil
if memory.enemy_force_name then
local ef = game.forces[memory.enemy_force_name]
if ef and ef.valid then
game.forces[memory.enemy_force_name].reset_evolution()
local base_evo = Balance.base_evolution()
game.forces[memory.enemy_force_name].evolution_factor = base_evo
end
end
game.delete_surface(oldsurface)
end
-- function Public.crowsnest_init_destinations()
-- local memory = Memory.get_crew_memory()
-- local tiles, entities = {}, {}
-- Overworld.try_overworld_move{x = 0, y = 0}
-- -- for _, destination_data in pairs(memory.destinations) do
-- -- local iconized_map = SurfacesCommon.fetch_iconized_map(destination_data.destination_index)
-- -- for _, t in pairs(iconized_map.tiles) do
-- -- local x = Crowsnest.platformrightmostedge + destination_data.overworld_position.x + t.position.x
-- -- local y = destination_data.overworld_position.y + t.position.y
-- -- if Math.abs(x) < Crowsnest.Data.width/2 and Math.abs(y) < Crowsnest.Data.height/2 then
-- -- tiles[#tiles+1] = {name = t.name, position = {x = x, y = y}}
-- -- end
-- -- end
-- -- for _, e in pairs(iconized_map.entities) do
-- -- local x = Crowsnest.platformrightmostedge + destination_data.overworld_position.x + e.position.x
-- -- local y = destination_data.overworld_position.y + e.position.y
-- -- if Math.abs(x) < Crowsnest.Data.width/2 then
-- -- local e2 = Utils.deepcopy(e)
-- -- e2.position = {x = x, y = y}
-- -- entities[#entities+1] = e2
-- -- end
-- -- end
-- -- end
-- -- Crowsnest.update_surface(tiles, entities)
-- end
function Public.player_goto_crows_nest(player, player_relative_pos)
local memory = Memory.get_crew_memory()
local surface = game.surfaces[SurfacesCommon.encode_surface_name(memory.id, 0, enum.CROWSNEST, nil)]
local carpos
if player_relative_pos.x < 0 then
carpos = {x = -2.29687, y = 0}
else
carpos = {x = 3.29687, y = 0}
end
local newpos = {x = memory.overworldx + carpos.x - player_relative_pos.x, y = memory.overworldy + carpos.y + player_relative_pos.y}
local newpos2 = surface.find_non_colliding_position('character', newpos, 5, 0.2) or newpos
if newpos2 then player.teleport(newpos2, surface) end
-- player.minimap_enabled = false
end
function Public.player_exit_crows_nest(player, player_relative_pos)
local memory = Memory.get_crew_memory()
local surface
if memory.boat and (memory.boat.state == Boats.enum_state.ATSEA_SAILING or memory.boat.state == Boats.enum_state.ATSEA_LOADING_MAP) then
surface = game.surfaces[SurfacesCommon.encode_surface_name(memory.id, 0, Public.enum.SEA, Public.Sea.enum.DEFAULT)]
else
surface = game.surfaces[Common.current_destination().surface_name]
end
local carpos
if player_relative_pos.x > 0 then
carpos = Boats.get_scope(memory.boat).Data.entercrowsnest_cars.right
else
carpos = Boats.get_scope(memory.boat).Data.entercrowsnest_cars.left
end
local newpos = {x = memory.boat.position.x + carpos.x - player_relative_pos.x, y = memory.boat.position.y + carpos.y + player_relative_pos.y}
local newpos2 = surface.find_non_colliding_position('character', newpos, 10, 0.2) or newpos
if newpos2 then player.teleport(newpos2, surface) end
-- player.minimap_enabled = true
end
function Public.player_goto_hold(player, relative_pos, nth)
local memory = Memory.get_crew_memory()
local surface = Hold.get_hold_surface(nth)
local newpos = {x = Hold.Data.loco_offset.x + 1 + relative_pos.x, y = Hold.Data.loco_offset.y + relative_pos.y}
local newpos2 = surface.find_non_colliding_position('character', newpos, 5, 0.2) or newpos
if newpos2 then player.teleport(newpos2, surface) end
end
function Public.player_exit_hold(player, relative_pos)
local memory = Memory.get_crew_memory()
local surface
if memory.boat and (memory.boat.state == Boats.enum_state.ATSEA_SAILING or memory.boat.state == Boats.enum_state.ATSEA_LOADING_MAP) then
surface = game.surfaces[SurfacesCommon.encode_surface_name(memory.id, 0, Public.enum.SEA, Public.Sea.enum.DEFAULT)]
else
surface = game.surfaces[Common.current_destination().surface_name]
end
local locopos = Boats.get_scope(memory.boat).Data.loco_pos
local newpos = {x = memory.boat.position.x + locopos.x + relative_pos.x, y = memory.boat.position.y + locopos.y + relative_pos.y}
local newpos2 = surface.find_non_colliding_position('character', newpos, 10, 0.2) or newpos
if newpos2 then player.teleport(newpos2, surface) end
end
function Public.player_goto_cabin(player, relative_pos)
local memory = Memory.get_crew_memory()
local surface = Cabin.get_cabin_surface()
local newpos = {x = Cabin.Data.car_pos.x - relative_pos.x, y = Cabin.Data.car_pos.y + relative_pos.y}
local newpos2 = surface.find_non_colliding_position('character', newpos, 5, 0.2) or newpos
if newpos2 then player.teleport(newpos2, surface) end
end
function Public.player_exit_cabin(player, relative_pos)
local memory = Memory.get_crew_memory()
local surface
if memory.boat and (memory.boat.state == Boats.enum_state.ATSEA_SAILING or memory.boat.state == Boats.enum_state.ATSEA_LOADING_MAP) then
surface = game.surfaces[SurfacesCommon.encode_surface_name(memory.id, 0, Public.enum.SEA, Public.Sea.enum.DEFAULT)]
else
surface = game.surfaces[Common.current_destination().surface_name]
end
local carpos = Boats.get_scope(memory.boat).Data.cabin_car
local newpos = {x = memory.boat.position.x + carpos.x - relative_pos.x, y = memory.boat.position.y + carpos.y + relative_pos.y}
local newpos2 = surface.find_non_colliding_position('character', newpos, 10, 0.2) or newpos
if newpos2 then player.teleport(newpos2, surface) end
end
return Public

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,148 @@
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 Islands = require 'maps.pirates.surfaces.islands.islands'
local Boats = require 'maps.pirates.structures.boats.boats'
local Surfaces = require 'maps.pirates.surfaces.surfaces'
local Interface = require 'maps.pirates.interface'
local Roles = require 'maps.pirates.roles.roles'
local Classes = require 'maps.pirates.roles.classes'
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 Overworld = require 'maps.pirates.overworld'
local Math = require 'maps.pirates.math'
local inspect = require 'utils.inspect'.inspect
local Quest = require 'maps.pirates.quest'
local Public = {}
function Public.update_character_properties(tickinterval)
local memory = Memory.get_crew_memory()
local crew = Common.crew_get_crew_members()
for _, player in pairs(crew) do
if Common.validate_player_and_character(player) then
local player_index = player.index
local character = player.character
if memory.classes_table and memory.classes_table[player_index] then
local max_reach_bonus = 0
-- if memory.classes_table[player_index] == Classes.enum.DECKHAND then
-- max_reach_bonus = Math.max(max_reach_bonus, 6)
-- character.character_build_distance_bonus = 6
-- else
-- character.character_build_distance_bonus = 0
-- end
if memory.classes_table[player_index] == Classes.enum.FISHERMAN then
max_reach_bonus = Math.max(max_reach_bonus, 10)
character.character_resource_reach_distance_bonus = 10
else
character.character_resource_reach_distance_bonus = 0
end
character.character_reach_distance_bonus = max_reach_bonus
end
local health_boost = 0
if memory.classes_table and memory.classes_table[player_index] then
local class = memory.classes_table[player_index]
if class == Classes.enum.SAMURAI then
health_boost = health_boost + 200
end
end
if memory.playerindex_captain and memory.playerindex_captain == player_index then
health_boost = health_boost + 50
end
character.character_health_bonus = health_boost
local speed_boost = Balance.base_extra_character_speed
if memory.speed_boost_characters and memory.speed_boost_characters[player_index] then
speed_boost = speed_boost + 0.75
else
if memory.classes_table and memory.classes_table[player_index] then
local class = memory.classes_table[player_index]
if class == Classes.enum.SCOUT then
speed_boost = speed_boost + 0.4
elseif class == Classes.enum.DECKHAND or class == Classes.enum.BOATSWAIN or class == Classes.enum.SHORESMAN then
local surfacedata = Surfaces.SurfacesCommon.decode_surface_name(player.surface.name)
local type = surfacedata.type
local on_ship_bool = type == Surfaces.enum.HOLD or type == Surfaces.enum.CABIN or type == Surfaces.enum.CROWSNEST or (player.surface.name == memory.boat.surface_name and Boats.on_boat(memory.boat, player.position))
local hold_bool = surfacedata.type == Surfaces.enum.HOLD
if class == Classes.enum.DECKHAND then
if on_ship_bool and (not hold_bool) then
speed_boost = speed_boost + 0.25
elseif (not on_ship_bool) then
speed_boost = speed_boost - 0.25
end
elseif class == Classes.enum.BOATSWAIN then
if hold_bool then
speed_boost = speed_boost + 0.25
elseif (not on_ship_bool) then
speed_boost = speed_boost - 0.25
end
elseif class == Classes.enum.SHORESMAN then
if on_ship_bool then
speed_boost = speed_boost - 0.25
else
speed_boost = speed_boost + 0.05
end
end
end
end
end
character.character_running_speed_modifier = speed_boost
end
end
end
function Public.Builder_and_Shoreman_rewards_tick(tickinterval)
local memory = Memory.get_crew_memory()
local crew = Common.crew_get_crew_members()
for _, player in pairs(crew) do
if Common.validate_player_and_character(player) then
local player_index = player.index
if memory.classes_table and memory.classes_table[player_index] then
local class = memory.classes_table[player_index]
if class == Classes.enum.DECKHAND or class == Classes.enum.SHORESMAN or class == Classes.enum.BOATSWAIN then
local surfacedata = Surfaces.SurfacesCommon.decode_surface_name(player.surface.name)
local type = surfacedata.type
local on_ship_bool = type == Surfaces.enum.HOLD or type == Surfaces.enum.CABIN or type == Surfaces.enum.CROWSNEST or (player.surface.name == memory.boat.surface_name and Boats.on_boat(memory.boat, player.position))
local hold_bool = surfacedata.type == Surfaces.enum.HOLD
if class == Classes.enum.DECKHAND and on_ship_bool and (not hold_bool) then
Common.flying_text_small(player.surface, player.position, '[color=0.7,0.8,0.8]+[/color]')
Common.give_reward_items{{name = 'iron-ore', count = Math.ceil(10 * Balance.class_resource_scale())}}
elseif class == Classes.enum.BOATSWAIN and hold_bool then
if Math.random(2) == 2 then
Common.flying_text_small(player.surface, player.position, '[color=0.85,0.58,0.37]+[/color]')
Common.give_reward_items{{name = 'copper-ore', count = Math.ceil(20 * Balance.class_resource_scale())}}
else
Common.flying_text_small(player.surface, player.position, '[color=0.7,0.8,0.8]+[/color]')
Common.give_reward_items{{name = 'iron-ore', count = Math.ceil(20 * Balance.class_resource_scale())}}
end
elseif class == Classes.enum.SHORESMAN and (not on_ship_bool) then
Common.flying_text_small(player.surface, player.position, '[color=0.7,0.8,0.8]+[/color]')
Common.give_reward_items{{name = 'iron-ore', count = Math.ceil(10 * Balance.class_resource_scale())}}
end
end
end
end
end
end
return Public

View File

@@ -0,0 +1,560 @@
local Math = require 'maps.pirates.math'
local inspect = require 'utils.inspect'.inspect
local simplex_noise = require 'utils.simplex_noise'.d2 --rms ~ 0.1925
local perlin_noise = require 'utils.perlin_noise'
local Memory = require 'maps.pirates.memory'
local CoreData = require 'maps.pirates.coredata'
local NoisePregen = require 'maps.pirates.noise_pregen.noise_pregen'
local Public = {}
-- Lua 5.2 compatibility
-- local unpack = unpack or table.unpack
function Public.stable_sort(list, comp) --sorts but preserves ordering of equals
comp = comp or function (a, b) return a < b end
local num = 0
for k, v in ipairs(list) do
num = num + 1
end
if num <= 1 then
return
end
local sorted = false
local n = num
while not sorted do
sorted = true
for i = 1, n - 1 do
if comp(list[i+1], list[i]) then
local tmp = list[i]
list[i] = list[i+1]
list[i+1] = tmp
sorted = false
end
end
n = n - 1
end
end
function Public.psum(plist)
local totalx, totaly = 0, 0
for i = 1, #plist do
if plist[i][1] then --multiplier
if plist[i][2] and plist[i][2].x and plist[i][2].y then
totalx = totalx + plist[i][1] * plist[i][2].x
totaly = totaly + plist[i][1] * plist[i][2].y
end
elseif plist[i].x and plist[i].y then
totalx = totalx + plist[i].x
totaly = totaly + plist[i].y
end
end
return {x = totalx, y = totaly}
end
function Public.interpolate(vector1, vector2, param)
return {x = vector1.x * (1-param) + vector2.x * param, y = vector1.y * (1-param) + vector2.y * param}
end
function Public.split(s, delimiter)
local result = {};
for match in (s..delimiter):gmatch("(.-)"..delimiter) do
table.insert(result, match);
end
return result;
end
function Public.contains(table, element)
if not table then return false end
for _, value in pairs(table) do
if value == element then
return true
end
end
return false
end
function Public.snap_coordinates_for_rails(p)
return {x = p.x + (p.x % 2) - 1, y = p.y + (p.y % 2)}
end
function Public.spritepath_to_richtext(spritepath)
return '[' .. spritepath:gsub("/", "=") .. ']'
end
function Public.nonrepeating_join_dict(t1, t2)
t1 = t1 or {}
t2 = t2 or {}
local t3 = {}
for k, i1 in pairs(t1) do
t3[k] = i1
end
for k, i2 in pairs(t2) do
t3[k] = i2
end
return t3
end
function Public.nonrepeating_join(t1, t2)
t1 = t1 or {}
t2 = t2 or {}
local t3 = {}
for _, i1 in pairs(t1) do
t3[#t3 + 1] = i1
end
for _, i2 in pairs(t2) do
if not Public.contains(t3, i2) then
t3[#t3 + 1] = i2
end
end
return t3
end
function Public.exclude(t, t_exclude)
t_exclude = t_exclude or {}
local t2 = {}
for _, i in pairs(t) do
if not Public.contains(t_exclude, i) then
t2[#t2 + 1] = i
end
end
return t2
end
function Public.exclude_position_arrays(a, b_exclude)
b_exclude = b_exclude or {}
local a2 = {}
for x, xtab in pairs(a) do
for y, _ in pairs(xtab) do
if not (b_exclude[x] and b_exclude[x][y]) then
if not a2[x] then a2[x] = {} end
a2[x][y] = true
end
end
end
return a2
end
function Public.unordered_table_with_values_removed(tbl, val)
local to_keep = {}
for k, v in pairs(tbl) do
if v ~= val then to_keep[k] = v end
end
return to_keep
end
function Public.ordered_table_with_values_removed(tbl, val)
local to_keep = {}
local j = 1
for i = 1, #tbl do
if tbl[i] ~= val then
to_keep[j] = tbl[i]
j = j + 1
end
end
return to_keep
end
function Public.ordered_table_with_single_value_removed(tbl, val)
local to_keep = {}
local j = 1
local taken_one = false
for i = 1, #tbl do
if (tbl[i] ~= val) or taken_one then
to_keep[j] = tbl[i]
j = j + 1
else
taken_one = true
end
end
return to_keep
end
function Public.ordered_table_with_index_removed(tbl, index)
local to_keep = {}
local j = 1
for i = 1, #tbl do
if i ~= index then
to_keep[j] = tbl[i]
j = j + 1
end
end
return to_keep
end
function Public.length(tbl)
local count = 0
for k, _ in pairs(tbl) do
count = count + 1
end
return count
end
function Public.standard_string_form_of_time_in_seconds(time)
local time2, str1
if time >= 0 then
time2 = time
str1 = ''
else
time2 = - time
str1 = '-'
end
local str2 = string.format('%.0fm%.0fs', Math.floor(Math.ceil(time2) / 60), Math.ceil(time2) % 60)
return str1 .. str2
end
function Public.time_longform(seconds)
local seconds2, str1
if seconds >= 0 then
seconds2 = seconds
str1 = ''
else
seconds2 = - seconds
str1 = '-'
end
local str2
if seconds2 < 60 - 1 then
str2 = string.format('%.0f seconds', Math.ceil(seconds2))
elseif seconds2 < 60 * 60 - 1 then
str2 = string.format('%.0f mins, %.0f seconds', Math.floor(Math.ceil(seconds2) / 60), Math.ceil(seconds2) % 60)
elseif seconds2 < 60 * 60 * 24 - 1 then
str2 = string.format('%.0f hours, %.0f mins, %.0f seconds', Math.floor(Math.ceil(seconds2) / (60*60)), Math.floor(Math.ceil(seconds2) / 60) % 60, Math.ceil(seconds2) % 60)
else
str2 = string.format('%.0fdays, %.0f hours, %.0f mins, %.0f seconds', Math.floor(Math.ceil(seconds2) / (24*60*60)), Math.floor(Math.ceil(seconds2) / (60*60)) % 24, Math.floor(Math.ceil(seconds2) / 60) % 60, Math.ceil(seconds2) % 60)
end
return str1 .. str2
end
function Public.time_mediumform(seconds)
local seconds2, str1
if seconds >= 0 then
seconds2 = seconds
str1 = ''
else
seconds2 = - seconds
str1 = '-'
end
local str2
if seconds2 < 60 - 1 then
str2 = string.format('%.0fs', Math.ceil(seconds2))
elseif seconds2 < 60 * 60 - 1 then
str2 = string.format('%.0fm%.0fs', Math.floor(Math.ceil(seconds2) / 60), Math.ceil(seconds2) % 60)
elseif seconds2 < 60 * 60 * 24 - 1 then
str2 = string.format('%.0fh%.0fm%.0fs', Math.floor(Math.ceil(seconds2) / (60*60)), Math.floor(Math.ceil(seconds2) / 60) % 60, Math.ceil(seconds2) % 60)
else
str2 = string.format('%.0fd%.0fh%.0fm%.0fs', Math.floor(Math.ceil(seconds2) / (24*60*60)), Math.floor(Math.ceil(seconds2) / (60*60)) % 24, Math.floor(Math.ceil(seconds2) / 60) % 60, Math.ceil(seconds2) % 60)
end
return str1 .. str2
end
function Public.deepcopy(obj) --doesn't copy metatables
if type(obj) ~= 'table' then return obj end
local res = {}
for k, v in pairs(obj) do res[Public.deepcopy(k)] = Public.deepcopy(v) end
return res
end
function Public.noise_field_simplex_2d(noise_data, seed, normalised)
normalised = normalised or false
local f = function(position)
local noise, _seed, weight_sum = 0, seed, 0
for i = 1, #noise_data do
local n = noise_data[i]
local toadd = n.amplitude
if n.wavelength > 0 then --=0 codes for infinite
toadd = toadd * simplex_noise(position.x / n.wavelength, position.y / n.wavelength, _seed)
_seed = _seed + 12345 --some deficiencies
end
if normalised then weight_sum = weight_sum + n.amplitude end
noise = noise + toadd
end
if normalised then noise = noise / weight_sum end
return noise
end
return f
end
function Public.hardcoded_noise_field_decompress(fieldtype, noise_data, seed, normalised)
normalised = normalised or false
local hardcoded_upperscale = NoisePregen[fieldtype].upperscale
local hardcoded_boxsize = NoisePregen[fieldtype].boxsize
local hardcoded_wordlength = NoisePregen[fieldtype].wordlength
local factor = NoisePregen[fieldtype].factor
local f = function(position)
local noise, weight_sum, _seed = 0, 0, seed
for i = 1, #noise_data do
local n = noise_data[i]
local toadd = n.amplitude
local seedfactor = n.seedfactor or 1
if n.upperscale > 0 then --=0 codes for infinite
local scale = n.upperscale / 100
local seed2 = seed * seedfactor
local x2 = position.x / scale
local y2 = position.y / scale
local x2remainder = x2%1
local y2remainder = y2%1
local x2floor = x2 - x2remainder
local y2floor = y2 - y2remainder
local topleftnoiseindex = seed2 % (1000*1000)
local relativeindex00 = x2floor + y2floor * 1000
local totalindex00 = (topleftnoiseindex + relativeindex00) % (1000*1000)
local totalindex10 = (1 + topleftnoiseindex + relativeindex00) % (1000*1000)
local totalindex01 = (1000 + topleftnoiseindex + relativeindex00) % (1000*1000)
local strindex00 = 1 + totalindex00 * hardcoded_wordlength
local strindex10 = 1 + totalindex10 * hardcoded_wordlength
local strindex01 = 1 + totalindex01 * hardcoded_wordlength
local str00 = NoisePregen[fieldtype].Data:sub(strindex00, strindex00 + (hardcoded_wordlength - 1))
local str10 = NoisePregen[fieldtype].Data:sub(strindex10, strindex10 + (hardcoded_wordlength - 1))
local str01 = NoisePregen[fieldtype].Data:sub(strindex01, strindex01 + (hardcoded_wordlength - 1))
local noise00, noise10, noise01 = 0, 0, 0
for j = 0, hardcoded_wordlength-1 do
noise00 = noise00 + NoisePregen.dec[str00:sub(hardcoded_wordlength - j, hardcoded_wordlength - j)] * (NoisePregen.encoding_length ^ j)
noise10 = noise10 + NoisePregen.dec[str10:sub(hardcoded_wordlength - j, hardcoded_wordlength - j)] * (NoisePregen.encoding_length ^ j)
noise01 = noise01 + NoisePregen.dec[str01:sub(hardcoded_wordlength - j, hardcoded_wordlength - j)] * (NoisePregen.encoding_length ^ j)
end
if noise00 % 2 == 1 then noise00 = -noise00 end
noise00 = noise00 / (NoisePregen.encoding_length ^ (hardcoded_wordlength-1))
if noise10 % 2 == 1 then noise10 = -noise10 end
noise10 = noise10 / (NoisePregen.encoding_length ^ (hardcoded_wordlength-1))
if noise01 % 2 == 1 then noise01 = -noise01 end
noise01 = noise01 / (NoisePregen.encoding_length ^ (hardcoded_wordlength-1))
-- local hardnoise00 = tonumber(strsub00:sub(2,6))/10000
-- if strsub00:sub(1,1) == '-' then hardnoise00 = -hardnoise00 end
-- local hardnoise10 = tonumber(strsub10:sub(2,6))/10000
-- if strsub10:sub(1,1) == '-' then hardnoise10 = -hardnoise10 end
-- local hardnoise01 = tonumber(strsub01:sub(2,6))/10000
-- if strsub01:sub(1,1) == '-' then hardnoise01 = -hardnoise01 end
-- log(inspect{topleftnoiseindex, topleftnoiseindex2, relativeindex00, relativeindex10, relativeindex01})
-- log(inspect{strindex00, strindex10, strindex01, hardnoise1, hardnoise2, hardnoise3})
local interpolatedhardnoise = noise00 + x2remainder*(noise10-noise00) + y2remainder*(noise01-noise00)
toadd = toadd * factor * tonumber(interpolatedhardnoise)
_seed = _seed + 12345
end
if normalised then weight_sum = weight_sum + n.amplitude end
noise = noise + toadd
end
if normalised then noise = noise / weight_sum end
return noise
end
return f
end
function Public.hardcoded_noise_field(fieldtype, noise_data, seed, normalised)
normalised = normalised or false
local hardcoded_upperscale = NoisePregen[fieldtype].upperscale --100
local hardcoded_boxsize = NoisePregen[fieldtype].boxsize --1000
local hardcoded_wordlength = NoisePregen[fieldtype].wordlength
local factor = NoisePregen[fieldtype].factor
local f = function(position)
local noise, weight_sum, _seed = 0, 0, seed
for i = 1, #noise_data do
local n = noise_data[i]
local toadd = n.amplitude
local seedfactor = n.seedfactor or 1
if n.upperscale > 0 then --=0 codes for infinite
local scale = n.upperscale / 100
local seed2 = seed * seedfactor
local x2 = position.x / scale
local y2 = position.y / scale
local x2remainder = x2%1
local y2remainder = y2%1
local x2floor = x2 - x2remainder
local y2floor = y2 - y2remainder
local seedindex = seed2 % (1000*1000)
local relativeindex00 = x2floor + y2floor * 1000
local noiseindex1 = seedindex + relativeindex00
local totalindex00 = noiseindex1 % (1000*1000)
local totalindex10 = (1 + noiseindex1) % (1000*1000)
local totalindex01 = (1000 + noiseindex1) % (1000*1000)
local strindex00 = 1 + totalindex00 * hardcoded_wordlength
local strindex10 = 1 + totalindex10 * hardcoded_wordlength
local strindex01 = 1 + totalindex01 * hardcoded_wordlength
local str00 = NoisePregen[fieldtype].Data:sub(strindex00, strindex00 + (hardcoded_wordlength - 1))
local str10 = NoisePregen[fieldtype].Data:sub(strindex10, strindex10 + (hardcoded_wordlength - 1))
local str01 = NoisePregen[fieldtype].Data:sub(strindex01, strindex01 + (hardcoded_wordlength - 1))
local noise00 = tonumber(str00:sub(2,6))/10000
if str00:sub(1,1) == '-' then noise00 = -noise00 end
local noise10 = tonumber(str10:sub(2,6))/10000
if str10:sub(1,1) == '-' then noise10 = -noise10 end
local noise01 = tonumber(str01:sub(2,6))/10000
if str01:sub(1,1) == '-' then noise01 = -noise01 end
-- log(inspect{topleftnoiseindex, topleftnoiseindex2, relativeindex00, relativeindex10, relativeindex01})
-- log(inspect{strindex00, strindex10, strindex01, hardnoise1, hardnoise2, hardnoise3})
local interpolatedhardnoise = noise00 + x2remainder*(noise10-noise00) + y2remainder*(noise01-noise00)
toadd = toadd * factor * tonumber(interpolatedhardnoise)
_seed = _seed + 12345 --some deficiencies
end
if normalised then weight_sum = weight_sum + n.amplitude end
noise = noise + toadd
end
if normalised then noise = noise / weight_sum end
return noise
end
return f
end
function Public.noise_generator(noiseparams, seed)
--memoizes locally
local noiseparams = noiseparams or {}
local seed = seed or 0
local ret = {}
for k, v in pairs(noiseparams) do
local fn
if v.type == 'simplex_2d' then
fn = Public.noise_field_simplex_2d(v.params, seed, v.normalised)
elseif v.type == 'perlin_1d_circle' then
fn = Public.noise_field_perlin_1d_circle(v.params, seed, v.normalised)
else
fn = Public.hardcoded_noise_field(v.type, v.params, seed, v.normalised)
end
ret[k] = Public.memoize(fn)
end
function ret:addNoise(key, new_noise_function)
if self[key] then return
else
self[key] = Public.memoize(new_noise_function)
end
end
ret.seed = seed
-- ret.noiseparams = noiseparams
return ret
end
local function cache_get(cache, params)
local node = cache
for i=1, #params do
node = node.children and node.children[params[i]]
if not node then return nil end
end
return node.results
end
local function cache_put(cache, params, results)
local node = cache
local param
for i=1, #params do
param = params[i]
node.children = node.children or {}
node.children[param] = node.children[param] or {}
node = node.children[param]
end
node.results = results
end
-- The following functions were adapted from https://github.com/kikito/memoize.lua/blob/master/memoize.lua, under the MIT License:
-- [[
-- MIT LICENSE
-- Copyright (c) 2018 Enrique García Cota
-- Permission is hereby granted, free of charge, to any person obtaining a
-- copy of this software and associated documentation files (the
-- "Software"), to deal in the Software without restriction, including
-- without limitation the rights to use, copy, modify, merge, publish,
-- distribute, sublicense, and/or sell copies of the Software, and to
-- permit persons to whom the Software is furnished to do so, subject to
-- the following conditions:
-- The above copyright notice and this permission notice shall be included
-- in all copies or substantial portions of the Software.
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-- ]]
local function is_callable(f)
local tf = type(f)
if tf == 'function' then return true end
if tf == 'table' then
local mt = getmetatable(f)
return type(mt) == 'table' and is_callable(mt.__call)
end
return false
end
-- == memoization
-- memoize takes in a function and outputs an auto-memoizing version of the same
-- e.g. local memoized_f = memoize(f, <cache>), explicit cache is optional
function Public.memoize(f, cache)
cache = cache or {}
if not is_callable(f) then
log(string.format(
"Only functions and callable tables are memoizable. Received %s (a %s)",
tostring(f), type(f)))
end
return function (...)
local params = {...}
local results = cache_get(cache, params)
if not results then
results = { f(...) }
cache_put(cache, params, results)
end
return table.unpack(results)
end
end
return Public