1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2025-01-10 00:43:27 +02:00
ComfyFactorio/maps/lumberjack/locomotive.lua
2020-05-13 08:18:14 +02:00

643 lines
17 KiB
Lua

local Event = require 'utils.event'
local Power = require 'maps.lumberjack.power'
local ICW = require 'maps.lumberjack.icw.main'
local WPT = require 'maps.lumberjack.table'
local RPG = require 'maps.lumberjack.rpg'
require 'maps.lumberjack.locomotive_market'
local Public = {}
local energy_upgrade = 50000000
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.players[player.index] then
return false
end
return true
end
local function rebuild_energy_overworld(data)
local this = data.this
local surface = data.surface
if this.ow_energy then
if this.ow_energy.valid then
local position = this.ow_energy.position
local area = {
left_top = {x = position.x - 2, y = position.y - 2},
right_bottom = {x = position.x + 2, y = position.y + 2}
}
if Public.contains_positions(this.locomotive.position, area) then
return
end
this.old_ow_energy = this.ow_energy.energy
this.ow_energy.destroy()
this.energy['lumberjack'] = nil
end
end
this.ow_energy =
surface.create_entity {
name = 'hidden-electric-energy-interface',
position = {
x = this.locomotive.position.x,
y = this.locomotive.position.y + 2
},
create_build_effect_smoke = false,
force = game.forces.enemy
}
this.ow_energy.destructible = false
this.ow_energy.minable = false
this.ow_energy.operable = false
this.ow_energy.power_production = 0
if this.energy_purchased then
this.ow_energy.electric_buffer_size = energy_upgrade
else
this.ow_energy.electric_buffer_size = 10000000
end
if this.old_ow_energy then
this.ow_energy.energy = this.old_ow_energy
end
end
local function rebuild_energy_loco(data, rebuild)
local this = data.this
local surface = data.surface
local pos = {x = -19, y = 3}
if rebuild then
local radius = 1024
local area = {{x = -radius, y = -radius}, {x = radius, y = radius}}
for _, entity in pairs(surface.find_entities_filtered {area = area, name = 'electric-energy-interface'}) do
entity.destroy()
end
this.energy.loco = nil
this.lo_energy = nil
end
this.lo_energy =
surface.create_entity {
name = 'electric-energy-interface',
position = pos,
create_build_effect_smoke = false,
force = game.forces.enemy
}
rendering.draw_text {
text = 'Power to overworld',
surface = surface,
target = this.lo_energy,
target_offset = {0, -1.5},
color = {r = 0, g = 1, b = 0},
alignment = 'center'
}
this.lo_energy.minable = false
this.lo_energy.destructible = false
this.lo_energy.operable = false
this.lo_energy.power_production = 0
if this.energy_purchased then
this.lo_energy.electric_buffer_size = energy_upgrade
else
this.lo_energy.electric_buffer_size = 10000000
end
end
local function property_boost(data)
local rng = math.random
local xp_floating_text_color = {r = rng(0, 250), g = 128, b = 0}
local visuals_delay = 1800
local this = data.this
local aura = this.locomotive_xp_aura
local rpg = data.rpg
local loco = this.locomotive.position
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
if Public.contains_positions(player.position, area) then
local pos = player.position
RPG.gain_xp(player, 0.4 * (rpg[player.index].bonus + this.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
end
end
end
local function train_rainbow()
local this = WPT.get_table()
if not this.locomotive then
return
end
if not this.locomotive.valid then
return
end
local color = {
a = math.sin((game.tick + 60) / 784) * 127 + 127,
r = math.sin((game.tick + 120) / 1700) * 127 + 127,
b = math.sin((game.tick + 600 + 440) / 1800) * 127 + 127,
g = math.sin((game.tick + 1200 + 770) / 1900) * 127 + 127
}
this.locomotive.color = color
rendering.set_text(this.health_text, 'HP: ' .. this.locomotive_health .. ' / ' .. this.locomotive_max_health)
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
}
end
local function fish_tag()
local this = WPT.get_table()
if not this.locomotive_cargo then
return
end
if not this.locomotive_cargo.valid then
return
end
if not this.locomotive_cargo.surface then
return
end
if not this.locomotive_cargo.surface.valid then
return
end
if this.locomotive_tag then
if this.locomotive_tag.valid then
if
this.locomotive_tag.position.x == this.locomotive_cargo.position.x and
this.locomotive_tag.position.y == this.locomotive_cargo.position.y
then
return
end
this.locomotive_tag.destroy()
end
end
this.locomotive_tag =
this.locomotive_cargo.force.add_chart_tag(
this.locomotive_cargo.surface,
{
icon = {type = 'item', name = 'raw-fish'},
position = this.locomotive_cargo.position,
text = ' '
}
)
end
local function set_player_spawn_and_refill_fish()
local this = WPT.get_table()
if not this.locomotive_cargo then
return
end
if not this.locomotive_cargo.valid then
return
end
this.locomotive_cargo.get_inventory(defines.inventory.cargo_wagon).insert(
{name = 'raw-fish', count = math.random(2, 5)}
)
local position =
this.locomotive_cargo.surface.find_non_colliding_position(
'stone-furnace',
this.locomotive_cargo.position,
16,
2
)
if not position then
return
end
game.forces.player.set_spawn_position({x = position.x, y = position.y}, this.locomotive_cargo.surface)
end
local direction_lookup = {
[-1] = {
[1] = defines.direction.southwest,
[0] = defines.direction.west,
[-1] = defines.direction.northwest
},
[0] = {
[1] = defines.direction.south,
[-1] = defines.direction.north
},
[1] = {
[1] = defines.direction.southeast,
[0] = defines.direction.east,
[-1] = defines.direction.northeast
}
}
local function rand_range(start, stop)
local this = WPT.get_table()
if not this.rng then
this.rng = game.create_random_generator()
end
return this.rng(start, stop)
end
local function get_axis(point, axis)
local function safe_get(t, k)
local res, value =
pcall(
function()
return t[k]
end
)
if res then
return value
end
return nil
end
if point.position then
return get_axis(point.position, axis)
end
if point[axis] then
return point[axis]
end
if safe_get(point, 'target') then
return get_axis(point.target, axis)
end
if #point ~= 2 then
log('get_axis: invalid point format')
return nil
end
if axis == 'x' then
return point[1]
end
return point[2]
end
local function get_direction(src, dest)
local src_x = get_axis(src, 'x')
local src_y = get_axis(src, 'y')
local dest_x = get_axis(dest, 'x')
local dest_y = get_axis(dest, 'y')
local step = {
x = nil,
y = nil
}
local precision = rand_range(1, 10)
if dest_x - precision > src_x then
step.x = 1
elseif dest_x < src_x - precision then
step.x = -1
else
step.x = 0
end
if dest_y - precision > src_y then
step.y = 1
elseif dest_y < src_y - precision then
step.y = -1
else
step.y = 0
end
return direction_lookup[step.x][step.y]
end
local function get_distance(a, b)
local h = (get_axis(a, 'x') - get_axis(b, 'x')) ^ 2
local v = (get_axis(a, 'y') - get_axis(b, 'y')) ^ 2
return math.sqrt(h + v)
end
local function move_to(ent, trgt, min_distance)
local state = {
walking = false
}
local distance = get_distance(trgt.position, ent.position)
if min_distance < distance then
local dir = get_direction(ent.position, trgt.position)
if dir then
state = {
walking = true,
direction = dir
}
end
end
ent.walking_state = state
return state.walking
end
local function tick()
local this = WPT.get_table()
if this.energy_shared then
Public.power_source_overworld()
Public.power_source_locomotive()
end
if game.tick % 120 == 0 then
Public.boost_players_around_train()
end
if game.tick % 80 == 0 then
train_rainbow()
end
if game.tick % 30 == 0 then
if game.tick % 1800 == 0 then
set_player_spawn_and_refill_fish()
end
--Public.spawn_player()
fish_tag()
end
end
function Public.boost_players_around_train()
local rpg = RPG.get_table()
local this = WPT.get_table()
local surface = game.surfaces[this.active_surface_index]
if not this.locomotive then
return
end
if not this.locomotive.valid then
return
end
local data = {
this = this,
surface = surface,
rpg = rpg
}
property_boost(data)
end
function Public.render_train_hp()
local this = WPT.get_table()
local surface = game.surfaces[this.active_surface_index]
this.health_text =
rendering.draw_text {
text = 'HP: ' .. this.locomotive_health .. ' / ' .. this.locomotive_max_health,
surface = surface,
target = this.locomotive,
target_offset = {0, -2.5},
color = this.locomotive.color,
scale = 1.40,
font = 'default-game',
alignment = 'center',
scale_with_zoom = false
}
this.caption =
rendering.draw_text {
text = 'Grandmasters Train',
surface = surface,
target = this.locomotive,
target_offset = {0, -4.25},
color = this.locomotive.color,
scale = 1.80,
font = 'default-game',
alignment = 'center',
scale_with_zoom = false
}
this.circle =
rendering.draw_circle {
surface = surface,
target = this.locomotive,
color = this.locomotive.color,
filled = false,
radius = this.locomotive_xp_aura,
only_in_alt_mode = true
}
end
function Public.spawn_player()
local rnd = math.random
local this = WPT.get_table()
local surface = game.surfaces[this.active_surface_index]
local position = this.locomotive.position
if not this.locomotive then
return
end
if not this.locomotive.valid then
return
end
if not this.lumberjack_one or not this.lumberjack_one.valid then
this.lumberjack_one =
surface.create_entity(
{
name = 'character',
position = {position.x + 5, position.y},
force = 'player',
direction = 0
}
)
this.lumberjack_one_caption =
rendering.draw_text {
text = 'Lumberjack',
surface = surface,
target = this.lumberjack_one,
target_offset = {0, -2.25},
color = {r = 0, g = 110, b = 33},
scale = 0.75,
font = 'default-game',
alignment = 'center',
scale_with_zoom = false
}
end
if not this.lumberjack_two or not this.lumberjack_two.valid then
this.lumberjack_two =
surface.create_entity(
{
name = 'character',
position = {position.x + -5, position.y},
force = 'player',
direction = 0
}
)
this.lumberjack_two_caption =
rendering.draw_text {
text = 'Lumberjack',
surface = surface,
target = this.lumberjack_two,
target_offset = {0, -2.25},
color = {r = 0, g = 110, b = 33},
scale = 0.75,
font = 'default-game',
alignment = 'center',
scale_with_zoom = false
}
end
for _, p in pairs(game.connected_players) do
if this.lumberjack_one and this.lumberjack_one.valid then
if rnd(1, 32) == 1 then
this.lumberjack_one.destroy()
return
end
move_to(this.lumberjack_one, p, rnd(15, 50))
end
if this.lumberjack_two and this.lumberjack_two.valid then
if rnd(1, 32) == 1 then
this.lumberjack_two.destroy()
return
end
move_to(this.lumberjack_two, p, rnd(15, 50))
end
end
end
function Public.locomotive_spawn(surface, position)
local this = WPT.get_table()
for y = -6, 6, 2 do
surface.create_entity(
{name = 'straight-rail', position = {position.x, position.y + y}, force = 'player', direction = 0}
)
end
this.locomotive =
surface.create_entity({name = 'locomotive', position = {position.x, position.y + -3}, force = 'player'})
this.locomotive.get_inventory(defines.inventory.fuel).insert({name = 'wood', count = 100})
this.locomotive_cargo =
surface.create_entity({name = 'cargo-wagon', position = {position.x, position.y + 3}, force = 'player'})
this.locomotive_cargo.get_inventory(defines.inventory.cargo_wagon).insert({name = 'raw-fish', count = 8})
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
}
)
for y = -1, 0, 0.05 do
local scale = math.random(50, 100) * 0.01
rendering.draw_sprite(
{
sprite = 'item/raw-fish',
orientation = math.random(0, 100) * 0.01,
x_scale = scale,
y_scale = scale,
tint = {math.random(60, 255), math.random(60, 255), math.random(60, 255)},
render_layer = 'selection-box',
target = this.locomotive_cargo,
target_offset = {-0.7 + math.random(0, 140) * 0.01, y},
surface = surface
}
)
end
this.locomotive.color = {0, 255, 0}
this.locomotive.minable = false
this.locomotive_cargo.minable = false
this.locomotive_cargo.operable = true
local locomotive = ICW.register_wagon(this.locomotive)
local wagon = ICW.register_wagon(this.locomotive_cargo)
locomotive.entity_count = 999
wagon.entity_count = 999
end
function Public.inside(pos, area)
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
function Public.contains_positions(pos, area)
if Public.inside(pos, area) then
return true
end
return false
end
function Public.power_source_overworld()
local this = WPT.get_table()
local surface = game.surfaces[this.active_surface_index]
if not this.locomotive then
return
end
if not this.locomotive.valid then
return
end
local data = {
this = this,
surface = surface
}
rebuild_energy_overworld(data)
end
function Public.power_source_locomotive()
local this = WPT.get_table()
local icw_table = ICW.get_table()
if not this.locomotive then
return
end
if not this.locomotive.valid then
return
end
local unit_surface = this.locomotive.unit_number
local surface = game.surfaces[icw_table.wagons[unit_surface].surface.index]
local data = {
this = this,
icw_table = icw_table,
surface = surface
}
if not this.lo_energy then
rebuild_energy_loco(data)
elseif not this.lo_energy.valid then
rebuild_energy_loco(data, true)
end
end
Event.on_nth_tick(5, tick)
return Public