mods that hopefully work for a TechAge-based pack
@@ -0,0 +1,10 @@
|
||||
name: luacheck
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
luacheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@main
|
||||
- name: Luacheck
|
||||
uses: lunarmodules/luacheck@master
|
||||
@@ -0,0 +1,28 @@
|
||||
unused_args = false
|
||||
|
||||
ignore = {
|
||||
"131", -- Unused global variable
|
||||
"432", -- Shadowing an upvalue argument
|
||||
}
|
||||
|
||||
read_globals = {
|
||||
"core",
|
||||
"minetest",
|
||||
"default",
|
||||
"worldedit",
|
||||
"tubelib2",
|
||||
"intllib",
|
||||
"DIR_DELIM",
|
||||
"techage",
|
||||
|
||||
string = {fields = {"split", "trim"}},
|
||||
vector = {fields = {"add", "equals", "multiply"}},
|
||||
table = {fields = {"copy", ""}},
|
||||
}
|
||||
|
||||
globals = {
|
||||
"hyperloop",
|
||||
"ItemStack",
|
||||
"screwdriver",
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -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)**
|
||||
|
||||

|
||||
|
||||
|
||||
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+
|
||||
@@ -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 = hyperloop.S
|
||||
--local NS = hyperloop.NS
|
||||
|
||||
local tBlockingTime = {}
|
||||
local tBookings = {} -- open bookings: tBookings[SP(departure_pos)] = arrival_pos
|
||||
|
||||
local Stations = hyperloop.Stations
|
||||
|
||||
-- Reserve departure and arrival stations for some time
|
||||
function hyperloop.reserve(departure_pos, arrival_pos, player)
|
||||
if Stations:get(departure_pos) == nil then
|
||||
hyperloop.chat(player, S("Station data is corrupted. Please rebuild the station!"))
|
||||
return false
|
||||
elseif Stations:get(arrival_pos) == nil then
|
||||
hyperloop.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
|
||||
hyperloop.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
|
||||
hyperloop.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 hyperloop.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 hyperloop.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 hyperloop.set_arrival(departure_pos, arrival_pos)
|
||||
tBookings[SP(departure_pos)] = arrival_pos
|
||||
end
|
||||
|
||||
function hyperloop.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
|
||||
@@ -0,0 +1,321 @@
|
||||
--[[
|
||||
|
||||
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 = hyperloop.S
|
||||
|
||||
-- Used to store the Station list for each booking machine:
|
||||
-- tStationList[SP(pos)] = {pos1, pos2, ...}
|
||||
local tStationList = {}
|
||||
|
||||
local Stations = hyperloop.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;hyperloop: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 hyperloop.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)
|
||||
-- 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
|
||||
|
||||
if hyperloop.subnet_enabled then
|
||||
naming_formspec = function(pos)
|
||||
local meta = M(pos)
|
||||
local formspec = "size[7,5.4]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"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")..";]" ..
|
||||
"field[0.2,3.9;7.1,1;subnet;"..S("Subnet name (optional)")..";]" ..
|
||||
"button_exit[2.5,4.7;2,1;exit;Save]"
|
||||
meta:set_string("formspec", formspec)
|
||||
meta:set_int("change_counter", 0)
|
||||
end
|
||||
else
|
||||
naming_formspec = function(pos)
|
||||
local meta = M(pos)
|
||||
local formspec = "size[7,4.4]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"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
|
||||
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
|
||||
hyperloop.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
|
||||
hyperloop.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 = hyperloop.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 hyperloop.reserve(src_pos, dest_pos, player) then
|
||||
hyperloop.set_arrival(src_pos, dest_pos)
|
||||
-- open the pod door
|
||||
hyperloop.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 = "hyperloop:booking_ground"
|
||||
node.param2 = hyperloop.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("hyperloop: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 = {cracky=2},
|
||||
is_ground_content = false,
|
||||
})
|
||||
|
||||
-- ground mounted booking machine
|
||||
minetest.register_node("hyperloop: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 = "hyperloop:booking",
|
||||
light_source = 2,
|
||||
paramtype = 'light',
|
||||
paramtype2 = "facedir",
|
||||
groups = {cracky=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
A
|
||||
_a_
|
||||
7
|
||||
B
|
||||
_b_
|
||||
5
|
||||
C
|
||||
_c_
|
||||
6
|
||||
D
|
||||
_d_
|
||||
6
|
||||
E
|
||||
_e_
|
||||
5
|
||||
F
|
||||
_f_
|
||||
5
|
||||
G
|
||||
_g_
|
||||
6
|
||||
H
|
||||
_h_
|
||||
6
|
||||
I
|
||||
_i_
|
||||
1
|
||||
J
|
||||
_j_
|
||||
4
|
||||
K
|
||||
_k_
|
||||
5
|
||||
L
|
||||
_l_
|
||||
4
|
||||
M
|
||||
_m_
|
||||
7
|
||||
N
|
||||
_n_
|
||||
6
|
||||
O
|
||||
_o_
|
||||
6
|
||||
P
|
||||
_p_
|
||||
5
|
||||
Q
|
||||
_q_
|
||||
7
|
||||
R
|
||||
_r_
|
||||
5
|
||||
S
|
||||
_s_
|
||||
5
|
||||
T
|
||||
_t_
|
||||
5
|
||||
U
|
||||
_u_
|
||||
6
|
||||
V
|
||||
_v_
|
||||
7
|
||||
W
|
||||
_w_
|
||||
9
|
||||
X
|
||||
_x_
|
||||
5
|
||||
Y
|
||||
_y_
|
||||
7
|
||||
Z
|
||||
_z_
|
||||
5
|
||||
a
|
||||
_a
|
||||
5
|
||||
b
|
||||
_b
|
||||
5
|
||||
c
|
||||
_c
|
||||
4
|
||||
d
|
||||
_d
|
||||
5
|
||||
e
|
||||
_e
|
||||
4
|
||||
f
|
||||
_f
|
||||
4
|
||||
g
|
||||
_g
|
||||
5
|
||||
h
|
||||
_h
|
||||
5
|
||||
i
|
||||
_i
|
||||
1
|
||||
j
|
||||
_j
|
||||
1
|
||||
k
|
||||
_k
|
||||
4
|
||||
l
|
||||
_l
|
||||
1
|
||||
m
|
||||
_m
|
||||
7
|
||||
n
|
||||
_n
|
||||
5
|
||||
o
|
||||
_o
|
||||
5
|
||||
p
|
||||
_p
|
||||
5
|
||||
q
|
||||
_q
|
||||
5
|
||||
r
|
||||
_r
|
||||
3
|
||||
s
|
||||
_s
|
||||
4
|
||||
t
|
||||
_t
|
||||
3
|
||||
u
|
||||
_u
|
||||
4
|
||||
v
|
||||
_v
|
||||
5
|
||||
w
|
||||
_w
|
||||
7
|
||||
x
|
||||
_x
|
||||
5
|
||||
y
|
||||
_y
|
||||
4
|
||||
z
|
||||
_z
|
||||
4
|
||||
|
||||
_sp
|
||||
2
|
||||
0
|
||||
_0
|
||||
4
|
||||
1
|
||||
_1
|
||||
2
|
||||
2
|
||||
_2
|
||||
4
|
||||
3
|
||||
_3
|
||||
4
|
||||
4
|
||||
_4
|
||||
4
|
||||
5
|
||||
_5
|
||||
4
|
||||
6
|
||||
_6
|
||||
4
|
||||
7
|
||||
_7
|
||||
4
|
||||
8
|
||||
_8
|
||||
4
|
||||
9
|
||||
_9
|
||||
4
|
||||
(
|
||||
_bl
|
||||
2
|
||||
)
|
||||
_br
|
||||
2
|
||||
{
|
||||
_cl
|
||||
3
|
||||
}
|
||||
_cr
|
||||
3
|
||||
[
|
||||
_sl
|
||||
2
|
||||
]
|
||||
_sr
|
||||
2
|
||||
!
|
||||
_ex
|
||||
1
|
||||
?
|
||||
_qu
|
||||
4
|
||||
#
|
||||
_hs
|
||||
5
|
||||
$
|
||||
_dl
|
||||
4
|
||||
%
|
||||
_pr
|
||||
5
|
||||
^
|
||||
_ca
|
||||
3
|
||||
_
|
||||
_un
|
||||
3
|
||||
+
|
||||
_ps
|
||||
3
|
||||
-
|
||||
_mn
|
||||
3
|
||||
=
|
||||
_eq
|
||||
3
|
||||
;
|
||||
_sm
|
||||
1
|
||||
:
|
||||
_co
|
||||
1
|
||||
,
|
||||
_cm
|
||||
2
|
||||
"
|
||||
_qo
|
||||
3
|
||||
/
|
||||
_dv
|
||||
5
|
||||
~
|
||||
_tl
|
||||
4
|
||||
<
|
||||
_lt
|
||||
3
|
||||
>
|
||||
_gt
|
||||
3
|
||||
\
|
||||
_re
|
||||
5
|
||||
|
|
||||
_vb
|
||||
1
|
||||
.
|
||||
_dt
|
||||
1
|
||||
@@ -0,0 +1,42 @@
|
||||
--[[
|
||||
|
||||
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 P = minetest.string_to_pos
|
||||
--local M = minetest.get_meta
|
||||
|
||||
hyperloop.Stations = hyperloop.Network:new()
|
||||
hyperloop.Elevators = hyperloop.Network:new()
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
hyperloop.Stations:deserialize(storage:get_string("Stations"))
|
||||
hyperloop.Elevators:deserialize(storage:get_string("Elevators"))
|
||||
|
||||
local function update_mod_storage()
|
||||
minetest.log("action", "[Hyperloop] Store data...")
|
||||
storage:set_string("Stations", hyperloop.Stations:serialize())
|
||||
storage:set_string("Elevators", hyperloop.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)
|
||||
@@ -0,0 +1,241 @@
|
||||
--[[
|
||||
|
||||
Hyperloop Mod
|
||||
=============
|
||||
|
||||
Copyright (C) 2017 Joachim Stolberg
|
||||
|
||||
LGPLv2.1+
|
||||
See LICENSE.txt for more information
|
||||
|
||||
History:
|
||||
see init.lua
|
||||
|
||||
]]--
|
||||
|
||||
-- Load support for intllib.
|
||||
local S = hyperloop.S
|
||||
|
||||
local tilesL = {"hyperloop_alpsL.png", "hyperloop_seaL.png", "hyperloop_agyptL.png"}
|
||||
local tilesR = {"hyperloop_alpsR.png", "hyperloop_seaR.png", "hyperloop_agyptR.png"}
|
||||
|
||||
-- determine facedir and pos on the right hand side from the given pos
|
||||
local function right_hand_side(pos, placer)
|
||||
local facedir = hyperloop.get_facedir(placer)
|
||||
pos = hyperloop.new_pos(pos, facedir, "1R", 0)
|
||||
return facedir,pos
|
||||
end
|
||||
|
||||
for idx = 1,3 do
|
||||
|
||||
minetest.register_node("hyperloop:poster"..idx.."L", {
|
||||
description = S("Hyperloop Promo Poster ")..idx,
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_skin2.png",
|
||||
"hyperloop_skin2.png",
|
||||
"hyperloop_skin2.png",
|
||||
"hyperloop_skin2.png",
|
||||
"hyperloop_skin2.png",
|
||||
tilesL[idx],
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -8/16, -8/16, -6/16, 8/16, 8/16, 8/16},
|
||||
},
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = { -8/16, -8/16, -6/16, 24/16, 8/16, 8/16},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local facedir
|
||||
facedir, pos = right_hand_side(pos, placer)
|
||||
meta:set_string("pos", minetest.pos_to_string(pos))
|
||||
if minetest.get_node_or_nil(pos).name == "air" then
|
||||
minetest.add_node(pos, {name="hyperloop:poster"..idx.."R", param2=facedir})
|
||||
end
|
||||
end,
|
||||
|
||||
on_destruct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
pos = minetest.string_to_pos(meta:get_string("pos"))
|
||||
if pos ~= nil and minetest.get_node_or_nil(pos).name == "hyperloop:poster"..idx.."R" then
|
||||
minetest.remove_node(pos)
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
paramtype2 = "facedir",
|
||||
light_source = 4,
|
||||
is_ground_content = false,
|
||||
groups = {cracky = 2, stone = 2},
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop:poster"..idx.."R", {
|
||||
description = S("Hyperloop Promo Poster ")..idx,
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_skin2.png",
|
||||
"hyperloop_skin2.png",
|
||||
"hyperloop_skin2.png",
|
||||
"hyperloop_skin2.png",
|
||||
"hyperloop_skin2.png",
|
||||
tilesR[idx],
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -8/16, -8/16, -6/16, 8/16, 8/16, 8/16},
|
||||
},
|
||||
},
|
||||
paramtype2 = "facedir",
|
||||
light_source = 4,
|
||||
is_ground_content = false,
|
||||
groups = {cracky = 2, stone = 2, not_in_creative_inventory=1},
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
minetest.register_node("hyperloop:sign", {
|
||||
description = S("Hyperloop Station Sign"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_sign_top.png",
|
||||
"hyperloop_sign.png",
|
||||
},
|
||||
light_source = 4,
|
||||
is_ground_content = false,
|
||||
groups = {cracky = 2, stone = 2},
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop:signR", {
|
||||
description = S("Hyperloop Station Sign Right"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_sign3.png^[transformR90]",
|
||||
"hyperloop_sign3.png^[transformR90]",
|
||||
"hyperloop_sign3.png",
|
||||
"hyperloop_sign3.png",
|
||||
"hyperloop_sign2.png^[transformFX",
|
||||
"hyperloop_sign2.png",
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -8/16, -5/16, 6/16, 8/16, 5/16, 8/16},
|
||||
},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||
pos.y = pos.y - 1
|
||||
if minetest.get_node_or_nil(pos).name ~= "air" then
|
||||
local node = minetest.get_node(pos)
|
||||
node.name = "hyperloop:signR_ground"
|
||||
node.param2 = hyperloop.get_facedir(placer)
|
||||
pos.y = pos.y + 1
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
end,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
paramtype = 'light',
|
||||
light_source = 4,
|
||||
is_ground_content = false,
|
||||
groups = {cracky = 2, stone = 2},
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop:signL", {
|
||||
description = S("Hyperloop Station Sign Left"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_sign3.png^[transformR90]",
|
||||
"hyperloop_sign3.png^[transformR90]",
|
||||
"hyperloop_sign3.png",
|
||||
"hyperloop_sign3.png",
|
||||
"hyperloop_sign2.png",
|
||||
"hyperloop_sign2.png^[transformFX",
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -8/16, -5/16, 6/16, 8/16, 5/16, 8/16},
|
||||
},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||
pos.y = pos.y - 1
|
||||
if minetest.get_node_or_nil(pos).name ~= "air" then
|
||||
local node = minetest.get_node(pos)
|
||||
node.name = "hyperloop:signL_ground"
|
||||
node.param2 = hyperloop.get_facedir(placer)
|
||||
pos.y = pos.y + 1
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
end,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
paramtype = 'light',
|
||||
light_source = 4,
|
||||
is_ground_content = false,
|
||||
groups = {cracky = 2, stone = 2},
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop:signR_ground", {
|
||||
description = S("Hyperloop Station Sign Right"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_sign3.png^[transformR90]",
|
||||
"hyperloop_sign3.png^[transformR90]",
|
||||
"hyperloop_sign3.png",
|
||||
"hyperloop_sign3.png",
|
||||
"hyperloop_sign2_ground.png^[transformFX",
|
||||
"hyperloop_sign2_ground.png",
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -8/16, -8/16, -1/16, 8/16, 2/16, 1/16},
|
||||
},
|
||||
},
|
||||
paramtype2 = "facedir",
|
||||
drop = "hyperloop:signR",
|
||||
paramtype = 'light',
|
||||
light_source = 4,
|
||||
is_ground_content = false,
|
||||
groups = {cracky = 2, stone = 2, not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop:signL_ground", {
|
||||
description = S("Hyperloop Station Sign Left"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_sign3.png^[transformR90]",
|
||||
"hyperloop_sign3.png^[transformR90]",
|
||||
"hyperloop_sign3.png",
|
||||
"hyperloop_sign3.png",
|
||||
"hyperloop_sign2_ground.png",
|
||||
"hyperloop_sign2_ground.png^[transformFX",
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -8/16, -8/16, -1/16, 8/16, 2/16, 1/16},
|
||||
},
|
||||
},
|
||||
paramtype2 = "facedir",
|
||||
drop = "hyperloop:signL",
|
||||
paramtype = 'light',
|
||||
light_source = 4,
|
||||
is_ground_content = false,
|
||||
groups = {cracky = 2, stone = 2, not_in_creative_inventory=1},
|
||||
})
|
||||
@@ -0,0 +1,202 @@
|
||||
--[[
|
||||
|
||||
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 = hyperloop.S
|
||||
|
||||
-- Open the door for an emergency
|
||||
local function door_on_punch(pos, node, puncher, pointed_thing)
|
||||
local station = hyperloop.get_base_station(pos)
|
||||
if station then
|
||||
if station.name == "Station" then
|
||||
hyperloop.chat(puncher, S("The Booking Machine for this station is missing!"))
|
||||
elseif not hyperloop.is_blocked(station.pos) then
|
||||
hyperloop.open_pod_door(station)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Open/close/animate the pod door
|
||||
-- door_pos1: position of the bottom door
|
||||
-- cmnd: "close", "open", or "animate"
|
||||
local function door_command(door_pos1, facedir, cmnd)
|
||||
-- one step up
|
||||
local door_pos2 = vector.add(door_pos1, {x=0, y=1, z=0})
|
||||
|
||||
local node1 = minetest.get_node(door_pos1)
|
||||
local node2 = minetest.get_node(door_pos2)
|
||||
if cmnd == "open" then
|
||||
minetest.sound_play("door", {
|
||||
pos = door_pos1,
|
||||
gain = 0.5,
|
||||
max_hear_distance = 10,
|
||||
})
|
||||
node1.name = "air"
|
||||
minetest.swap_node(door_pos1, node1)
|
||||
node2.name = "air"
|
||||
minetest.swap_node(door_pos2, node2)
|
||||
elseif cmnd == "close" then
|
||||
minetest.sound_play("door", {
|
||||
pos = door_pos1,
|
||||
gain = 0.5,
|
||||
max_hear_distance = 10,
|
||||
})
|
||||
node1.name = "hyperloop:doorBottom"
|
||||
node1.param2 = facedir
|
||||
minetest.swap_node(door_pos1, node1)
|
||||
node2.name = "hyperloop:doorTopPassive"
|
||||
node2.param2 = facedir
|
||||
minetest.swap_node(door_pos2, node2)
|
||||
elseif cmnd == "animate" then
|
||||
node2.name = "hyperloop:doorTopActive"
|
||||
node2.param2 = facedir
|
||||
minetest.swap_node(door_pos2, node2)
|
||||
end
|
||||
end
|
||||
|
||||
-- door command based on the station data table
|
||||
function hyperloop.open_pod_door(tStation)
|
||||
if tStation ~= nil then
|
||||
tStation.facedir = tStation.facedir or 0
|
||||
local door_pos = hyperloop.new_pos(tStation.pos, tStation.facedir, "1F1L", 1)
|
||||
local door_facedir = (tStation.facedir + 1) % 4
|
||||
door_command(door_pos, door_facedir, "open")
|
||||
end
|
||||
end
|
||||
|
||||
-- door command based on the station data table
|
||||
function hyperloop.close_pod_door(tStation)
|
||||
if tStation ~= nil then
|
||||
tStation.facedir = tStation.facedir or 0
|
||||
local door_pos = hyperloop.new_pos(tStation.pos, tStation.facedir, "1F1L", 1)
|
||||
local door_facedir = (tStation.facedir + 1) % 4
|
||||
door_command(door_pos, door_facedir, "close")
|
||||
end
|
||||
end
|
||||
|
||||
-- door command based on the station data table
|
||||
function hyperloop.animate_pod_door(tStation)
|
||||
if tStation ~= nil then
|
||||
tStation.facedir = tStation.facedir or 0
|
||||
local door_pos = hyperloop.new_pos(tStation.pos, tStation.facedir, "1F1L", 1)
|
||||
local door_facedir = (tStation.facedir + 1) % 4
|
||||
door_command(door_pos, door_facedir, "animate")
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("hyperloop:doorTopPassive", {
|
||||
description = S("Hyperloop Door Top"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_skin_door.png",
|
||||
"hyperloop_skin_door.png",
|
||||
"hyperloop_skin_door.png",
|
||||
"hyperloop_skin_door.png",
|
||||
"hyperloop_door1OUT.png",
|
||||
"hyperloop_door1OUT.png",
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {-8/16, -8/16, -5/16, 8/16, 8/16, 5/16},
|
||||
},
|
||||
|
||||
on_punch = door_on_punch,
|
||||
|
||||
auto_place_node = function(pos, facedir, sStationPos)
|
||||
M(pos):set_int("facedir", facedir)
|
||||
M(pos):set_string("sStationPos", sStationPos)
|
||||
end,
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype = 'light',
|
||||
light_source = 1,
|
||||
paramtype2 = "facedir",
|
||||
drop = "",
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
groups = {cracky=1, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop:doorTopActive", {
|
||||
description = S("Hyperloop Door Top"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_skin_door.png",
|
||||
"hyperloop_skin_door.png",
|
||||
"hyperloop_skin_door.png",
|
||||
"hyperloop_skin_door.png",
|
||||
{
|
||||
name = "hyperloop_door1IN.png",
|
||||
animation = {
|
||||
type = "vertical_frames",
|
||||
aspect_w = 32,
|
||||
aspect_h = 32,
|
||||
length = 1.0,
|
||||
},
|
||||
},
|
||||
"hyperloop_door1OUT.png",
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {-8/16, -8/16, -5/16, 8/16, 8/16, 5/16},
|
||||
},
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype2 = "facedir",
|
||||
drop = "",
|
||||
light_source = 2,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
groups = {cracky=1, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop:doorBottom", {
|
||||
description = S("Hyperloop Door Bottom"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_skin_door.png",
|
||||
"hyperloop_skin_door.png",
|
||||
"hyperloop_skin_door.png",
|
||||
"hyperloop_skin_door.png",
|
||||
"hyperloop_door2IN.png",
|
||||
"hyperloop_door2OUT.png",
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {-8/16, -8/16, -5/16, 8/16, 8/16, 5/16},
|
||||
},
|
||||
|
||||
on_punch = door_on_punch,
|
||||
|
||||
auto_place_node = function(pos, facedir, sStationPos)
|
||||
M(pos):set_int("facedir", facedir)
|
||||
M(pos):set_string("sStationPos", sStationPos)
|
||||
end,
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype = 'light',
|
||||
light_source = 1,
|
||||
paramtype2 = "facedir",
|
||||
drop = "",
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
groups = {cracky=1, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,682 @@
|
||||
--[[
|
||||
|
||||
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 = hyperloop.S
|
||||
|
||||
-- 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 hyperloop.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 = {"hyperloop:shaft", "hyperloop:shaft2", "hyperloop:shaftA", "hyperloop:shaftA2"},
|
||||
secondary_node_names = {"hyperloop:elevator_bottom", "hyperloop: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 = "hyperloop:shaft2", param2 = param2})
|
||||
else
|
||||
minetest.swap_node(pos, {name = "hyperloop:shaft", param2 = param2})
|
||||
end
|
||||
else
|
||||
if num_tubes == 2 then
|
||||
minetest.swap_node(pos, {name = "hyperloop:shaftA2", param2 = param2})
|
||||
else
|
||||
minetest.swap_node(pos, {name = "hyperloop:shaftA", param2 = param2})
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
hyperloop.Shaft = Shaft
|
||||
local Elevators = hyperloop.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 _,node1 = Shaft:get_node(peer_pos)
|
||||
if node1.name == "hyperloop: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("hyperloop: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 = {cracky = 1},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop: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 = {cracky = 1, not_in_creative_inventory=1},
|
||||
drop = "hyperloop:shaft",
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop: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,
|
||||
----- To be unbreakable -----
|
||||
on_blast = function() end,
|
||||
on_destruct = function () end,
|
||||
can_dig = function() return false end,
|
||||
diggable = false,
|
||||
groups = {cracky = 1, not_in_creative_inventory=1, unbreakable=1},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop: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,
|
||||
----- To be unbreakable -----
|
||||
on_blast = function() end,
|
||||
on_destruct = function () end,
|
||||
can_dig = function() return false end,
|
||||
diggable = false,
|
||||
groups = {cracky = 1, not_in_creative_inventory=1, unbreakable=1},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- 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 = hyperloop.new_pos(floor_pos, facedir, "1B", 0)
|
||||
local door_pos2 = hyperloop.new_pos(floor_pos, facedir, "1B", 1)
|
||||
local meta = M(floor_pos)
|
||||
local owner = meta:contains("owner") and meta:get_string("owner")
|
||||
if owner and (minetest.is_protected(door_pos1, owner) or minetest.is_protected(door_pos2, owner)) then
|
||||
return
|
||||
end
|
||||
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 = "hyperloop:elevator_door"
|
||||
node1.param2 = facedir
|
||||
minetest.swap_node(door_pos1, node1)
|
||||
node2.name = "hyperloop:elevator_door_top"
|
||||
node2.param2 = facedir
|
||||
minetest.swap_node(door_pos2, node2)
|
||||
elseif cmnd == "darken" then
|
||||
node1.name = "hyperloop:elevator_door_dark"
|
||||
node1.param2 = facedir
|
||||
minetest.swap_node(door_pos1, node1)
|
||||
node2.name = "hyperloop: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 hyperloop.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("hyperloop: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 = hyperloop.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 fs = "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", fs)
|
||||
meta:set_string("owner", placer:get_player_name())
|
||||
|
||||
-- add upper part of the car
|
||||
pos = Shaft:get_pos(pos, 6)
|
||||
minetest.add_node(pos, {name="hyperloop: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 = hyperloop.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("hyperloop: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("hyperloop: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 = hyperloop.CLIP,
|
||||
is_ground_content = false,
|
||||
groups = {snappy = 3, not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop: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 = hyperloop.CLIP,
|
||||
is_ground_content = false,
|
||||
groups = {snappy = 3, not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop: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("hyperloop: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},
|
||||
})
|
||||
@@ -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()
|
||||
@@ -0,0 +1,92 @@
|
||||
--[[
|
||||
|
||||
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
|
||||
|
||||
]]--
|
||||
|
||||
hyperloop = {}
|
||||
|
||||
-- Version for compatibility checks, see history
|
||||
hyperloop.version = 2.08
|
||||
|
||||
if minetest.global_exists("techage") and techage.version < 0.06 then
|
||||
error("[hyperloop] Hyperloop requires techage version 0.06 or newer!")
|
||||
return
|
||||
end
|
||||
|
||||
hyperloop.S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
-- MT 5.4 new string mode
|
||||
hyperloop.CLIP = minetest.features.use_texture_alpha_string_modes and "clip" or false
|
||||
hyperloop.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
|
||||
hyperloop.wifi_enabled = minetest.settings:get_bool("hyperloop_wifi_enabled")
|
||||
hyperloop.wifi_crafting_enabled = minetest.settings:get_bool("hyperloop_wifi_crafting_enabled")
|
||||
hyperloop.free_tube_placement_enabled = minetest.settings:get_bool("hyperloop_free_tube_placement_enabled", true)
|
||||
hyperloop.subnet_enabled = minetest.settings:get_bool("hyperloop_subnet_enabled", true)
|
||||
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/network.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/data_base.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/booking.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/utils.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/elevator.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/tube.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/tubecrowbar.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/junction.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/station.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/booking_node.lua")
|
||||
if hyperloop.wifi_enabled then
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/wifi.lua")
|
||||
end
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/map.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/door.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/seat.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/lcd.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/waypoint.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/deco.lua")
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/recipes.lua")
|
||||
---- Migration from v1 to v2
|
||||
dofile(minetest.get_modpath("hyperloop") .. "/migrate.lua")
|
||||
|
||||
print ("[MOD] Hyperloop loaded")
|
||||
end
|
||||
@@ -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
|
||||
@@ -0,0 +1,92 @@
|
||||
--[[
|
||||
|
||||
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 = hyperloop.S
|
||||
|
||||
local Tube = hyperloop.Tube
|
||||
local Stations = hyperloop.Stations
|
||||
|
||||
|
||||
Tube:register_on_tube_update(function(node, pos, out_dir, peer_pos, peer_in_dir)
|
||||
if node.name == "hyperloop:station" then
|
||||
if out_dir <= 5 then
|
||||
Stations:update_connections(pos, out_dir, peer_pos)
|
||||
local s = hyperloop.get_connection_string(pos)
|
||||
M(pos):set_string("infotext", S("Station connected to ")..s)
|
||||
end
|
||||
elseif node.name == "hyperloop:junction" then
|
||||
Stations:update_connections(pos, out_dir, peer_pos)
|
||||
local s = hyperloop.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 = hyperloop.get_connection_string(pos)
|
||||
M(pos):set_string("conn_to", s)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_node("hyperloop: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)
|
||||
hyperloop.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 = {cracky = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
-- for tube viaducts
|
||||
minetest.register_node("hyperloop: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 = {cracky = 2, stone = 2},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
@@ -0,0 +1,202 @@
|
||||
--[[
|
||||
|
||||
LCD
|
||||
===
|
||||
|
||||
Derived from the work of kaeza, sofar and others (digilines)
|
||||
|
||||
LGPLv2.1+
|
||||
See LICENSE.txt for more information
|
||||
|
||||
]]--
|
||||
|
||||
-- Load support for intllib.
|
||||
local S = hyperloop.S
|
||||
|
||||
-- load characters map
|
||||
local chars_file = io.open(minetest.get_modpath("hyperloop").."/characters.data", "r")
|
||||
local charmap = {}
|
||||
local max_chars = 16
|
||||
if not chars_file then
|
||||
print("[Hyperloop] E: LCD: character map file not found")
|
||||
else
|
||||
while true do
|
||||
local char = chars_file:read("*l")
|
||||
if char == nil then
|
||||
break
|
||||
end
|
||||
local img = chars_file:read("*l")
|
||||
chars_file:read("*l")
|
||||
charmap[char] = img
|
||||
end
|
||||
end
|
||||
|
||||
-- CONSTANTS
|
||||
local LCD_WITH = 112
|
||||
|
||||
local LINE_LENGTH = 17
|
||||
local NUMBER_OF_LINES = 6
|
||||
|
||||
local LINE_HEIGHT = 14
|
||||
local CHAR_WIDTH = 5
|
||||
|
||||
local create_lines = function(text)
|
||||
local line = ""
|
||||
local line_num = 1
|
||||
local tab = {}
|
||||
for word in string.gmatch(text, "%S+") do
|
||||
if string.len(line)+string.len(word) < LINE_LENGTH and word ~= "|" then
|
||||
if line ~= "" then
|
||||
line = line.." "..word
|
||||
else
|
||||
line = word
|
||||
end
|
||||
else
|
||||
table.insert(tab, line)
|
||||
if word ~= "|" then
|
||||
line = word
|
||||
else
|
||||
line = ""
|
||||
end
|
||||
line_num = line_num+1
|
||||
if line_num > NUMBER_OF_LINES then
|
||||
return tab
|
||||
end
|
||||
end
|
||||
end
|
||||
table.insert(tab, line)
|
||||
return tab
|
||||
end
|
||||
|
||||
local generate_line = function(s, ypos)
|
||||
local i = 1
|
||||
local parsed = {}
|
||||
local width = 0
|
||||
local chars = 0
|
||||
while chars < max_chars and i <= #s do
|
||||
local file = nil
|
||||
if charmap[s:sub(i, i)] ~= nil then
|
||||
file = charmap[s:sub(i, i)]
|
||||
i = i + 1
|
||||
elseif i < #s and charmap[s:sub(i, i + 1)] ~= nil then
|
||||
file = charmap[s:sub(i, i + 1)]
|
||||
i = i + 2
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
if file ~= nil then
|
||||
width = width + CHAR_WIDTH
|
||||
table.insert(parsed, file)
|
||||
chars = chars + 1
|
||||
end
|
||||
end
|
||||
width = width - 1
|
||||
|
||||
local texture = ""
|
||||
local xpos = math.floor((LCD_WITH - width) / 2) - CHAR_WIDTH
|
||||
--xpos = 5
|
||||
for ii = 1, #parsed do
|
||||
texture = texture..":"..xpos..","..ypos.."="..parsed[ii]..".png"
|
||||
xpos = xpos + CHAR_WIDTH + 1
|
||||
end
|
||||
return texture
|
||||
end
|
||||
|
||||
local generate_texture = function(lines)
|
||||
local texture = "[combine:"..LCD_WITH.."x"..LCD_WITH
|
||||
local ypos = 8
|
||||
for i = 1, #lines do
|
||||
texture = texture..generate_line(lines[i], ypos)
|
||||
ypos = ypos + LINE_HEIGHT
|
||||
end
|
||||
return texture
|
||||
end
|
||||
|
||||
local lcds = {
|
||||
[2] = {delta = {x = 0.425, y = 0, z = 0}, yaw = math.pi / -2},
|
||||
[3] = {delta = {x = -0.425, y = 0, z = 0}, yaw = math.pi / 2},
|
||||
[4] = {delta = {x = 0, y = 0, z = 0.425}, yaw = 0},
|
||||
[5] = {delta = {x = 0, y = 0, z = -0.425}, yaw = math.pi},
|
||||
}
|
||||
|
||||
local clearscreen = function(pos)
|
||||
local objects = minetest.get_objects_inside_radius(pos, 0.5)
|
||||
for _, o in ipairs(objects) do
|
||||
local o_entity = o:get_luaentity()
|
||||
if o_entity and o_entity.name == "hyperloop_lcd:text" then
|
||||
o:remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local prepare_writing = function(pos)
|
||||
local lcd_info = lcds[minetest.get_node(pos).param2]
|
||||
if lcd_info == nil then return end
|
||||
local text = minetest.add_entity(
|
||||
{x = pos.x + lcd_info.delta.x,
|
||||
y = pos.y + lcd_info.delta.y,
|
||||
z = pos.z + lcd_info.delta.z}, "hyperloop_lcd:text")
|
||||
text:set_yaw(lcd_info.yaw or 0)
|
||||
--* text:setpitch(lcd_info.yaw or 0)
|
||||
return text
|
||||
end
|
||||
|
||||
local lcd_update = function(pos, text)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("text", text)
|
||||
clearscreen(pos)
|
||||
prepare_writing(pos)
|
||||
end
|
||||
|
||||
local lcd_box = {
|
||||
type = "wallmounted",
|
||||
wall_top = {-8/16, 15/32, -8/16, 8/16, 8/16, 8/16}
|
||||
}
|
||||
|
||||
|
||||
minetest.register_node("hyperloop:lcd", {
|
||||
drawtype = "nodebox",
|
||||
description = S("Hyperloop Display"),
|
||||
tiles = {"hyperloop_lcd.png"},
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "wallmounted",
|
||||
node_box = lcd_box,
|
||||
selection_box = lcd_box,
|
||||
drop = "",
|
||||
groups = {cracky=1, not_in_creative_inventory=1},
|
||||
|
||||
auto_place_node = function(pos, placer, facedir)
|
||||
local param2 = minetest.get_node(pos).param2
|
||||
if param2 == 0 or param2 == 1 then
|
||||
minetest.add_node(pos, {name = "hyperloop:lcd", param2 = 3})
|
||||
end
|
||||
lcd_update(pos, " | | << Hyperloop >> | be anywhere")
|
||||
end,
|
||||
|
||||
on_destruct = function(pos)
|
||||
clearscreen(pos)
|
||||
end,
|
||||
|
||||
update = function(pos, text)
|
||||
lcd_update(pos, text)
|
||||
end,
|
||||
|
||||
light_source = 6,
|
||||
})
|
||||
|
||||
minetest.register_entity(":hyperloop_lcd:text", {
|
||||
initial_properties = {
|
||||
collisionbox = { 0, 0, 0, 0, 0, 0 },
|
||||
visual = "upright_sprite",
|
||||
textures = {},
|
||||
},
|
||||
on_activate = function(self)
|
||||
local meta = minetest.get_meta(self.object:get_pos())
|
||||
local text = meta:get_string("text")
|
||||
self.object:set_properties({textures={generate_texture(create_lines(text))}})
|
||||
end
|
||||
})
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,142 @@
|
||||
# textdomain: hyperloop
|
||||
|
||||
|
||||
|
||||
### booking.lua ###
|
||||
|
||||
Station data is corrupted. Please rebuild the station!=Les données de la station sont corrompues. Veuillez reconstruire la station !
|
||||
Station is still blocked. Please try again in a few seconds!=La station est toujours bloquée. Veuillez réessayer dans quelques secondes !
|
||||
|
||||
### booking_node.lua ###
|
||||
|
||||
Please enter the station name to@nwhich this booking machine belongs.=Veuillez entrer le nom de la station@nà laquelle appartient cette machine de réservation.
|
||||
Station name=Nom de la station
|
||||
Additional station information=Renseignements supplémentaires sur la station
|
||||
Station has already a booking machine!=La station a déjà une machine de réservation !
|
||||
Invalid station name!==Nom de station invalide !
|
||||
Hyperloop Booking Machine=Machine de réservation Hyperloop
|
||||
|
||||
### booking_node.lua ###
|
||||
### elevator.lua ###
|
||||
|
||||
Select your destination=Sélectionnez votre destination
|
||||
|
||||
### booking_node.lua ###
|
||||
### migrate.lua ###
|
||||
|
||||
<unknown>=
|
||||
|
||||
### deco.lua ###
|
||||
|
||||
Hyperloop Promo Poster=Affiche promotionnelle Hyperloop
|
||||
Hyperloop Station Sign=Panneau de station Hyperloop
|
||||
Hyperloop Station Sign Right=Panneau droit de station Hyperloop
|
||||
Hyperloop Station Sign Left=Panneau gauche de station Hyperloop
|
||||
|
||||
### door.lua ###
|
||||
|
||||
The Booking Machine for this station is missing!=La machine de réservation pour cette station est manquante !
|
||||
Hyperloop Door Top=Haut de porte Hyperloop
|
||||
Hyperloop Door Bottom=Bas de porte Hyperloop
|
||||
|
||||
### elevator.lua ###
|
||||
|
||||
Hyperloop Elevator Shaft=Cage d’ascenseur Hyperloop
|
||||
Destination=Destination
|
||||
Floor=Etage
|
||||
(current position)=(position courante)
|
||||
Hyperloop Elevator=Ascenseur Hyperloop
|
||||
Please insert floor name=Veuillez insérer le nom de l’étage
|
||||
Floor name=Nom de l’étage
|
||||
Base=Base
|
||||
|
||||
### elevator.lua ###
|
||||
### wifi.lua ###
|
||||
|
||||
Save=Enregistrer
|
||||
|
||||
### junction.lua ###
|
||||
|
||||
Station connected with =Station reliée à
|
||||
Junction connected with =Jonction reliée à
|
||||
Hyperloop Junction Block=Bloc de jonction Hyperloop
|
||||
Hyperloop Pillar=Pillier Hyperloop
|
||||
|
||||
### junction.lua ###
|
||||
### migrate.lua ###
|
||||
|
||||
Junction=Jonction
|
||||
|
||||
### lcd.lua ###
|
||||
|
||||
Hyperloop Display=Ecran Hyperloop
|
||||
|
||||
### map.lua ###
|
||||
|
||||
Dist.=Dist.
|
||||
Station/Junction=Station/Jonction
|
||||
Position=Position
|
||||
Owner=Propriétaire
|
||||
Conn. with=Conn. avec
|
||||
Close=Fermer
|
||||
Hyperloop Station Book=Livre des stations Hyperloop
|
||||
|
||||
### migrate.lua ###
|
||||
|
||||
Hyperloop Legacy Tube=Tube traditionnel Hyperloop
|
||||
unknown=inconnu
|
||||
|
||||
### recipes.lua ###
|
||||
### station.lua ###
|
||||
|
||||
Hypersteel Ingot=Lingot Hypersteel
|
||||
|
||||
### seat.lua ###
|
||||
|
||||
[Hyperloop] No booking entered!=[Hyperloop] Aucune réservation saisie !
|
||||
Hyperloop Pod Seat=Siège de module Hyperloop
|
||||
|
||||
### station.lua ###
|
||||
|
||||
Station completed. Now place the Booking Machine!=Station terminée. Placez maintenant la machine de réservation !
|
||||
Area is protected!=La zone est protégée
|
||||
Not enough space to build the station!=Pas assez de place pour construire la station !
|
||||
Hyperloop Station Pod Builder=Module de construction de station Hyperloop
|
||||
Hyperloop Pod Shell=Coque de module Hyperloop
|
||||
Blue Wool=Laine blue
|
||||
Glass=Verre
|
||||
Not enough inventory items to build the station!=Pas assez d’items en stock pour construire la station
|
||||
Destroy Station=Détruire la station
|
||||
Build Station=Construire la station
|
||||
Hyperloop Station Block=Bloc de station Hyperloop
|
||||
Station=Station
|
||||
|
||||
### tube.lua ###
|
||||
|
||||
Junction at =Jonction à
|
||||
Station '=Station '
|
||||
Station at =Station à
|
||||
Open end at =Extrémité ouverte à
|
||||
There is no station/junction on this level. =Il n’y a pas de station/jonction à ce niveau.
|
||||
Do you really want to start a new network?!=Voulez-vous vraiment démarrer un nouveau réseau ?
|
||||
Hyperloop Tube=Tube Hyperloop
|
||||
|
||||
### tubecrowbar.lua ###
|
||||
|
||||
[Hyperloop] Error: Tube is too long!=[Hyperloop] Erreur : Tube trop long
|
||||
[Crowbar Help]@n=[Crowbar Help]@n
|
||||
left: remove node@n=gauche : supprimer le nœud @n
|
||||
right: repair tube/shaft line@n=droite : réparer le tube / ligne d'arbre @n
|
||||
You don't have the necessary privs!=Vous n'avez pas les droits nécessaires !
|
||||
Hyperloop Tube Crowbar=Pied de biche Hyperloop
|
||||
Rights to remove tube nodes by means of the crowbar=Droits de suppression des nœuds de tubes au moyen du pied de biche
|
||||
Repair via WorldEdit placed Hyperloop tubes by reusing WorldEdit pos1/pos2=Réparation via WorldEdit des tubes Hyperloop placés en réutilisant WorldEdit pos1/pos2
|
||||
|
||||
### waypoint.lua ###
|
||||
|
||||
Hyperloop Waypoint=Point de passage Hyperloop
|
||||
|
||||
### wifi.lua ###
|
||||
|
||||
Enter channel string=Entrer la valeur pour la chaîne
|
||||
Hyperloop WiFi Tube=Tube WiFi Hyperloop
|
||||
@@ -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=
|
||||
@@ -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 = hyperloop.S
|
||||
|
||||
local Stations = hyperloop.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, "hyperloop: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, "hyperloop:station_map", formspec)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Tool for tube workers to find the next station
|
||||
minetest.register_node("hyperloop: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,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,388 @@
|
||||
--[[
|
||||
|
||||
Hyperloop Mod
|
||||
=============
|
||||
|
||||
Copyright (C) 2017 Joachim Stolberg
|
||||
|
||||
LGPLv2.1+
|
||||
See LICENSE.txt for more information
|
||||
|
||||
History:
|
||||
see init.lua
|
||||
|
||||
Migrate from v1 to v2
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local SP = minetest.pos_to_string
|
||||
local P = minetest.string_to_pos
|
||||
local M = minetest.get_meta
|
||||
|
||||
-- Load support for intllib.
|
||||
local S = hyperloop.S
|
||||
|
||||
local Tube = hyperloop.Tube
|
||||
local Shaft = hyperloop.Shaft
|
||||
|
||||
local Elevators = hyperloop.Elevators
|
||||
local Stations = hyperloop.Stations
|
||||
|
||||
local tLegacyNodeNames = {}
|
||||
|
||||
local JunctionsToBePlacedAfter = {}
|
||||
|
||||
local function get_tube_data(pos, dir1, dir2, num_tubes)
|
||||
local param2, tube_type = tubelib2.encode_param2(dir1, dir2, num_tubes)
|
||||
return pos, param2, tube_type, num_tubes
|
||||
end
|
||||
|
||||
-- Check if node has a connection on the given dir
|
||||
local function connected(self, pos, dir)
|
||||
local _,node = self:get_node(pos, dir)
|
||||
return self.primary_node_names[node.name]
|
||||
or self.secondary_node_names[node.name]
|
||||
end
|
||||
|
||||
-- Determine dirs via surrounding nodes
|
||||
local function determine_dir1_dir2_and_num_conn(self, pos)
|
||||
local dirs = {}
|
||||
for dir = 1, 6 do
|
||||
if connected(self, pos, dir) then
|
||||
dirs[#dirs+1] = dir
|
||||
end
|
||||
end
|
||||
if #dirs == 1 then
|
||||
return dirs[1], nil, 1
|
||||
elseif #dirs == 2 then
|
||||
return dirs[1], dirs[2], 2
|
||||
end
|
||||
end
|
||||
|
||||
-- convert legacy tubes to current tubes
|
||||
for idx = 0,2 do
|
||||
minetest.register_node("hyperloop:tube"..idx, {
|
||||
description = S("Hyperloop Legacy Tube"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_tube_locked.png^[transformR90]",
|
||||
"hyperloop_tube_locked.png^[transformR90]",
|
||||
'hyperloop_tube_closed.png',
|
||||
'hyperloop_tube_closed.png',
|
||||
'hyperloop_tube_open.png',
|
||||
'hyperloop_tube_open.png',
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||
local node = minetest.get_node(pos)
|
||||
node.name = "hyperloop:tubeS"
|
||||
minetest.swap_node(pos, node)
|
||||
if not Tube:after_place_tube(pos, placer, pointed_thing) then
|
||||
minetest.remove_node(pos)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
node_placement_prediction = "hyperloop:tubeS",
|
||||
groups = {cracky=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
end
|
||||
|
||||
local function convert_legary_nodes(self, pos, dir)
|
||||
local convert_next_tube = function(self, pos, dir)
|
||||
local npos, node = self:get_node(pos, dir)
|
||||
if tLegacyNodeNames[node.name] then
|
||||
local dir1, dir2, num = determine_dir1_dir2_and_num_conn(self, npos)
|
||||
if dir1 then
|
||||
self.clbk_after_place_tube(get_tube_data(npos, dir1,
|
||||
dir2 or tubelib2.Turn180Deg[dir1], num))
|
||||
if tubelib2.Turn180Deg[dir] == dir1 then
|
||||
return npos, dir2
|
||||
else
|
||||
return npos, dir1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local cnt = 0
|
||||
if not dir then return pos, dir, cnt end
|
||||
while cnt <= 64000 do
|
||||
local new_pos, new_dir = convert_next_tube(self, pos, dir)
|
||||
if cnt > 0 and (cnt % self.max_tube_length) == 0 then -- border reached?
|
||||
JunctionsToBePlacedAfter[#JunctionsToBePlacedAfter + 1] = pos
|
||||
end
|
||||
if not new_dir then break end
|
||||
pos, dir = new_pos, new_dir
|
||||
cnt = cnt + 1
|
||||
end
|
||||
return pos, dir, cnt
|
||||
end
|
||||
|
||||
local function convert_line(self, pos, dir)
|
||||
convert_legary_nodes(self, pos, dir)
|
||||
self:tool_repair_tube(pos)
|
||||
end
|
||||
|
||||
|
||||
local tWifiNodes = {} -- user for pairing
|
||||
local lWifiNodes = {} -- used for post processing
|
||||
|
||||
local function set_pairing(pos, peer_pos)
|
||||
|
||||
M(pos):set_int("tube_dir", Tube:get_primary_dir(pos))
|
||||
M(peer_pos):set_int("tube_dir", Tube:get_primary_dir(peer_pos))
|
||||
|
||||
Tube:store_teleport_data(pos, peer_pos)
|
||||
Tube:store_teleport_data(peer_pos, pos)
|
||||
end
|
||||
|
||||
|
||||
local function wifi_post_processing()
|
||||
for _,pos in ipairs(lWifiNodes) do
|
||||
local dir = Tube:get_primary_dir(pos)
|
||||
local npos = Tube:get_pos(pos, dir)
|
||||
Tube:tool_repair_tube(npos)
|
||||
end
|
||||
end
|
||||
|
||||
-- Wifi nodes don't know their counterpart.
|
||||
-- But by means of the tube head nodes, two
|
||||
-- Wifi nodes in one tube line can be determined.
|
||||
local function determine_wifi_pairs(pos)
|
||||
-- determine 1. tube head node
|
||||
local pos1 = M(pos):get_string("peer")
|
||||
if pos1 == "" then return end
|
||||
-- determine 2. tube head node
|
||||
local pos2 = M(P(pos1)):get_string("peer")
|
||||
if pos2 == "" then return end
|
||||
for k,item in pairs(tWifiNodes) do
|
||||
-- entry already available
|
||||
if item[1] == pos2 and item[2] == pos1 then
|
||||
tWifiNodes[k] = nil
|
||||
-- start paring
|
||||
set_pairing(P(k), pos)
|
||||
return
|
||||
end
|
||||
end
|
||||
-- add single Wifi node to pairing table
|
||||
tWifiNodes[SP(pos)] = {pos1, pos2}
|
||||
end
|
||||
|
||||
local function next_node_on_the_way_to_a_wifi_node(pos)
|
||||
local dirs = {}
|
||||
for dir = 1, 6 do
|
||||
local npos, node = Tube:get_node(pos, dir)
|
||||
if tLegacyNodeNames[node.name] then
|
||||
dirs[#dirs+1] = dir
|
||||
elseif node.name == "hyperloop:tube_wifi1" then
|
||||
lWifiNodes[#lWifiNodes+1] = npos
|
||||
determine_wifi_pairs(npos)
|
||||
end
|
||||
end
|
||||
if #dirs == 1 then
|
||||
return dirs[1], nil, 1
|
||||
elseif #dirs == 2 then
|
||||
return dirs[1], dirs[2], 2
|
||||
end
|
||||
end
|
||||
|
||||
local function search_wifi_node(pos, dir)
|
||||
local convert_next_tube = function(pos, dir)
|
||||
local npos, _ = Tube:get_node(pos, dir)
|
||||
local dir1, dir2, _ = next_node_on_the_way_to_a_wifi_node(npos)
|
||||
if dir1 then
|
||||
if tubelib2.Turn180Deg[dir] == dir1 then
|
||||
return npos, dir2
|
||||
else
|
||||
return npos, dir1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local cnt = 0
|
||||
if not dir then return pos, cnt end
|
||||
while true do
|
||||
local new_pos, new_dir = convert_next_tube(pos, dir)
|
||||
if not new_dir then break end
|
||||
pos, dir = new_pos, new_dir
|
||||
cnt = cnt + 1
|
||||
end
|
||||
return pos, dir, cnt
|
||||
end
|
||||
|
||||
local function search_wifi_node_in_all_dirs(pos)
|
||||
-- check all positions
|
||||
for dir = 1, 6 do
|
||||
local _, node = Tube:get_node(pos, dir)
|
||||
if node and node.name == "hyperloop:tube1" then
|
||||
search_wifi_node(pos, dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function convert_tube_line(pos)
|
||||
-- check all positions
|
||||
for dir = 1, 6 do
|
||||
local _, node = Tube:get_node(pos, dir)
|
||||
if node and node.name == "hyperloop:tube1" then
|
||||
convert_line(Tube, pos, dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function convert_shaft_line(pos)
|
||||
-- check lower position
|
||||
convert_line(Shaft, pos, 5)
|
||||
-- check upper position
|
||||
pos.y = pos.y + 1
|
||||
convert_line(Shaft, pos, 6)
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
|
||||
local function station_name(item)
|
||||
if item.junction == true then
|
||||
return "Junction"
|
||||
elseif item.station_name then
|
||||
return item.station_name
|
||||
else
|
||||
return "Station"
|
||||
end
|
||||
end
|
||||
|
||||
local function add_to_table(tbl, tValues)
|
||||
local res = table.copy(tbl)
|
||||
for k,v in pairs(tValues) do
|
||||
tbl[k] = v
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
local function convert_station_data(tAllStations)
|
||||
tLegacyNodeNames = {
|
||||
["hyperloop:tube0"] = true,
|
||||
["hyperloop:tube1"] = true,
|
||||
["hyperloop:tube2"] = true,
|
||||
}
|
||||
|
||||
local originNodeNames = add_to_table(Tube.primary_node_names, tLegacyNodeNames)
|
||||
|
||||
for key,item in pairs(tAllStations) do
|
||||
if item.pos and Tube:is_secondary_node(item.pos) then
|
||||
Stations:set(item.pos, station_name(item), {
|
||||
owner = item.owner or S("<unknown>"),
|
||||
junction = item.junction,
|
||||
facedir = item.facedir,
|
||||
booking_info = item.booking_info,
|
||||
booking_pos = item.booking_pos,
|
||||
})
|
||||
end
|
||||
end
|
||||
-- First perform the Wifi node pairing
|
||||
-- before all tube node loose their meta data
|
||||
-- while converted.
|
||||
for key,item in pairs(tAllStations) do
|
||||
if item.pos and Tube:is_secondary_node(item.pos) then
|
||||
search_wifi_node_in_all_dirs(item.pos)
|
||||
end
|
||||
end
|
||||
-- Then convert all tube nodes
|
||||
for key,item in pairs(tAllStations) do
|
||||
if item.pos and Tube:is_secondary_node(item.pos) then
|
||||
convert_tube_line(item.pos)
|
||||
Tube:after_place_node(item.pos)
|
||||
end
|
||||
end
|
||||
-- Repair the tube lines of wifi nodes
|
||||
wifi_post_processing()
|
||||
|
||||
Tube.primary_node_names = originNodeNames
|
||||
end
|
||||
|
||||
local function convert_elevator_data(tAllElevators)
|
||||
tLegacyNodeNames = {
|
||||
["hyperloop:shaft"] = true,
|
||||
["hyperloop:shaft2"] = true,
|
||||
}
|
||||
local originNodeNames = add_to_table(Shaft.primary_node_names, tLegacyNodeNames)
|
||||
local originDirsToCheck = table.copy(Shaft.dirs_to_check)
|
||||
Shaft.dirs_to_check = {5,6} -- legacy elevators use up/down only
|
||||
|
||||
for pos,tElevator in pairs(tAllElevators) do
|
||||
for _,floor in pairs(tElevator.floors) do
|
||||
if floor.pos and Shaft:is_secondary_node(floor.pos) then
|
||||
Elevators:set(floor.pos, floor.name, {
|
||||
facedir = floor.facedir,
|
||||
})
|
||||
convert_shaft_line(floor.pos)
|
||||
M(floor.pos):set_int("change_counter", 0)
|
||||
Shaft:after_place_node(floor.pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Shaft.primary_node_names = originNodeNames
|
||||
Shaft.dirs_to_check = originDirsToCheck
|
||||
end
|
||||
|
||||
local function place_junctions()
|
||||
for _,pos in ipairs(JunctionsToBePlacedAfter) do
|
||||
minetest.set_node(pos, {name = "hyperloop:junction"})
|
||||
M(pos):set_string("infotext", S("Junction"))
|
||||
Stations:set(pos, "Junction", {owner = S("unknown"), junction = true})
|
||||
Tube:after_place_node(pos)
|
||||
minetest.log("action", "[Hyperloop] Junction placed at "..SP(pos))
|
||||
end
|
||||
end
|
||||
|
||||
local wpath = minetest.get_worldpath()
|
||||
function hyperloop.file2table(filename)
|
||||
local f = io.open(wpath..DIR_DELIM..filename, "r")
|
||||
if f == nil then return nil end
|
||||
local t = f:read("*all")
|
||||
f:close()
|
||||
if t == "" or t == nil then return nil end
|
||||
return minetest.deserialize(t)
|
||||
end
|
||||
|
||||
local function migrate()
|
||||
local data = hyperloop.file2table("mod_hyperloop.data")
|
||||
if data then
|
||||
minetest.log("action", "[Hyperloop] Migrate data...")
|
||||
hyperloop.convert = true
|
||||
convert_station_data(data.tAllStations)
|
||||
convert_elevator_data(data.tAllElevators)
|
||||
os.remove(wpath..DIR_DELIM.."mod_hyperloop.data")
|
||||
place_junctions()
|
||||
hyperloop.convert = nil
|
||||
minetest.log("action", "[Hyperloop] Data migrated")
|
||||
end
|
||||
end
|
||||
|
||||
minetest.after(5, migrate)
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "[Hyperloop] booking/seat/door migration",
|
||||
name = "hyperloop:migrate",
|
||||
nodenames = {
|
||||
"hyperloop:booking", "hyperloop:booking_ground",
|
||||
"hyperloop:doorTopPassive", "hyperloop:doorBottom",
|
||||
"hyperloop:seat",
|
||||
},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
local meta = M(pos)
|
||||
if meta:get_string("key_str") ~= "" then
|
||||
local s = meta:get_string("key_str")
|
||||
meta:set_string("sStationPos", "("..string.sub(s, 2, -2)..")")
|
||||
if node.name == "hyperloop:booking" or node.name == "hyperloop:booking_ground" then
|
||||
meta:set_int("change_counter", 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
@@ -0,0 +1,5 @@
|
||||
name = hyperloop
|
||||
depends = default, tubelib2
|
||||
optional_depends = techage, worldedit
|
||||
description = Hyperloop Mod, the fast and modern way of traveling.
|
||||
supported_games = minetest_game
|
||||
@@ -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 = {}
|
||||
hyperloop.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
|
||||
@@ -0,0 +1,243 @@
|
||||
--[[
|
||||
|
||||
Hyperloop Mod
|
||||
=============
|
||||
|
||||
Copyright (C) 2017 Joachim Stolberg
|
||||
|
||||
LGPLv2.1+
|
||||
See LICENSE.txt for more information
|
||||
|
||||
History:
|
||||
see init.lua
|
||||
|
||||
]]--
|
||||
|
||||
-- Load support for intllib.
|
||||
local S = hyperloop.S
|
||||
|
||||
minetest.register_craftitem("hyperloop:hypersteel_ingot", {
|
||||
description = S("Hypersteel Ingot"),
|
||||
inventory_image = "hyperloop_hypersteel_ingot.png",
|
||||
})
|
||||
|
||||
if minetest.global_exists("techage") then
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:hypersteel_ingot 4",
|
||||
recipe = {
|
||||
{"default:steel_ingot", "default:tin_ingot"},
|
||||
{"techage:aluminum", "dye:cyan"},
|
||||
},
|
||||
})
|
||||
else
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:hypersteel_ingot 4",
|
||||
recipe = {
|
||||
{"default:steel_ingot", "default:tin_ingot"},
|
||||
{"default:copper_ingot", "dye:cyan"},
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:tubeS 8",
|
||||
recipe = {
|
||||
{"", "hyperloop:hypersteel_ingot", ""},
|
||||
{"hyperloop:hypersteel_ingot", "", "hyperloop:hypersteel_ingot"},
|
||||
{"", "hyperloop:hypersteel_ingot", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:pillar 8",
|
||||
recipe = {
|
||||
{"", "hyperloop:hypersteel_ingot", ""},
|
||||
{"", "hyperloop:hypersteel_ingot", ""},
|
||||
{"", "hyperloop:hypersteel_ingot", ""},
|
||||
},
|
||||
})
|
||||
|
||||
if minetest.global_exists("techage") then
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:pod_wall 6",
|
||||
recipe = {
|
||||
{"basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet"},
|
||||
{"basic_materials:plastic_sheet", "dye:white", "basic_materials:plastic_sheet"},
|
||||
{"hyperloop:hypersteel_ingot", "hyperloop:hypersteel_ingot", "hyperloop:hypersteel_ingot"},
|
||||
},
|
||||
})
|
||||
else
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:pod_wall 8",
|
||||
recipe = {
|
||||
{"hyperloop:hypersteel_ingot", "hyperloop:hypersteel_ingot", "hyperloop:hypersteel_ingot"},
|
||||
{"hyperloop:hypersteel_ingot", "dye:white", "hyperloop:hypersteel_ingot"},
|
||||
{"hyperloop:hypersteel_ingot", "hyperloop:hypersteel_ingot", "hyperloop:hypersteel_ingot"},
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:booking 1",
|
||||
recipe = {
|
||||
{"hyperloop:hypersteel_ingot", "", "hyperloop:hypersteel_ingot"},
|
||||
{"", "default:paper", ""},
|
||||
{"hyperloop:hypersteel_ingot", "", "hyperloop:hypersteel_ingot"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:junction",
|
||||
recipe = {
|
||||
{"", "hyperloop:hypersteel_ingot", ""},
|
||||
{"hyperloop:hypersteel_ingot", "default:mese_crystal", "hyperloop:hypersteel_ingot"},
|
||||
{"", "hyperloop:hypersteel_ingot", ""},
|
||||
},
|
||||
})
|
||||
|
||||
if minetest.global_exists("techage") then
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:station",
|
||||
recipe = {
|
||||
{"hyperloop:hypersteel_ingot", "default:mese_crystal", "hyperloop:hypersteel_ingot"},
|
||||
{"", "techage:ta4_wlanchip", ""},
|
||||
{"hyperloop:hypersteel_ingot", "default:mese_crystal", "hyperloop:hypersteel_ingot"},
|
||||
},
|
||||
})
|
||||
else
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:station",
|
||||
recipe = {
|
||||
{"hyperloop:hypersteel_ingot", "default:mese_crystal", "hyperloop:hypersteel_ingot"},
|
||||
{"", "default:mese_crystal", ""},
|
||||
{"hyperloop:hypersteel_ingot", "default:mese_crystal", "hyperloop:hypersteel_ingot"},
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:robot",
|
||||
recipe = {
|
||||
{"hyperloop:hypersteel_ingot", "hyperloop:hypersteel_ingot", "hyperloop:hypersteel_ingot"},
|
||||
{"hyperloop:hypersteel_ingot", "default:mese_crystal", "hyperloop:hypersteel_ingot"},
|
||||
{"hyperloop:hypersteel_ingot", "hyperloop:hypersteel_ingot", "hyperloop:hypersteel_ingot"},
|
||||
},
|
||||
})
|
||||
|
||||
if hyperloop.wifi_crafting_enabled then
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:tube_wifi1 2",
|
||||
recipe = {
|
||||
{"default:mese_crystal", "hyperloop:hypersteel_ingot", "default:mese_crystal"},
|
||||
{"hyperloop:hypersteel_ingot", "default:mese_crystal", "hyperloop:hypersteel_ingot"},
|
||||
{"default:mese_crystal", "hyperloop:hypersteel_ingot", "default:mese_crystal"},
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:station_map",
|
||||
recipe = {
|
||||
{"default:paper", "dye:red", ""},
|
||||
{"default:paper", "dye:red", ""},
|
||||
{"default:paper", "dye:red", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:shaft 8",
|
||||
recipe = {
|
||||
{"hyperloop:hypersteel_ingot", "", "hyperloop:hypersteel_ingot"},
|
||||
{"", "", ""},
|
||||
{"hyperloop:hypersteel_ingot", "", "hyperloop:hypersteel_ingot"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:elevator_bottom 2",
|
||||
recipe = {
|
||||
{"", "default:glass", "hyperloop:hypersteel_ingot"},
|
||||
{"", "dye:red", "default:mese_crystal"},
|
||||
{"", "default:glass", "hyperloop:hypersteel_ingot"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:sign",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"", "dye:cyan", "hyperloop:hypersteel_ingot"},
|
||||
{"", "default:wood", "default:wood"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:signL 4",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"", "", ""},
|
||||
{"dye:cyan", "hyperloop:hypersteel_ingot", "default:wood"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:signR 4",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"", "", ""},
|
||||
{"default:wood", "hyperloop:hypersteel_ingot", "dye:cyan"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:poster1L",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"", "dye:white", "hyperloop:hypersteel_ingot"},
|
||||
{"", "dye:blue", "default:wood"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:poster2L",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"", "dye:white", "hyperloop:hypersteel_ingot"},
|
||||
{"", "dye:cyan", "default:wood"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:poster3L",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"", "dye:white", "hyperloop:hypersteel_ingot"},
|
||||
{"", "dye:brown", "default:wood"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:waypoint",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"", "", ""},
|
||||
{"default:steel_ingot", "hyperloop:hypersteel_ingot", "default:gold_ingot"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hyperloop:tube_crowbar",
|
||||
recipe = {
|
||||
{"", "", "dye:red"},
|
||||
{"", "hyperloop:hypersteel_ingot", ""},
|
||||
{"hyperloop:hypersteel_ingot", "", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = "dye:cyan",
|
||||
recipe = "default:cactus",
|
||||
cooktime = 3,
|
||||
})
|
||||
|
||||
|
After Width: | Height: | Size: 277 KiB |
@@ -0,0 +1,235 @@
|
||||
--[[
|
||||
|
||||
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 = hyperloop.S
|
||||
local I, _ = dofile( minetest.get_modpath("hyperloop").."/intllib.lua")
|
||||
|
||||
local PlayerNameTags = {}
|
||||
|
||||
local function enter_display(tStation, text)
|
||||
-- determine position
|
||||
if tStation ~= nil then
|
||||
local lcd_pos = hyperloop.new_pos(tStation.pos, tStation.facedir, "1F", 2)
|
||||
-- update display
|
||||
minetest.registered_nodes["hyperloop: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 hyperloop.is_player_around(tStation.pos) then
|
||||
-- try again later
|
||||
minetest.after(3.0, on_final_close_door, tStation)
|
||||
else
|
||||
hyperloop.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
|
||||
hyperloop.open_pod_door(tArrival)
|
||||
-- prepare display for the next trip
|
||||
enter_display(tArrival, I("Thank you | for | travelling | with | Hyperloop."))
|
||||
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 = hyperloop.facedir_to_rad(tDeparture.facedir)
|
||||
local val2 = player:get_look_horizontal()
|
||||
if val1 ~= nil and val2 ~= nil then
|
||||
local offs = val1 - val2
|
||||
local yaw = hyperloop.facedir_to_rad(tArrival.facedir) - offs
|
||||
player:set_look_horizontal(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,
|
||||
})
|
||||
hyperloop.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 = hyperloop.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 = hyperloop.get_base_station(pos)
|
||||
local arrival_pos = hyperloop.get_arrival(departure_pos)
|
||||
if arrival_pos == nil then
|
||||
minetest.chat_send_player(player_name, S("[Hyperloop] No booking entered!"))
|
||||
return
|
||||
end
|
||||
local tArrival = hyperloop.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
|
||||
hyperloop.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(hyperloop.facedir_to_rad(tDeparture.facedir))
|
||||
-- hide player name
|
||||
PlayerNameTags[player_name] = clicker:get_nametag_attributes()
|
||||
clicker:set_nametag_attributes({text = " "})
|
||||
|
||||
-- activate display
|
||||
local dist = hyperloop.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
|
||||
hyperloop.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)
|
||||
hyperloop.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("hyperloop: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, crumbly=3},
|
||||
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,
|
||||
})
|
||||
@@ -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
|
||||
@@ -0,0 +1,353 @@
|
||||
--[[
|
||||
|
||||
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 = hyperloop.S
|
||||
|
||||
local Tube = hyperloop.Tube
|
||||
local Stations = hyperloop.Stations
|
||||
|
||||
|
||||
-- Station Pod Assembly Plan
|
||||
local AssemblyPlan = {
|
||||
-- y-offs, x/z-path, facedir-offs, name
|
||||
-- middle slice
|
||||
{ 1, "2F", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1B", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1B", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1B", 0, "hyperloop:pod_wall_ni"},
|
||||
{-1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{-1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1F", 2, "hyperloop:seat"},
|
||||
{ 0, "1F", 0, "hyperloop:pod_floor"},
|
||||
{ 1, "", 0, "hyperloop:lcd"},
|
||||
-- right slice
|
||||
{-1, "1F1R", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1B", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1B", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1B", 0, "hyperloop:pod_wall_ni"},
|
||||
{-1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{-1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1F", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1F", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1B", 0, "hyperloop:pod_wall_ni"},
|
||||
-- left slice
|
||||
{-1, "2L2R", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1B", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1B", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1B", 0, "hyperloop:pod_wall_ni"},
|
||||
{-1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{-1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1F", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 1, "", 0, "hyperloop:pod_wall_ni"},
|
||||
{ 0, "1F", 1, "hyperloop:doorTopPassive"},
|
||||
{-1, "", 1, "hyperloop:doorBottom"},
|
||||
}
|
||||
|
||||
|
||||
local function store_station(pos, placer)
|
||||
local facedir = hyperloop.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
|
||||
|
||||
-- Calls the node related "auto_place_node()" callback.
|
||||
local function call_auto_place_node(name, pos, facedir, sKey)
|
||||
local node = minetest.registered_nodes[name]
|
||||
if node.auto_place_node ~= nil then
|
||||
node.auto_place_node(pos, facedir, sKey)
|
||||
end
|
||||
end
|
||||
|
||||
local function place_node(pos, facedir, node_name, sKey)
|
||||
if node_name == "hyperloop:lcd" then
|
||||
-- wallmounted devices need a facedir correction
|
||||
local tbl = {[0]=4, [1]=2, [2]=5, [3]=3}
|
||||
minetest.add_node(pos, {name=node_name, paramtype2="wallmounted", param2=tbl[facedir]})
|
||||
else
|
||||
minetest.add_node(pos, {name=node_name, param2=facedir})
|
||||
end
|
||||
call_auto_place_node(node_name, pos, facedir, sKey)
|
||||
end
|
||||
|
||||
-- timer function, called cyclically
|
||||
local function construct(idx, pos, facedir, player_name, sKey)
|
||||
local item = AssemblyPlan[idx]
|
||||
if item ~= nil then
|
||||
local y, path, fd_offs, node_name = item[1], item[2], item[3], item[4]
|
||||
pos = hyperloop.new_pos(pos, facedir, path, y)
|
||||
place_node(pos, (facedir + fd_offs) % 4, node_name, sKey)
|
||||
minetest.after(0.5, construct, idx+1, pos, facedir, player_name, sKey)
|
||||
else
|
||||
hyperloop.chat(player_name, S("Station completed. Now place the Booking Machine!"))
|
||||
end
|
||||
end
|
||||
|
||||
local function check_space(pos, facedir, placer)
|
||||
for _,item in ipairs(AssemblyPlan) do
|
||||
local y, path, _ = item[1], item[2], item[4]
|
||||
pos = hyperloop.new_pos(pos, facedir, path, y)
|
||||
if minetest.is_protected(pos, placer:get_player_name()) then
|
||||
hyperloop.chat(placer, S("Area is protected!"))
|
||||
return false
|
||||
elseif minetest.get_node_or_nil(pos).name ~= "air" then
|
||||
hyperloop.chat(placer, S("Not enough space to build the station!"))
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local station_formspec =
|
||||
"size[8,9]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"label[2,0;"..S("Hyperloop Station Pod Builder").."]" ..
|
||||
"image[0.2,0.9;3,3;hyperloop_station_formspec.png]"..
|
||||
"list[context;src;3,0.9;1,4;]"..
|
||||
"label[4,1.2;30 x "..S("Hyperloop Pod Shell").."]" ..
|
||||
"item_image[3,0.9;1,1;hyperloop:pod_wall]"..
|
||||
"label[4,2.2;4 x "..S("Hypersteel Ingot").."]" ..
|
||||
"item_image[3,1.9;1,1;hyperloop:hypersteel_ingot]"..
|
||||
"label[4,3.2;2 x "..S("Blue Wool").."]" ..
|
||||
"item_image[3,2.9;1,1;wool:blue]"..
|
||||
"label[4,4.2;2 x "..S("Glass").."]" ..
|
||||
"item_image[3,3.9;1,1;default:glass]"..
|
||||
"list[current_player;main;0,5.3;8,4;]"..
|
||||
"listring[context;src]"..
|
||||
"listring[current_player;main]"
|
||||
|
||||
|
||||
local function allow_metadata_inventory(pos, listname, index, stack, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return 0
|
||||
end
|
||||
if M(pos):get_int("busy") == 1 then
|
||||
return 0
|
||||
end
|
||||
return stack:get_count()
|
||||
end
|
||||
|
||||
local function check_inventory(inv, player)
|
||||
local list = inv:get_list("src")
|
||||
if list[1]:get_name() == "hyperloop:pod_wall" and list[1]:get_count() >= 30 then
|
||||
if list[2]:get_name() == "hyperloop:hypersteel_ingot" and list[2]:get_count() >= 4 then
|
||||
if list[3]:get_name() == "wool:blue" and list[3]:get_count() >= 2 then
|
||||
if list[4]:get_name() == "default:glass" and list[4]:get_count() >= 2 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
hyperloop.chat(player, S("Not enough inventory items to build the station!"))
|
||||
return false
|
||||
end
|
||||
|
||||
local function remove_inventory_items(inv, meta)
|
||||
inv:remove_item("src", ItemStack("hyperloop:pod_wall 30"))
|
||||
inv:remove_item("src", ItemStack("hyperloop:hypersteel_ingot 4"))
|
||||
inv:remove_item("src", ItemStack("wool:blue 2"))
|
||||
inv:remove_item("src", ItemStack("default:glass 2"))
|
||||
meta:set_int("busy", 0)
|
||||
end
|
||||
|
||||
local function add_inventory_items(inv)
|
||||
inv:add_item("src", ItemStack("hyperloop:pod_wall 30"))
|
||||
inv:add_item("src", ItemStack("hyperloop:hypersteel_ingot 4"))
|
||||
inv:add_item("src", ItemStack("wool:blue 2"))
|
||||
inv:add_item("src", ItemStack("default:glass 2"))
|
||||
end
|
||||
|
||||
local function build_station(pos, placer)
|
||||
-- check protection
|
||||
if minetest.is_protected(pos, placer:get_player_name()) then
|
||||
return
|
||||
end
|
||||
local meta = M(pos)
|
||||
local inv = meta:get_inventory()
|
||||
local facedir = hyperloop.get_facedir(placer)
|
||||
-- do a facedir correction
|
||||
facedir = (facedir + 3) % 4 -- face to LCD
|
||||
if check_inventory(inv, placer) then
|
||||
Stations:update(pos, {facedir = facedir})
|
||||
|
||||
if check_space(table.copy(pos), facedir, placer) then
|
||||
construct(1, table.copy(pos), facedir, placer:get_player_name(), SP(pos))
|
||||
meta:set_string("formspec", station_formspec ..
|
||||
"button_exit[0,3.9;3,1;destroy;"..S("Destroy Station").."]")
|
||||
meta:set_int("built", 1)
|
||||
meta:set_int("busy", 1)
|
||||
-- remove items aften the station is build
|
||||
minetest.after(20, remove_inventory_items, inv, meta)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function on_destruct(pos)
|
||||
Stations:update(pos, {
|
||||
booking_pos = "nil",
|
||||
booking_info = "nil",
|
||||
name = "Station",
|
||||
})
|
||||
end
|
||||
|
||||
local function destroy_station(pos, player_name)
|
||||
-- check protection
|
||||
if minetest.is_protected(pos, player_name) then
|
||||
return
|
||||
end
|
||||
|
||||
local station = Stations:get(pos)
|
||||
if station then
|
||||
-- remove nodes
|
||||
local _pos = table.copy(pos)
|
||||
for _,item in ipairs(AssemblyPlan) do
|
||||
local y, path, _ = item[1], item[2], item[4]
|
||||
_pos = hyperloop.new_pos(_pos, station.facedir, path, y)
|
||||
minetest.remove_node(_pos)
|
||||
end
|
||||
on_destruct(pos)
|
||||
-- maintain meta
|
||||
local meta = M(pos)
|
||||
meta:set_string("formspec", station_formspec ..
|
||||
"button_exit[0,3.9;3,1;build;"..S("Build Station").."]")
|
||||
local inv = meta:get_inventory()
|
||||
add_inventory_items(inv)
|
||||
meta:set_int("built", 0)
|
||||
else
|
||||
M(pos):set_int("built", 0)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("hyperloop:station", {
|
||||
description = S("Hyperloop Station Block"),
|
||||
drawtype = "nodebox",
|
||||
tiles = {
|
||||
"hyperloop_station.png",
|
||||
"hyperloop_station_connection.png",
|
||||
"hyperloop_station_connection.png",
|
||||
},
|
||||
|
||||
on_construct = function(pos)
|
||||
local meta = M(pos)
|
||||
meta:set_string("formspec", station_formspec ..
|
||||
"button_exit[0,3.9;3,1;build;"..S("Build Station").."]")
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size('src', 4)
|
||||
end,
|
||||
|
||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||
hyperloop.check_network_level(pos, placer)
|
||||
M(pos):set_string("infotext", S("Station"))
|
||||
store_station(pos, placer)
|
||||
Tube:after_place_node(pos)
|
||||
end,
|
||||
|
||||
allow_metadata_inventory_put = allow_metadata_inventory,
|
||||
allow_metadata_inventory_take = allow_metadata_inventory,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, player)
|
||||
if fields.destroy ~= nil then
|
||||
destroy_station(pos, player:get_player_name())
|
||||
elseif fields.build ~= nil then
|
||||
build_station(pos, player)
|
||||
end
|
||||
end,
|
||||
|
||||
on_dig = function(pos, node, puncher, pointed_thing)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
if inv:is_empty("src") and meta:get_int("built") ~= 1 then
|
||||
minetest.node_dig(pos, node, puncher, pointed_thing)
|
||||
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 = {cracky = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop:pod_wall", {
|
||||
description = S("Hyperloop Pod Shell"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_skin2.png",
|
||||
"hyperloop_skin2.png",
|
||||
"hyperloop_skin.png",
|
||||
},
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype2 = "facedir",
|
||||
groups = {cracky=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop:pod_wall_ni", {
|
||||
description = S("Hyperloop Pod Shell"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_skin2.png",
|
||||
"hyperloop_skin2.png",
|
||||
"hyperloop_skin.png",
|
||||
},
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype2 = "facedir",
|
||||
groups = {cracky=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
drop = "",
|
||||
})
|
||||
|
||||
minetest.register_node("hyperloop:pod_floor", {
|
||||
description = S("Hyperloop Pod Shell"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"hyperloop_skin2.png",
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-8/16, -8/16, -8/16, 8/16, -7.5/16, 8/16},
|
||||
},
|
||||
},
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype2 = "facedir",
|
||||
groups = {cracky=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
drop = "",
|
||||
})
|
||||
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 138 B |
|
After Width: | Height: | Size: 143 B |
|
After Width: | Height: | Size: 141 B |
|
After Width: | Height: | Size: 143 B |
|
After Width: | Height: | Size: 141 B |
|
After Width: | Height: | Size: 141 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 141 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 137 B |
|
After Width: | Height: | Size: 137 B |
|
After Width: | Height: | Size: 138 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 138 B |
|
After Width: | Height: | Size: 134 B |
|
After Width: | Height: | Size: 135 B |
|
After Width: | Height: | Size: 138 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 144 B |
|
After Width: | Height: | Size: 132 B |
|
After Width: | Height: | Size: 135 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 132 B |
|
After Width: | Height: | Size: 135 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 141 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 135 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 135 B |
|
After Width: | Height: | Size: 131 B |
|
After Width: | Height: | Size: 138 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 138 B |
|
After Width: | Height: | Size: 138 B |
|
After Width: | Height: | Size: 142 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 138 B |
|
After Width: | Height: | Size: 134 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 132 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 144 B |
|
After Width: | Height: | Size: 135 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 138 B |
|
After Width: | Height: | Size: 132 B |
|
After Width: | Height: | Size: 140 B |