diff --git a/locale/en/pirates.cfg b/locale/en/pirates.cfg index 76c54a4a..45a4944b 100644 --- a/locale/en/pirates.cfg +++ b/locale/en/pirates.cfg @@ -182,6 +182,7 @@ market_error_not_captain_or_officer=Purchase error: You need to be a captain or market_error_maximum_loading_time=Purchase error: Reached the maximum allowed loading time. repaired_cannons=[font=heading-1]__1__ repaired the ship's cannons.[/font] +upgraded_cannons=[font=heading-1]__1__ repaired and upgraded the ship's cannons.[/font] upgrade_hold=[font=heading-1]__1__ upgraded the ship's hold.[/font] upgrade_power=[font=heading-1]__1__ upgraded the ship's power.[/font] upgrade_merchants=[font=heading-1]__1__ unlocked merchant ships at future islands.[/font] @@ -213,6 +214,8 @@ role_captain_description=Has executive power to undock the ship, purchase items, class_obtainable=Class is obtainable. class_unobtainable=Class was disabled and is unobtainable. +class_definition_for=Class definition for + class_deckhand=Deckhand class_deckhand_explanation=They move faster and generate ore for the cabin whilst onboard above deck. class_deckhand_explanation_advanced=They move __1__% times faster and generate ore (with current crew size +__2__ every __3__ seconds) for the cabin whilst onboard above deck. @@ -531,4 +534,28 @@ gui_questframe_nodamage=Island Quest: No Damage\n\nLaunch a rocket without the s gui_crew_tooltip_1=Your Crew\n\nPerform crew actions, such as selecting a class if any are available. gui_crew_tooltip_2=Your Crew\n\nYou're a free agent, so there's nothing to do here. -gui_progress_tooltip=Progress: __1__ leagues.\n\nTravel __2__ leagues to win the game. \ No newline at end of file +gui_progress_tooltip=Progress: __1__ leagues.\n\nTravel __2__ leagues to win the game. + +cmd_notify_set_max_crews=The maximum number of concurrent crews has been set to __1__. + +cmd_error_not_admin=[ERROR] Only admins are allowed to run this command! +cmd_error_not_captain=[ERROR] Only captains are allowed to run this command! +cmd_error_invalid_player_name=[ERROR] Player __1__ not found. +cmd_error_invalid_class_name=[ERROR] Class __1__ not found. +cmd_error_color_not_found=[ERROR] Color __1__ not found. + +cmd_explain_set_max_crews=is an admin command to set the maximum number of concurrent crews allowed on the server. +cmd_explain_sail=is an admin command to set the ship sailing after an island, in case there's a problem with the captain doing so. +cmd_explain_setcaptain={player} is an admin command to set the crew's captain to {player}. +cmd_explain_summoncrew=is an admin command to summon the crew to the ship. +cmd_explain_ok=is used to accept captainhood. +cmd_explain_classinfo={class name} returns the definition of the named class. +cmd_explain_classinfofull={class name} returns detailed definition of the named class. +cmd_explain_take={class name} takes a spare class with the given name for yourself. +cmd_explain_giveup=gives up your current class, making it available for others. +cmd_explain_ccolor=is an extension to the built-in /color command, with more colors. +cmd_explain_plank={player} is a captain command to remove a player by making them a spectator. +cmd_explain_officer={player} is a captain command to make a player into an officer, or remove them as one. +cmd_explain_undock=is a captain command to undock the ship. +cmd_explain_tax=is a captain command to take a quarter of all coins, plus other game-critical items from the crew, into your inventory. +cmd_explain_dev=is a dev command. \ No newline at end of file diff --git a/maps/pirates/api_events.lua b/maps/pirates/api_events.lua index a47848eb..42f2b587 100644 --- a/maps/pirates/api_events.lua +++ b/maps/pirates/api_events.lua @@ -154,6 +154,17 @@ local function damage_to_silo(event) if destination.dynamic_data.rocketsilos and destination.dynamic_data.rocketsilos[1] and destination.dynamic_data.rocketsilos[1].valid and entity == Common.current_destination().dynamic_data.rocketsilos[1] then if string.sub(event.cause.force.name, 1, 4) ~= 'crew' then + + -- play alert sound for all crew members + if memory.seconds_until_alert_sound_can_be_played_again <= 0 then + memory.seconds_until_alert_sound_can_be_played_again = Balance.alert_sound_max_frequency_in_seconds + + for _, player_index in pairs(memory.crewplayerindices) do + local player = game.players[player_index] + player.play_sound({path = 'utility/alert_destroyed', volume_modifier = 1}) + end + end + if Common.entity_damage_healthbar(entity, event.original_damage_amount / Balance.silo_resistance_factor * (1 + Balance.biter_timeofday_bonus_damage(event.cause.surface.darkness))) <= 0 then Public.silo_die() else @@ -197,7 +208,7 @@ local function damage_to_enemyboat_spawners(event) end local function damage_to_artillery(event) - -- local memory = Memory.get_crew_memory() + local memory = Memory.get_crew_memory() if not event.cause then return end if not event.cause.valid then return end @@ -207,6 +218,16 @@ local function damage_to_artillery(event) if (event.cause.name == 'small-biter') or (event.cause.name == 'small-spitter') or (event.cause.name == 'medium-biter') or (event.cause.name == 'medium-spitter') or (event.cause.name == 'big-biter') or (event.cause.name == 'big-spitter') or (event.cause.name == 'behemoth-biter') or (event.cause.name == 'behemoth-spitter') then if string.sub(event.cause.force.name, 1, 5) ~= 'enemy' then return end + -- play alert sound for all crew members + if memory.seconds_until_alert_sound_can_be_played_again <= 0 then + memory.seconds_until_alert_sound_can_be_played_again = Balance.alert_sound_max_frequency_in_seconds + + for _, player_index in pairs(memory.crewplayerindices) do + local player = game.players[player_index] + player.play_sound({path = 'utility/alert_destroyed', volume_modifier = 1}) + end + end + -- remove resistances: -- event.entity.health = event.entity.health + event.final_damage_amount - event.original_damage_amount diff --git a/maps/pirates/api_on_tick.lua b/maps/pirates/api_on_tick.lua index dba75d4e..a75d493c 100644 --- a/maps/pirates/api_on_tick.lua +++ b/maps/pirates/api_on_tick.lua @@ -1376,6 +1376,12 @@ function Public.update_players_second() end end - +function Public.update_alert_sound_frequency_tracker() + local memory = Memory.get_crew_memory() + if memory.seconds_until_alert_sound_can_be_played_again > 0 then + memory.seconds_until_alert_sound_can_be_played_again = memory.seconds_until_alert_sound_can_be_played_again - 1 + Math.max(0, memory.seconds_until_alert_sound_can_be_played_again) + end +end return Public \ No newline at end of file diff --git a/maps/pirates/balance.lua b/maps/pirates/balance.lua index 803418d4..2bb9d2a1 100644 --- a/maps/pirates/balance.lua +++ b/maps/pirates/balance.lua @@ -12,10 +12,20 @@ local _inspect = require 'utils.inspect'.inspect -- this file is an API to all the balance tuning knobs +-- Kraken related parameters +Public.biter_swim_speed = 1 +Public.kraken_biter_spawn_radius = 6 -- only used during non automatic forced spawning during kraken's "special ability" +Public.kraken_spit_targetting_player_chance = 0.4 + Public.base_extra_character_speed = 1.44 Public.respawn_speed_boost = 1.75 -Public.cannon_starting_hp = 2000--too low, and crew is too fragile. too high, and the run survives when we should put it out of its misery. But this should go up later in the game. +-- maximum rate at which alert sound can be played when important buildings are damaged (like silo or cannons) +-- NOTE: frequency can sometimes be faster by 1 second than denoted, but accuracy doesn't really matter here +Public.alert_sound_max_frequency_in_seconds = 3 + +Public.cannon_extra_hp_for_upgrade = 1000 +Public.cannon_starting_hp = 2000 Public.cannon_resistance_factor = 2 Public.technology_price_multiplier = 1 diff --git a/maps/pirates/commands.lua b/maps/pirates/commands.lua index 16376d11..2046bf77 100644 --- a/maps/pirates/commands.lua +++ b/maps/pirates/commands.lua @@ -51,13 +51,13 @@ end local function check_admin(cmd) local Session = require 'utils.datastore.session_data' local player = game.players[cmd.player_index] - local trusted = Session.get_trusted_table() + --local trusted = Session.get_trusted_table() local p if player then if player ~= nil then p = player.print if not player.admin then - p('[ERROR] Only admins are allowed to run this command!', Color.fail) + p({'pirates.cmd_error_not_admin'}, Color.fail) return false end else @@ -77,7 +77,7 @@ local function check_captain(cmd) p = player.print if not Common.validate_player(player) then return end if not (Roles.player_privilege_level(player) >= Roles.privilege_levels.CAPTAIN) then - p('[ERROR] Only captains are allowed to run this command!', Color.fail) + p({'pirates.cmd_error_not_captain'}, Color.fail) return false end else @@ -97,7 +97,7 @@ local function check_captain_or_admin(cmd) p = player.print if not Common.validate_player(player) then return end if not (player.admin or Roles.player_privilege_level(player) >= Roles.privilege_levels.CAPTAIN) then - p('[ERROR] Only captains are allowed to run this command!', Color.fail) + p({'pirates.cmd_error_not_captain'}, Color.fail) return false end else @@ -131,7 +131,7 @@ end commands.add_command( 'set_max_crews', -'is an admin command to set the maximum number of concurrent crews allowed on the server.', +{'pirates.cmd_explain_set_max_crews'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -140,20 +140,20 @@ function(cmd) if tonumber(param) then global_memory.active_crews_cap = tonumber(param) - Common.notify_player_expected(player, 'The maximum number of concurrent crews has been set to ' .. param .. '.') + Common.notify_player_expected(player, {'pirates.cmd_notify_set_max_crews', param}) end end end) commands.add_command( 'sail', -'is an admin command to set the ship sailing after an island, in case there\'s a problem with the captain doing so.', +{'pirates.cmd_explain_sail'}, function(cmd) cmd_set_memory(cmd) - local param = tostring(cmd.parameter) + --local param = tostring(cmd.parameter) if check_admin(cmd) then - local player = game.players[cmd.player_index] + --local player = game.players[cmd.player_index] local memory = Memory.get_crew_memory() Crew.summon_crew() if memory.boat.state == Boats.enum_state.ATSEA_WAITING_TO_SAIL then @@ -164,7 +164,7 @@ end) commands.add_command( 'setcaptain', -'{player} is an admin command to set the crew\'s captain to {player}.', +{'pirates.cmd_explain_setcaptain'}, function(cmd) cmd_set_memory(cmd) @@ -174,18 +174,18 @@ function(cmd) if param and game.players[param] and game.players[param].index then Roles.make_captain(game.players[param]) else - Common.notify_player_error(player, 'Command error: Invalid player name.') + Common.notify_player_error(player, {'pirates.cmd_error_invalid_player_name', param}) end end end) commands.add_command( 'summoncrew', -'is an admin command to summon the crew to the ship.', +{'pirates.cmd_explain_summoncrew'}, function(cmd) cmd_set_memory(cmd) - local param = tostring(cmd.parameter) + --local param = tostring(cmd.parameter) if check_admin(cmd) then local player = game.players[cmd.player_index] local crew_id = tonumber(string.sub(player.force.name, -3, -1)) or nil @@ -200,13 +200,13 @@ end) commands.add_command( 'ok', -'is used to accept captainhood.', +{'pirates.cmd_explain_ok'}, function(cmd) cmd_set_memory(cmd) local player = game.players[cmd.player_index] if not Common.validate_player(player) then return end - local memory = Memory.get_crew_memory() + --local memory = Memory.get_crew_memory() Roles.player_confirm_captainhood(player) end) @@ -222,7 +222,7 @@ end) commands.add_command( 'classinfo', -'{classname} returns the definition of the named class.', +{'pirates.cmd_explain_classinfo'}, function(cmd) local param = tostring(cmd.parameter) local player = game.players[cmd.player_index] @@ -231,18 +231,19 @@ function(cmd) if param and param ~= 'nil' then local string = Roles.get_class_print_string(param, false) if string then - Common.notify_player_expected(player, {'', 'Class definition for ', string}) + Common.notify_player_expected(player, {'', {'pirates.class_definition_for'}, ' ', string}) else - Common.notify_player_error(player, 'Command error: Class ' .. param .. ' not found.') + Common.notify_player_error(player, {'pirates.cmd_error_invalid_class_name', param}) end else - Common.notify_player_expected(player, '/classinfo {classname} returns the definition of the named class.') + --Common.notify_player_expected(player, '/classinfo {classname} returns the definition of the named class.') + Common.notify_player_expected(player, {'', '/classinfo ', {'pirates.cmd_explain_classinfo'}}) end end) commands.add_command( 'classinfofull', -'{classname} returns detailed definition of the named class.', +{'pirates.cmd_explain_classinfofull'}, function(cmd) cmd_set_memory(cmd) local param = tostring(cmd.parameter) @@ -252,18 +253,18 @@ function(cmd) if param and param ~= 'nil' then local string = Roles.get_class_print_string(param, true) if string then - Common.notify_player_expected(player, {'', 'Class definition for ', string}) + Common.notify_player_expected(player, {'', {'pirates.class_definition_for'}, ' ', string}) else - Common.notify_player_error(player, 'Command error: Class ' .. param .. ' not found.') + Common.notify_player_error(player, {'pirates.cmd_error_invalid_class_name', param}) end else - Common.notify_player_expected(player, '/classinfofull {classname} returns detailed definition of the named class.') + Common.notify_player_expected(player, {'', '/classinfofull ', {'pirates.cmd_explain_classinfofull'}}) end end) commands.add_command( 'take', -'{classname} takes a spare class with the given name for yourself.', +{'pirates.cmd_explain_take'}, function(cmd) cmd_set_memory(cmd) local param = tostring(cmd.parameter) @@ -278,32 +279,28 @@ function(cmd) end end --fallthrough: - Common.notify_player_error(player, 'Command error: Class ' .. param .. ' not found.') + Common.notify_player_error(player, {'pirates.cmd_error_invalid_class_name', param}) return false else - Common.notify_player_expected(player, '/take {classname} takes a spare class with the given name for yourself.') + Common.notify_player_expected(player, {'', '/take ', {'pirates.cmd_explain_take'}}) end end) commands.add_command( 'giveup', -'gives up your current class, making it available for others.', +{'pirates.cmd_explain_giveup'}, function(cmd) cmd_set_memory(cmd) - local param = tostring(cmd.parameter) + --local param = tostring(cmd.parameter) local player = game.players[cmd.player_index] if not Common.validate_player(player) then return end - if param and param == 'nil' then - Classes.try_renounce_class(player, true) - else - Common.notify_player_error(player, 'Command error: parameter not needed.') - end + Classes.try_renounce_class(player, true) end) commands.add_command( 'ccolor', -'is an extension to the built-in /color command, with more colors.', +{'pirates.cmd_explain_ccolor'}, function(cmd) local param = tostring(cmd.parameter) local player_index = cmd.player_index @@ -319,7 +316,7 @@ function(cmd) -- local message = '[color=' .. rgb.r .. ',' .. rgb.g .. ',' .. rgb.b .. ']' .. player.name .. ' chose the color ' .. param .. '[/color] (via /ccolor).' Common.notify_game(message) else - Common.notify_player_error(player, 'Command error: Color \'' .. param .. '\' not found.') + Common.notify_player_error(player, {'pirates.cmd_error_color_not_found', param}) end else local color = PlayerColors.bright_color_names[Math.random(#PlayerColors.bright_color_names)] @@ -372,7 +369,7 @@ local go_1 = Token.register( commands.add_command( 'plank', -'is a captain command to remove a player by making them a spectator.', +{'pirates.cmd_explain_plank'}, function(cmd) cmd_set_memory(cmd) @@ -382,14 +379,14 @@ function(cmd) if param and game.players[param] and game.players[param].index then Crew.plank(player, game.players[param]) else - Common.notify_player_error(player, 'Command error: Invalid player name.') + Common.notify_player_error(player, {'pirates.cmd_error_invalid_player_name', param}) end end end) commands.add_command( 'officer', -'is a captain command to make a player into an officer, or remove them as one.', +{'pirates.cmd_explain_officer'}, function(cmd) cmd_set_memory(cmd) @@ -404,18 +401,18 @@ function(cmd) Roles.make_officer(player, game.players[param]) end else - Common.notify_player_error(player, 'Command error: Invalid player name.') + Common.notify_player_error(player, {'pirates.cmd_error_invalid_player_name', param}) end end end) commands.add_command( 'undock', -'is a captain command to undock the ship.', +{'pirates.cmd_explain_undock'}, function(cmd) cmd_set_memory(cmd) - local param = tostring(cmd.parameter) + --local param = tostring(cmd.parameter) if check_captain_or_admin(cmd) then local player = game.players[cmd.player_index] local memory = Memory.get_crew_memory() @@ -429,13 +426,13 @@ end) commands.add_command( 'tax', -'is a captain command to take a quarter of all coins, plus other game-critical items from the crew, into your inventory.', +{'pirates.cmd_explain_tax'}, function(cmd) cmd_set_memory(cmd) - local param = tostring(cmd.parameter) + --local param = tostring(cmd.parameter) if check_captain(cmd) then - local player = game.players[cmd.player_index] + --local player = game.players[cmd.player_index] local memory = Memory.get_crew_memory() Roles.captain_tax(memory.playerindex_captain) end --@TODO: else @@ -443,7 +440,7 @@ end) commands.add_command( 'dump_highscores', -'is a dev command.', +{'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -457,7 +454,7 @@ end) commands.add_command( 'setclass', -'is a dev command.', +{'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -474,7 +471,7 @@ end) commands.add_command( 'setevo', -'is a dev command.', +{'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -487,7 +484,7 @@ end) commands.add_command( 'modi', -'is a dev command.', +{'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -511,7 +508,7 @@ end) commands.add_command( 'ret', -'is a dev command.', +{'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -524,7 +521,7 @@ end) commands.add_command( 'jump', -'is a dev command.', +{'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -537,7 +534,7 @@ end) commands.add_command( 'advu', -'is a dev command.', +{'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -550,7 +547,7 @@ end) commands.add_command( 'advd', -'is a dev command.', +{'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -564,7 +561,7 @@ end) commands.add_command( 'overwrite_scores_specific', -'is a dev command.', +{'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -581,7 +578,7 @@ if _DEBUG then commands.add_command( 'go', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -622,7 +619,7 @@ if _DEBUG then commands.add_command( 'chnk', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -642,7 +639,7 @@ if _DEBUG then commands.add_command( 'spd', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -656,7 +653,7 @@ if _DEBUG then commands.add_command( 'stp', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -670,7 +667,7 @@ if _DEBUG then commands.add_command( 'rms', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -689,7 +686,7 @@ if _DEBUG then commands.add_command( 'pro', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -711,7 +708,7 @@ if _DEBUG then commands.add_command( 'lev', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -724,7 +721,7 @@ if _DEBUG then commands.add_command( 'hld', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -737,7 +734,7 @@ if _DEBUG then commands.add_command( 'pwr', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -751,7 +748,7 @@ if _DEBUG then commands.add_command( 'score', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -767,7 +764,7 @@ if _DEBUG then commands.add_command( 'scrget', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -779,7 +776,7 @@ if _DEBUG then commands.add_command( 'tim', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -793,7 +790,7 @@ if _DEBUG then commands.add_command( 'gld', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -806,7 +803,7 @@ if _DEBUG then commands.add_command( 'bld', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -819,7 +816,7 @@ if _DEBUG then commands.add_command( 'rad', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -835,7 +832,7 @@ if _DEBUG then commands.add_command( 'rad2', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -851,7 +848,7 @@ if _DEBUG then commands.add_command( 'krk', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -864,7 +861,7 @@ if _DEBUG then commands.add_command( '1/4', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -875,7 +872,7 @@ if _DEBUG then commands.add_command( '1/2', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -886,7 +883,7 @@ if _DEBUG then commands.add_command( '1', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -897,7 +894,7 @@ if _DEBUG then commands.add_command( '2', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -908,7 +905,7 @@ if _DEBUG then commands.add_command( '4', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -919,7 +916,7 @@ if _DEBUG then commands.add_command( '8', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -930,7 +927,7 @@ if _DEBUG then commands.add_command( '16', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -941,7 +938,7 @@ if _DEBUG then commands.add_command( '32', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -952,7 +949,7 @@ if _DEBUG then commands.add_command( '64', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -963,7 +960,7 @@ if _DEBUG then commands.add_command( 'ef1', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -978,7 +975,7 @@ if _DEBUG then commands.add_command( 'ef2', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -993,7 +990,7 @@ if _DEBUG then commands.add_command( 'ef3', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -1008,7 +1005,7 @@ if _DEBUG then commands.add_command( 'ef4', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -1023,7 +1020,7 @@ if _DEBUG then commands.add_command( 'ef5', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) cmd_set_memory(cmd) @@ -1038,7 +1035,7 @@ if _DEBUG then commands.add_command( 'emoji', - 'is a dev command.', + {'pirates.cmd_explain_dev'}, function(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then @@ -1051,11 +1048,22 @@ if _DEBUG then 'piratux_test', 'is a dev command of piratux.', function(cmd) + cmd_set_memory(cmd) local param = tostring(cmd.parameter) + if check_admin(cmd) then + local memory = Memory.get_crew_memory() local player = game.players[cmd.player_index] - player.print('speed: ' .. player.character.speed .. 'effective_speed: ' .. player.character.effective_speed) + local spawners_biters = player.surface.find_entities_filtered{position = player.position, radius = 50, force = memory.enemy_force_name} + player.print('size: ' .. #spawners_biters) + for _, biter in pairs(spawners_biters) do + if biter and biter.valid then + if string.sub(biter.force.name, 1, 5) == 'enemy' then + player.print('biter[' .. biter.unit_number .. ']: pos: ' .. biter.position.x .. ', ' .. biter.position.y .. ', name: ' .. biter.name) + end + end + end end end) end \ No newline at end of file diff --git a/maps/pirates/crew.lua b/maps/pirates/crew.lua index f132ab95..58887003 100644 --- a/maps/pirates/crew.lua +++ b/maps/pirates/crew.lua @@ -982,7 +982,7 @@ function Public.reset_crew_and_enemy_force(id) crew_force.technologies['productivity-module-2'].enabled = true crew_force.technologies['productivity-module-3'].enabled = false - crew_force.technologies['speed-module'].enabled = false + crew_force.technologies['speed-module'].enabled = true crew_force.technologies['speed-module-2'].enabled = false crew_force.technologies['speed-module-3'].enabled = false crew_force.technologies['effectivity-module'].enabled = false diff --git a/maps/pirates/main.lua b/maps/pirates/main.lua index 63239175..47dd1047 100644 --- a/maps/pirates/main.lua +++ b/maps/pirates/main.lua @@ -181,7 +181,7 @@ local function crew_tick() PiratesApiOnTick.slower_boat_tick(60) PiratesApiOnTick.raft_raids(60) PiratesApiOnTick.place_cached_structures(60) - + PiratesApiOnTick.update_alert_sound_frequency_tracker() if destination.dynamic_data.timer then destination.dynamic_data.timer = destination.dynamic_data.timer + 1 diff --git a/maps/pirates/math.lua b/maps/pirates/math.lua index c58823fa..eebf6be6 100644 --- a/maps/pirates/math.lua +++ b/maps/pirates/math.lua @@ -70,6 +70,36 @@ function Public.vector_sum(vec1, vec2) return {x = vec1.x + vec2.x, y = vec1.y + vec2.y} end +-- normalises vector to unit vector (length 1) +-- if vector length is 0, returns {x = 0, y = 1} vector +function Public.vector_norm(vec) + local vec_copy = { x = vec.x, y = vec.y} + local vec_length = Public.sqrt(vec_copy.x^2 + vec_copy.y^2) + if(vec_length == 0) then + vec_copy.x = 0 + vec_copy.y = 1 + else + vec_copy.x = vec_copy.x / vec_length + vec_copy.y = vec_copy.y / vec_length + end + return {x = vec_copy.x, y = vec_copy.y} +end + +-- multiplies vec coordinates by scalar +function Public.vector_scale(vec, scalar) + return {x = vec.x * scalar, y = vec.y * scalar} +end + +-- returns vector which points from position to target +function Public.vector_dir(pos_from, pos_target) + return {x = pos_target.x - pos_from.x, y = pos_target.y - pos_from.y} +end + + +function Public.random_float_in_range(from, to) + return Public.random() * (to - from) + from +end + function Public.snap_to_grid(point) return {x = Public.ceil(point.x), y = Public.ceil(point.x)} end diff --git a/maps/pirates/memory.lua b/maps/pirates/memory.lua index 5866625f..8ec934ae 100644 --- a/maps/pirates/memory.lua +++ b/maps/pirates/memory.lua @@ -79,6 +79,7 @@ function Public.initialise_crew_memory(id) --mostly serves as a dev reference of memory.available_classes_pool = nil + memory.seconds_until_alert_sound_can_be_played_again = 0 memory.crewplayerindices = nil memory.spectatorplayerindices = nil memory.tempbanned_from_joining_data = nil diff --git a/maps/pirates/progression.lua b/maps/pirates/progression.lua index b86364dc..fc01c447 100644 --- a/maps/pirates/progression.lua +++ b/maps/pirates/progression.lua @@ -233,7 +233,7 @@ function Public.progress_to_destination(destination_index) -- memory.mainshop_availability_bools.buy_fast_loader = true -- memory.mainshop_availability_bools.sell_copper = true - memory.mainshop_availability_bools.repair_cannons = true + memory.mainshop_availability_bools.upgrade_cannons = true local boat_for_sale_type = Common.current_destination().static_params.boat_for_sale_type if boat_for_sale_type then @@ -412,7 +412,7 @@ function Public.check_for_end_of_boat_movement(boat) 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.repair_cannons = false + memory.mainshop_availability_bools.upgrade_cannons = false memory.mainshop_availability_bools.extra_hold = false memory.mainshop_availability_bools.upgrade_power = false diff --git a/maps/pirates/shop/captains.lua b/maps/pirates/shop/captains.lua index 5db6c547..2246b554 100644 --- a/maps/pirates/shop/captains.lua +++ b/maps/pirates/shop/captains.lua @@ -28,8 +28,8 @@ local Public = {} -- WARNING: The Crowsnest caption pulls data from this data. But the actual dock market pulls from boat_upgrades.lua. Public.main_shop_data_1 = { - repair_cannons = { - tooltip = 'Repair the cannons.', + upgrade_cannons = { + tooltip = 'Increase cannons max health. This will also repair them.', what_you_get_sprite_buttons = {['item/artillery-turret'] = false}, base_cost = {coins = 1000}, }, @@ -139,7 +139,7 @@ function Public.initialise_captains_shop() new_boat_cutter_with_hold = false, new_boat_cutter = false, buy_iron = false, - repair_cannons = false, + upgrade_cannons = false, -- sell_iron = false, -- buy_fast_loader = true, -- sell_copper = false, diff --git a/maps/pirates/shop/shop.lua b/maps/pirates/shop/shop.lua index cc309cc6..6ebde980 100644 --- a/maps/pirates/shop/shop.lua +++ b/maps/pirates/shop/shop.lua @@ -185,13 +185,14 @@ function Public.event_on_market_item_purchased(event) local healthbar = memory.boat.healthbars[unit_number] if healthbar then + healthbar.max_health = healthbar.max_health + Balance.cannon_extra_hp_for_upgrade healthbar.health = healthbar.max_health Common.update_healthbar_rendering(healthbar, healthbar.max_health) else log('error: healthbar ' .. unit_number .. ' not found') end end - Common.notify_force(force,{'pirates.repaired_cannons', player.name}) + Common.notify_force(force,{'pirates.upgraded_cannons', player.name}) market.remove_market_item(offer_index) else local upgrade_type = Common.current_destination().static_params.upgrade_for_sale @@ -210,35 +211,48 @@ function Public.event_on_market_item_purchased(event) -- if not class_for_sale then return end local required_class = Classes.class_purchase_requirement[class_for_sale] - local ok = true - -- check if they have the required class to buy it - if required_class then - if not (memory.classes_table and memory.classes_table[player.index] and memory.classes_table[player.index] == required_class) then - ok = false - Common.notify_force_error(force, {'pirates.class_purchase_error_prerequisite_class',Classes.display_form(required_class)}) + local ok = false + + if memory.classes_table and memory.spare_classes then + if required_class then + local chosen_class_assigned = false + + if required_class then + for p_index, chosen_class in pairs(memory.classes_table) do + if chosen_class == required_class then + memory.classes_table[p_index] = class_for_sale + chosen_class_assigned = true + ok = true + break + end + end + end + + if not chosen_class_assigned then + for i, spare_class in pairs(memory.spare_classes) do + if spare_class == required_class then + memory.spare_classes[i] = class_for_sale + ok = true + break + end + end + end + else -- there is no required class + if not memory.classes_table[player.index] then + memory.classes_table[player.index] = class_for_sale + else + memory.spare_classes[#memory.spare_classes + 1] = class_for_sale + end + ok = true end end if ok then - if required_class then - if force and force.valid then - local message = {'pirates.class_upgrade', player.name, Classes.display_form(required_class), Classes.display_form(class_for_sale), Classes.explanation(class_for_sale)} - Common.notify_force_light(force,message) - end - else - -- check if they have a role already - renounce it if so - if memory.classes_table and memory.classes_table[player.index] then - Classes.try_renounce_class(player, false) - end - - if force and force.valid then - local message = {'pirates.class_purchase', player.name, Classes.display_form(class_for_sale), Classes.explanation(class_for_sale)} - Common.notify_force_light(force, message) - end + if force and force.valid then + local message = {'pirates.class_purchase', player.name, Classes.display_form(class_for_sale), Classes.explanation(class_for_sale)} + Common.notify_force_light(force, message) end - memory.classes_table[player.index] = class_for_sale - memory.available_classes_pool = Utils.ordered_table_with_single_value_removed(memory.available_classes_pool, class_for_sale) -- if destination.dynamic_data and destination.dynamic_data.market_class_offer_rendering then @@ -253,6 +267,10 @@ function Public.event_on_market_item_purchased(event) end end else + if force and force.valid then + Common.notify_force_error(force, {'pirates.class_purchase_error_prerequisite_class', Classes.display_form(required_class)}) + end + --refund inv = player.get_inventory(defines.inventory.character_main) if not inv then return end diff --git a/maps/pirates/structures/island_structures/mattisso/data.lua b/maps/pirates/structures/island_structures/mattisso/data.lua index 5ebe289d..e184acec 100644 --- a/maps/pirates/structures/island_structures/mattisso/data.lua +++ b/maps/pirates/structures/island_structures/mattisso/data.lua @@ -179,7 +179,7 @@ Public.small_primitive_mining_base = { type = 'entities_minable', name = 'burner-mining-drill', force = 'ancient-friendly', - offset = {x = -1, y = -1}, + offset = {x = 0, y = 0}, instances = {{position = {x = -4, y = -6}, direction = defines.direction.south}, {position = {x = -6, y = -4}, direction = defines.direction.east},{position = {x = 0, y = 1}, direction = defines.direction.south}, {position = {x = -2, y = 3}, direction = defines.direction.east},{position = {x = 5, y = 1}, direction = defines.direction.south}, {position = {x = 5, y = 5}, direction = defines.direction.north}} }, }, diff --git a/maps/pirates/structures/structures.lua b/maps/pirates/structures/structures.lua index 09cbbc28..787d9190 100644 --- a/maps/pirates/structures/structures.lua +++ b/maps/pirates/structures/structures.lua @@ -118,7 +118,7 @@ function Public.configure_structure_entities(special_name, components) e.insert_fluid(Loot.storage_tank_fluid_loot('crude-oil')) elseif e.name == 'storage-tank' and special_name == 'small_abandoned_refinery' then e.insert_fluid(Loot.storage_tank_fluid_loot('petroleum-gas')) - elseif e.name == 'storage-tank' and (not special_name == 'small_radioactive_reactor') then + elseif e.name == 'storage-tank' and (not (special_name == 'small_radioactive_reactor')) then e.insert_fluid(Loot.storage_tank_fluid_loot()) elseif (special_name == 'maze_labs') and e.name == 'lab' then local inv = e.get_inventory(defines.inventory.lab_input) diff --git a/maps/pirates/surfaces/sea/kraken.lua b/maps/pirates/surfaces/sea/kraken.lua index 8955c313..24623c1a 100644 --- a/maps/pirates/surfaces/sea/kraken.lua +++ b/maps/pirates/surfaces/sea/kraken.lua @@ -1,5 +1,6 @@ -- This file is part of thesixthroc's Pirate Ship softmod, licensed under GPLv3 and stored at https://github.com/danielmartin0/ComfyFactorio-Pirates. +local Boats = require 'maps.pirates.structures.boats.boats' local Memory = require 'maps.pirates.memory' local Math = require 'maps.pirates.math' @@ -41,14 +42,56 @@ local kraken_tick_token = Public.kraken_tick(data.crew_id, data.kraken_id, data.step, data.substep) end ) + +local swimming_biters_tick_token = + Token.register( + function(data) + Public.swimming_biters_tick(data.crew_id, data.kraken_id) + end +) + +-- should only be used during kraken encounter +function Public.swimming_biters_tick(crew_id, kraken_id) + 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 kraken_data = memory.active_sea_enemies.krakens[kraken_id] + if not kraken_data then return end --check if kraken died + local surface = game.surfaces[memory.sea_name] + + local spawners_biters = surface.find_entities_filtered{force = memory.enemy_force_name} + for _, biter in pairs(spawners_biters) do + if biter and biter.valid then + if biter.name ~= 'biter-spawner' then -- might need to be changed if kraken battle one day will involve worms too + if not Boats.on_boat(memory.boat, biter.position) then + local biter_pos = biter.position + local target_pos = {x = 0, y = 0} + + -- choose closest boarding entrance on the ship + target_pos.x = biter_pos.x > 0 and Math.random_float_in_range(18, 11) or Math.random_float_in_range(-18, -11) + target_pos.y = biter_pos.y > 0 and 12 or -12 + + local towards_target_vec = Math.vector_dir(biter_pos, target_pos) + towards_target_vec = Math.vector_norm(towards_target_vec) + towards_target_vec = Math.vector_scale(towards_target_vec, Balance.biter_swim_speed) + biter.teleport(Math.vector_sum(biter_pos, towards_target_vec)) + end + end + end + end + + Task.set_timeout_in_ticks(20, swimming_biters_tick_token, {crew_id = crew_id, kraken_id = kraken_id}) +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 + local surface = game.surfaces[memory.sea_name] local kraken_spawner_entity = kraken_data.spawner_entity if step == 1 then @@ -100,17 +143,35 @@ function Public.kraken_tick(crew_id, kraken_id, step, substep) -- firing speed now depends on player count: local firing_period + local summoned_biter_amount if crewCount <= 12 then firing_period = 4 + summoned_biter_amount = 2 else firing_period = 3 + summoned_biter_amount = 3 -- elseif crewCount <= 24 then -- firing_period = 3 -- else -- firing_period = 2 end - if substep % firing_period == 0 then + -- special ability: stop shooting, and summon some biters randomly around the spawner + if substep % 100 > 70 then + if substep % 5 == 0 then + if kraken_spawner_entity then + for i = 1, summoned_biter_amount do + local name = Common.get_random_unit_type(memory.evolution_factor) + local random_dir_vec = {x = Math.random_float_in_range(-1, 1), y = Math.random_float_in_range(-1, 1)} + random_dir_vec = Math.vector_norm(random_dir_vec) + random_dir_vec = Math.vector_scale(random_dir_vec, Balance.kraken_biter_spawn_radius) + local spawn_pos = Math.vector_sum(kraken_spawner_entity.position, random_dir_vec) + surface.create_entity{name = name, position = spawn_pos, force = memory.enemy_force_name} + end + end + end + -- otherwise continue actively shooting at the ship/random player + elseif substep % firing_period == 0 then local p_can_fire_at = {} for _, player in pairs(crewmembers) do local p = player.position @@ -119,20 +180,29 @@ function Public.kraken_tick(crew_id, kraken_id, step, substep) 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) + + local spit_target_pos + + -- shoot at player + if Math.random() < Balance.kraken_spit_targetting_player_chance and #p_can_fire_at > 0 then + spit_target_pos = p_can_fire_at[Math.random(#p_can_fire_at)] + -- shoot at the ship + else + -- select random position in hardcoded bounded box within the ship + spit_target_pos = {x = Math.random_float_in_range(-28, 21), y = Math.random_float_in_range(-9, 9)} end + + local stream = surface.create_entity{ + name = 'acid-stream-spitter-big', + position = kraken_data.position, + force = memory.enemy_force_name, + source = kraken_data.position, + target = spit_target_pos, + max_range = 500, + speed = 0.1 + } + memory.kraken_stream_registrations[#memory.kraken_stream_registrations + 1] = {number = script.register_on_entity_destroyed(stream), position = spit_target_pos} + Effects.kraken_effect_4(surface, kraken_data.position) end if substep % 50 > 40 then @@ -192,7 +262,6 @@ local function on_entity_destroyed(event) end end - function Public.try_spawn_kraken() local memory = Memory.get_crew_memory() local surface = game.surfaces[memory.sea_name] @@ -221,6 +290,7 @@ function Public.try_spawn_kraken() } Task.set_timeout_in_ticks(10, kraken_tick_token, {crew_id = memory.id, kraken_id = kraken_id, step = 1, substep = 1}) + Task.set_timeout_in_ticks(10, swimming_biters_tick_token, {crew_id = memory.id, kraken_id = kraken_id}) end end