Started working on vents for traitors.

master
Nathan Salapat 2022-05-16 21:00:07 -05:00
parent 4e0861ddce
commit ef26034269
186 changed files with 4849 additions and 0 deletions

1
mods/tubelib2 Submodule

@ -0,0 +1 @@
Subproject commit b6fbd71be1ceaa590b3ac4f84219aaeeb5c464c6

13
mods/vents/LICENSE.txt Normal file
View File

@ -0,0 +1,13 @@
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

91
mods/vents/README.md Normal file
View File

@ -0,0 +1,91 @@
# Hyperloop v2
**A new evolution in the voxel word:**
## Minetest goes Hyperloop!
Hyperloop is passenger transportation system for travelling through evacuated tubes my means of passenger pods.
It is the fast and modern way of travelling.
* Hyperloop allows travelling from point to point in seconds (900 km/h) :-)
* The tubes system with all stations and pods have to be build by players
* It can be used even on small servers without lagging
* No configuration or programming of the tube network is necessary (only the station names have to be entered)
**[See Wiki Page for more info](https://github.com/joe7575/Minetest-Hyperloop/wiki)**
![screenshot](https://github.com/joe7575/Minetest-Hyperloop/blob/master/screenshot.png)
The mod includes many different kind of blocks:
- Hyperloop Stations Block to automatically build the pod/car
- Hyperloop Booking Machine for the station to select the destination
- Hyperloop Tube to connect two stations
- Hyperloop Junction Block to connect up to 6 tubes for complex network structures
- Hyperloop Stations Signs
- Hyperloop Promo Poster for station advertisement
- Hyperloop Elevator to reach other levels
- Hyperloop Elevator Shaft to connect two elevator cars
- Hyperloop Station Book with all available stations (for builders/engineers)
- Hyperloop Tube Crowbar to crack/repair tube lines (for admins)
- Hyperloop WiFi Tubes for very large distances (optional)
- chat command to repair WorldEdit placed tubes
..and more.
Browse on: [GitHub](https://github.com/joe7575/Minetest-Hyperloop)
Download: [GitHub](https://github.com/joe7575/Minetest-Hyperloop/archive/master.zip)
## Migration from v1 to v2
The logic behind the tubes/shafts has changed. Hyperloop now uses tubelib2 as tube library.
That means, available worlds have to be migrated for the new tubes. This is done automatically but
has some risks. Therefore:
**I recommend to backup your world or test the migration from v1 to v2 on a copy of your world!!!**
## What is new in v2
- some textures changed
- the Elevator Shafts can now be used as ladder/climbing shafts
- the Crowbar is public available, but cracking a tube line need 'hyperloop' privs
- the Station Book is improved and simplified to find stations, junctions, and open tube ends
- a Waypoint plate is added to mark and easier find the tube destination
- Elevator shafts can be build in all directions (optional)
- WiFi Tubes can be crafted and placed by players (optional)
- intllib support added (German translation available)
## Introduction
**[See Wiki Page for more info](https://github.com/joe7575/Minetest-Hyperloop/wiki)**
## Configuration
The following can be changed in the minetest menu (Settings -> Advanced Settings -> Mods -> hyperloop) or directly in 'minetest.conf'
* "WiFi block enabled" - To enable the usage of WiFi blocks (default: false)
* "WiFi block crafting enabled" - To enable the crafting of WiFi blocks (default: false)
* "free tube placement enabled" - If enabled Hyperloop Tubes and Elevator Shafts can be build in all directions (default: true)
When this option is disabled, Hyperloop tubes can only be built in the horizontal direction and elevator shafts in the vertical direction.
* "enable building of subnets" - If enabled the ticket block has an additional field for specifying a subnet name. Stations with the same subnet name (optional) represent an isolated subnet within the Hyperloop network.
Example for 'minetest.conf':
```LUA
hyperloop_wifi_enabled = true -- WiFi block enabled
hyperloop_wifi_crafting_enabled = false -- WiFi block crafting enabled
hyperloop_free_tube_placement_enabled = true -- free tube placement enabled
hyperloop_subnet_enabled = true -- enable building of subnets
```
## Dependencies
tubelib2 ([GitHub](https://github.com/joe7575/tubelib2))
default
intllib
optional: worldedit, techage
# License
Copyright (C) 2017,2021 Joachim Stolberg
Code: Licensed under the GNU LGPL version 2.1 or later. See LICENSE.txt and http://www.gnu.org/licenses/lgpl-2.1.txt
Textures: CC0
Display: Derived from the work of kaeza, sofar and others (digilines) LGPLv2.1+

84
mods/vents/booking.lua Normal file
View File

@ -0,0 +1,84 @@
--[[
Hyperloop Mod
=============
Copyright (C) 2017-2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
Station reservation/blocking and trip booking
]]--
-- for lazy programmers
local SP = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
local S = vents.S
local NS = vents.NS
local tBlockingTime = {}
local tBookings = {} -- open bookings: tBookings[SP(departure_pos)] = arrival_pos
local Stations = vents.Stations
-- Reserve departure and arrival stations for some time
function vents.reserve(departure_pos, arrival_pos, player)
if Stations:get(departure_pos) == nil then
vents.chat(player, S("Station data is corrupted. Please rebuild the station!"))
return false
elseif Stations:get(arrival_pos) == nil then
vents.chat(player, S("Station data is corrupted. Please rebuild the station!"))
return false
end
if (tBlockingTime[SP(departure_pos)] or 0) > minetest.get_gametime() then
vents.chat(player, S("Station is still blocked. Please try again in a few seconds!"))
return false
elseif (tBlockingTime[SP(arrival_pos)] or 0) > minetest.get_gametime() then
vents.chat(player, S("Station is still blocked. Please try again in a few seconds!"))
return false
end
-- place a reservation for 20 seconds to start the trip
tBlockingTime[SP(departure_pos)] = minetest.get_gametime() + 20
tBlockingTime[SP(arrival_pos)] = minetest.get_gametime() + 20
return true
end
-- block the already reserved stations
function vents.block(departure_pos, arrival_pos, seconds)
if Stations:get(departure_pos) == nil then
return false
elseif Stations:get(arrival_pos) == nil then
return false
end
tBlockingTime[SP(departure_pos)] = minetest.get_gametime() + seconds
tBlockingTime[SP(arrival_pos)] = minetest.get_gametime() + seconds
return true
end
-- check if station is blocked
function vents.is_blocked(pos)
if not pos then return false end
if Stations:get(pos) == nil then
return false
end
return (tBlockingTime[SP(pos)] or 0) > minetest.get_gametime()
end
function vents.set_arrival(departure_pos, arrival_pos)
tBookings[SP(departure_pos)] = arrival_pos
end
function vents.get_arrival(departure_pos)
-- Return and delete the arrival pos
local arrival_pos = tBookings[SP(departure_pos)]
tBookings[SP(departure_pos)] = nil
return arrival_pos
end

301
mods/vents/booking_node.lua Normal file
View File

@ -0,0 +1,301 @@
--[[
Hyperloop Mod
=============
Copyright (C) 2017-2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
Booking/ticket machine
]]--
-- for lazy programmers
local SP = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local S = vents.S
local NS = vents.NS
-- Used to store the Station list for each booking machine:
-- tStationList[SP(pos)] = {pos1, pos2, ...}
local tStationList = {}
local Stations = vents.Stations
-- Form spec for the station list
local function generate_string(sortedList)
local tRes = {"size[12,8]"..
-- default.gui_bg..
-- default.gui_bg_img..
-- default.gui_slots..
"item_image[0,0;1,1;vents:booking]"..
"label[4,0; "..S("Select your destination").."]"}
tRes[2] = "tablecolumns[text,width=20;text,width=6,align=right;text]"
local stations = {}
for idx,tDest in ipairs(sortedList) do
local name = tDest.name or S("<unknown>")
local distance = tDest.distance or 0
local info = tDest.booking_info or ""
stations[#stations+1] = minetest.formspec_escape(string.sub(name, 1, 28))
stations[#stations+1] = distance.."m"
stations[#stations+1] = minetest.formspec_escape(info)
end
if #stations>0 then
tRes[#tRes+1] = "table[0,1;11.8,7.2;button;"..table.concat(stations, ",").."]"
else
tRes[#tRes+1] = "button_exit[4,4;3,1;button;Update]"
end
return table.concat(tRes)
end
local function store_station_list(pos, sortedList)
local tbl = {}
for idx,item in ipairs(sortedList) do
tbl[#tbl+1] = item.pos
end
tStationList[SP(pos)] = tbl
end
local function remove_junctions(sortedList)
local tbl = {}
for idx,item in ipairs(sortedList) do
if not item.junction and item.booking_pos then
tbl[#tbl+1] = item
end
end
return tbl
end
local function filter_subnet(sortedList, subnet)
if vents.subnet_enabled then
if subnet == "" then
subnet = nil
end
local tbl = {}
for idx,item in ipairs(sortedList) do
if item.subnet == subnet then
tbl[#tbl+1] = item
end
end
return tbl
end
return sortedList
end
-- Used to update the station list for booking machine
-- and teleport list.
local function station_list_as_string(pos, subnet)
local meta = M(pos)
-- Generate a name sorted list of all connected stations
local sortedList = Stations:station_list(pos, pos, "name")
-- remove all junctions from the list
sortedList = remove_junctions(sortedList)
-- use subnet pattern to reduce the list
sortedList = filter_subnet(sortedList, subnet)
-- store the list for later use
store_station_list(pos, sortedList)
-- Generate the formspec string
return generate_string(sortedList)
end
local naming_formspec = function(pos)
local meta = M(pos)
local formspec = "size[7,4.4]"..
"label[0,0;"..S("Please enter the station name to\nwhich this booking machine belongs.").."]" ..
"field[0.2,1.5;7.1,1;name;"..S("Station name")..";MyTown]" ..
"field[0.2,2.7;7.1,1;info;"..S("Additional station information")..";]" ..
"button_exit[2.5,3.7;2,1;exit;Save]"
meta:set_string("formspec", formspec)
meta:set_int("change_counter", 0)
end
local function booking_machine_update(pos)
local meta = M(pos)
local sStationPos = meta:get_string("sStationPos")
if sStationPos ~= "" then
local station_pos = P(sStationPos)
local counter = meta:get_int("change_counter") or 0
local changed, newcounter = Stations:changed(counter)
if changed or not tStationList[sStationPos] then
local subnet = meta:get_string("subnet")
meta:set_string("formspec", station_list_as_string(station_pos, subnet))
meta:set_int("change_counter", newcounter)
end
end
end
local function on_rightclick(pos)
booking_machine_update(pos)
end
local function on_receive_fields(pos, formname, fields, player)
-- station name entered?
if fields.name ~= nil then
local station_name = string.trim(fields.name)
if station_name == "" then
return
end
local stationPos = Stations:get_next_station(pos)
if stationPos then
if Stations:get(stationPos).booking_pos then
vents.chat(player, S("Station has already a booking machine!"))
return
end
-- add subnet name if available
local subnet = string.trim(fields.subnet or "")
if subnet == "" then
subnet = nil
end
-- store meta and generate station formspec
Stations:update(stationPos, {
name = station_name,
booking_pos = pos,
booking_info = string.trim(fields.info),
subnet = subnet,
})
local meta = M(pos)
meta:set_string("sStationPos", SP(stationPos))
meta:set_string("infotext", "Station: "..station_name)
meta:set_string("subnet", string.trim(fields.subnet or ""))
meta:set_int("change_counter", 0) -- force update
booking_machine_update(pos)
else
vents.chat(player, S("Invalid station name!"))
end
elseif fields.button ~= nil then -- destination selected?
local te = minetest.explode_table_event(fields.button)
local idx = tonumber(te.row)
if idx and te.type=="CHG" then
local tStation, src_pos = vents.get_base_station(pos)
local dest_pos = tStationList[SP(src_pos)] and tStationList[SP(src_pos)][idx]
if dest_pos and tStation then
-- place booking if not already blocked
if vents.reserve(src_pos, dest_pos, player) then
vents.set_arrival(src_pos, dest_pos)
-- open the pod door
--vents.open_pod_door(tStation)
end
else
-- data is corrupt, try an update
M(pos):set_int("change_counter", 0)
end
minetest.close_formspec(player:get_player_name(), formname)
end
end
end
local function on_destruct(pos)
local sStationPos = M(pos):get_string("sStationPos")
if sStationPos ~= "" then
Stations:update(P(sStationPos), {
booking_pos = "nil",
booking_info = "nil",
name = "Station",
})
end
end
-- wap from wall to ground
local function swap_node(pos, placer)
pos.y = pos.y - 1
if minetest.get_node_or_nil(pos).name ~= "air" then
local node = minetest.get_node(pos)
node.name = "vents:booking_ground"
node.param2 = vents.get_facedir(placer)
pos.y = pos.y + 1
minetest.swap_node(pos, node)
else
pos.y = pos.y + 1
end
end
-- wall mounted booking machine
minetest.register_node("vents:booking", {
description = S("Hyperloop Booking Machine"),
tiles = {
-- up, down, right, left, back, front
"hyperloop_booking.png",
"hyperloop_booking.png",
"hyperloop_booking.png",
"hyperloop_booking.png",
"hyperloop_booking.png",
"hyperloop_booking_front.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -8/16, -8/16, 2/16, 8/16, 8/16, 8/16},
},
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
naming_formspec(pos)
swap_node(pos, placer)
end,
on_rotate = screwdriver.disallow,
on_receive_fields = on_receive_fields,
on_destruct = on_destruct,
on_rightclick = on_rightclick,
paramtype = 'light',
light_source = 2,
paramtype2 = "facedir",
groups = {breakable=1},
is_ground_content = false,
})
-- ground mounted booking machine
minetest.register_node("vents:booking_ground", {
description = S("Hyperloop Booking Machine"),
tiles = {
-- up, down, right, left, back, front
"hyperloop_booking.png",
"hyperloop_booking.png",
"hyperloop_booking.png",
"hyperloop_booking.png",
"hyperloop_booking.png",
"hyperloop_booking_front.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -8/16, -8/16, -3/16, 8/16, 8/16, 3/16},
},
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
naming_formspec(pos)
end,
on_receive_fields = on_receive_fields,
on_destruct = on_destruct,
on_rightclick = on_rightclick,
on_rotate = screwdriver.disallow,
drop = "vents:booking",
light_source = 2,
paramtype = 'light',
paramtype2 = "facedir",
groups = {breakable=1, not_in_creative_inventory=1},
is_ground_content = false,
})

60
mods/vents/data_base.lua Normal file
View File

@ -0,0 +1,60 @@
--[[
Hyperloop Mod
=============
Copyright (C) 2017-2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
mod storage and data integrity
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
vents.Stations = vents.Network:new()
vents.Elevators = vents.Network:new()
-- Check all nodes on the map and delete useless data base entries
local function check_data_base()
-- used for VM get_node
local tube = tubelib2.Tube:new({})
vents.Stations:filter(function(pos)
local _,node = tube:get_node(pos)
return node.name == "vents:station" or node.name == "vents:junction"
end)
vents.Elevators:filter(function(pos)
local _,node = tube:get_node(pos)
return node.name == "vents:elevator_bottom"
end)
end
local storage = minetest.get_mod_storage()
vents.Stations:deserialize(storage:get_string("Stations"))
vents.Elevators:deserialize(storage:get_string("Elevators"))
local function update_mod_storage()
minetest.log("action", "[Hyperloop] Store data...")
storage:set_string("Stations", vents.Stations:serialize())
storage:set_string("Elevators", vents.Elevators:serialize())
-- store data each hour
minetest.after(60*60, update_mod_storage)
minetest.log("action", "[Hyperloop] Data stored")
end
minetest.register_on_shutdown(function()
update_mod_storage()
end)
-- delete data base entries without corresponding nodes
--minetest.after(5, check_data_base)
-- store data after one hour
minetest.after(60*60, update_mod_storage)

669
mods/vents/elevator.lua Normal file
View File

@ -0,0 +1,669 @@
--[[
Hyperloop Mod
=============
Copyright (C) 2017-2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
]]--
-- for lazy programmers
local SP = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local S = vents.S
local NS = vents.NS
-- To store elevator floors and formspecs
local Cache = {}
local PlayerNameTags = {}
local kPLAYER_OVER_GROUND = 0.5
-------------------------------------------------------------------------------
-- Elevator Shaft
-------------------------------------------------------------------------------
-- Down, Up
local dirs_to_check = {5,6} -- vertical only
if vents.free_tube_placement_enabled then
dirs_to_check = {1,2,3,4,5,6} -- all directions
end
local Shaft = tubelib2.Tube:new({
dirs_to_check = dirs_to_check,
max_tube_length = 1000,
show_infotext = true,
primary_node_names = {"vents:shaft", "vents:shaft2", "vents:shaftA", "vents:shaftA2"},
secondary_node_names = {"vents:elevator_bottom", "vents:elevator_top"},
after_place_tube = function(pos, param2, tube_type, num_tubes)
if tube_type == "S" then
if num_tubes == 2 then
minetest.swap_node(pos, {name = "vents:shaft2", param2 = param2})
else
minetest.swap_node(pos, {name = "vents:shaft", param2 = param2})
end
else
if num_tubes == 2 then
minetest.swap_node(pos, {name = "vents:shaftA2", param2 = param2})
else
minetest.swap_node(pos, {name = "vents:shaftA", param2 = param2})
end
end
end,
})
vents.Shaft = Shaft
local Elevators = vents.Elevators
Shaft:register_on_tube_update(function(node, pos, out_dir, peer_pos, peer_in_dir)
if out_dir == 6 then -- to the top?
-- switch to elevator_bottom node
pos = Shaft:get_pos(pos, 5)
elseif peer_pos then
local _,node = Shaft:get_node(peer_pos)
if node.name == "vents:elevator_top" then
peer_pos = Shaft:get_pos(peer_pos, 5)
end
end
Elevators:update_connections(pos, out_dir, peer_pos)
end)
minetest.register_node("vents:shaft", {
description = S("Hyperloop Elevator Shaft"),
inventory_image = 'hyperloop_shaft_inv.png',
tiles = {
-- up, down, right, left, back, front
"hyperloop_tube_closed.png^[transformR90]",
"hyperloop_tube_closed.png^[transformR90]",
"hyperloop_tube_closed.png",
"hyperloop_tube_closed.png",
'hyperloop_tube.png',
'hyperloop_tube.png',
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, -7/16, 8/16, 8/16},
{ 7/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, 7/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16},
},
},
selection_box = {
type = "fixed",
fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16},
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Shaft:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Shaft:after_dig_tube(pos, oldnode, oldmetadata)
end,
climbable = true,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
paramtype = "light",
light_source = 2,
sunlight_propagates = true,
is_ground_content = false,
groups = {breakable=1},
sounds = {footstep = {name = 'metal', gain = 1}},
})
minetest.register_node("vents:shaftA", {
description = S("Hyperloop Elevator Shaft"),
tiles = {
-- up, down, right, left, back, front
"hyperloop_tube_closed.png^[transformR90]",
'hyperloop_tube.png',
"hyperloop_tube_closed.png",
"hyperloop_tube_closed.png",
"hyperloop_tube_closed.png",
'hyperloop_tube.png',
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, -7/16, 8/16, 8/16},
{ 7/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, 7/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, 7/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, -8/16, 8/16, -7/16, -7/16},
},
},
selection_box = {
type = "fixed",
fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16},
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Shaft:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Shaft:after_dig_tube(pos, oldnode, oldmetadata)
end,
climbable = true,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
paramtype = "light",
light_source = 2,
sunlight_propagates = true,
is_ground_content = false,
groups = {breakable=1, not_in_creative_inventory=1},
drop = "vents:shaft",
sounds = {footstep = {name = 'metal', gain = 1}},
})
minetest.register_node("vents:shaft2", {
description = S("Hyperloop Elevator Shaft"),
tiles = {
-- up, down, right, left, back, front
"hyperloop_tube_locked.png^hyperloop_elogo.png^[transformR270]",
"hyperloop_tube_locked.png^hyperloop_elogo.png^[transformR90]",
"hyperloop_tube_locked.png^hyperloop_elogo.png^[transformR180]",
"hyperloop_tube_locked.png^hyperloop_elogo.png",
'hyperloop_tube.png',
'hyperloop_tube.png',
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, -7/16, 8/16, 8/16},
{ 7/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, 7/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16},
},
},
selection_box = {
type = "fixed",
fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16},
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Shaft:after_dig_tube(pos, oldnode, oldmetadata)
end,
climbable = true,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
paramtype = "light",
light_source = 2,
sunlight_propagates = true,
is_ground_content = false,
diggable = false,
groups = {breakable=1, not_in_creative_inventory=1},
sounds = {footstep = {name = 'metal', gain = 1}},
})
minetest.register_node("vents:shaftA2", {
description = S("Hyperloop Elevator Shaft"),
tiles = {
-- up, down, right, left, back, front
"hyperloop_tube_locked.png^hyperloop_elogo.png^[transformR270]",
'hyperloop_tube.png',
"hyperloop_tube_locked.png^hyperloop_elogo.png^[transformR180]",
"hyperloop_tube_locked.png^hyperloop_elogo.png^[transformR180]",
"hyperloop_tube_locked.png^hyperloop_elogo.png^[transformR90]",
'hyperloop_tube.png',
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, -7/16, 8/16, 8/16},
{ 7/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, 7/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, 7/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, -8/16, 8/16, -7/16, -7/16},
},
},
selection_box = {
type = "fixed",
fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16},
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Shaft:after_dig_tube(pos, oldnode, oldmetadata)
end,
climbable = true,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
paramtype = "light",
light_source = 2,
sunlight_propagates = true,
is_ground_content = false,
diggable = false,
groups = {breakable=1, not_in_creative_inventory=1},
sounds = {footstep = {name = 'metal', gain = 1}},
})
-------------------------------------------------------------------------------
-- Elevator Car
-------------------------------------------------------------------------------
-- Form spec for the floor list
local function formspec(pos, lFloors)
local tRes = {"size[6,10]label[0.5,0; "..S("Select your destination").."]"}
tRes[2] = "label[0.5,0.6;"..S("Destination").."]label[2,0.6;"..S("Floor").."]"
if #lFloors == 0 then
tRes[#tRes+1] = "button_exit[1,3;3,1;button;Update]"
elseif #lFloors < 10 then
for idx,floor in ipairs(lFloors) do
local ypos = 0.5 + idx*0.8
local ypos2 = ypos - 0.2
tRes[#tRes+1] = "button_exit[0.5,"..ypos2..";1,1;button;"..(#lFloors-idx).."]"
if vector.equals(floor.pos, pos) then
tRes[#tRes+1] = "label[2,"..ypos..";"..S("(current position)").."]"
else
tRes[#tRes+1] = "label[2,"..ypos..";"..(floor.name or "<unknown>").."]"
end
end
else
tRes[3] = "scrollbaroptions[smallstep=100;largestep=200]"
tRes[4] = "scrollbar[5.3,1.5;0.4,8.2;vertical;floors;0]"
tRes[5] = "scroll_container[0.5,2;5,9.5;floors;vertical;0.02]"
for idx,floor in ipairs(lFloors) do
local ypos = idx*0.8 - 0.5
local ypos2 = ypos - 0.2
tRes[#tRes+1] = "button_exit[0,"..ypos2..";1,1;button;"..(#lFloors-idx).."]"
if vector.equals(floor.pos, pos) then
tRes[#tRes+1] = "label[1.5,"..ypos..";"..S("(current position)").."]"
else
tRes[#tRes+1] = "label[1.5,"..ypos..";"..(floor.name or "<unknown>").."]"
end
end
tRes[#tRes+1] = "scroll_container_end[]"
end
return table.concat(tRes)
end
local function update_formspec(pos)
local meta = M(pos)
local counter = meta:get_int("change_counter") or 0
local changed, newcounter = Elevators:changed(counter)
local sKey = SP(pos)
if changed or not Cache[sKey] then
local lFloors = Elevators:station_list(pos, pos, "level")
Cache[sKey] = {}
Cache[sKey].lFloors = lFloors
Cache[sKey].formspec = formspec(pos, lFloors)
meta:set_int("change_counter", newcounter)
end
M(pos):set_string("formspec", Cache[sKey].formspec)
end
-- Open/close/darken the elevator door
-- floor_pos: position of elevator floor
-- cmnd: "close", "open", or "darken"
local function door_command(floor_pos, facedir, cmnd, sound)
-- one step up
local door_pos1 = vents.new_pos(floor_pos, facedir, "1B", 0)
local door_pos2 = vents.new_pos(floor_pos, facedir, "1B", 1)
local node1 = minetest.get_node(door_pos1)
local node2 = minetest.get_node(door_pos2)
if sound then
minetest.sound_play("ele_door", {
pos = floor_pos,
gain = 0.8,
max_hear_distance = 10,
})
end
if cmnd == "open" then
node1.name = "air"
minetest.swap_node(door_pos1, node1)
node2.name = "air"
minetest.swap_node(door_pos2, node2)
elseif cmnd == "close" then
M(door_pos1):set_string("floor_pos", SP(floor_pos))
M(door_pos2):set_string("floor_pos", SP(floor_pos))
node1.name = "vents:elevator_door"
node1.param2 = facedir
minetest.swap_node(door_pos1, node1)
node2.name = "vents:elevator_door_top"
node2.param2 = facedir
minetest.swap_node(door_pos2, node2)
elseif cmnd == "darken" then
node1.name = "vents:elevator_door_dark"
node1.param2 = facedir
minetest.swap_node(door_pos1, node1)
node2.name = "vents:elevator_door_dark_top"
node2.param2 = facedir
minetest.swap_node(door_pos2, node2)
end
end
local function on_final_close_door(tArrival)
-- close the door and play sound if no player is around
if vents.is_player_around(tArrival.pos) then
-- try again later
minetest.after(3.0, on_final_close_door, tArrival)
else
door_command(tArrival.pos, tArrival.facedir, "close", true)
end
end
local function on_open_door(tArrival)
door_command(tArrival.pos, tArrival.facedir, "open", true)
minetest.after(5.0, on_final_close_door, tArrival)
tArrival.busy = false
end
local function on_arrival_floor(tDeparture, tArrival, player_name, snd)
local player = minetest.get_player_by_name(player_name)
door_command(tDeparture.pos, tDeparture.facedir, "close", false)
door_command(tArrival.pos, tArrival.facedir, "close", false)
tDeparture.busy = false
if player ~= nil then
tArrival.pos.y = tArrival.pos.y - kPLAYER_OVER_GROUND
player:set_pos(tArrival.pos)
if PlayerNameTags[player_name] then
player:set_nametag_attributes(PlayerNameTags[player_name])
PlayerNameTags[player_name] = nil
end
tArrival.pos.y = tArrival.pos.y + kPLAYER_OVER_GROUND
end
minetest.sound_stop(snd)
minetest.after(1.0, on_open_door, tArrival)
end
local function on_travel(tDeparture, tArrival, player_name, seconds)
local player = minetest.get_player_by_name(player_name)
door_command(tDeparture.pos, tDeparture.facedir, "darken", false)
door_command(tArrival.pos, tArrival.facedir, "darken", false)
if player ~= nil then
PlayerNameTags[player_name] = player:get_nametag_attributes()
player:set_nametag_attributes({text = " "})
end
local snd = minetest.sound_play("ele_norm", {
pos = tDeparture.pos,
gain = 0.5,
max_hear_distance = 3,
loop = true,
})
minetest.after(seconds, on_arrival_floor, tDeparture, tArrival, player_name, snd)
end
minetest.register_node("vents:elevator_bottom", {
description = S("Hyperloop Elevator"),
tiles = {
"hyperloop_elevator_bottom.png",
"hyperloop_elevator_bottom.png",
"hyperloop_elevator.png",
"hyperloop_elevator.png",
"hyperloop_elevator.png",
"hyperloop_elevator.png",
},
node_box = {
type = "fixed",
fixed = {
{ -8/16, -8/16, -8/16, -7/16, 8/16, 8/16},
{ 7/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{ -7/16, -8/16, 7/16, 7/16, 8/16, 8/16},
{ -8/16, -8/16, -8/16, 8/16, -7/16, 8/16},
},
},
selection_box = {
type = "fixed",
fixed = { -8/16, -8/16, -8/16, 8/16, 23/16, 8/16 },
},
inventory_image = "hyperloop_elevator_inventory.png",
on_rotate = screwdriver.disallow,
drawtype = "nodebox",
paramtype = 'light',
light_source = 6,
paramtype2 = "facedir",
is_ground_content = false,
groups = {snappy = 3},
after_place_node = function(pos, placer, itemstack, pointed_thing)
local _,node = Shaft:get_node(pos, 6)
if node.name == "air" then
local facedir = vents.get_facedir(placer)
Elevators:set(pos, "<unknown>", {facedir=facedir, busy=false})
Shaft:after_place_node(pos, {5})
-- formspec
local meta = minetest.get_meta(pos)
local formspec = "size[6,4]"..
"label[0,0;"..S("Please insert floor name").."]" ..
"field[0.5,1.5;5,1;floor;"..S("Floor name")..";"..S("Base").."]" ..
"button_exit[2,3;2,1;exit;"..S("Save").."]"
meta:set_string("formspec", formspec)
-- add upper part of the car
pos = Shaft:get_pos(pos, 6)
minetest.add_node(pos, {name="vents:elevator_top", param2=facedir})
Shaft:after_place_node(pos, {6})
else
minetest.remove_node(pos)
return true
end
end,
on_receive_fields = function(pos, formname, fields, player)
-- floor name entered?
if fields.floor ~= nil then
local floor = string.trim(fields.floor)
if floor == "" then
return
end
Elevators:update(pos, {name=floor})
update_formspec(pos)
elseif fields.button ~= nil then -- destination selected?
update_formspec(pos)
local floor = Elevators:get(pos)
if floor then
floor = table.copy(floor)
floor.pos = pos
local sKey = SP(pos)
local idx = tonumber(fields.button)
if idx then
local lFloors = Cache[sKey].lFloors
local dest = lFloors[#lFloors-idx]
if dest and dest.pos and floor.pos then
local dist = vents.distance(dest.pos, floor.pos)
if dist ~= 0 and floor.busy ~= true then
if player ~= nil then
pos.y = pos.y - kPLAYER_OVER_GROUND
player:set_pos(pos)
pos.y = pos.y + kPLAYER_OVER_GROUND
end
-- due to the missing display, a trip needs 20 sec maximum
local seconds = math.min(1 + math.floor(dist/30), 20)
floor.busy = true
door_command(floor.pos, floor.facedir, "close", true)
door_command(dest.pos, dest.facedir, "close", true)
minetest.after(1.0, on_travel, floor, dest, player:get_player_name(), seconds)
end
end
end
end
end
end,
on_punch = function(pos, node, puncher, pointed_thing)
update_formspec(pos)
local floor = Elevators:get(pos)
if floor and floor.busy ~= true then
door_command(pos, floor.facedir, "open", true)
end
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Shaft:after_dig_node(pos, {5})
Elevators:delete(pos)
-- remove the bottom also
pos = Shaft:get_pos(pos, 6)
minetest.remove_node(pos)
Shaft:after_dig_node(pos, {6})
end,
})
minetest.register_node("vents:elevator_top", {
description = S("Hyperloop Elevator"),
tiles = {
-- up, down, right, left, back, front
"hyperloop_elevator_bottom.png",
"hyperloop_elevator_bottom.png",
"hyperloop_elevator_top.png",
"hyperloop_elevator.png",
"hyperloop_elevator.png",
"hyperloop_elevator.png",
},
node_box = {
type = "fixed",
fixed = {
{ -8/16, 7/16, -8/16, 8/16, 8/16, 8/16},
{ -8/16, -8/16, -8/16, -7/16, 8/16, 8/16},
{ 7/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{ -7/16, -8/16, 7/16, 7/16, 8/16, 8/16},
},
},
on_rotate = screwdriver.disallow,
drawtype = "nodebox",
paramtype = 'light',
light_source = 6,
paramtype2 = "facedir",
is_ground_content = false,
diggable = false,
groups = {not_in_creative_inventory=1},
drop = "",
})
minetest.register_node("vents:elevator_door_top", {
description = "Hyperloop Elevator Door",
tiles = {
-- up, down, right, left, back, front
"hyperloop_elevator_door_top.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -8/16, -8/16, 7/16, 8/16, 8/16, 8/16},
},
},
on_rotate = screwdriver.disallow,
drop = "",
paramtype = 'light',
paramtype2 = "facedir",
use_texture_alpha = vents.CLIP,
is_ground_content = false,
groups = {snappy = 3, not_in_creative_inventory=1},
})
minetest.register_node("vents:elevator_door", {
description = "Hyperloop Elevator Door",
tiles = {
-- up, down, right, left, back, front
"hyperloop_elevator_door.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -8/16, -8/16, 7/16, 8/16, 8/16, 8/16},
},
},
selection_box = {
type = "fixed",
fixed = { -8/16, -8/16, 6.5/16, 8/16, 24/16, 8/16 },
},
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local floor_pos = P(M(pos):get_string("floor_pos"))
if floor_pos ~= nil then
update_formspec(floor_pos)
local floor = Elevators:get(floor_pos)
if floor and floor.busy ~= true then
door_command(floor_pos, floor.facedir, "open", true)
end
end
end,
on_rotate = screwdriver.disallow,
drop = "",
paramtype = 'light',
paramtype2 = "facedir",
use_texture_alpha = vents.CLIP,
is_ground_content = false,
groups = {snappy = 3, not_in_creative_inventory=1},
})
minetest.register_node("vents:elevator_door_dark_top", {
description = "Hyperloop Elevator Door",
tiles = {
-- up, down, right, left, back, front
"hyperloop_elevator_dark_top.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -8/16, -8/16, 7/16, 8/16, 8/16, 8/16},
},
},
on_rotate = screwdriver.disallow,
drop = "",
paramtype = 'light',
paramtype2 = "facedir",
is_ground_content = false,
groups = {snappy = 3, not_in_creative_inventory=1},
})
minetest.register_node("vents:elevator_door_dark", {
description = "Hyperloop Elevator Door",
tiles = {
-- up, down, right, left, back, front
"hyperloop_elevator_dark.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -8/16, -8/16, 7/16, 8/16, 8/16, 8/16},
},
},
selection_box = {
type = "fixed",
fixed = { -8/16, -8/16, 7/16, 8/16, 24/16, 8/16 },
},
on_rotate = screwdriver.disallow,
drop = "",
paramtype = 'light',
paramtype2 = "facedir",
is_ground_content = false,
groups = {snappy = 3, not_in_creative_inventory=1},
})

View File

@ -0,0 +1 @@
return {["Wangen"] = {["routes"] = {{"1.3", "3.1"}, {"1.2", "2.1"}}, ["pos"] = "(1,2,3)"}, ["München"] = {["routes"] = {{"2.1", "1.2"}, {"2.3", "3.2"}}, ["pos"] = "(1,2,3)"}, ["Stuttgart"] = {["routes"] = {{"3.1", "1.3"}, {"3.2", "2.3"}, {"3.4", "4.3"}}, ["pos"] = "(1,2,3)"}, ["Heidelberg"] = {["routes"] = {{"4.3", "3.4"}}, ["pos"] = "(1,2,3)"}, ["Hamburg"] = {["routes"] = {{"6.5", "5.6"}}, ["pos"] = "(1,2,3)"}, ["Berlin"] = {["routes"] = {{"5.6", "6.5"}}, ["pos"] = "(1,2,3)"}}

458
mods/vents/i18n.py Normal file
View File

@ -0,0 +1,458 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Script to generate the template file and update the translation files.
# Copy the script into the mod or modpack root folder and run it there.
#
# Copyright (C) 2019 Joachim Stolberg, 2020 FaceDeer, 2020 Louis Royer
# LGPLv2.1+
#
# See https://github.com/minetest-tools/update_translations for
# potential future updates to this script.
from __future__ import print_function
import os, fnmatch, re, shutil, errno
from sys import argv as _argv
from sys import stderr as _stderr
# Running params
params = {"recursive": False,
"help": False,
"mods": False,
"verbose": False,
"folders": [],
"no-old-file": False,
"break-long-lines": False,
"sort": False
}
# Available CLI options
options = {"recursive": ['--recursive', '-r'],
"help": ['--help', '-h'],
"mods": ['--installed-mods', '-m'],
"verbose": ['--verbose', '-v'],
"no-old-file": ['--no-old-file', '-O'],
"break-long-lines": ['--break-long-lines', '-b'],
"sort": ['--sort', '-s']
}
# Strings longer than this will have extra space added between
# them in the translation files to make it easier to distinguish their
# beginnings and endings at a glance
doublespace_threshold = 80
def set_params_folders(tab: list):
'''Initialize params["folders"] from CLI arguments.'''
# Discarding argument 0 (tool name)
for param in tab[1:]:
stop_param = False
for option in options:
if param in options[option]:
stop_param = True
break
if not stop_param:
params["folders"].append(os.path.abspath(param))
def set_params(tab: list):
'''Initialize params from CLI arguments.'''
for option in options:
for option_name in options[option]:
if option_name in tab:
params[option] = True
break
def print_help(name):
'''Prints some help message.'''
print(f'''SYNOPSIS
{name} [OPTIONS] [PATHS...]
DESCRIPTION
{', '.join(options["help"])}
prints this help message
{', '.join(options["recursive"])}
run on all subfolders of paths given
{', '.join(options["mods"])}
run on locally installed modules
{', '.join(options["no-old-file"])}
do not create *.old files
{', '.join(options["sort"])}
sort output strings alphabetically
{', '.join(options["break-long-lines"])}
add extra line breaks before and after long strings
{', '.join(options["verbose"])}
add output information
''')
def main():
'''Main function'''
set_params(_argv)
set_params_folders(_argv)
if params["help"]:
print_help(_argv[0])
elif params["recursive"] and params["mods"]:
print("Option --installed-mods is incompatible with --recursive")
else:
# Add recursivity message
print("Running ", end='')
if params["recursive"]:
print("recursively ", end='')
# Running
if params["mods"]:
print(f"on all locally installed modules in {os.path.abspath('~/.minetest/mods/')}")
run_all_subfolders("~/.minetest/mods")
elif len(params["folders"]) >= 2:
print("on folder list:", params["folders"])
for f in params["folders"]:
if params["recursive"]:
run_all_subfolders(f)
else:
update_folder(f)
elif len(params["folders"]) == 1:
print("on folder", params["folders"][0])
if params["recursive"]:
run_all_subfolders(params["folders"][0])
else:
update_folder(params["folders"][0])
else:
print("on folder", os.path.abspath("./"))
if params["recursive"]:
run_all_subfolders(os.path.abspath("./"))
else:
update_folder(os.path.abspath("./"))
#group 2 will be the string, groups 1 and 3 will be the delimiters (" or ')
#See https://stackoverflow.com/questions/46967465/regex-match-text-in-either-single-or-double-quote
pattern_lua_s = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)[\s,\)]', re.DOTALL)
pattern_lua_fs = re.compile(r'[\.=^\t,{\(\s]N?FS\(\s*(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)[\s,\)]', re.DOTALL)
pattern_lua_bracketed_s = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*\[\[(.*?)\]\][\s,\)]', re.DOTALL)
pattern_lua_bracketed_fs = re.compile(r'[\.=^\t,{\(\s]N?FS\(\s*\[\[(.*?)\]\][\s,\)]', re.DOTALL)
# Handles "concatenation" .. " of strings"
pattern_concat = re.compile(r'["\'][\s]*\.\.[\s]*["\']', re.DOTALL)
pattern_tr = re.compile(r'(.*?[^@])=(.*)')
pattern_name = re.compile(r'^name[ ]*=[ ]*([^ \n]*)')
pattern_tr_filename = re.compile(r'\.tr$')
pattern_po_language_code = re.compile(r'(.*)\.po$')
#attempt to read the mod's name from the mod.conf file. Returns None on failure
def get_modname(folder):
try:
with open(os.path.join(folder, "mod.conf"), "r", encoding='utf-8') as mod_conf:
for line in mod_conf:
match = pattern_name.match(line)
if match:
return match.group(1)
except FileNotFoundError:
pass
return None
#If there are already .tr files in /locale, returns a list of their names
def get_existing_tr_files(folder):
out = []
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
for name in files:
if pattern_tr_filename.search(name):
out.append(name)
return out
# A series of search and replaces that massage a .po file's contents into
# a .tr file's equivalent
def process_po_file(text):
# The first three items are for unused matches
text = re.sub(r'#~ msgid "', "", text)
text = re.sub(r'"\n#~ msgstr ""\n"', "=", text)
text = re.sub(r'"\n#~ msgstr "', "=", text)
# comment lines
text = re.sub(r'#.*\n', "", text)
# converting msg pairs into "=" pairs
text = re.sub(r'msgid "', "", text)
text = re.sub(r'"\nmsgstr ""\n"', "=", text)
text = re.sub(r'"\nmsgstr "', "=", text)
# various line breaks and escape codes
text = re.sub(r'"\n"', "", text)
text = re.sub(r'"\n', "\n", text)
text = re.sub(r'\\"', '"', text)
text = re.sub(r'\\n', '@n', text)
# remove header text
text = re.sub(r'=Project-Id-Version:.*\n', "", text)
# remove double-spaced lines
text = re.sub(r'\n\n', '\n', text)
return text
# Go through existing .po files and, if a .tr file for that language
# *doesn't* exist, convert it and create it.
# The .tr file that results will subsequently be reprocessed so
# any "no longer used" strings will be preserved.
# Note that "fuzzy" tags will be lost in this process.
def process_po_files(folder, modname):
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
for name in files:
code_match = pattern_po_language_code.match(name)
if code_match == None:
continue
language_code = code_match.group(1)
tr_name = modname + "." + language_code + ".tr"
tr_file = os.path.join(root, tr_name)
if os.path.exists(tr_file):
if params["verbose"]:
print(f"{tr_name} already exists, ignoring {name}")
continue
fname = os.path.join(root, name)
with open(fname, "r", encoding='utf-8') as po_file:
if params["verbose"]:
print(f"Importing translations from {name}")
text = process_po_file(po_file.read())
with open(tr_file, "wt", encoding='utf-8') as tr_out:
tr_out.write(text)
# from https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python/600612#600612
# Creates a directory if it doesn't exist, silently does
# nothing if it already exists
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else: raise
# Converts the template dictionary to a text to be written as a file
# dKeyStrings is a dictionary of localized string to source file sets
# dOld is a dictionary of existing translations and comments from
# the previous version of this text
def strings_to_text(dkeyStrings, dOld, mod_name, header_comments):
lOut = [f"# textdomain: {mod_name}\n"]
if header_comments is not None:
lOut.append(header_comments)
dGroupedBySource = {}
for key in dkeyStrings:
sourceList = list(dkeyStrings[key])
if params["sort"]:
sourceList.sort()
sourceString = "\n".join(sourceList)
listForSource = dGroupedBySource.get(sourceString, [])
listForSource.append(key)
dGroupedBySource[sourceString] = listForSource
lSourceKeys = list(dGroupedBySource.keys())
lSourceKeys.sort()
for source in lSourceKeys:
localizedStrings = dGroupedBySource[source]
if params["sort"]:
localizedStrings.sort()
lOut.append("")
lOut.append(source)
lOut.append("")
for localizedString in localizedStrings:
val = dOld.get(localizedString, {})
translation = val.get("translation", "")
comment = val.get("comment")
if params["break-long-lines"] and len(localizedString) > doublespace_threshold and not lOut[-1] == "":
lOut.append("")
if comment != None:
lOut.append(comment)
lOut.append(f"{localizedString}={translation}")
if params["break-long-lines"] and len(localizedString) > doublespace_threshold:
lOut.append("")
unusedExist = False
for key in dOld:
if key not in dkeyStrings:
val = dOld[key]
translation = val.get("translation")
comment = val.get("comment")
# only keep an unused translation if there was translated
# text or a comment associated with it
if translation != None and (translation != "" or comment):
if not unusedExist:
unusedExist = True
lOut.append("\n\n##### not used anymore #####\n")
if params["break-long-lines"] and len(key) > doublespace_threshold and not lOut[-1] == "":
lOut.append("")
if comment != None:
lOut.append(comment)
lOut.append(f"{key}={translation}")
if params["break-long-lines"] and len(key) > doublespace_threshold:
lOut.append("")
return "\n".join(lOut) + '\n'
# Writes a template.txt file
# dkeyStrings is the dictionary returned by generate_template
def write_template(templ_file, dkeyStrings, mod_name):
# read existing template file to preserve comments
existing_template = import_tr_file(templ_file)
text = strings_to_text(dkeyStrings, existing_template[0], mod_name, existing_template[2])
mkdir_p(os.path.dirname(templ_file))
with open(templ_file, "wt", encoding='utf-8') as template_file:
template_file.write(text)
# Gets all translatable strings from a lua file
def read_lua_file_strings(lua_file):
lOut = []
with open(lua_file, encoding='utf-8') as text_file:
text = text_file.read()
#TODO remove comments here
text = re.sub(pattern_concat, "", text)
strings = []
for s in pattern_lua_s.findall(text):
strings.append(s[1])
for s in pattern_lua_bracketed_s.findall(text):
strings.append(s)
for s in pattern_lua_fs.findall(text):
strings.append(s[1])
for s in pattern_lua_bracketed_fs.findall(text):
strings.append(s)
for s in strings:
s = re.sub(r'"\.\.\s+"', "", s)
s = re.sub("@[^@=0-9]", "@@", s)
s = s.replace('\\"', '"')
s = s.replace("\\'", "'")
s = s.replace("\n", "@n")
s = s.replace("\\n", "@n")
s = s.replace("=", "@=")
lOut.append(s)
return lOut
# Gets strings from an existing translation file
# returns both a dictionary of translations
# and the full original source text so that the new text
# can be compared to it for changes.
# Returns also header comments in the third return value.
def import_tr_file(tr_file):
dOut = {}
text = None
header_comment = None
if os.path.exists(tr_file):
with open(tr_file, "r", encoding='utf-8') as existing_file :
# save the full text to allow for comparison
# of the old version with the new output
text = existing_file.read()
existing_file.seek(0)
# a running record of the current comment block
# we're inside, to allow preceeding multi-line comments
# to be retained for a translation line
latest_comment_block = None
for line in existing_file.readlines():
line = line.rstrip('\n')
if line[:3] == "###":
if header_comment is None:
# Save header comments
header_comment = latest_comment_block
# Stip textdomain line
tmp_h_c = ""
for l in header_comment.split('\n'):
if not l.startswith("# textdomain:"):
tmp_h_c += l + '\n'
header_comment = tmp_h_c
# Reset comment block if we hit a header
latest_comment_block = None
continue
if line[:1] == "#":
# Save the comment we're inside
if not latest_comment_block:
latest_comment_block = line
else:
latest_comment_block = latest_comment_block + "\n" + line
continue
match = pattern_tr.match(line)
if match:
# this line is a translated line
outval = {}
outval["translation"] = match.group(2)
if latest_comment_block:
# if there was a comment, record that.
outval["comment"] = latest_comment_block
latest_comment_block = None
dOut[match.group(1)] = outval
return (dOut, text, header_comment)
# Walks all lua files in the mod folder, collects translatable strings,
# and writes it to a template.txt file
# Returns a dictionary of localized strings to source file sets
# that can be used with the strings_to_text function.
def generate_template(folder, mod_name):
dOut = {}
for root, dirs, files in os.walk(folder):
for name in files:
if fnmatch.fnmatch(name, "*.lua"):
fname = os.path.join(root, name)
found = read_lua_file_strings(fname)
if params["verbose"]:
print(f"{fname}: {str(len(found))} translatable strings")
for s in found:
sources = dOut.get(s, set())
sources.add(f"### {os.path.basename(fname)} ###")
dOut[s] = sources
if len(dOut) == 0:
return None
templ_file = os.path.join(folder, "locale/template.txt")
write_template(templ_file, dOut, mod_name)
return dOut
# Updates an existing .tr file, copying the old one to a ".old" file
# if any changes have happened
# dNew is the data used to generate the template, it has all the
# currently-existing localized strings
def update_tr_file(dNew, mod_name, tr_file):
if params["verbose"]:
print(f"updating {tr_file}")
tr_import = import_tr_file(tr_file)
dOld = tr_import[0]
textOld = tr_import[1]
textNew = strings_to_text(dNew, dOld, mod_name, tr_import[2])
if textOld and textOld != textNew:
print(f"{tr_file} has changed.")
if not params["no-old-file"]:
shutil.copyfile(tr_file, f"{tr_file}.old")
with open(tr_file, "w", encoding='utf-8') as new_tr_file:
new_tr_file.write(textNew)
# Updates translation files for the mod in the given folder
def update_mod(folder):
modname = get_modname(folder)
if modname is not None:
process_po_files(folder, modname)
print(f"Updating translations for {modname}")
data = generate_template(folder, modname)
if data == None:
print(f"No translatable strings found in {modname}")
else:
for tr_file in get_existing_tr_files(folder):
update_tr_file(data, modname, os.path.join(folder, "locale/", tr_file))
else:
print(f"\033[31mUnable to find modname in folder {folder}.\033[0m", file=_stderr)
exit(1)
# Determines if the folder being pointed to is a mod or a mod pack
# and then runs update_mod accordingly
def update_folder(folder):
is_modpack = os.path.exists(os.path.join(folder, "modpack.txt")) or os.path.exists(os.path.join(folder, "modpack.conf"))
if is_modpack:
subfolders = [f.path for f in os.scandir(folder) if f.is_dir()]
for subfolder in subfolders:
update_mod(subfolder + "/")
else:
update_mod(folder)
print("Done.")
def run_all_subfolders(folder):
for modfolder in [f.path for f in os.scandir(folder) if f.is_dir()]:
update_folder(modfolder + "/")
main()

82
mods/vents/init.lua Normal file
View File

@ -0,0 +1,82 @@
--[[
Hyperloop Mod
=============
v2.06 by JoSt
Copyright (C) 2017-2021 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
History:
2017-06-18 v0.01 First version
2017-07-06 v0.02 Version on GitHub
2017-07-07 v0.03 Recipes added, settingstypes added
2017-07-08 v0.04 Door removal issue fixed
2017-07-16 v0.05 Doors can be opened manually
2017-07-24 v0.06 Tubes with limited slope, elevator and deco blocks added
2017-07-28 v0.07 Slope removed, Station auto-builder added
2017-07-30 v0.08 Signs added, tube robot added, crowbar added
2017-07-31 v0.09 Some bug fixes on the Bocking Machine
2017-08-01 v0.10 Elevator now with sound and travel animation plus minor bug fixes
2017-08-06 v0.11 Crowbar now allows repairing of illegally detroyed tubes
2018-03-27 v0.12 Some minor improvements with player position, arrival time,
Wifi node improvements, Podshell cheating bugfix,
forceload_block removed.
2018-04-13 v0.13 Potential 'Never Store ObjectRefs' bug fixed
2018-10-27 v1.00 Release
2018-10-27 v2.00 Switched to lubelib2 for shafts and tubes
2018-12-16 v2.01 Adapted to lubelib2 v0.5
2018-12-20 v2.02 Intllib support added, bugs fixed
2019-03-23 v2.03 Elevator duplication bugfix
2020-01-03 v2.04 Elevator door bugfix (MT 5+)
2020-03-12 v2.05 minetest translator added (thanks to acmgit/Clyde)
2020-06-14 v2.06 The default value for `hyperloop_free_tube_placement_enabled` is now true
2021-02-07 v2.07 tube_crowbar: Add tube length check
2021-11-01 v2.08 Enable the use of hyperloop networks for other mods
]]--
vents = {}
-- Version for compatibility checks, see history
vents.version = 2.08
if minetest.get_translator ~= nil then
vents.S = minetest.get_translator(minetest.get_current_modname())
else
-- Load support for intllib.
local MP = minetest.get_modpath('vents')
vents.S, vents.NS = dofile(MP..'/intllib.lua')
end
-- MT 5.4 new string mode
vents.CLIP = minetest.features.use_texture_alpha_string_modes and 'clip' or false
vents.BLEND = minetest.features.use_texture_alpha_string_modes and 'blend' or true
if tubelib2.version < 1.7 then
error('Hyperloop requires tubelib2 version 1.7 or newer!!!')
else
-- Configuration settings
vents.free_tube_placement_enabled = minetest.settings:get_bool('hyperloop_free_tube_placement_enabled', true)
vents.subnet_enabled = minetest.settings:get_bool('hyperloop_subnet_enabled', true)
dofile(minetest.get_modpath('vents') .. '/network.lua')
dofile(minetest.get_modpath('vents') .. '/data_base.lua')
dofile(minetest.get_modpath('vents') .. '/booking.lua')
dofile(minetest.get_modpath('vents') .. '/utils.lua')
-- dofile(minetest.get_modpath('vents') .. '/elevator.lua')
dofile(minetest.get_modpath('vents') .. '/tube.lua')
dofile(minetest.get_modpath('vents') .. '/tubecrowbar.lua')
dofile(minetest.get_modpath('vents') .. '/junction.lua')
dofile(minetest.get_modpath('vents') .. '/station.lua')
dofile(minetest.get_modpath('vents') .. '/booking_node.lua')
-- dofile(minetest.get_modpath('vents') .. '/map.lua')
dofile(minetest.get_modpath('vents') .. '/seat.lua')
end

45
mods/vents/intllib.lua Normal file
View File

@ -0,0 +1,45 @@
-- Fallback functions for when `intllib` is not installed.
-- Code released under Unlicense <http://unlicense.org>.
-- Get the latest version of this file at:
-- https://raw.githubusercontent.com/minetest-mods/intllib/master/lib/intllib.lua
local function format(str, ...)
local args = { ... }
local function repl(escape, open, num, close)
if escape == "" then
local replacement = tostring(args[tonumber(num)])
if open == "" then
replacement = replacement..close
end
return replacement
else
return "@"..open..num..close
end
end
return (str:gsub("(@?)@(%(?)(%d+)(%)?)", repl))
end
local gettext, ngettext
if minetest.get_modpath("intllib") then
if intllib.make_gettext_pair then
-- New method using gettext.
gettext, ngettext = intllib.make_gettext_pair()
else
-- Old method using text files.
gettext = intllib.Getter()
end
end
-- Fill in missing functions.
gettext = gettext or function(msgid, ...)
return format(msgid, ...)
end
ngettext = ngettext or function(msgid, msgid_plural, n, ...)
return format(n==1 and msgid or msgid_plural, ...)
end
return gettext, ngettext

3
mods/vents/intllib.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
../intllib/tools/xgettext.sh ./booking.lua ./door.lua ./lcd.lua ./tube.lua ./booking_node.lua ./elevator.lua ./map.lua ./seat.lua ./utils.lua ./data_base.lua ./init.lua ./waypoint.lua ./network.lua ./station.lua ./wifi.lua ./deco.lua ./junction.lua ./recipes.lua ./tubecrowbar.lua ./recipes.lua

View File

@ -0,0 +1,30 @@
# Introduction
Connect two Junction blocks with a line of Tube blocks. The tube itself is automatically protected. You can dig only the ends of a tube line (head blocks). The junction block / station has to be protected manually.
A Junction block, which is the basis for a station, can have up to four tubes. That means you can build complex networks of tube lines. Each junction/station can be reaches from each point with one trip.
![Image](https://github.com/joe7575/Minetest-Hyperloop/blob/master/img/intro03.png)
To build a station, give the Junction block a unique station name and place the Pod Seat on top of it.
![Image](https://github.com/joe7575/Minetest-Hyperloop/blob/master/img/intro01.png)
Build the pod around the seat according to the following picture. To get the best illusion of traveling, it is important that all pods are look the same from the inside.
![Image](https://github.com/joe7575/Minetest-Hyperloop/blob/master/img/intro04.png)
The pod shell is not important for the function, the minimal equipment for testing is: the Tube line with Junction blocks, a Pod Seat on each station, the Display in front of the seat, and the Booking Machine. The Booking Machine has to get the same station name as the Junction block and has to be placed nearby the Junction block (max. 30 blocks difference).
![Image](https://github.com/joe7575/Minetest-Hyperloop/blob/master/img/intro02.png)
Keep a hole for the door which will be placed automatically when you start your first trip. The door hole has always to be on the left side of the pod (see the following picture).
![Image](https://github.com/joe7575/Minetest-Hyperloop/blob/master/img/intro05.png)
For traveling you have to use the Booking Machine to select you destination. After booking, the pods (departure and arrival) are reserved for 20 seconds to start the trip. For starting the trip you have to use the Pod Seat. You will be placed on the seat and the door will close automatically.

93
mods/vents/junction.lua Normal file
View File

@ -0,0 +1,93 @@
--[[
Hyperloop Mod
=============
Copyright (C) 2017-2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
]]--
-- for lazy programmers
local SP = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local S = vents.S
local NS = vents.NS
local Tube = vents.Tube
local Stations = vents.Stations
Tube:register_on_tube_update(function(node, pos, out_dir, peer_pos, peer_in_dir)
if node.name == "vents:station" then
if out_dir <= 5 then
Stations:update_connections(pos, out_dir, peer_pos)
local s = vents.get_connection_string(pos)
M(pos):set_string("infotext", S("Station connected to ")..s)
end
elseif node.name == "vents:junction" then
Stations:update_connections(pos, out_dir, peer_pos)
local s = vents.get_connection_string(pos)
M(pos):set_string("infotext", S("Junction connected to ")..s)
elseif Tube.secondary_node_names[node.name] then
if out_dir == 5 then
Stations:update_connections(pos, out_dir, peer_pos)
local s = vents.get_connection_string(pos)
M(pos):set_string("conn_to", s)
end
end
end)
minetest.register_node("vents:junction", {
description = S("Hyperloop Junction Block"),
tiles = {
"hyperloop_junction_top.png",
"hyperloop_junction_top.png",
"hyperloop_station_connection.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
vents.check_network_level(pos, placer)
M(pos):set_string("infotext", S("Junction"))
Stations:set(pos, "Junction", {
owner = placer:get_player_name(), junction = true})
Tube:after_place_node(pos)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_node(pos)
Stations:delete(pos)
end,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
paramtype = "light",
sunlight_propagates = true,
groups = {breakable=1},
is_ground_content = false,
sounds = {footstep = {name = 'metal', gain = 1}},
})
-- for tube viaducts
minetest.register_node("vents:pillar", {
description = S("Hyperloop Pillar"),
tiles = {"hyperloop_tube_locked.png^[transformR90]"},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -3/8, -4/8, -3/8, 3/8, 4/8, 3/8},
},
},
on_rotate = screwdriver.disallow,
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {breakable=1, stone = 2},
sounds = {footstep = {name = 'metal', gain = 1}},
})

BIN
mods/vents/locale/de.mo Normal file

Binary file not shown.

314
mods/vents/locale/de.po Normal file
View File

@ -0,0 +1,314 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-22 11:22+0100\n"
"PO-Revision-Date: 2018-12-22 11:23+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.0.6\n"
#: booking.lua
msgid "Station data is corrupted. Please rebuild the station!"
msgstr "Stationsdaten sind beschädigt. Bitte die Station neu bauen!"
#: booking.lua
msgid "Station is still blocked. Please try again in a few seconds!"
msgstr ""
"Die Station ist noch blockiert. Bitte versuche es in ein paar Sekunden "
"wieder!"
#: door.lua
msgid "The Booking Machine for this station is missing!"
msgstr "Der Fahrkartenautomat für die Station fehlt!"
#: lcd.lua
msgid "Hyperloop Display"
msgstr "Hyperloop Bildschirm"
#: lcd.lua seat.lua
msgid " | | << Hyperloop >> | be anywhere"
msgstr " | | << Hyperloop >> | be anywhere"
#: tube.lua
msgid "Junction at "
msgstr "Anschlussstelle bei "
#: tube.lua
msgid "There is no station/junction on this level. "
msgstr "Es gibt keine Station/Anschlussstelle auf dieser Höhe. "
#: tube.lua
msgid "Do you really want to start a new network?!"
msgstr "Willst du wirklich ein neues Liniennetz beginnen?!"
#: tube.lua
msgid "Hyperloop Tube"
msgstr "Hyperloop Röhre"
#: booking_node.lua elevator.lua
msgid "Select your destination"
msgstr "Wähle dein Ziel"
#: booking_node.lua elevator.lua
msgid "Destination"
msgstr "Ziel"
#: booking_node.lua
msgid "Distance"
msgstr "Entfernung"
#: booking_node.lua
msgid "Local Info"
msgstr "Zusatzinfo"
#: booking_node.lua
msgid ""
"Please enter the station name to\n"
"which this booking machine belongs."
msgstr ""
"Bitte gib den Stationsnamen ein\n"
"zu dem dieser Fahrkartenautomat gehört."
#: booking_node.lua
msgid "Station name"
msgstr "Stationsname"
#: booking_node.lua
msgid "Additional station information"
msgstr "Zusätzliche Stationsinformationen"
#: booking_node.lua
msgid "Station has already a booking machine!"
msgstr "Station hat bereits einen Fahrkartenautomat!"
#: booking_node.lua
msgid "Invalid station name!"
msgstr "Ungültiger Stationsname!"
#: booking_node.lua
msgid "Hyperloop Booking Machine"
msgstr "Hyperloop Fahrkartenautomat"
#: elevator.lua
msgid "Hyperloop Elevator Shaft"
msgstr "Hyperloop Aufzugsschacht"
#: elevator.lua
msgid "Floor"
msgstr "Stockwerk"
#: elevator.lua
msgid "(current position)"
msgstr "(aktuelle Position)"
#: elevator.lua
msgid "Hyperloop Elevator"
msgstr "Hyperloop Aufzug"
#: elevator.lua
msgid "Please insert floor name"
msgstr "Gib den Stockwerknamen ein"
#: elevator.lua
msgid "Floor name"
msgstr "Stockwerkname"
#: elevator.lua
msgid "Base"
msgstr "Basis"
#: elevator.lua wifi.lua
msgid "Save"
msgstr "Speichern"
#: map.lua
msgid "Dist."
msgstr "Entf."
#: map.lua
msgid "Station/Junction"
msgstr "Station/Anschlussstelle"
#: map.lua
msgid "Position"
msgstr "Position"
#: map.lua
msgid "Owner"
msgstr "Besitzer"
#: map.lua
msgid "Conn. with"
msgstr "Verb. mit"
#: map.lua
msgid "Close"
msgstr "Schließen"
#: map.lua
msgid "Hyperloop Station Book"
msgstr "Hyperloop Stationsbuch"
#: seat.lua
msgid "Thank you | for | travelling | with | Hyperloop."
msgstr "Thank you | for | travelling | with | Hyperloop."
#: seat.lua
msgid " | Welcome at | | "
msgstr " | Willkommen | in | | "
#: seat.lua
msgid "[Hyperloop] No booking entered!"
msgstr "[Hyperloop] Keine Buchung eingegeben!"
#: seat.lua
msgid "Destination:"
msgstr "Ziel:"
#: seat.lua
msgid "Distance:"
msgstr "Entfernung:"
#: seat.lua
msgid "Arrival in:"
msgstr "Ankunft in:"
#: seat.lua
msgid "Hyperloop Pod Seat"
msgstr "Hyperloop Sitz"
#: waypoint.lua
msgid "Hyperloop Waypoint"
msgstr "Hyperloop Wegpunkt"
#: station.lua
msgid "Station completed. Now place the Booking Machine!"
msgstr "Station fertig. Setze nun den Fahrkartenautomat!"
#: station.lua
msgid "Area is protected!"
msgstr "Die Area ist geschützt!"
#: station.lua
msgid "Not enough space to build the station!"
msgstr "Nicht ausreichend Platz um die Station zu errichten!"
#: station.lua
msgid "Hyperloop Station Pod Builder"
msgstr "Hyperloop Stations Ersteller"
#: station.lua
msgid "Hyperloop Pod Shell"
msgstr "Hyperloop Kabinenwand"
#: station.lua recipes.lua
msgid "Hypersteel Ingot"
msgstr "Hypersteel Barren"
#: station.lua
msgid "Blue Wool"
msgstr "Blaue Wolle"
#: station.lua
msgid "Glass"
msgstr "Glas"
#: station.lua
msgid "Not enough inventory items to build the station!"
msgstr "Nicht ausreichend Inventory Items um die Station zu bauen!"
#: station.lua
msgid "Destroy Station"
msgstr "Zerstöre Station"
#: station.lua
msgid "Build Station"
msgstr "Baue Station"
#: station.lua
msgid "Hyperloop Station Block"
msgstr "Hyperloop Stations Block"
#: station.lua
msgid "Station"
msgstr "Station"
#: wifi.lua
msgid "Enter channel string"
msgstr "Kanalname eingeben"
#: wifi.lua
msgid "Hyperloop WiFi Tube"
msgstr "Hyperloop Wifi Röhre"
#: deco.lua
msgid "Hyperloop Promo Poster "
msgstr "Hyperloop Werbeposter "
#: deco.lua
msgid "Hyperloop Station Sign"
msgstr "Hyperloop Stationszeichen"
#: deco.lua
msgid "Hyperloop Station Sign Right"
msgstr "Hyperloop Stationszeichen rechts"
#: deco.lua
msgid "Hyperloop Station Sign Left"
msgstr "Hyperloop Stationszeichen links"
#: junction.lua
msgid "Station connected with "
msgstr "Station verbunden mit "
#: junction.lua
msgid "Junction connected with "
msgstr "Anschlussstelle verbunden mit "
#: junction.lua
msgid "Hyperloop Junction Block"
msgstr "Hyperloop Anschlussstelle"
#: junction.lua
msgid "Junction"
msgstr "Anschlussstelle"
#: junction.lua
msgid "Hyperloop Pillar"
msgstr "Hyperloop Stütze"
#: tubecrowbar.lua
msgid "[Crowbar Help]\n"
msgstr "[Brecheisen Hilfe]\n"
#: tubecrowbar.lua
msgid " left: remove node\n"
msgstr " links: entferne Block\n"
#: tubecrowbar.lua
msgid " right: repair tube/shaft line\n"
msgstr " rechts: repariere Röhre/Schacht\n"
#: tubecrowbar.lua
msgid "You don't have the necessary privs!"
msgstr "Du hast nicht die notwendigen Rechte!"
#: tubecrowbar.lua
msgid "Hyperloop Tube Crowbar"
msgstr "Hyperloop Brecheisen"
#~ msgid "Tube connection missing!"
#~ msgstr "Anschluss an eine Röhre fehlt!"
#~ msgid "Hypersteel Pod Shell"
#~ msgstr "Hyperloop Kabinenwand"

View File

@ -0,0 +1,142 @@
# textdomain: hyperloop
### booking.lua ###
Station data is corrupted. Please rebuild the station!=Stationsdaten sind beschädigt. Bitte die Station neu bauen!
Station is still blocked. Please try again in a few seconds!=Die Station ist noch blockiert. Bitte versuche es in ein paar Sekunden wieder!
### booking_node.lua ###
Please enter the station name to@nwhich this booking machine belongs.=Bitte gib den Stationsnamen ein@nzu dem dieser Fahrkartenautomat gehört.
Station name=Stationsname
Additional station information=Zusätzliche Stationsinformationen
Station has already a booking machine!=Station hat bereits einen Fahrkartenautomat!
Invalid station name!=Ungültiger Stationsname!
Hyperloop Booking Machine=Hyperloop Fahrkartenautomat
### booking_node.lua ###
### elevator.lua ###
Select your destination=Wähle dein Ziel
### booking_node.lua ###
### migrate.lua ###
<unknown>=<unbekannt>
### deco.lua ###
Hyperloop Promo Poster =Hyperloop Werbeposter
Hyperloop Station Sign=Hyperloop Stationszeichen
Hyperloop Station Sign Right=Hyperloop Stationszeichen rechts
Hyperloop Station Sign Left=Hyperloop Stationszeichen links
### door.lua ###
The Booking Machine for this station is missing!=Der Fahrkartenautomat für die Station fehlt!
Hyperloop Door Top=Hyperloop Tür Oberteil
Hyperloop Door Bottom=Hyperloop Tür Unterteil
### elevator.lua ###
Hyperloop Elevator Shaft=Hyperloop Aufzugsschacht
Destination=Ziel
Floor=Stockwerk
(current position)=(aktuelle Position)
Hyperloop Elevator=Hyperloop Aufzug
Please insert floor name=Gib den Stockwerknamen ein
Floor name=Stockwerkname
Base=Basis
### elevator.lua ###
### wifi.lua ###
Save=Speichern
### junction.lua ###
Station connected to =Station verbunden mit
Junction connected to =Anschlussstelle verbunden mit
Hyperloop Junction Block=Hyperloop Anschlussstelle
Hyperloop Pillar=Hyperloop Stütze
### junction.lua ###
### migrate.lua ###
Junction=Anschlussstelle
### lcd.lua ###
Hyperloop Display=Hyperloop Bildschirm
### map.lua ###
Dist.=Entf.
Station/Junction=Station/Anschlussstelle
Position=Position
Owner=Besitzer
Conn. to=Verb. mit
Close=Schließen
Hyperloop Station Book=Hyperloop Stationsbuch
### migrate.lua ###
Hyperloop Legacy Tube=Hyperloop veraltetes Rohr
unknown=unbekant
### recipes.lua ###
### station.lua ###
Hypersteel Ingot=Hyperstahl Barren
### seat.lua ###
[Hyperloop] No booking entered!=[Hyperloop] Keine Buchung eingegeben!
Hyperloop Pod Seat=Hyperloop Sitz
### station.lua ###
Station completed. Now place the Booking Machine!=Station fertig. Setze nun den Fahrkartenautomat!
Area is protected!=Die Area ist geschützt!
Not enough space to build the station!=Nicht ausreichend Platz um die Station zu errichten!
Hyperloop Station Pod Builder=Hyperloop Stations Ersteller
Hyperloop Pod Shell=Hyperloop Kabinenwand
Blue Wool=Blaue Wolle
Glass=Glas
Not enough inventory items to build the station!=Nicht ausreichend Inventory Items um die Station zu bauen!
Destroy Station=Zerstöre Station
Build Station=Baue Station
Hyperloop Station Block=Hyperloop Stations Block
Station=Station
### tube.lua ###
Junction at =Anschlussstelle bei
Station '=Station '
Station at =Station bei
Open end at =Offenes Ende bei
There is no station/junction on this level. =Es gibt keine Station/Anschlussstelle auf dieser Höhe.
Do you really want to start a new network?!=Willst du wirklich ein neues Liniennetz beginnen?!
Hyperloop Tube=Hyperloop Röhre
### tubecrowbar.lua ###
[Hyperloop] Error: Tube is too long!=[Hyperloop] Fehler: Röhre ist zu lang!
[Crowbar Help]@n=[Brecheisen Hilfe]@n
left: remove node@n= links: entferne Block@n
right: repair tube/shaft line@n= rechts: repariere Röhre/Schacht@n
You don't have the necessary privs!=Du hast nicht die notwendigen Rechte!
Hyperloop Tube Crowbar=Hyperloop Brecheisen
Rights to remove tube nodes by means of the crowbar=Rechte zur Entfernung von Rohrknoten mit Hilfe der Brechstange
Repair via WorldEdit placed Hyperloop tubes by reusing WorldEdit pos1/pos2=Reparatur über WorldEdit platzierte Hyperloop-Röhren durch Wiederverwendung von WorldEdit pos1/pos2
### waypoint.lua ###
Hyperloop Waypoint=Hyperloop Wegpunkt
### wifi.lua ###
Enter channel string=Kanalname eingeben
Hyperloop WiFi Tube=Hyperloop Wifi Röhre

View File

@ -0,0 +1,304 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-22 11:22+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: booking.lua
msgid "Station data is corrupted. Please rebuild the station!"
msgstr ""
#: booking.lua
msgid "Station is still blocked. Please try again in a few seconds!"
msgstr ""
#: door.lua
msgid "The Booking Machine for this station is missing!"
msgstr ""
#: lcd.lua
msgid "Hyperloop Display"
msgstr ""
#: lcd.lua seat.lua
msgid " | | << Hyperloop >> | be anywhere"
msgstr ""
#: tube.lua
msgid "Junction at "
msgstr ""
#: tube.lua
msgid "There is no station/junction on this level. "
msgstr ""
#: tube.lua
msgid "Do you really want to start a new network?!"
msgstr ""
#: tube.lua
msgid "Hyperloop Tube"
msgstr ""
#: booking_node.lua elevator.lua
msgid "Select your destination"
msgstr ""
#: booking_node.lua elevator.lua
msgid "Destination"
msgstr ""
#: booking_node.lua
msgid "Distance"
msgstr ""
#: booking_node.lua
msgid "Local Info"
msgstr ""
#: booking_node.lua
msgid ""
"Please enter the station name to\n"
"which this booking machine belongs."
msgstr ""
#: booking_node.lua
msgid "Station name"
msgstr ""
#: booking_node.lua
msgid "Additional station information"
msgstr ""
#: booking_node.lua
msgid "Station has already a booking machine!"
msgstr ""
#: booking_node.lua
msgid "Invalid station name!"
msgstr ""
#: booking_node.lua
msgid "Hyperloop Booking Machine"
msgstr ""
#: elevator.lua
msgid "Hyperloop Elevator Shaft"
msgstr ""
#: elevator.lua
msgid "Floor"
msgstr ""
#: elevator.lua
msgid "(current position)"
msgstr ""
#: elevator.lua
msgid "Hyperloop Elevator"
msgstr ""
#: elevator.lua
msgid "Please insert floor name"
msgstr ""
#: elevator.lua
msgid "Floor name"
msgstr ""
#: elevator.lua
msgid "Base"
msgstr ""
#: elevator.lua wifi.lua
msgid "Save"
msgstr ""
#: map.lua
msgid "Dist."
msgstr ""
#: map.lua
msgid "Station/Junction"
msgstr ""
#: map.lua
msgid "Position"
msgstr ""
#: map.lua
msgid "Owner"
msgstr ""
#: map.lua
msgid "Conn. with"
msgstr ""
#: map.lua
msgid "Close"
msgstr ""
#: map.lua
msgid "Hyperloop Station Book"
msgstr ""
#: seat.lua
msgid "Thank you | for | travelling | with | Hyperloop."
msgstr ""
#: seat.lua
msgid " | Welcome at | | "
msgstr ""
#: seat.lua
msgid "[Hyperloop] No booking entered!"
msgstr ""
#: seat.lua
msgid "Destination:"
msgstr ""
#: seat.lua
msgid "Distance:"
msgstr ""
#: seat.lua
msgid "Arrival in:"
msgstr ""
#: seat.lua
msgid "Hyperloop Pod Seat"
msgstr ""
#: waypoint.lua
msgid "Hyperloop Waypoint"
msgstr ""
#: station.lua
msgid "Station completed. Now place the Booking Machine!"
msgstr ""
#: station.lua
msgid "Area is protected!"
msgstr ""
#: station.lua
msgid "Not enough space to build the station!"
msgstr ""
#: station.lua
msgid "Hyperloop Station Pod Builder"
msgstr ""
#: station.lua
msgid "Hyperloop Pod Shell"
msgstr ""
#: station.lua recipes.lua
msgid "Hypersteel Ingot"
msgstr ""
#: station.lua
msgid "Blue Wool"
msgstr ""
#: station.lua
msgid "Glass"
msgstr ""
#: station.lua
msgid "Not enough inventory items to build the station!"
msgstr ""
#: station.lua
msgid "Destroy Station"
msgstr ""
#: station.lua
msgid "Build Station"
msgstr ""
#: station.lua
msgid "Hyperloop Station Block"
msgstr ""
#: station.lua
msgid "Station"
msgstr ""
#: wifi.lua
msgid "Enter channel string"
msgstr ""
#: wifi.lua
msgid "Hyperloop WiFi Tube"
msgstr ""
#: deco.lua
msgid "Hyperloop Promo Poster "
msgstr ""
#: deco.lua
msgid "Hyperloop Station Sign"
msgstr ""
#: deco.lua
msgid "Hyperloop Station Sign Right"
msgstr ""
#: deco.lua
msgid "Hyperloop Station Sign Left"
msgstr ""
#: junction.lua
msgid "Station connected with "
msgstr ""
#: junction.lua
msgid "Junction connected with "
msgstr ""
#: junction.lua
msgid "Hyperloop Junction Block"
msgstr ""
#: junction.lua
msgid "Junction"
msgstr ""
#: junction.lua
msgid "Hyperloop Pillar"
msgstr ""
#: tubecrowbar.lua
msgid "[Crowbar Help]\n"
msgstr ""
#: tubecrowbar.lua
msgid " left: remove node\n"
msgstr ""
#: tubecrowbar.lua
msgid " right: repair tube/shaft line\n"
msgstr ""
#: tubecrowbar.lua
msgid "You don't have the necessary privs!"
msgstr ""
#: tubecrowbar.lua
msgid "Hyperloop Tube Crowbar"
msgstr ""

View File

@ -0,0 +1,142 @@
# textdomain: hyperloop
### booking.lua ###
Station data is corrupted. Please rebuild the station!=
Station is still blocked. Please try again in a few seconds!=
### booking_node.lua ###
Please enter the station name to@nwhich this booking machine belongs.=
Station name=
Additional station information=
Station has already a booking machine!=
Invalid station name!=
Hyperloop Booking Machine=
### booking_node.lua ###
### elevator.lua ###
Select your destination=
### booking_node.lua ###
### migrate.lua ###
<unknown>=
### deco.lua ###
Hyperloop Promo Poster =
Hyperloop Station Sign=
Hyperloop Station Sign Right=
Hyperloop Station Sign Left=
### door.lua ###
The Booking Machine for this station is missing!=
Hyperloop Door Top=
Hyperloop Door Bottom=
### elevator.lua ###
Hyperloop Elevator Shaft=
Destination=
Floor=
(current position)=
Hyperloop Elevator=
Please insert floor name=
Floor name=
Base=
### elevator.lua ###
### wifi.lua ###
Save=
### junction.lua ###
Station connected with =
Junction connected with =
Hyperloop Junction Block=
Hyperloop Pillar=
### junction.lua ###
### migrate.lua ###
Junction=
### lcd.lua ###
Hyperloop Display=
### map.lua ###
Dist.=
Station/Junction=
Position=
Owner=
Conn. with=
Close=
Hyperloop Station Book=
### migrate.lua ###
Hyperloop Legacy Tube=
unknown=
### recipes.lua ###
### station.lua ###
Hypersteel Ingot=
### seat.lua ###
[Hyperloop] No booking entered!=
Hyperloop Pod Seat=
### station.lua ###
Station completed. Now place the Booking Machine!=
Area is protected!=
Not enough space to build the station!=
Hyperloop Station Pod Builder=
Hyperloop Pod Shell=
Blue Wool=
Glass=
Not enough inventory items to build the station!=
Destroy Station=
Build Station=
Hyperloop Station Block=
Station=
### tube.lua ###
Junction at =
Station '=
Station at =
Open end at =
There is no station/junction on this level. =
Do you really want to start a new network?!=
Hyperloop Tube=
### tubecrowbar.lua ###
[Hyperloop] Error: Tube is too long!=
[Crowbar Help]@n=
left: remove node@n=
right: repair tube/shaft line@n=
You don't have the necessary privs!=
Hyperloop Tube Crowbar=
Rights to remove tube nodes by means of the crowbar=
Repair via WorldEdit placed Hyperloop tubes by reusing WorldEdit pos1/pos2=
### waypoint.lua ###
Hyperloop Waypoint=
### wifi.lua ###
Enter channel string=
Hyperloop WiFi Tube=

126
mods/vents/map.lua Normal file
View File

@ -0,0 +1,126 @@
--[[
Hyperloop Mod
=============
Copyright (C) 2017-2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
]]--
-- for lazy programmers
local SP = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local S = vents.S
local NS = vents.NS
local Stations = vents.Stations
-- Return a text block with all given station names and their attributes
local function generate_string(sortedList)
-- Generate a list with lStationPositions[pos] = idx
-- used to generate the "connected with" list.
local lStationPositions = {}
for idx,item in ipairs(sortedList) do
local sKey = SP(item.pos)
lStationPositions[sKey] = idx
end
local tRes = {
"label[0,0;ID]"..
"label[0.7,0;"..S("Dist.").."]"..
"label[1.8,0;"..S("Station/Junction").."]"..
"label[5.4,0;"..S("Position").."]"..
"label[7.9,0;"..S("Owner").."]"..
"label[10,0;"..S("Conn. to").."]"}
for idx,dataSet in ipairs(sortedList) do
if idx == 23 then
break
end
local ypos = 0.2 + idx * 0.4
local owner = dataSet.owner or "<unknown>"
local name = dataSet.name or "<unknown>"
local distance = dataSet.distance or 0
tRes[#tRes+1] = "label[0,"..ypos..";"..idx.."]"
tRes[#tRes+1] = "label[0.7,"..ypos..";"..distance.." m]"
tRes[#tRes+1] = "label[1.8,"..ypos..";"..string.sub(name,1,24).."]"
tRes[#tRes+1] = "label[5.4,"..ypos..";"..SP(dataSet.pos).."]"
tRes[#tRes+1] = "label[7.9,"..ypos..";"..string.sub(owner,1,14).."]"
tRes[#tRes+1] = "label[10,"..ypos..";"
for dir,conn in pairs(dataSet.conn) do
if conn and lStationPositions[conn] then
tRes[#tRes + 1] = lStationPositions[conn]
tRes[#tRes + 1] = ", "
else
tRes[#tRes + 1] = conn
tRes[#tRes + 1] = ", "
end
end
tRes[#tRes] = "]"
end
return table.concat(tRes)
end
local function station_list_as_string(pos)
-- Generate a distance sorted list of all stations
local sortedList = Stations:station_list(pos, nil, "dist")
-- Generate the formspec string
return generate_string(sortedList)
end
local function network_list_as_string(pos)
-- Determine next station position
local next_pos = Stations:get_next_station(pos)
-- Generate a distance sorted list of all connected stations
local sortedList = Stations:station_list(pos, next_pos, "dist")
-- Generate the formspec string
return generate_string(sortedList)
end
local function map_on_use(itemstack, user)
local player_name = user:get_player_name()
local pos = user:get_pos()
local sStationList = station_list_as_string(pos)
local formspec = "size[12,10]" ..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
sStationList ..
"button_exit[5,9.5;2,1;close;"..S("Close").."]"
minetest.show_formspec(player_name, "vents:station_map", formspec)
return itemstack
end
local function map_on_secondary_use(itemstack, user)
local player_name = user:get_player_name()
local pos = user:get_pos()
local sStationList = network_list_as_string(pos)
local formspec = "size[12,10]" ..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
sStationList ..
"button_exit[5,9.5;2,1;close;"..S("Close").."]"
minetest.show_formspec(player_name, "vents:station_map", formspec)
return itemstack
end
-- Tool for tube workers to find the next station
minetest.register_node("vents:station_map", {
description = S("Hyperloop Station Book"),
inventory_image = "hyperloop_stations_book.png",
wield_image = "hyperloop_stations_book.png",
groups = {cracky=1, book=1},
on_use = map_on_use,
on_place = map_on_secondary_use,
on_secondary_use = map_on_secondary_use,
stack_max = 1,
})

3
mods/vents/mod.conf Normal file
View File

@ -0,0 +1,3 @@
name = vents
depends = tubelib2
optional_depends = worldedit, intllib

288
mods/vents/network.lua Normal file
View File

@ -0,0 +1,288 @@
--[[
Hyperloop Mod
=============
Copyright (C) 2017-2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
Station and elevator network management
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Convert to list and add pos based on key string
local function table_to_list(table)
local lRes = {}
for key,item in pairs(table) do
item.pos = P(key)
lRes[#lRes+1] = item
end
return lRes
end
local function distance(pos1, pos2)
return math.floor(math.abs(pos1.x - pos2.x) +
math.abs(pos1.y - pos2.y) + math.abs(pos1.z - pos2.z))
end
-- Add the distance to pos to each list item
local function add_distance_to_list(lStations, pos)
for _,item in ipairs(lStations) do
item.distance = distance(item.pos, pos)
end
return lStations
end
-- Add the index to each list item
local function add_index_to_list(lStations)
-- walk through the list of floors for the next connection
local get_next = function(key, idx)
for _,floor in ipairs(lStations) do
if floor.conn[6] == key then -- upward match?
floor.idx = idx
return S(floor.pos) -- return floor key
end
end
end
local key = nil
for idx = 1,#lStations do
key = get_next(key, idx)
end
return lStations
end
-- Return a table with all stations, the given station (as 'sKey') is connected with
-- tRes is used for the resulting table (recursive call)
local function get_stations(tStations, sKey, tRes)
if not tStations[sKey] or not tStations[sKey].conn then
return {}
end
for dir,dest in pairs(tStations[sKey].conn) do
-- Not already visited?
if not tRes[dest] then
-- Known station?
if tStations[dest] then
tStations[dest].name = tStations[dest].name or ""
tRes[dest] = tStations[dest]
get_stations(tStations, dest, tRes)
end
end
end
return tRes
end
-- Return a list with sorted elevators, beginning with the top car
-- with no shaft upwards
local function sort_based_on_level(tStations)
local lStations = table_to_list(table.copy(tStations))
-- to be able to sort the list, an index has to be added
lStations = add_index_to_list(lStations)
table.sort(lStations, function(a,b) return (a.idx or 9999) < (b.idx or 9999) end)
return lStations
end
-- Return a list with sorted stations
local function sort_based_on_distance(tStations, pos)
local lStations = table_to_list(table.copy(tStations))
-- to be able to sort the list, the distance to pos has to be added
lStations = add_distance_to_list(lStations, pos)
table.sort(lStations, function(a,b) return a.distance < b.distance end)
return lStations
end
-- Return a list with sorted stations
local function sort_based_on_name(tStations, pos)
local lStations = table_to_list(table.copy(tStations))
-- Add distance
lStations = add_distance_to_list(lStations, pos)
table.sort(lStations, function(a,b) return a.name < b.name end)
return lStations
end
--
-- Class Network
--
--[[
tStations["(x,y,z)"] = {
["conn"] = {
dir = "(200,0,20)",
},
}
change_counter = n,
]]--
local Network = {}
vents.Network = Network
function Network:new()
local o = {
tStations = {},
change_counter = 0,
}
setmetatable(o, self)
self.__index = self
return o
end
-- Set an elevator or station entry.
-- tAttr is a table with additional attributes to be stored.
function Network:set(pos, name, tAttr)
if pos then
local sKey = S(pos)
if not self.tStations[sKey] then
self.tStations[sKey] = {
conn = {},
}
end
self.tStations[sKey].name = name or ""
for k,v in pairs(tAttr) do
self.tStations[sKey][k] = v
end
self.change_counter = self.change_counter + 1
end
end
-- Update an elevator or station entry.
-- tAttr is a table with additional attributes to be stored.
function Network:update(pos, tAttr)
if pos then
local sKey = S(pos)
if self.tStations[sKey] then
for k,v in pairs(tAttr) do
if v == "nil" then
self.tStations[sKey][k] = nil
else
self.tStations[sKey][k] = v
end
end
self.change_counter = self.change_counter + 1
end
end
end
function Network:get(pos)
return pos and self.tStations[S(pos)]
end
-- Delete an elevator or station entry.
function Network:delete(pos)
if pos then
self.tStations[S(pos)] = nil
self.change_counter = self.change_counter + 1
end
end
function Network:changed(counter)
return self.change_counter > counter, self.change_counter
end
-- Update the connection data base. The output dir information is needed
-- to be able to delete a connection, if necessary.
-- Returns true, if data base is changed.
function Network:update_connections(pos, out_dir, conn_pos)
local sKey = S(pos)
local res = false
if not self.tStations[sKey] then
self.tStations[sKey] = {}
res = true
end
if not self.tStations[sKey].conn then
self.tStations[sKey].conn = {}
res = true
end
conn_pos = S(conn_pos)
if self.tStations[sKey].conn[out_dir] ~= conn_pos then
self.tStations[sKey].conn[out_dir] = conn_pos
res = true
end
if res then
self.change_counter = self.change_counter + 1
end
return res
end
-- Return the nearest station position
function Network:get_next_station(pos)
local min_dist = 999999
local min_key = nil
local dist
for key,item in pairs(self.tStations) do
if not item.junction then
dist = distance(pos, P(key))
if dist < min_dist then
min_dist = dist
min_key = key
end
end
end
return P(min_key)
end
-- Return a sorted list of stations
-- Param pos: player pos
-- Param station_pos: next station pos or nil.
-- Used to generate list with connected stations only
-- Param sorted: either "dist" or "level"
function Network:station_list(pos, station_pos, sorted)
local tStations, lStations
if station_pos then
local tRes = {}
tStations = get_stations(self.tStations, S(station_pos), tRes) -- reduced
else
tStations = self.tStations -- all stations
end
if sorted == "dist" then
lStations = sort_based_on_distance(tStations, pos)
elseif sorted == "level" then
lStations = sort_based_on_level(tStations)
else
-- delete own station from list
tStations[S(station_pos)] = nil
lStations = sort_based_on_name(tStations, pos)
end
return lStations
end
-- Check the complete table by means of the provided callback bool = func(pos)
function Network:filter(callback)
local lKeys = {}
for key,_ in pairs(self.tStations) do
lKeys[#lKeys+1] = key
end
for _,key in ipairs(lKeys) do
if not callback(P(key)) then
self.tStations[key] = nil
end
end
end
function Network:deserialize(data)
if data ~= "" then
data = minetest.deserialize(data)
self.tStations = data.tStations
self.change_counter = data.change_counter
end
end
function Network:serialize()
return minetest.serialize(self)
end
-- Return a pos/item table with all network nodes, the node at pos is connected with
function Network:get_node_table(pos)
local tRes = {}
local key = S(pos)
get_stations(self.tStations, key, tRes)
tRes[key] = nil
return tRes
end

62
mods/vents/pod.lua Normal file
View File

@ -0,0 +1,62 @@
--[[
Hyperloop Mod
=============
Copyright (C) 2017 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
History:
see init.lua
]]--
function vents.enter_display(seat_pos, facedir, text)
if seat_pos == nil then
return
end
-- determine position
local pos = vector.add(seat_pos, vents.placedir_to_dir(facedir))
pos.y = pos.y + 1
-- load map
minetest.forceload_block(pos)
-- update display
minetest.registered_nodes["vents:lcd"].update(pos, text)
end
-- to build the pod
minetest.register_node("vents:pod_wall", {
description = "Hyperloop Pod Shell",
tiles = {
-- up, down, right, left, back, front
"hyperloop_skin2.png",
"hyperloop_skin2.png",
"hyperloop_skin.png",
"hyperloop_skin.png",
"hyperloop_skin.png",
"hyperloop_skin.png",
},
paramtype2 = "facedir",
groups = {cracky=1, stone = 2},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
-- for tube viaducts
minetest.register_node("vents:pillar", {
description = "Hyperloop Pillar",
tiles = {"hyperloop_tube_locked.png^[transformR90]"},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -3/8, -4/8, -3/8, 3/8, 4/8, 3/8},
},
},
is_ground_content = false,
groups = {cracky = 2, stone = 2},
sounds = default.node_sound_metal_defaults(),
})

161
mods/vents/robot.lua Normal file
View File

@ -0,0 +1,161 @@
--[[
Hyperloop Mod
=============
Copyright (C) 2017 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
History:
see init.lua
]]--
local function get_inventory_item(inv)
local stack = ItemStack("vents:tube0")
local taken = inv:remove_item("src", stack)
return taken:get_count() == 1
end
local function get_inventory(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local stack = ItemStack("vents:tube0 99")
return inv:remove_item("src", stack)
end
local function set_inventory(pos, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:add_item("src", stack)
return inv
end
local function allow_metadata_inventory(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function place_tube(pos, name, facedir, placer)
if minetest.is_protected(pos, placer:get_player_name()) then
vents.chat(placer, "Area is protected!")
return false
end
node = minetest.get_node(pos)
if node.name ~= "air" and node.name ~= "default:water_source" and node.name ~= "default:water_flowing" then
return false
end
if vents.scan_neighbours(pos) ~= 1 then
return false
end
minetest.add_node(pos, {name=name, param2=facedir})
minetest.registered_nodes[name].after_place_node(pos, placer, nil, nil)
return true
end
local function move_robot(pos, inv, facedir, placer)
if minetest.get_meta(pos):get_int("stopped") ~= 1 then
if get_inventory_item(inv) then
-- remve robot and replace through tube
local stack = get_inventory(pos)
minetest.remove_node(pos)
place_tube(pos, "vents:tube1", facedir, placer)
-- place robot on the new position
pos = vents.new_pos(pos, facedir, "1F", 0)
if place_tube(pos, "vents:robot", facedir, placer) then
inv = set_inventory(pos, stack)
minetest.after(1, move_robot, pos, inv, facedir, placer)
else
pos = vents.new_pos(pos, facedir, "1B", 0)
minetest.remove_node(pos)
place_tube(pos, "vents:robot", facedir, placer)
stack:add_item("src", ItemStack("vents:tube0"))
set_inventory(pos, stack)
end
end
end
end
local station_formspec =
"size[8,8]"..
"label[3,0;Hyperloop Tube Robot]" ..
"label[1,1.3;Hyperloop Tubes]" ..
"list[context;src;3,1;1,1;]"..
"button_exit[4,1;1,1;button;Start]"..
"list[current_player;main;0,4;8,4;]"..
"listring[context;src]"..
"listring[current_player;main]"
minetest.register_node("vents:robot", {
description = "Hyperloop Tube Robot",
tiles = {
-- up, down, right, left, back, front
"hyperloop_robot.png",
"hyperloop_robot.png",
"hyperloop_robot2.png",
"hyperloop_robot2.png",
"hyperloop_robot2.png",
"hyperloop_robot2.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
local res, nodes = vents.scan_neighbours(pos)
if res == 1 then -- one neighbor available?
local dir = vector.subtract(pos, nodes[1].pos)
local facedir = minetest.dir_to_facedir(dir)
local meta = minetest.get_meta(pos)
meta:set_int("facedir", facedir)
meta:set_string("formspec", station_formspec)
local inv = meta:get_inventory()
inv:set_size('src', 1)
else
vents.chat(player, "You can't start with a Robot block!")
local node = minetest.get_node(pos)
vents.remove_node(pos, node)
return itemstack
end
end,
on_receive_fields = function(pos, formname, fields, player)
if fields.button == nil then
return
end
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local facedir = meta:get_int("facedir")
meta:set_int("stopped", 0)
minetest.after(1, move_robot, pos, inv, facedir, player)
end,
on_punch = function(pos, node, puncher, pointed_thing)
if minetest.is_protected(pos, puncher:get_player_name()) then
return
end
local meta = minetest.get_meta(pos)
meta:set_int("stopped", 1)
end,
on_dig = function(pos, node, puncher, pointed_thing)
if minetest.is_protected(pos, puncher:get_player_name()) then
return
end
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
meta:set_int("stopped", 1)
if inv:is_empty("src") then
minetest.node_dig(pos, node, puncher, pointed_thing)
end
end,
allow_metadata_inventory_put = allow_metadata_inventory,
allow_metadata_inventory_take = allow_metadata_inventory,
on_rotate = screwdriver.disallow,
paramtype2 = "facedir",
groups = {cracky=1},
is_ground_content = false,
})

237
mods/vents/seat.lua Normal file
View File

@ -0,0 +1,237 @@
--[[
Hyperloop Mod
=============
Copyright (C) 2017-2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
]]--
-- for lazy programmers
local SP = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local S = vents.S
local NS = vents.NS
local I, _ = dofile( minetest.get_modpath("vents").."/intllib.lua")
local Stations = vents.Stations
local PlayerNameTags = {}
local function enter_display(tStation, text)
-- determine position
if tStation ~= nil then
local lcd_pos = vents.new_pos(tStation.pos, tStation.facedir, "1F", 2)
-- update display
minetest.registered_nodes["vents:lcd"].update(lcd_pos, text)
end
end
local function on_final_close_door(tStation)
-- close the door and play sound if no player is around
if vents.is_player_around(tStation.pos) then
-- try again later
minetest.after(3.0, on_final_close_door, tStation)
else
vents.close_pod_door(tStation)
enter_display(tStation, I(" | | << Hyperloop >> | be anywhere"))
end
end
local function on_open_door(tArrival)
-- open the door and play sound
local meta = minetest.get_meta(tArrival.pos)
meta:set_int("arrival_time", 0) -- finished
-- open door
vents.open_pod_door(tArrival)
-- prepare display for the next trip
enter_display(tArrival, I("Thank you | for | travelling | with | vents."))
minetest.after(5.0, on_final_close_door, tArrival, tArrival.facedir)
end
local function on_arrival(tDeparture, tArrival, player_name, sound)
local player = minetest.get_player_by_name(player_name)
-- activate display
local text = I(" | Welcome at | | ")..string.sub(tArrival.name, 1, 13)
enter_display(tArrival, text)
-- stop timer
minetest.get_node_timer(tDeparture.pos):stop()
-- move player to the arrival station
if player ~= nil then
local pos = table.copy(tArrival.pos)
pos.y = pos.y + 0.5
player:set_pos(pos)
-- rotate player to look in correct arrival direction
-- calculate the look correction
-- workaround to prevent server crashes
local val1 = vents.facedir_to_rad(tDeparture.facedir)
local val2 = player:get_look_horizontal()
if val1 ~= nil and val2 ~= nil then
local offs = val1 - val2
local yaw = vents.facedir_to_rad(tArrival.facedir) - offs
player:set_look_yaw(yaw)
end
-- set player name again
if PlayerNameTags[player_name] then
player:set_nametag_attributes(PlayerNameTags[player_name])
PlayerNameTags[player_name] = nil
end
end
-- play arrival sound
minetest.sound_stop(sound)
minetest.sound_play("down2", {
pos = tArrival.pos,
gain = 0.5,
max_hear_distance = 2
})
minetest.after(4.0, on_open_door, tArrival)
end
local function on_travel(tDeparture, tArrival, player_name, atime)
-- play sound and switch door state
local sound = minetest.sound_play("normal2", {
pos = tDeparture.pos,
gain = 0.5,
max_hear_distance = 2,
loop = true,
})
vents.animate_pod_door(tDeparture)
minetest.after(atime, on_arrival, tDeparture, tArrival, player_name, sound)
minetest.after(atime, on_final_close_door, tDeparture)
end
local function display_timer(pos, elapsed)
-- update display with trip data
local tStation = vents.get_base_station(pos)
if tStation then
local meta = M(pos)
local atime = meta:get_int("arrival_time") - 1
meta:set_int("arrival_time", atime)
local text = meta:get_string("lcd_text")
if atime > 2 then
enter_display(tStation, text..atime.." sec")
return true
else
return false
end
end
return false
end
local function meter_to_km(dist)
if dist < 1000 then
return tostring(dist).." m"
elseif dist < 10000 then
return string.format("%.3f km", dist/1000)
else
return string.format("%.1f km", dist/1000)
end
end
-- place the player, close the door, activate display
local function on_start_travel(pos, node, clicker)
-- arrival data
local meta = M(pos)
local player_name = clicker:get_player_name()
local tDeparture, departure_pos = vents.get_base_station(pos)
local arrival_pos = vents.get_arrival(departure_pos)
if arrival_pos == nil then
minetest.chat_send_player(player_name, S("[Hyperloop] No booking entered!"))
return
end
local tArrival = vents.get_station(arrival_pos)
if tDeparture == nil or tArrival == nil then
return
end
minetest.sound_play("up2", {
pos = pos,
gain = 0.5,
max_hear_distance = 2
})
-- close the door at arrival station
vents.close_pod_door(tArrival)
-- place player on the seat
pos.y = pos.y - 0.5
clicker:set_pos(pos)
-- rotate player to look in move direction
clicker:set_look_horizontal(vents.facedir_to_rad(tDeparture.facedir))
-- hide player name
PlayerNameTags[player_name] = clicker:get_nametag_attributes()
clicker:set_nametag_attributes({text = " "})
-- activate display
local dist = vents.distance(pos, tArrival.pos)
local text = I("Destination:").." | "..string.sub(tArrival.name, 1, 13).." | "..I("Distance:").." | "..
meter_to_km(dist).." | "..I("Arrival in:").." | "
local atime
if dist < 1000 then
atime = 10 + math.floor(dist/200) -- 10..15 sec
elseif dist < 10000 then
atime = 15 + math.floor(dist/600) -- 16..32 sec
else
atime = 32 -- 32 sec is the maximum
end
enter_display(tDeparture, text..atime.." sec")
-- block departure and arrival stations
vents.block(departure_pos, arrival_pos, atime+10)
-- store some data for on_timer()
meta:set_int("arrival_time", atime)
meta:set_string("lcd_text", text)
minetest.get_node_timer(pos):start(1.0)
vents.close_pod_door(tDeparture)
atime = atime - 7 -- substract start/arrival time
minetest.after(4.9, on_travel, tDeparture, tArrival, player_name, atime)
end
-- Hyperloop Seat
minetest.register_node("vents:seat", {
description = S("Hyperloop Pod Seat"),
tiles = {
"hyperloop_seat-top.png",
"hyperloop_seat-side.png",
"hyperloop_seat-side.png",
"hyperloop_seat-side.png",
"hyperloop_seat-side.png",
"hyperloop_seat-side.png",
},
drawtype = "nodebox",
paramtype = 'light',
light_source = 1,
paramtype2 = "facedir",
is_ground_content = false,
walkable = false,
drop = "",
groups = {not_in_creative_inventory=1, breakable=1},
node_box = {
type = "fixed",
fixed = {
{ -6/16, -8/16, -8/16, 6/16, -2/16, 5/16},
{ -8/16, -8/16, -8/16, -6/16, 4/16, 8/16},
{ 6/16, -8/16, -8/16, 8/16, 4/16, 8/16},
{ -6/16, -8/16, 4/16, 6/16, 6/16, 8/16},
},
},
selection_box = {
type = "fixed",
fixed = { -8/16, -8/16, -8/16, 8/16, -2/16, 8/16 },
},
on_timer = display_timer,
on_rightclick = on_start_travel,
on_rotate = screwdriver.disallow,
auto_place_node = function(pos, facedir, sStationPos)
M(pos):set_string("sStationPos", sStationPos)
end,
})

View File

@ -0,0 +1,15 @@
# Enable WiFi blocks (exclude recipe)
hyperloop_wifi_enabled (WiFi block enabled) bool false
# Enable WiFi block crafting
hyperloop_wifi_crafting_enabled (WiFi block crafting enabled) bool false
# Enable free tube placement with no level limitation.
# If disabled, connected stations have to be on one level,
# typically underground.
hyperloop_free_tube_placement_enabled (free tube placement enabled) bool false
# The ticket block has an additional field for specifying a subnet name.
# Stations with the same subnet name (optional) represent an isolated
# subnet within the Hyperloop network.
hyperloop_subnet_enabled (enable building of subnets) bool true

105
mods/vents/shaft.lua Normal file
View File

@ -0,0 +1,105 @@
--[[
Hyperloop Mod
=============
Copyright (C) 2017 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
History:
see init.lua
]]--
-- simple shaft without logic or "memory"
minetest.register_node("vents:shaft", {
description = "Hyperloop Elevator Shaft",
tiles = {
-- up, down, right, left, back, front
'hyperloop_tube_open.png',
'hyperloop_tube_open.png',
"hyperloop_tube_locked.png^[transformR90]",
"hyperloop_tube_locked.png^[transformR90]",
"hyperloop_tube_locked.png^[transformR90]",
"hyperloop_tube_locked.png^[transformR90]",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
local npos = table.copy(pos)
-- check above
npos.y = npos.y + 1
if minetest.get_node_or_nil(npos).name == "vents:shaft" then
local node = minetest.get_node(npos)
node.name = "vents:shaft2"
minetest.swap_node(npos, node)
return
elseif minetest.get_node_or_nil(npos).name == "vents:elevator_top" then
npos.y = npos.y - 1
vents.update_elevator(npos)
npos.y = npos.y + 1
return
end
-- check below
npos.y = npos.y - 2
if minetest.get_node_or_nil(npos).name == "vents:shaft" then
local node = minetest.get_node(npos)
node.name = "vents:shaft2"
minetest.swap_node(npos, node)
elseif minetest.get_node_or_nil(npos).name == "vents:elevator_top" then
npos.y = npos.y - 1
vents.update_elevator(npos)
else
minetest.remove_node(pos)
return itemstack
end
end,
after_destruct = function(pos)
local npos = table.copy(pos)
npos.y = npos.y - 1
if minetest.get_node_or_nil(npos).name == "vents:shaft2" then
local node = minetest.get_node(npos)
node.name = "vents:shaft"
minetest.swap_node(npos, node)
elseif minetest.get_node_or_nil(npos).name == "vents:elevator_top" then
npos.y = npos.y - 1
vents.update_elevator(npos)
end
npos.y = npos.y + 2
if minetest.get_node_or_nil(npos).name == "vents:shaft2" then
local node = minetest.get_node(npos)
node.name = "vents:shaft"
minetest.swap_node(npos, node)
end
end,
on_rotate = screwdriver.disallow,
light_source = 6,
paramtype2 = "facedir",
groups = {breakable=1},
is_ground_content = false,
})
-- simple shaft without logic or "memory"
minetest.register_node("vents:shaft2", {
description = "Hyperloop Elevator Shaft",
tiles = {
-- up, down, right, left, back, front
"hyperloop_tube_locked.png^[transformR90]",
"hyperloop_tube_locked.png^[transformR90]",
"hyperloop_tube_locked.png^[transformR90]",
"hyperloop_tube_locked.png^[transformR90]",
"hyperloop_tube_locked.png^[transformR90]",
"hyperloop_tube_locked.png^[transformR90]",
},
on_rotate = screwdriver.disallow,
diggable = false,
paramtype2 = "facedir",
groups = {breakable=1, not_in_creative_inventory=1},
is_ground_content = false,
})

BIN
mods/vents/sounds/door.ogg Normal file

Binary file not shown.

BIN
mods/vents/sounds/down2.ogg Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
mods/vents/sounds/up2.ogg Normal file

Binary file not shown.

94
mods/vents/station.lua Normal file
View File

@ -0,0 +1,94 @@
--[[
Hyperloop Mod
=============
Copyright (C) 2017-2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
]]--
-- for lazy programmers
local SP = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local S = vents.S
local NS = vents.NS
local Tube = vents.Tube
local Stations = vents.Stations
local function store_station(pos, placer)
local facedir = vents.get_facedir(placer)
-- do a facedir correction
facedir = (facedir + 3) % 4 -- face to LCD
Stations:set(pos, "Station", {
owner = placer:get_player_name(),
facedir = facedir,
time_blocked = 0})
end
local function naming_formspec(pos)
local formspec =
"size[7,4.4]"..
"label[0,0;"..S("Please enter the vent name.").."]" ..
"field[0.2,1.5;7.1,1;name;"..S("Vent name")..";Vent]" ..
"field[0.2,2.7;7.1,1;info;"..S("Additional vent information")..";]" ..
"button_exit[2.5,3.7;2,1;exit;Save]"
return formspec
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == 'vents:setup' then
if fields.exit then
local name = player:get_player_name()
minetest.chat_send_player(name, 'Saving data')
end
end
end)
minetest.register_node("vents:station", {
description = S("Hyperloop Station Block"),
drawtype = "nodebox",
tiles = {
"hyperloop_station.png",
"hyperloop_station_connection.png",
"hyperloop_station_connection.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
vents.check_network_level(pos, placer)
M(pos):set_string("infotext", S("Access Point"))
store_station(pos, placer)
Tube:after_place_node(pos)
end,
on_rightclick = function(pos, node, clicker)
local name = clicker:get_player_name()
local player_attributes = clicker:get_meta()
local mode = player_attributes:get_string('mode')
if mode == 'traitor' then
minetest.chat_send_player(name,'You can use this!')
elseif mode == 'builder' then
minetest.chat_send_player(name, 'setup the access point please.')
meta = minetest.get_meta(pos)
meta:set_int("change_counter", 0) --No idea what this is for.
minetest.show_formspec(name, 'vents:setup', naming_formspec(pos))
end
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_node(pos)
Stations:delete(pos)
end,
on_rotate = screwdriver.disallow,
paramtype2 = "facedir",
groups = {breakable=1},
is_ground_content = false,
sounds = {footstep = {name = 'metal', gain = 1}},
})

313
mods/vents/station_data.lua Normal file
View File

@ -0,0 +1,313 @@
{
owner = "JoSto",
pos = {
y = 2,
x = 426,
z = 549
},
junction = true,
routes = {
{
"(426,2,550)",
"(426,6,551)"
},
{
"(426,2,548)",
"(426,2,542)"
}
}
}
{
owner = "JoSto",
pos = {
y = 2,
x = 426,
z = 541
},
junction = true,
routes = {
{
"(426,2,542)",
"(426,2,548)"
}
}
}
{
owner = "JoSto",
pos = {
y = 5,
x = 500,
z = 400
},
routes = {
{
"(501,5,400)",
"(502,5,400)"
},
{
"(499,5,400)",
"(401,5,400)"
},
{
"(500,5,401)",
"(500,5,499)"
},
{
"(500,5,399)",
"(400,5,501)"
}
},
junction = true
}
{
owner = "JoSto",
pos = {
y = 5,
x = 400,
z = 400
},
routes = {
{
"(401,5,400)",
"(499,5,400)"
},
{
"(400,5,401)",
"(400,5,499)"
},
{
"(400,5,399)",
"(400,5,398)"
}
},
junction = true
}
{
owner = "JoSto",
pos = {
y = 0,
x = 505,
z = 400
},
facedir = 2,
routes = {
{
"(504,0,400)",
"(503,4,400)"
}
},
time_blocked = 0
}
{
owner = "JoSto",
pos = {
y = 2,
x = 432,
z = 545
},
facedir = 0,
booking_info = "",
routes = {
{
"(432,2,544)",
"(432,2,534)"
}
},
booking_pos = {
y = 4,
x = 430,
z = 545
},
time_blocked = 64894,
station_name = "x"
}
{
owner = "JoSto",
pos = {
y = 5,
x = 503,
z = 400
},
facedir = 1,
station_name = "BBB",
routes = {
{
"(503,4,400)",
"(504,0,400)"
},
{
"(502,5,400)",
"(501,5,400)"
}
},
booking_info = "",
time_blocked = 64716,
booking_pos = {
y = 7,
x = 503,
z = 402
}
}
{
owner = "JoSto",
pos = {
y = 5,
x = 400,
z = 500
},
routes = {
{
"(401,5,500)",
"(499,5,500)"
},
{
"(399,5,500)",
"(398,5,500)"
},
{
"(400,5,501)",
"(500,5,399)"
},
{
"(400,5,499)",
"(400,5,401)"
}
},
junction = true
}
{
owner = "JoSto",
pos = {
y = 5,
x = 500,
z = 503
},
facedir = 1,
routes = {
{
"(500,5,502)",
"(500,5,501)"
}
},
time_blocked = 0
}
{
owner = "JoSto",
pos = {
y = 2,
x = 432,
z = 533
},
facedir = 2,
booking_info = "",
routes = {
{
"(432,2,534)",
"(432,2,544)"
}
},
booking_pos = {
y = 4,
x = 434,
z = 533
},
time_blocked = 64894,
station_name = "y"
}
{
owner = "JoSto",
pos = {
y = 5,
x = 397,
z = 500
},
facedir = 0,
routes = {
{
"(398,5,500)",
"(399,5,500)"
},
{
"(396,5,500)",
"(395,8,500)"
}
},
time_blocked = 0
}
{
owner = "JoSto",
pos = {
y = 8,
x = 394,
z = 500
},
facedir = 1,
station_name = "AAA",
routes = {
{
"(395,8,500)",
"(396,5,500)"
}
},
booking_info = "",
time_blocked = 64716,
booking_pos = {
y = 10,
x = 394,
z = 502
}
}
{
owner = "JoSto",
pos = {
y = 5,
x = 500,
z = 500
},
routes = {
{
"(499,5,500)",
"(401,5,500)"
},
{
"(500,5,501)",
"(500,5,502)"
},
{
"(500,5,499)",
"(500,5,401)"
}
},
junction = true
}
{
owner = "JoSto",
pos = {
y = 5,
x = 400,
z = 397
},
facedir = 3,
routes = {
{
"(400,5,398)",
"(400,5,399)"
}
},
time_blocked = 0
}
{
owner = "JoSto",
pos = {
y = 6,
x = 426,
z = 552
},
routes = {
{
"(426,6,551)",
"(426,2,550)"
}
},
junction = true
}

BIN
mods/vents/textures/_0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

BIN
mods/vents/textures/_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

BIN
mods/vents/textures/_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

BIN
mods/vents/textures/_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

BIN
mods/vents/textures/_4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

BIN
mods/vents/textures/_5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

BIN
mods/vents/textures/_6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

BIN
mods/vents/textures/_7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
mods/vents/textures/_8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

BIN
mods/vents/textures/_9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

BIN
mods/vents/textures/_a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

BIN
mods/vents/textures/_a_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
mods/vents/textures/_b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
mods/vents/textures/_b_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

BIN
mods/vents/textures/_bl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

BIN
mods/vents/textures/_br.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

BIN
mods/vents/textures/_c.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

BIN
mods/vents/textures/_c_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

BIN
mods/vents/textures/_ca.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

BIN
mods/vents/textures/_cl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

BIN
mods/vents/textures/_cm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

BIN
mods/vents/textures/_co.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

BIN
mods/vents/textures/_cr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

BIN
mods/vents/textures/_d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
mods/vents/textures/_d_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

BIN
mods/vents/textures/_dl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

BIN
mods/vents/textures/_dt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

BIN
mods/vents/textures/_dv.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

BIN
mods/vents/textures/_e.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

BIN
mods/vents/textures/_e_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
mods/vents/textures/_eq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

BIN
mods/vents/textures/_ex.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

BIN
mods/vents/textures/_f.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

BIN
mods/vents/textures/_f_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

BIN
mods/vents/textures/_g.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
mods/vents/textures/_g_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
mods/vents/textures/_gt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

BIN
mods/vents/textures/_h.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
mods/vents/textures/_h_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

BIN
mods/vents/textures/_ha.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

BIN
mods/vents/textures/_hs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

BIN
mods/vents/textures/_i.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

BIN
mods/vents/textures/_i_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

BIN
mods/vents/textures/_j.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

BIN
mods/vents/textures/_j_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

BIN
mods/vents/textures/_k.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

BIN
mods/vents/textures/_k_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
mods/vents/textures/_l.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

BIN
mods/vents/textures/_l_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

BIN
mods/vents/textures/_lt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

BIN
mods/vents/textures/_m.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

BIN
mods/vents/textures/_m_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

BIN
mods/vents/textures/_mn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

BIN
mods/vents/textures/_n.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

BIN
mods/vents/textures/_n_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
mods/vents/textures/_o.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

BIN
mods/vents/textures/_o_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

BIN
mods/vents/textures/_p.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
mods/vents/textures/_p_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

BIN
mods/vents/textures/_pr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

BIN
mods/vents/textures/_ps.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

BIN
mods/vents/textures/_q.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
mods/vents/textures/_q_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

BIN
mods/vents/textures/_qo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

Some files were not shown because too many files have changed in this diff Show More