From 18fc18b5aece7aae1caafd38a2c742af7974348c Mon Sep 17 00:00:00 2001 From: Vanessa Dannenberg Date: Sun, 10 Mar 2019 19:44:56 -0400 Subject: [PATCH] update cottages, digilines, locks, maptools, moreblocks, technic, and travelnet --- cottages/nodes_water.lua | 1 + digilines/.luacheckrc | 2 + digilines/init.lua | 10 +- digilines/internal.lua | 11 +- digilines/inventory.lua | 289 +++++++++++++++----- digilines/lcd.lua | 2 +- locks/init.lua | 7 +- maptools/.travis.yml | 15 + maptools/CHANGELOG.md | 5 + maptools/README.md | 13 +- maptools/craftitems.lua | 2 +- maptools/default_nodes.lua | 2 +- maptools/init.lua | 20 +- maptools/intllib.lua | 44 +++ maptools/nodes.lua | 51 ++-- maptools/tools.lua | 59 ++-- moreblocks/.travis.yml | 15 + moreblocks/CHANGELOG.md | 13 +- moreblocks/README.md | 13 +- moreblocks/circular_saw.lua | 2 +- moreblocks/init.lua | 16 +- moreblocks/intllib.lua | 44 +++ moreblocks/nodes.lua | 2 +- moreblocks/ownership.lua | 2 +- moreblocks/stairsplus/common.lua | 2 +- moreblocks/stairsplus/custom.lua | 3 +- moreblocks/stairsplus/init.lua | 3 +- moreblocks/stairsplus/microblocks.lua | 3 +- moreblocks/stairsplus/panels.lua | 3 +- moreblocks/stairsplus/slabs.lua | 6 +- moreblocks/stairsplus/slopes.lua | 3 +- moreblocks/stairsplus/stairs.lua | 3 +- moreores/.travis.yml | 15 + moreores/CHANGELOG.md | 1 + moreores/README.md | 13 +- moreores/init.lua | 11 +- moreores/intllib.lua | 44 +++ technic/machines/HV/quarry.lua | 2 +- technic/tools/chainsaw.lua | 2 + travelnet/config.lua | 13 +- travelnet/etc/travelnet_bell.mmpz | Bin 0 -> 2884 bytes travelnet/etc/travelnet_bell.xml | 7 + travelnet/etc/travelnet_travel.mmpz | Bin 0 -> 2937 bytes travelnet/etc/travelnet_travel.xml | 7 + travelnet/init.lua | 210 ++++++++------ travelnet/intllib.lua | 45 +++ travelnet/locale/de.po | 326 ++++++++++++++++++++++ travelnet/locale/de.txt | 94 ------- travelnet/locale/ru.po | 377 ++++++++++++++++++++++++++ travelnet/locale/template.pot | 372 +++++++++++++++++++++++++ travelnet/locale/template.txt | 94 ------- travelnet/mod.conf | 1 + travelnet/sounds/travelnet_bell.ogg | Bin 0 -> 19085 bytes travelnet/sounds/travelnet_travel.ogg | Bin 0 -> 53124 bytes travelnet/travelnet.lua | 4 +- 55 files changed, 1829 insertions(+), 475 deletions(-) create mode 100644 maptools/.travis.yml create mode 100644 maptools/intllib.lua create mode 100644 moreblocks/.travis.yml create mode 100644 moreblocks/intllib.lua create mode 100644 moreores/.travis.yml create mode 100644 moreores/intllib.lua create mode 100644 travelnet/etc/travelnet_bell.mmpz create mode 100644 travelnet/etc/travelnet_bell.xml create mode 100644 travelnet/etc/travelnet_travel.mmpz create mode 100644 travelnet/etc/travelnet_travel.xml create mode 100644 travelnet/intllib.lua create mode 100644 travelnet/locale/de.po delete mode 100644 travelnet/locale/de.txt create mode 100644 travelnet/locale/ru.po create mode 100644 travelnet/locale/template.pot delete mode 100644 travelnet/locale/template.txt create mode 100644 travelnet/mod.conf create mode 100644 travelnet/sounds/travelnet_bell.ogg create mode 100644 travelnet/sounds/travelnet_travel.ogg diff --git a/cottages/nodes_water.lua b/cottages/nodes_water.lua index 1cfe77df..c2bb1185 100644 --- a/cottages/nodes_water.lua +++ b/cottages/nodes_water.lua @@ -16,6 +16,7 @@ -- how many seconds does it take to fill a bucket? cottages.water_fill_time = 10 +local S = cottages.S -- code taken from the itemframes mod in homedecor -- (the relevant functions are sadly private there and thus cannot be reused) diff --git a/digilines/.luacheckrc b/digilines/.luacheckrc index 6d89a3f0..b356748e 100644 --- a/digilines/.luacheckrc +++ b/digilines/.luacheckrc @@ -1,5 +1,7 @@ read_globals = { + "vector", + "screwdriver", "minetest", "default", "pipeworks", diff --git a/digilines/init.lua b/digilines/init.lua index 21c1c8ee..93c94e98 100644 --- a/digilines/init.lua +++ b/digilines/init.lua @@ -64,19 +64,19 @@ minetest.register_craft({ } }) --- former submods -if minetest.is_yes(minetest.setting_get("digilines_enable_inventory") or true) then +-- For minetest 0.4 support returned nil are also tested: ~= false +if minetest.settings:get_bool("digilines_enable_inventory", true) ~= false then dofile(modpath .. "/inventory.lua") end -if minetest.is_yes(minetest.setting_get("digilines_enable_lcd") or true) then +if minetest.settings:get_bool("digilines_enable_lcd", true) ~= false then dofile(modpath .. "/lcd.lua") end -if minetest.is_yes(minetest.setting_get("digilines_enable_lightsensor") or true) then +if minetest.settings:get_bool("digilines_enable_lightsensor", true) ~= false then dofile(modpath .. "/lightsensor.lua") end -if minetest.is_yes(minetest.setting_get("digilines_enable_rtc") or true) then +if minetest.settings:get_bool("digilines_enable_rtc", true) ~= false then dofile(modpath .. "/rtc.lua") end diff --git a/digilines/internal.lua b/digilines/internal.lua index 2528f35a..05c93faa 100644 --- a/digilines/internal.lua +++ b/digilines/internal.lua @@ -1,6 +1,7 @@ function digilines.getspec(node) - if not minetest.registered_nodes[node.name] then return false end - return minetest.registered_nodes[node.name].digiline + local def = minetest.registered_nodes[node.name] + if not def then return false end + return def.digilines or def.digiline end function digilines.importrules(spec, node) @@ -86,6 +87,12 @@ local function queue_dequeue(queue) end function digilines.transmit(pos, channel, msg, checked) + local checkedID = minetest.hash_node_position(pos) + if checked[checkedID] then + return + end + checked[checkedID] = true + digilines.vm_begin() local queue = queue_new() queue_enqueue(queue, pos) diff --git a/digilines/inventory.lua b/digilines/inventory.lua index 693f882f..86b1536e 100644 --- a/digilines/inventory.lua +++ b/digilines/inventory.lua @@ -1,33 +1,56 @@ local pipeworks_enabled = minetest.get_modpath("pipeworks") ~= nil -local function sendMessage(pos, msg, channel) - if channel == nil then - channel = minetest.get_meta(pos):get_string("channel") - end - digilines.receptor_send(pos,digilines.rules.default,channel,msg) +-- Sends a message onto the Digilines network. +-- pos: the position of the Digilines chest node. +-- action: the action string indicating what happened. +-- stack: the ItemStack that the action acted on (optional). +-- from_slot: the slot number that is taken from (optional). +-- to_slot: the slot number that is put into (optional). +-- side: which side of the chest the action occurred (optional). +local function send_message(pos, action, stack, from_slot, to_slot, side) + local channel = minetest.get_meta(pos):get_string("channel") + local msg = { + action = action, + stack = stack and stack:to_table(), + from_slot = from_slot, + to_slot = to_slot, + -- Duplicate the vector in case the caller expects it not to change. + side = side and vector.new(side) + } + digilines.receptor_send(pos, digilines.rules.default, channel, msg) end -local function maybeString(stack) - if type(stack)=='string' then return stack - elseif type(stack)=='table' then return dump(stack) - else return stack:to_string() +-- Checks if the inventory has become empty and, if so, sends an empty message. +local function check_empty(pos) + if minetest.get_meta(pos):get_inventory():is_empty("main") then + send_message(pos, "empty") end end -local function can_insert(pos, stack) - local can = minetest.get_meta(pos):get_inventory():room_for_item("main", stack) - if can then - sendMessage(pos,"put "..maybeString(stack)) - else - -- overflow and lost means that items are gonna be out as entities :/ - sendMessage(pos,"lost "..maybeString(stack)) +-- Checks if the inventory has become full for a particular type of item and, +-- if so, sends a full message. +local function check_full(pos, stack) + local one_item_stack = ItemStack(stack) + one_item_stack:set_count(1) + if not minetest.get_meta(pos):get_inventory():room_for_item("main", one_item_stack) then + send_message(pos, "full", one_item_stack) end - return can end local tubeconn = pipeworks_enabled and "^pipeworks_tube_connection_wooden.png" or "" local tubescan = pipeworks_enabled and function(pos) pipeworks.scan_for_tube_objects(pos) end or nil +-- A place to remember things from allow_metadata_inventory_put to +-- on_metadata_inventory_put. This is a hack due to issue +-- minetest/minetest#6534 that should be removed once that’s fixed. +local last_inventory_put_index +local last_inventory_put_stack + +-- A place to remember things from allow_metadata_inventory_take to +-- tube.remove_items. This is a hack due to issue minetest-mods/pipeworks#205 +-- that should be removed once that’s fixed. +local last_inventory_take_index + minetest.register_alias("digilines_inventory:chest", "digilines:chest") minetest.register_node("digilines:chest", { description = "Digiline Chest", @@ -86,63 +109,203 @@ minetest.register_node("digilines:chest", { return not pipeworks.connects.facingFront(i,param2) end, input_inventory = "main", - can_insert = function(pos, _, stack) - return can_insert(pos, stack) - end, - insert_object = function(pos, _, stack) - local inv = minetest.get_meta(pos):get_inventory() - local leftover = inv:add_item("main", stack) - local count = leftover:get_count() - if count == 0 then - local derpstack = stack:get_name()..' 1' - if not inv:room_for_item("main", derpstack) then - -- when you can't put a single more of whatever you just put, - -- you'll get a put for it, then a full - sendMessage(pos,"full "..maybeString(stack)..' '..tostring(count)) - end - else - -- this happens when the chest has received two stacks in a row and - -- filled up exactly with the first one. - -- You get a put for the first stack, a put for the second - -- and then a overflow with the first in stack and the second in leftover - -- and NO full? - sendMessage(pos,"overflow "..maybeString(stack)..' '..tostring(count)) + can_insert = function(pos, _, stack, direction) + local ret = minetest.get_meta(pos):get_inventory():room_for_item("main", stack) + if not ret then + -- The stack cannot be accepted. It will never be passed to + -- insert_object, but it should be reported as a toverflow. + -- Here, direction = direction item is moving, which is into + -- side. + local side = vector.multiply(direction, -1) + send_message(pos, "toverflow", stack, nil, nil, side) end - return leftover + return ret + end, + insert_object = function(pos, _, original_stack, direction) + -- Here, direction = direction item is moving, which is into side. + local side = vector.multiply(direction, -1) + local inv = minetest.get_meta(pos):get_inventory() + local inv_contents = inv:get_list("main") + local any_put = false + local stack = original_stack + local stack_name = stack:get_name() + local stack_count = stack:get_count() + -- Walk the inventory, adding items to existing stacks of the same + -- type. + for i = 1, #inv_contents do + local existing_stack = inv_contents[i] + if not existing_stack:is_empty() and existing_stack:get_name() == stack_name then + local leftover = existing_stack:add_item(stack) + local leftover_count = leftover:get_count() + if leftover_count ~= stack_count then + -- We put some items into the slot. Update the slot in + -- the inventory, tell Digilines listeners about it, + -- and keep looking for the a place to put the + -- leftovers if any. + any_put = true + inv:set_stack("main", i, existing_stack) + local stack_that_was_put + if leftover_count == 0 then + stack_that_was_put = stack + else + stack_that_was_put = ItemStack(stack) + stack_that_was_put:set_count(stack_count - leftover_count) + end + send_message(pos, "tput", stack_that_was_put, nil, i, side) + stack = leftover + stack_count = leftover_count + if stack_count == 0 then + break + end + end + end + end + if stack_count ~= 0 then + -- Walk the inventory, adding items to empty slots. + for i = 1, #inv_contents do + local existing_stack = inv_contents[i] + if existing_stack:is_empty() then + local leftover = existing_stack:add_item(stack) + local leftover_count = leftover:get_count() + if leftover_count ~= stack_count then + -- We put some items into the slot. Update the slot in + -- the inventory, tell Digilines listeners about it, + -- and keep looking for the a place to put the + -- leftovers if any. + any_put = true + inv:set_stack("main", i, existing_stack) + local stack_that_was_put + if leftover_count == 0 then + stack_that_was_put = stack + else + stack_that_was_put = ItemStack(stack) + stack_that_was_put:set_count(stack_count - leftover_count) + end + send_message(pos, "tput", stack_that_was_put, nil, i, side) + stack = leftover + stack_count = leftover_count + if stack_count == 0 then + break + end + end + end + end + end + if any_put then + check_full(pos, original_stack) + end + if stack_count ~= 0 then + -- Some items could not be added and bounced back. Report them. + send_message(pos, "toverflow", stack, nil, nil, side) + end + return stack + end, + remove_items = function(pos, _, stack, dir, count) + -- Here, stack is the ItemStack in our own inventory that is being + -- pulled from, NOT the stack that is actually pulled out. + -- Combining it with count gives the stack that is pulled out. + -- Also, note that Pipeworks doesn’t pass the index to this + -- function, so we use the one recorded in + -- allow_metadata_inventory_take; because we don’t implement + -- tube.can_remove, Pipeworks will call + -- allow_metadata_inventory_take instead and will pass it the + -- index. + local taken = stack:take_item(count) + minetest.get_meta(pos):get_inventory():set_stack("main", last_inventory_take_index, stack) + send_message(pos, "ttake", taken, last_inventory_take_index, nil, dir) + check_empty(pos) + return taken end, }, - allow_metadata_inventory_put = function(pos, _, _, stack) - if not can_insert(pos, stack) then - sendMessage(pos,"uoverflow "..maybeString(stack)) - end + allow_metadata_inventory_put = function(pos, _, index, stack) + -- Remember what was in the target slot before the put; see + -- on_metadata_inventory_put for why we care. + last_inventory_put_index = index + last_inventory_put_stack = minetest.get_meta(pos):get_inventory():get_stack("main", index) return stack:get_count() end, - on_metadata_inventory_move = function(pos, _, _, _, _, _, player) + allow_metadata_inventory_take = function(_, _, index, stack) + -- Remember the index value; see tube.remove_items for why we care. + last_inventory_take_index = index + return stack:get_count() + end, + on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + -- See what would happen if we were to move the items back from in the + -- opposite direction. In the event of a normal move, this must + -- succeed, because a normal move subtracts some items from the from + -- stack and adds them to the to stack; the two stacks naturally must + -- be compatible and so the reverse operation must succeed. However, if + -- the user *swaps* the two stacks instead, then due to issue + -- minetest/minetest#6534, this function is only called once; however, + -- when it is called, the stack that used to be in the to stack has + -- already been moved to the from stack, so we can detect the situation + -- by the fact that the reverse move will fail due to the from stack + -- being incompatible with its former contents. + local inv = minetest.get_meta(pos):get_inventory() + local from_stack = inv:get_stack("main", from_index) + local to_stack = inv:get_stack("main", to_index) + local reverse_move_stack = ItemStack(to_stack) + reverse_move_stack:set_count(count) + local swapped = from_stack:add_item(reverse_move_stack):get_count() == count + if swapped then + local channel = minetest.get_meta(pos):get_string("channel") + to_stack:set_count(count) + local msg = { + action = "uswap", + -- The slot and stack do not match because this function is + -- called after the action has taken place, but the Digilines + -- message is from the perspective of a viewer who hasn’t + -- observed the movement yet. + x_stack = to_stack:to_table(), + x_slot = from_index, + y_stack = from_stack:to_table(), + y_slot = to_index, + } + digilines.receptor_send(pos, digilines.rules.default, channel, msg) + else + to_stack:set_count(count) + send_message(pos, "umove", to_stack, from_index, to_index) + end minetest.log("action", player:get_player_name().." moves stuff in chest at "..minetest.pos_to_string(pos)) end, - on_metadata_inventory_put = function(pos, _, _, stack, player) - local channel = minetest.get_meta(pos):get_string("channel") - local send = function(msg) - sendMessage(pos,msg,channel) - end - -- direction is only for furnaces - -- as the item has already been put, can_insert should return false if the chest is now full. - local derpstack = stack:get_name()..' 1' - if can_insert(pos,derpstack) then - send("uput "..maybeString(stack)) + on_metadata_inventory_put = function(pos, _, index, stack, player) + -- Get what was in the target slot before the put; it has disappeared + -- by now (been replaced by the result of the put action) but we saved + -- it in allow_metadata_inventory_put. This should always work + -- (allow_metadata_inventory_put should AFAICT always be called + -- immediately before on_metadata_inventory_put), but in case of + -- something weird happening, just fall back to using an empty + -- ItemStack rather than crashing. + local old_stack + if last_inventory_put_index == index then + old_stack = last_inventory_put_stack + last_inventory_put_index = nil + last_inventory_put_stack = nil else - send("ufull "..maybeString(stack)) + old_stack = ItemStack(nil) end + -- If the player tries to place a stack into an inventory, there’s + -- already a stack there, and the existing stack is either of a + -- different item type or full, then obviously the stacks can’t be + -- merged; instead the stacks are swapped. This information is not + -- reported to mods (Minetest core neither tells us that a particular + -- action was a swap, nor tells us a take followed by a put). In core, + -- the condition for swapping is that you try to add the new stack to + -- the existing stack and the leftovers are as big as the original + -- stack to put. Replicate that logic here using the old stack saved in + -- allow_metadata_inventory_put. If a swap happened, report it to the + -- Digilines network as a utake followed by a uput. + local leftovers = old_stack:add_item(stack) + if leftovers:get_count() == stack:get_count() then + send_message(pos, "utake", old_stack, index) + end + send_message(pos, "uput", stack, nil, index) + check_full(pos, stack) minetest.log("action", player:get_player_name().." puts stuff into chest at "..minetest.pos_to_string(pos)) end, - on_metadata_inventory_take = function(pos, listname, _, stack, player) - local meta = minetest.get_meta(pos) - local channel = meta:get_string("channel") - local inv = meta:get_inventory() - if inv:is_empty(listname) then - sendMessage(pos, "empty", channel) - end - sendMessage(pos,"utake "..maybeString(stack)) + on_metadata_inventory_take = function(pos, _, index, stack, player) + send_message(pos, "utake", stack, index) + check_empty(pos) minetest.log("action", player:get_player_name().." takes stuff from chest at "..minetest.pos_to_string(pos)) end }) diff --git a/digilines/lcd.lua b/digilines/lcd.lua index a59b0b25..37ce3e05 100644 --- a/digilines/lcd.lua +++ b/digilines/lcd.lua @@ -178,7 +178,7 @@ end local spawn_entity = function(pos) if not get_entity(pos) then - local text = minetest.add_entity(pos, "digilines_lcd:text") + minetest.add_entity(pos, "digilines_lcd:text") rotate_text(pos) end end diff --git a/locks/init.lua b/locks/init.lua index e8a1355e..0f463c3e 100644 --- a/locks/init.lua +++ b/locks/init.lua @@ -46,7 +46,7 @@ minetest.register_privilege("diglocks", { description = "allows to open/use and locks.config_button = [[ - image_button[%d,%d;1,1;locks_lock16.png;locks_config;Config + image_button[%s,%s;1,1;locks_lock16.png;locks_config;Config Locks] tooltip[locks_config;Configure the players or set the password to grant access to other players.] ]] @@ -56,7 +56,7 @@ function locks.get_config_button(x,y) end locks.authorize_button = [[ - image_button[%d,%d;1,1;locks_key16.png;locks_authorize;Autho- + image_button[%s,%s;1,1;locks_key16.png;locks_authorize;Autho- rize] tooltip[locks_authorize;Opens a password prompt to grant you access to this object.] ]] @@ -181,6 +181,7 @@ function locks:lock_init( pos, default_formspec ) meta:set_string("allowed_users",""); -- objects can be unlocked by passwords as well (if it is set) meta:set_string("password",""); + meta:mark_as_private("password") -- the last player who entered the right password (to save space this is not a list) meta:set_string("pw_user",""); -- this formspec is presented on right-click for every user @@ -228,6 +229,7 @@ function locks:set_lockdata( pos, data ) meta:set_string("owner", (data.owner or "")); meta:set_string("allowed_users",(data.allowed_users or "")); meta:set_string("password", (data.password or "")); + meta:mark_as_private("password") meta:set_string("pw_user", (data.pw_user or "")); meta:set_string("formspec", (data.formspec or "")); end @@ -598,6 +600,7 @@ function locks:lock_handle_input( pos, formname, fields, player ) meta:set_string( "password", help[2]); + meta:mark_as_private("password") -- reset the list of users who typed the right password meta:set_string("pw_users",""); diff --git a/maptools/.travis.yml b/maptools/.travis.yml new file mode 100644 index 00000000..1c4c0d8a --- /dev/null +++ b/maptools/.travis.yml @@ -0,0 +1,15 @@ +language: generic + +addons: + apt: + packages: + - luarocks + +install: + - pyenv global 3.6.3 + - pip3 install --user pre-commit + - luarocks install --local luacheck + +script: + - $HOME/.local/bin/pre-commit run --all-files + - $HOME/.luarocks/bin/luacheck . diff --git a/maptools/CHANGELOG.md b/maptools/CHANGELOG.md index 0830e621..6e022a49 100644 --- a/maptools/CHANGELOG.md +++ b/maptools/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Changed + +- Increased the range of the Admin Pickaxe from 12 to 20 nodes. +- Updated intllib support to avoid using deprecated functions. + ## 1.0.0 - 2017-02-19 - Initial versioned release. diff --git a/maptools/README.md b/maptools/README.md index 7a14122c..9474ce56 100644 --- a/maptools/README.md +++ b/maptools/README.md @@ -12,15 +12,15 @@ world block sandbox game. To install Map Tools, clone this Git repository into your Minetest's `mods/` directory: -``` +```bash git clone https://github.com/minetest-mods/maptools.git ``` You can also [download a ZIP archive](https://github.com/minetest-mods/maptools/archive/master.zip) -of Map Tools. If you do so, you will need to extract the archive, then rename +of Map Tools. If you do so, you will need to extract the archive then rename the resulting folder from `maptools-master` to `maptools` – this is -**absolutely** necessary to do, else, it won't work! +**absolutely** required, as the mod won't work otherwise. ### Enable the mod @@ -43,16 +43,17 @@ This is the easiest way to enable Map Tools when playing in singleplayer This is the recommended way to enable the mod on a server without using a GUI. -1. Make sure Minetest is not currently running (else, it will overwrite +1. Make sure Minetest is not currently running (otherwise, it will overwrite the changes when exiting). 2. Open the world's `world.mt` file using a text editor. 3. Add the following line at the end of the file: -``` +```text load_mod_maptools = true ``` -If the line is already present in the file, then replace `false` with `true` on that line. +If the line is already present in the file, then replace `false` with `true` +on that line. 4. Save the file, then start a game on the world you enabled Map Tools on. 5. Map Tools should now be running on your world. diff --git a/maptools/craftitems.lua b/maptools/craftitems.lua index aa2330b4..00f09f27 100644 --- a/maptools/craftitems.lua +++ b/maptools/craftitems.lua @@ -5,7 +5,7 @@ Copyright © 2012-2019 Hugo Locurcio and contributors. Licensed under the zlib license. See LICENSE.md for more information. --]] -local S = maptools.intllib +local S = maptools.S maptools.creative = maptools.config["hide_from_creative_inventory"] diff --git a/maptools/default_nodes.lua b/maptools/default_nodes.lua index 89409f02..15ce9253 100644 --- a/maptools/default_nodes.lua +++ b/maptools/default_nodes.lua @@ -5,7 +5,7 @@ Copyright © 2012-2019 Hugo Locurcio and contributors. Licensed under the zlib license. See LICENSE.md for more information. --]] -local S = maptools.intllib +local S = maptools.S maptools.creative = maptools.config["hide_from_creative_inventory"] diff --git a/maptools/init.lua b/maptools/init.lua index a329f624..a7ae4a59 100644 --- a/maptools/init.lua +++ b/maptools/init.lua @@ -10,20 +10,11 @@ Licensed under the zlib license. See LICENSE.md for more information. maptools = {} -local S -if minetest.get_modpath("intllib") then - S = intllib.Getter() -else - S = function(s) return s end -end -maptools.intllib = S - local modpath = minetest.get_modpath("maptools") -maptools.drop_msg = function(itemstack, player) - local name = player:get_player_name() - minetest.chat_send_player(name, S("[maptools] tools/nodes do not drop!")) -end +local S, NS = dofile(modpath .. "/intllib.lua") +maptools.S = S +maptools.NS = NS dofile(modpath .. "/config.lua") dofile(modpath .. "/aliases.lua") @@ -32,6 +23,11 @@ dofile(modpath .. "/default_nodes.lua") dofile(modpath .. "/nodes.lua") dofile(modpath .. "/tools.lua") +maptools.drop_msg = function(itemstack, player) + local name = player:get_player_name() + minetest.chat_send_player(name, S("[maptools] tools/nodes do not drop!")) +end + if minetest.setting_getbool("log_mods") then minetest.log("action", S("[maptools] loaded.")) end diff --git a/maptools/intllib.lua b/maptools/intllib.lua new file mode 100644 index 00000000..c7af2c2b --- /dev/null +++ b/maptools/intllib.lua @@ -0,0 +1,44 @@ +-- Fallback functions for when `intllib` is not installed. +-- Code released under Unlicense . + +-- 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 diff --git a/maptools/nodes.lua b/maptools/nodes.lua index 3a2ebf54..200107f0 100644 --- a/maptools/nodes.lua +++ b/maptools/nodes.lua @@ -5,11 +5,11 @@ Copyright © 2012-2019 Hugo Locurcio and contributors. Licensed under the zlib license. See LICENSE.md for more information. --]] -local S = maptools.intllib +local S = maptools.S maptools.creative = maptools.config["hide_from_creative_inventory"] --- Redefine cloud so that the admin pickaxe can mine it: +-- Redefine cloud so that the admin pickaxe can mine it minetest.register_node(":default:cloud", { description = S("Cloud"), tiles = {"default_cloud.png"}, @@ -20,7 +20,6 @@ minetest.register_node(":default:cloud", { }) -- Nodes --- ===== minetest.register_node("maptools:black", { description = S("Black"), @@ -239,29 +238,29 @@ minetest.register_node("maptools:playerclip_top", { }) for pusher_num=1,10,1 do -minetest.register_node("maptools:pusher_" .. pusher_num, { - description = S("Pusher (%s)"):format(pusher_num), - range = 12, - stack_max = 10000, - inventory_image = "default_steel_block.png^default_apple.png", - drawtype = "nodebox", - tiles = {"invisible.png"}, - paramtype = "light", - paramtype2 = "facedir", - sunlight_propagates = true, - node_box = { - type = "fixed", - fixed = {-0.5, -0.5, -0.5, 0.5, -0.4999, 0.5}, - }, - drop = "", - groups = { - unbreakable = 1, - not_in_creative_inventory = maptools.creative, - fall_damage_add_percent = -100, - bouncy = pusher_num * 100, - }, - on_drop = maptools.drop_msg -}) + minetest.register_node("maptools:pusher_" .. pusher_num, { + description = S("Pusher (%s)"):format(pusher_num), + range = 12, + stack_max = 10000, + inventory_image = "default_steel_block.png^default_apple.png", + drawtype = "nodebox", + tiles = {"invisible.png"}, + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, -0.4999, 0.5}, + }, + drop = "", + groups = { + unbreakable = 1, + not_in_creative_inventory = maptools.creative, + fall_damage_add_percent = -100, + bouncy = pusher_num * 100, + }, + on_drop = maptools.drop_msg + }) end minetest.register_node("maptools:lightbulb", { diff --git a/maptools/tools.lua b/maptools/tools.lua index 9e784aec..550ab6b5 100644 --- a/maptools/tools.lua +++ b/maptools/tools.lua @@ -5,52 +5,41 @@ Copyright © 2012-2019 Hugo Locurcio and contributors. Licensed under the zlib license. See LICENSE.md for more information. --]] -local S = maptools.intllib +local S = maptools.S maptools.creative = maptools.config["hide_from_creative_inventory"] +local pick_admin_toolcaps = { + full_punch_interval = 0.1, + max_drop_level = 3, + groupcaps = { + unbreakable = {times = {[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, + fleshy = {times = {[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, + choppy = {times = {[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, + bendy = {times = {[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, + cracky = {times = {[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, + crumbly = {times = {[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, + snappy = {times = {[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, + }, + damage_groups = {fleshy = 1000}, +} + minetest.register_tool("maptools:pick_admin", { description = S("Admin Pickaxe"), - range = 12, + range = 20, inventory_image = "maptools_adminpick.png", groups = {not_in_creative_inventory = maptools.creative}, - tool_capabilities = { - full_punch_interval = 0.1, - max_drop_level = 3, - groupcaps= { - unbreakable = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - fleshy = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - choppy = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - bendy = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - cracky = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - crumbly = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - snappy = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - }, - damage_groups = {fleshy = 1000}, - }, - on_drop = maptools.drop_msg + tool_capabilities = pick_admin_toolcaps, + on_drop = maptools.drop_msg, }) minetest.register_tool("maptools:pick_admin_with_drops", { description = S("Admin Pickaxe with Drops"), - range = 12, + range = 20, inventory_image = "maptools_adminpick_with_drops.png", groups = {not_in_creative_inventory = maptools.creative}, - tool_capabilities = { - full_punch_interval = 0.35, - max_drop_level = 3, - groupcaps = { - unbreakable = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - fleshy = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - choppy = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - bendy = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - cracky = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - crumbly = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - snappy = {times={[1] = 0, [2] = 0, [3] = 0}, uses = 0, maxlevel = 3}, - }, - damage_groups = {fleshy = 1000}, - }, - on_drop = maptools.drop_msg + tool_capabilities = pick_admin_toolcaps, + on_drop = maptools.drop_msg, }) minetest.register_on_punchnode(function(pos, node, puncher) @@ -66,9 +55,9 @@ minetest.register_on_punchnode(function(pos, node, puncher) " using an Admin Pickaxe." ) -- The node is removed directly, which means it even works - -- on non-empty containers and group-less nodes. + -- on non-empty containers and group-less nodes minetest.remove_node(pos) - -- Run node update actions like falling nodes. + -- Run node update actions like falling nodes minetest.check_for_falling(pos) end end) diff --git a/moreblocks/.travis.yml b/moreblocks/.travis.yml new file mode 100644 index 00000000..1c4c0d8a --- /dev/null +++ b/moreblocks/.travis.yml @@ -0,0 +1,15 @@ +language: generic + +addons: + apt: + packages: + - luarocks + +install: + - pyenv global 3.6.3 + - pip3 install --user pre-commit + - luarocks install --local luacheck + +script: + - $HOME/.local/bin/pre-commit run --all-files + - $HOME/.luarocks/bin/luacheck . diff --git a/moreblocks/CHANGELOG.md b/moreblocks/CHANGELOG.md index 0d949aa6..aa9942c1 100644 --- a/moreblocks/CHANGELOG.md +++ b/moreblocks/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Changed + +- Updated intllib support to avoid using deprecated functions. + ### Fixed - Node rotation now works correctly when placing Stairs+ nodes. @@ -32,12 +36,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed -- New craft for: +- New crafting recipes for: - Stone Tile - Circle Stone Bricks - Stairs+: - - Move definitions to `stairsplus.defs` table in a separate file - - Move recipe definitions to `stairsplus.register_recipes` function in a separate file + - Moved definitions to `stairsplus.defs` table into a separate file. + - Moved recipe definitions to `stairsplus.register_recipes` function + into a separate file. ## [1.1.0] - 2017-10-04 @@ -57,7 +62,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Straw - Tin Block - Wool (all colors) -- Other mods can now get a list of all the defined Stairs+ shapes +- Other mods can now get a list of all the defined Stairs+ shapes. ## 1.0.0 - 2017-02-19 diff --git a/moreblocks/README.md b/moreblocks/README.md index 739164b5..4e588142 100644 --- a/moreblocks/README.md +++ b/moreblocks/README.md @@ -12,15 +12,15 @@ world block sandbox game. To install More Blocks, clone this Git repository into your Minetest's `mods/` directory: -``` +```bash git clone https://github.com/minetest-mods/moreblocks.git ``` You can also [download a ZIP archive](https://github.com/minetest-mods/moreblocks/archive/master.zip) -of More Blocks. If you do so, you will need to extract the archive, then rename +of More Blocks. If you do so, you will need to extract the archive then rename the resulting folder from `moreblocks-master` to `moreblocks` – this is -**absolutely** necessary to do, else, it won't work! +**absolutely** required, as the mod won't work otherwise. ### Enable the mod @@ -43,16 +43,17 @@ This is the easiest way to enable More Blocks when playing in singleplayer This is the recommended way to enable the mod on a server without using a GUI. -1. Make sure Minetest is not currently running (else, it will overwrite +1. Make sure Minetest is not currently running (otherwise, it will overwrite the changes when exiting). 2. Open the world's `world.mt` file using a text editor. 3. Add the following line at the end of the file: -``` +```text load_mod_moreblocks = true ``` -If the line is already present in the file, then replace `false` with `true` on that line. +If the line is already present in the file, then replace `false` with `true` +on that line. 4. Save the file, then start a game on the world you enabled More Blocks on. 5. More Blocks should now be running on your world. diff --git a/moreblocks/circular_saw.lua b/moreblocks/circular_saw.lua index 4d1a3d9a..1dce479c 100644 --- a/moreblocks/circular_saw.lua +++ b/moreblocks/circular_saw.lua @@ -5,7 +5,7 @@ Copyright © 2011-2019 Hugo Locurcio, Sokomine and contributors. Licensed under the zlib license. See LICENSE.md for more information. --]] -local S = moreblocks.intllib +local S = moreblocks.S circular_saw = {} diff --git a/moreblocks/init.lua b/moreblocks/init.lua index ad5ad254..7627f7d5 100644 --- a/moreblocks/init.lua +++ b/moreblocks/init.lua @@ -10,20 +10,12 @@ Licensed under the zlib license. See LICENSE.md for more information. moreblocks = {} -local S -if minetest.global_exists("intllib") then - if intllib.make_gettext_pair then - S = intllib.make_gettext_pair() - else - S = intllib.Getter() - end -else - S = function(s) return s end -end -moreblocks.intllib = S - local modpath = minetest.get_modpath("moreblocks") +local S, NS = dofile(modpath .. "/intllib.lua") +moreblocks.S = S +moreblocks.NS = NS + dofile(modpath .. "/config.lua") dofile(modpath .. "/circular_saw.lua") dofile(modpath .. "/stairsplus/init.lua") diff --git a/moreblocks/intllib.lua b/moreblocks/intllib.lua new file mode 100644 index 00000000..c7af2c2b --- /dev/null +++ b/moreblocks/intllib.lua @@ -0,0 +1,44 @@ +-- Fallback functions for when `intllib` is not installed. +-- Code released under Unlicense . + +-- 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 diff --git a/moreblocks/nodes.lua b/moreblocks/nodes.lua index 5bcab6c0..047f59e9 100644 --- a/moreblocks/nodes.lua +++ b/moreblocks/nodes.lua @@ -5,7 +5,7 @@ Copyright © 2011-2019 Hugo Locurcio and contributors. Licensed under the zlib license. See LICENSE.md for more information. --]] -local S = moreblocks.intllib +local S = moreblocks.S local sound_dirt = default.node_sound_dirt_defaults() local sound_wood = default.node_sound_wood_defaults() diff --git a/moreblocks/ownership.lua b/moreblocks/ownership.lua index 34bcffa4..20f0fe11 100644 --- a/moreblocks/ownership.lua +++ b/moreblocks/ownership.lua @@ -5,7 +5,7 @@ Copyright © 2011-2019 Hugo Locurcio and contributors. Licensed under the zlib license. See LICENSE.md for more information. --]] -local S = moreblocks.gettext +local S = moreblocks.S function moreblocks.node_is_owned(pos, placer) local ownername = false diff --git a/moreblocks/stairsplus/common.lua b/moreblocks/stairsplus/common.lua index 6ec51017..7b86fadd 100644 --- a/moreblocks/stairsplus/common.lua +++ b/moreblocks/stairsplus/common.lua @@ -5,7 +5,7 @@ Copyright © 2011-2019 Hugo Locurcio and contributors. Licensed under the zlib license. See LICENSE.md for more information. --]] -local S = moreblocks.intllib +local S = moreblocks.S stairsplus.register_single = function(category, alternate, info, modname, subname, recipeitem, fields) diff --git a/moreblocks/stairsplus/custom.lua b/moreblocks/stairsplus/custom.lua index ad67009a..4004c6cb 100644 --- a/moreblocks/stairsplus/custom.lua +++ b/moreblocks/stairsplus/custom.lua @@ -61,7 +61,8 @@ local subset = { } --]] -function register_custom_subset(subset, modname, subname, recipeitem, groups, images, description, drop, light) +-- luacheck: no unused +local function register_custom_subset(subset, modname, subname, recipeitem, groups, images, description, drop, light) stairsplus:register_custom_subset(subset, modname, subname, recipeitem, { groups = groups, tiles = images, diff --git a/moreblocks/stairsplus/init.lua b/moreblocks/stairsplus/init.lua index 0d99a14d..a3f3399e 100644 --- a/moreblocks/stairsplus/init.lua +++ b/moreblocks/stairsplus/init.lua @@ -58,7 +58,8 @@ function stairsplus:register_alias_force_all(modname_old, subname_old, modname_n self:register_micro_alias_force(modname_old, subname_old, modname_new, subname_new) end -function register_stair_slab_panel_micro(modname, subname, recipeitem, groups, images, description, drop, light) +-- luacheck: no unused +local function register_stair_slab_panel_micro(modname, subname, recipeitem, groups, images, description, drop, light) stairsplus:register_all(modname, subname, recipeitem, { groups = groups, tiles = images, diff --git a/moreblocks/stairsplus/microblocks.lua b/moreblocks/stairsplus/microblocks.lua index a08ec7c8..e4776648 100644 --- a/moreblocks/stairsplus/microblocks.lua +++ b/moreblocks/stairsplus/microblocks.lua @@ -7,7 +7,8 @@ Licensed under the zlib license. See LICENSE.md for more information. -- Node will be called :micro_ -function register_micro(modname, subname, recipeitem, groups, images, description, drop, light) +-- luacheck: no unused +local function register_micro(modname, subname, recipeitem, groups, images, description, drop, light) stairsplus:register_micro(modname, subname, recipeitem, { groups = groups, tiles = images, diff --git a/moreblocks/stairsplus/panels.lua b/moreblocks/stairsplus/panels.lua index c017af64..095c4c25 100644 --- a/moreblocks/stairsplus/panels.lua +++ b/moreblocks/stairsplus/panels.lua @@ -7,7 +7,8 @@ Licensed under the zlib license. See LICENSE.md for more information. -- Node will be called :panel_ -function register_panel(modname, subname, recipeitem, groups, images, description, drop, light) +-- luacheck: no unused +local function register_panel(modname, subname, recipeitem, groups, images, description, drop, light) stairsplus:register_panel(modname, subname, recipeitem, { groups = groups, tiles = images, diff --git a/moreblocks/stairsplus/slabs.lua b/moreblocks/stairsplus/slabs.lua index c41b2e34..ee9ce895 100644 --- a/moreblocks/stairsplus/slabs.lua +++ b/moreblocks/stairsplus/slabs.lua @@ -5,11 +5,10 @@ Copyright © 2011-2019 Hugo Locurcio and contributors. Licensed under the zlib license. See LICENSE.md for more information. --]] -local S = moreblocks.intllib - -- Node will be called :slab_ -function register_slab(modname, subname, recipeitem, groups, images, description, drop, light) +-- luacheck: no unused +local function register_slab(modname, subname, recipeitem, groups, images, description, drop, light) stairsplus:register_slab(modname, subname, recipeitem, { groups = groups, tiles = images, @@ -36,7 +35,6 @@ end function stairsplus:register_slab(modname, subname, recipeitem, fields) local defs = table.copy(stairsplus.defs["slab"]) - local desc_base = S("%s Slab"):format(fields.description) for alternate, shape in pairs(defs) do stairsplus.register_single("slab", alternate, shape, modname, subname, recipeitem, fields) end diff --git a/moreblocks/stairsplus/slopes.lua b/moreblocks/stairsplus/slopes.lua index 0652a51a..6e516d56 100644 --- a/moreblocks/stairsplus/slopes.lua +++ b/moreblocks/stairsplus/slopes.lua @@ -7,7 +7,8 @@ Licensed under the zlib license. See LICENSE.md for more information. -- Node will be called :slope_ -function register_slope(modname, subname, recipeitem, groups, images, description, drop, light) +-- luacheck: no unused +local function register_slope(modname, subname, recipeitem, groups, images, description, drop, light) stairsplus:register_slope(modname, subname, recipeitem, { groups = groups, tiles = images, diff --git a/moreblocks/stairsplus/stairs.lua b/moreblocks/stairsplus/stairs.lua index c72b2689..8c774985 100644 --- a/moreblocks/stairsplus/stairs.lua +++ b/moreblocks/stairsplus/stairs.lua @@ -7,7 +7,8 @@ Licensed under the zlib license. See LICENSE.md for more information. -- Node will be called :stair_ -function register_stair(modname, subname, recipeitem, groups, images, description, drop, light) +-- luacheck: no unused +local function register_stair(modname, subname, recipeitem, groups, images, description, drop, light) stairsplus:register_stair(modname, subname, recipeitem, { groups = groups, tiles = images, diff --git a/moreores/.travis.yml b/moreores/.travis.yml new file mode 100644 index 00000000..1c4c0d8a --- /dev/null +++ b/moreores/.travis.yml @@ -0,0 +1,15 @@ +language: generic + +addons: + apt: + packages: + - luarocks + +install: + - pyenv global 3.6.3 + - pip3 install --user pre-commit + - luarocks install --local luacheck + +script: + - $HOME/.local/bin/pre-commit run --all-files + - $HOME/.luarocks/bin/luacheck . diff --git a/moreores/CHANGELOG.md b/moreores/CHANGELOG.md index 6ec2e510..cd7bd337 100644 --- a/moreores/CHANGELOG.md +++ b/moreores/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed - Ores are now slower to mine and cannot be mined using wooden tools anymore. +- Updated intllib support to avoid using deprecated functions. ### Deprecated diff --git a/moreores/README.md b/moreores/README.md index 5b4877e7..601001b1 100644 --- a/moreores/README.md +++ b/moreores/README.md @@ -12,15 +12,15 @@ world block sandbox game. To install More Ores, clone this Git repository into your Minetest's `mods/` directory: -``` +```bash git clone https://github.com/minetest-mods/moreores.git ``` You can also [download a ZIP archive](https://github.com/minetest-mods/moreores/archive/master.zip) -of More Ores. If you do so, you will need to extract the archive, then rename +of More Ores. If you do so, you will need to extract the archive then rename the resulting folder from `moreores-master` to `moreores` – this is -**absolutely** necessary to do, else, it won't work! +**absolutely** required, as the mod won't work otherwise. ### Enable the mod @@ -43,16 +43,17 @@ This is the easiest way to enable More Ores when playing in singleplayer This is the recommended way to enable the mod on a server without using a GUI. -1. Make sure Minetest is not currently running (else, it will overwrite +1. Make sure Minetest is not currently running (otherwise, it will overwrite the changes when exiting). 2. Open the world's `world.mt` file using a text editor. 3. Add the following line at the end of the file: -``` +```text load_mod_moreores = true ``` -If the line is already present in the file, then replace `false` with `true` on that line. +If the line is already present in the file, then replace `false` with `true` +on that line. 4. Save the file, then start a game on the world you enabled More Ores on. 5. More Ores should now be running on your world. diff --git a/moreores/init.lua b/moreores/init.lua index 08bc0a67..e3897781 100644 --- a/moreores/init.lua +++ b/moreores/init.lua @@ -10,15 +10,12 @@ Licensed under the zlib license. See LICENSE.md for more information. moreores = {} -local S -if minetest.get_modpath("intllib") then - S = intllib.Getter() -else - S = function(s) return s end -end - local modpath = minetest.get_modpath("moreores") +local S, NS = dofile(modpath .. "/intllib.lua") +moreores.S = S +moreores.NS = NS + dofile(modpath .. "/_config.txt") -- `mg` mapgen support diff --git a/moreores/intllib.lua b/moreores/intllib.lua new file mode 100644 index 00000000..c7af2c2b --- /dev/null +++ b/moreores/intllib.lua @@ -0,0 +1,44 @@ +-- Fallback functions for when `intllib` is not installed. +-- Code released under Unlicense . + +-- 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 diff --git a/technic/machines/HV/quarry.lua b/technic/machines/HV/quarry.lua index b6f9c14e..1671c4e0 100644 --- a/technic/machines/HV/quarry.lua +++ b/technic/machines/HV/quarry.lua @@ -129,7 +129,7 @@ local function quarry_run(pos, node) vector.multiply(qdir, -radius)) local owner = meta:get_string("owner") local nd = meta:get_int("dug") - while nd ~= diameter*diameter * (quarry_dig_above_nodes+1+quarry_max_depth) do + while nd < diameter*diameter * (quarry_dig_above_nodes+1+quarry_max_depth) do local ry = math.floor(nd / (diameter*diameter)) local ndl = nd % (diameter*diameter) if ry % 2 == 1 then diff --git a/technic/tools/chainsaw.lua b/technic/tools/chainsaw.lua index 8245fd6f..4b9ccfd1 100644 --- a/technic/tools/chainsaw.lua +++ b/technic/tools/chainsaw.lua @@ -51,6 +51,7 @@ if minetest.get_modpath("moretrees") then timber_nodenames["moretrees:spruce_trunk"] = true timber_nodenames["moretrees:willow_trunk"] = true timber_nodenames["moretrees:jungletree_trunk"] = true + timber_nodenames["moretrees:poplar_trunk"] = true if chainsaw_leaves then timber_nodenames["moretrees:acacia_leaves"] = true @@ -75,6 +76,7 @@ if minetest.get_modpath("moretrees") then timber_nodenames["moretrees:pine_cone"] = true timber_nodenames["moretrees:fir_cone"] = true timber_nodenames["moretrees:apple_blossoms"] = true + timber_nodenames["moretrees:poplar_leaves"] = true end end diff --git a/travelnet/config.lua b/travelnet/config.lua index 519e66d9..83115de9 100644 --- a/travelnet/config.lua +++ b/travelnet/config.lua @@ -48,6 +48,7 @@ travelnet.travelnet_inventory_image = "travelnet_inv.png" travelnet.elevator_inventory_image = "travelnet_elevator_inv.png" if( minetest.registered_nodes["mcl_core:wood"]) then + local w_texture = "default_wood.png^[transformR90"; -- "mcl_doors_door_spruce_lower.png"; travelnet.travelnet_recipe = { {"mcl_stairs:slab_wood", "mcl_stairs:slab_wood", "mcl_stairs:slab_wood",}, {"mesecons_torch:mesecon_torch_on", "mcl_chests:chest", "mesecons_torch:mesecon_torch_on"}, @@ -65,11 +66,11 @@ if( minetest.registered_nodes["mcl_core:wood"]) then -- {"mcl_core:iron_ingot", "mcl_core:glass", "mcl_core:iron_ingot", } } travelnet.tiles_travelnet = { - "default_wood.png^[transformR90", -- backward view - "default_wood.png^[transformR90", -- front view - "default_wood.png^[transformR90", -- sides :) - "default_wood.png^[transformR90", -- view from top - "default_wood.png^[transformR90", -- view from bottom + w_texture, -- backward view + w_texture, -- front view + w_texture, -- sides :) + w_texture, -- view from top + w_texture, -- view from bottom } travelnet.tiles_elevator = { "mcl_core_planks_big_oak.png^[transformR90", -- front @@ -118,3 +119,5 @@ travelnet.allow_travel = function( player_name, owner_name, network_name, statio return true; end + +travelnet.travelnet_sound_enabled = true diff --git a/travelnet/etc/travelnet_bell.mmpz b/travelnet/etc/travelnet_bell.mmpz new file mode 100644 index 0000000000000000000000000000000000000000..161be57274f315c29245b20383dadb39f53fb22d GIT binary patch literal 2884 zcmV-K3%m3H06Kkmob6ldZ`(!^|DL~s)dANpCvulh$(CItc8V)5X@c0-!=WgG6}ggF z^A&Ps*>|}A{bnD0lak^%X&!}PfZUy(*Y3>xIHVRo+{KZ0OY~L#XE5Hp)%=_imgbGcrjDk$Z%*0_HFlrTvq_OA>q)ujZ1Upe z%d5%x6HQxeC<(M>76Y}-sl%8S;reZ|jcG1v?THqXg3&w+nZG%kpz{7UjbIgOtO{t7 z#$i&fGlT>#nqR;r%ZY#ErwJorLUZlzY~oC`4Gq^Db~dp%r+YDU8y4X*0<|&73X?Dn z|3d>Ic^3u@bZ}9}vY6b}R8m?gPb<V8A$}`k`!Pq19HckXu>x+N!C*7+BK^?<+E);TW-W^QCnO~pi-C#h0|K$ zCb_V(Jp-{oHO+eW;G3B170g2YBbvA(`w1WMK zB$>E0OA~U=V--f6XM=?#1-Yh_+oZ&tGTWr9RY6%tG;WGEh3Jw}PL(RlJMew2RBqOn zxW1GG(r|fQax_aG)dlXEg}Aa{2aFvbr2 zz;%lQ-1FkpRW#4yuqc`oDqX|fny|)QNmFY9H~zgJ(Q>A^39|v8=2;NtgH$<0DW(^E8TRuF~Ee4dje0NK;%^CMkvr1Z zzs8DYDixKus`5trcChGQkr-;ECg%DD-)t8ALXftLeO1pt%z_5%_tO3u1c>pB6h#C@ zM?-xBaMOV0vc`;ufnrKn3sM&OvHbFYgCo z!85Hsv7?*6gJU;@p_yW6=r6l`ya^%cmwc=kysn`x3x!tnWjmm-94}>`t zmu~^=RK|V_kf$>C>jyq%p!DI7nt2Qmq*#4zP)M2eO#mWg>wAKV@^p=WqlzGdvrh8_ z3JlGFA9mqzr^Qi)xcjtX^x=ik#sN*t(?KIg;hm>jmd1oZEgM5@P80Buid;||gHxpg z_$Eq5G$~|;vGG`ACheR9VnD zUuw8&tJoq@C3LqTd7Q$GErU)?d!ji5ipk*y9nayq>tRPUdz{uPR}ydIw`l-$u2M4@&c6?)gsZ+;@VEJ@DR*d<*_P*(3z*3men@W?dk&hW3M%0 zwk$GBH%Sq0rAJBNv~_^nsXMnCjj$Dz-z5=9u|a1w4Kll0c`Y4)*47cWxuT8Moh|Hi zTcoJVsq&TCmhV;at0BZ2n&2~p80FwUn{}T9X4R21cg2zZLYj8&r)b*E zX1Z;9)}M{LFQRdG3@WWa&c2QpFyj8J5X=n)wP&U(u8yPd9DfC-xVO|(N(@4`VPyMI z)aur+CdV-A0}w0f5?i zAf;V#H4n3O-a`fVXcfGM3dlRi8Tb6t@;#dI5P6{Q`@E&drte3zs$D)p(DL*MjdNIz zdq_^#oxSc<`|x*W0UGq!LbA%kC8Posa2!cj9`#9945-pwlSSKgm{hB-c9dqn{Pg&!F~Y-10aaOHph^7L zVHmC6KMdcbjO6!M86~{6{rIt{W0yZ&)B$PEJPQu&9~73Rd8oiwr{rMO!bek@M^l!k z#XP=jcRX1x6Vv_I;(V~>wgdUc;2`BpQ9_2WJog~^{P?{_$7)-rnNjp| zh`>BVP@j@RNTd5P!-wn`-g72CjPdb^W{jY-@gr38gIj~fG>@P7`EPu4+nb^w%3&AE_zE$J`HJ&x##srOQiuZLwTk`Lyx zGjiJ>)-kP{rcq#?e#yOz4+-un@kPkU)F_T zTwY(w2|#^@@%-nBHrX(iofyV$x6^l)p5|-g`i=4C`Ned@;>bou0nz3&JzxPG(*++q z7r*a2U&ItDg*@T!fM&z!9h->HnP?(|#5i9R?4ExjFX{&;F#MtbM%mxsp+NgD|LBR) zDNh~rgn#=q-Q^@Z)&BQnVThII3quN9rop`?hR*mmB?+6ZNE}A@C*Qxk(ylfX4#;J+ z*39ou4iZ(Q-Iyef}gP$_^=U(D2eNBxZ=A&^|51h;AE#xg idTo;xOy#`t@YZj13;Fv?L;e605`XLGr2hv>T5ziJow3va literal 0 HcmV?d00001 diff --git a/travelnet/etc/travelnet_bell.xml b/travelnet/etc/travelnet_bell.xml new file mode 100644 index 00000000..e62bc893 --- /dev/null +++ b/travelnet/etc/travelnet_bell.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/travelnet/etc/travelnet_travel.mmpz b/travelnet/etc/travelnet_travel.mmpz new file mode 100644 index 0000000000000000000000000000000000000000..a67a7df46c0d269cdcd96e3223fd6fb13257448a GIT binary patch literal 2937 zcmV-<3x@On06zwJob6ldZ{xTT|Gs~P&INj3YKhd-N}L?_k}X+oSsa|EL}~iK_`>9 z@7{fyoW9bu`I?eYTjU8)+nhQ|Xc?_8(@jDPNo!BEgp`aHdBlSC$plr;*I5jsP-|33 z(=3V7YMdb?aMAn+{A2|Qu7WIOBuZ(a-JDFEiMFQEYRyh27Uy((GMT{)qB2^uHNmo+o#x%pi-C# zg|kNCHo2H(x1USLU{4DcJR?O(&6CO0gk{{4YszPcghD0D*CAz_)Rb$Qg(O~O*2x51 zXbI~ROEU4(tfo+K9?K}^JXUf0+>J;r z&O;iD?vMs*L?K#qaL95~^3YW60gGvRU5O}f(*VpNHLGN_O~);F13oW}TZ!RXDDFa` zZeppJ$K^Wj8Ba_TOz;w>34ZX*r#UyI&v)8_bykF`Drw?jN>c)kE{L45K%b_E8w`}c3 zj^R?iIzscF3kK&0k+Pf$^L*9bVO z33BjtTBJ~5Xb$|a3(lRD2NmMo-HOqN7e*Hcv@y>P8aW8>yxy=ZAq;BS7-DnUfQQuN zg4!7DstmvvQ8J=wDNmR-s(uQCU>`R3kTKLRsnB^rRvOXNs%qOcBnsd}%Q8w=+8<+f ze8!6Sv@z8|(|lj7NE!v-`~g&^^xW|S)m$Hc*dn2%bh{=+l0lDbsJcCIhysf7X17DA zk}XLc8BS`1D;aK*%d89}IL%^D{Adlvaw;UXD=u#Jqvq>LtJAGGb>f;%Ezx0B@LnC5 z)g=6w$5eK71#oJK1OeR%IN~I;)gaHZS_eb8#oO)J#i`6DI~{onRvk_)p(HMdKyNJ~ zON^ZpOM6#xYsvvVG3b(mP9K_2JXPD?IupSG1nLJuH>5h7Zu4pUlK zouo+`hg;22hX08&JKocL1}Hf;cxEyRs&1RD7kl+zYS>FwEruT%pyc1}cyDO~Pn0=7xp{LhL0P``G?3sfPP^lYF%bNs}Oz+N} zLl_>l*gD|W-Lagpn|6_$cZxMG2`@_4g~(q<4zZ?hDP5R==! zf;&0@XcLa|+wx3*%rgg$r^LRDry&dcNh<>q(@R-o<7`zM&9zM3b_Q+?pz05D?z*hQ z@1w??b)Qn$M2tl2{X3;PzYv*SKICiz+ZC={RVg>uMo_f#Br5R4had{rXdTXAgc`41D<aU%0>gJWx~j(i(Q{bR;Rar-H!{gWF_d znE3&*<(tkPk*+oKbkDqZc-1Hb<8e1_g2M6~er@Ui~xd64Jr+uZ7|W%=XBRA^8( z?lpIcjOCd4!6J8ge-lTbB*`z6EX`i7uhr-huq%HNWMofSJIL;Uubf3l9Fg)8+i0jH z-?g}W>;qPIZm2t&s!28QOCZ_A8^ooPdOWKyy+4xR>K_r^^4loeYObS9^%;VX%mc2Y z#77IA>nJsgc^;88oQTS8glzsasneLOJJ1$3F1!s4}bfT z(J2ofdc%HH}ipd(e8UaU0Z+Km=?a^Is9`gag*^?`sEki*z!8%i2NNK@$FHZ + + + + + + diff --git a/travelnet/init.lua b/travelnet/init.lua index 7827a700..b1ceb6bf 100644 --- a/travelnet/init.lua +++ b/travelnet/init.lua @@ -1,5 +1,5 @@ - + --[[ Teleporter networks that allow players to choose a destination out of a list Copyright (C) 2013 Sokomine @@ -17,11 +17,17 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . - Version: 2.2 (with optional abm for self-healing) - + Version: 2.3 (click button to dig) + Please configure this mod in config.lua Changelog: + 10.03.19 - Added the extra config buttons for locked_travelnet mod. + 09.03.19 - Several PRs merged (sound added, locale changed etc.) + Version bumped to 2.3 + 26.02.19 - Removing a travelnet can now be done by clicking on a button (no need to + wield a diamond pick anymore) + 26.02.19 - Added compatibility with MineClone2 22.09.18 - Move up/move down no longer close the formspec. 22.09.18 - If in creative mode, wield a diamond pick to dig the station. This avoids conflicts with too fast punches. @@ -78,57 +84,65 @@ - target list is now centered if there are less than 9 targets --]] +-- Required to save the travelnet data properly in all cases +if not minetest.safe_file_write then + error("[Mod travelnet] Your Minetest version is no longer supported. (version < 0.4.17)") +end travelnet = {}; travelnet.targets = {}; +travelnet.path = minetest.get_modpath(minetest.get_current_modname()) --- Boilerplate to support localized strings if intllib mod is installed. -if minetest.get_modpath( "intllib" ) and intllib then - travelnet.S = intllib.Getter() -else - travelnet.S = function(s) return s end -end -local S = travelnet.S; +-- Intllib +local S = dofile(travelnet.path .. "/intllib.lua") +travelnet.S = S + minetest.register_privilege("travelnet_attach", { description = S("allows to attach travelnet boxes to travelnets of other players"), give_to_singleplayer = false}); minetest.register_privilege("travelnet_remove", { description = S("allows to dig travelnet boxes which belog to nets of other players"), give_to_singleplayer = false}); -- read the configuration -dofile(minetest.get_modpath("travelnet").."/config.lua"); -- the normal, default travelnet - +dofile(travelnet.path.."/config.lua"); -- the normal, default travelnet +travelnet.mod_data_path = minetest.get_worldpath().."/mod_travelnet.data" -- TODO: save and restore ought to be library functions and not implemented in each individual mod! -- called whenever a station is added or removed travelnet.save_data = function() - - local data = minetest.serialize( travelnet.targets ); - local path = minetest.get_worldpath().."/mod_travelnet.data"; - local file = io.open( path, "w" ); - if( file ) then - file:write( data ); - file:close(); - else - print(S("[Mod travelnet] Error: Savefile '%s' could not be written."):format(tostring(path))); + local data = minetest.serialize( travelnet.targets ); + + local success = minetest.safe_file_write( travelnet.mod_data_path, data ); + if( not success ) then + print(S("[Mod travelnet] Error: Savefile '%s' could not be written.") + :format(travelnet.mod_data_path)); end end travelnet.restore_data = function() - - local path = minetest.get_worldpath().."/mod_travelnet.data"; - local file = io.open( path, "r" ); - if( file ) then - local data = file:read("*all"); - travelnet.targets = minetest.deserialize( data ); - file:close(); - else - print(S("[Mod travelnet] Error: Savefile '%s' not found."):format(tostring(path))); + local file = io.open( travelnet.mod_data_path, "r" ); + if( not file ) then + print(S("[Mod travelnet] Error: Savefile '%s' not found.") + :format(travelnet.mod_data_path)); + return; end + + local data = file:read("*all"); + travelnet.targets = minetest.deserialize( data ); + + if( not travelnet.targets ) then + local backup_file = travelnet.mod_data_path..".bak" + print(S("[Mod travelnet] Error: Savefile '%s' is damaged. Saved the backup as '%s'.") + :format(travelnet.mod_data_path, backup_file)); + + minetest.safe_file_write( backup_file, data ); + travelnet.targets = {}; + end + file:close(); end @@ -191,6 +205,9 @@ end travelnet.form_input_handler = function( player, formname, fields) if(formname == "travelnet:show" and fields and fields.pos2str) then local pos = minetest.string_to_pos( fields.pos2str ); + if( locks and (fields.locks_config or fields.locks_authorize)) then + return locks:lock_handle_input( pos, formname, fields, player ) + end -- back button leads back to the main menu if( fields.back and fields.back ~= "" ) then return travelnet.show_current_formspec( pos, @@ -231,7 +248,7 @@ travelnet.reset_formspec = function( meta ) "field[0.3,2.8;9,0.9;station_network;"..S("Assign to Network:")..";".. minetest.formspec_escape(station_network or "").."]".. - "label[0.3,3.1;"..S("You can have more than one network. If unsure, use \"%s\""):format(tostring(station_network)).."\".]".. + "label[0.3,3.1;"..S("You can have more than one network. If unsure, use \"%s\""):format(tostring(station_network))..".]".. "field[0.3,4.4;9,0.9;owner;"..S("Owned by:")..";]".. "label[0.3,4.7;"..S("Unless you know what you are doing, leave this empty.").."]".. "button_exit[1.3,5.3;1.7,0.7;station_help_setup;"..S("Help").."]".. @@ -248,7 +265,7 @@ travelnet.update_formspec = function( pos, puncher_name, fields ) if( this_node ~= nil and this_node.name == 'travelnet:elevator' ) then is_elevator = true; - end + end if( not( meta )) then return; @@ -258,7 +275,7 @@ travelnet.update_formspec = function( pos, puncher_name, fields ) local station_name = meta:get_string( "station_name" ); local station_network = meta:get_string( "station_network" ); - if( not( owner_name ) + if( not( owner_name ) or not( station_name ) or station_network == '' or not( station_network )) then @@ -288,7 +305,7 @@ travelnet.update_formspec = function( pos, puncher_name, fields ) if( not( travelnet.targets[ owner_name ] )) then travelnet.targets[ owner_name ] = {}; end - + -- first station on this network? if( not( travelnet.targets[ owner_name ][ station_network ] )) then travelnet.targets[ owner_name ][ station_network ] = {}; @@ -312,8 +329,10 @@ travelnet.update_formspec = function( pos, puncher_name, fields ) -- add name of station + network + owner + update-button local zusatzstr = ""; local trheight = "10"; - if( this_node and this_node.name=="locked_travelnet:travelnet" ) then - zusatzstr = "field[0.3,11;6,0.7;locks_sent_lock_command;"..S("Locked travelnet. Type /help for help:")..";]"; + if( this_node and this_node.name=="locked_travelnet:travelnet" and locks) then + zusatzstr = "field[0.3,11;6,0.7;locks_sent_lock_command;"..S("Locked travelnet. Type /help for help:")..";]".. + locks.get_authorize_button(10,"10.5").. + locks.get_config_button(11,"10.5") trheight = "11.5"; end local formspec = "size[12,"..trheight.."]".. @@ -331,15 +350,15 @@ travelnet.update_formspec = function( pos, puncher_name, fields ) -- collect all station names in a table local stations = {}; - + for k,v in pairs( travelnet.targets[ owner_name ][ station_network ] ) do table.insert( stations, k ); end -- minetest.chat_send_player(puncher_name, "stations: "..minetest.serialize( stations )); - + local ground_level = 1; if( is_elevator ) then - table.sort( stations, function(a,b) return travelnet.targets[ owner_name ][ station_network ][ a ].pos.y > + table.sort( stations, function(a,b) return travelnet.targets[ owner_name ][ station_network ][ a ].pos.y > travelnet.targets[ owner_name ][ station_network ][ b ].pos.y end); -- find ground level local vgl_timestamp = 999999999999; @@ -348,7 +367,7 @@ travelnet.update_formspec = function( pos, puncher_name, fields ) travelnet.targets[ owner_name ][ station_network ][ k ].timestamp = os.time(); end if( travelnet.targets[ owner_name ][ station_network ][ k ].timestamp < vgl_timestamp ) then - vgl_timestamp = travelnet.targets[ owner_name ][ station_network ][ k ].timestamp; + vgl_timestamp = travelnet.targets[ owner_name ][ station_network ][ k ].timestamp; ground_level = index; end end @@ -359,10 +378,10 @@ travelnet.update_formspec = function( pos, puncher_name, fields ) travelnet.targets[ owner_name ][ station_network ][ k ].nr = tostring( ground_level - index ); end end - - else + + else -- sort the table according to the timestamp (=time the station was configured) - table.sort( stations, function(a,b) return travelnet.targets[ owner_name ][ station_network ][ a ].timestamp < + table.sort( stations, function(a,b) return travelnet.targets[ owner_name ][ station_network ][ a ].timestamp < travelnet.targets[ owner_name ][ station_network ][ b ].timestamp end); end @@ -400,9 +419,9 @@ travelnet.update_formspec = function( pos, puncher_name, fields ) else -- swap the actual data by which the stations are sorted local old_timestamp = travelnet.targets[ owner_name ][ station_network ][ stations[swap_with_pos]].timestamp; - travelnet.targets[ owner_name ][ station_network ][ stations[swap_with_pos]].timestamp = + travelnet.targets[ owner_name ][ station_network ][ stations[swap_with_pos]].timestamp = travelnet.targets[ owner_name ][ station_network ][ stations[current_pos ]].timestamp; - travelnet.targets[ owner_name ][ station_network ][ stations[current_pos ]].timestamp = + travelnet.targets[ owner_name ][ station_network ][ stations[current_pos ]].timestamp = old_timestamp; -- for elevators, only the "G"(round) marking is moved; no point in swapping stations @@ -423,7 +442,7 @@ travelnet.update_formspec = function( pos, puncher_name, fields ) x = 4; end - for index,k in ipairs( stations ) do + for index,k in ipairs( stations ) do -- check if there is an elevator door in front that needs to be opened local open_door_cmd = false; @@ -431,7 +450,7 @@ travelnet.update_formspec = function( pos, puncher_name, fields ) open_door_cmd = true; end - if( k ~= station_name or open_door_cmd) then + if( k ~= station_name or open_door_cmd) then i = i+1; -- new column @@ -489,7 +508,7 @@ travelnet.add_target = function( station_name, network_name, pos, player_name, m if( this_node.name == 'travelnet:elevator' ) then -- owner_name = '*'; -- the owner name is not relevant here is_elevator = true; - network_name = tostring( pos.x )..','..tostring( pos.z ); + network_name = tostring( pos.x )..','..tostring( pos.z ); if( not( station_name ) or station_name == '' ) then station_name = S('at %s m'):format(tostring( pos.y )); end @@ -531,7 +550,7 @@ travelnet.add_target = function( station_name, network_name, pos, player_name, m if( not( travelnet.targets[ owner_name ] )) then travelnet.targets[ owner_name ] = {}; end - + -- first station on this network? if( not( travelnet.targets[ owner_name ][ network_name ] )) then travelnet.targets[ owner_name ][ network_name ] = {}; @@ -558,7 +577,7 @@ travelnet.add_target = function( station_name, network_name, pos, player_name, m "Please choose a diffrent/new network name."):format(travelnet.MAX_STATIONS_PER_NETWORK)); return; end - + -- add this station travelnet.targets[ owner_name ][ network_name ][ station_name ] = {pos=pos, timestamp=os.time() }; @@ -574,7 +593,7 @@ travelnet.add_target = function( station_name, network_name, pos, player_name, m meta:set_string( "owner", owner_name ); meta:set_int( "timestamp", travelnet.targets[ owner_name ][ network_name ][ station_name ].timestamp); - meta:set_string("formspec", + meta:set_string("formspec", "size[12,10]".. "field[0.3,0.6;6,0.7;station_name;"..S("Station:")..";".. minetest.formspec_escape(meta:get_string("station_name")).."]".. "field[0.3,3.6;6,0.7;station_network;"..S("Network:")..";"..minetest.formspec_escape(meta:get_string("station_network")).."]" ); @@ -592,7 +611,11 @@ end -- allow doors to open travelnet.open_close_door = function( pos, player, mode ) - local this_node = minetest.get_node( pos ); + local this_node = minetest.get_node_or_nil( pos ); + -- give up if the area is *still* not loaded + if( this_node == nil ) then + return + end local pos2 = {x=pos.x,y=pos.y,z=pos.z}; if( this_node.param2 == 0 ) then pos2 = {x=pos.x,y=pos.y,z=(pos.z-1)}; @@ -609,20 +632,22 @@ travelnet.open_close_door = function( pos, player, mode ) -- do not close the elevator door if it is already closed if( mode==1 and ( string.sub( door_node.name, -7 ) == '_closed' -- handle doors that change their facedir - or ( door_node.param2 == this_node.param2 + or ( door_node.param2 == ((this_node.param2 + 2)%4) and door_node.name ~= 'travelnet:elevator_door_glass_open' + and door_node.name ~= 'travelnet:elevator_door_tin_open' and door_node.name ~= 'travelnet:elevator_door_steel_open'))) then return; end -- do not open the doors if they are already open (works only on elevator-doors; not on doors in general) if( mode==2 and ( string.sub( door_node.name, -5 ) == '_open' -- handle doors that change their facedir - or ( door_node.param2 ~= this_node.param2 + or ( door_node.param2 ~= ((this_node.param2 + 2)%4) and door_node.name ~= 'travelnet:elevator_door_glass_closed' + and door_node.name ~= 'travelnet:elevator_door_tin_closed' and door_node.name ~= 'travelnet:elevator_door_steel_closed'))) then return; end - + if( mode==2 ) then minetest.after( 1, minetest.registered_nodes[ door_node.name ].on_rightclick, pos2, door_node, player ); else @@ -645,6 +670,11 @@ travelnet.on_receive_fields = function(pos, formname, fields, player) return; end + -- show special locks buttons if needed + if( locks and (fields.locks_config or fields.locks_authorize)) then + return locks:lock_handle_input( pos, formname, fields, player ) + end + -- show help text if( fields and fields.station_help_setup and fields.station_help_setup ~= "") then -- simulate right-click @@ -667,6 +697,8 @@ travelnet.on_receive_fields = function(pos, formname, fields, player) description = "travelnet box" elseif( node and node.name and node.name == "travelnet:elevator") then description = "elevator" + elseif( node and node.name and node.name == "locked_travelnet:travelnet") then + description = "locked travelnet" else minetest.chat_send_player(name, "Error: Unkown node."); return @@ -704,7 +736,7 @@ travelnet.on_receive_fields = function(pos, formname, fields, player) -- if the box has not been configured yet if( meta:get_string("station_network")=="" ) then - travelnet.add_target( fields.station_name, fields.station_network, pos, name, meta, fields.owner_name ); + travelnet.add_target( fields.station_name, fields.station_network, pos, name, meta, fields.owner ); return; end @@ -730,8 +762,8 @@ travelnet.on_receive_fields = function(pos, formname, fields, player) local station_name = meta:get_string( "station_name" ); local station_network = meta:get_string( "station_network" ); - if( not( owner_name ) - or not( station_name ) + if( not( owner_name ) + or not( station_name ) or not( station_network ) or not( travelnet.targets[ owner_name ] ) or not( travelnet.targets[ owner_name ][ station_network ] )) then @@ -766,7 +798,7 @@ travelnet.on_receive_fields = function(pos, formname, fields, player) end local this_node = minetest.get_node( pos ); - if( this_node ~= nil and this_node.name == 'travelnet:elevator' ) then + if( this_node ~= nil and this_node.name == 'travelnet:elevator' ) then for k,v in pairs( travelnet.targets[ owner_name ][ station_network ] ) do if( travelnet.targets[ owner_name ][ station_network ][ k ].nr --..' ('..tostring( travelnet.targets[ owner_name ][ station_network ][ k ].pos.y )..'m)' == fields.target) then @@ -794,9 +826,13 @@ travelnet.on_receive_fields = function(pos, formname, fields, player) if( travelnet.travelnet_sound_enabled ) then - minetest.sound_play("128590_7037-lq.mp3", {pos = pos, gain = 1.0, max_hear_distance = 10,}) + if ( this_node.name == 'travelnet:elevator' ) then + minetest.sound_play("travelnet_bell", {pos = pos, gain = 0.75, max_hear_distance = 10,}); + else + minetest.sound_play("travelnet_travel", {pos = pos, gain = 0.75, max_hear_distance = 10,}); + end end - if( travelnet.travelnet_effect_enabled ) then + if( travelnet.travelnet_effect_enabled ) then minetest.add_entity( {x=pos.x,y=pos.y+0.5,z=pos.z}, "travelnet:effect"); -- it self-destructs after 20 turns end @@ -807,16 +843,13 @@ travelnet.on_receive_fields = function(pos, formname, fields, player) local target_pos = travelnet.targets[ owner_name ][ station_network ][ fields.target ].pos; player:moveto( target_pos, false); - if( travelnet.travelnet_sound_enabled ) then - minetest.sound_play("travelnet_travel.wav", {pos = target_pos, gain = 1.0, max_hear_distance = 10,}) - end if( travelnet.travelnet_effect_enabled ) then minetest.add_entity( {x=target_pos.x,y=target_pos.y+0.5,z=target_pos.z}, "travelnet:effect"); -- it self-destructs after 20 turns end -- check if the box has at the other end has been removed. - local node2 = minetest.get_node( target_pos ); + local node2 = minetest.get_node_or_nil( target_pos ); if( node2 ~= nil and node2.name ~= 'ignore' and node2.name ~= 'travelnet:travelnet' and node2.name ~= 'travelnet:elevator' and node2.name ~= "locked_travelnet:travelnet" and node2.name ~= "travelnet:travelnet_private") then -- provide information necessary to identify the removed box @@ -828,9 +861,32 @@ travelnet.on_receive_fields = function(pos, formname, fields, player) -- send the player back as there's no receiving travelnet player:moveto( pos, false ); - -- do this only on servers where the function exists - elseif( player.set_look_horizontal ) then + else + travelnet.rotate_player( target_pos, player, 0 ) + end +end +travelnet.rotate_player = function( target_pos, player, tries ) + -- try later when the box is loaded + local node2 = minetest.get_node_or_nil( target_pos ); + if( node2 == nil ) then + if( tries < 30 ) then + minetest.after( 0, travelnet.rotate_player, target_pos, player, tries+1 ) + end + return + end + + -- play sound at the target position as well + if( travelnet.travelnet_sound_enabled ) then + if ( node2.name == 'travelnet:elevator' ) then + minetest.sound_play("travelnet_bell", {pos = target_pos, gain = 0.75, max_hear_distance = 10,}); + else + minetest.sound_play("travelnet_travel", {pos = target_pos, gain = 0.75, max_hear_distance = 10,}); + end + end + + -- do this only on servers where the function exists + if( player.set_look_horizontal ) then -- rotate the player so that he/she can walk straight out of the box local yaw = 0; local param2 = node2.param2; @@ -843,7 +899,7 @@ travelnet.on_receive_fields = function(pos, formname, fields, player) elseif( param2==3 ) then yaw = 270; end - + player:set_look_horizontal( math.rad( yaw )); player:set_look_vertical( math.rad( 0 )); end @@ -865,19 +921,19 @@ travelnet.remove_box = function( pos, oldnode, oldmetadata, digger ) local station_network = oldmetadata.fields[ "station_network" ]; -- station is not known? then just remove it - if( not( owner_name ) - or not( station_name ) - or not( station_network ) + if( not( owner_name ) + or not( station_name ) + or not( station_network ) or not( travelnet.targets[ owner_name ] ) or not( travelnet.targets[ owner_name ][ station_network ] )) then - + minetest.chat_send_player( digger:get_player_name(), S("Error")..": ".. S("Could not find the station that is to be removed.")); return; end travelnet.targets[ owner_name ][ station_network ][ station_name ] = nil; - + -- inform the owner minetest.chat_send_player( owner_name, S("Station '%s'"):format(station_name ).." ".. S("has been REMOVED from the network '%s'."):format(station_network)); @@ -971,17 +1027,17 @@ end if( travelnet.travelnet_enabled ) then - dofile(minetest.get_modpath("travelnet").."/travelnet.lua"); -- the travelnet node definition + dofile(travelnet.path.."/travelnet.lua"); -- the travelnet node definition end if( travelnet.elevator_enabled ) then - dofile(minetest.get_modpath("travelnet").."/elevator.lua"); -- allows up/down transfers only + dofile(travelnet.path.."/elevator.lua"); -- allows up/down transfers only end if( travelnet.doors_enabled ) then - dofile(minetest.get_modpath("travelnet").."/doors.lua"); -- doors that open and close automaticly when the travelnet or elevator is used + dofile(travelnet.path.."/doors.lua"); -- doors that open and close automaticly when the travelnet or elevator is used end if( travelnet.abm_enabled ) then - dofile(minetest.get_modpath("travelnet").."/restore_network_via_abm.lua"); -- restore travelnet data when players pass by broken networks + dofile(travelnet.path.."/restore_network_via_abm.lua"); -- restore travelnet data when players pass by broken networks end -- upon server start, read the savefile diff --git a/travelnet/intllib.lua b/travelnet/intllib.lua new file mode 100644 index 00000000..6669d720 --- /dev/null +++ b/travelnet/intllib.lua @@ -0,0 +1,45 @@ + +-- Fallback functions for when `intllib` is not installed. +-- Code released under Unlicense . + +-- 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 diff --git a/travelnet/locale/de.po b/travelnet/locale/de.po new file mode 100644 index 00000000..f39db714 --- /dev/null +++ b/travelnet/locale/de.po @@ -0,0 +1,326 @@ +# German translation for the travelnet mod. +# Copyright (C) 2018 Sokomine +# This file is distributed under the same license as the travelnet package. +# Sokomine, 2017 +# CodeXP , 2018. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: 1.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-03-24 01:31+0100\n" +"PO-Revision-Date: \n" +"Last-Translator: CodeXP \n" +"Language-Team: \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: init.lua +msgid "allows to attach travelnet boxes to travelnets of other players" +msgstr "erlaubt es, Stationen zu den Reisenetzwerken anderer Spieler hinzuzufügen" + +#: init.lua +msgid "allows to dig travelnet boxes which belog to nets of other players" +msgstr "erlaubt es, die Reisenetz-Stationen anderer Spieler zu entfernen" + +#: init.lua +msgid "[Mod travelnet] Error: Savefile '%s' could not be written." +msgstr "[Mod travelnet] Fehler: Sicherungsdatei '%s' konnte nicht geschrieben werden." + +#: init.lua +msgid "[Mod travelnet] Error: Savefile '%s' not found." +msgstr "[Mod travelnet] Fehler: Sicherungsdatei '%s' nicht gefunden." + +#: init.lua +msgid "Back" +msgstr "Zurück" + +#: init.lua +msgid "Exit" +msgstr "Ende" + +#: init.lua +msgid "Travelnet-box (unconfigured)" +msgstr "Reisenetz-Box (nicht konfiguriert)" + +#: init.lua +msgid "Configure this travelnet station" +msgstr "Konfiguration dieser Reisenetz-Box" + +#: init.lua +msgid "Name of this station" +msgstr "Name dieser Reisenetz-Box" + +#: init.lua +msgid "How do you call this place here? Example: \"my first house\", \"mine\", \"shop\"..." +msgstr "Wie willst du diesen Ort nennen? Beispiel: \"mein erstes Haus\", \"Mine\", \"Laden\"..." + +#: init.lua +msgid "Assign to Network:" +msgstr "Station dem folgendem Netzwerk zuweisen:" + +#: init.lua +msgid "You can have more than one network. If unsure, use \"%s\"" +msgstr "Du kannst mehrere Netzwerke anlegen. Falls du nicht weißt, was du tun sollst, wähle \"%s\"" + +#: init.lua +msgid "Owned by:" +msgstr "Besitzer:" + +#: init.lua +msgid "Unless you know what you are doing, leave this empty." +msgstr "Wenn du nicht weißt, wozu dieses Feld dient, laß es leer." + +#: init.lua +msgid "Help" +msgstr "Hilfe" + +#: init.lua +msgid "Save" +msgstr "Speichern" + +#: init.lua +msgid "Update failed! Resetting this box on the travelnet." +msgstr "Aktualisierung gescheitert. Konfiguration der Reisenetz-Box wird zurückgesetzt." + +#: init.lua +msgid "Station '%s'" +msgstr "Station '%s'" + +#: init.lua +msgid "has been reattached to the network '%s'." +msgstr "wurde dem Netzwerk '%s' wieder hinzugefügt." + +#: init.lua +msgid "Locked travelnet. Type /help for help:" +msgstr "Abgeschlossene Reisenetz-Box. Tippe /help für Hilfe:" + +#: init.lua +msgid "Punch box to update target list." +msgstr "Reisenetz-Box mit Linksklick aktualisieren." + +#: init.lua +msgid "Travelnet-Box" +msgstr "Reisenetz-Box" + +#: init.lua +msgid "Name of this station:" +msgstr "Name dieser Station:" + +#: init.lua +msgid "Assigned to Network:" +msgstr "Zugehöriges Netzwerk:" + +#: init.lua +msgid "Click on target to travel there:" +msgstr "Klicke auf das Ziel um dorthin zu reisen:" + +#: init.lua +msgid "G" +msgstr "E" + +#: init.lua +msgid "This station is already the first one on the list." +msgstr "Diese Reisenetz-Box ist bereits die erste auf der Liste." + +#: init.lua +msgid "This station is already the last one on the list." +msgstr "Diese Reisenetz-Box ist bereits die letzte auf der Liste." + +#: init.lua +msgid "Position in list:" +msgstr "Listenposition:" + +#: init.lua +msgid "move up" +msgstr "hoch" + +#: init.lua +msgid "move down" +msgstr "runter" + +#: init.lua +msgid "on travelnet '%s'" +msgstr "im Reisenetzwerk '%s'" + +#: init.lua +msgid "owned by %s" +msgstr "Eigentum von %s" + +#: init.lua +msgid "ready for usage. Right-click to travel, punch to update." +msgstr "bereit für die Nutzung. Rechtsklick um zu Reisen, Linksklick für Update." + +#: init.lua +msgid "at %s m" +msgstr "in %s m Höhe" + +#: init.lua +msgid "Error" +msgstr "Fehler" + +#: init.lua +msgid "Please provide a name for this station." +msgstr "Bitte gib einen Namen für diese Reisenetz-Box an." + +#: init.lua +msgid "Please provide the name of the network this station ought to be connected to." +msgstr "Bitte gib einen Namen für das Netzwerk an zu dem diese Reisenetz-Box gehören soll." + +#: init.lua +msgid "There is no player with interact privilege named '%s'. Aborting." +msgstr "Es gibt keinen Spieler mit interact-Recht names '%s'. Abbruch." + +#: init.lua +msgid "You do not have the travelnet_attach priv which is required to attach your box to the network of someone else. Aborting." +msgstr "Dir fehlt das travelnet_attach-Recht, welches für das Hinzufügen von Reisenetz-Boxen zu Netzwerken nötig ist, die anderen Spielern gehören. Abbruch." + +#: init.lua +msgid "A station named '%s' already exists on this network. Please choose a diffrent name!" +msgstr "Eine Reisenetz-Box namens '%s' existiert bereits in diesem Netzwerk. Abbruch." + +#: init.lua +msgid "Network '%s'" +msgstr "Netzwerk '%s'" + +#: init.lua +msgid "already contains the maximum number (" +msgstr "%s) of allowed stations per network. Please choose a diffrent/new network name. = enthält bereits die maixmale Anzahl (=%s) erlaubert Stationen pro Netzwerk. Bitte wähle ein anderes bzw. neues Netzwerk." + +#: init.lua +msgid "has been added to the network '%s'" +msgstr "wurde an das Netzwerk '%s' angeschlossen." + +#: init.lua +msgid ", which now consists of %s station(s)." +msgstr ", das nun aus %s Station(en) besteht." + +#: init.lua +msgid "Station:" +msgstr "Station:" + +#: init.lua +msgid "Network:" +msgstr "Netzwerk:" + +#: init.lua +msgid "No help available yet." +msgstr "Noch keine Hilfe eingebaut." + +#: init.lua +msgid "Please click on the target you want to travel to." +msgstr "Bitte klicke auf das Ziel zu dem du reisen willst." + +#: init.lua +msgid "There is something wrong with the configuration of this station." +msgstr "Die Konfiguration dieser Reisenetz-Box ist fehlerhaft." + +#: init.lua +msgid "This travelnet is lacking data and/or improperly configured." +msgstr "Diese Reisenetz-Box ist fehlerhaft oder unvollständig konfiguriert." + +#: init.lua +msgid "does not exist (anymore?) on this network." +msgstr "gibt es nicht (mehr?) in diesem Netzwerk." + +#: init.lua +msgid "Initiating transfer to station '%s'." +msgstr "leite Reise zur Station '%s' ein." + +#: init.lua +msgid "Could not find information about the station that is to be removed." +msgstr "Konnte keine Informationen über die zu entfernende Station finden." + +#: init.lua +msgid "Could not find the station that is to be removed." +msgstr "Konnte die zu entfernende Station nicht finden." + +#: init.lua +msgid "has been REMOVED from the network '%s'." +msgstr "wurde vom Netzwerk '%s' ENTFERNT." + +#: init.lua +msgid "This %s has not been configured yet. Please set it up first to claim it. Afterwards you can remove it because you are then the owner." +msgstr "Diese Reisenetz-Box wurde noch nicht konfiguriert. Bitte konfiguriere sie um sie in Besitz zu nehmen. Anschließend kannst du sie auch wieder entfernen da du dann der Besitzer bist." + +#: init.lua +msgid "This %s belongs to %s. You can't remove it." +msgstr "Diese Reisenetz-Box gehört %s. Du kannst sie nicht entfernen." + +#: travelnet.lua +msgid "Not enough vertical space to place the travelnet box!" +msgstr "Nicht genug Platz (vertikal) um die Reisenetz-Box zu setzen!" + +#: elevator.lua +msgid "Congratulations! This is your first elevator. You can build an elevator network by placing further elevators somewhere above or below this one. Just make sure that the x and z coordinate are the same." +msgstr "" + +#: elevator.lua +msgid "This elevator will automaticly connect to the other elevators you have placed at diffrent heights. Just enter a station name and click on \"store\" to set it up. Or just punch it to set the height as station name." +msgstr "Dieser Aufzug wird sich automatisch mit anderen Aufzügen verbinden die du auf unterschiedlichen Höhen positioniert hast. Gib einfach einen Namen für diese Station hier ein und klicke auf \"Speichern\" um die Station einzurichten. Oder mache einen Linksklick um die Höhe als Stationsname zu setzen." + +#: elevator.lua +msgid "Your nearest elevator network is located" +msgstr "Dein nächstgelegenes Aufzugs-Netzwerk befindet sich" + +#: elevator.lua +msgid "m behind this elevator and" +msgstr "m hinter diesem Aufzug und" + +#: elevator.lua +msgid "m in front of this elevator and" +msgstr "m vor diesem Aufzug und" + +#: elevator.lua +msgid "m to the left" +msgstr "m links" + +#: elevator.lua +msgid "m to the right" +msgstr "m rechts" + +#: elevator.lua +msgid ", located at x" +msgstr ", an Position x" + +#: elevator.lua +msgid "This elevator here will start a new shaft/network." +msgstr "Dieser Aufzug hier wird einen neuen Schaft bzw. ein neues Netzwerk erstellen." + +#: elevator.lua +msgid "This is your first elevator. It differs from travelnet networks by only allowing movement in vertical direction (up or down). All further elevators which you will place at the same x,z coordinates at differnt heights will be able to connect to this elevator." +msgstr "Dies ist dein erster Aufzug. Der Aufzug unterscheidet sich von Reisenetz-Boxen insofern als daß er nur Reisen in vertikaler Richtung (hoch und runter) erlaubt. Alle folgenden Aufzüge, die du an die selben x,z Koordinaten auf verschiedenen Höhenpositionen setzen wirst, werden sich automatisch mit diesem Aufzug verbinden." + +#: elevator.lua +msgid "Elevator" +msgstr "Aufzug" + +#: elevator.lua +msgid "Elevator (unconfigured)" +msgstr "Aufzug (nicht konfiguriert)" + +#: doors.lua +msgid "elevator door (open)" +msgstr "Aufzugstür (offen)" + +#: doors.lua +msgid "elevator door (closed)" +msgstr "Aufzugstür (geschlossen)" + +#: init.lua +#, lua-format +msgid "Remove station" +msgstr "Station entfernen" + +#: init.lua +#, lua-format +msgid "You do not have enough room in your inventory." +msgstr "Du hast nicht genug Platz in deinem Inventar." + +#: init.lua +#, lua-format +msgid "[Mod travelnet] Error: Savefile '%s' is damaged. Saved the backup as '%s'." +msgstr "[Mod travelnet] Fehler: Sicherungsdatei '%s' ist beschädigt. Backup wurde unter '%s' gespeichert." diff --git a/travelnet/locale/de.txt b/travelnet/locale/de.txt deleted file mode 100644 index e5f76422..00000000 --- a/travelnet/locale/de.txt +++ /dev/null @@ -1,94 +0,0 @@ -# Template - -### config.lua ### - -### init.lua ### - -allows to attach travelnet boxes to travelnets of other players = erlaubt es, Stationen zu den Reisenetzwerken anderer Spieler hinzuzufügen -allows to dig travelnet boxes which belog to nets of other players = erlaubt es, die Reisenetz-Stationen anderer Spieler zu entfernen - -[Mod travelnet] Error: Savefile '%s' could not be written. = [Mod travelnet] Fehler: Sicherungsdatei '%s' konnte nicht geschrieben werden. -[Mod travelnet] Error: Savefile '%s' not found. = [Mod travelnet] Fehler: Sicherungsdatei '%s' nicht gefunden. - -Back = Zurück -Exit = Ende - -Travelnet-box (unconfigured) = Reisenetz-Box (nicht konfiguriert) - -Configure this travelnet station = Konfiguration dieser Reisenetz-Box -Name of this station = Name dieser Reisenetz-Box -How do you call this place here? Example: \"my first house\", \"mine\", \"shop\"... = Wie willst du diesen Ort nennen? Beispiel: \"mein erstes Haus\", \"Mine\", \"Laden\"... -Assign to Network: = Station dem folgendem Netzwerk zuweisen: -You can have more than one network. If unsure, use \"%s\" = Du kannst mehrere Netzwerke anlegen. Falls du nicht weißt, was du tun sollst, wähle \"%s\" -Owned by: = Besitzer: -Unless you know what you are doing, leave this empty. = Wenn du nicht weißt, wozu dieses Feld dient, laß es leer. -Help = Hilfe -Save = Speichern -Remove station = Station entfernen -You do not have enough room in your inventory. = Du hast nicht genug Platz in deinem Inventar. -Update failed! Resetting this box on the travelnet. = Aktualisierung gescheitert. Konfiguration der Reisenetz-Box wird zurückgesetzt. -Station '%s' = Station '%s' -has been reattached to the network '%s'. = wurde dem Netzwerk '%s' wieder hinzugefügt. -Locked travelnet. Type /help for help: = Abgeschlossene Reisenetz-Box. Tippe /help für Hilfe: -Punch box to update target list. = Reisenetz-Box mit Linksklick aktualisieren. -Travelnet-Box = Reisenetz-Box -Name of this station: = Name dieser Station: -Assigned to Network: = Zugehöriges Netzwerk: -Click on target to travel there: = Klicke auf das Ziel um dorthin zu reisen: -G = E -This station is already the first one on the list. = Diese Reisenetz-Box ist bereits die erste auf der Liste. -This station is already the last one on the list. = Diese Reisenetz-Box ist bereits die letzte auf der Liste. -Position in list: = Listenposition: -move up = hoch -move down = runter -on travelnet '%s' = im Reisenetzwerk '%s' -owned by %s = Eigentum von %s -ready for usage. Right-click to travel, punch to update. = bereit für die Nutzung. Rechtsklick um zu Reisen, Linksklick für Update. -at %s m = in %s m Höhe -Error = Fehler -Please provide a name for this station. = Bitte gib einen Namen für diese Reisenetz-Box an. -Please provide the name of the network this station ought to be connected to. = Bitte gib einen Namen für das Netzwerk an zu dem diese Reisenetz-Box gehören soll. -There is no player with interact privilege named '%s'. Aborting. = Es gibt keinen Spieler mit interact-Recht names '%s'. Abbruch. -You do not have the travelnet_attach priv which is required to attach your box to the network of someone else. Aborting. = Dir fehlt das travelnet_attach-Recht, welches für das Hinzufügen von Reisenetz-Boxen zu Netzwerken nötig ist, die anderen Spielern gehören. Abbruch. -A station named '%s' already exists on this network. Please choose a diffrent name! = Eine Reisenetz-Box namens '%s' existiert bereits in diesem Netzwerk. Abbruch. -Network '%s' = Netzwerk '%s' -already contains the maximum number (=%s) of allowed stations per network. Please choose a diffrent/new network name. = enthält bereits die maixmale Anzahl (=%s) erlaubert Stationen pro Netzwerk. Bitte wähle ein anderes bzw. neues Netzwerk. -has been added to the network '%s' = wurde an das Netzwerk '%s' angeschlossen. -, which now consists of %s station(s). = , das nun aus %s Station(en) besteht. -Station: = Station: -Network: = Netzwerk: -No help available yet. = Noch keine Hilfe eingebaut. -Please click on the target you want to travel to. = Bitte klicke auf das Ziel zu dem du reisen willst. -There is something wrong with the configuration of this station. = Die Konfiguration dieser Reisenetz-Box ist fehlerhaft. -This travelnet is lacking data and/or improperly configured. = Diese Reisenetz-Box ist fehlerhaft oder unvollständig konfiguriert. -does not exist (anymore?) on this network. = gibt es nicht (mehr?) in diesem Netzwerk. -Initiating transfer to station '%s'. = leite Reise zur Station '%s' ein. -Could not find information about the station that is to be removed. = Konnte keine Informationen über die zu entfernende Station finden. -Could not find the station that is to be removed. = Konnte die zu entfernende Station nicht finden. -has been REMOVED from the network '%s'. = wurde vom Netzwerk '%s' ENTFERNT. -This %s has not been configured yet. Please set it up first to claim it. Afterwards you can remove it because you are then the owner. = Diese Reisenetz-Box wurde noch nicht konfiguriert. Bitte konfiguriere sie um sie in Besitz zu nehmen. Anschließend kannst du sie auch wieder entfernen da du dann der Besitzer bist. -This %s belongs to %s. You can't remove it. = Diese Reisenetz-Box gehört %s. Du kannst sie nicht entfernen. - - -### travelnet.lua ### -Not enough vertical space to place the travelnet box! = Nicht genug Platz (vertikal) um die Reisenetz-Box zu setzen! - - -### elevator.lua ### -Congratulations! This is your first elevator. You can build an elevator network by placing further elevators somewhere above or below this one. Just make sure that the x and z coordinate are the same. = -This elevator will automaticly connect to the other elevators you have placed at diffrent heights. Just enter a station name and click on \"store\" to set it up. Or just punch it to set the height as station name. = Dieser Aufzug wird sich automatisch mit anderen Aufzügen verbinden die du auf unterschiedlichen Höhen positioniert hast. Gib einfach einen Namen für diese Station hier ein und klicke auf \"Speichern\" um die Station einzurichten. Oder mache einen Linksklick um die Höhe als Stationsname zu setzen. -Your nearest elevator network is located = Dein nächstgelegenes Aufzugs-Netzwerk befindet sich -m behind this elevator and = m hinter diesem Aufzug und -m in front of this elevator and = m vor diesem Aufzug und -m to the left = m links -m to the right = m rechts -, located at x = , an Position x -This elevator here will start a new shaft/network. = Dieser Aufzug hier wird einen neuen Schaft bzw. ein neues Netzwerk erstellen. -This is your first elevator. It differs from travelnet networks by only allowing movement in vertical direction (up or down). All further elevators which you will place at the same x,z coordinates at differnt heights will be able to connect to this elevator. = Dies ist dein erster Aufzug. Der Aufzug unterscheidet sich von Reisenetz-Boxen insofern als daß er nur Reisen in vertikaler Richtung (hoch und runter) erlaubt. Alle folgenden Aufzüge, die du an die selben x,z Koordinaten auf verschiedenen Höhenpositionen setzen wirst, werden sich automatisch mit diesem Aufzug verbinden. -Elevator = Aufzug -Elevator (unconfigured) = Aufzug (nicht konfiguriert) - - -### doors.lua ### -elevator door (open) = Aufzugstür (offen) -elevator door (closed) = Aufzugstür (geschlossen) diff --git a/travelnet/locale/ru.po b/travelnet/locale/ru.po new file mode 100644 index 00000000..004fe291 --- /dev/null +++ b/travelnet/locale/ru.po @@ -0,0 +1,377 @@ +# Russian translation for the travelnet mod. +# Copyright (C) 2018 Sokomine +# This file is distributed under the same license as the travelnet package. +# CodeXP , 2018. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: travelnet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-04-05 14:30+0200\n" +"PO-Revision-Date: \n" +"Last-Translator: CodeXP \n" +"Language-Team: \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: doors.lua +msgid "elevator door (open)" +msgstr "дверь лифта (открыта)" + +#: doors.lua +msgid "elevator door (closed)" +msgstr "дверь лифта (закрыта)" + +#: elevator.lua +msgid "" +"Congratulations! This is your first elevator.You can build an elevator " +"network by placing further elevators somewhere above or below this one. " +"Just make sure that the x and z coordinate are the same." +msgstr "" +"Поздравляем! Это ваш первый лифт. Вы можете построить сеть лифтов, " +"разместив дополнительные лифты выше или ниже этого лифта. " +"Только убедитесь, что координаты x и z совпадают." + +#: elevator.lua +msgid "" +"This elevator will automaticly connect to the other elevators you have " +"placed at diffrent heights. Just enter a station name and click on \"store\" " +"to set it up. Or just punch it to set the height as station name." +msgstr "" +"Этот лифт будет автоматически подключен к другим лифтам, которые размещены " +"на разных высотах. После установки можете ввести название лифта и нажать \"сохранить\". " +"Или просто ударьте его, чтобы установить высоту в качестве названия лифта." + +#: elevator.lua +msgid "Your nearest elevator network is located" +msgstr "Ваша ближайшая сеть лифтов находится" + +#: elevator.lua +msgid "m behind this elevator and" +msgstr "м за этим лифтом" + +#: elevator.lua +msgid "m in front of this elevator and" +msgstr "м перед этим лифтом" + +#: elevator.lua +msgid " ERROR" +msgstr " ОЩИБКА" + +#: elevator.lua +msgid "m to the left" +msgstr "м с лева" + +#: elevator.lua +msgid "m to the right" +msgstr "м с права" + +#: elevator.lua +msgid ", located at x" +msgstr ", находится на x" + +#: elevator.lua +msgid "This elevator here will start a new shaft/network." +msgstr "Этот лифт составит новую сеть." + +#: elevator.lua +msgid "" +"This is your first elevator. It differs from travelnet networks by only " +"allowing movement in vertical direction (up or down). All further elevators " +"which you will place at the same x,z coordinates at differnt heights will be " +"able to connect to this elevator." +msgstr "" +"Это ваш первый лифт. Он отличается от сети телепортов только тем что " +"движение ограниченно в вертикальном направлении (вверх или вниз). " +"Все дополнительные лифты, которые вы будете размещать в тех же координатах " +"(x, z) на разных высотах, будут подключены к этому лифту." + +#: elevator.lua +msgid "Elevator" +msgstr "Лифт" + +#: elevator.lua +msgid "Elevator (unconfigured)" +msgstr "Лифт (без настройки)" + +#: elevator.lua init.lua +msgid "Name of this station:" +msgstr "Имя этой станции:" + +#: elevator.lua +msgid "Store" +msgstr "Сохранить" + +#: elevator.lua travelnet.lua +msgid "Not enough vertical space to place the travelnet box!" +msgstr "Недостаточно вертикального места, чтобы разместить телепорт!" + +#: init.lua +msgid "allows to attach travelnet boxes to travelnets of other players" +msgstr "позволяет присоеденять телепорты к сетям других игроков" + +#: init.lua +msgid "allows to dig travelnet boxes which belog to nets of other players" +msgstr "позволяет убирать телепорты других игроков" + +#: init.lua +#, lua-format +msgid "[Mod travelnet] Error: Savefile '%s' could not be written." +msgstr "[MOD travelnet] Ошибка: Файл «%s» не может быть записан." + +#: init.lua +#, lua-format +msgid "[Mod travelnet] Error: Savefile '%s' not found." +msgstr "[MOD travelnet] Ошибка: Файл «%s» не найден." + +#: init.lua +msgid "Back" +msgstr "Назад" + +#: init.lua +msgid "Exit" +msgstr "Выход" + +#: init.lua +msgid "Travelnet-box (unconfigured)" +msgstr "Телепорт (без настройки)" + +#: init.lua +msgid "Configure this travelnet station" +msgstr "НАСТРОЙКИ СТАНЦИИ" + +#: init.lua +msgid "Name of this station" +msgstr "Имя этой станции" + +#: init.lua +msgid "" +"How do you call this place here? Example: \"my first house\", \"mine\", \"shop\"..." +msgstr "" +"Как вы назавёте это место? Пример: \"мой первый дом\", \"шахта\", \"магазин\"..." + +#: init.lua +msgid "Assign to Network:" +msgstr "Добавить в сеть:" + +#: init.lua +#, lua-format +msgid "You can have more than one network. If unsure, use \"%s\"" +msgstr "Вы можете иметь несколько сетей. Если вы не уверены, используйте \"%s\"" + +#: init.lua +msgid "Owned by:" +msgstr "Пренадлежит:" + +#: init.lua +msgid "Unless you know what you are doing, leave this empty." +msgstr "Если вы не знаете для чего это, оставьте это пустым." + +#: init.lua +msgid "Help" +msgstr "Справка" + +#: init.lua +msgid "Save" +msgstr "Сохранить" + +#: init.lua +msgid "Update failed! Resetting this box on the travelnet." +msgstr "Обновление не выполнено! Нстройки телепорта сброшенны." + +#: init.lua +#, lua-format +msgid "Station '%s'" +msgstr "Станция «%s»" + +#: init.lua +#, lua-format +msgid " has been reattached to the network '%s'." +msgstr " присоеденён к сети «%s»." + +#: init.lua +msgid "Locked travelnet. Type /help for help:" +msgstr "Закрытый телепорт. Напишите /help для справки:" + +#: init.lua travelnet.lua +msgid "Travelnet-Box" +msgstr "Телепорт" + +#: init.lua +msgid "Punch box to update target list." +msgstr "Ударьте станцию для обновления целей." + +#: init.lua +msgid "Assigned to Network:" +msgstr "Присоеденён к сети:" + +#: init.lua +msgid "Click on target to travel there:" +msgstr "Выберите цель, чтобы переместится:" + +# (G)round floor +#: init.lua +msgid "G" +msgstr "1" + +#: init.lua +msgid "This station is already the first one on the list." +msgstr "Эта станция уже первая в списке." + +#: init.lua +msgid "This station is already the last one on the list." +msgstr "Эта станция уже последнея в списке." + +#: init.lua +msgid "Position in list:" +msgstr "Позиция:" + +#: init.lua +msgid "move up" +msgstr "▲ вверх" + +#: init.lua +msgid "move down" +msgstr "▼ вниз" + +#: init.lua +#, lua-format +msgid "on travelnet '%s'" +msgstr "на сети «%s»" + +#: init.lua +#, lua-format +msgid "(owned by %s)" +msgstr "(пренадлежит %s)" + +#: init.lua +msgid "ready for usage. Right-click to travel, punch to update." +msgstr "готова к использованию. Правая кнопка для перемещения, ударить чтобы обновить." + +#: init.lua +#, lua-format +msgid "at %s m" +msgstr "на %s м" + +#: init.lua +msgid "Error" +msgstr "Ошибка" + +#: init.lua +msgid "Please provide a name for this station." +msgstr "Укажите название этой станции." + +#: init.lua +msgid "" +"Please provide the name of the network this station ought to be connected to." +msgstr "" +"Укажите название сети, к которой добавить эту станцию." + +#: init.lua +#, lua-format +msgid "There is no player with interact privilege named '%s'. Aborting." +msgstr "Нет игрока с привилегией «interact» по имени «%s». Отмена." + +#: init.lua +msgid "" +"You do not have the travelnet_attach priv which is required to attach your " +"box to the network of someone else. Aborting." +msgstr "" +"У вас нет привилегии «travelnet_attach», которая необходима для добавки " +"вашего телепорта в сеть другого игрока. Отмена." + +#: init.lua +#, lua-format +msgid "" +"A station named '%s' already exists on this network. Please choose a " +"diffrent name!" +msgstr "" +"Станция «%s» уже существует в этой сети. " +"Попробуйте другое имя!" + +#: init.lua +#, lua-format +msgid "Network '%s'," +msgstr "Сеть «%s»," + +#: init.lua +#, lua-format +msgid "" +"already contains the maximum number (=%s) of allowed stations per network. " +"Please choose a diffrent/new network name." +msgstr "" +"уже содержит максимальное количество (=%s) разрешенных станций на сеть. " +"Выберите друю сеть (иное имя сети)." + +#: init.lua +#, lua-format +msgid "has been added to the network '%s'" +msgstr "была добавлена в сеть «%s»" + +#: init.lua +#, lua-format +msgid ", which now consists of %s station(s)." +msgstr ", которая теперь состоит из %s станций." + +#: init.lua +msgid "Station:" +msgstr "Станция:" + +#: init.lua +msgid "Network:" +msgstr "Сеть:" + +#: init.lua +msgid "No help available yet." +msgstr "Пока нет справки." + +#: init.lua +msgid "Please click on the target you want to travel to." +msgstr "Пожалуйста, выберите цель, куда вы хотели бы попасть." + +#: init.lua +msgid "There is something wrong with the configuration of this station." +msgstr "С конфигурацией этой станции что-то не так." + +#: init.lua +msgid "This travelnet is lacking data and/or improperly configured." +msgstr "В этом телепорте отсутствуют данные или он неправильно настроен." + +#: init.lua +msgid "does not exist (anymore?) on this network." +msgstr "в этой сети (больше?) не существует." + +#: init.lua +#, lua-format +msgid "Initiating transfer to station '%s'." +msgstr "Инициирование перехода на станцию «%s»." + +#: init.lua +msgid "Could not find information about the station that is to be removed." +msgstr "Не удалось найти информацию о станции, для удаления." + +#: init.lua +msgid "Could not find the station that is to be removed." +msgstr "Не удалось найти станцию, для удаления." + +#: init.lua +#, lua-format +msgid "has been REMOVED from the network '%s'." +msgstr "УДАЛЕНА из сети «%s»." + +#: init.lua +#, lua-format +msgid "" +"This %s has not been configured yet. Please set it up first to claim it. " +"Afterwards you can remove it because you are then the owner." +msgstr "" +"Этот %s еще не настроен. Пожалуйста, сначала настройте его, чтобы перенять имущество. " +"После этого вы можете удалить его, так как вы являетесь владельцем." + +#: init.lua +#, lua-format +msgid "This %s belongs to %s. You can't remove it." +msgstr "Этот %s принадлежит %s." diff --git a/travelnet/locale/template.pot b/travelnet/locale/template.pot new file mode 100644 index 00000000..86e0e5cb --- /dev/null +++ b/travelnet/locale/template.pot @@ -0,0 +1,372 @@ +# LANGUAGE translation for the travelnet mod. +# Copyright (C) 2018 Sokomine +# This file is distributed under the same license as the travelnet package. +# CodeXP , 2018. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: travelnet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-04-05 14:34+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: doors.lua +msgid "elevator door (open)" +msgstr "" + +#: doors.lua +msgid "elevator door (closed)" +msgstr "" + +#: elevator.lua +msgid "" +"Congratulations! This is your first elevator.You can build an elevator " +"network by placing further elevators somewhere above or below this one. Just " +"make sure that the x and z coordinate are the same." +msgstr "" + +#: elevator.lua +msgid "" +"This elevator will automaticly connect to the other elevators you have " +"placed at diffrent heights. Just enter a station name and click on \"store\" " +"to set it up. Or just punch it to set the height as station name." +msgstr "" + +#: elevator.lua +msgid "Your nearest elevator network is located" +msgstr "" + +#: elevator.lua +msgid "m behind this elevator and" +msgstr "" + +#: elevator.lua +msgid "m in front of this elevator and" +msgstr "" + +#: elevator.lua +msgid " ERROR" +msgstr "" + +#: elevator.lua +msgid "m to the left" +msgstr "" + +#: elevator.lua +msgid "m to the right" +msgstr "" + +#: elevator.lua +msgid ", located at x" +msgstr "" + +#: elevator.lua +msgid "This elevator here will start a new shaft/network." +msgstr "" + +#: elevator.lua +msgid "" +"This is your first elevator. It differs from travelnet networks by only " +"allowing movement in vertical direction (up or down). All further elevators " +"which you will place at the same x,z coordinates at differnt heights will be " +"able to connect to this elevator." +msgstr "" + +#: elevator.lua +msgid "Elevator" +msgstr "" + +#: elevator.lua +msgid "Elevator (unconfigured)" +msgstr "" + +#: elevator.lua init.lua +msgid "Name of this station:" +msgstr "" + +#: elevator.lua +msgid "Store" +msgstr "" + +#: elevator.lua travelnet.lua +msgid "Not enough vertical space to place the travelnet box!" +msgstr "" + +#: init.lua +msgid "allows to attach travelnet boxes to travelnets of other players" +msgstr "" + +#: init.lua +msgid "allows to dig travelnet boxes which belog to nets of other players" +msgstr "" + +#: init.lua +#, lua-format +msgid "[Mod travelnet] Error: Savefile '%s' could not be written." +msgstr "" + +#: init.lua +#, lua-format +msgid "[Mod travelnet] Error: Savefile '%s' not found." +msgstr "" + +#: init.lua +msgid "Back" +msgstr "" + +#: init.lua +msgid "Exit" +msgstr "" + +#: init.lua +msgid "Travelnet-box (unconfigured)" +msgstr "" + +#: init.lua +msgid "Configure this travelnet station" +msgstr "" + +#: init.lua +msgid "Name of this station" +msgstr "" + +#: init.lua +msgid "" +"How do you call this place here? Example: \"my first house\", \"mine\", " +"\"shop\"..." +msgstr "" + +#: init.lua +msgid "Assign to Network:" +msgstr "" + +#: init.lua +#, lua-format +msgid "You can have more than one network. If unsure, use \"%s\"" +msgstr "" + +#: init.lua +msgid "Owned by:" +msgstr "" + +#: init.lua +msgid "Unless you know what you are doing, leave this empty." +msgstr "" + +#: init.lua +msgid "Help" +msgstr "" + +#: init.lua +msgid "Save" +msgstr "" + +#: init.lua +msgid "Update failed! Resetting this box on the travelnet." +msgstr "" + +#: init.lua +#, lua-format +msgid "Station '%s'" +msgstr "" + +#: init.lua +#, lua-format +msgid " has been reattached to the network '%s'." +msgstr "" + +#: init.lua +msgid "Locked travelnet. Type /help for help:" +msgstr "" + +#: init.lua travelnet.lua +msgid "Travelnet-Box" +msgstr "" + +#: init.lua +msgid "Punch box to update target list." +msgstr "" + +#: init.lua +msgid "Assigned to Network:" +msgstr "" + +#: init.lua +msgid "Click on target to travel there:" +msgstr "" + +#: init.lua +msgid "G" +msgstr "" + +#: init.lua +msgid "This station is already the first one on the list." +msgstr "" + +#: init.lua +msgid "This station is already the last one on the list." +msgstr "" + +#: init.lua +msgid "Position in list:" +msgstr "" + +#: init.lua +msgid "move up" +msgstr "" + +#: init.lua +msgid "move down" +msgstr "" + +#: init.lua +#, lua-format +msgid "on travelnet '%s'" +msgstr "" + +#: init.lua +#, lua-format +msgid "(owned by %s)" +msgstr "" + +#: init.lua +msgid "ready for usage. Right-click to travel, punch to update." +msgstr "" + +#: init.lua +#, lua-format +msgid "at %s m" +msgstr "" + +#: init.lua +msgid "Error" +msgstr "" + +#: init.lua +msgid "Please provide a name for this station." +msgstr "" + +#: init.lua +msgid "" +"Please provide the name of the network this station ought to be connected to." +msgstr "" + +#: init.lua +#, lua-format +msgid "There is no player with interact privilege named '%s'. Aborting." +msgstr "" + +#: init.lua +msgid "" +"You do not have the travelnet_attach priv which is required to attach your " +"box to the network of someone else. Aborting." +msgstr "" + +#: init.lua +#, lua-format +msgid "" +"A station named '%s' already exists on this network. Please choose a " +"diffrent name!" +msgstr "" + +#: init.lua +#, lua-format +msgid "Network '%s'," +msgstr "" + +#: init.lua +#, lua-format +msgid "" +"already contains the maximum number (=%s) of allowed stations per network. " +"Please choose a diffrent/new network name." +msgstr "" + +#: init.lua +#, lua-format +msgid "has been added to the network '%s'" +msgstr "" + +#: init.lua +#, lua-format +msgid ", which now consists of %s station(s)." +msgstr "" + +#: init.lua +msgid "Station:" +msgstr "" + +#: init.lua +msgid "Network:" +msgstr "" + +#: init.lua +msgid "No help available yet." +msgstr "" + +#: init.lua +msgid "Please click on the target you want to travel to." +msgstr "" + +#: init.lua +msgid "There is something wrong with the configuration of this station." +msgstr "" + +#: init.lua +msgid "This travelnet is lacking data and/or improperly configured." +msgstr "" + +#: init.lua +msgid "does not exist (anymore?) on this network." +msgstr "" + +#: init.lua +#, lua-format +msgid "Initiating transfer to station '%s'." +msgstr "" + +#: init.lua +msgid "Could not find information about the station that is to be removed." +msgstr "" + +#: init.lua +msgid "Could not find the station that is to be removed." +msgstr "" + +#: init.lua +#, lua-format +msgid "has been REMOVED from the network '%s'." +msgstr "" + +#: init.lua +#, lua-format +msgid "" +"This %s has not been configured yet. Please set it up first to claim it. " +"Afterwards you can remove it because you are then the owner." +msgstr "" + +#: init.lua +#, lua-format +msgid "This %s belongs to %s. You can't remove it." +msgstr "" + +#: init.lua +#, lua-format +msgid "Remove station" +msgstr "" + +#: init.lua +#, lua-format +msgid "You do not have enough room in your inventory." +msgstr "" + +#: init.lua +#, lua-format +msgid "[Mod travelnet] Error: Savefile '%s' is damaged. Saved the backup as '%s'." +msgstr "" diff --git a/travelnet/locale/template.txt b/travelnet/locale/template.txt deleted file mode 100644 index f247861a..00000000 --- a/travelnet/locale/template.txt +++ /dev/null @@ -1,94 +0,0 @@ -# Template - -### config.lua ### - -### init.lua ### - -allows to attach travelnet boxes to travelnets of other players = -allows to dig travelnet boxes which belog to nets of other players = - -[Mod travelnet] Error: Savefile '%s' could not be written. = -[Mod travelnet] Error: Savefile '%s' not found. = - -Back = -Exit = - -Travelnet-box (unconfigured) = - -Configure this travelnet station = -Name of this station = -How do you call this place here? Example: \"my first house\", \"mine\", \"shop\"... = -Assign to Network: = -You can have more than one network. If unsure, use \"%s\" = -Owned by: = -Unless you know what you are doing, leave this empty. = -Help = -Save = -Remove station = -You do not have enough room in your inventory. = -Update failed! Resetting this box on the travelnet. = -Station '%s' = -has been reattached to the network '%s'. = -Locked travelnet. Type /help for help: = -Punch box to update target list. = -Travelnet-Box = -Name of this station: = -Assigned to Network: = -Click on target to travel there: = -G = -This station is already the first one on the list. = -This station is already the last one on the list. = -Position in list: = -move up = -move down = -on travelnet '%s' = -owned by %s = -ready for usage. Right-click to travel, punch to update. = -at %s m = -Error = -Please provide a name for this station. = -Please provide the name of the network this station ought to be connected to. = -There is no player with interact privilege named '%s'. Aborting. = -You do not have the travelnet_attach priv which is required to attach your box to the network of someone else. Aborting. = -A station named '%s' already exists on this network. Please choose a diffrent name! = -Network '%s' = -already contains the maximum number (=%s) of allowed stations per network. Please choose a diffrent/new network name. = -has been added to the network '%s' = -, which now consists of %s station(s). = -Station: = -Network: = -No help available yet. = -Please click on the target you want to travel to. = -There is something wrong with the configuration of this station. = -This travelnet is lacking data and/or improperly configured. = -does not exist (anymore?) on this network. = -Initiating transfer to station '%s'. = -Could not find information about the station that is to be removed. = -Could not find the station that is to be removed. = -has been REMOVED from the network '%s'. = -This %s has not been configured yet. Please set it up first to claim it. Afterwards you can remove it because you are then the owner. = -This %s belongs to %s. You can't remove it. = - - -### travelnet.lua ### -Not enough vertical space to place the travelnet box! = - - -### elevator.lua ### -Congratulations! This is your first elevator. You can build an elevator network by placing further elevators somewhere above or below this one. Just make sure that the x and z coordinate are the same. = -This elevator will automaticly connect to the other elevators you have placed at diffrent heights. Just enter a station name and click on \"store\" to set it up. Or just punch it to set the height as station name. = -Your nearest elevator network is located = -m behind this elevator and = -m in front of this elevator and = -m to the left = -m to the right = -, located at x = -This elevator here will start a new shaft/network. = -This is your first elevator. It differs from travelnet networks by only allowing movement in vertical direction (up or down). All further elevators which you will place at the same x,z coordinates at differnt heights will be able to connect to this elevator. = -Elevator = -Elevator (unconfigured) = - - -### doors.lua ### -elevator door (open) = -elevator door (closed) = diff --git a/travelnet/mod.conf b/travelnet/mod.conf new file mode 100644 index 00000000..49fcb681 --- /dev/null +++ b/travelnet/mod.conf @@ -0,0 +1 @@ +name = travelnet diff --git a/travelnet/sounds/travelnet_bell.ogg b/travelnet/sounds/travelnet_bell.ogg new file mode 100644 index 0000000000000000000000000000000000000000..994f6499a34a8cdb1a46292419c1dc62f5f64575 GIT binary patch literal 19085 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 FzyXz(klz3R literal 0 HcmV?d00001 diff --git a/travelnet/travelnet.lua b/travelnet/travelnet.lua index 56cbf357..9fba7fe2 100644 --- a/travelnet/travelnet.lua +++ b/travelnet/travelnet.lua @@ -74,7 +74,9 @@ minetest.register_node("travelnet:travelnet", { on_place = function(itemstack, placer, pointed_thing) local pos = pointed_thing.above; - if( minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name ~= "air" ) then + local def = minetest.registered_nodes[ + minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name] + if not def or not def.buildable_to then minetest.chat_send_player( placer:get_player_name(), S('Not enough vertical space to place the travelnet box!')) return;