1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2025-01-10 00:43:27 +02:00
ComfyFactorio/maps/mountain_fortress_v3/locomotive.lua

2638 lines
84 KiB
Lua
Raw Normal View History

2020-05-17 12:23:55 +02:00
local Event = require 'utils.event'
2020-07-06 15:45:09 +02:00
local Market = require 'maps.mountain_fortress_v3.basic_markets'
2020-12-20 20:56:26 +02:00
local Generate = require 'maps.mountain_fortress_v3.generate'
2020-05-17 12:23:55 +02:00
local ICW = require 'maps.mountain_fortress_v3.icw.main'
local WPT = require 'maps.mountain_fortress_v3.table'
local ICFunctions = require 'maps.mountain_fortress_v3.ic.functions'
2020-07-28 11:24:16 +02:00
local WD = require 'modules.wave_defense.table'
2020-08-14 22:07:54 +02:00
local Session = require 'utils.datastore.session_data'
2020-10-30 23:05:05 +02:00
local Difficulty = require 'modules.difficulty_vote_by_amount'
2020-08-14 22:07:54 +02:00
local Jailed = require 'utils.datastore.jail_data'
2021-05-25 22:19:20 +02:00
local RPG = require 'modules.rpg.main'
2020-07-06 15:45:09 +02:00
local Gui = require 'utils.gui'
2020-06-03 20:09:00 +02:00
local Server = require 'utils.server'
2020-06-07 13:33:24 +02:00
local Alert = require 'utils.alert'
2020-07-06 15:45:09 +02:00
local Math2D = require 'math2d'
local Antigrief = require 'antigrief'
2020-09-17 09:14:07 +02:00
local Task = require 'utils.task'
local Token = require 'utils.token'
local MapFunctions = require 'tools.map_functions'
2020-12-14 20:36:37 +02:00
local SpamProtection = require 'utils.spam_protection'
2020-06-03 20:09:00 +02:00
local format_number = require 'util'.format_number
2020-05-17 12:23:55 +02:00
local Public = {}
2020-06-03 20:09:00 +02:00
local concat = table.concat
2020-07-06 15:45:09 +02:00
local main_frame_name = Gui.uid_name()
2021-05-25 22:19:20 +02:00
local rpg_main_frame = RPG.main_frame_name
2020-08-09 20:22:33 +02:00
local random = math.random
local floor = math.floor
local round = math.round
2020-08-09 20:22:33 +02:00
local rad = math.rad
local sin = math.sin
local cos = math.cos
local ceil = math.ceil
2020-05-17 12:23:55 +02:00
2020-06-07 13:33:24 +02:00
local shopkeeper = '[color=blue]Shopkeeper:[/color]\n'
2020-06-03 20:09:00 +02:00
local space = {
minimal_height = 10,
top_padding = 0,
bottom_padding = 0
}
2020-09-17 09:14:07 +02:00
local function initial_cargo_boxes()
return {
{name = 'loader', count = 1},
{name = 'coal', count = random(32, 64)},
{name = 'coal', count = random(32, 64)},
{name = 'iron-ore', count = random(32, 128)},
{name = 'copper-ore', count = random(32, 128)},
{name = 'empty-barrel', count = random(16, 32)},
{name = 'submachine-gun', count = 1},
{name = 'submachine-gun', count = 1},
{name = 'submachine-gun', count = 1},
{name = 'submachine-gun', count = 1},
{name = 'submachine-gun', count = 1},
{name = 'shotgun', count = 1},
{name = 'shotgun', count = 1},
{name = 'shotgun', count = 1},
{name = 'shotgun-shell', count = random(4, 5)},
{name = 'shotgun-shell', count = random(4, 5)},
{name = 'land-mine', count = random(6, 18)},
{name = 'grenade', count = random(2, 3)},
{name = 'grenade', count = random(2, 3)},
{name = 'grenade', count = random(2, 3)},
{name = 'iron-gear-wheel', count = random(7, 15)},
{name = 'iron-gear-wheel', count = random(7, 15)},
{name = 'iron-gear-wheel', count = random(7, 15)},
{name = 'iron-gear-wheel', count = random(7, 15)},
{name = 'iron-plate', count = random(15, 23)},
{name = 'iron-plate', count = random(15, 23)},
{name = 'iron-plate', count = random(15, 23)},
{name = 'iron-plate', count = random(15, 23)},
{name = 'copper-plate', count = random(15, 23)},
{name = 'copper-plate', count = random(15, 23)},
{name = 'copper-plate', count = random(15, 23)},
{name = 'copper-plate', count = random(15, 23)},
{name = 'firearm-magazine', count = random(10, 30)},
{name = 'firearm-magazine', count = random(10, 30)},
{name = 'firearm-magazine', count = random(10, 30)},
{name = 'rail', count = random(16, 24)},
{name = 'rail', count = random(16, 24)}
}
end
local function add_random_loot_to_main_market(rarity)
local main_market_items = WPT.get('main_market_items')
local items = Market.get_random_item(rarity, true, false)
2020-10-24 14:46:14 +02:00
if not items then
return false
end
local types = game.item_prototypes
for k, v in pairs(main_market_items) do
if not v.static then
main_market_items[k] = nil
end
end
for k, v in pairs(items) do
local price = v.price[1][2] + random(1, 15) * rarity
local value = v.price[1][1]
local stack = 1
if v.offer.item == 'coin' then
price = v.price[1][2]
stack = v.offer.count
if not stack then
stack = v.price[1][2]
end
end
2020-10-24 14:46:14 +02:00
if not main_market_items[v.offer.item] then
main_market_items[v.offer.item] = {
stack = stack,
value = value,
price = price,
tooltip = types[v.offer.item].localised_name,
upgrade = false
}
end
end
end
2020-09-17 09:14:07 +02:00
local set_loco_tiles =
Token.register(
function(data)
local position = data.position
local surface = data.surface
2020-10-21 23:17:17 +02:00
if not surface or not surface.valid then
return
end
2020-09-17 09:14:07 +02:00
local cargo_boxes = initial_cargo_boxes()
local p = {}
for x = position.x - 5, 1, 3 do
for y = 1, position.y + 5, 2 do
if random(1, 4) == 1 then
p[#p + 1] = {x = x, y = y}
end
end
end
2021-04-04 13:50:17 +02:00
if random(1, 6) == 1 then
MapFunctions.draw_noise_tile_circle(position, 'blue-refined-concrete', surface, 18)
elseif random(1, 5) == 1 then
MapFunctions.draw_noise_tile_circle(position, 'black-refined-concrete', surface, 18)
elseif random(1, 4) == 1 then
MapFunctions.draw_noise_tile_circle(position, 'cyan-refined-concrete', surface, 18)
elseif random(1, 3) == 1 then
MapFunctions.draw_noise_tile_circle(position, 'hazard-concrete-right', surface, 18)
else
MapFunctions.draw_noise_tile_circle(position, 'blue-refined-concrete', surface, 18)
end
2020-09-17 09:14:07 +02:00
for i = 1, #cargo_boxes, 1 do
if not p[i] then
break
end
if surface.can_place_entity({name = 'wooden-chest', position = p[i]}) then
local e = surface.create_entity({name = 'wooden-chest', position = p[i], force = 'player', create_build_effect_smoke = false})
2020-12-04 02:09:52 +02:00
e.minable = false
2020-09-17 09:14:07 +02:00
local inventory = e.get_inventory(defines.inventory.chest)
inventory.insert(cargo_boxes[i])
end
end
end
)
2020-06-03 20:09:00 +02:00
local function add_style(frame, style)
for k, v in pairs(style) do
frame.style[k] = v
end
end
local function add_space(frame)
add_style(frame.add {type = 'line', direction = 'horizontal'}, space)
end
2020-05-17 12:23:55 +02:00
local function validate_player(player)
if not player then
return false
end
if not player.valid then
return false
end
if not player.character then
return false
end
if not player.connected then
return false
end
2020-07-06 15:45:09 +02:00
if not game.players[player.name] then
2020-05-17 12:23:55 +02:00
return false
end
return true
end
2020-08-09 20:31:50 +02:00
function Public.add_player_to_permission_group(player, group, forced)
2020-07-25 17:22:04 +02:00
local jailed = Jailed.get_jailed_table()
2020-07-27 11:07:32 +02:00
local enable_permission_group_disconnect = WPT.get('disconnect_wagon')
2020-07-28 11:24:16 +02:00
local session = Session.get_session_table()
local AG = Antigrief.get()
local allow_decon = WPT.get('allow_decon')
local default_group = game.permissions.get_group('Default')
default_group.set_allows_action(defines.input_action.deconstruct, false)
default_group.set_allows_action(defines.input_action.activate_cut, false)
if not game.permissions.get_group('limited') then
local limited_group = game.permissions.create_group('limited')
limited_group.set_allows_action(defines.input_action.cancel_craft, false)
limited_group.set_allows_action(defines.input_action.edit_permission_group, false)
limited_group.set_allows_action(defines.input_action.import_permissions_string, false)
limited_group.set_allows_action(defines.input_action.delete_permission_group, false)
limited_group.set_allows_action(defines.input_action.add_permission_group, false)
limited_group.set_allows_action(defines.input_action.admin_action, false)
limited_group.set_allows_action(defines.input_action.drop_item, false)
if allow_decon then
limited_group.set_allows_action(defines.input_action.deconstruct, true)
else
limited_group.set_allows_action(defines.input_action.deconstruct, false)
end
limited_group.set_allows_action(defines.input_action.activate_cut, false)
end
if not game.permissions.get_group('near_locomotive') then
local near_locomotive_group = game.permissions.create_group('near_locomotive')
near_locomotive_group.set_allows_action(defines.input_action.cancel_craft, false)
near_locomotive_group.set_allows_action(defines.input_action.edit_permission_group, false)
near_locomotive_group.set_allows_action(defines.input_action.import_permissions_string, false)
near_locomotive_group.set_allows_action(defines.input_action.delete_permission_group, false)
near_locomotive_group.set_allows_action(defines.input_action.add_permission_group, false)
near_locomotive_group.set_allows_action(defines.input_action.admin_action, false)
near_locomotive_group.set_allows_action(defines.input_action.drop_item, false)
near_locomotive_group.set_allows_action(defines.input_action.deconstruct, false)
near_locomotive_group.set_allows_action(defines.input_action.activate_cut, false)
end
if not game.permissions.get_group('main_surface') then
local main_surface_group = game.permissions.create_group('main_surface')
main_surface_group.set_allows_action(defines.input_action.edit_permission_group, false)
main_surface_group.set_allows_action(defines.input_action.import_permissions_string, false)
main_surface_group.set_allows_action(defines.input_action.delete_permission_group, false)
main_surface_group.set_allows_action(defines.input_action.add_permission_group, false)
main_surface_group.set_allows_action(defines.input_action.admin_action, false)
main_surface_group.set_allows_action(defines.input_action.deconstruct, false)
main_surface_group.set_allows_action(defines.input_action.activate_cut, false)
2020-08-17 20:18:06 +02:00
end
if not game.permissions.get_group('not_trusted') then
local not_trusted = game.permissions.create_group('not_trusted')
not_trusted.set_allows_action(defines.input_action.cancel_craft, false)
not_trusted.set_allows_action(defines.input_action.edit_permission_group, false)
not_trusted.set_allows_action(defines.input_action.import_permissions_string, false)
not_trusted.set_allows_action(defines.input_action.delete_permission_group, false)
not_trusted.set_allows_action(defines.input_action.add_permission_group, false)
not_trusted.set_allows_action(defines.input_action.admin_action, false)
not_trusted.set_allows_action(defines.input_action.drop_item, false)
not_trusted.set_allows_action(defines.input_action.disconnect_rolling_stock, false)
not_trusted.set_allows_action(defines.input_action.connect_rolling_stock, false)
2021-03-14 23:49:18 +02:00
not_trusted.set_allows_action(defines.input_action.open_train_gui, false)
not_trusted.set_allows_action(defines.input_action.open_train_station_gui, false)
not_trusted.set_allows_action(defines.input_action.open_trains_gui, false)
not_trusted.set_allows_action(defines.input_action.change_train_stop_station, false)
not_trusted.set_allows_action(defines.input_action.change_train_wait_condition, false)
not_trusted.set_allows_action(defines.input_action.change_train_wait_condition_data, false)
not_trusted.set_allows_action(defines.input_action.drag_train_schedule, false)
not_trusted.set_allows_action(defines.input_action.drag_train_wait_condition, false)
not_trusted.set_allows_action(defines.input_action.go_to_train_station, false)
not_trusted.set_allows_action(defines.input_action.remove_train_station, false)
not_trusted.set_allows_action(defines.input_action.set_trains_limit, false)
not_trusted.set_allows_action(defines.input_action.set_train_stopped, false)
not_trusted.set_allows_action(defines.input_action.deconstruct, false)
2021-07-23 17:23:33 +02:00
not_trusted.set_allows_action(defines.input_action.activate_cut, false)
end
if not AG.enabled then
default_group.add_player(player)
return
end
local gulag = game.permissions.get_group('gulag')
local tbl = gulag and gulag.players
for i = 1, #tbl do
if tbl[i].index == player.index then
return
end
end
if player.admin then
return
end
if forced then
default_group.add_player(player)
return
end
local playtime = player.online_time
if session[player.name] then
playtime = player.online_time + session[player.name]
end
if jailed[player.name] then
return
2020-08-17 20:18:06 +02:00
end
2020-07-27 11:07:32 +02:00
if enable_permission_group_disconnect then
local limited_group = game.permissions.get_group('limited')
local main_surface_group = game.permissions.get_group('main_surface')
local near_locomotive_group = game.permissions.get_group('near_locomotive')
if limited_group then
limited_group.set_allows_action(defines.input_action.disconnect_rolling_stock, true)
end
if main_surface_group then
main_surface_group.set_allows_action(defines.input_action.disconnect_rolling_stock, true)
2020-07-27 11:07:32 +02:00
end
if near_locomotive_group then
near_locomotive_group.set_allows_action(defines.input_action.disconnect_rolling_stock, true)
2020-08-17 20:18:06 +02:00
end
2020-10-20 11:17:25 +02:00
if default_group then
default_group.set_allows_action(defines.input_action.disconnect_rolling_stock, true)
end
2020-07-27 11:07:32 +02:00
else
local limited_group = game.permissions.get_group('limited')
local main_surface_group = game.permissions.get_group('main_surface')
local near_locomotive_group = game.permissions.get_group('near_locomotive')
if limited_group then
limited_group.set_allows_action(defines.input_action.disconnect_rolling_stock, false)
2020-07-24 17:33:28 +02:00
end
if main_surface_group then
main_surface_group.set_allows_action(defines.input_action.disconnect_rolling_stock, false)
end
if near_locomotive_group then
near_locomotive_group.set_allows_action(defines.input_action.disconnect_rolling_stock, false)
2020-08-17 20:18:06 +02:00
end
2020-10-20 11:17:25 +02:00
if default_group then
default_group.set_allows_action(defines.input_action.disconnect_rolling_stock, false)
end
2020-07-27 11:07:32 +02:00
end
2020-07-28 11:24:16 +02:00
if playtime < 5184000 then -- 24 hours
2020-08-17 20:18:06 +02:00
local not_trusted = game.permissions.get_group('not_trusted')
2020-07-27 11:07:32 +02:00
not_trusted.add_player(player)
else
if group == 'limited' then
local limited_group = game.permissions.get_group('limited')
limited_group.add_player(player)
elseif group == 'main_surface' then
local main_surface_group = game.permissions.get_group('main_surface')
main_surface_group.add_player(player)
elseif group == 'near_locomotive' then
local near_locomotive_group = game.permissions.get_group('near_locomotive')
near_locomotive_group.add_player(player)
2020-07-27 11:07:32 +02:00
elseif group == 'default' then
default_group.add_player(player)
end
2020-07-24 17:33:28 +02:00
end
end
2020-05-17 12:23:55 +02:00
local function property_boost(data)
2020-08-14 17:16:04 +02:00
local xp_floating_text_color = {r = 188, g = 201, b = 63}
2020-05-17 12:23:55 +02:00
local visuals_delay = 1800
2020-11-17 13:45:27 +02:00
local loco_surface = WPT.get('loco_surface')
if not (loco_surface and loco_surface.valid) then
return
end
2020-11-15 20:23:54 +02:00
local locomotive_xp_aura = WPT.get('locomotive_xp_aura')
local locomotive = WPT.get('locomotive')
local xp_points = WPT.get('xp_points')
local aura = locomotive_xp_aura
2020-05-17 12:23:55 +02:00
local rpg = data.rpg
2020-11-15 20:23:54 +02:00
local loco = locomotive.position
2020-05-17 12:23:55 +02:00
local area = {
left_top = {x = loco.x - aura, y = loco.y - aura},
right_bottom = {x = loco.x + aura, y = loco.y + aura}
}
for _, player in pairs(game.connected_players) do
if not validate_player(player) then
return
end
2020-05-23 21:18:18 +02:00
if player.afk_time < 200 then
2020-11-17 13:45:27 +02:00
if Math2D.bounding_box.contains_point(area, player.position) or player.surface.index == loco_surface.index then
if player.surface.index == loco_surface.index then
Public.add_player_to_permission_group(player, 'limited')
elseif ICFunctions.get_player_surface(player) then
return Public.add_player_to_permission_group(player, 'limited')
else
Public.add_player_to_permission_group(player, 'near_locomotive')
end
2020-05-23 21:18:18 +02:00
local pos = player.position
2021-05-25 22:19:20 +02:00
RPG.gain_xp(player, 0.5 * (rpg[player.index].bonus + xp_points))
2020-05-23 21:18:18 +02:00
player.create_local_flying_text {
text = '+' .. '',
position = {x = pos.x, y = pos.y - 2},
color = xp_floating_text_color,
time_to_live = 60,
speed = 3
}
rpg[player.index].xp_since_last_floaty_text = 0
rpg[player.index].last_floaty_text = game.tick + visuals_delay
if player.gui.screen[rpg_main_frame] then
local f = player.gui.screen[rpg_main_frame]
2020-07-28 11:24:16 +02:00
local d = Gui.get_data(f)
if d.exp_gui and d.exp_gui.valid then
2020-08-09 20:22:33 +02:00
d.exp_gui.caption = floor(rpg[player.index].xp)
2020-07-28 11:24:16 +02:00
end
end
2020-07-24 17:33:28 +02:00
else
local active_surface_index = WPT.get('active_surface_index')
local surface = game.surfaces[active_surface_index]
if surface and surface.valid then
if player.surface.index == surface.index then
Public.add_player_to_permission_group(player, 'main_surface')
end
end
2020-05-23 21:18:18 +02:00
end
2020-05-17 12:23:55 +02:00
end
end
end
2020-07-07 16:30:04 +02:00
local function is_around_train(data)
local entity = data.entity
2020-08-26 11:08:12 +02:00
local aura = data.aura + 20
2020-07-07 16:30:04 +02:00
local loco = data.locomotive.position
local area = {
left_top = {x = loco.x - aura, y = loco.y - aura},
right_bottom = {x = loco.x + aura, y = loco.y + aura}
}
local pos = entity.position
if Math2D.bounding_box.contains_point(area, pos) then
return true
end
return false
end
2020-05-17 12:23:55 +02:00
local function fish_tag()
2020-11-15 20:23:54 +02:00
local locomotive_cargo = WPT.get('locomotive_cargo')
if not (locomotive_cargo and locomotive_cargo.valid) then
2020-05-17 12:23:55 +02:00
return
end
2020-11-15 20:23:54 +02:00
if not (locomotive_cargo.surface and locomotive_cargo.surface.valid) then
2020-05-17 12:23:55 +02:00
return
end
2020-11-15 20:23:54 +02:00
local locomotive_tag = WPT.get('locomotive_tag')
if locomotive_tag then
if locomotive_tag.valid then
if locomotive_tag.position.x == locomotive_cargo.position.x and locomotive_tag.position.y == locomotive_cargo.position.y then
2020-05-17 12:23:55 +02:00
return
end
2020-11-15 20:23:54 +02:00
locomotive_tag.destroy()
2020-05-17 12:23:55 +02:00
end
end
2021-05-16 14:42:15 +02:00
WPT.set(
'locomotive_tag',
2020-11-15 20:23:54 +02:00
locomotive_cargo.force.add_chart_tag(
2021-05-16 14:42:15 +02:00
locomotive_cargo.surface,
{
icon = {type = 'item', name = 'raw-fish'},
position = locomotive_cargo.position,
text = ' '
}
)
2020-05-17 12:23:55 +02:00
)
end
2020-06-03 20:09:00 +02:00
local function set_player_spawn()
local locomotive = WPT.get('locomotive')
if not locomotive then
2020-05-17 12:23:55 +02:00
return
end
2020-06-03 20:09:00 +02:00
if not locomotive.valid then
2020-05-17 12:23:55 +02:00
return
end
2020-06-03 20:09:00 +02:00
local position = locomotive.surface.find_non_colliding_position('stone-furnace', locomotive.position, 16, 2)
2020-05-17 12:23:55 +02:00
if not position then
return
end
2020-06-03 20:09:00 +02:00
game.forces.player.set_spawn_position({x = position.x, y = position.y}, locomotive.surface)
end
local function refill_fish()
local locomotive_cargo = WPT.get('locomotive_cargo')
if not locomotive_cargo then
return
end
if not locomotive_cargo.valid then
return
end
2020-08-09 20:22:33 +02:00
locomotive_cargo.get_inventory(defines.inventory.cargo_wagon).insert({name = 'raw-fish', count = random(2, 5)})
2020-05-17 12:23:55 +02:00
end
local function set_carriages()
local locomotive = WPT.get('locomotive')
if not locomotive or not locomotive.valid then
return
end
2021-06-06 20:14:26 +02:00
if not locomotive.train then
return
end
local carriages = locomotive.train.carriages
local t = {}
for i = 1, #carriages do
local e = carriages[i]
if (e and e.valid) then
t[e.unit_number] = true
end
end
WPT.set('carriages_numbers', t)
WPT.set('carriages', locomotive.train.carriages)
end
2020-05-19 23:00:52 +02:00
local function set_locomotive_health()
2020-11-15 20:23:54 +02:00
local locomotive_health = WPT.get('locomotive_health')
local locomotive_max_health = WPT.get('locomotive_max_health')
local locomotive = WPT.get('locomotive')
2020-07-28 11:24:16 +02:00
2020-11-04 18:14:30 +02:00
local function check_health()
2020-11-15 20:23:54 +02:00
local m = locomotive_health / locomotive_max_health
2021-03-14 23:49:18 +02:00
if locomotive_health > locomotive_max_health then
WPT.set('locomotive_health', locomotive_max_health)
end
2021-05-15 16:01:07 +02:00
rendering.set_text(WPT.get('health_text'), 'HP: ' .. round(locomotive_health) .. ' / ' .. round(locomotive_max_health))
2020-11-15 20:23:54 +02:00
local carriages = WPT.get('carriages')
if carriages then
for i = 1, #carriages do
local entity = carriages[i]
2020-11-04 18:14:30 +02:00
if not (entity and entity.valid) then
return
end
local cargo_health = 600
2020-11-04 18:14:30 +02:00
if entity.type == 'locomotive' then
entity.health = 1000 * m
else
entity.health = cargo_health * m
2020-11-04 18:14:30 +02:00
end
end
end
end
2020-11-15 20:23:54 +02:00
if not (locomotive and locomotive.valid) then
2020-05-20 09:10:17 +02:00
return
end
2020-07-28 11:24:16 +02:00
2020-11-04 18:14:30 +02:00
check_health()
2020-05-19 23:00:52 +02:00
end
2020-06-03 20:09:00 +02:00
local function validate_index()
local locomotive = WPT.get('locomotive')
if not locomotive then
return
end
if not locomotive.valid then
return
end
2020-07-28 11:24:16 +02:00
2021-05-16 14:42:15 +02:00
local icw_table = ICW.get_table()
2020-06-03 20:09:00 +02:00
local icw_locomotive = WPT.get('icw_locomotive')
local loco_surface = icw_locomotive.surface
local unit_surface = locomotive.unit_number
local locomotive_surface = game.surfaces[icw_table.wagons[unit_surface].surface.index]
2020-11-23 23:10:45 +02:00
if loco_surface.valid then
WPT.set('loco_surface', locomotive_surface)
2020-06-03 20:09:00 +02:00
end
end
local function create_defense_system(position, name, target)
2020-06-07 13:33:24 +02:00
local active_surface_index = WPT.get('active_surface_index')
local surface = game.surfaces[active_surface_index]
local random_angles = {
2020-08-09 20:22:33 +02:00
rad(random(359)),
rad(random(359)),
rad(random(359)),
rad(random(359))
2020-06-07 13:33:24 +02:00
}
surface.create_entity(
{
name = name,
position = {x = position.x, y = position.y},
target = target,
speed = 1.5,
force = 'player'
}
)
surface.create_entity(
{
name = name,
2020-06-07 13:33:24 +02:00
position = {
2020-08-09 20:22:33 +02:00
x = position.x + 12 * cos(random_angles[1]),
y = position.y + 12 * sin(random_angles[1])
},
target = target,
speed = 1.5,
force = 'player'
2020-06-07 13:33:24 +02:00
}
)
surface.create_entity(
{
name = name,
2020-06-07 13:33:24 +02:00
position = {
2020-08-09 20:22:33 +02:00
x = position.x + 12 * cos(random_angles[2]),
y = position.y + 12 * sin(random_angles[2])
},
target = target,
speed = 1.5,
force = 'player'
2020-06-07 13:33:24 +02:00
}
)
surface.create_entity(
{
name = name,
2020-06-07 13:33:24 +02:00
position = {
2020-08-09 20:22:33 +02:00
x = position.x + 12 * cos(random_angles[3]),
y = position.y + 12 * sin(random_angles[3])
},
target = target,
speed = 1.5,
force = 'player'
2020-06-07 13:33:24 +02:00
}
)
surface.create_entity(
{
name = name,
2020-06-07 13:33:24 +02:00
position = {
2020-08-09 20:22:33 +02:00
x = position.x + 12 * cos(random_angles[4]),
y = position.y + 12 * sin(random_angles[4])
},
target = target,
speed = 1.5,
force = 'player'
2020-06-07 13:33:24 +02:00
}
)
end
2020-06-03 20:09:00 +02:00
local function close_market_gui(player)
2020-11-23 23:10:45 +02:00
local players = WPT.get('players')
2020-06-03 20:09:00 +02:00
2020-07-06 15:45:09 +02:00
local element = player.gui.screen
2020-11-23 23:10:45 +02:00
local data = players[player.index].data
2020-06-03 20:09:00 +02:00
if not data then
return
end
2020-07-06 15:45:09 +02:00
local frame = element[main_frame_name]
Public.close_gui_player(frame)
if data then
2020-11-23 23:10:45 +02:00
players[player.index].data = nil
2020-06-03 20:09:00 +02:00
end
end
2020-07-01 19:35:38 +02:00
local function redraw_market_items(gui, player, search_text)
2020-06-03 20:09:00 +02:00
if not validate_player(player) then
return
end
2020-07-06 15:45:09 +02:00
local players = WPT.get('players')
2021-05-23 17:03:52 +02:00
if not players then
return
end
2020-08-26 12:09:06 +02:00
if gui and gui.valid then
gui.clear()
end
2020-06-03 20:09:00 +02:00
local inventory = player.get_main_inventory()
2020-07-06 15:45:09 +02:00
local player_item_count
2020-06-03 20:09:00 +02:00
2020-12-29 01:09:18 +02:00
if not (gui and gui.valid) then
return
end
2020-07-06 15:45:09 +02:00
gui.add(
{
type = 'label',
2020-09-04 22:04:28 +02:00
caption = ({'locomotive.upgrades'})
2020-07-06 15:45:09 +02:00
}
)
local upgrade_table = gui.add({type = 'table', column_count = 6})
2020-06-03 20:09:00 +02:00
for item, data in pairs(Public.get_items()) do
2020-07-06 15:45:09 +02:00
if data.upgrade then
if not search_text then
goto continue
end
if not search_text.text then
goto continue
end
if not string.lower(item:gsub('-', ' ')):find(search_text.text) then
goto continue
end
local item_count = data.stack
local item_cost = data.price
local frame = upgrade_table.add({type = 'flow'})
frame.style.vertical_align = 'bottom'
player_item_count = inventory.get_item_count(data.value)
local button =
frame.add(
{
type = 'sprite-button',
sprite = data.sprite or 'item/' .. item,
number = item_count,
name = item,
tooltip = data.tooltip,
style = 'slot_button',
enabled = data.enabled
}
)
local label =
frame.add(
{
type = 'label',
caption = concat {'[item=', data.value, ']: '} .. format_number(item_cost, true)
}
)
label.style.font = 'default-bold'
if player_item_count < item_cost then
button.enabled = false
end
::continue::
2020-07-01 19:35:38 +02:00
end
2020-07-06 15:45:09 +02:00
end
gui.add(
{
type = 'label',
2020-09-04 22:04:28 +02:00
caption = ({'locomotive.items'})
2020-07-06 15:45:09 +02:00
}
)
2020-06-03 20:09:00 +02:00
2020-08-09 20:22:33 +02:00
local slider_value = ceil(players[player.index].data.slider.slider_value)
2020-07-06 15:45:09 +02:00
local items_table = gui.add({type = 'table', column_count = 6})
2020-06-03 20:09:00 +02:00
2020-07-06 15:45:09 +02:00
for item, data in pairs(Public.get_items()) do
if not data.upgrade then
if not search_text then
goto continue
end
if not search_text.text then
goto continue
end
if not string.lower(item:gsub('-', ' ')):find(search_text.text) then
goto continue
end
local item_count = data.stack * slider_value
local item_cost = data.price * slider_value
local frame = items_table.add({type = 'flow'})
frame.style.vertical_align = 'bottom'
player_item_count = inventory.get_item_count(data.value)
local button =
frame.add(
{
type = 'sprite-button',
sprite = data.sprite or 'item/' .. item,
number = item_count,
name = item,
tooltip = data.tooltip,
style = 'slot_button',
enabled = data.enabled
}
)
2020-08-27 13:27:34 +02:00
if WPT.get('trusted_only_car_tanks') then
local trustedPlayer = Session.get_trusted_player(player)
if not trustedPlayer then
2020-08-27 13:27:34 +02:00
if item == 'tank' then
button.enabled = false
2020-09-04 22:04:28 +02:00
button.tooltip = ({'locomotive.not_trusted'})
2020-08-27 13:27:34 +02:00
end
if item == 'car' then
2020-08-27 13:27:34 +02:00
button.enabled = false
2020-09-04 22:04:28 +02:00
button.tooltip = ({'locomotive.not_trusted'})
end
2020-08-27 13:27:34 +02:00
end
end
2020-07-06 15:45:09 +02:00
local label =
frame.add(
{
type = 'label',
caption = concat {'[item=', data.value, ']: '} .. format_number(item_cost, true)
}
)
label.style.font = 'default-bold'
2020-06-03 20:09:00 +02:00
2020-07-06 15:45:09 +02:00
if player_item_count < item_cost then
button.enabled = false
end
::continue::
2020-06-03 20:09:00 +02:00
end
end
end
local function redraw_coins_left(gui, player)
if not validate_player(player) then
return
end
gui.clear()
local inventory = player.get_main_inventory()
local player_item_count = inventory.get_item_count('coin')
local coinsleft =
gui.add(
{
type = 'label',
2020-09-04 22:04:28 +02:00
caption = ({'locomotive.coins_left', format_number(player_item_count, true)})
2020-06-03 20:09:00 +02:00
}
)
add_space(coinsleft)
end
local function slider_changed(event)
local player = game.players[event.player_index]
2020-11-15 20:23:54 +02:00
local players = WPT.get('players')
2021-05-23 17:03:52 +02:00
if not players then
return
end
2020-06-03 20:09:00 +02:00
local slider_value
2020-11-15 20:23:54 +02:00
slider_value = players
2020-06-03 20:09:00 +02:00
if not slider_value then
return
end
slider_value = slider_value[player.index].data
if not slider_value then
return
end
2020-12-14 20:36:37 +02:00
2021-01-12 22:53:19 +02:00
local is_spamming = SpamProtection.is_spamming(player, 2, 'Locomotive Slider Change')
2020-12-14 20:36:37 +02:00
if is_spamming then
return
end
2020-06-03 20:09:00 +02:00
slider_value = slider_value.slider
if not slider_value then
return
end
slider_value = slider_value.slider_value
if not slider_value then
return
end
2020-08-09 20:22:33 +02:00
slider_value = ceil(slider_value)
2020-11-25 20:55:51 +02:00
if players[player.index] and players[player.index].data and players[player.index].data.text_input then
2020-12-04 02:09:52 +02:00
players[player.index].data.text_input.text = tostring(slider_value)
2020-11-25 20:55:51 +02:00
redraw_market_items(players[player.index].data.item_frame, player, players[player.index].data.search_text)
end
2020-06-03 20:09:00 +02:00
end
local function text_changed(event)
2020-07-01 19:35:38 +02:00
local element = event.element
if not element then
return
end
if not element.valid then
return
end
2020-11-15 20:23:54 +02:00
local players = WPT.get('players')
2021-05-23 17:03:52 +02:00
if not players then
return
end
2020-06-03 20:09:00 +02:00
local player = game.players[event.player_index]
2020-11-15 20:23:54 +02:00
local data = players[player.index].data
2020-06-03 20:09:00 +02:00
if not data then
return
end
2020-08-26 12:09:06 +02:00
2021-01-12 22:53:19 +02:00
local is_spamming = SpamProtection.is_spamming(player, 2, 'Locomotive Text Changed')
2020-12-14 20:36:37 +02:00
if is_spamming then
return
end
2020-08-27 13:27:34 +02:00
if not data.text_input or not data.text_input.valid then
2020-06-03 20:09:00 +02:00
return
end
2020-08-27 13:27:34 +02:00
if not data.text_input.text then
2020-06-03 20:09:00 +02:00
return
end
2020-08-27 13:27:34 +02:00
local value = tonumber(data.text_input.text)
2020-06-05 23:53:58 +02:00
2020-06-03 20:09:00 +02:00
if not value then
return
end
2020-08-26 22:20:18 +02:00
if (value > 1e2) then
2020-08-27 13:27:34 +02:00
data.text_input.text = '100'
2020-08-26 22:20:18 +02:00
value = 1e2
elseif (value <= 0) then
2020-08-27 13:27:34 +02:00
data.text_input.text = '1'
value = 1
end
2020-12-04 02:09:52 +02:00
data.slider.slider_value = tostring(value)
2020-06-05 23:53:58 +02:00
2020-07-01 19:35:38 +02:00
redraw_market_items(data.item_frame, player, data.search_text)
2020-06-03 20:09:00 +02:00
end
local function gui_opened(event)
2020-11-15 20:23:54 +02:00
local market = WPT.get('market')
2020-06-03 20:09:00 +02:00
if not event.gui_type == defines.gui_type.entity then
return
end
local entity = event.entity
if not entity then
return
end
2020-11-15 20:23:54 +02:00
if entity ~= market then
2020-06-03 20:09:00 +02:00
return
end
local player = game.players[event.player_index]
if not validate_player(player) then
return
end
local inventory = player.get_main_inventory()
local player_item_count = inventory.get_item_count('coin')
2020-11-15 20:23:54 +02:00
local players = WPT.get('players')
2021-05-23 17:03:52 +02:00
if not players then
return
end
2020-11-15 20:23:54 +02:00
if not players[player.index].data then
players[player.index].data = {}
2020-07-06 15:45:09 +02:00
end
2020-11-15 20:23:54 +02:00
local data = players[player.index].data
2020-06-03 20:09:00 +02:00
if data.frame then
data.frame = nil
end
local frame =
player.gui.screen.add(
{
type = 'frame',
2020-09-04 22:04:28 +02:00
caption = ({'locomotive.market_name'}),
2020-06-03 20:09:00 +02:00
direction = 'vertical',
2020-07-06 15:45:09 +02:00
name = main_frame_name
2020-06-03 20:09:00 +02:00
}
)
frame.auto_center = true
player.opened = frame
frame.style.minimal_width = 325
frame.style.minimal_height = 250
local search_table = frame.add({type = 'table', column_count = 2})
2020-09-04 22:04:28 +02:00
search_table.add({type = 'label', caption = ({'locomotive.search_text'})})
2020-06-03 20:09:00 +02:00
local search_text = search_table.add({type = 'textfield'})
search_text.style.width = 140
add_space(frame)
local pane =
frame.add {
type = 'scroll-pane',
direction = 'vertical',
vertical_scroll_policy = 'always',
horizontal_scroll_policy = 'never'
}
pane.style.maximal_height = 200
pane.style.horizontally_stretchable = true
pane.style.minimal_height = 200
pane.style.right_padding = 0
local flow = frame.add({type = 'flow'})
add_space(flow)
2020-08-26 18:57:12 +02:00
local bottom_grid = frame.add({type = 'table', column_count = 4})
2020-07-25 17:22:04 +02:00
bottom_grid.style.vertically_stretchable = false
2020-06-03 20:09:00 +02:00
2020-09-04 22:04:28 +02:00
local bg = bottom_grid.add({type = 'label', caption = ({'locomotive.quantity_text'})})
bg.style.font = 'default-bold'
2020-06-03 20:09:00 +02:00
2020-08-27 13:27:34 +02:00
local text_input =
2020-06-03 20:09:00 +02:00
bottom_grid.add(
{
type = 'text-box',
text = 1
}
)
2020-08-27 13:27:34 +02:00
text_input.style.maximal_height = 28
2020-06-03 20:09:00 +02:00
local slider =
frame.add(
{
type = 'slider',
minimum_value = 1,
2020-08-26 20:08:14 +02:00
maximum_value = 1e2,
2020-06-03 20:09:00 +02:00
value = 1
}
)
slider.style.width = 115
2020-08-27 13:27:34 +02:00
text_input.style.width = 60
2020-06-03 20:09:00 +02:00
local coinsleft = frame.add({type = 'flow'})
coinsleft.add(
{
type = 'label',
2020-09-04 22:04:28 +02:00
caption = ({'locomotive.coins_left', format_number(player_item_count, true)})
2020-06-03 20:09:00 +02:00
}
)
2020-11-15 20:23:54 +02:00
players[player.index].data.search_text = search_text
players[player.index].data.text_input = text_input
players[player.index].data.slider = slider
players[player.index].data.frame = frame
players[player.index].data.item_frame = pane
players[player.index].data.coins_left = coinsleft
2020-06-03 20:09:00 +02:00
2020-07-01 19:35:38 +02:00
redraw_market_items(pane, player, search_text)
2020-06-03 20:09:00 +02:00
end
local function gui_click(event)
2020-11-15 20:23:54 +02:00
local players = WPT.get('players')
2021-05-23 17:03:52 +02:00
if not players then
return
end
2020-06-03 20:09:00 +02:00
local element = event.element
local player = game.players[event.player_index]
if not validate_player(player) then
return
end
2020-11-15 20:23:54 +02:00
if not players[player.index] then
2020-06-03 20:09:00 +02:00
return
end
2020-11-15 20:23:54 +02:00
local data = players[player.index].data
2020-06-03 20:09:00 +02:00
if not data then
return
end
if not element.valid then
return
end
local name = element.name
if not player.opened then
return
end
2020-06-05 18:01:32 +02:00
2020-07-06 15:45:09 +02:00
if not player.opened == main_frame_name then
2020-06-05 18:01:32 +02:00
return
end
2021-01-12 22:53:19 +02:00
local is_spamming = SpamProtection.is_spamming(player, nil, 'Locomotive Gui Clicked')
2020-12-14 20:36:37 +02:00
if is_spamming then
return
end
2020-06-03 20:09:00 +02:00
if not data then
return
end
local item = Public.get_items()[name]
if not item then
return
end
local inventory = player.get_main_inventory()
local player_item_count = inventory.get_item_count(item.value)
2020-08-09 20:22:33 +02:00
local slider_value = ceil(data.slider.slider_value)
2020-06-03 20:09:00 +02:00
local cost = (item.price * slider_value)
local item_count = item.stack * slider_value
2020-11-15 20:23:54 +02:00
local this = WPT.get()
if name == 'upgrade_pickaxe' then
player.remove_item({name = item.value, count = item.price})
this.pickaxe_tier = this.pickaxe_tier + item.stack
local pickaxe_tiers = WPT.pickaxe_upgrades
local tier = this.pickaxe_tier
local offer = pickaxe_tiers[tier]
local message = ({
'locomotive.pickaxe_bought_info',
shopkeeper,
player.name,
offer,
format_number(item.price, true)
})
Alert.alert_all_players(5, message)
Server.to_discord_bold(
table.concat {
2020-11-04 18:14:30 +02:00
player.name .. ' has upgraded the teams pickaxe to tier ' .. tier .. ' for ' .. format_number(item.price, true) .. ' coins.'
}
)
2020-10-20 11:17:25 +02:00
local force = game.forces.player
2020-10-24 14:46:14 +02:00
force.manual_mining_speed_modifier = force.manual_mining_speed_modifier + this.pickaxe_speed_per_purchase
redraw_market_items(data.item_frame, player, data.search_text)
redraw_coins_left(data.coins_left, player)
return
end
2020-07-06 15:45:09 +02:00
if name == 'chest_limit_outside' then
2020-07-07 16:30:04 +02:00
if this.chest_limit_outside_upgrades == 8 then
local main_market_items = WPT.get('main_market_items')
main_market_items['chest_limit_outside'].enabled = false
2020-09-04 22:04:28 +02:00
main_market_items['chest_limit_outside'].tooltip = ({'locomotive.limit_reached'})
2020-07-07 16:30:04 +02:00
redraw_market_items(data.item_frame, player, data.search_text)
2020-09-04 22:04:28 +02:00
return player.print(({'locomotive.chests_full'}), {r = 0.98, g = 0.66, b = 0.22})
2020-07-07 16:30:04 +02:00
end
2020-07-06 15:45:09 +02:00
player.remove_item({name = item.value, count = item.price})
2020-09-04 22:04:28 +02:00
local message = ({'locomotive.chest_bought_info', shopkeeper, player.name, format_number(item.price, true)})
2020-07-06 15:45:09 +02:00
Alert.alert_all_players(5, message)
Server.to_discord_bold(
table.concat {
2020-11-04 18:14:30 +02:00
player.name .. ' has bought the chest limit upgrade for ' .. format_number(item.price, true) .. ' coins.'
2020-07-06 15:45:09 +02:00
}
)
this.chest_limit_outside_upgrades = this.chest_limit_outside_upgrades + item.stack
redraw_market_items(data.item_frame, player, data.search_text)
redraw_coins_left(data.coins_left, player)
return
end
2020-06-03 20:09:00 +02:00
if name == 'locomotive_max_health' then
2021-05-16 13:48:50 +02:00
if this.health_upgrades >= this.health_upgrades_limit then
local main_market_items = WPT.get('main_market_items')
main_market_items['locomotive_max_health'].enabled = false
main_market_items['locomotive_max_health'].tooltip = ({'locomotive.limit_reached'})
redraw_market_items(data.item_frame, player, data.search_text)
return
end
2020-07-06 15:45:09 +02:00
player.remove_item({name = item.value, count = item.price})
2020-09-04 22:04:28 +02:00
local message = ({'locomotive.health_bought_info', shopkeeper, player.name, format_number(item.price, true)})
2020-06-03 20:09:00 +02:00
2020-06-05 23:53:58 +02:00
Alert.alert_all_players(5, message)
2020-06-03 20:09:00 +02:00
Server.to_discord_bold(
table.concat {
2020-11-04 18:14:30 +02:00
player.name .. ' has bought the locomotive health modifier for ' .. format_number(item.price, true) .. ' coins.'
2020-06-03 20:09:00 +02:00
}
)
2021-05-16 13:48:50 +02:00
2021-07-07 12:22:22 +02:00
this.locomotive_max_health = this.locomotive_max_health + 20000
2021-05-16 13:48:50 +02:00
--[[
this.locomotive_max_health = this.locomotive_max_health + (this.locomotive_max_health * 0.5)
This exists as a reminder to never ever screw up health pool ever again.
]]
2020-06-03 20:09:00 +02:00
local m = this.locomotive_health / this.locomotive_max_health
2020-11-04 18:14:30 +02:00
if this.carriages then
for i = 1, #this.carriages do
local entity = this.carriages[i]
if not (entity and entity.valid) then
return
end
local cargo_health = 600
2020-11-04 18:14:30 +02:00
if entity.type == 'locomotive' then
entity.health = 1000 * m
else
entity.health = cargo_health * m
2020-11-04 18:14:30 +02:00
end
end
end
2020-06-03 20:09:00 +02:00
2020-07-06 15:45:09 +02:00
this.train_upgrades = this.train_upgrades + item.stack
this.health_upgrades = this.health_upgrades + item.stack
2021-05-15 16:01:07 +02:00
rendering.set_text(this.health_text, 'HP: ' .. round(this.locomotive_health) .. ' / ' .. round(this.locomotive_max_health))
2020-06-03 20:09:00 +02:00
2020-07-01 19:35:38 +02:00
redraw_market_items(data.item_frame, player, data.search_text)
2020-06-03 20:09:00 +02:00
redraw_coins_left(data.coins_left, player)
return
end
if name == 'locomotive_xp_aura' then
2020-07-06 15:45:09 +02:00
player.remove_item({name = item.value, count = item.price})
2020-06-03 20:09:00 +02:00
2020-09-04 22:04:28 +02:00
local message = ({'locomotive.aura_bought_info', shopkeeper, player.name, format_number(item.price, true)})
2020-06-05 23:53:58 +02:00
Alert.alert_all_players(5, message)
2020-06-03 20:09:00 +02:00
Server.to_discord_bold(
table.concat {
2020-11-04 18:14:30 +02:00
player.name .. ' has bought the locomotive xp aura modifier for ' .. format_number(item.price, true) .. ' coins.'
2020-06-03 20:09:00 +02:00
}
)
this.locomotive_xp_aura = this.locomotive_xp_aura + 5
2020-07-06 15:45:09 +02:00
this.aura_upgrades = this.aura_upgrades + item.stack
this.train_upgrades = this.train_upgrades + item.stack
2020-06-03 20:09:00 +02:00
if this.circle then
rendering.destroy(this.circle)
end
this.circle =
rendering.draw_circle {
surface = game.surfaces[this.active_surface_index],
target = this.locomotive,
color = this.locomotive.color,
filled = false,
radius = this.locomotive_xp_aura,
only_in_alt_mode = true
}
2020-07-01 19:35:38 +02:00
redraw_market_items(data.item_frame, player, data.search_text)
2020-06-03 20:09:00 +02:00
redraw_coins_left(data.coins_left, player)
return
end
if name == 'xp_points_boost' then
2020-07-06 15:45:09 +02:00
player.remove_item({name = item.value, count = item.price})
2020-09-04 22:04:28 +02:00
local message = ({'locomotive.xp_bought_info', shopkeeper, player.name, format_number(item.price, true)})
2020-06-03 20:09:00 +02:00
2020-06-05 23:53:58 +02:00
Alert.alert_all_players(5, message)
2020-06-03 20:09:00 +02:00
Server.to_discord_bold(
table.concat {
2020-07-06 15:45:09 +02:00
player.name .. ' has bought the XP points modifier for ' .. format_number(item.price) .. ' coins.'
2020-06-03 20:09:00 +02:00
}
)
this.xp_points = this.xp_points + 0.5
2020-07-06 15:45:09 +02:00
this.xp_points_upgrade = this.xp_points_upgrade + item.stack
this.train_upgrades = this.train_upgrades + item.stack
2020-06-03 20:09:00 +02:00
2020-07-01 19:35:38 +02:00
redraw_market_items(data.item_frame, player, data.search_text)
2020-06-03 20:09:00 +02:00
redraw_coins_left(data.coins_left, player)
return
end
2020-08-21 13:56:01 +02:00
if name == 'explosive_bullets' then
player.remove_item({name = item.value, count = item.price})
2020-09-04 22:04:28 +02:00
local message = ({
'locomotive.explosive_bullet_bought_info',
shopkeeper,
player.name,
format_number(item.price, true)
})
2020-08-21 13:56:01 +02:00
Alert.alert_all_players(5, message)
Server.to_discord_bold(
table.concat {
2020-11-04 18:14:30 +02:00
player.name .. ' has bought the explosive bullet modifier for ' .. format_number(item.price) .. ' coins.'
2020-08-21 13:56:01 +02:00
}
)
2021-05-25 22:19:20 +02:00
RPG.enable_explosive_bullets(true)
2020-08-21 13:56:01 +02:00
this.explosive_bullets = true
redraw_market_items(data.item_frame, player, data.search_text)
redraw_coins_left(data.coins_left, player)
return
end
2020-06-03 20:09:00 +02:00
if name == 'flamethrower_turrets' then
2020-07-06 15:45:09 +02:00
player.remove_item({name = item.value, count = item.price})
if item.stack >= 1 then
2020-09-04 22:04:28 +02:00
local message = ({
'locomotive.one_flamethrower_bought_info',
shopkeeper,
player.name,
format_number(item.price, true)
})
2020-06-05 23:53:58 +02:00
Alert.alert_all_players(5, message)
2020-06-03 20:09:00 +02:00
Server.to_discord_bold(
table.concat {
2020-11-04 18:14:30 +02:00
player.name .. ' has bought a flamethrower-turret slot for ' .. format_number(item.price, true) .. ' coins.'
2020-06-03 20:09:00 +02:00
}
)
else
2020-09-04 22:04:28 +02:00
local message = ({
'locomotive.multiple_flamethrower_bought_info',
shopkeeper,
player.name,
item.stack,
format_number(item.price, true)
})
2020-06-05 23:53:58 +02:00
Alert.alert_all_players(5, message)
2020-06-03 20:09:00 +02:00
Server.to_discord_bold(
table.concat {
player.name .. ' has bought ' .. item.stack .. ' flamethrower-turret slots for ' .. format_number(item.price, true) .. ' coins.'
2020-06-03 20:09:00 +02:00
}
)
end
2020-07-06 15:45:09 +02:00
this.upgrades.flame_turret.limit = this.upgrades.flame_turret.limit + item.stack
this.upgrades.flame_turret.bought = this.upgrades.flame_turret.bought + item.stack
2020-06-03 20:09:00 +02:00
2020-07-01 19:35:38 +02:00
redraw_market_items(data.item_frame, player, data.search_text)
2020-06-03 20:09:00 +02:00
redraw_coins_left(data.coins_left, player)
return
end
if name == 'land_mine' then
2020-07-06 15:45:09 +02:00
player.remove_item({name = item.value, count = item.price})
2020-06-03 20:09:00 +02:00
2020-07-06 15:45:09 +02:00
if item.stack >= 1 and this.upgrades.landmine.bought % 10 == 0 then
2020-09-04 22:04:28 +02:00
local message = ({
'locomotive.landmine_bought_info',
shopkeeper,
player.name,
format_number(item.price, true)
})
2020-06-05 23:53:58 +02:00
Alert.alert_all_players(3, message)
2020-06-07 13:33:24 +02:00
2020-07-06 15:45:09 +02:00
if item.price >= 1000 then
2020-06-03 20:09:00 +02:00
Server.to_discord_bold(
table.concat {
player.name .. ' has bought ' .. item.stack .. ' landmine slots for ' .. format_number(item.price, true) .. ' coins.'
2020-06-03 20:09:00 +02:00
}
)
end
end
2020-07-06 15:45:09 +02:00
this.upgrades.landmine.limit = this.upgrades.landmine.limit + item.stack
this.upgrades.landmine.bought = this.upgrades.landmine.bought + item.stack
2020-06-03 20:09:00 +02:00
2020-07-01 19:35:38 +02:00
redraw_market_items(data.item_frame, player, data.search_text)
2020-06-03 20:09:00 +02:00
redraw_coins_left(data.coins_left, player)
return
end
if player_item_count >= cost then
if player.can_insert({name = name, count = item_count}) then
player.play_sound({path = 'entity-close/stone-furnace', volume_modifier = 0.65})
local inserted_count = player.insert({name = name, count = item_count})
if inserted_count < item_count then
player.play_sound({path = 'utility/cannot_build', volume_modifier = 0.65})
2020-09-04 22:04:28 +02:00
player.print(({'locomotive.full_inventory', inserted_count, name}), {r = 0.98, g = 0.66, b = 0.22})
player.print(({'locomotive.change_returned'}), {r = 0.98, g = 0.66, b = 0.22})
player.insert({name = name, count = inserted_count})
player.remove_item({name = item.value, count = ceil(item.price * (inserted_count / item.stack))})
else
player.remove_item({name = item.value, count = cost})
2020-06-03 20:09:00 +02:00
end
2020-07-01 19:35:38 +02:00
redraw_market_items(data.item_frame, player, data.search_text)
2020-06-03 20:09:00 +02:00
redraw_coins_left(data.coins_left, player)
else
2020-08-26 22:20:18 +02:00
player.play_sound({path = 'utility/cannot_build', volume_modifier = 0.65})
if (random(1, 10) > 1) then
2020-09-04 22:04:28 +02:00
player.print(({'locomotive.notify_full_inventory_1'}), {r = 0.98, g = 0.66, b = 0.22})
player.print(({'locomotive.notify_full_inventory_2'}), {r = 0.98, g = 0.66, b = 0.22})
2020-08-26 22:20:18 +02:00
else
2020-09-04 22:04:28 +02:00
player.print(({'locomotive.notify_full_inventory_2'}), {r = 0.98, g = 0.66, b = 0.22})
2020-08-26 22:20:18 +02:00
end
2020-06-03 20:09:00 +02:00
end
end
end
local function gui_closed(event)
local player = game.players[event.player_index]
2020-11-15 20:23:54 +02:00
local players = WPT.get('players')
2021-05-23 17:03:52 +02:00
if not players then
return
end
2020-06-03 20:09:00 +02:00
local type = event.gui_type
if type == defines.gui_type.custom then
2020-11-15 20:23:54 +02:00
local data = players[player.index].data
2020-06-03 20:09:00 +02:00
if not data then
return
end
close_market_gui(player)
end
end
local function on_player_changed_position(event)
2020-11-15 20:23:54 +02:00
local players = WPT.get('players')
2021-05-23 17:03:52 +02:00
if not players then
return
end
2020-06-03 20:09:00 +02:00
local player = game.players[event.player_index]
2020-11-15 20:23:54 +02:00
if not players[player.index] then
2020-06-03 20:09:00 +02:00
return
end
2020-11-15 20:23:54 +02:00
local data = players[player.index].data
local market = WPT.get('market')
2020-06-03 20:09:00 +02:00
2020-11-15 20:23:54 +02:00
if not (market and market.valid) then
2020-09-25 11:08:15 +02:00
return
end
2020-06-03 20:09:00 +02:00
if data and data.frame and data.frame.valid then
2020-11-15 20:23:54 +02:00
local position = market.position
2020-06-03 20:09:00 +02:00
local area = {
left_top = {x = position.x - 10, y = position.y - 10},
right_bottom = {x = position.x + 10, y = position.y + 10}
}
2020-07-06 15:45:09 +02:00
if Math2D.bounding_box.contains_point(area, player.position) then
2020-06-03 20:09:00 +02:00
return
end
if not data then
return
end
close_market_gui(player)
end
end
2020-07-27 11:07:32 +02:00
local function spawn_biter()
local this = WPT.get()
local loco_surface = this.icw_locomotive.surface
if not loco_surface.valid then
return
end
local locomotive = this.icw_locomotive
local center_position = {
x = locomotive.area.left_top.x + (locomotive.area.right_bottom.x - locomotive.area.left_top.x) * 0.5,
y = locomotive.area.left_top.y + (locomotive.area.right_bottom.y - locomotive.area.left_top.y) * 0.5
}
if not this.icw_area then
this.icw_area = center_position
end
local position = loco_surface.find_non_colliding_position('market', center_position, 128, 0.5)
local biters = {
'big-biter',
'behemoth-biter',
'big-spitter',
'behemoth-spitter'
}
local size_of = #biters
2020-09-25 11:08:15 +02:00
if not position then
return
end
this.locomotive_biter = loco_surface.create_entity({name = biters[random(1, size_of)], position = position, force = 'player', create_build_effect_smoke = false})
2020-07-27 11:07:32 +02:00
this.locomotive_biter.ai_settings.allow_destroy_when_commands_fail = false
this.locomotive_biter.ai_settings.allow_try_return_to_spawner = false
rendering.draw_text {
2020-09-04 22:04:28 +02:00
text = ({'locomotive.shoo'}),
2020-07-27 11:07:32 +02:00
surface = this.locomotive_biter.surface,
target = this.locomotive_biter,
target_offset = {0, -3.5},
scale = 1.05,
font = 'default-large-semibold',
color = {r = 175, g = 75, b = 255},
alignment = 'center',
scale_with_zoom = false
}
end
2020-06-03 20:09:00 +02:00
local function create_market(data, rebuild)
local surface = data.surface
2021-05-16 14:42:15 +02:00
local this = WPT.get()
2020-06-03 20:09:00 +02:00
if not this.locomotive then
return
end
if not this.locomotive.valid then
return
end
if rebuild then
local radius = 512
local area = {{x = -radius, y = -radius}, {x = radius, y = radius}}
for _, entity in pairs(surface.find_entities_filtered {area = area, name = 'market'}) do
entity.destroy()
end
2020-11-04 18:14:30 +02:00
for _, entity in pairs(surface.find_entities_filtered {area = area, type = 'item-entity', name = 'item-on-ground'}) do
2020-06-03 20:09:00 +02:00
entity.destroy()
end
for _, entity in pairs(surface.find_entities_filtered {area = area, type = 'unit'}) do
entity.destroy()
end
this.market = nil
end
local locomotive = this.icw_locomotive
local loco_surface = this.icw_locomotive.surface
if not loco_surface.valid then
return
end
local center_position = {
x = locomotive.area.left_top.x + (locomotive.area.right_bottom.x - locomotive.area.left_top.x) * 0.5,
y = locomotive.area.left_top.y + (locomotive.area.right_bottom.y - locomotive.area.left_top.y) * 0.5
}
if not this.icw_area then
this.icw_area = center_position
end
this.market = surface.create_entity {name = 'market', position = center_position, force = 'player'}
2020-12-20 21:40:12 +02:00
Generate.wintery(this.market, 5.5)
2020-06-03 20:09:00 +02:00
rendering.draw_text {
text = 'Market',
surface = surface,
target = this.market,
scale = 1.5,
target_offset = {0, -2},
color = {r = 0.98, g = 0.66, b = 0.22},
alignment = 'center'
}
this.market.destructible = false
2020-07-27 11:07:32 +02:00
spawn_biter()
2020-06-03 20:09:00 +02:00
for x = center_position.x - 5, center_position.x + 5, 1 do
for y = center_position.y - 5, center_position.y + 5, 1 do
2020-08-09 20:22:33 +02:00
if random(1, 2) == 1 then
2020-11-04 18:14:30 +02:00
loco_surface.spill_item_stack({x + random(0, 9) * 0.1, y + random(0, 9) * 0.1}, {name = 'raw-fish', count = 1}, false)
2020-06-03 20:09:00 +02:00
end
loco_surface.set_tiles({{name = 'blue-refined-concrete', position = {x, y}}}, true)
end
end
for x = center_position.x - 3, center_position.x + 3, 1 do
for y = center_position.y - 3, center_position.y + 3, 1 do
2020-08-09 20:22:33 +02:00
if random(1, 2) == 1 then
2020-11-04 18:14:30 +02:00
loco_surface.spill_item_stack({x + random(0, 9) * 0.1, y + random(0, 9) * 0.1}, {name = 'raw-fish', count = 1}, false)
2020-06-03 20:09:00 +02:00
end
loco_surface.set_tiles({{name = 'cyan-refined-concrete', position = {x, y}}}, true)
end
end
end
2020-07-06 15:45:09 +02:00
local function contains_positions(area)
local function inside(pos)
local lt = area.left_top
local rb = area.right_bottom
return pos.x >= lt.x and pos.y >= lt.y and pos.x <= rb.x and pos.y <= rb.y
end
local wagons = ICW.get_table('wagons')
for _, wagon in pairs(wagons) do
2020-07-28 11:24:16 +02:00
if wagon.entity and wagon.entity.valid then
if wagon.entity.name == 'cargo-wagon' then
if inside(wagon.entity.position, area) then
return true, wagon.entity
end
2020-07-06 15:45:09 +02:00
end
end
end
return false, nil
end
local function on_built_entity(event)
local entity = event.created_entity
if not entity.valid then
return
end
if entity.name ~= 'steel-chest' then
return
end
local map_name = 'mountain_fortress_v3'
if string.sub(entity.surface.name, 0, #map_name) ~= map_name then
return
end
local area = {
left_top = {x = entity.position.x - 3, y = entity.position.y - 3},
right_bottom = {x = entity.position.x + 3, y = entity.position.y + 3}
}
local success, train = contains_positions(area)
if not success then
return
end
local outside_chests = WPT.get('outside_chests')
local chests_linked_to = WPT.get('chests_linked_to')
local chest_limit_outside_upgrades = WPT.get('chest_limit_outside_upgrades')
local chest_created
2020-07-07 16:30:04 +02:00
local increased = false
2020-07-06 15:45:09 +02:00
2021-01-30 21:43:53 +02:00
for k, data in pairs(outside_chests) do
if data and data.chest and data.chest.valid then
2020-07-06 15:45:09 +02:00
if chests_linked_to[train.unit_number] then
local linked_to = chests_linked_to[train.unit_number].count
if linked_to == chest_limit_outside_upgrades then
return
end
2020-12-29 01:09:18 +02:00
outside_chests[entity.unit_number] = {chest = entity, position = entity.position, linked = train.unit_number}
2020-07-07 16:30:04 +02:00
if not increased then
chests_linked_to[train.unit_number].count = linked_to + 1
chests_linked_to[train.unit_number][entity.unit_number] = true
increased = true
2021-01-30 21:43:53 +02:00
2020-07-07 16:30:04 +02:00
goto continue
end
2020-07-06 15:45:09 +02:00
else
2020-12-29 01:09:18 +02:00
outside_chests[entity.unit_number] = {chest = entity, position = entity.position, linked = train.unit_number}
2020-07-07 16:30:04 +02:00
chests_linked_to[train.unit_number] = {count = 1}
2020-07-06 15:45:09 +02:00
end
2020-07-07 16:30:04 +02:00
::continue::
2020-07-06 15:45:09 +02:00
rendering.draw_text {
text = '',
surface = entity.surface,
target = entity,
target_offset = {0, -0.6},
scale = 2,
color = {r = 0, g = 0.6, b = 1},
alignment = 'center'
}
chest_created = true
end
end
if chest_created then
return
end
if next(outside_chests) == nil then
2020-12-29 01:09:18 +02:00
outside_chests[entity.unit_number] = {chest = entity, position = entity.position, linked = train.unit_number}
2020-07-07 16:30:04 +02:00
chests_linked_to[train.unit_number] = {count = 1}
chests_linked_to[train.unit_number][entity.unit_number] = true
2020-07-06 15:45:09 +02:00
rendering.draw_text {
text = '',
surface = entity.surface,
target = entity,
target_offset = {0, -0.6},
scale = 2,
color = {r = 0, g = 0.6, b = 1},
alignment = 'center'
}
return
end
end
local function on_player_and_robot_mined_entity(event)
local entity = event.entity
if not entity.valid then
return
end
local outside_chests = WPT.get('outside_chests')
local chests_linked_to = WPT.get('chests_linked_to')
if outside_chests[entity.unit_number] then
for k, data in pairs(chests_linked_to) do
if data[entity.unit_number] then
data.count = data.count - 1
if data.count <= 0 then
2020-07-06 15:45:09 +02:00
chests_linked_to[k] = nil
end
end
2020-07-07 16:30:04 +02:00
if chests_linked_to[k] and chests_linked_to[k][entity.unit_number] then
chests_linked_to[k][entity.unit_number] = nil
end
2020-07-06 15:45:09 +02:00
end
outside_chests[entity.unit_number] = nil
end
end
local function divide_contents()
local outside_chests = WPT.get('outside_chests')
2020-12-29 01:09:18 +02:00
local chests_linked_to = WPT.get('chests_linked_to')
2020-07-06 15:45:09 +02:00
local target_chest
2020-12-29 01:09:18 +02:00
if not next(outside_chests) then
goto final
end
2020-07-06 15:45:09 +02:00
2020-12-29 01:09:18 +02:00
for key, data in pairs(outside_chests) do
local chest = data.chest
2020-07-06 15:45:09 +02:00
local area = {
2020-12-29 01:09:18 +02:00
left_top = {x = data.position.x - 4, y = data.position.y - 4},
right_bottom = {x = data.position.x + 4, y = data.position.y + 4}
2020-07-06 15:45:09 +02:00
}
2020-12-29 01:09:18 +02:00
if not (chest and chest.valid) then
if chests_linked_to[data.linked] then
if chests_linked_to[data.linked][key] then
chests_linked_to[data.linked][key] = nil
chests_linked_to[data.linked].count = chests_linked_to[data.linked].count - 1
if chests_linked_to[data.linked].count <= 0 then
chests_linked_to[data.linked] = nil
end
end
end
outside_chests[key] = nil
goto continue
end
2020-07-06 15:45:09 +02:00
local success, entity = contains_positions(area)
if success then
target_chest = entity
else
2020-12-29 01:09:18 +02:00
if chests_linked_to[data.linked] then
if chests_linked_to[data.linked][key] then
chests_linked_to[data.linked][key] = nil
chests_linked_to[data.linked].count = chests_linked_to[data.linked].count - 1
if chests_linked_to[data.linked].count <= 0 then
chests_linked_to[data.linked] = nil
end
end
end
goto continue
2020-07-06 15:45:09 +02:00
end
local chest1 = chest.get_inventory(defines.inventory.chest)
local chest2 = target_chest.get_inventory(defines.inventory.cargo_wagon)
for item, count in pairs(chest1.get_contents()) do
local t = {name = item, count = count}
local c = chest2.insert(t)
if (c > 0) then
chest1.remove({name = item, count = c})
end
end
2020-12-29 01:09:18 +02:00
::continue::
2020-07-06 15:45:09 +02:00
end
2020-12-29 01:09:18 +02:00
::final::
2020-07-06 15:45:09 +02:00
end
2020-06-03 20:09:00 +02:00
local function place_market()
2021-05-16 14:42:15 +02:00
local locomotive = WPT.get('locomotive')
if not locomotive then
2020-06-03 20:09:00 +02:00
return
end
2021-05-16 14:42:15 +02:00
if not locomotive.valid then
2020-06-03 20:09:00 +02:00
return
end
2021-05-16 14:42:15 +02:00
local icw_table = ICW.get_table()
local unit_surface = locomotive.unit_number
2020-06-03 20:09:00 +02:00
local surface = game.surfaces[icw_table.wagons[unit_surface].surface.index]
2021-05-16 14:42:15 +02:00
local market = WPT.get('market')
2020-06-03 20:09:00 +02:00
local data = {
surface = surface
}
2021-05-16 14:42:15 +02:00
if not market then
2020-06-03 20:09:00 +02:00
create_market(data)
2021-05-16 14:42:15 +02:00
elseif not market.valid then
2020-06-03 20:09:00 +02:00
create_market(data, true)
end
end
local function on_research_finished(event)
local research = event.research
if not research then
2020-07-07 16:30:04 +02:00
return
end
local name = research.name
if name == 'discharge-defense-equipment' then
local message = ({'locomotive.discharge_unlocked'})
Alert.alert_all_players(15, message, nil, 'achievement/tech-maniac', 0.1)
end
if name == 'artillery' then
local message = ({'locomotive.artillery_unlocked'})
Alert.alert_all_players(15, message, nil, 'achievement/tech-maniac', 0.1)
end
2020-07-06 15:45:09 +02:00
local locomotive = WPT.get('locomotive')
if not locomotive or not locomotive.valid then
return
end
local market_announce = WPT.get('market_announce')
if market_announce > game.tick then
return
end
2020-07-06 15:45:09 +02:00
local breached_wall = WPT.get('breached_wall')
add_random_loot_to_main_market(breached_wall)
2020-09-04 22:04:28 +02:00
local message = ({'locomotive.new_items_at_market'})
2020-07-06 15:45:09 +02:00
Alert.alert_all_players(5, message, nil, 'achievement/tech-maniac', 0.1)
Public.refresh_gui()
end
2020-07-27 11:07:32 +02:00
local function shoo(event)
local icw_locomotive = WPT.get('icw_locomotive')
local loco_surface = icw_locomotive.surface
if not loco_surface.valid then
return
end
local player = game.players[event.player_index]
if player and player.valid then
if player.surface.index ~= loco_surface.index then
return
end
end
local locomotive_biter = WPT.get('locomotive_biter')
local surface = player.surface
local message = event.message
message = string.lower(message)
for word in string.gmatch(message, '%g+') do
if word == 'shoo' then
if not locomotive_biter or not locomotive_biter.valid then
2020-07-27 11:07:32 +02:00
spawn_biter()
return
end
surface.create_entity(
{
name = 'rocket',
position = locomotive_biter.position,
force = 'enemy',
speed = 1,
max_range = 1200,
target = locomotive_biter,
source = locomotive_biter
}
)
if locomotive_biter and locomotive_biter.valid then
locomotive_biter.die()
WPT.set().locomotive_biter = nil
end
return
end
end
end
local function on_console_chat(event)
if not event.player_index then
return
end
shoo(event)
end
2020-08-04 12:10:15 +02:00
local function on_player_changed_surface(event)
local player = game.players[event.player_index]
if not validate_player(player) then
return
end
local active_surface = WPT.get('active_surface_index')
local surface = game.surfaces[active_surface]
if not surface or not surface.valid then
return
end
2020-08-04 12:10:15 +02:00
2020-08-14 22:53:59 +02:00
if player.surface.name == 'nauvis' then
2021-07-07 12:22:22 +02:00
local pos = surface.find_non_colliding_position('character', game.forces.player.get_spawn_position(surface), 3, 0, 5)
if pos then
player.teleport(pos, surface)
else
pos = game.forces.player.get_spawn_position(surface)
player.teleport(pos, surface)
end
2020-08-14 22:53:59 +02:00
end
local locomotive_surface = WPT.get('loco_surface')
if locomotive_surface and locomotive_surface.valid and player.surface.index == locomotive_surface.index then
return Public.add_player_to_permission_group(player, 'limited')
elseif ICFunctions.get_player_surface(player) then
return Public.add_player_to_permission_group(player, 'limited')
elseif player.surface.index == surface.index then
return Public.add_player_to_permission_group(player, 'main_surface')
2020-08-04 12:10:15 +02:00
end
end
2021-02-04 21:23:07 +02:00
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
2021-02-10 22:21:19 +02:00
local entity = event.entity
if not entity or not entity.valid then
return
end
2021-02-04 21:23:07 +02:00
local trusted = Session.get_trusted_table()
2021-02-12 00:19:04 +02:00
if #trusted == 0 then
return
end
2021-02-04 21:23:07 +02:00
local locomotive = WPT.get('locomotive')
if not locomotive or not locomotive.valid then
return
end
2021-02-10 22:21:19 +02:00
if entity.unit_number == locomotive.unit_number then
if not trusted[player.name] then
if player.character and player.character.valid and player.character.driving then
player.character.driving = false
end
2021-02-04 21:23:07 +02:00
end
end
end
2020-07-06 15:45:09 +02:00
function Public.close_gui_player(frame)
if not frame then
return
end
if frame then
frame.destroy()
end
end
function Public.refresh_gui()
local players = game.connected_players
for i = 1, #players do
local player = players[i]
local gui = player.gui
local screen = gui.screen
local player_data = WPT.get('players')
2021-05-23 17:03:52 +02:00
if not players then
return
end
2020-07-06 15:45:09 +02:00
local data = player_data[player.index].data
if screen and data and data.frame then
redraw_market_items(data.item_frame, player, data.search_text)
end
end
end
2020-05-17 12:23:55 +02:00
function Public.boost_players_around_train()
2021-05-25 22:19:20 +02:00
local rpg = RPG.get('rpg_t')
2020-11-15 20:23:54 +02:00
local active_surface_index = WPT.get('active_surface_index')
if not active_surface_index then
2020-05-17 12:23:55 +02:00
return
end
2020-11-15 20:23:54 +02:00
local locomotive = WPT.get('locomotive')
if not (locomotive and locomotive.valid) then
2020-05-17 12:23:55 +02:00
return
end
2020-11-15 20:23:54 +02:00
local surface = game.surfaces[active_surface_index]
2020-05-23 21:18:18 +02:00
local icw_table = ICW.get_table()
2020-11-15 20:23:54 +02:00
local unit_surface = locomotive.unit_number
2020-05-23 21:18:18 +02:00
local locomotive_surface = game.surfaces[icw_table.wagons[unit_surface].surface.index]
2020-05-17 12:23:55 +02:00
local data = {
surface = surface,
locomotive_surface = locomotive_surface,
rpg = rpg
}
property_boost(data)
end
2020-07-07 16:30:04 +02:00
function Public.is_around_train(entity)
local locomotive = WPT.get('locomotive')
local active_surface_index = WPT.get('active_surface_index')
if not active_surface_index then
return false
end
if not locomotive then
return false
end
if not locomotive.valid then
return false
end
if not entity or not entity.valid then
return false
end
local surface = game.surfaces[active_surface_index]
2020-08-26 11:08:12 +02:00
local aura = WPT.get('locomotive_xp_aura')
2020-07-07 16:30:04 +02:00
local data = {
locomotive = locomotive,
surface = surface,
2020-08-26 11:08:12 +02:00
entity = entity,
aura = aura
2020-07-07 16:30:04 +02:00
}
local success = is_around_train(data)
return success
end
2020-05-17 12:23:55 +02:00
function Public.render_train_hp()
2020-11-15 20:23:54 +02:00
local active_surface_index = WPT.get('active_surface_index')
local surface = game.surfaces[active_surface_index]
local locomotive_health = WPT.get('locomotive_health')
local locomotive_max_health = WPT.get('locomotive_max_health')
local locomotive = WPT.get('locomotive')
local locomotive_xp_aura = WPT.get('locomotive_xp_aura')
2020-05-17 12:23:55 +02:00
2020-11-15 20:23:54 +02:00
WPT.set().health_text =
2020-05-17 12:23:55 +02:00
rendering.draw_text {
2020-11-15 20:23:54 +02:00
text = 'HP: ' .. locomotive_health .. ' / ' .. locomotive_max_health,
2020-05-17 12:23:55 +02:00
surface = surface,
2020-11-15 20:23:54 +02:00
target = locomotive,
2020-06-21 09:29:01 +02:00
target_offset = {0, -4.5},
2020-11-15 20:23:54 +02:00
color = locomotive.color,
2020-05-17 12:23:55 +02:00
scale = 1.40,
font = 'default-game',
alignment = 'center',
scale_with_zoom = false
}
2020-11-15 20:23:54 +02:00
WPT.set().caption =
2020-05-17 12:23:55 +02:00
rendering.draw_text {
2020-05-21 23:08:23 +02:00
text = 'Comfy Choo Choo',
2020-05-17 12:23:55 +02:00
surface = surface,
2020-11-15 20:23:54 +02:00
target = locomotive,
2020-06-21 09:29:01 +02:00
target_offset = {0, -6.25},
2020-11-15 20:23:54 +02:00
color = locomotive.color,
2020-05-17 12:23:55 +02:00
scale = 1.80,
font = 'default-game',
alignment = 'center',
scale_with_zoom = false
}
2020-11-15 20:23:54 +02:00
WPT.set().circle =
2020-05-17 12:23:55 +02:00
rendering.draw_circle {
surface = surface,
2020-11-15 20:23:54 +02:00
target = locomotive,
color = locomotive.color,
2020-05-17 12:23:55 +02:00
filled = false,
2020-11-15 20:23:54 +02:00
radius = locomotive_xp_aura,
2020-05-17 12:23:55 +02:00
only_in_alt_mode = true
}
end
function Public.locomotive_spawn(surface, position)
2020-05-20 09:09:39 +02:00
local this = WPT.get()
2020-11-15 20:23:54 +02:00
for y = -6, 6, 2 do
2020-11-04 18:14:30 +02:00
surface.create_entity({name = 'straight-rail', position = {position.x, position.y + y}, force = 'player', direction = 0})
2020-05-17 12:23:55 +02:00
end
2020-11-04 18:14:30 +02:00
this.locomotive = surface.create_entity({name = 'locomotive', position = {position.x, position.y + -3}, force = 'player'})
2020-05-17 12:23:55 +02:00
this.locomotive.get_inventory(defines.inventory.fuel).insert({name = 'wood', count = 100})
2020-11-04 18:14:30 +02:00
this.locomotive_cargo = surface.create_entity({name = 'cargo-wagon', position = {position.x, position.y + 3}, force = 'player'})
2020-05-17 12:23:55 +02:00
this.locomotive_cargo.get_inventory(defines.inventory.cargo_wagon).insert({name = 'raw-fish', count = 8})
2020-12-20 20:56:26 +02:00
local winter_mode_locomotive = Generate.wintery(this.locomotive, 5.5)
if not winter_mode_locomotive then
rendering.draw_light(
{
sprite = 'utility/light_medium',
scale = 5.5,
intensity = 1,
minimum_darkness = 0,
oriented = true,
color = {255, 255, 255},
target = this.locomotive,
surface = surface,
visible = true,
only_in_alt_mode = false
}
)
end
2020-05-17 12:23:55 +02:00
2020-12-20 20:56:26 +02:00
local winter_mode_cargo = Generate.wintery(this.locomotive_cargo, 5.5)
if not winter_mode_cargo then
rendering.draw_light(
{
sprite = 'utility/light_medium',
scale = 5.5,
intensity = 1,
minimum_darkness = 0,
oriented = true,
color = {255, 255, 255},
target = this.locomotive_cargo,
surface = surface,
visible = true,
only_in_alt_mode = false
}
)
end
2020-11-04 18:14:30 +02:00
2020-09-17 09:14:07 +02:00
local data = {
surface = surface,
position = position
}
2021-05-15 16:01:07 +02:00
Task.set_timeout_in_ticks(400, set_loco_tiles, data)
2020-09-17 09:14:07 +02:00
2020-05-17 12:23:55 +02:00
for y = -1, 0, 0.05 do
2020-08-09 20:22:33 +02:00
local scale = random(50, 100) * 0.01
2020-05-17 12:23:55 +02:00
rendering.draw_sprite(
{
sprite = 'item/raw-fish',
2020-08-09 20:22:33 +02:00
orientation = random(0, 100) * 0.01,
2020-05-17 12:23:55 +02:00
x_scale = scale,
y_scale = scale,
2020-08-09 20:22:33 +02:00
tint = {random(60, 255), random(60, 255), random(60, 255)},
2020-05-17 12:23:55 +02:00
render_layer = 'selection-box',
target = this.locomotive_cargo,
2020-08-09 20:22:33 +02:00
target_offset = {-0.7 + random(0, 140) * 0.01, y},
2020-05-17 12:23:55 +02:00
surface = surface
}
)
end
2020-09-17 09:14:07 +02:00
this.locomotive.color = {0, 255, random(60, 255)}
2020-05-17 12:23:55 +02:00
this.locomotive.minable = false
this.locomotive_cargo.minable = false
this.locomotive_cargo.operable = true
local locomotive = ICW.register_wagon(this.locomotive)
2020-11-04 18:14:30 +02:00
ICW.register_wagon(this.locomotive_cargo)
2020-05-17 12:23:55 +02:00
2020-06-03 20:09:00 +02:00
this.icw_locomotive = locomotive
2020-05-21 23:08:23 +02:00
2020-06-03 20:09:00 +02:00
game.forces.player.set_spawn_position({0, 19}, locomotive.surface)
2020-05-17 12:23:55 +02:00
end
function Public.get_items()
2020-07-06 15:45:09 +02:00
local chest_limit_outside_upgrades = WPT.get('chest_limit_outside_upgrades')
local health_upgrades = WPT.get('health_upgrades')
local pickaxe_tier = WPT.get('pickaxe_tier')
2020-07-06 15:45:09 +02:00
local aura_upgrades = WPT.get('aura_upgrades')
local main_market_items = WPT.get('main_market_items')
local xp_points_upgrade = WPT.get('xp_points_upgrade')
local flame_turret = WPT.get('upgrades').flame_turret.bought
local landmine = WPT.get('upgrades').landmine.bought
2020-10-21 23:17:17 +02:00
local fixed_prices = WPT.get('marked_fixed_prices')
local chest_limit_cost = round(fixed_prices.chest_limit_cost * (1 + chest_limit_outside_upgrades))
local health_cost = round(fixed_prices.health_cost * (1 + health_upgrades))
local pickaxe_cost = round(fixed_prices.pickaxe_cost * (0.1 + pickaxe_tier / 2))
local aura_cost = round(fixed_prices.aura_cost * (1 + aura_upgrades))
local xp_point_boost_cost = round(fixed_prices.xp_point_boost_cost * (1 + xp_points_upgrade))
local explosive_bullets_cost = round(fixed_prices.explosive_bullets_cost)
local flamethrower_turrets_cost = round(fixed_prices.flamethrower_turrets_cost * (1 + flame_turret))
local land_mine_cost = round(fixed_prices.land_mine_cost * (1 + landmine))
2020-10-21 23:17:17 +02:00
local pickaxe_tiers = WPT.pickaxe_upgrades
local tier = WPT.get('pickaxe_tier')
local offer = pickaxe_tiers[tier]
2020-11-29 03:23:33 +02:00
if pickaxe_tier >= 59 then
main_market_items['upgrade_pickaxe'] = {
stack = 1,
value = 'coin',
price = pickaxe_cost,
tooltip = ({'main_market.sold_out'}),
sprite = 'achievement/delivery-service',
enabled = false,
upgrade = true,
static = true
}
else
main_market_items['upgrade_pickaxe'] = {
stack = 1,
value = 'coin',
price = pickaxe_cost,
tooltip = ({'main_market.purchase_pickaxe', offer}),
sprite = 'achievement/delivery-service',
enabled = true,
upgrade = true,
static = true
}
end
2021-05-16 13:48:50 +02:00
2020-07-07 16:30:04 +02:00
if main_market_items['chest_limit_outside'] then
main_market_items['chest_limit_outside'] = {
stack = 1,
value = 'coin',
price = chest_limit_cost,
tooltip = main_market_items['chest_limit_outside'].tooltip,
sprite = 'achievement/so-long-and-thanks-for-all-the-fish',
enabled = main_market_items['chest_limit_outside'].enabled,
upgrade = true,
static = true
}
else
main_market_items['chest_limit_outside'] = {
stack = 1,
value = 'coin',
price = chest_limit_cost,
2020-09-04 22:04:28 +02:00
tooltip = ({'main_market.chest'}),
2020-07-07 16:30:04 +02:00
sprite = 'achievement/so-long-and-thanks-for-all-the-fish',
enabled = true,
upgrade = true,
static = true
}
end
2021-05-16 13:48:50 +02:00
if main_market_items['locomotive_max_health'] then
main_market_items['locomotive_max_health'] = {
stack = 1,
value = 'coin',
price = health_cost,
tooltip = main_market_items['locomotive_max_health'].tooltip,
sprite = 'achievement/getting-on-track',
enabled = main_market_items['locomotive_max_health'].enabled,
upgrade = true,
static = true
}
else
main_market_items['locomotive_max_health'] = {
stack = 1,
value = 'coin',
price = health_cost,
tooltip = ({'main_market.locomotive_max_health'}),
sprite = 'achievement/getting-on-track',
enabled = true,
upgrade = true,
static = true
}
end
2020-07-06 15:45:09 +02:00
main_market_items['locomotive_xp_aura'] = {
2020-06-03 20:09:00 +02:00
stack = 1,
value = 'coin',
price = aura_cost,
2020-09-04 22:04:28 +02:00
tooltip = ({'main_market.locomotive_xp_aura'}),
2020-06-07 13:33:24 +02:00
sprite = 'achievement/tech-maniac',
2020-07-06 15:45:09 +02:00
enabled = true,
upgrade = true,
static = true
2020-06-03 20:09:00 +02:00
}
2020-07-06 15:45:09 +02:00
main_market_items['xp_points_boost'] = {
2020-06-03 20:09:00 +02:00
stack = 1,
value = 'coin',
price = xp_point_boost_cost,
2020-09-04 22:04:28 +02:00
tooltip = ({'main_market.xp_points_boost'}),
2020-06-07 13:33:24 +02:00
sprite = 'achievement/trans-factorio-express',
2020-07-06 15:45:09 +02:00
enabled = true,
upgrade = true,
static = true
2020-06-03 20:09:00 +02:00
}
2020-08-21 13:56:01 +02:00
if WPT.get('explosive_bullets') then
main_market_items['explosive_bullets'] = {
stack = 1,
value = 'coin',
price = explosive_bullets_cost,
2020-09-04 22:04:28 +02:00
tooltip = ({'main_market.sold_out'}),
2020-08-21 13:56:01 +02:00
sprite = 'achievement/steamrolled',
enabled = false,
upgrade = true,
static = true
}
else
main_market_items['explosive_bullets'] = {
stack = 1,
value = 'coin',
price = explosive_bullets_cost,
2020-09-04 22:04:28 +02:00
tooltip = ({'main_market.explosive_bullets'}),
2020-08-21 13:56:01 +02:00
sprite = 'achievement/steamrolled',
enabled = true,
upgrade = true,
static = true
}
end
2020-07-06 15:45:09 +02:00
main_market_items['flamethrower_turrets'] = {
2020-06-03 20:09:00 +02:00
stack = 1,
value = 'coin',
price = flamethrower_turrets_cost,
2020-09-04 22:04:28 +02:00
tooltip = ({'main_market.flamethrower_turret'}),
2020-06-07 13:33:24 +02:00
sprite = 'achievement/pyromaniac',
2020-07-06 15:45:09 +02:00
enabled = true,
upgrade = true,
static = true
2020-06-03 20:09:00 +02:00
}
2020-07-06 15:45:09 +02:00
main_market_items['land_mine'] = {
2020-06-03 20:09:00 +02:00
stack = 1,
value = 'coin',
price = land_mine_cost,
2020-09-04 22:04:28 +02:00
tooltip = ({'main_market.land_mine'}),
2020-06-07 13:33:24 +02:00
sprite = 'achievement/watch-your-step',
2020-07-06 15:45:09 +02:00
enabled = true,
upgrade = true,
static = true
2020-06-07 13:33:24 +02:00
}
2020-08-09 20:31:50 +02:00
if game.forces.player.technologies['logistics'].researched then
2021-05-15 16:01:07 +02:00
main_market_items['loader'] = {
stack = 1,
value = 'coin',
price = 128,
tooltip = ({'entity-name.loader'}),
upgrade = false,
static = true
}
2020-08-09 20:31:50 +02:00
end
if game.forces.player.technologies['logistics-2'].researched then
2021-05-15 16:01:07 +02:00
main_market_items['fast-loader'] = {
stack = 1,
value = 'coin',
price = 256,
tooltip = ({'entity-name.fast-loader'}),
upgrade = false,
static = true
}
2020-08-09 20:31:50 +02:00
end
if game.forces.player.technologies['logistics-3'].researched then
2021-05-16 13:48:50 +02:00
main_market_items['express-loader'] = {
stack = 1,
value = 'coin',
price = 512,
tooltip = ({'entity-name.express-loader'}),
upgrade = false,
static = true
}
2020-08-09 20:31:50 +02:00
end
2020-07-06 15:45:09 +02:00
main_market_items['small-lamp'] = {
stack = 1,
value = 'coin',
price = 5,
2020-09-04 22:04:28 +02:00
tooltip = ({'entity-name.small-lamp'}),
2020-07-06 15:45:09 +02:00
upgrade = false,
static = false
2020-07-06 15:45:09 +02:00
}
if game.forces.player.technologies['discharge-defense-equipment'].researched then
main_market_items['discharge-defense-equipment'] = {
stack = 1,
value = 'coin',
price = 9216,
tooltip = ({'equipment-name.discharge-defense-equipment'}),
upgrade = false,
static = false
}
main_market_items['discharge-defense-remote'] = {
stack = 1,
value = 'coin',
price = 1024,
tooltip = ({'item-name.discharge-defense-remote'}),
upgrade = false,
static = false
}
end
if game.forces.player.technologies['artillery'].researched then
main_market_items['artillery-turret'] = {
stack = 1,
value = 'coin',
price = 9216,
tooltip = ({'item-name.artillery-turret'}),
upgrade = false,
static = false
}
main_market_items['artillery-shell'] = {
stack = 1,
value = 'coin',
price = 1024,
tooltip = ({'item-name.artillery-shell'}),
upgrade = false,
static = false
}
end
2020-07-06 15:45:09 +02:00
main_market_items['wood'] = {
stack = 50,
value = 'coin',
price = 12,
2020-09-04 22:04:28 +02:00
tooltip = ({'item-name.wood'}),
2020-07-06 15:45:09 +02:00
upgrade = false,
static = false
2020-07-06 15:45:09 +02:00
}
main_market_items['iron-ore'] = {
stack = 50,
value = 'coin',
price = 12,
2020-09-04 22:04:28 +02:00
tooltip = ({'item-name.iron-ore'}),
2020-07-06 15:45:09 +02:00
upgrade = false,
static = false
2020-07-06 15:45:09 +02:00
}
main_market_items['copper-ore'] = {
stack = 50,
value = 'coin',
price = 12,
2020-09-04 22:04:28 +02:00
tooltip = ({'item-name.copper-ore'}),
2020-07-06 15:45:09 +02:00
upgrade = false,
static = false
2020-07-06 15:45:09 +02:00
}
main_market_items['stone'] = {
stack = 50,
value = 'coin',
price = 12,
2020-09-04 22:04:28 +02:00
tooltip = ({'item-name.stone'}),
2020-07-06 15:45:09 +02:00
upgrade = false,
static = false
2020-07-06 15:45:09 +02:00
}
main_market_items['coal'] = {
stack = 50,
value = 'coin',
price = 12,
2020-09-04 22:04:28 +02:00
tooltip = ({'item-name.coal'}),
2020-07-06 15:45:09 +02:00
upgrade = false,
static = false
2020-07-06 15:45:09 +02:00
}
main_market_items['uranium-ore'] = {
stack = 50,
value = 'coin',
price = 12,
2020-09-04 22:04:28 +02:00
tooltip = ({'item-name.uranium-ore'}),
2020-07-06 15:45:09 +02:00
upgrade = false,
static = false
2020-07-06 15:45:09 +02:00
}
main_market_items['land-mine'] = {
stack = 1,
value = 'coin',
price = 10,
2020-09-04 22:04:28 +02:00
tooltip = ({'entity-name.land-mine'}),
2020-07-06 15:45:09 +02:00
upgrade = false,
static = false
2020-07-06 15:45:09 +02:00
}
main_market_items['raw-fish'] = {
stack = 1,
value = 'coin',
price = 4,
2020-09-04 22:04:28 +02:00
tooltip = ({'item-name.raw-fish'}),
2020-07-06 15:45:09 +02:00
upgrade = false,
static = false
2020-07-06 15:45:09 +02:00
}
main_market_items['firearm-magazine'] = {
stack = 1,
value = 'coin',
price = 5,
2020-09-04 22:04:28 +02:00
tooltip = ({'item-name.firearm-magazine'}),
2020-07-06 15:45:09 +02:00
upgrade = false,
static = false
2020-07-06 15:45:09 +02:00
}
main_market_items['crude-oil-barrel'] = {
stack = 1,
value = 'coin',
price = 8,
2020-09-04 22:04:28 +02:00
tooltip = ({'item-name.crude-oil-barrel'}),
2020-07-06 15:45:09 +02:00
upgrade = false,
static = false
2020-07-06 15:45:09 +02:00
}
main_market_items['car'] = {
2020-07-30 17:47:50 +02:00
stack = 1,
value = 'coin',
2021-02-04 21:23:07 +02:00
price = 6000,
2020-09-04 22:04:28 +02:00
tooltip = ({'main_market.car'}),
2020-08-05 21:36:20 +02:00
upgrade = false,
static = true
}
2020-08-05 21:36:20 +02:00
main_market_items['tank'] = {
stack = 1,
value = 'coin',
2021-02-04 21:23:07 +02:00
price = 12000,
2020-09-04 22:04:28 +02:00
tooltip = ({'main_market.tank'}),
2020-07-30 17:47:50 +02:00
upgrade = false,
static = true
}
2020-07-28 11:24:16 +02:00
local wave_number = WD.get_wave()
2020-08-22 20:15:56 +02:00
if wave_number >= 650 then
main_market_items['tank-cannon'] = {
stack = 1,
value = 'coin',
price = 25000,
tooltip = ({'item-name.tank-cannon'}),
2020-08-22 20:15:56 +02:00
upgrade = false,
static = true,
enabled = true
}
else
main_market_items['tank-cannon'] = {
stack = 1,
value = 'coin',
price = 25000,
2021-02-01 01:09:59 +02:00
tooltip = ({'main_market.tank_cannon_na', 650}),
2020-08-22 20:15:56 +02:00
upgrade = false,
static = true,
enabled = false
}
end
if wave_number >= 100 then
2020-08-22 20:15:56 +02:00
main_market_items['vehicle-machine-gun'] = {
stack = 1,
value = 'coin',
price = 2000,
2020-09-04 22:04:28 +02:00
tooltip = ({'item-name.vehicle-machine-gun'}),
2020-08-22 20:15:56 +02:00
upgrade = false,
static = true,
enabled = true
}
else
main_market_items['vehicle-machine-gun'] = {
stack = 1,
value = 'coin',
price = 2000,
2021-02-01 01:09:59 +02:00
tooltip = ({'main_market.vehicle_machine_gun_na', 100}),
2020-08-22 20:15:56 +02:00
upgrade = false,
static = true,
enabled = false
}
2020-07-28 11:24:16 +02:00
end
2020-07-06 15:45:09 +02:00
return main_market_items
2020-06-03 20:09:00 +02:00
end
2020-06-07 13:33:24 +02:00
function Public.transfer_pollution()
local locomotive = WPT.get('locomotive')
2021-05-16 14:42:15 +02:00
if not locomotive or not locomotive.valid then
2020-06-07 13:33:24 +02:00
return
end
2021-05-16 14:42:15 +02:00
local active_surface_index = WPT.get('active_surface_index')
2020-08-14 22:41:45 +02:00
local active_surface = game.surfaces[active_surface_index]
if not active_surface or not active_surface.valid then
return
end
2021-05-16 14:42:15 +02:00
local icw_locomotive = WPT.get('icw_locomotive')
local surface = icw_locomotive.surface
if not surface or not surface.valid then
2020-08-14 22:41:45 +02:00
return
end
2020-06-07 13:33:24 +02:00
local total_interior_pollution = surface.get_total_pollution()
2020-06-25 17:59:16 +02:00
local pollution = surface.get_total_pollution() * (3 / (4 / 3 + 1)) * Difficulty.get().difficulty_vote_value
2020-08-14 22:41:45 +02:00
active_surface.pollute(locomotive.position, pollution)
2020-06-07 13:33:24 +02:00
game.pollution_statistics.on_flow('locomotive', pollution - total_interior_pollution)
surface.clear_pollution()
end
function Public.enable_poison_defense(pos)
local locomotive = WPT.get('locomotive')
if not locomotive then
return
end
if not locomotive.valid then
return
end
pos = pos or locomotive.position
create_defense_system({x = pos.x, y = pos.y}, 'poison-cloud', pos)
if random(1, 4) == 1 then
local random_angles = {rad(random(344))}
create_defense_system({x = pos.x + 24 * cos(random_angles[1]), y = pos.y + -24 * sin(random_angles[1])}, 'poison-cloud', pos)
end
end
function Public.enable_robotic_defense(pos)
2020-06-07 13:33:24 +02:00
local locomotive = WPT.get('locomotive')
if not locomotive then
return
end
if not locomotive.valid then
return
end
2021-05-16 14:42:15 +02:00
pos = pos or locomotive.position
create_defense_system({x = pos.x, y = pos.y}, 'destroyer-capsule', pos)
2020-08-10 23:15:29 +02:00
if random(1, 4) == 1 then
local random_angles = {rad(random(324))}
create_defense_system({x = pos.x + 24 * cos(random_angles[1]), y = pos.y + -24 * sin(random_angles[1])}, 'destroyer-capsule', pos)
2020-06-07 13:33:24 +02:00
end
end
2020-07-28 11:24:16 +02:00
local boost_players = Public.boost_players_around_train
local pollute_area = Public.transfer_pollution
local function tick()
local ticker = game.tick
if ticker % 30 == 0 then
set_locomotive_health()
place_market()
validate_index()
fish_tag()
divide_contents()
end
if ticker % 120 == 0 then
2020-08-09 20:31:50 +02:00
-- tp_player()
2020-07-28 11:24:16 +02:00
boost_players()
end
2020-08-04 12:10:15 +02:00
if ticker % 1200 == 0 then
2020-07-28 11:24:16 +02:00
set_player_spawn()
refill_fish()
end
2020-08-04 12:10:15 +02:00
if ticker % 2500 == 0 then
pollute_area()
end
2020-07-28 11:24:16 +02:00
end
2020-06-03 20:09:00 +02:00
Public.place_market = place_market
2020-05-20 09:09:39 +02:00
Event.on_nth_tick(5, tick)
2020-06-03 20:09:00 +02:00
Event.add(defines.events.on_gui_click, gui_click)
Event.add(defines.events.on_gui_opened, gui_opened)
Event.add(defines.events.on_gui_value_changed, slider_changed)
Event.add(defines.events.on_gui_text_changed, text_changed)
Event.add(defines.events.on_gui_closed, gui_closed)
Event.add(defines.events.on_player_changed_position, on_player_changed_position)
2020-07-06 15:45:09 +02:00
Event.add(defines.events.on_research_finished, on_research_finished)
Event.add(defines.events.on_built_entity, on_built_entity)
2020-07-07 16:30:04 +02:00
Event.add(defines.events.on_robot_built_entity, on_built_entity)
2020-07-06 15:45:09 +02:00
Event.add(defines.events.on_entity_died, on_player_and_robot_mined_entity)
Event.add(defines.events.on_pre_player_mined_item, on_player_and_robot_mined_entity)
Event.add(defines.events.on_robot_mined_entity, on_player_and_robot_mined_entity)
2020-07-27 11:07:32 +02:00
Event.add(defines.events.on_console_chat, on_console_chat)
2020-08-04 12:10:15 +02:00
Event.add(defines.events.on_player_changed_surface, on_player_changed_surface)
2021-02-04 21:23:07 +02:00
Event.add(defines.events.on_player_driving_changed_state, on_player_driving_changed_state)
Event.add(defines.events.on_train_created, set_carriages)
2020-05-17 12:23:55 +02:00
return Public