1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2024-12-28 23:06:38 +02:00
ComfyFactorio/maps/mountain_fortress_v3/locomotive.lua

728 lines
23 KiB
Lua

local Event = require 'utils.event'
local Market = require 'maps.mountain_fortress_v3.basic_markets'
local LocomotiveMarket = require 'maps.mountain_fortress_v3.locomotive.market'
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'
local Session = require 'utils.datastore.session_data'
local Difficulty = require 'modules.difficulty_vote_by_amount'
local RPG = require 'modules.rpg.main'
local Gui = require 'utils.gui'
local Alert = require 'utils.alert'
local PermissionGroups = require 'maps.mountain_fortress_v3.locomotive.permission_groups'
local Public = {}
local rpg_main_frame = RPG.main_frame_name
local random = math.random
local floor = math.floor
local round = math.round
local sub = string.sub
local clear_items_upon_surface_entry = {
['entity-ghost'] = true,
['small-electric-pole'] = true,
['medium-electric-pole'] = true,
['big-electric-pole'] = true,
['substation'] = true
}
local valid_armors = {
['modular-armor'] = true,
['power-armor'] = true,
['power-armor-mk2'] = true
}
local non_valid_vehicles = {
['car'] = true,
['spider-vehicle'] = true
}
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)
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
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
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
if not game.get_player(player.name) then
return false
end
return true
end
local function death_effects(player)
local position = {x = player.position.x - 0.75, y = player.position.y - 1}
local b = 0.75
for _ = 1, 5, 1 do
local p = {
(position.x + 0.4) + (b * -1 + math.random(0, b * 20) * 0.1),
position.y + (b * -1 + math.random(0, b * 20) * 0.1)
}
player.surface.create_entity({name = 'flying-text', position = p, text = '☠️', color = {255, math.random(0, 100), 0}})
end
player.play_sound {path = 'utility/axe_fighting', volume_modifier = 0.9}
end
local messages = {
' likes to play in magma.',
' got melted.',
' tried to swim in lava.',
' was incinerated.',
" couldn't put the fire out.",
' was turned into their molten form.'
}
local function is_around_train(data)
local entity = data.entity
local locomotive_aura_radius = data.locomotive_aura_radius + 20
local loco = data.locomotive.position
local position = entity.position
local inside = ((position.x - loco.x) ^ 2 + (position.y - loco.y) ^ 2) < locomotive_aura_radius ^ 2
if inside then
return true
end
return false
end
local function hurt_players_outside_of_aura()
local Diff = Difficulty.get()
if not Diff then
return
end
local difficulty_set = WPT.get('difficulty_set')
if not difficulty_set then
return
end
local death_mode = false
if Diff.index == 1 then
return
elseif Diff.index == 3 then
death_mode = true
end
local loco_surface = WPT.get('loco_surface')
if not (loco_surface and loco_surface.valid) then
return
end
local locomotive = WPT.get('locomotive')
local loco = locomotive.position
local upgrades = WPT.get('upgrades')
local players = game.connected_players
for i = 1, #players do
local player = players[i]
if validate_player(player) then
local map_name = 'mtn_v3'
if sub(player.surface.name, 0, #map_name) == map_name then
local position = player.position
local inside = ((position.x - loco.x) ^ 2 + (position.y - loco.y) ^ 2) < upgrades.locomotive_aura_radius ^ 2
if not inside then
death_effects(player)
player.surface.create_entity({name = 'fire-flame', position = position})
if random(1, 3) == 1 then
player.surface.create_entity({name = 'medium-scorchmark', position = position, force = 'neutral'})
end
local entity = player.character
if entity and entity.valid then
local max_health = floor(player.character.prototype.max_health + player.character_health_bonus + player.force.character_health_bonus)
local vehicle = player.vehicle
if vehicle and vehicle.valid and non_valid_vehicles[vehicle.type] then
player.driving = false
end
if death_mode then
if entity.name == 'character' then
game.print(player.name .. messages[random(1, #messages)], {r = 200, g = 0, b = 0})
end
if entity.valid then
entity.die()
end
else
local armor_inventory = player.get_inventory(defines.inventory.character_armor)
if not armor_inventory.valid then
return
end
local armor = armor_inventory[1]
if not armor.valid_for_read then
return
end
local grid = armor.grid
if not grid or not grid.valid then
return
end
local equip = grid.equipment
for _, piece in pairs(equip) do
if piece.valid then
piece.energy = 0
end
end
local damage = (max_health / 18)
if entity.valid then
if entity.health - damage <= 0 then
if entity.name == 'character' then
game.print(player.name .. messages[random(1, #messages)], {r = 200, g = 0, b = 0})
end
end
end
entity.damage(damage, 'enemy')
end
end
end
end
end
end
end
local function give_passive_xp(data)
local xp_floating_text_color = {r = 188, g = 201, b = 63}
local visuals_delay = 1800
local loco_surface = WPT.get('loco_surface')
if not (loco_surface and loco_surface.valid) then
return
end
local upgrades = WPT.get('upgrades')
local locomotive = WPT.get('locomotive')
local rpg = data.rpg
local loco = locomotive.position
for _, player in pairs(game.connected_players) do
if not validate_player(player) then
return
end
local position = player.position
local inside = ((position.x - loco.x) ^ 2 + (position.y - loco.y) ^ 2) < upgrades.locomotive_aura_radius ^ 2
if player.afk_time < 200 and not RPG.get_last_spell_cast(player) then
if inside or player.surface.index == loco_surface.index then
if player.surface.index == loco_surface.index then
PermissionGroups.add_player_to_permission_group(player, 'limited')
elseif ICFunctions.get_player_surface(player) then
return PermissionGroups.add_player_to_permission_group(player, 'limited')
else
PermissionGroups.add_player_to_permission_group(player, 'near_locomotive')
end
local pos = player.position
RPG.gain_xp(player, 0.5 * (rpg[player.index].bonus + upgrades.xp_points))
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
RPG.set_last_spell_cast(player, player.position)
if player.gui.screen[rpg_main_frame] then
local f = player.gui.screen[rpg_main_frame]
local d = Gui.get_data(f)
if d.exp_gui and d.exp_gui.valid then
d.exp_gui.caption = floor(rpg[player.index].xp)
end
end
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
PermissionGroups.add_player_to_permission_group(player, 'main_surface')
end
end
end
end
end
end
local function fish_tag()
local locomotive_cargo = WPT.get('locomotive_cargo')
if not (locomotive_cargo and locomotive_cargo.valid) then
return
end
if not (locomotive_cargo.surface and locomotive_cargo.surface.valid) then
return
end
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
return
end
locomotive_tag.destroy()
end
end
WPT.set(
'locomotive_tag',
locomotive_cargo.force.add_chart_tag(
locomotive_cargo.surface,
{
icon = {type = 'item', name = 'raw-fish'},
position = locomotive_cargo.position,
text = ' '
}
)
)
end
local function set_player_spawn()
local locomotive = WPT.get('locomotive')
if not locomotive then
return
end
if not locomotive.valid then
return
end
local position = locomotive.surface.find_non_colliding_position('stone-furnace', locomotive.position, 16, 2)
if not position then
return
end
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
locomotive_cargo.get_inventory(defines.inventory.cargo_wagon).insert({name = 'raw-fish', count = random(2, 5)})
end
local function set_carriages()
local locomotive = WPT.get('locomotive')
if not locomotive or not locomotive.valid then
return
end
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
local function get_driver_action(entity)
if not entity or not entity.valid then
return
end
local driver = entity.get_driver()
if not driver or not driver.valid then
return
end
local player = driver.player
if not player or not player.valid then
return
end
if player.cursor_stack and player.cursor_stack.valid_for_read and player.cursor_stack.name == 'raw-fish' then
player.print('[color=blue][Locomotive][/color] Unequip your fishy if you want to drive.')
driver.driving = false
return
end
local armor = driver.get_inventory(defines.inventory.character_armor)
if armor and armor[1] and armor[1].valid_for_read and valid_armors[armor[1].name] then
player.print('[color=blue][Locomotive][/color] Unequip your armor if you want to drive.')
driver.driving = false
end
end
local function set_locomotive_health()
local locomotive_health = WPT.get('locomotive_health')
local locomotive_max_health = WPT.get('locomotive_max_health')
local locomotive = WPT.get('locomotive')
local function check_health()
local m = locomotive_health / locomotive_max_health
if locomotive_health > locomotive_max_health then
WPT.set('locomotive_health', locomotive_max_health)
end
rendering.set_text(WPT.get('health_text'), 'HP: ' .. round(locomotive_health) .. ' / ' .. round(locomotive_max_health))
local carriages = WPT.get('carriages')
if carriages then
for i = 1, #carriages do
local entity = carriages[i]
if not (entity and entity.valid) then
return
end
get_driver_action(entity)
local cargo_health = 600
if entity.type == 'locomotive' then
entity.health = 1000 * m
else
entity.health = cargo_health * m
end
end
end
end
if not (locomotive and locomotive.valid) then
return
end
check_health()
end
local function validate_index()
local locomotive = WPT.get('locomotive')
if not locomotive then
return
end
if not locomotive.valid then
return
end
local icw_table = ICW.get_table()
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]
if loco_surface.valid then
WPT.set('loco_surface', locomotive_surface)
end
end
local function on_research_finished(event)
local research = event.research
if not research then
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
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
local breached_wall = WPT.get('breached_wall')
add_random_loot_to_main_market(breached_wall)
local message = ({'locomotive.new_items_at_market'})
Alert.alert_all_players(5, message, nil, 'achievement/tech-maniac', 0.1)
LocomotiveMarket.refresh_gui()
end
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
local itemGhost = player.cursor_ghost
if itemGhost then
player.cursor_ghost = nil
end
local item = player.cursor_stack
if item and item.valid_for_read then
local name = item.name
if clear_items_upon_surface_entry[name] then
player.cursor_stack.clear()
end
end
if player.surface.name == 'nauvis' then
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
end
local locomotive_surface = WPT.get('loco_surface')
if locomotive_surface and locomotive_surface.valid and player.surface.index == locomotive_surface.index then
return PermissionGroups.add_player_to_permission_group(player, 'limited')
elseif ICFunctions.get_player_surface(player) then
return PermissionGroups.add_player_to_permission_group(player, 'limited')
elseif player.surface.index == surface.index then
return PermissionGroups.add_player_to_permission_group(player, 'main_surface')
end
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 entity = event.entity
if not entity or not entity.valid then
return
end
local trusted = Session.get_trusted_table()
if #trusted == 0 then
return
end
local locomotive = WPT.get('locomotive')
if not locomotive or not locomotive.valid then
return
end
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
end
end
end
function Public.boost_players_around_train()
local rpg = RPG.get('rpg_t')
local active_surface_index = WPT.get('active_surface_index')
if not active_surface_index then
return
end
local locomotive = WPT.get('locomotive')
if not (locomotive and locomotive.valid) then
return
end
local surface = game.surfaces[active_surface_index]
local icw_table = ICW.get_table()
local unit_surface = locomotive.unit_number
local locomotive_surface = game.surfaces[icw_table.wagons[unit_surface].surface.index]
local data = {
surface = surface,
locomotive_surface = locomotive_surface,
rpg = rpg
}
give_passive_xp(data)
end
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]
local upgrades = WPT.get('upgrades')
local data = {
locomotive = locomotive,
surface = surface,
entity = entity,
locomotive_aura_radius = upgrades.locomotive_aura_radius
}
local success = is_around_train(data)
return success
end
function Public.render_train_hp()
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 upgrades = WPT.get('upgrades')
WPT.set(
'health_text',
rendering.draw_text {
text = 'HP: ' .. locomotive_health .. ' / ' .. locomotive_max_health,
surface = surface,
target = locomotive,
target_offset = {0, -4.5},
color = locomotive.color,
scale = 1.40,
font = 'default-game',
alignment = 'center',
scale_with_zoom = false
}
)
WPT.set(
'caption',
rendering.draw_text {
text = 'Comfy Choo Choo',
surface = surface,
target = locomotive,
target_offset = {0, -6.25},
color = locomotive.color,
scale = 1.80,
font = 'default-game',
alignment = 'center',
scale_with_zoom = false
}
)
WPT.set(
'circle',
rendering.draw_circle {
surface = surface,
target = locomotive,
color = locomotive.color,
filled = false,
radius = upgrades.locomotive_aura_radius,
only_in_alt_mode = true
}
)
end
function Public.transfer_pollution()
local locomotive = WPT.get('locomotive')
if not locomotive or not locomotive.valid then
return
end
local active_surface_index = WPT.get('active_surface_index')
local active_surface = game.surfaces[active_surface_index]
if not active_surface or not active_surface.valid then
return
end
local icw_locomotive = WPT.get('icw_locomotive')
local surface = icw_locomotive.surface
if not surface or not surface.valid then
return
end
local total_interior_pollution = surface.get_total_pollution()
local pollution = surface.get_total_pollution() * (3 / (4 / 3 + 1)) * Difficulty.get().value
active_surface.pollute(locomotive.position, pollution)
game.pollution_statistics.on_flow('locomotive', pollution - total_interior_pollution)
surface.clear_pollution()
end
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()
validate_index()
fish_tag()
hurt_players_outside_of_aura()
end
if ticker % 120 == 0 then
-- tp_player()
boost_players()
end
if ticker % 1200 == 0 then
set_player_spawn()
refill_fish()
end
if ticker % 2500 == 0 then
pollute_area()
end
end
Event.on_nth_tick(5, tick)
Event.add(defines.events.on_research_finished, on_research_finished)
Event.add(defines.events.on_player_changed_surface, on_player_changed_surface)
Event.add(defines.events.on_player_driving_changed_state, on_player_driving_changed_state)
Event.add(defines.events.on_train_created, set_carriages)
return Public