mirror of
https://github.com/ComfyFactory/ComfyFactorio.git
synced 2025-02-03 13:12:11 +02:00
Add break/AFK protection shield
This commit is contained in:
parent
d672332b33
commit
f5d04d8c63
@ -59,9 +59,9 @@ local function on_chunk_charted(event)
|
||||
update_forces(health_text)
|
||||
add_force(health_text, force.name)
|
||||
-- protection text
|
||||
local zone_text = town_center.zone_text
|
||||
update_forces(zone_text)
|
||||
add_force(zone_text, force.name)
|
||||
local shield_text = town_center.shield_text
|
||||
update_forces(shield_text)
|
||||
add_force(shield_text, force.name)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -2,6 +2,7 @@ local table_insert = table.insert
|
||||
|
||||
local ScenarioTable = require 'maps.scrap_towny_ffa.table'
|
||||
local Town_center = require 'maps.scrap_towny_ffa.town_center'
|
||||
local PvPShield = require 'maps.scrap_towny_ffa.pvp_shield'
|
||||
|
||||
local upgrade_functions = {
|
||||
-- Upgrade Town Center Health
|
||||
@ -86,6 +87,33 @@ local upgrade_functions = {
|
||||
this.spawn_point[player.index] = spawn_point
|
||||
surface.play_sound({path = 'utility/scenario_message', position = player.position, volume_modifier = 1})
|
||||
return false
|
||||
end,
|
||||
-- Pause-mode PvP Shield
|
||||
[8] = function(town_center, player)
|
||||
local this = ScenarioTable.get_table()
|
||||
local market = town_center.market
|
||||
local force = market.force
|
||||
local surface = market.surface
|
||||
local shield_lifetime_ticks = 10 * 60 * 60
|
||||
|
||||
if not this.pvp_shields[player.force.name] then
|
||||
-- Double-check with the player to prevent accidental clicks
|
||||
if this.pvp_shield_warned[player.force.name] ~= nil and game.tick - this.pvp_shield_warned[player.force.name] < 60 * 60 then
|
||||
if not Town_center.enemy_players_nearby(town_center, 100) then
|
||||
PvPShield.add_shield(surface, force, market.position, shield_lifetime_ticks, 2 * 60 * 60, true)
|
||||
surface.play_sound({path = 'utility/scenario_message', position = player.position, volume_modifier = 1})
|
||||
this.pvp_shield_warned[player.force.name] = nil
|
||||
else
|
||||
player.print("Enemy players are too close, can't deploy PvP shield")
|
||||
end
|
||||
else
|
||||
player.force.print('You have requested a temporary PvP shield. This will freeze all players in your town for ' .. string.format("%.0f", shield_lifetime_ticks / 60 / 60) .. ' minutes to take a break. Click again to confirm.')
|
||||
this.pvp_shield_warned[player.force.name] = game.tick
|
||||
end
|
||||
else
|
||||
player.print("Your town already has a PvP shield")
|
||||
end
|
||||
return false
|
||||
end
|
||||
}
|
||||
|
||||
@ -134,6 +162,7 @@ local function set_offers(town_center)
|
||||
special_offers[6] = {{{'coin', (town_center.upgrades.laser_turret.slots * 150)}}, laser_turret}
|
||||
local spawn_point = 'Set Spawn Point'
|
||||
special_offers[7] = {{}, spawn_point}
|
||||
special_offers[8] = {{}, 'Temporary PvP Shield for pause/AFK'}
|
||||
for _, v in pairs(special_offers) do
|
||||
table_insert(market_items, {price = v[1], offer = {type = 'nothing', effect_description = v[2]}})
|
||||
end
|
||||
|
@ -1,20 +1,22 @@
|
||||
local Public = {}
|
||||
|
||||
local math_sqrt = math.sqrt
|
||||
|
||||
local Event = require 'utils.event'
|
||||
local ScenarioTable = require 'maps.scrap_towny_ffa.table'
|
||||
local CommonFunctions = require 'utils.common'
|
||||
|
||||
local max_size = 120
|
||||
local beam_type = 'electric-beam-no-sound'
|
||||
local max_lifetime_ticks = 4 * 60 * 60 * 60
|
||||
local time_to_full_size_ticks = 60 * 60
|
||||
local default_lifetime_ticks = 2 * 60 * 60 * 60
|
||||
local default_time_to_full_size_ticks = 60 * 60
|
||||
|
||||
local function draw_borders(zone)
|
||||
local surface = zone.surface
|
||||
local right = zone.box.right_bottom.x
|
||||
local left = zone.box.left_top.x
|
||||
local top = zone.box.left_top.y
|
||||
local bottom = zone.box.right_bottom.y
|
||||
local function draw_borders(shield)
|
||||
local surface = shield.surface
|
||||
local right = shield.box.right_bottom.x
|
||||
local left = shield.box.left_top.x
|
||||
local top = shield.box.left_top.y
|
||||
local bottom = shield.box.right_bottom.y
|
||||
|
||||
surface.create_entity({name = beam_type, position = {right, top},
|
||||
source = {right, top}, target = {right, bottom + 0.5}}) -- intentional offset here to correct visual appearance
|
||||
@ -26,56 +28,73 @@ local function draw_borders(zone)
|
||||
source = {left, top - 0.5}, target = {right, top}})
|
||||
end
|
||||
|
||||
local function remove_drawn_borders(zone)
|
||||
for _, e in pairs(zone.surface.find_entities_filtered({area = zone.box, name = beam_type})) do
|
||||
local function remove_drawn_borders(shield)
|
||||
for _, e in pairs(shield.surface.find_entities_filtered({area = shield.box, name = beam_type})) do
|
||||
if e.valid then
|
||||
e.destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function scale_size_and_box(zone)
|
||||
local time_scale = math.min(1, (game.tick - zone.lifetime_start) / time_to_full_size_ticks)
|
||||
local function scale_size_and_box(shield)
|
||||
local time_scale = math.min(1, (game.tick - shield.lifetime_start) / shield.time_to_full_size_ticks)
|
||||
local scaled_size = time_scale * max_size
|
||||
|
||||
local center = zone.center
|
||||
local center = shield.center
|
||||
local box = {left_top = { x = center.x - scaled_size / 2, y = center.y - scaled_size / 2},
|
||||
right_bottom = { x = center.x + scaled_size / 2, y = center.y + scaled_size / 2}}
|
||||
zone.box = box
|
||||
zone.size = scaled_size
|
||||
shield.box = box
|
||||
shield.size = scaled_size
|
||||
end
|
||||
|
||||
function Public.add_zone(surface, force, center)
|
||||
function Public.add_shield(surface, force, center, lifetime_ticks, time_to_full_size_ticks, is_pause_mode)
|
||||
local this = ScenarioTable.get_table()
|
||||
|
||||
local zone = {surface = surface, force = force, center = center, lifetime_start = game.tick}
|
||||
scale_size_and_box(zone)
|
||||
this.pvp_shields[force.name] = zone
|
||||
if not lifetime_ticks then
|
||||
lifetime_ticks = default_lifetime_ticks
|
||||
end
|
||||
if not time_to_full_size_ticks then
|
||||
time_to_full_size_ticks = default_time_to_full_size_ticks
|
||||
end
|
||||
|
||||
local shield = {surface = surface, force = force, center = center, max_lifetime_ticks = lifetime_ticks,
|
||||
time_to_full_size_ticks = time_to_full_size_ticks, lifetime_start = game.tick, is_pause_mode = is_pause_mode}
|
||||
|
||||
if is_pause_mode then
|
||||
-- Freeze players to avoid AFK abuse
|
||||
shield.force.character_running_speed_modifier = -1
|
||||
game.print("Your AFK PvP shield is now rolling out. You will be frozen until it expires in " ..
|
||||
string.format("%.0f", (Public.remaining_lifetime(shield)) / 60 / 60) .. ' minutes')
|
||||
end
|
||||
|
||||
scale_size_and_box(shield)
|
||||
this.pvp_shields[force.name] = shield
|
||||
end
|
||||
|
||||
function Public.remove_zone(zone)
|
||||
function Public.remove_shield(shield)
|
||||
local this = ScenarioTable.get_table()
|
||||
remove_drawn_borders(zone)
|
||||
this.pvp_shields[zone.force.name] = nil
|
||||
zone.force.print("Your PvP Shield has expired", {r = 1, g = 0, b = 0})
|
||||
remove_drawn_borders(shield)
|
||||
|
||||
if shield.is_pause_mode then
|
||||
shield.force.character_running_speed_modifier = 0
|
||||
end
|
||||
|
||||
this.pvp_shields[shield.force.name] = nil
|
||||
shield.force.print("Your PvP Shield has expired", {r = 1, g = 0, b = 0})
|
||||
end
|
||||
|
||||
function Public.remaining_lifetime(zone)
|
||||
return max_lifetime_ticks - (game.tick - zone.lifetime_start)
|
||||
function Public.remaining_lifetime(shield)
|
||||
return shield.max_lifetime_ticks - (game.tick - shield.lifetime_start)
|
||||
end
|
||||
|
||||
local function vector_norm(vector)
|
||||
return math.sqrt(vector.x ^ 2 + vector.y ^ 2)
|
||||
end
|
||||
|
||||
local function update_zone_lifetime()
|
||||
local function update_shield_lifetime()
|
||||
local this = ScenarioTable.get_table()
|
||||
for _, zone in pairs(this.pvp_shields) do
|
||||
if Public.remaining_lifetime(zone) > 0 then
|
||||
if zone.size < max_size then
|
||||
remove_drawn_borders(zone)
|
||||
scale_size_and_box(zone)
|
||||
draw_borders(zone)
|
||||
for _, shield in pairs(this.pvp_shields) do
|
||||
if Public.remaining_lifetime(shield) > 0 then
|
||||
if shield.size < max_size then
|
||||
remove_drawn_borders(shield)
|
||||
scale_size_and_box(shield)
|
||||
draw_borders(shield)
|
||||
|
||||
-- Push everyone out as we grow (even if they're just standing)
|
||||
for _, player in pairs(game.connected_players) do
|
||||
@ -83,19 +102,23 @@ local function update_zone_lifetime()
|
||||
end
|
||||
end
|
||||
else
|
||||
Public.remove_zone(zone)
|
||||
Public.remove_shield(shield)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function vector_norm(vector)
|
||||
return math_sqrt(vector.x ^ 2 + vector.y ^ 2)
|
||||
end
|
||||
|
||||
function Public.push_enemies_out(player)
|
||||
local this = ScenarioTable.get_table()
|
||||
for _, zone in pairs(this.pvp_shields) do
|
||||
if not (zone.force == player.force or zone.force.get_friend(player.force) or player.surface ~= zone.surface) then
|
||||
if CommonFunctions.point_in_bounding_box(player.position, zone.box) then
|
||||
for _, shield in pairs(this.pvp_shields) do
|
||||
if not (shield.force == player.force or shield.force.get_friend(player.force) or player.surface ~= shield.surface) then
|
||||
if CommonFunctions.point_in_bounding_box(player.position, shield.box) then
|
||||
if player.character then
|
||||
-- Push player away from center
|
||||
local center_diff = { x = player.position.x - zone.center.x, y = player.position.y - zone.center.y}
|
||||
local center_diff = { x = player.position.x - shield.center.x, y = player.position.y - shield.center.y}
|
||||
center_diff.x = center_diff.x / vector_norm(center_diff)
|
||||
center_diff.y = center_diff.y / vector_norm(center_diff)
|
||||
player.teleport({ player.position.x + center_diff.x, player.position.y + center_diff.y}, player.surface)
|
||||
@ -128,6 +151,6 @@ local function on_player_changed_position(event)
|
||||
end
|
||||
|
||||
Event.add(defines.events.on_player_changed_position, on_player_changed_position)
|
||||
Event.on_nth_tick(60, update_zone_lifetime)
|
||||
Event.on_nth_tick(60, update_shield_lifetime)
|
||||
|
||||
return Public
|
||||
|
@ -38,6 +38,7 @@ function Public.reset_table()
|
||||
this.mining_target = {}
|
||||
this.spaceships = {}
|
||||
this.pvp_shields = {}
|
||||
this.pvp_shield_warned = {}
|
||||
end
|
||||
|
||||
function Public.get_table()
|
||||
|
@ -826,7 +826,7 @@ local function kill_force(force_name, cause)
|
||||
end
|
||||
end
|
||||
if this.pvp_shields[force_name] then
|
||||
PvPShield.remove_zone(this.pvp_shields[force_name])
|
||||
PvPShield.remove_shield(this.pvp_shields[force_name])
|
||||
end
|
||||
game.merge_forces(force_name, 'neutral')
|
||||
this.town_centers[force_name] = nil
|
||||
|
@ -3,6 +3,7 @@ local Public = {}
|
||||
local math_random = math.random
|
||||
local table_insert = table.insert
|
||||
local math_floor = math.floor
|
||||
local math_sqrt = math.sqrt
|
||||
local table_shuffle = table.shuffle_table
|
||||
|
||||
local Event = require 'utils.event'
|
||||
@ -368,17 +369,35 @@ function Public.update_coin_balance(force)
|
||||
rendering.set_text(town_center.coins_text, 'Coins: ' .. town_center.coin_balance)
|
||||
end
|
||||
|
||||
local function update_protection_display()
|
||||
function Public.enemy_players_nearby(town_center, max_radius)
|
||||
local own_force = town_center.market.force
|
||||
local town_position = town_center.market.position
|
||||
|
||||
for _, player in pairs(game.connected_players) do
|
||||
if player.surface == town_center.market.surface then
|
||||
local distance = math_floor(math_sqrt((player.position.x - town_position.x) ^ 2
|
||||
+ (player.position.y - town_position.y) ^ 2))
|
||||
if distance < max_radius then
|
||||
if player.force ~= "enemy" and (own_force ~= player.force and not own_force.get_friend(player.force)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function update_pvp_shields_display()
|
||||
local this = ScenarioTable.get_table()
|
||||
for _, town_center in pairs(this.town_centers) do
|
||||
local zone = this.pvp_shields[town_center.market.force.name]
|
||||
local shield = this.pvp_shields[town_center.market.force.name]
|
||||
local info
|
||||
if zone then
|
||||
info = 'PvP Shield: ' .. string.format("%.0f", (PvPShield.remaining_lifetime(zone)) / 60 / 60) .. ' minutes'
|
||||
if shield then
|
||||
info = 'PvP Shield: ' .. string.format("%.0f", (PvPShield.remaining_lifetime(shield)) / 60 / 60) .. ' minutes'
|
||||
else
|
||||
info = ''
|
||||
end
|
||||
rendering.set_text(town_center.zone_text, info)
|
||||
rendering.set_text(town_center.shield_text, info)
|
||||
end
|
||||
end
|
||||
|
||||
@ -528,7 +547,7 @@ local function found_town(event)
|
||||
scale_with_zoom = false
|
||||
}
|
||||
|
||||
town_center.zone_text = rendering.draw_text {
|
||||
town_center.shield_text = rendering.draw_text {
|
||||
text = 'PvP Shield: (..)',
|
||||
surface = surface,
|
||||
forces = {force_name, game.forces.player, game.forces.rogue},
|
||||
@ -545,8 +564,8 @@ local function found_town(event)
|
||||
|
||||
Enemy.clear_enemies(position, surface, town_radius * 5)
|
||||
draw_town_spawn(force_name)
|
||||
PvPShield.add_zone(surface, force, { x = position.x + 0.5, y = position.y + 0.5}) -- Market center is slightly shifted
|
||||
update_protection_display()
|
||||
PvPShield.add_shield(surface, force, { x = position.x + 0.5, y = position.y + 0.5}) -- Market center is slightly shifted
|
||||
update_pvp_shields_display()
|
||||
|
||||
-- set the spawn point
|
||||
local pos = {x = town_center.market.position.x, y = town_center.market.position.y + 4}
|
||||
@ -634,7 +653,7 @@ commands.add_command(
|
||||
|
||||
Event.add(defines.events.on_built_entity, on_built_entity)
|
||||
Event.add(defines.events.on_player_repaired_entity, on_player_repaired_entity)
|
||||
Event.on_nth_tick(60, update_protection_display)
|
||||
Event.on_nth_tick(60, update_pvp_shields_display)
|
||||
--Event.add(defines.events.on_robot_repaired_entity, on_robot_repaired_entity)
|
||||
Event.add(defines.events.on_entity_damaged, on_entity_damaged)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user