mirror of
https://github.com/ComfyFactory/ComfyFactorio.git
synced 2024-12-30 23:17:53 +02:00
Scrap Towny - minor changes
This commit is contained in:
parent
ebed7f49e0
commit
f8eed9baab
@ -4,7 +4,6 @@ local math_floor = math.floor
|
||||
local table_insert = table.insert
|
||||
local table_size = table.size
|
||||
local ScenarioTable = require 'maps.scrap_towny_ffa.table'
|
||||
local PvPShield = require 'maps.scrap_towny_ffa.pvp_shield'
|
||||
|
||||
local town_zoning_entity_types = { "wall", "gate", "electric-pole", "ammo-turret", "electric-turret", "fluid-turret"}
|
||||
|
||||
@ -236,11 +235,10 @@ local function process_built_entities(event)
|
||||
force_name = force.name
|
||||
end
|
||||
|
||||
if PvPShield.in_other_zones(surface, position, force) or Public.near_another_town(force_name, position, surface, 32) == true then
|
||||
if Public.near_another_town(force_name, position, surface, 32) == true then
|
||||
if neutral_whitelist[name] then
|
||||
entity.force = game.forces['neutral']
|
||||
else
|
||||
-- Prevent entities from being built near towns
|
||||
entity.destroy()
|
||||
if player_index ~= nil then
|
||||
local player = game.players[player_index]
|
||||
|
@ -1,8 +1,7 @@
|
||||
local Event = require 'utils.event'
|
||||
local Public = {}
|
||||
|
||||
local player_ammo_damage_starting_modifiers = {
|
||||
--['artillery-shell'] = -0.75,
|
||||
--['biological'] = -0.5,
|
||||
['bullet'] = 0,
|
||||
['cannon-shell'] = -0.5,
|
||||
['capsule'] = 0,
|
||||
@ -12,13 +11,9 @@ local player_ammo_damage_starting_modifiers = {
|
||||
['flamethrower'] = 0,
|
||||
['grenade'] = -0.5,
|
||||
['landmine'] = -0.75,
|
||||
--['melee'] = 2,
|
||||
--['rocket'] = -0.75,
|
||||
['shotgun-shell'] = 0
|
||||
}
|
||||
local player_ammo_damage_modifiers = {
|
||||
--['artillery-shell'] = -0.75,
|
||||
--['biological'] = -0.5,
|
||||
['bullet'] = 0,
|
||||
['cannon-shell'] = -0.5,
|
||||
['capsule'] = 0,
|
||||
@ -28,13 +23,9 @@ local player_ammo_damage_modifiers = {
|
||||
['flamethrower'] = 0,
|
||||
['grenade'] = -0.5,
|
||||
['landmine'] = -0.5,
|
||||
--['melee'] = 0,
|
||||
--['rocket'] = -0.5,
|
||||
['shotgun-shell'] = 0
|
||||
}
|
||||
local player_gun_speed_modifiers = {
|
||||
--['artillery-shell'] = -0.75,
|
||||
--['biological'] = -0.5,
|
||||
['bullet'] = 0,
|
||||
['cannon-shell'] = -0.5,
|
||||
['capsule'] = -0.5,
|
||||
@ -44,51 +35,9 @@ local player_gun_speed_modifiers = {
|
||||
['flamethrower'] = 0,
|
||||
['grenade'] = -0.5,
|
||||
['landmine'] = 0,
|
||||
--['melee'] = 1,
|
||||
--['rocket'] = -0.75,
|
||||
['shotgun-shell'] = 0
|
||||
}
|
||||
|
||||
--local player_turrets_research_modifiers = {
|
||||
-- ['gun-turret'] = 0,
|
||||
-- ['laser-turret'] = 1.5,
|
||||
-- ['flamethrower-turret'] = 0
|
||||
--}
|
||||
|
||||
--local enemy_ammo_starting_modifiers = {
|
||||
-- ['artillery-shell'] = 3,
|
||||
-- ['biological'] = 3,
|
||||
-- ['bullet'] = 2,
|
||||
-- ['cannon-shell'] = 0,
|
||||
-- ['capsule'] = 0,
|
||||
-- ['beam'] = 0,
|
||||
-- ['laser'] = 0,
|
||||
-- ['electric'] = 0,
|
||||
-- ['flamethrower'] = 0,
|
||||
-- ['grenade'] = 0,
|
||||
-- ['landmine'] = 0,
|
||||
-- ['melee'] = 1,
|
||||
-- ['rocket'] = 0,
|
||||
-- ['shotgun-shell'] = 0
|
||||
--}
|
||||
|
||||
--local enemy_ammo_evolution_modifiers = {
|
||||
-- ['artillery-shell'] = 1,
|
||||
-- ['biological'] = 2,
|
||||
-- ['bullet'] = 1,
|
||||
-- --['cannon-shell'] = 1,
|
||||
-- ['capsule'] = 1,
|
||||
-- ['beam'] = 1,
|
||||
-- ['laser'] = 1,
|
||||
-- ['electric'] = 1,
|
||||
-- ['flamethrower'] = 2,
|
||||
-- --['grenade'] = 1,
|
||||
-- --['landmine'] = 1,
|
||||
-- ['melee'] = 2
|
||||
-- --['rocket'] = 1,
|
||||
-- --['shotgun-shell'] = 1
|
||||
--}
|
||||
|
||||
function Public.init_player_weapon_damage(force)
|
||||
for k, v in pairs(player_ammo_damage_starting_modifiers) do
|
||||
force.set_ammo_damage_modifier(k, v)
|
||||
@ -101,27 +50,6 @@ function Public.init_player_weapon_damage(force)
|
||||
force.set_turret_attack_modifier('laser-turret', 3)
|
||||
end
|
||||
|
||||
--local function init_enemy_weapon_damage()
|
||||
-- local e_force = game.forces['enemy']
|
||||
--
|
||||
-- for k, v in pairs(enemy_ammo_starting_modifiers) do
|
||||
-- e_force.set_ammo_damage_modifier(k, v)
|
||||
-- end
|
||||
--end
|
||||
--
|
||||
--local function enemy_weapon_damage()
|
||||
-- local f = game.forces.enemy
|
||||
--
|
||||
-- local ef = f.evolution_factor
|
||||
--
|
||||
-- for k, v in pairs(enemy_ammo_evolution_modifiers) do
|
||||
-- local base = enemy_ammo_starting_modifiers[k]
|
||||
--
|
||||
-- local new = base + v * ef
|
||||
-- f.set_ammo_damage_modifier(k, new)
|
||||
-- end
|
||||
--end
|
||||
|
||||
-- After a research is finished and the game applied the modifier, we reduce modifiers to achieve the reduction
|
||||
local function research_finished(event)
|
||||
local r = event.research
|
||||
@ -138,15 +66,6 @@ local function research_finished(event)
|
||||
local current_m = p_force.get_ammo_damage_modifier(category)
|
||||
p_force.set_ammo_damage_modifier(category, current_m + factor * e.modifier)
|
||||
end
|
||||
--elseif t == 'turret-attack' then -- NOTE: this doesn't trigger for laser turrets :-(
|
||||
-- local category = e.turret_id
|
||||
-- local factor = player_turrets_research_modifiers[category]
|
||||
-- game.print("XDB cat " .. category)
|
||||
-- if factor then
|
||||
-- local current_m = p_force.get_turret_attack_modifier(category)
|
||||
-- game.print("XDB mod " .. current_m .. " -> " .. current_m + factor * e.modifier)
|
||||
-- p_force.set_turret_attack_modifier(category, current_m + factor * e.modifier)
|
||||
-- end
|
||||
elseif t == 'gun-speed' then
|
||||
local category = e.ammo_category
|
||||
local factor = player_gun_speed_modifiers[category]
|
||||
@ -159,8 +78,5 @@ local function research_finished(event)
|
||||
end
|
||||
end
|
||||
|
||||
local Event = require 'utils.event'
|
||||
--Event.on_init(init_enemy_weapon_damage)
|
||||
--Event.on_nth_tick(18000, enemy_weapon_damage)
|
||||
Event.add(defines.events.on_research_finished, research_finished)
|
||||
return Public
|
||||
return Public
|
||||
|
@ -1,20 +1,20 @@
|
||||
local Public = {}
|
||||
|
||||
local info =
|
||||
[[This is the wasteland. Who will survive?
|
||||
local info = [[This is the wasteland. Who will survive?
|
||||
|
||||
In this mode, players build towns and fight against other towns and the biters.
|
||||
The Comfy gui has been disabled since it contains too many goodies.
|
||||
|
||||
Have fun and be comfy ^.^]]
|
||||
|
||||
local info_adv =
|
||||
[[
|
||||
# Changelog (10th-16th October 2022):
|
||||
- PvP shields now prevent building inside
|
||||
# Changelog (21th October 2022):
|
||||
- Suicide command has been added. The poison pill will kill the character after 3 minutes
|
||||
- Game will automatically reset whenever a town reaches 48h of survival time
|
||||
- PvP Shield has been removed
|
||||
- Combat balance overhaul (see "Bonuses" button top right to check modifiers)
|
||||
- Town player limit fixes
|
||||
- Towns have an initial PvP protection shield - size and duration is scaled with the biggest town size
|
||||
- Temporary PvP shield available in market for breaks / AFK
|
||||
- Improved base defenses and offline survivability
|
||||
- Loads of bugfixes including freezes and desyncs
|
||||
|
||||
@ -34,9 +34,6 @@ Survive as long as you can. Raid other towns. Defend your town.
|
||||
Tip: use filter inserters with to get coins/iron/.. out of the market
|
||||
- Fishes procreate near towns. The more fishes, the quicker they multiply. Automated fish farm, anyone?
|
||||
- Use /rename-town NEWNAME (chat command) to rename your town
|
||||
- PvP shields prevent players from entering and building inside, but they can still shoot inside!
|
||||
- Your town has a AFK PvP shield that you can use to safely take a quick break
|
||||
without other players killing your town. Deploy it from the market.
|
||||
|
||||
# Town members and alliances
|
||||
- Once a town is formed, members may invite other players and teams using a coin. To invite another player, drop a coin
|
||||
|
@ -58,10 +58,6 @@ local function on_chunk_charted(event)
|
||||
local health_text = town_center.health_text
|
||||
update_forces(health_text)
|
||||
add_force(health_text, force.name)
|
||||
-- protection text
|
||||
local shield_text = town_center.shield_text
|
||||
update_forces(shield_text)
|
||||
add_force(shield_text, force.name)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -21,6 +21,7 @@ require 'maps.scrap_towny_ffa.vehicles'
|
||||
require 'maps.scrap_towny_ffa.suicide'
|
||||
|
||||
local Event = require 'utils.event'
|
||||
local Alert = require 'utils.alert'
|
||||
local Autostash = require 'modules.autostash'
|
||||
local MapDefaults = require 'maps.scrap_towny_ffa.map_defaults'
|
||||
local BottomFrame = require 'utils.gui.bottom_frame'
|
||||
@ -36,24 +37,21 @@ local Evolution = require 'maps.scrap_towny_ffa.evolution'
|
||||
local mod_gui = require('mod-gui')
|
||||
local Gui = require 'utils.gui'
|
||||
local Color = require 'utils.color_presets'
|
||||
local Server = require 'utils.server'
|
||||
local Where = require 'utils.commands.where'
|
||||
local Inventory = require 'modules.show_inventory'
|
||||
|
||||
local function spairs(t, order)
|
||||
local function spairs(t)
|
||||
local keys = {}
|
||||
for k in pairs(t) do
|
||||
keys[#keys + 1] = k
|
||||
end
|
||||
if order then
|
||||
table.sort(
|
||||
keys,
|
||||
function(a, b)
|
||||
return order(t, a, b)
|
||||
end
|
||||
)
|
||||
else
|
||||
table.sort(keys)
|
||||
end
|
||||
table.sort(
|
||||
keys,
|
||||
function(a, b)
|
||||
return t[b] < t[a]
|
||||
end
|
||||
)
|
||||
local i = 0
|
||||
return function()
|
||||
i = i + 1
|
||||
@ -79,6 +77,50 @@ end
|
||||
local function update_score()
|
||||
local this = ScenarioTable.get_table()
|
||||
|
||||
if this.winner then
|
||||
if not this.game_won then
|
||||
this.game_won = true
|
||||
this.game_reset_tick = 5400
|
||||
Alert.alert_all_players(900, 'Winner winner chicken dinner!\n[color=red]' .. this.winner.name .. '[/color] has won the game!', Color.white, 'restart_required', 1.0)
|
||||
for _, player in pairs(game.connected_players) do
|
||||
player.play_sound {path = 'utility/game_won', volume_modifier = 0.75}
|
||||
end
|
||||
local winner = this.winner
|
||||
local message = {
|
||||
title = 'Game over',
|
||||
description = 'Town statistics is below',
|
||||
color = 'success',
|
||||
field1 = {
|
||||
text1 = 'Town won:',
|
||||
text2 = winner.name,
|
||||
inline = 'false'
|
||||
},
|
||||
field2 = {
|
||||
text1 = 'Town researched:',
|
||||
text2 = winner.name .. ' with a score of ' .. winner.research_counter .. ' techs!',
|
||||
inline = 'false'
|
||||
},
|
||||
field3 = {
|
||||
text1 = 'Town upgrades:',
|
||||
text2 = winner.name .. ' upgraded their town with:\nCrafting speed:' .. winner.upgrades.crafting_speed .. '\nMining speed:' .. winner.upgrades.mining_speed,
|
||||
inline = 'false'
|
||||
},
|
||||
field4 = {
|
||||
text1 = 'Town health:',
|
||||
text2 = winner.name .. ' had a health of ' .. winner.health .. ' left!',
|
||||
inline = 'false'
|
||||
},
|
||||
field5 = {
|
||||
text1 = 'Town coins:',
|
||||
text2 = winner.name .. ' had ' .. winner.coin_balance .. ' coins stashed!',
|
||||
inline = 'false'
|
||||
}
|
||||
}
|
||||
Server.to_discord_embed_parsed(message)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
for _, player in pairs(game.connected_players) do
|
||||
local frame = this.score_gui_frame[player.index]
|
||||
if not (frame and frame.valid) then
|
||||
@ -118,12 +160,7 @@ local function update_score()
|
||||
|
||||
local rank = 1
|
||||
|
||||
for town_center, age in spairs(
|
||||
town_ages,
|
||||
function(t, a, b)
|
||||
return t[b] < t[a]
|
||||
end
|
||||
) do
|
||||
for town_center, age in spairs(town_ages) do
|
||||
local position = information_table.add {type = 'label', caption = '#' .. rank}
|
||||
if town_center == this.town_centers[player.force.name] then
|
||||
position.style.font = 'default-semibold'
|
||||
@ -137,9 +174,20 @@ local function update_score()
|
||||
label.style.font = 'default-semibold'
|
||||
label.style.font_color = town_center.color
|
||||
local age_hours = age / 60 / 3600
|
||||
information_table.add {type = 'label', caption = string.format('%.1f', age_hours) .. 'h'}
|
||||
local total_age = string.format('%.1f', age_hours)
|
||||
information_table.add {type = 'label', caption = total_age .. 'h'}
|
||||
|
||||
rank = rank + 1
|
||||
|
||||
if tonumber(total_age) >= this.required_time_to_win then
|
||||
this.winner = {
|
||||
name = town_center.town_name,
|
||||
research_counter = town_center.research_counter,
|
||||
upgrades = town_center.upgrades,
|
||||
health = town_center.health,
|
||||
coin_balance = town_center.coin_balance
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- Outlander section
|
||||
@ -229,7 +277,7 @@ Event.on_nth_tick(60, on_nth_tick) -- once every second
|
||||
Event.on_nth_tick(60 * 30, ui_smell_evolution)
|
||||
Event.on_nth_tick(60, update_score)
|
||||
|
||||
--Disable the comfy main gui since we good too many goodies there.
|
||||
--Disable the comfy main gui since we got too many goodies there.
|
||||
Event.add(
|
||||
defines.events.on_gui_click,
|
||||
function(event)
|
||||
|
@ -2,7 +2,6 @@ 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
|
||||
@ -87,33 +86,6 @@ 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, 120, 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
|
||||
}
|
||||
|
||||
@ -162,7 +134,6 @@ local function set_offers(town_center)
|
||||
special_offers[6] = {{{'coin', (town_center.upgrades.laser_turret.slots * 200)}}, 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,185 +0,0 @@
|
||||
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 beam_type = 'electric-beam-no-sound'
|
||||
|
||||
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
|
||||
surface.create_entity({name = beam_type, position = {right, bottom},
|
||||
source = {right, bottom}, target = {left, bottom + 0.5}})
|
||||
surface.create_entity({name = beam_type, position = {left, bottom},
|
||||
source = {left, bottom}, target = {left, top}})
|
||||
surface.create_entity({name = beam_type, position = {left, top - 0.5},
|
||||
source = {left, top - 0.5}, target = {right, top}})
|
||||
end
|
||||
|
||||
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_by_lifetime(shield)
|
||||
local time_scale = math.min(1, (game.tick - shield.lifetime_start) / shield.time_to_full_size_ticks)
|
||||
local scaled_size = time_scale * shield.max_size
|
||||
|
||||
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}}
|
||||
shield.box = box
|
||||
shield.size = scaled_size
|
||||
end
|
||||
|
||||
function Public.add_shield(surface, force, center, max_size, lifetime_ticks, time_to_full_size_ticks, is_pause_mode)
|
||||
local this = ScenarioTable.get_table()
|
||||
|
||||
local shield = {surface = surface, force = force, center = center, max_size = max_size, 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
|
||||
-- Kick players out of vehicles if needed
|
||||
for _, player in pairs(force.connected_players) do
|
||||
if player.character.driving then
|
||||
player.character.driving = false
|
||||
end
|
||||
end
|
||||
shield.force.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_by_lifetime(shield)
|
||||
this.pvp_shields[force.name] = shield
|
||||
end
|
||||
|
||||
function Public.remove_shield(shield)
|
||||
local this = ScenarioTable.get_table()
|
||||
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(shield)
|
||||
return shield.max_lifetime_ticks - (game.tick - shield.lifetime_start)
|
||||
end
|
||||
|
||||
local function update_shield_lifetime()
|
||||
local this = ScenarioTable.get_table()
|
||||
for _, shield in pairs(this.pvp_shields) do
|
||||
if Public.remaining_lifetime(shield) > 0 then
|
||||
if shield.size < shield.max_size then
|
||||
remove_drawn_borders(shield)
|
||||
scale_size_by_lifetime(shield)
|
||||
draw_borders(shield)
|
||||
|
||||
-- Push everyone out as we grow (even if they're just standing)
|
||||
for _, player in pairs(game.connected_players) do
|
||||
Public.push_enemies_out(player)
|
||||
end
|
||||
end
|
||||
else
|
||||
Public.remove_shield(shield)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function vector_norm(vector)
|
||||
return math_sqrt(vector.x ^ 2 + vector.y ^ 2)
|
||||
end
|
||||
|
||||
function Public.in_other_zones(surface, position, force)
|
||||
local this = ScenarioTable.get_table()
|
||||
for _, shield in pairs(this.pvp_shields) do
|
||||
if not (shield.force == force or surface ~= shield.surface) then
|
||||
if CommonFunctions.point_in_bounding_box(position, shield.box) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function Public.push_enemies_out(player)
|
||||
local this = ScenarioTable.get_table()
|
||||
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 - 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)
|
||||
|
||||
-- Kick players out of vehicles if needed
|
||||
if player.character.driving then
|
||||
player.character.driving = false
|
||||
end
|
||||
|
||||
-- Damage player
|
||||
player.character.health = player.character.health - 25
|
||||
player.character.surface.create_entity({name = 'water-splash', position = player.position})
|
||||
if player.character.health <= 0 then
|
||||
player.character.die('enemy')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function on_player_changed_position(event)
|
||||
local player = game.get_player(event.player_index)
|
||||
local surface = player.surface
|
||||
if not surface or not surface.valid then
|
||||
return
|
||||
end
|
||||
|
||||
Public.push_enemies_out(player)
|
||||
end
|
||||
|
||||
local function on_player_driving_changed_state(event)
|
||||
local player = game.players[event.player_index]
|
||||
if not player or not player.valid then
|
||||
return
|
||||
end
|
||||
local this = ScenarioTable.get_table()
|
||||
for _, shield in pairs(this.pvp_shields) do
|
||||
if shield.force == player.force and shield.is_pause_mode then
|
||||
local vehicle = player.vehicle
|
||||
if vehicle and vehicle.valid then
|
||||
-- Kick players out of vehicles if needed
|
||||
if player.character.driving then
|
||||
player.character.driving = false
|
||||
player.print("Can't drive around while AFK PvP Shield is active")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Event.add(defines.events.on_player_driving_changed_state, on_player_driving_changed_state)
|
||||
Event.add(defines.events.on_player_changed_position, on_player_changed_position)
|
||||
Event.on_nth_tick(60, update_shield_lifetime)
|
||||
|
||||
return Public
|
@ -47,57 +47,106 @@ local function armageddon()
|
||||
end
|
||||
end
|
||||
|
||||
local function reset_map()
|
||||
local this = ScenarioTable.get_table()
|
||||
local function has_the_game_ended()
|
||||
local game_reset_tick = ScenarioTable.get('game_reset_tick')
|
||||
if game_reset_tick then
|
||||
if game_reset_tick < 0 then
|
||||
return
|
||||
end
|
||||
|
||||
if this.shutdown then
|
||||
Server.to_discord_bold('*** Soft-reset is disabled! Server will shutdown. Most likely because of updates. ***', true)
|
||||
return Server.stop_scenario()
|
||||
end
|
||||
local this = ScenarioTable.get_table()
|
||||
|
||||
if this.restart then
|
||||
Server.to_discord_bold('*** Soft-reset is disabled! Server will restart to load new changes. ***', true)
|
||||
return Server.start_scenario('Towny')
|
||||
end
|
||||
this.game_reset_tick = this.game_reset_tick - 30
|
||||
if this.game_reset_tick % 1800 == 0 then
|
||||
if this.game_reset_tick > 0 then
|
||||
local cause_msg
|
||||
if this.restart then
|
||||
cause_msg = 'restart'
|
||||
elseif this.shutdown then
|
||||
cause_msg = 'shutdown'
|
||||
elseif this.soft_reset then
|
||||
cause_msg = 'soft-reset'
|
||||
end
|
||||
|
||||
for _, player in pairs(game.players) do
|
||||
local frame = this.score_gui_frame[player.index]
|
||||
if frame and frame.valid then
|
||||
frame.destroy()
|
||||
game.print(({'main.reset_in', cause_msg, this.game_reset_tick / 60}), {r = 0.22, g = 0.88, b = 0.22})
|
||||
end
|
||||
|
||||
if this.soft_reset and this.game_reset_tick == 0 then
|
||||
for _, player in pairs(game.players) do
|
||||
local frame = this.score_gui_frame[player.index]
|
||||
if frame and frame.valid then
|
||||
frame.destroy()
|
||||
end
|
||||
end
|
||||
this.game_reset_tick = nil
|
||||
this.game_won = false
|
||||
ScenarioTable.reset_table()
|
||||
local surface = game.surfaces['nauvis']
|
||||
if get_victorious_force() then
|
||||
surface.play_sound({path = 'utility/game_won', volume_modifier = 1})
|
||||
else
|
||||
surface.play_sound({path = 'utility/game_lost', volume_modifier = 1})
|
||||
end
|
||||
game.reset_time_played()
|
||||
game.reset_game_state()
|
||||
for _, player in pairs(game.players) do
|
||||
player.teleport({0, 0}, game.surfaces['limbo'])
|
||||
end
|
||||
Nauvis.initialize()
|
||||
Team.initialize()
|
||||
if game.forces['rogue'] == nil then
|
||||
log('rogue force is missing!')
|
||||
end
|
||||
for _, player in pairs(game.players) do
|
||||
Player.increment()
|
||||
Player.initialize(player)
|
||||
Team.set_player_color(player)
|
||||
Player.spawn(player)
|
||||
Player.load_buffs(player)
|
||||
Player.requests(player)
|
||||
end
|
||||
|
||||
Alert.alert_all_players(5, 'The world has been reset!', Color.white, 'restart_required', 1.0)
|
||||
game.print('The world has been reset!', {r = 0.22, g = 0.88, b = 0.22})
|
||||
|
||||
Server.to_discord_embed('*** The world has been reset! ***')
|
||||
return
|
||||
end
|
||||
|
||||
if this.restart and this.game_reset_tick == 0 then
|
||||
if not this.announced_message then
|
||||
game.print(({'entity.notify_restart'}), {r = 0.22, g = 0.88, b = 0.22})
|
||||
local message = 'Soft-reset is disabled! Server will restart from scenario to load new changes.'
|
||||
Server.to_discord_bold(table.concat {'*** ', message, ' ***'})
|
||||
Server.start_scenario('Towny')
|
||||
this.announced_message = true
|
||||
return
|
||||
end
|
||||
end
|
||||
if this.shutdown and this.game_reset_tick == 0 then
|
||||
if not this.announced_message then
|
||||
game.print(({'entity.notify_shutdown'}), {r = 0.22, g = 0.88, b = 0.22})
|
||||
local message = 'Soft-reset is disabled! Server will shutdown. Most likely because of updates.'
|
||||
Server.to_discord_bold(table.concat {'*** ', message, ' ***'})
|
||||
Server.stop_scenario()
|
||||
this.announced_message = true
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
ScenarioTable.reset_table()
|
||||
local surface = game.surfaces['nauvis']
|
||||
if get_victorious_force() then
|
||||
surface.play_sound({path = 'utility/game_won', volume_modifier = 1})
|
||||
else
|
||||
surface.play_sound({path = 'utility/game_lost', volume_modifier = 1})
|
||||
end
|
||||
game.reset_time_played()
|
||||
game.reset_game_state()
|
||||
for _, player in pairs(game.players) do
|
||||
player.teleport({0, 0}, game.surfaces['limbo'])
|
||||
end
|
||||
Nauvis.initialize()
|
||||
Team.initialize()
|
||||
if game.forces['rogue'] == nil then
|
||||
log('rogue force is missing!')
|
||||
end
|
||||
for _, player in pairs(game.players) do
|
||||
Player.increment()
|
||||
Player.initialize(player)
|
||||
Team.set_player_color(player)
|
||||
Player.spawn(player)
|
||||
Player.load_buffs(player)
|
||||
Player.requests(player)
|
||||
end
|
||||
Alert.alert_all_players(5, 'The world has been reset!', Color.white, 'restart_required', 1.0)
|
||||
Server.to_discord_embed('*** The world has been reset! ***')
|
||||
end
|
||||
|
||||
local function on_tick()
|
||||
local tick = game.tick
|
||||
if tick > 0 then
|
||||
if tick % 40 == 0 then
|
||||
local game_won = ScenarioTable.get('game_won')
|
||||
if game_won then
|
||||
has_the_game_ended()
|
||||
end
|
||||
end
|
||||
|
||||
if (tick + armageddon_duration + warning_duration) % game_duration == 0 then
|
||||
warning()
|
||||
end
|
||||
@ -109,7 +158,7 @@ local function on_tick()
|
||||
Team.reset_all_forces()
|
||||
end
|
||||
if tick % game_duration == 0 then
|
||||
reset_map()
|
||||
has_the_game_ended()
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -193,12 +242,12 @@ commands.add_command(
|
||||
else
|
||||
game.print(mapkeeper .. ' server, has reset the game!', {r = 0.98, g = 0.66, b = 0.22})
|
||||
end
|
||||
reset_map()
|
||||
has_the_game_ended()
|
||||
p('[WARNING] Game has been reset!')
|
||||
return
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
Event.add(defines.events.on_tick, on_tick)
|
||||
Event.on_nth_tick(10, on_tick)
|
||||
Event.add(defines.events.on_rocket_launched, on_rocket_launched)
|
||||
|
@ -2,10 +2,10 @@ local Scheduler = require 'utils.scheduler'
|
||||
local ScenarioTable = require 'maps.scrap_towny_ffa.table'
|
||||
local Event = require 'utils.event'
|
||||
|
||||
local yellow = { r = 200, g = 200, b = 0 }
|
||||
local yellow = {r = 200, g = 200, b = 0}
|
||||
|
||||
-- Must be at least 1 minute
|
||||
local minutes_to_die = 10
|
||||
local minutes_to_die = 5
|
||||
|
||||
local one_minute = 60 * 60
|
||||
|
||||
@ -17,56 +17,58 @@ end
|
||||
|
||||
Event.add(defines.events.on_player_died, on_player_died)
|
||||
|
||||
local suicide_handler = Scheduler.set(function(data)
|
||||
for i = 1, #data do
|
||||
local this = ScenarioTable.get_table()
|
||||
local player_index = data[i].player_index
|
||||
local player = game.get_player(player_index)
|
||||
if not player or not player.valid or not player.character then
|
||||
return
|
||||
end
|
||||
|
||||
if not this.suicides[player.index] then
|
||||
-- the suicide was cancelled (the character died)
|
||||
return
|
||||
end
|
||||
|
||||
local minutes_remaining = this.suicides[player.index].minutes_remaining
|
||||
|
||||
if minutes_remaining <= 0 then
|
||||
player.character.die(player.force, player.character)
|
||||
this.suicides[player.index] = nil
|
||||
else
|
||||
if minutes_remaining == 1 then
|
||||
player.print(minutes_remaining .. " minute remaining until death.", yellow)
|
||||
else
|
||||
player.print(minutes_remaining .. " minutes remaining until death.", yellow)
|
||||
local suicide_handler =
|
||||
Scheduler.set(
|
||||
function(data)
|
||||
for i = 1, #data do
|
||||
local this = ScenarioTable.get_table()
|
||||
local player_index = data[i].player_index
|
||||
local player = game.get_player(player_index)
|
||||
if not player or not player.valid or not player.character then
|
||||
return
|
||||
end
|
||||
|
||||
if not this.suicides[player.index] then
|
||||
-- the suicide was cancelled (the character died)
|
||||
return
|
||||
end
|
||||
|
||||
local minutes_remaining = this.suicides[player.index].minutes_remaining
|
||||
|
||||
if minutes_remaining <= 0 then
|
||||
player.character.die()
|
||||
this.suicides[player.index] = nil
|
||||
else
|
||||
if minutes_remaining == 1 then
|
||||
player.print(minutes_remaining .. ' minute remaining until death.', yellow)
|
||||
else
|
||||
player.print(minutes_remaining .. ' minutes remaining until death.', yellow)
|
||||
end
|
||||
this.suicides[player.index].minutes_remaining = this.suicides[player.index].minutes_remaining - 1
|
||||
Scheduler.timer(game.tick + one_minute, data[i].handler, {player_index = player.index, handler = data[i].handler})
|
||||
end
|
||||
this.suicides[player.index].minutes_remaining = this.suicides[player.index].minutes_remaining - 1
|
||||
Scheduler.timer(game.tick + one_minute, data[i].handler, { player_index = player.index, handler = data[i].handler})
|
||||
end
|
||||
end
|
||||
|
||||
end)
|
||||
)
|
||||
|
||||
commands.add_command(
|
||||
'suicide',
|
||||
'Kills the player',
|
||||
function()
|
||||
local this = ScenarioTable.get_table()
|
||||
local player = game.player
|
||||
'suicide',
|
||||
'Kills the player',
|
||||
function()
|
||||
local this = ScenarioTable.get_table()
|
||||
local player = game.player
|
||||
|
||||
if not player or not player.valid then
|
||||
return
|
||||
end
|
||||
|
||||
if this.suicides[player.index] then
|
||||
player.print("You are already dying!", yellow)
|
||||
return
|
||||
end
|
||||
|
||||
this.suicides[player.index] = {minutes_remaining = minutes_to_die - 1}
|
||||
Scheduler.timer(game.tick + one_minute, suicide_handler, { player_index = player.index, handler = suicide_handler })
|
||||
player.print("You ate a poison pill. You will die in " .. minutes_to_die .. " minutes.", yellow)
|
||||
if not player or not player.valid then
|
||||
return
|
||||
end
|
||||
|
||||
if this.suicides[player.index] then
|
||||
player.print('You are already dying!', yellow)
|
||||
return
|
||||
end
|
||||
|
||||
this.suicides[player.index] = {minutes_remaining = minutes_to_die - 1}
|
||||
Scheduler.timer(game.tick + one_minute, suicide_handler, {player_index = player.index, handler = suicide_handler})
|
||||
player.print('You ate a poison pill. You will die in ' .. minutes_to_die .. ' minutes.', yellow)
|
||||
end
|
||||
)
|
||||
|
@ -36,9 +36,11 @@ function Public.reset_table()
|
||||
this.mining_entity = {}
|
||||
this.mining_target = {}
|
||||
this.spaceships = {}
|
||||
this.pvp_shields = {}
|
||||
this.pvp_shield_warned = {}
|
||||
this.suicides = {}
|
||||
this.required_time_to_win = 48
|
||||
this.announced_message = nil
|
||||
this.soft_reset = true
|
||||
this.winner = nil
|
||||
end
|
||||
|
||||
function Public.get_table()
|
||||
|
@ -9,7 +9,6 @@ local math_min = math.min
|
||||
local Server = require 'utils.server'
|
||||
local Map = require 'maps.scrap_towny_ffa.map'
|
||||
local ScenarioTable = require 'maps.scrap_towny_ffa.table'
|
||||
local PvPShield = require 'maps.scrap_towny_ffa.pvp_shield'
|
||||
local CombatBalance = require 'maps.scrap_towny_ffa.combat_balance'
|
||||
|
||||
local outlander_color = {150, 150, 150}
|
||||
@ -804,9 +803,6 @@ local function kill_force(force_name, cause)
|
||||
e.destroy()
|
||||
end
|
||||
end
|
||||
if this.pvp_shields[force_name] then
|
||||
PvPShield.remove_shield(this.pvp_shields[force_name])
|
||||
end
|
||||
|
||||
game.merge_forces(force_name, 'neutral')
|
||||
this.town_centers[force_name] = nil
|
||||
|
@ -4,7 +4,6 @@ local math_random = math.random
|
||||
local table_insert = table.insert
|
||||
local math_floor = math.floor
|
||||
local math_sqrt = math.sqrt
|
||||
local math_min = math.min
|
||||
local table_shuffle = table.shuffle_table
|
||||
local table_size = table.size
|
||||
|
||||
@ -16,8 +15,6 @@ local Building = require 'maps.scrap_towny_ffa.building'
|
||||
local Colors = require 'maps.scrap_towny_ffa.colors'
|
||||
local Enemy = require 'maps.scrap_towny_ffa.enemy'
|
||||
local Color = require 'utils.color_presets'
|
||||
local PvPShield = require 'maps.scrap_towny_ffa.pvp_shield'
|
||||
local Evolution = require 'maps.scrap_towny_ffa.evolution'
|
||||
|
||||
local town_radius = 27
|
||||
local radius_between_towns = 120
|
||||
@ -378,10 +375,9 @@ function Public.enemy_players_nearby(town_center, max_radius)
|
||||
|
||||
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))
|
||||
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
|
||||
if player.force ~= 'enemy' and (own_force ~= player.force and not own_force.get_friend(player.force)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
@ -390,38 +386,6 @@ function Public.enemy_players_nearby(town_center, max_radius)
|
||||
return false
|
||||
end
|
||||
|
||||
local function update_pvp_shields_display()
|
||||
local this = ScenarioTable.get_table()
|
||||
for _, town_center in pairs(this.town_centers) do
|
||||
local shield = this.pvp_shields[town_center.market.force.name]
|
||||
local info
|
||||
if shield then
|
||||
info = 'PvP Shield: ' .. string.format("%.0f", (PvPShield.remaining_lifetime(shield)) / 60 / 60) .. ' minutes'
|
||||
else
|
||||
info = ''
|
||||
end
|
||||
rendering.set_text(town_center.shield_text, info)
|
||||
end
|
||||
end
|
||||
|
||||
local function add_pvp_shield_scaled(position, force, surface)
|
||||
local evo = Evolution.get_highest_evolution()
|
||||
|
||||
local min_size = 70
|
||||
local max_size = 150
|
||||
local min_duration = 0.5 * 60 * 60 * 60
|
||||
local max_duration = 8 * 60 * 60 * 60
|
||||
local lifetime_ticks = math_min(min_duration + 2 * evo * (max_duration - min_duration), max_duration)
|
||||
local size = math_min(min_size + 2 * evo * (max_size - min_size), max_size)
|
||||
|
||||
PvPShield.add_shield(surface, force, position, size, lifetime_ticks, 60 * 60)
|
||||
update_pvp_shields_display()
|
||||
force.print("Based on the highest tech on map, your town deploys a PvP shield of "
|
||||
.. string.format("%.0f", size) .. " tiles"
|
||||
.. " for " .. string.format("%.0f", lifetime_ticks/60/60) .. " minutes."
|
||||
.. " Enemy players will not be able to enter and build in the shielded area.")
|
||||
end
|
||||
|
||||
local function found_town(event)
|
||||
local entity = event.created_entity
|
||||
-- is a valid entity placed?
|
||||
@ -568,19 +532,6 @@ local function found_town(event)
|
||||
scale_with_zoom = false
|
||||
}
|
||||
|
||||
town_center.shield_text = rendering.draw_text {
|
||||
text = 'PvP Shield: (..)',
|
||||
surface = surface,
|
||||
forces = {force_name, game.forces.player, game.forces.rogue},
|
||||
target = town_center.market,
|
||||
target_offset = {0, -2.25},
|
||||
color = {200, 200, 200},
|
||||
scale = 1.00,
|
||||
font = 'default-game',
|
||||
alignment = 'center',
|
||||
scale_with_zoom = false
|
||||
}
|
||||
|
||||
Enemy.clear_enemies(position, surface, town_radius * 5)
|
||||
draw_town_spawn(force_name)
|
||||
|
||||
@ -592,31 +543,12 @@ local function found_town(event)
|
||||
Team.add_player_to_town(player, town_center)
|
||||
Team.remove_key(player.index)
|
||||
Team.add_chart_tag(town_center)
|
||||
add_pvp_shield_scaled({ x = position.x + 0.5, y = position.y + 0.5}, force, surface) -- Market center is slightly shifted
|
||||
|
||||
game.print('>> ' .. player.name .. ' has founded a new town!', {255, 255, 0})
|
||||
Server.to_discord_embed(player.name .. ' has founded a new town!')
|
||||
player.print('Your town color is ' .. crayola.name, crayola.color)
|
||||
end
|
||||
|
||||
local Token = require 'utils.token'
|
||||
local Task = require 'utils.task'
|
||||
|
||||
local do_something_token =
|
||||
Token.register(
|
||||
function(event)
|
||||
local player_index = event.player_index
|
||||
local player = game.get_player(player_index)
|
||||
if not player or not player.valid then
|
||||
return
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
local function some_event_that_fires_the_callback()
|
||||
Task.set_timeout_in_ticks(do_something_token, params)
|
||||
end
|
||||
|
||||
local function on_built_entity(event)
|
||||
found_town(event)
|
||||
end
|
||||
@ -689,7 +621,6 @@ 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_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…
Reference in New Issue
Block a user