364 lines
14 KiB
Lua
364 lines
14 KiB
Lua
--[[
|
|
vehicles.lua
|
|
Adds honking for trains and vehicles
|
|
Adds vehicle snapping for cars and tanks
|
|
Adds goto selected station hotkey when inside a train
|
|
Adds toggle train mode hotkey
|
|
Adds automatic train mode toggling
|
|
|
|
"name": "DelticHonk",
|
|
"title": "Deltic Honk",
|
|
"author": "Michael Cowgill (ChurchOrganist)",
|
|
"contact": "jmcowgill@gmail.com",
|
|
"description": "blatant hack of Gotlag's original Honk mod which changes the sounds to Deltic horns.
|
|
Trains honk when stopping. And starting. And on command."
|
|
|
|
"name": "Horns",
|
|
"title": "Horns",
|
|
"author": "TaxiService",
|
|
"homepage": "https://forums.factorio.com/viewtopic.php?f=190&t=59417",
|
|
"description": "Adds horns to cars and tanks. Honking can attract enemies in a tweakable radius.",
|
|
|
|
"name": "Better-TrainHorn",
|
|
"title": "Better Train Horn",
|
|
"author": "Luc Mellee",
|
|
"contact": "melleeluc@gmail.com",
|
|
"description": "This mod is a updated version of Benjamin Lee's TrainHorn mod
|
|
Original Description: \n Trains will now blare their horn after killing a player (sound by CrazyWashingtonianTrainNut on freesound)"
|
|
|
|
"name": "VehicleSnap",
|
|
"author": "Zaflis",
|
|
"homepage": "https://forums.factorio.com/viewtopic.php?f=92&t=25501",
|
|
"description": "Snaps movement angle when driving cars or tanks.",
|
|
--]]
|
|
local Event = require('__stdlib__/stdlib/event/event')
|
|
local Player = require('__stdlib__/stdlib/event/player')
|
|
local interface = require('__stdlib__/stdlib/scripts/interface')
|
|
|
|
local function attract_enemies(entity, range)
|
|
if settings.global['picker-train-honk-attract'].value then
|
|
for _, enemy in pairs(entity.surface.find_enemy_units(entity.position, range)) do
|
|
enemy.set_command({type = defines.command.attack, target = entity, distraction = defines.distraction.by_damage})
|
|
end
|
|
end
|
|
end
|
|
|
|
local HONK_COOLDOWN = 120
|
|
|
|
local honk_states = {
|
|
[defines.train_state.on_the_path] = true,
|
|
[defines.train_state.arrive_station] = true,
|
|
[defines.train_state.arrive_signal] = true
|
|
}
|
|
|
|
local ts = {
|
|
wait_station = defines.train_state.wait_station,
|
|
no_path = defines.train_state.no_path,
|
|
no_schedule = defines.train_state.no_schedule,
|
|
manual = defines.train_state.manual_control
|
|
}
|
|
|
|
local available_ts = {
|
|
[defines.train_state.no_schedule] = true,
|
|
[defines.train_state.no_path] = true
|
|
}
|
|
|
|
local consist = {
|
|
['locomotive'] = true,
|
|
['cargo-wagon'] = true,
|
|
['fluid-wagon'] = true,
|
|
['artillery-wagon'] = true
|
|
}
|
|
|
|
-- Is the train available for automatic to manual control.
|
|
local function available_train(train)
|
|
return available_ts[train.state] or (train.state == ts.wait_station and #train.schedule.records == 1)
|
|
end
|
|
|
|
-- When entering a train if it is in automatic and waiting at a station, or has no schedule or path
|
|
-- then set to manual mode.
|
|
local function on_player_driving_changed_state(event)
|
|
local player = game.players[event.player_index]
|
|
if player.vehicle and player.vehicle.train and player.mod_settings['picker-auto-manual-train'].value then
|
|
local train = player.vehicle.train
|
|
--Set train to manual
|
|
if #train.passengers == 1 and available_train(train) then
|
|
player.vehicle.train.manual_mode = true
|
|
player.create_local_flying_text {
|
|
text = {'vehicles.manual-mode'},
|
|
position = player.vehicle.position,
|
|
color = defines.color.green
|
|
}
|
|
end
|
|
end
|
|
end
|
|
Event.register(defines.events.on_player_driving_changed_state, on_player_driving_changed_state)
|
|
|
|
-- Force the train to go to the next station. Check selected trains first
|
|
local function goto_next_station(event)
|
|
local player = game.get_player(event.player_index)
|
|
local vehicle = player.vehicle
|
|
local selected = player.selected
|
|
local train = selected and selected.train or vehicle and player.vehicle.train
|
|
|
|
if train and not (selected and selected.type == 'train-stop') then
|
|
local schedule = train.schedule
|
|
local stops = #schedule.records
|
|
if stops > 0 then
|
|
if schedule.current < stops then
|
|
schedule.current = schedule.current + 1
|
|
else
|
|
schedule.current = 1
|
|
end
|
|
local station_name = schedule.records[schedule.current].station
|
|
train.schedule = schedule
|
|
train.manual_mode = false
|
|
player.create_local_flying_text {
|
|
text = {'vehicles.next-station', station_name},
|
|
position = vehicle and vehicle.position or selected and selected.position,
|
|
color = defines.color.green
|
|
}
|
|
end
|
|
end
|
|
end
|
|
Event.register('picker-goto-next-station', goto_next_station)
|
|
|
|
-- Hotkey for toggling a train between automatic and manual.
|
|
local function toggle_train_control(event)
|
|
local player = game.get_player(event.player_index)
|
|
local vehicle = player.vehicle
|
|
local selected = player.selected
|
|
local train = selected and selected.train or vehicle and player.vehicle.train
|
|
|
|
if train and not (selected and selected.type == 'train-stop') then
|
|
train.manual_mode = not train.manual_mode
|
|
local text = train.manual_mode and {'vehicles.manual-mode'} or {'vehicles.automatic-mode'}
|
|
player.create_local_flying_text {
|
|
text = text,
|
|
position = vehicle and vehicle.position or selected and selected.position,
|
|
color = defines.color.green
|
|
}
|
|
end
|
|
end
|
|
Event.register('picker-toggle-train-control', toggle_train_control)
|
|
|
|
-- Hotkey while selecting a station will tell the train to go to that station if
|
|
-- the train has 1 or fewer stations.
|
|
local function goto_station(event)
|
|
local player = game.players[event.player_index]
|
|
local selected = player.selected
|
|
if selected and selected.type == 'train-stop' then
|
|
local vehicle = player.vehicle
|
|
local train = vehicle and vehicle.train
|
|
if train and (train.schedule and #train.schedule.records or 0) <= 1 then
|
|
train.schedule = {
|
|
current = 1,
|
|
records = {
|
|
[1] = {time_to_wait = 999, station = selected.backer_name}
|
|
}
|
|
}
|
|
train.manual_mode = false
|
|
end
|
|
end
|
|
end
|
|
Event.register('picker-goto-station', goto_station)
|
|
|
|
-- Create a custom alert to help find the last car you were in.
|
|
local function remove_beam(pdata)
|
|
if pdata.car_finder_beam and pdata.car_finder_beam.valid then
|
|
pdata.car_finder_beam.destroy()
|
|
end
|
|
pdata.car_finder_beam = nil
|
|
end
|
|
|
|
local function wheres_my_car(event)
|
|
local player, pdata = Player.get(event.player_index)
|
|
local vehicle, selected = player.vehicle, player.selected
|
|
if not event.input and vehicle and vehicle.type == 'car' then
|
|
pdata.last_car = vehicle
|
|
remove_beam(pdata)
|
|
elseif selected and selected.type == 'car' then
|
|
pdata.last_car = selected
|
|
elseif event.input_name and pdata.last_car and pdata.last_car.valid and player.surface == pdata.last_car.surface then
|
|
if not (pdata.car_finder_beam and pdata.car_finder_beam.valid) then
|
|
player.add_custom_alert(pdata.last_car, {type = 'item', name = pdata.last_car.name}, {'vehicles.dude-wheres-my-car'}, true)
|
|
pdata.car_finder_beam =
|
|
player.surface.create_entity(
|
|
{
|
|
name = 'picker-pointer-beam',
|
|
position = player.position, -- Can be any position, not used for beams, just can't be nil
|
|
source = player.character,
|
|
source_offset = {0, -1},
|
|
target = pdata.last_car,
|
|
duration = 2000000000
|
|
}
|
|
)
|
|
elseif pdata.car_finder_beam then
|
|
remove_beam(pdata)
|
|
end
|
|
end
|
|
end
|
|
Event.register({'picker-dude-wheres-my-car', defines.events.on_player_driving_changed_state}, wheres_my_car)
|
|
--[[
|
|
-- Trains honk when in automatic mode when starting or stopping.
|
|
local function attempt_honk(event)
|
|
if honk_states[event.train.state] and settings.global['picker-train-honk'].value then
|
|
local honk = settings.global['picker-train-honk-type'].value .. (event.name == defines.train_state.on_the_path and '-start' or '-stop')
|
|
local entity
|
|
global.recently_honked = global.recently_honked or {}
|
|
if (global.recently_honked[event.train.id] or event.tick) <= event.tick then
|
|
if event.train.speed >= 0 and #event.train.locomotives.front_movers > 0 then
|
|
entity = event.train.locomotives.front_movers[1]
|
|
elseif event.train.speed <= 0 and #event.train.locomotives.back_movers > 0 then
|
|
entity = event.train.locomotives.back_movers[#event.train.locomotives.back_movers]
|
|
end
|
|
global.recently_honked[event.train.id] = event.tick + HONK_COOLDOWN
|
|
if entity then
|
|
entity.surface.play_sound {
|
|
path = honk,
|
|
position = entity.position,
|
|
volume = 1
|
|
}
|
|
attract_enemies(entity, 75)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Event.register(defines.events.on_train_changed_state, attempt_honk)
|
|
]]
|
|
-- Hotkey for manually honking a vehicle train.
|
|
local function manual_honk(event)
|
|
local player = game.players[event.player_index]
|
|
local vehicle = player.vehicle
|
|
if vehicle then
|
|
if vehicle.type == 'locomotive' then
|
|
local sound = settings.global['picker-train-honk-type'].value
|
|
if vehicle.train.manual_mode then
|
|
local train = vehicle.train
|
|
if train.speed == 0 then
|
|
vehicle.surface.play_sound {
|
|
path = sound .. '-start',
|
|
position = vehicle.position,
|
|
volume = 1
|
|
}
|
|
else
|
|
vehicle.surface.play_sound {
|
|
path = sound .. '-stop',
|
|
position = vehicle.position,
|
|
volume = 1
|
|
}
|
|
end
|
|
attract_enemies(vehicle, 75)
|
|
end
|
|
else
|
|
if vehicle.name:find('tank') then
|
|
vehicle.surface.play_sound {
|
|
path = 'train-stop',
|
|
position = vehicle.position,
|
|
volume = 1
|
|
}
|
|
else
|
|
vehicle.surface.play_sound {
|
|
path = 'car-horn',
|
|
position = vehicle.position,
|
|
volume = 1
|
|
}
|
|
end
|
|
attract_enemies(vehicle, 50)
|
|
end
|
|
end
|
|
end
|
|
Event.register('picker-honk', manual_honk)
|
|
|
|
local function casey_jones(event)
|
|
local cause = event.cause
|
|
if cause and consist[cause.type] then
|
|
cause.surface.play_sound {
|
|
path = 'horn-long',
|
|
position = cause.position,
|
|
volume = 1
|
|
}
|
|
attract_enemies(cause, 50)
|
|
-- Get out of the way
|
|
local character = game.get_player(event.player_index).character
|
|
local p_force, c_force = character.force, cause.force
|
|
if (character.force == cause.force or c_force.get_friend(p_force)) and settings.global['picker-get-out-of-the-way'].value then
|
|
local pos = cause.surface.find_non_colliding_position('character', event.cause.position, 5, 0.5)
|
|
if pos then
|
|
character.teleport(pos)
|
|
if character.health == 0 then
|
|
character.health = 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Event.register(defines.events.on_pre_player_died, casey_jones)
|
|
|
|
-- snap amount is the amount of different angles car can drive on,
|
|
-- (360 / vehiclesnap_amount) is the difference between 2 axis
|
|
-- car will slowly turn towards such angle axis
|
|
local SNAP_AMOUNT = 16
|
|
|
|
Player.additional_data {snap = true}
|
|
|
|
local function snap_vehicle(event)
|
|
if not global.disable_snapping then
|
|
local player, pdata = Player.get(event.player_index)
|
|
if pdata.snap then
|
|
local vehicle = player.vehicle
|
|
if player and vehicle and vehicle.type == 'car' and vehicle.speed > 0.1 then
|
|
local o = vehicle.orientation
|
|
local last_o = pdata._last_orientation
|
|
if last_o and math.abs(o - last_o) < 0.001 then
|
|
local snap_o = math.floor(o * SNAP_AMOUNT + 0.5) / SNAP_AMOUNT
|
|
-- Interpolate with 80% current and 20% target orientation
|
|
o = (o * 4.0 + snap_o) * 0.2
|
|
vehicle.orientation = o
|
|
end
|
|
pdata._last_orientation = o
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Event.register(defines.events.on_player_changed_position, snap_vehicle)
|
|
|
|
local function toggle_snap(command)
|
|
local player, pdata = Player.get(command.player_index)
|
|
pdata.snap = not pdata.snap
|
|
player.print({'vehicles.snapping', tostring(pdata.snap)})
|
|
end
|
|
commands.add_command('snap', 'snapdriving', toggle_snap)
|
|
|
|
function interface.disable_snapping(bool)
|
|
global.disable_snapping = bool or false
|
|
end
|
|
|
|
--[[
|
|
"name": "auto_manual_mode",
|
|
"title": "Auto Manual Mode",
|
|
"author": "Roy Scheerens",
|
|
"description": "When in a train, using the movement controls will automatically set the train in manual mode.",
|
|
--]]
|
|
local function set_to_manual(event)
|
|
local player = game.get_player(event.player_index)
|
|
local vehicle = player.vehicle
|
|
|
|
if vehicle then
|
|
local train = vehicle.train
|
|
if train and not train.manual_mode and player.render_mode == defines.render_mode.game then
|
|
if not player.mod_settings['picker-manual-train-keys'].value then
|
|
return
|
|
end
|
|
train.manual_mode = true
|
|
player.create_local_flying_text {
|
|
text = {'vehicles.manual-mode'},
|
|
position = vehicle.position,
|
|
color = defines.color.green
|
|
}
|
|
end
|
|
end
|
|
end
|
|
local keys = {'picker-up-event', 'picker-down-event', 'picker-left-event', 'picker-right-event'}
|
|
Event.register(keys, set_to_manual)
|