diff --git a/control.lua b/control.lua index df144849..14b826b9 100644 --- a/control.lua +++ b/control.lua @@ -112,7 +112,7 @@ require 'utils.freeplay' --require 'maps.chronosphere.main' --![[Adventure as a crew of pirates]]-- -require 'maps.pirates.main' +--require 'maps.pirates.main' --![[Launch rockets in increasingly harder getting worlds.]]-- --require 'maps.journey.main' diff --git a/locale/en/pirates.cfg b/locale/en/pirates.cfg index 42567bb8..d90b0da1 100644 --- a/locale/en/pirates.cfg +++ b/locale/en/pirates.cfg @@ -210,42 +210,63 @@ role_officer_description=Assigned by the captain, officers can use the Captain's role_captain=Captain role_captain_description=Has executive power to undock the ship, purchase items, and various other special actions. When the game assigns a captain, it gives priority to those who have been playing the longest as a non-captain. +class_obtainable=Class is obtainable. +class_unobtainable=Class was disabled and is unobtainable. + 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. class_fisherman=Fisherman class_fisherman_explanation=They fish at greater distance. +class_fisherman_explanation_advanced=They fish (as well as reach objects as side effect) at greater distance (__1__ extra tile range). class_scout=Scout class_scout_explanation=They are faster, but frail and deal less damage. +class_scout_explanation_advanced=They move __1__% times faster, but receive __2__% more damage and deal __3__% less damage. class_samurai=Samurai class_samurai_explanation=They are tough, and *with no weapon equipped* fight well by melee, but poorly otherwise. +class_samurai_explanation_advanced=They receive __1__% less damage, and with no weapon equipped do extra __2__ damage in melee (scales with 'physical projectile damage' research bonuses), but deal __3__% less damage otherwise. class_merchant=Merchant class_merchant_explanation=They generate 50 doubloons per league. +class_merchant_explanation_advanced=They generate 50 doubloons per league. class_shoresman=Shoresman class_shoresman_explanation=They move slightly faster and generate ore for the cabin whilst offboard. +class_shoresman_explanation_advanced=They move __1__% times faster and generate ore (with current crew size +__2__ every __3__ seconds) for the cabin whilst offboard. class_boatswain=Boatswain class_boatswain_explanation=They move faster and generate ore for the cabin whilst below deck. +class_boatswain_explanation_advanced=They move __1__% times faster and generate ore (with current crew size +__2__ every __3__ seconds) for the cabin whilst below deck. class_prospector=Prospector class_prospector_explanation=They find more resources when handmining. +class_prospector_explanation_advanced=They find more resources when handmining. class_lumberjack=Lumberjack class_lumberjack_explanation=They find more resources when chopping trees. +class_lumberjack_explanation_advanced=They find ores and more coins when chopping trees. class_master_angler=Master Angler class_master_angler_explanation=They fish at much greater distance, and catch more. +class_master_angler_explanation_advanced=They fish at much greater distance (__1__ extra tile range), and catch more (+__2__ fish and +__3__ coins). class_wood_lord=Lord of the Woods class_wood_lord_explanation=They find many more resources when chopping trees. +class_wood_lord_explanation_advanced=They find many more resources when chopping trees. class_chief_excavator=Chief Excavator class_chief_excavator_explanation=They find many more resources when handmining. +class_chief_excavator_explanation_advanced=They find many more resources when handmining. class_hatamoto=Hatamoto class_hatamoto_explanation=They are very tough, and *with no weapon equipped* fight well by melee, but poorly otherwise. +class_hatamoto_explanation_advanced=They receive __1__% less damage, and with no weapon equipped do extra __2__ damage in melee (scales with 'physical projectile damage' research bonuses), but deal __3__% less damage otherwise. class_iron_leg=Iron Leg class_iron_leg_explanation=They are very resistant to damage when carrying 3000 iron ore. +class_iron_leg_explanation_advanced=They receive __1__% less damage when carrying at least __2__ iron ore. class_quartermaster=Quartermaster class_quartermaster_explanation=Nearby crewmates get +10% physical attack and generate ore for the cabin. +class_quartermaster_explanation_advanced=Nearby crewmates (at __1__ tile radius) get +__2__% physical attack and generate ore for the cabin (ore amount depends on nearby crewmate count). class_dredger=Dredger class_dredger_explanation=They find surprising items when they fish. +class_dredger_explanation_advanced=They inherit the previous class bonuses and find surprising items when they fish. class_smoldering=Smoldering class_smoldering_explanation=They periodically convert wood into coal, if they have less than 50 coal. +class_smoldering_explanation_advanced=They periodically convert wood into coal, if they have less than 50 coal. class_gourmet=Gourmet class_gourmet_explanation=They generate ore for the cabin by eating fish in fancy locations. +class_gourmet_explanation_advanced=They generate ore for the cabin by eating fish in fancy locations. class_explanation=__1__: __2__ diff --git a/maps/pirates/api_events.lua b/maps/pirates/api_events.lua index acb2ae72..9259162f 100644 --- a/maps/pirates/api_events.lua +++ b/maps/pirates/api_events.lua @@ -278,20 +278,22 @@ local function damage_to_players_changes(event) local damage_multiplier = 1 - if event.damage_type.name == 'poison' then --make all poison damage stronger against players - damage_multiplier = damage_multiplier * 1.85 + --game.print('on damage info: {name: ' .. event.damage_type.name .. ', object_name: ' .. event.damage_type.object_name .. '}') + + if event.damage_type.name == 'poison' then --make all poison damage stronger against players and enemies + damage_multiplier = damage_multiplier * Balance.poison_damage_multiplier else if class and class == Classes.enum.SCOUT then - damage_multiplier = damage_multiplier * 1.25 + damage_multiplier = damage_multiplier * Balance.scout_damage_taken_multiplier -- elseif class and class == Classes.enum.MERCHANT then -- damage_multiplier = damage_multiplier * 1.10 elseif class and class == Classes.enum.SAMURAI then - damage_multiplier = damage_multiplier * (1 - Balance.samurai_resistance) - elseif class and class == Classes.enum.HATAMOTO then - damage_multiplier = damage_multiplier * (1 - Balance.hatamoto_resistance) - elseif class and class == Classes.enum.IRON_LEG then + damage_multiplier = damage_multiplier * Balance.samurai_damage_taken_multiplier + elseif class and class == Classes.enum.HATAMOTO then --lethal damage needs to be unaffected + damage_multiplier = damage_multiplier * Balance.hatamoto_damage_taken_multiplier + elseif class and class == Classes.enum.IRON_LEG then --lethal damage needs to be unaffected if memory.class_auxiliary_data[player_index] and memory.class_auxiliary_data[player_index].iron_leg_active then - damage_multiplier = damage_multiplier * (1 - Balance.iron_leg_resistance) + damage_multiplier = damage_multiplier * Balance.iron_leg_damage_taken_multiplier end -- else -- damage_multiplier = damage_multiplier * (1 + Balance.bonus_damage_to_humans()) @@ -308,6 +310,24 @@ local function damage_to_players_changes(event) elseif damage_multiplier < 1 and event.final_health > 0 then --lethal damage needs to be unaffected, else they never die event.entity.health = event.entity.health + event.final_damage_amount * (1 - damage_multiplier) end + + + -- deal with damage reduction on lethal damage for players + local player = game.players[player_index] + if not (player and player.valid and player.character and player.character.valid) then + return + end + + local global_memory = Memory.get_global_memory() + + if damage_multiplier < 1 and event.final_health <= 0 then + local damage_dealt = event.final_damage_amount * damage_multiplier + if damage_dealt < global_memory.last_players_health[player_index] then + event.entity.health = global_memory.last_players_health[player_index] - damage_dealt + end + end + + global_memory.last_players_health[player_index] = event.entity.health end @@ -351,7 +371,7 @@ local function damage_dealt_by_players_changes(event) local class = memory.classes_table and memory.classes_table[player_index] if class and class == Classes.enum.SCOUT and event.final_health > 0 then --lethal damage must be unaffected - event.entity.health = event.entity.health + 0.4 * event.final_damage_amount + event.entity.health = event.entity.health + (1 - Balance.scout_damage_dealt_multiplier) * event.final_damage_amount elseif class and (class == Classes.enum.SAMURAI or class == Classes.enum.HATAMOTO) then local samurai = memory.classes_table[player_index] == Classes.enum.SAMURAI local hatamoto = memory.classes_table[player_index] == Classes.enum.HATAMOTO @@ -367,19 +387,23 @@ local function damage_dealt_by_players_changes(event) local big_number = 1000 + local extra_physical_damage_from_research_multiplier = 1 + memory.force.get_ammo_damage_modifier('bullet') + if melee and event.final_health > 0 then if physical then if samurai then - extra_damage_to_deal = 30 + extra_damage_to_deal = Balance.samurai_damage_dealt_with_melee_multiplier * extra_physical_damage_from_research_multiplier elseif hatamoto then - extra_damage_to_deal = 50 + extra_damage_to_deal = Balance.hatamoto_damage_dealt_with_melee_multiplier * extra_physical_damage_from_research_multiplier end elseif acid then --this hacky stuff is to implement repeated spillover splash damage, whilst getting around the fact that if ovekill damage takes something to zero health, we can't tell in that event how much double-overkill damage should be dealt by reading off its HP. This code assumes that characters only deal acid damage via this function. extra_damage_to_deal = event.original_damage_amount * big_number end elseif (not melee) and event.final_health > 0 then - if samurai or hatamoto then - event.entity.health = event.entity.health + 0.25 * event.final_damage_amount + if samurai then + event.entity.health = event.entity.health + (1 - Balance.samurai_damage_dealt_when_not_melee_multiplier) * event.final_damage_amount + elseif hatamoto then + event.entity.health = event.entity.health + (1 - Balance.hatamoto_damage_dealt_when_not_melee_multiplier) * event.final_damage_amount end end @@ -400,13 +424,13 @@ local function damage_dealt_by_players_changes(event) if physical then -- QUARTERMASTER BUFFS - local nearby_players = player.surface.find_entities_filtered{position = player.position, radius = Common.quartermaster_range, type = {'character'}} + local nearby_players = player.surface.find_entities_filtered{position = player.position, radius = Balance.quartermaster_range, type = {'character'}} for _, p2 in pairs(nearby_players) do if p2.player and p2.player.valid then local p2_index = p2.player.index if event.entity.valid and player_index ~= p2_index and memory.classes_table[p2_index] and memory.classes_table[p2_index] == Classes.enum.QUARTERMASTER then - event.entity.damage(0.1 * event.final_damage_amount, character.force, 'impact', character) --triggers this function again, but not physical this time + event.entity.damage(Balance.quartermaster_bonus_physical_damage * event.final_damage_amount, character.force, 'impact', character) --triggers this function again, but not physical this time end end end @@ -660,10 +684,6 @@ end -- -- end -- end - -Public.every_nth_tree_gives_coins = 6 - - local function event_on_player_mined_entity(event) if not event.player_index then return end local player = game.players[event.player_index] @@ -739,7 +759,7 @@ local function event_on_player_mined_entity(event) -- end else give[#give + 1] = {name = 'wood', count = amount} - if Math.random(Public.every_nth_tree_gives_coins) == 1 then --tuned + if Math.random(Balance.every_nth_tree_gives_coins) == 1 then --tuned local a = 5 give[#give + 1] = {name = 'coin', count = a} memory.playtesting_stats.coins_gained_by_trees_and_rocks = memory.playtesting_stats.coins_gained_by_trees_and_rocks + a @@ -756,13 +776,13 @@ local function event_on_player_mined_entity(event) if memory.classes_table and memory.classes_table[event.player_index] and memory.classes_table[event.player_index] == Classes.enum.MASTER_ANGLER then - Common.give(player, {{name = 'raw-fish', count = 4}, {name = 'coin', count = 10}}, entity.position) + Common.give(player, {{name = 'raw-fish', count = Balance.base_caught_fish_amount + Balance.master_angler_fish_bonus}, {name = 'coin', count = Balance.master_angler_coin_bonus}}, entity.position) elseif memory.classes_table and memory.classes_table[event.player_index] and memory.classes_table[event.player_index] == Classes.enum.DREDGER then - local to_give = {{name = 'raw-fish', count = 4}} + local to_give = {{name = 'raw-fish', count = Balance.base_caught_fish_amount + Balance.dredger_fish_bonus}} to_give[#to_give + 1] = Loot.dredger_loot()[1] Common.give(player, to_give, entity.position) else - Common.give(player, {{name = 'raw-fish', count = 3}}, entity.position) + Common.give(player, {{name = 'raw-fish', count = Balance.base_caught_fish_amount}}, entity.position) end event.buffer.clear() @@ -1263,6 +1283,8 @@ local function event_on_player_joined_game(event) Gui.info.toggle_window(player) end + global_memory.last_players_health[event.player_index] = player.character.health + -- player.teleport(surface.find_non_colliding_position('character', spawnpoint, 32, 0.5), surface) -- -- for item, amount in pairs(Balance.starting_items_player) do -- -- player.insert({name = item, count = amount}) @@ -1332,6 +1354,8 @@ local function event_on_pre_player_left_game(event) break end end + + global_memory.last_players_health[event.player_index] = nil end @@ -1795,6 +1819,9 @@ local function event_on_player_respawned(event) if player.character and player.character.valid then Task.set_timeout_in_ticks(360, boost_movement_speed_on_respawn, {player = player, crew_id = crew_id}) + + local global_memory = Memory.get_global_memory() + global_memory.last_players_health[event.player_index] = player.character.health end end end diff --git a/maps/pirates/balance.lua b/maps/pirates/balance.lua index 3f74f226..2923c768 100644 --- a/maps/pirates/balance.lua +++ b/maps/pirates/balance.lua @@ -11,12 +11,62 @@ local _inspect = require 'utils.inspect'.inspect -- this file is an API to all the balance tuning knobs +-- damage_taken_multiplier: +-- if multiplier > 1: entity takes more damage +-- if multiplier < 1: entity takes less damage (has damage reduction) + +-- damage_dealt_multiplier: +-- if multiplier > 1: entity deals more damage +-- if multiplier < 1: entity deals less damage + +-- extra_speed: +-- if multiplier > 1: entity moves faster +-- if multiplier < 1: entity moves slower +-- NOTE: when some extra speed modifiers stack, they stack multiplicatively + +Public.base_extra_character_speed = 1.44 +Public.respawn_speed_boost = 1.75 -Public.base_extra_character_speed = 0.20 Public.cannon_starting_hp = 2000 Public.cannon_resistance_factor = 2.5 Public.technology_price_multiplier = 1 +Public.rocket_launch_coin_reward = 5000 +Public.base_caught_fish_amount = 3 +Public.class_reward_tick_rate_in_seconds = 7 +Public.poison_damage_multiplier = 1.85 +Public.every_nth_tree_gives_coins = 6 + +Public.samurai_damage_taken_multiplier = 0.26 +Public.samurai_damage_dealt_when_not_melee_multiplier = 0.75 +Public.samurai_damage_dealt_with_melee_multiplier = 25 +Public.hatamoto_damage_taken_multiplier = 0.16 +Public.hatamoto_damage_dealt_when_not_melee_multiplier = 0.75 +Public.hatamoto_damage_dealt_with_melee_multiplier = 45 +Public.iron_leg_damage_taken_multiplier = 0.18 +Public.iron_leg_iron_ore_required = 3000 +Public.deckhand_extra_speed = 1.25 +Public.deckhand_ore_grant_multiplier = 2 +Public.deckhand_ore_scaling_enabled = true +Public.boatswain_extra_speed = 1.25 +Public.boatswain_ore_grant_multiplier = 4 +Public.boatswain_ore_scaling_enabled = true +Public.shoresman_extra_speed = 1.1 +Public.shoresman_ore_grant_multiplier = 2 +Public.shoresman_ore_scaling_enabled = true +Public.quartermaster_range = 19 +Public.quartermaster_bonus_physical_damage = 0.1 +Public.quartermaster_ore_scaling_enabled = false +Public.scout_extra_speed = 1.3 +Public.scout_damage_taken_multiplier = 1.25 +Public.scout_damage_dealt_multiplier = 0.6 +Public.fisherman_reach_bonus = 10 +Public.master_angler_reach_bonus = 16 +Public.master_angler_fish_bonus = 1 +Public.master_angler_coin_bonus = 10 +Public.dredger_reach_bonus = 16 +Public.dredger_fish_bonus = 1 +Public.gourmet_ore_scaling_enabled = false function Public.starting_boatEEIpower_production_MW() -- return 3 * Math.sloped(Common.capacity_scale(), 1/2) / 2 --/2 as we have 2 @@ -44,8 +94,6 @@ function Public.cost_to_leave_multiplier() return Math.sloped(Common.difficulty_scale(), 8/10) end -Public.rocket_launch_coin_reward = 5000 - function Public.crew_scale() local ret = Common.activecrewcount()/10 if ret == 0 then ret = 1/10 end --if all players are afk @@ -301,10 +349,6 @@ function Public.class_resource_scale() return 1 / (Public.crew_scale()^(2/5)) --already helped by longer timescales end -Public.samurai_resistance = 0.74 -Public.hatamoto_resistance = 0.84 -Public.iron_leg_resistance = 0.82 - function Public.biter_base_density_scale() local p = Public.crew_scale() if p >= 1 then diff --git a/maps/pirates/commands.lua b/maps/pirates/commands.lua index 3de84ebf..16376d11 100644 --- a/maps/pirates/commands.lua +++ b/maps/pirates/commands.lua @@ -229,7 +229,7 @@ function(cmd) if not Common.validate_player(player) then return end if param and param ~= 'nil' then - local string = Roles.get_class_print_string(param) + local string = Roles.get_class_print_string(param, false) if string then Common.notify_player_expected(player, {'', 'Class definition for ', string}) else @@ -240,6 +240,27 @@ function(cmd) end end) +commands.add_command( +'classinfofull', +'{classname} returns detailed definition of the named class.', +function(cmd) + cmd_set_memory(cmd) + 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 + local string = Roles.get_class_print_string(param, true) + if string then + Common.notify_player_expected(player, {'', 'Class definition for ', string}) + else + Common.notify_player_error(player, 'Command error: Class ' .. param .. ' not found.') + end + else + Common.notify_player_expected(player, '/classinfofull {classname} returns detailed definition of the named class.') + end +end) + commands.add_command( 'take', '{classname} takes a spare class with the given name for yourself.', @@ -1025,4 +1046,16 @@ if _DEBUG then Server.to_discord_embed_raw(CoreData.comfy_emojis.monkas) end end) + + commands.add_command( + 'piratux_test', + 'is a dev command of piratux.', + function(cmd) + local param = tostring(cmd.parameter) + if check_admin(cmd) then + local player = game.players[cmd.player_index] + + player.print('speed: ' .. player.character.speed .. 'effective_speed: ' .. player.character.effective_speed) + end + end) end \ No newline at end of file diff --git a/maps/pirates/common.lua b/maps/pirates/common.lua index 866c5d8e..a3e3420f 100644 --- a/maps/pirates/common.lua +++ b/maps/pirates/common.lua @@ -37,7 +37,6 @@ Public.deepwater_distance_from_leftmost_shore = 32 Public.lobby_spawnpoint = {x = -72, y = -8} Public.structure_ensure_chunk_radius = 2 -Public.quartermaster_range = 19 Public.allow_barreling_off_ship = true Public.coin_tax_percentage = 10 diff --git a/maps/pirates/crew.lua b/maps/pirates/crew.lua index e108a143..f132ab95 100644 --- a/maps/pirates/crew.lua +++ b/maps/pirates/crew.lua @@ -839,7 +839,7 @@ function Public.reset_crew_and_enemy_force(id) crew_force.manual_mining_speed_modifier = 3 crew_force.character_inventory_slots_bonus = 0 -- crew_force.character_inventory_slots_bonus = 10 - crew_force.character_running_speed_modifier = Balance.base_extra_character_speed + -- crew_force.character_running_speed_modifier = Balance.base_extra_character_speed crew_force.laboratory_productivity_bonus = 0 crew_force.ghost_time_to_live = 12 * 60 * 60 diff --git a/maps/pirates/main.lua b/maps/pirates/main.lua index 54408be9..63239175 100644 --- a/maps/pirates/main.lua +++ b/maps/pirates/main.lua @@ -113,7 +113,7 @@ local function on_init() 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 + -- game.forces.player.character_running_speed_modifier = Balance.base_extra_character_speed game.create_force('environment') for id = 1, 3, 1 do @@ -248,8 +248,8 @@ local function crew_tick() end - if tick % 420 == 0 then - ClassPiratesApiOnTick.class_rewards_tick(420) + if tick % (60 * Balance.class_reward_tick_rate_in_seconds) == 0 then + ClassPiratesApiOnTick.class_rewards_tick(60 * Balance.class_reward_tick_rate_in_seconds) end end end diff --git a/maps/pirates/memory.lua b/maps/pirates/memory.lua index 2f35a5e2..5866625f 100644 --- a/maps/pirates/memory.lua +++ b/maps/pirates/memory.lua @@ -37,6 +37,8 @@ function Public.global_reset_memory() pirates_global_memory.global_delayed_tasks = {} pirates_global_memory.global_buffered_tasks = {} + + pirates_global_memory.last_players_health = {} --used to make damage reduction work somewhat properly end diff --git a/maps/pirates/roles/classes.lua b/maps/pirates/roles/classes.lua index fbf2c546..62c030d9 100644 --- a/maps/pirates/roles/classes.lua +++ b/maps/pirates/roles/classes.lua @@ -70,6 +70,65 @@ function Public.explanation(class) return {'pirates.class_' .. class .. '_explanation'} end +function Public.explanation_advanced(class) + local explanation = 'pirates.class_' .. class .. '_explanation_advanced' + local full_explanation = {} + + if class == enum.DECKHAND then + local extra_speed = Public.percentage_points_difference_from_100_percent(Balance.deckhand_extra_speed) + local ore_amount = Public.ore_grant_amount(Balance.deckhand_ore_grant_multiplier, Balance.deckhand_ore_scaling_enabled) + local tick_rate = Balance.class_reward_tick_rate_in_seconds + full_explanation = {'', {explanation, extra_speed, ore_amount, tick_rate}} + elseif class == enum.BOATSWAIN then + local extra_speed = Public.percentage_points_difference_from_100_percent(Balance.boatswain_extra_speed) + local ore_amount = Public.ore_grant_amount(Balance.boatswain_ore_grant_multiplier, Balance.boatswain_ore_scaling_enabled) + local tick_rate = Balance.class_reward_tick_rate_in_seconds + full_explanation = {'', {explanation, extra_speed, ore_amount, tick_rate}} + elseif class == enum.SHORESMAN then + local extra_speed = Public.percentage_points_difference_from_100_percent(Balance.shoresman_extra_speed) + local ore_amount = Public.ore_grant_amount(Balance.shoresman_ore_grant_multiplier, Balance.shoresman_ore_scaling_enabled) + local tick_rate = Balance.class_reward_tick_rate_in_seconds + full_explanation = {'', {explanation, extra_speed, ore_amount, tick_rate}} + elseif class == enum.QUARTERMASTER then + local range = Balance.quartermaster_range + local extra_physical = Public.percentage_points_difference_from_100_percent(Balance.quartermaster_bonus_physical_damage) + full_explanation = {'', {explanation, range, extra_physical}} + elseif class == enum.FISHERMAN then + local extra_range = Balance.fisherman_reach_bonus + full_explanation = {'', {explanation, extra_range}} + elseif class == enum.MASTER_ANGLER then + local extra_range = Balance.master_angler_reach_bonus + local extra_fish = Balance.master_angler_fish_bonus + local extra_coins = Balance.master_angler_coin_bonus + full_explanation = {'', {explanation, extra_range, extra_fish, extra_coins}} + elseif class == enum.SCOUT then + local extra_speed = Public.percentage_points_difference_from_100_percent(Balance.scout_extra_speed) + local received_damage = Public.percentage_points_difference_from_100_percent(Balance.scout_damage_taken_multiplier) + local dealt_damage = Public.percentage_points_difference_from_100_percent(Balance.scout_damage_dealt_multiplier) + full_explanation = {'', {explanation, extra_speed, received_damage, dealt_damage}} + elseif class == enum.SAMURAI then + local received_damage = Public.percentage_points_difference_from_100_percent(Balance.samurai_damage_taken_multiplier) + local melee_damage = Balance.samurai_damage_dealt_with_melee_multiplier + local non_melee_damage = Public.percentage_points_difference_from_100_percent(Balance.samurai_damage_dealt_when_not_melee_multiplier) + full_explanation = {'', {explanation, received_damage, melee_damage, non_melee_damage}} + elseif class == enum.HATAMOTO then + local received_damage = Public.percentage_points_difference_from_100_percent(Balance.hatamoto_damage_taken_multiplier) + local melee_damage = Balance.hatamoto_damage_dealt_with_melee_multiplier + local non_melee_damage = Public.percentage_points_difference_from_100_percent(Balance.hatamoto_damage_dealt_when_not_melee_multiplier) + full_explanation = {'', {explanation, received_damage, melee_damage, non_melee_damage}} + elseif class == enum.IRON_LEG then + local received_damage = Public.percentage_points_difference_from_100_percent(Balance.iron_leg_damage_taken_multiplier) + local iron_ore_required = Balance.iron_leg_iron_ore_required + full_explanation = {'', {explanation, received_damage, iron_ore_required}} + else + full_explanation = {'', {explanation}} + end + + full_explanation[#full_explanation + 1] = Public.class_is_obtainable(class) and {'', ' ', {'pirates.class_obtainable'}} or {'', ' ', {'pirates.class_unobtainable'}} + + return full_explanation +end + -- Public.display_form = { -- [enum.DECKHAND] = {'pirates.class_deckhand'}, -- } @@ -78,6 +137,17 @@ end -- } +-- returns by how much % result changes when you multiply it by multiplier +-- for example consider these multiplier cases {0.6, 1.2}: +-- number * 0.6 -> result decreased by 40% +-- number * 1.2 -> result increased by 20% +function Public.percentage_points_difference_from_100_percent(multiplier) + if(multiplier < 1) then + return (1 - multiplier) * 100 + else + return (multiplier - 1) * 100 + end +end Public.class_unlocks = { @@ -116,6 +186,24 @@ function Public.initial_class_pool() } end +function Public.class_is_obtainable(class) + local obtainable_class_pool = Public.initial_class_pool() + + for _, unlocked_class_list in pairs(Public.class_unlocks) do + for __, unlocked_class in ipairs(unlocked_class_list) do + obtainable_class_pool[#obtainable_class_pool + 1] = unlocked_class + end + end + + for _, unlockable_class in ipairs(obtainable_class_pool) do + if unlockable_class == class then + return true + end + end + + return false +end + function Public.assign_class(player_index, class, self_assigned) local memory = Memory.get_crew_memory() @@ -191,13 +279,9 @@ end -function Public.class_ore_grant(player, how_much, disable_scaling) - local count - if disable_scaling then - count = Math.ceil(how_much) - else - count = Math.ceil(how_much * Balance.class_resource_scale()) - end +function Public.class_ore_grant(player, how_much, enable_scaling) + local count = ore_grant_amount(how_much, enable_scaling) + if Math.random(4) == 1 then Common.flying_text_small(player.surface, player.position, '[color=0.85,0.58,0.37]+' .. count .. '[/color]') Common.give_items_to_crew{{name = 'copper-ore', count = count}} @@ -207,6 +291,13 @@ function Public.class_ore_grant(player, how_much, disable_scaling) end end +function Public.ore_grant_amount(how_much, enable_scaling) + if enable_scaling then + return Math.ceil(how_much * Balance.class_resource_scale()) + else + return Math.ceil(how_much) + end +end local function class_on_player_used_capsule(event) @@ -227,6 +318,9 @@ local function class_on_player_used_capsule(event) local item = event.item if not (item and item.name and item.name == 'raw-fish') then return end + local global_memory = Memory.get_global_memory() + global_memory.last_players_health[event.player_index] = player.character.health + if memory.classes_table and memory.classes_table[player_index] then local class = memory.classes_table[player_index] if class == Public.enum.GOURMET then @@ -263,7 +357,7 @@ local function class_on_player_used_capsule(event) multiplier = multiplier * 5 memory.gourmet_recency_tick = game.tick - timescale*10 + timescale end - Public.class_ore_grant(player, 10 * multiplier, true) + Public.class_ore_grant(player, 10 * multiplier, Balance.gourmet_ore_scaling_enabled) end end end @@ -273,7 +367,7 @@ end function Public.lumberjack_bonus_items(give_table) local memory = Memory.get_crew_memory() - if Math.random(Public.every_nth_tree_gives_coins) == 1 then + if Math.random(Balance.every_nth_tree_gives_coins) == 1 then local a = 12 give_table[#give_table + 1] = {name = 'coin', count = a} memory.playtesting_stats.coins_gained_by_trees_and_rocks = memory.playtesting_stats.coins_gained_by_trees_and_rocks + a diff --git a/maps/pirates/roles/roles.lua b/maps/pirates/roles/roles.lua index b28906a6..e0b86b54 100644 --- a/maps/pirates/roles/roles.lua +++ b/maps/pirates/roles/roles.lua @@ -131,14 +131,21 @@ end -- return str -- end -function Public.get_class_print_string(class) +function Public.get_class_print_string(class, full) for _, class2 in pairs(Classes.enum) do if Classes.eng_form[class2]:lower() == class:lower() or class2 == class:lower() then + local explanation = nil + if full then + explanation = Classes.explanation_advanced(class2) + else + explanation = Classes.explanation(class2) + end + if Classes.class_purchase_requirement[class2] then - return {'pirates.class_explanation_upgraded_class', Classes.display_form(class2), Classes.display_form(Classes.class_purchase_requirement[class2]), Classes.explanation(class2)} + return {'pirates.class_explanation_upgraded_class', Classes.display_form(class2), Classes.display_form(Classes.class_purchase_requirement[class2]), explanation} else - return {'pirates.class_explanation', Classes.display_form(class2), Classes.explanation(class2)} + return {'pirates.class_explanation', Classes.display_form(class2), explanation} end end end diff --git a/maps/pirates/roles/tick_functions.lua b/maps/pirates/roles/tick_functions.lua index b3c4d9ed..1c35b1be 100644 --- a/maps/pirates/roles/tick_functions.lua +++ b/maps/pirates/roles/tick_functions.lua @@ -1,5 +1,3 @@ --- This file is part of thesixthroc's Pirate Ship softmod, licensed under GPLv3 and stored at https://github.com/danielmartin0/ComfyFactorio-Pirates. - --luacheck: ignore --luacheck ignores because tickinterval arguments are a code templating choice... @@ -38,7 +36,7 @@ function Public.class_update_auxiliary_data(tickinterval) local inv = player.character.get_inventory(defines.inventory.character_main) if inv and inv.valid then local count = inv.get_item_count('iron-ore') - if count and count >= 3000 then + if count and count >= Balance.iron_leg_iron_ore_required then check = true end end @@ -105,7 +103,7 @@ function Public.class_renderings(tickinterval) target = player.character, color = CoreData.colors.toughness_rendering, filled = false, - radius = Balance.samurai_resistance^2, + radius = (1 - Balance.samurai_damage_taken_multiplier)^2, only_in_alt_mode = false, draw_on_ground = true, } @@ -117,7 +115,7 @@ function Public.class_renderings(tickinterval) target = player.character, color = CoreData.colors.toughness_rendering, filled = false, - radius = Balance.hatamoto_resistance^2, + radius = (1 - Balance.hatamoto_damage_taken_multiplier)^2, only_in_alt_mode = false, draw_on_ground = true, } @@ -129,7 +127,7 @@ function Public.class_renderings(tickinterval) target = player.character, color = CoreData.colors.toughness_rendering, filled = false, - radius = Balance.iron_leg_resistance^2, + radius = (1 - Balance.iron_leg_damage_taken_multiplier)^2, only_in_alt_mode = false, draw_on_ground = true, } @@ -169,14 +167,25 @@ function Public.update_character_properties(tickinterval) 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 - character.character_reach_distance_bonus = 10 - elseif memory.classes_table[player_index] == Classes.enum.MASTER_ANGLER or memory.classes_table[player_index] == Classes.enum.DREDGER then - character.character_reach_distance_bonus = 16 + character.character_reach_distance_bonus = Balance.fisherman_reach_bonus + elseif memory.classes_table[player_index] == Classes.enum.MASTER_ANGLER then + character.character_reach_distance_bonus = Balance.master_angler_reach_bonus + elseif memory.classes_table[player_index] == Classes.enum.DREDGER then + character.character_reach_distance_bonus = Balance.dredger_reach_bonus else character.character_reach_distance_bonus = 0 end + + --character.character_reach_distance_bonus = max_reach_bonus end local health_boost = 0 -- base health is 250 @@ -198,13 +207,14 @@ function Public.update_character_properties(tickinterval) 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.85 + speed_boost = speed_boost * Balance.respawn_speed_boost 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.35 + speed_boost = speed_boost * Balance.scout_extra_speed 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 @@ -213,27 +223,27 @@ function Public.update_character_properties(tickinterval) if class == Classes.enum.DECKHAND then if on_ship_bool and (not hold_bool) then - speed_boost = speed_boost + 0.25 + speed_boost = speed_boost * Balance.deckhand_extra_speed end elseif class == Classes.enum.BOATSWAIN then if hold_bool then - speed_boost = speed_boost + 0.25 + speed_boost = speed_boost * Balance.boatswain_extra_speed end elseif class == Classes.enum.SHORESMAN then if not on_ship_bool then - speed_boost = speed_boost + 0.07 + speed_boost = speed_boost * Balance.shoresman_extra_speed end end end end end - character.character_running_speed_modifier = speed_boost + character.character_running_speed_modifier = speed_boost - 1 end end end function Public.class_rewards_tick(tickinterval) - --assuming tickinterval = 6 seconds for now + --assuming tickinterval = 7 seconds for now local memory = Memory.get_crew_memory() local crew = Common.crew_get_crew_members() @@ -262,7 +272,7 @@ function Public.class_rewards_tick(tickinterval) end - if game.tick % tickinterval == 0 and (not (memory.boat and memory.boat.state and (memory.boat.state == Structures.Boats.enum_state.ATSEA_LOADING_MAP or memory.boat.state == Structures.Boats.enum_state.ATSEA_WAITING_TO_SAIL))) then --it is possible to spend extra time here, so don't give out freebies + if game.tick % tickinterval == 0 and (not (memory.boat and memory.boat.state and memory.boat.state == Structures.Boats.enum_state.ATSEA_LOADING_MAP)) then --it is possible to spend extra time here, so don't give out freebies if memory.classes_table and memory.classes_table[player_index] then local class = memory.classes_table[player_index] @@ -273,16 +283,16 @@ function Public.class_rewards_tick(tickinterval) local hold_bool = surfacedata.type == Surfaces.enum.HOLD if class == Classes.enum.DECKHAND and on_ship_bool and (not hold_bool) then - Classes.class_ore_grant(player, 2) + Classes.class_ore_grant(player, Balance.deckhand_ore_grant_multiplier, Balance.deckhand_ore_scaling_enabled) elseif class == Classes.enum.BOATSWAIN and hold_bool then - Classes.class_ore_grant(player, 4) + Classes.class_ore_grant(player, Balance.boatswain_ore_grant_multiplier, Balance.boatswain_ore_scaling_enabled) elseif class == Classes.enum.SHORESMAN and (not on_ship_bool) then - Classes.class_ore_grant(player, 2) + Classes.class_ore_grant(player, Balance.shoresman_ore_grant_multiplier, Balance.shoresman_ore_scaling_enabled) elseif class == Classes.enum.QUARTERMASTER then - local nearby_players = #player.surface.find_entities_filtered{position = player.position, radius = Common.quartermaster_range, name = 'character'} + local nearby_players = #player.surface.find_entities_filtered{position = player.position, radius = Balance.quartermaster_range, name = 'character'} if nearby_players > 1 then - Classes.class_ore_grant(player, nearby_players - 1, true) + Classes.class_ore_grant(player, nearby_players - 1, Balance.quartermaster_ore_scaling_enabled) end end end