From a6f38971cc17a188331c9e93006808ca5d03d2c9 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 8 Feb 2021 17:57:40 +0100 Subject: [PATCH 1/7] update --- mods/3d_armor/3d_armor/init.lua | 100 ++-- mods/advtrains/advtrains/couple.lua | 2 +- mods/advtrains/advtrains/helpers.lua | 25 + mods/advtrains/advtrains/nodedb.lua | 11 +- mods/advtrains/advtrains/p_mesecon_iface.lua | 20 +- mods/advtrains/advtrains/trainlogic.lua | 15 +- mods/advtrains/advtrains/wagons.lua | 23 +- .../advtrains_luaautomation/README.txt | 491 ++++++++++-------- .../advtrains_luaautomation/active_common.lua | 6 +- mods/advtrains/advtrains_train_track/init.lua | 14 +- mods/builtin_item/init.lua | 3 +- mods/mobs_redo/api.lua | 22 +- mods/mobs_sky/mobs_bat/mod.conf | 2 +- mods/plantlife_modpack/woodsoils/nodes.lua | 20 + mods/tubelib2/tube_api.lua | 6 +- mods/tubelib2/tube_test.lua | 51 +- 16 files changed, 472 insertions(+), 339 deletions(-) mode change 100644 => 100755 mods/advtrains/advtrains_luaautomation/README.txt diff --git a/mods/3d_armor/3d_armor/init.lua b/mods/3d_armor/3d_armor/init.lua index da381d41..049b6fd2 100644 --- a/mods/3d_armor/3d_armor/init.lua +++ b/mods/3d_armor/3d_armor/init.lua @@ -436,80 +436,68 @@ end, true) minetest.register_globalstep(function(dtime) timer = timer + dtime - if timer > armor.config.init_delay then - for player, count in pairs(pending_players) do - local remove = init_player_armor(player) == true - pending_players[player] = count + 1 - if remove == false and count > armor.config.init_times then - minetest.log("warning", S("3d_armor: Failed to initialize player")) - remove = true - end - if remove == true then - pending_players[player] = nil + if timer <= armor.config.init_delay then + return + end + timer = 0 + + for player, count in pairs(pending_players) do + local remove = init_player_armor(player) == true + pending_players[player] = count + 1 + if remove == false and count > armor.config.init_times then + minetest.log("warning", S("3d_armor: Failed to initialize player")) + remove = true + end + if remove == true then + pending_players[player] = nil + end + end + + -- water breathing protection, added by TenPlus1 + if armor.config.water_protect == true then + for _,player in pairs(minetest.get_connected_players()) do + local name = player:get_player_name() + if armor.def[name].water > 0 and + player:get_breath() < 10 then + player:set_breath(10) end end - timer = 0 end end) --- Fire Protection and water breathing, added by TenPlus1. - +-- Fire Protection, added by TenPlus1. if armor.config.fire_protect == true then - -- override hot nodes so they do not hurt player anywhere but mod + -- override any hot nodes that do not already deal damage for _, row in pairs(armor.fire_nodes) do if minetest.registered_nodes[row[1]] then - minetest.override_item(row[1], {damage_per_second = 0}) + local damage = minetest.registered_nodes[row[1]].damage_per_second + if not damage or damage == 0 then + minetest.override_item(row[1], {damage_per_second = row[3]}) + end end end else - print (S("[3d_armor] Fire Nodes disabled")) + print ("[3d_armor] Fire Nodes disabled") end -if armor.config.water_protect == true or armor.config.fire_protect == true then - minetest.register_globalstep(function(dtime) - armor.timer = armor.timer + dtime - if armor.timer < armor.config.update_time then - return - end - for _,player in pairs(minetest.get_connected_players()) do - local name = player:get_player_name() - local pos = player:get_pos() - local hp = player:get_hp() - if not name or not pos or not hp then - return - end - -- water breathing - if armor.config.water_protect == true then - if armor.def[name].water > 0 and - player:get_breath() < 10 then - player:set_breath(10) - end - end +if armor.config.fire_protect == true then + minetest.register_on_player_hpchange(function(player, hp_change, reason) + + if reason.type == "node_damage" and reason.node then -- fire protection - if armor.config.fire_protect == true then - local fire_damage = true - pos.y = pos.y + 1.4 -- head level - local node_head = minetest.get_node(pos).name - pos.y = pos.y - 1.2 -- feet level - local node_feet = minetest.get_node(pos).name - -- is player inside a hot node? - for _, row in pairs(armor.fire_nodes) do - -- check fire protection, if not enough then get hurt - if row[1] == node_head or row[1] == node_feet then - if fire_damage == true then + if armor.config.fire_protect == true and hp_change < 0 then + local name = player:get_player_name() + for _,igniter in pairs(armor.fire_nodes) do + if reason.node == igniter[1] then + if armor.def[name].fire < igniter[2] then armor:punch(player, "fire") - last_punch_time[name] = minetest.get_gametime() - fire_damage = false - end - if hp > 0 and armor.def[name].fire < row[2] then - hp = hp - row[3] * armor.config.update_time - player:set_hp(hp) - break + else + hp_change = 0 end end end end end - armor.timer = 0 - end) + return hp_change + end, true) end diff --git a/mods/advtrains/advtrains/couple.lua b/mods/advtrains/advtrains/couple.lua index 5116bacc..76fa4474 100644 --- a/mods/advtrains/advtrains/couple.lua +++ b/mods/advtrains/advtrains/couple.lua @@ -106,7 +106,7 @@ minetest.register_entity("advtrains:couple", { end, on_step=function(self, dtime) return advtrains.pcall(function() - if advtrains.outside_range(self.object:getpos()) then + if advtrains.wagon_outside_range(self.object:getpos()) then self.object:remove() return end diff --git a/mods/advtrains/advtrains/helpers.lua b/mods/advtrains/advtrains/helpers.lua index 3b0bedd8..cf890caa 100644 --- a/mods/advtrains/advtrains/helpers.lua +++ b/mods/advtrains/advtrains/helpers.lua @@ -445,3 +445,28 @@ atdebug("pts",os.clock()-t1,"s") ]] +-- Function to check whether a position is near (within range of) any player +function advtrains.position_in_range(pos, range) + if not pos then + return true + end + for _,p in pairs(minetest.get_connected_players()) do + if vector.distance(p:get_pos(),pos)<=range then + return true + end + end + return false +end + +local active_node_range = tonumber(minetest.settings:get("active_block_range"))*16 + 16 +-- Function to check whether node at position(pos) is "loaded"/"active" +-- That is, whether it is within the active_block_range to a player +if minetest.is_block_active then -- define function differently whether minetest.is_block_active is available or not + advtrains.is_node_loaded = minetest.is_block_active +else + function advtrains.is_node_loaded(pos) + if advtrains.position_in_range(pos, active_node_range) then + return true + end + end +end diff --git a/mods/advtrains/advtrains/nodedb.lua b/mods/advtrains/advtrains/nodedb.lua index 531979e9..878ed88b 100644 --- a/mods/advtrains/advtrains/nodedb.lua +++ b/mods/advtrains/advtrains/nodedb.lua @@ -223,7 +223,7 @@ end function ndb.swap_node(pos, node, no_inval) - if minetest.get_node_or_nil(pos) then + if advtrains.is_node_loaded(pos) then minetest.swap_node(pos, node) end ndb.update(pos, node) @@ -294,11 +294,12 @@ ndb.run_lbm = function(pos, node) ndb.update(pos, node) else if (nodeid~=node.name or param2~=node.param2) then - atprint("nodedb: lbm replaced", pos, "with nodeid", nodeid, "param2", param2, "cid is", cid) - minetest.swap_node(pos, {name=nodeid, param2 = param2}) + --atprint("nodedb: lbm replaced", pos, "with nodeid", nodeid, "param2", param2, "cid is", cid) + local newnode = {name=nodeid, param2 = param2} + minetest.swap_node(pos, newnode) local ndef=minetest.registered_nodes[nodeid] - if ndef and ndef.on_updated_from_nodedb then - ndef.on_updated_from_nodedb(pos, node) + if ndef and ndef.advtrains and ndef.advtrains.on_updated_from_nodedb then + ndef.advtrains.on_updated_from_nodedb(pos, newnode) end return true end diff --git a/mods/advtrains/advtrains/p_mesecon_iface.lua b/mods/advtrains/advtrains/p_mesecon_iface.lua index 177112e9..0eef96ae 100644 --- a/mods/advtrains/advtrains/p_mesecon_iface.lua +++ b/mods/advtrains/advtrains/p_mesecon_iface.lua @@ -13,17 +13,19 @@ minetest.override_item("mesecons_switch:mesecon_switch_off", { mesecon.receptor_on(pos) minetest.sound_play("mesecons_switch", {pos=pos}) end, - on_updated_from_nodedb = function(pos, node) - mesecon.receptor_off(pos) - end, advtrains = { getstate = "off", setstate = function(pos, node, newstate) if newstate=="on" then advtrains.ndb.swap_node(pos, {name="mesecons_switch:mesecon_switch_on", param2=node.param2}) - mesecon.receptor_on(pos) + if advtrains.is_node_loaded(pos) then + mesecon.receptor_on(pos) + end end end, + on_updated_from_nodedb = function(pos, node) + mesecon.receptor_off(pos) + end, }, }) @@ -38,17 +40,19 @@ minetest.override_item("mesecons_switch:mesecon_switch_on", { mesecon.receptor_off(pos) minetest.sound_play("mesecons_switch", {pos=pos}) end, - on_updated_from_nodedb = function(pos, node) - mesecon.receptor_on(pos) - end, advtrains = { getstate = "on", setstate = function(pos, node, newstate) if newstate=="off" then advtrains.ndb.swap_node(pos, {name="mesecons_switch:mesecon_switch_off", param2=node.param2}) - mesecon.receptor_off(pos) + if advtrains.is_node_loaded(pos) then + mesecon.receptor_off(pos) + end end end, fallback_state = "off", + on_updated_from_nodedb = function(pos, node) + mesecon.receptor_on(pos) + end, }, }) diff --git a/mods/advtrains/advtrains/trainlogic.lua b/mods/advtrains/advtrains/trainlogic.lua index cc34b4fd..76bbb7a6 100644 --- a/mods/advtrains/advtrains/trainlogic.lua +++ b/mods/advtrains/advtrains/trainlogic.lua @@ -527,7 +527,7 @@ function advtrains.train_step_c(id, train, dtime) local collpos = advtrains.path_get(train, atround(collindex)) if collpos then local rcollpos=advtrains.round_vector_floor_y(collpos) - local is_loaded_area = minetest.get_node_or_nil(rcollpos) ~= nil + local is_loaded_area = advtrains.is_node_loaded(rcollpos) for x=-train.extent_h,train.extent_h do for z=-train.extent_h,train.extent_h do local testpos=vector.add(rcollpos, {x=x, y=0, z=z}) @@ -870,14 +870,7 @@ function advtrains.spawn_wagons(train_id) local index = advtrains.path_get_index_by_offset(train, train.index, -data.pos_in_train) local pos = advtrains.path_get(train, atfloor(index)) - local spawn = false - for _,p in pairs(minetest.get_connected_players()) do - if vector.distance(p:get_pos(),pos)<=ablkrng then - spawn = true - end - end - - if spawn then + if advtrains.position_in_range(pos, ablkrng) then --atdebug("wagon",w_id,"spawning") local wt = advtrains.get_wagon_prototype(data) local wagon = minetest.add_entity(pos, wt):get_luaentity() @@ -1032,7 +1025,7 @@ function advtrains.train_check_couples(train) if not train.cpl_front then -- recheck front couple local front_trains, pos = advtrains.occ.get_occupations(train, atround(train.index) + CPL_CHK_DST) - if minetest.get_node_or_nil(pos) then -- if the position is loaded... + if advtrains.is_node_loaded(pos) then -- if the position is loaded... for tid, idx in pairs(front_trains) do local other_train = advtrains.trains[tid] if not advtrains.train_ensure_init(tid, other_train) then @@ -1062,7 +1055,7 @@ function advtrains.train_check_couples(train) if not train.cpl_back then -- recheck back couple local back_trains, pos = advtrains.occ.get_occupations(train, atround(train.end_index) - CPL_CHK_DST) - if minetest.get_node_or_nil(pos) then -- if the position is loaded... + if advtrains.is_node_loaded(pos) then -- if the position is loaded... for tid, idx in pairs(back_trains) do local other_train = advtrains.trains[tid] if not advtrains.train_ensure_init(tid, other_train) then diff --git a/mods/advtrains/advtrains/wagons.lua b/mods/advtrains/advtrains/wagons.lua index 5c8ac257..1c663feb 100644 --- a/mods/advtrains/advtrains/wagons.lua +++ b/mods/advtrains/advtrains/wagons.lua @@ -15,19 +15,8 @@ advtrains.wagon_prototypes = {} advtrains.wagon_objects = {} local unload_wgn_range = advtrains.wagon_load_range + 32 -function advtrains.outside_range(pos) -- returns true if the object is outside of unload_wgn_range of any player - -- this is part of a workaround until mintest core devs decide to fix a bug with static_save=false. - local outofrange = true - if not pos then - return true - end - for _,p in pairs(minetest.get_connected_players()) do - if vector.distance(p:get_pos(),pos)<=unload_wgn_range then - outofrange = false - break - end - end - return outofrange +function advtrains.wagon_outside_range(pos) -- returns true if the object is outside of unload_wgn_range of any player + return not advtrains.position_in_range(pos, unload_wgn_range) end local setting_show_ids = minetest.settings:get_bool("advtrains_show_ids") @@ -299,6 +288,8 @@ function wagon:on_step(dtime) end local train=self:train() + + local is_in_loaded_area = advtrains.is_node_loaded(pos) --custom on_step function if self.custom_on_step then @@ -453,7 +444,7 @@ function wagon:on_step(dtime) end --checking for environment collisions(a 3x3 cube around the center) - if not train.recently_collided_with_env then + if is_in_loaded_area and not train.recently_collided_with_env then local collides=false local exh = self.extent_h or 1 local exv = self.extent_v or 2 @@ -477,7 +468,7 @@ function wagon:on_step(dtime) --DisCouple -- FIX: Need to do this after the yaw calculation - if data.pos_in_trainparts and data.pos_in_trainparts>1 then + if is_in_loaded_area and data.pos_in_trainparts and data.pos_in_trainparts>1 then if train.velocity==0 then if not self.discouple or not self.discouple.object:getyaw() then atprint(self.id,"trying to spawn discouple") @@ -530,7 +521,7 @@ function wagon:on_step(dtime) end end if not players_in then - if advtrains.outside_range(pos) then + if advtrains.wagon_outside_range(pos) then --atdebug("wagon",self.id,"unloading (too far away)") -- Workaround until minetest engine deletes attached sounds if self.sound_loop_handle then diff --git a/mods/advtrains/advtrains_luaautomation/README.txt b/mods/advtrains/advtrains_luaautomation/README.txt old mode 100644 new mode 100755 index 287a0bdc..c320d313 --- a/mods/advtrains/advtrains_luaautomation/README.txt +++ b/mods/advtrains/advtrains_luaautomation/README.txt @@ -1,288 +1,359 @@ -#### Advtrains - Lua Automation features +# Advtrains - Lua Automation features -This mod offers components that run LUA code and interface with each other through a global environment. It makes complex automated railway systems possible. +This mod offers components that run LUA code and interface with each other through a global environment. It makes complex automated railway systems possible. The mod is sometimes abbreviated as 'atlatc'. This stands for AdvTrainsLuaATC. This short name has been chosen for user convenience, since the name of this mod ('advtrains_luaautomation') is very long. -### atlatc -The mod is sometimes abbreviated as 'atlatc'. This stands for AdvTrainsLuaATC. This short name has been chosen for user convenience, since the name of this mod ('advtrains_luaautomation') is very long. - -### Privilege +## Privileges To perform any operations using this mod (except executing operation panels), players need the "atlatc" privilege. This privilege should never be granted to anyone except trusted administrators. Even though the LUA environment is sandboxed, it is still possible to DoS the server by coding infinite loops or requesting expotentially growing interrupts. -### Active and passive -Active components are these who have LUA code running in them. They are triggered on specific events. Passive components are dumb, they only have a state and can be set to another state, they can't perform actions themselves. +## Environments -### Environments - -Each active component is assigned to an environment. This is where all data are held. Components in different environments can't inferface with each other. +Each active component is assigned to an environment where all atlac data is held. Components in different environments can't inferface with each other. This system allows multiple independent automation systems to run simultaneously without polluting each other's environment. -/env_create -Create environment with the given name. To be able to do anything, you first need to create an environment. Choose the name wisely, you can't change it afterwards. + - `/env_create `: +Create environment with the given name. To be able to do anything, you first need to create an environment. Choose the name wisely, you can't change it afterwards without deleting the environment and starting again. -/env_setup + - `/env_setup `: Invoke the form to edit the environment's initialization code. For more information, see the section on active components. You can also delete an environment from here. -### Active components +## Functions and variables +### General Functions and Variables +The following standard Lua libraries are available: + - `string` + - `math` + - `table` + - `os` + +The following standard Lua functions are available: + - `assert` + - `error` + - `ipairs` + - `pairs` + - `next` + - `select` + - `tonumber` + - `tostring` + - `type` + - `unpack` -The code of every active component is run on specific events which are explained soon. When run, every variable written that is not local and is no function or userdata is saved over code re-runs and over server restarts. Additionally, the following global variables are defined: +Any attempt to overwrite the predefined values results in an error. -# event -The variable 'event' contains a table with information on the current event. How this table can look is explained below. +## Components and Events -# S +### Components +Atlac components introduce automation-capable components that fall within two categories: + - Active Components are components that are able to run Lua code, triggered by specific events. + - Passive Components can't perform actions themselves. Their state can be read and set by active components or manually by the player. + + + +## Functions and Variables + +### Events +The event table is a variable created locally by the component being triggered. It is a table with the following format: +```lua +event = { + type = "", + = true, + --additional event-specific content +} +``` +You can check the event type by using the following: +```lua +if event.type == "wanted" then + --do stuff +end +``` +or +```lua +if event.wanted then + --do stuff +end +```` +where `wanted` is the event type to check for. +See the "Active Components" section below for details on the various event types as not all of them are applicable to all components. + +### LuaAutomation Global Variables + - `S` The variable 'S' contains a table which is shared between all components of the environment. Its contents are persistent over server restarts. May not contain functions, every other value is allowed. -Example: -Component 1: S.stuff="foo" -Component 2: print(S.stuff) --> foo -# F + - `F` The variable 'F' also contains a table which is shared between all components of the environment. Its contents are discarded on server shutdown or when the init code gets re-run. Every data type is allowed, even functions. The purpose of this table is not to save data, but to provide static value and function definitions. The table should be populated by the init code. -# Standard Lua functions -The following standard Lua libraries are available: -string, math, table, os -The following standard Lua functions are available: -assert, error, ipairs, pairs, next, select, tonumber, tostring, type, unpack +### LuaAutomation Global Functions +> Note: in the following functions, all parameters named `pos` designate a position. You can use the following: +> - a default Minetest position vector (eg. {x=34, y=2, z=-18}) +> - the POS(34,2,-18) shorthand below. +> - A string, the passive component name. See 'passive component naming'. + -Every attempt to overwrite any of the predefined values results in an error. -# LuaAutomation-specific global functions + - `POS(x,y,z)` +Shorthand function to create a position vector {x=?, y=?, z=?} with less characters. -POS(x,y,z) -Shorthand function to create a position vector {x=?, y=?, z=?} with less characters + - `getstate(pos)` +Get the state of the passive component at position `pos`. -In the following functions, all parameters named 'pos' designate a position. You can use either: -- a default Minetest position vector (like {x=34, y=2, z=-18}) -- the POS(34,2,-18) shorthand -- A string, the passive component name. See 'passive component naming'. + - `setstate(pos, newstate)` +Set the state of the passive component at position `pos`. -getstate(pos) -Get the state of the passive component at position 'pos'. See section on passive components for more info. -pos can be either a position vector (created by POS()) or a string, the name of this passive component. - -setstate(pos, newstate) -Set the state of the passive component at position 'pos'. - -is_passive(pos) + - `is_passive(pos)` Checks whether there is a passive component at the position pos (and/or whether a passive component with this name exists) -interrupt(time, message) -Cause LuaAutomation to trigger an 'int' event on this component after the given time in seconds with the specified 'message' field. 'message' can be of any Lua data type. -Not available in init code! + - `interrupt(time, message)` +Cause LuaAutomation to trigger an `int` event on this component after the given time in seconds with the specified `message` field. `message` can be of any Lua data type. *Not available in init code.* -interrupt_pos(pos, message) -Immediately trigger an 'ext_int' event on the active component at position pos. 'message' is like in interrupt(). -USE WITH CARE, or better don't use! Incorrect use can result in expotential growth of interrupts. + - `interrupt_pos(pos, message)` +Immediately trigger an `ext_int` event on the active component at position pos. `message` is like in interrupt(). Use with care, or better **_don't use_**! Incorrect use can result in **_expotential growth of interrupts_**. -digiline_send(channel, message) + - `digiline_send(channel, message)` Make this active component send a digiline message on the specified channel. -Not available in init code! +Not available in init code. --- The next 4 functions are available when advtrains_interlocking is enabled: -- +#### Interlocking Route Management Functions +If `advtrains_interlocking` is enabled, the following aditional functions can be used: -can_set_route(pos, route_name) + - `can_set_route(pos, route_name)` Returns whether it is possible to set the route designated by route_name from the signal at pos. -set_route(pos, route_name) + - `set_route(pos, route_name)` Requests the given route from the signal at pos. Has the same effect as clicking "Set Route" in the signalling dialog. -cancel_route(pos) + - `cancel_route(pos)` Cancels the route that is set from the signal at pos. Has the same effect as clicking "Cancel Route" in the signalling dialog. -get_aspect(pos) + - `get_aspect(pos)` Returns the signal aspect of the signal at pos. A signal aspect has the following format: -aspect = { +```lua +{ main = { -- the next track section in line. Shows blocked for shunt routes free = , speed = , }, shunt = { -- whether a "shunting allowed" aspect should be shown free = , - } + }, dst = { -- the aspect of the next main signal on (at end of) route free = , speed = , - } + }, info = { call_on = , -- Call-on route, expect train in track ahead dead_end = , -- Route ends on a dead end (e.g. bumper) } } -As of August 2018, only the aspect.main.free field is ever used by the interlocking system. +``` +As of August 2018 (git commit d837e7e), only the aspect.main.free field is ever used by the interlocking system. -# Lines +### Active Component +#### Lua ATC Rails +Lua ATC rails are the only components that can actually interface with trains. The following event types are available to the Lua ATC rails: + - ```lua +{type="train", train=true, id=""} +``` + * This event is fired when a train enters the rail. The field `id` is the unique train ID, which is 6-digit random numerical string. + * If the world contains trains from an older advtrains version, this string may be longer and contain a dot `.` + + - ```lua +{type="int", int=true, msg=} +``` + * Fired when an interrupt set by the `interrupt` function runs out. `` is the message passed to the interrupt function. + * For backwards compatiblity reasons, `` is also contained in an `event.message` variable. + + - ```lua +{type="ext_int", ext_int=true, message=} +``` + * Fired when another node called `interrupt_pos` on this position. `message` is the message passed to the interrupt_pos function. + + - ```lua +{type="digiline", digiline=true, channel=, msg=} +``` + * Fired when the controller receives a digiline message. + +##### Basic Lua Rail Functions and Variables +In addition to the above environment functions, the following functions are available to whilst the train is in contact with the LuaATC rail: + + - `atc_send()` + Sends the specified ATC command to the train (a string) and returns true. If there is no train, returns false and does nothing. See [atc_command.txt](../atc_command.txt) for the ATC command syntax. + + - `atc_reset()` + Resets the train's current ATC command. If there is no train, returns false and does nothing. + + - `atc_arrow` + Boolean, true when the train is driving in the direction of the arrows of the ATC rail. Nil if there is no train. + + - `atc_id` + Train ID of the train currently passing the controller. Nil if there's no train. + + - `atc_speed` + Speed of the train, or nil if there is no train. + + - `atc_set_text_outside(text)` + Set text shown on the outside of the train. Pass nil to show no text. `text` must be a string. + + - `atc_set_text_inside(text)` + Set text shown to train passengers. Pass nil to show no text. `text` must be a string. + + - `get_line()` + Returns the "Line" property of the train (a string). + This can be used to distinguish between trains of different lines and route them appropriately. + The interlocking system also uses this property for Automatic Routesetting. + + - `set_line(line)` + Sets the "Line" property of the train (a string). + If the first digit of this string is a number (0-9), any subway wagons on the train (from advtrains_train_subway) will have this one displayed as line number + (where "0" is actually shown as Line 10 on the train) + + - `get_rc()` + Returns the "Routingcode" property of the train (a string). + The interlocking system uses this property for Automatic Routesetting. + + - `set_rc(routingcode)` + Sets the "Routingcode" property of the train (a string). + The interlocking system uses this property for Automatic Routesetting. + +##### Shunting Functions and Variables +There are several functions available especially for shunting operations. Some of these functions make use of Freight Codes (FC) set in the Wagon Properties of each wagon and/or locomotive: + + - `split_at_index(index, atc_command)` + Splits the train at the specified index, into a train with index-1 wagons and a second train starting with the index-th wagon. The `atc_command` specified is sent to the second train after decoupling. `"S0"` or `"B0"` is common to ensure any locomotives in the remaining train don't continue to move. + + Example: train has wagons `"foo","foo","foo","bar","bar","bar"` + Command: `split_at_index(4,"S0")` + Result: first train (continues at previous speed): `"foo","foo","foo"`, second train (slows at S0): `"bar","bar","bar"` + + - `split_at_fc(atc_command, len)` + Splits the train in such a way that all cars with non-empty current FC of the first part of the train have the same FC. The + `atc_command` specified is sent to the rear part, as with split_at_index. It returns the fc of the cars of the first part. + + Example : Train has current FCs `"" "" "bar" "foo" "bar"` + Command: `split_at_fc()` + Result: `train "" "" "bar"` and `train "foo" "bar"` + The function returns `"bar"` in this case. + + The optional argument `len` specifies the maximum length for the + first part of the train. + Example: Train has current FCs `"foo" "foo" "foo" "foo" "bar" "bar"` + Command: `split_at_fc(,3)` + Result: `"foo" "foo" "foo"` and `"foo" "bar" "bar"` + The function returns `"foo"` in this case. + + + + - `split_off_locomotive(command, len)` + Splits off the locomotives at the front of the train, which are + identified by an empty FC. `command` specifies the ATC command to be + executed by the rear half of the train. The optional argument `len` specifies the maximum length for the + first part of the train as above. + + - `step_fc()` + Steps the FCs of all train cars forward. FCs are composed of codes + separated by exclamation marks (`!`), for instance + `"foo!bar!baz"`. Each wagon has a current FC, indicating its next + destination. Stepping the freight code forward, selects the next + code after the !. If the end of the string is reached, then the + first code is selected, except if the string ends with a question + mark (`?`), then the order is reversed. + + + - `train_length()` + returns the number of cars the train is composed of. + + - `set_autocouple()` + Sets the train into autocouple mode. The train will couple to the next train it collides with. + + - `unset_autocouple()` + Unsets autocouple mode + +Deprecated: + - `set_shunt()`, `unset_shunt()` + deprecated aliases for set_autocouple() and unset_autocouple(), will be removed from a later release. + +##### Timetable Automation The advtrains_line_automation component adds a few contraptions that should make creating timeable systems easier. Part of its functionality is also available in LuaATC: -- rwt.* - all Railway Time functions are included as documented in https://advtrains.de/wiki/doku.php?id=dev:lines:rwt +- `rwt.*` +All Railway Time functions are included as documented in https://advtrains.de/wiki/doku.php?id=dev:lines:rwt -- schedule(rw_time, msg) -- schedule_in(rw_dtime, msg) -Schedules an event of type {type="schedule", schedule=true, msg=msg} at (resp. after) the specified railway time. -(which can be in any format). You can only schedule one event this way. (uses the new lines-internal scheduler) +- `schedule(rw_time, msg)` +- `schedule_in(rw_dtime, msg)` +Schedules the following event `{type="schedule", schedule=true, msg=msg}` at (resp. after) the specified railway time (which can be in any format). You can only schedule one event this way. Uses the new lines-internal scheduler. -## Components and events +#### Operator panel +This simple node executes its actions when punched. It can be used to change a switch and update the corresponding signals or similar applications. It can also be connected to by the`digilines` mod. -The event table is a table of the following format: -{ - type = "", - = true, - ... additional content ... -} -You can check for the event type by either using -if event.type == "wanted" then ...do stuff... end -or -if event.wanted then ...do stuff... end -(if 'wanted' is the event type to check for) +The event fired is `{type="punch", punch=true}` by default. In case of an interrupt or a digiline message, the events are similar to the ones of the ATC rail. -# Init code -The initialization code is not a component as such, but rather a part of the whole environment. It can (and should) be used to make definitions that other components can refer to. -Examples: -A function to define behavior for trains in subway stations: -function F.station() - if event.train then atc_send("B0WOL") end - if event.int and event.message="depart" then atc_send("OCD1SM") end +#### Init code +The initialization code is not a component as such, but rather a part of the whole environment. It can (and should) be used to make definitions that other components can refer to. +A basic example function to define behavior for trains in stations: +```lua +function F.station(station_name) + if event.train then + atc_send("B0WOL") + atc_set_text_inside(station_name) + interrupt(10,"depart") + end + if event.int and event.message="depart" then + atc_set_text_inside("") --an empty string clears the displayed text + atc_send("OCD1SM") + end end +```` + +The corresponding Lua ATC Rail(s) would then contain the following or similar: +````lua +F.station("Main Station") +```` The init code is run whenever the F table needs to be refilled with data. This is the case on server startup and whenever the init code is changed and you choose to run it. -Functions are run in the environment of the currently active node, regardless of where they were defined. So, the 'event' table always reflects the state of the calling node. - -The 'event' table of the init code is always {type="init", init=true}. - -# ATC rails -The Lua-controlled ATC rails are the only components that can actually interface with trains. The following event types are generated: - -{type="train", train=true, id=""} -This event is fired when a train enters the rail. The field 'id' is the unique train ID, which is 6-digit random numerical string. -If the world contains trains from an older advtrains version, this string may be longer and contain a dot (.) - -{type="int", int=true, msg=} -Fired when an interrupt set by the 'interrupt' function runs out. 'message' is the message passed to the interrupt function. -For backwards compatiblity reasons, is also contained in an event.message field. -{type="ext_int", ext_int=true, message=} -Fired when another node called 'interrupt_pos' on this position. 'message' is the message passed to the interrupt_pos function. - -{type="digiline", digiline=true, channel=, msg=} -Fired when the controller receives a digiline message. - -In addition to the default environment functions, the following functions are available: - -atc_send() - Sends the specified ATC command to the train and returns true. If there is no train, returns false and does nothing. -atc_reset() - Resets the train's current ATC command. If there is no train, returns false and does nothing. -atc_arrow - Boolean, true when the train is driving in the direction of the arrows of the ATC rail. Nil if there is no train. -atc_id - Train ID of the train currently passing the controller. Nil if there's no train. -atc_speed - Speed of the train, or nil if there is no train. -atc_set_text_outside(text) - Set text shown on the outside of the train. Pass nil to show no text. -atc_set_text_inside(text) - Set text shown to train passengers. Pass nil to show no text. -get_line() - Returns the "Line" property of the train (a string). - This can be used to distinguish between trains of different lines and route them appropriately. - The interlocking system also uses this property for Automatic Routesetting. -set_line(line) - Sets the "Line" property of the train (a string). - If the first digit of this string is a number (0-9), any subway wagons on the train will have this one displayed as line number - (where "0" is actually shown as Line 10 on the train) -get_rc() - Returns the "Routingcode" property of the train (a string). - The interlocking system uses this property for Automatic Routesetting. -set_rc(routingcode) - Sets the "Routingcode" property of the train (a string). - The interlocking system uses this property for Automatic Routesetting. -split_at_index(index, command) - Splits the train at the specified index, into a train with index-1 wagons and a second train starting with the index-th wagon. - command specifies an atc command to be sent to the second train after decoupling. -split_at_fc(command, len) - Splits the train in such a way that all cars with non-empty - current FC of the first part of the train have the same FC. The - command specified is sent to the rear part, as with - split_at_index. It returns the fc of the cars of the first part. - - The optional argument len specifies the maximum length for the - first part of the train. Say, we have len=3, and the train has "" - "" "foo" "foo" "foo" "bar", then the first train part will be "" - "" "foo". - - Example : Train has current FCs "" "" "foo" "bar" "foo" - Result: first train: "" "" "foo"; second train: "bar" "foo" - The command returns "foo" in this case -split_off_locomotive(command, len) - Splits off the locomotives at the front of the train, which are - identified by an empty FC. command specifies the command to be - executed by the rear half of the train. - - The optional argument len specifies the maximum length for the - first part of the train. Say, we have len=3, and the train has "" - "" "foo" "foo" "foo" "bar", then the first train part will be "" - "" "foo". -step_fc() - Steps the FCs of all train cars forward. FCs are composed of codes - separated by exclamation marks (!), for instance - "foo!bar!baz". Each wagon has a current FC, indicating its next - destination. Stepping the freight code forward, selects the next - code after the !. If the end of the string is reached, then the - first code is selected, except if the string ends with a question - mark, then the order is reversed. - -train_length() - returns the number of cars the train is composed of -set_autocouple() - Sets the train into autocouple mode -unset_autocouple() - Unsets autocouple mode - -set_shunt(), unset_shunt() - deprecated aliases for set_autocouple() and unset_autocouple(), will be removed from a later release. - - -# Operator panel -This simple node executes its actions when punched. It can be used to change a switch and update the corresponding signals or similar applications. - -The event fired is {type="punch", punch=true} by default. In case of an interrupt or a digiline message, the events are similar to the ones of the ATC rail. +The event table of the init code is always `{type="init", init=true}` and can not be anything else. +Functions are run in the environment of the currently active node, regardless of where they were defined. ### Passive components -All passive components can be interfaced with the setstate and getstate functions(see above). -Below, each apperance is mapped to the "state" of that node. +All passive components can be interfaced with the `setstate()` and `getstate()` functions (see above). +Each node below has been mapped to specific "states": -## Signals -The light signals are interfaceable, the analog signals are not. -"green" - Signal shows green light -"red" - Signal shows red light +#### Signals +The red/green light signals `advtrains:signal_on/off` are interfaceable. Others such as `advtrains:retrosignal_on/off` are not. If advtrains_interlocking is enabled, trains will obey the signal if the influence point is set. + - "green" - Signal shows green light + - "red" - Signal shows red light -## Switches -All default rail switches are interfaceable, independent of orientation. -"cr" - The switch is set in the direction that is not straight. -"st" - The switch is set in the direction that is straight. +#### Switches/Turnouts +All default rail switches are interfaceable, independent of orientation. + - "cr" The switch is set in the direction that is not straight. + - "st" The switch is set in the direction that is straight. -## Mesecon Switch -The Mesecon switch can be switched using LuaAutomation. Note that this is not possible on levers, only the full-node 'Switch' block. -"on" - the switch is switched on -"off" - the switch is switched off +The "Y" and "3-Way" switches have custom states. Looking from the convergence point: + - "l" The switch is set towards the left. + - "c" The switch is set towards the center (3-way only). + - "r" The switch is set towards the right. -##Andrew's Cross -"on" - it blinks -"off" - it does not blink -### Passive component naming +#### Mesecon Switch +The Mesecon switch can be switched using LuaAutomation. Note that this is not possible on levers or protected mesecon switches, only the unprotected full-node 'Switch' block `mesecons_switch:mesecon_switch_on/off`. + - "on" - the switch is switched on. + - "off" - the switch is switched off. + +#### Andrew's Cross + - "on" - it blinks. + - "off" - it does not blink. + +#### Passive Component Naming You can assign names to passive components using the Passive Component Naming tool. -Once you set a name for any component, you can reference it by that name in the getstate() and setstate() functions, like this: -(Imagine a signal that you have named "Stn_P1_out" at position (1,2,3) ) -setstate("Stn_P1_out", "green") instead of setstate(POS(1,2,3), "green") +Once you set a name for any component, you can reference it by that name in the `getstate()` and `setstate()` functions. This way, you don't need to memorize positions. -PC-Naming can also be used to name interlocking signals for route setting via the set_route() functions. IMPORTANT: The "Signal Name" set in the -signalling formspec is completely independent and can NOT be used to look up the position, you need to explicitly use the PCNaming tool. +Example: signal named `"Stn_P1_out"` at `(1,2,3)` +Use `setstate("Stn_P1_out", "green")` instead of `setstate(POS(1,2,3), "green")` + +If `advtrains_interlocking` is enabled, PC-Naming can also be used to name interlocking signals for route setting via the `set_route()` functions. +**Important**: The "Signal Name" field in the signalling formspec is completely independent from PC-Naming and can't be used to look up the position. You need to explicitly use the PC-Naming tool. --TODO: Ein paar mehr Codebeispiele wären schön, insbesondere mit os.date und so... diff --git a/mods/advtrains/advtrains_luaautomation/active_common.lua b/mods/advtrains/advtrains_luaautomation/active_common.lua index dac81b35..7db3eafc 100644 --- a/mods/advtrains/advtrains_luaautomation/active_common.lua +++ b/mods/advtrains/advtrains_luaautomation/active_common.lua @@ -101,7 +101,7 @@ function ac.run_in_env(pos, evtdata, customfct_p) end local meta - if minetest.get_node_or_nil(pos) then + if advtrains.is_node_loaded(pos) then meta=minetest.get_meta(pos) end @@ -125,7 +125,9 @@ function ac.run_in_env(pos, evtdata, customfct_p) if minetest.global_exists("digiline") then customfct.digiline_send=function(channel, msg) assertt(channel, "string") - digiline:receptor_send(pos, digiline.rules.default, channel, msg) + if advtrains.is_node_loaded(pos) then + digiline:receptor_send(pos, digiline.rules.default, channel, msg) + end end end -- add lines scheduler if enabled diff --git a/mods/advtrains/advtrains_train_track/init.lua b/mods/advtrains/advtrains_train_track/init.lua index 227bf02f..7f1f73c4 100644 --- a/mods/advtrains/advtrains_train_track/init.lua +++ b/mods/advtrains/advtrains_train_track/init.lua @@ -318,9 +318,14 @@ if mesecon then } }, advtrains = { + on_updated_from_nodedb = function(pos, node) + mesecon.receptor_off(pos, advtrains.meseconrules) + end, on_train_enter=function(pos, train_id) advtrains.ndb.swap_node(pos, {name="advtrains:dtrack_detector_on".."_"..suffix..rotation, param2=advtrains.ndb.get_node(pos).param2}) - mesecon.receptor_on(pos, advtrains.meseconrules) + if advtrains.is_node_loaded(pos) then + mesecon.receptor_on(pos, advtrains.meseconrules) + end end } } @@ -343,9 +348,14 @@ if mesecon then } }, advtrains = { + on_updated_from_nodedb = function(pos, node) + mesecon.receptor_on(pos, advtrains.meseconrules) + end, on_train_leave=function(pos, train_id) advtrains.ndb.swap_node(pos, {name="advtrains:dtrack_detector_off".."_"..suffix..rotation, param2=advtrains.ndb.get_node(pos).param2}) - mesecon.receptor_off(pos, advtrains.meseconrules) + if advtrains.is_node_loaded(pos) then + mesecon.receptor_off(pos, advtrains.meseconrules) + end end } } diff --git a/mods/builtin_item/init.lua b/mods/builtin_item/init.lua index d136fef9..4b1f7943 100644 --- a/mods/builtin_item/init.lua +++ b/mods/builtin_item/init.lua @@ -177,6 +177,7 @@ core.register_entity(":__builtin:item", { end local name1 = stack:get_meta():get_string("description") + local name if name1 == "" then name = core.registered_items[itemname].description @@ -194,7 +195,7 @@ core.register_entity(":__builtin:item", { automatic_rotate = 0.314 / size, wield_item = self.itemstring, glow = glow, - infotext = name..c1.."\n("..itemname..c2..")" + infotext = name .. c1 .. "\n(" .. itemname .. c2 .. ")" }) end, diff --git a/mods/mobs_redo/api.lua b/mods/mobs_redo/api.lua index 1d9e9afa..c1ea9693 100644 --- a/mods/mobs_redo/api.lua +++ b/mods/mobs_redo/api.lua @@ -8,7 +8,7 @@ local use_cmi = minetest.global_exists("cmi") mobs = { mod = "redo", - version = "20210114", + version = "20210206", intllib = S, invis = minetest.global_exists("invisibility") and invisibility or {} } @@ -539,12 +539,10 @@ local ray_line_of_sight = function(self, pos1, pos2) return true end --- detect if using minetest 5.0 by searching for permafrost node -local is_50 = minetest.registered_nodes["default:permafrost"] function mob_class:line_of_sight(pos1, pos2, stepsize) - if is_50 then -- only use if minetest 5.0 is detected + if minetest.raycast then -- only use if minetest 5.0 is detected return ray_line_of_sight(self, pos1, pos2) end @@ -1354,11 +1352,15 @@ function mob_class:breed() self.on_grown(self) else -- jump when fully grown so as not to fall into ground - self.object:set_velocity({ - x = 0, - y = self.jump_height, - z = 0 - }) +-- self.object:set_velocity({ +-- x = 0, +-- y = self.jump_height, +-- z = 0 +-- }) + local pos = self.object:get_pos() ; if not pos then return end + local ent = self.object:get_luaentity() + pos.y = pos.y + (ent.collisionbox[2] * -1) - 0.4 + self.object:set_pos(pos) end end @@ -1458,6 +1460,8 @@ function mob_class:breed() effect(pos, 15, "tnt_smoke.png", 1, 2, 2, 15, 5) end + pos.y = pos.y + 0.5 -- spawn child a little higher + local mob = minetest.add_entity(pos, self.name) local ent2 = mob:get_luaentity() local textures = self.base_texture diff --git a/mods/mobs_sky/mobs_bat/mod.conf b/mods/mobs_sky/mobs_bat/mod.conf index cf04dfa2..30bf1262 100644 --- a/mods/mobs_sky/mobs_bat/mod.conf +++ b/mods/mobs_sky/mobs_bat/mod.conf @@ -1,4 +1,4 @@ -name = mobs_sky +name = mobs_bat depends = default, mobs optional_depends = description = Adds bats into your world. diff --git a/mods/plantlife_modpack/woodsoils/nodes.lua b/mods/plantlife_modpack/woodsoils/nodes.lua index 6ece7e08..94dd2543 100644 --- a/mods/plantlife_modpack/woodsoils/nodes.lua +++ b/mods/plantlife_modpack/woodsoils/nodes.lua @@ -19,6 +19,11 @@ minetest.register_node("woodsoils:dirt_with_leaves_1", { sounds = default.node_sound_dirt_defaults({ footstep = {name="default_grass_footstep", gain=0.4}, }), + soil = { + base = "woodsoils:dirt_with_leaves_1", + dry = "farming:soil", + wet = "farming:soil_wet" + } }) minetest.register_node("woodsoils:dirt_with_leaves_2", { @@ -37,6 +42,11 @@ minetest.register_node("woodsoils:dirt_with_leaves_2", { sounds = default.node_sound_dirt_defaults({ footstep = {name="default_grass_footstep", gain=0.4}, }), + soil = { + base = "woodsoils:dirt_with_leaves_2", + dry = "farming:soil", + wet = "farming:soil_wet" + } }) minetest.register_node("woodsoils:grass_with_leaves_1", { @@ -55,6 +65,11 @@ minetest.register_node("woodsoils:grass_with_leaves_1", { sounds = default.node_sound_dirt_defaults({ footstep = {name="default_grass_footstep", gain=0.4}, }), + soil = { + base = "woodsoils:grass_with_leaves_1", + dry = "farming:soil", + wet = "farming:soil_wet" + } }) minetest.register_node("woodsoils:grass_with_leaves_2", { @@ -73,6 +88,11 @@ minetest.register_node("woodsoils:grass_with_leaves_2", { sounds = default.node_sound_dirt_defaults({ footstep = {name="default_grass_footstep", gain=0.4}, }), + soil = { + base = "woodsoils:grass_with_leaves_2", + dry = "farming:soil", + wet = "farming:soil_wet" + } }) -- For compatibility with older stuff diff --git a/mods/tubelib2/tube_api.lua b/mods/tubelib2/tube_api.lua index 003e7d9e..e9996e45 100644 --- a/mods/tubelib2/tube_api.lua +++ b/mods/tubelib2/tube_api.lua @@ -105,9 +105,9 @@ local function update1(self, pos, dir) end local function update2(self, pos1, dir1, pos2, dir2) - local fpos1,fdir1 = self:walk_tube_line(pos1, dir1) - local fpos2,fdir2 = self:walk_tube_line(pos2, dir2) - if not fdir1 or not fdir2 then -- line to long? + local fpos1,fdir1,cnt1 = self:walk_tube_line(pos1, dir1) + local fpos2,fdir2,cnt2 = self:walk_tube_line(pos2, dir2) + if cnt1 + cnt2 >= self.max_tube_length then -- line to long? -- reset next tube(s) to head tube(s) again local param2 = self:encode_param2(dir1, dir2, 2) self:update_after_dig_tube(pos1, param2) diff --git a/mods/tubelib2/tube_test.lua b/mods/tubelib2/tube_test.lua index aa520dcf..fc92a515 100644 --- a/mods/tubelib2/tube_test.lua +++ b/mods/tubelib2/tube_test.lua @@ -62,7 +62,7 @@ local Tube = tubelib2.Tube:new({ -- dirs_to_check = {1,2,3,4}, -- horizontal only -- dirs_to_check = {5,6}, -- vertical only dirs_to_check = {1,2,3,4,5,6}, - max_tube_length = 1000, + max_tube_length = 10, show_infotext = true, primary_node_names = {"tubelib2:tubeS", "tubelib2:tubeA"}, secondary_node_names = {"default:chest", "default:chest_open", @@ -385,18 +385,45 @@ local function remove_tube(itemstack, placer, pointed_thing) end end -local function walk(itemstack, placer, pointed_thing) +--local function walk(itemstack, placer, pointed_thing) +-- if pointed_thing.type == "node" then +-- local pos = pointed_thing.under +-- local dir = (minetest.dir_to_facedir(placer:get_look_dir()) % 4) + 1 +-- local t = minetest.get_us_time() +-- local pos1, outdir1, pos2, outdir2, cnt = Tube:walk(pos, dir) +-- t = minetest.get_us_time() - t +-- print("time", t) +-- if pos1 then +-- local s = "[Tubelib2] pos1="..P2S(pos1)..", outdir1="..outdir1..", pos2="..P2S(pos2)..", outdir2="..outdir2..", cnt="..cnt +-- minetest.chat_send_player(placer:get_player_name(), s) +-- end +-- else +-- local dir = (minetest.dir_to_facedir(placer:get_look_dir()) % 4) + 1 +-- minetest.chat_send_player(placer:get_player_name(), +-- "[Tool Help] dir="..dir.."\n".. +-- " left: remove node\n".. +-- " right: repair tube line\n") +-- end +--end + +local function repair_tube(itemstack, placer, pointed_thing) if pointed_thing.type == "node" then local pos = pointed_thing.under - local dir = (minetest.dir_to_facedir(placer:get_look_dir()) % 4) + 1 - local t = minetest.get_us_time() - local pos1, outdir1, pos2, outdir2, cnt = Tube:walk(pos, dir) - t = minetest.get_us_time() - t - print("time", t) - if pos1 then - local s = "[Tubelib2] pos1="..P2S(pos1)..", outdir1="..outdir1..", pos2="..P2S(pos2)..", outdir2="..outdir2..", cnt="..cnt + local _, _, fpos1, fpos2, _, _, cnt1, cnt2 = Tube:tool_repair_tube(pos) + local length = cnt1 + cnt2 + + local s = "Tube from " .. P2S(fpos1) .. " to " .. P2S(fpos2) .. ". Lenght = " .. length + minetest.chat_send_player(placer:get_player_name(), s) + + if length > Tube.max_tube_length then + local s = string.char(0x1b) .. "(c@#ff0000)" .. "Tube length error!" minetest.chat_send_player(placer:get_player_name(), s) end + + minetest.sound_play("carts_cart_new", { + pos = pos, + gain = 1, + max_hear_distance = 5}) else local dir = (minetest.dir_to_facedir(placer:get_look_dir()) % 4) + 1 minetest.chat_send_player(placer:get_player_name(), @@ -406,10 +433,6 @@ local function walk(itemstack, placer, pointed_thing) end end -local function debug(itemstack, placer, pointed_thing) - Tube:dbg_out() -end - -- Tool for tube workers to crack a protected tube line minetest.register_node("tubelib2:tool", { description = "Tubelib2 Tool", @@ -418,7 +441,7 @@ minetest.register_node("tubelib2:tool", { use_texture_alpha = true, groups = {cracky=1, book=1}, on_use = remove_tube, - on_place = debug, + on_place = repair_tube, node_placement_prediction = "", stack_max = 1, }) -- 2.25.1 From 9ecf1bb63f5ff3451467abe6c7a7fe21a25a2f47 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 8 Feb 2021 18:43:46 +0100 Subject: [PATCH 2/7] update --- reset-all-world.mt-regenerate-from-config-file | 3 +++ 1 file changed, 3 insertions(+) diff --git a/reset-all-world.mt-regenerate-from-config-file b/reset-all-world.mt-regenerate-from-config-file index 8e80c91a..2840a0b3 100644 --- a/reset-all-world.mt-regenerate-from-config-file +++ b/reset-all-world.mt-regenerate-from-config-file @@ -51,5 +51,8 @@ cp -r mods /home/minetest/.minetest/mods echo "Fix privileges on /home/minetest" chown minetest:minetest /home/minetest/ -cR +if [ -z "$1" ] +then echo "Start minetestsrv service" systemctl start minetestsrv +fi -- 2.25.1 From 34c8058b8a01bb29bc18b9544c062ba2806a953f Mon Sep 17 00:00:00 2001 From: root Date: Wed, 10 Feb 2021 09:40:32 +0100 Subject: [PATCH 3/7] update --- mods/mobs_animal/chicken.lua | 2 +- mods/stamina/init.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/mobs_animal/chicken.lua b/mods/mobs_animal/chicken.lua index ad552408..2c3b4484 100644 --- a/mods/mobs_animal/chicken.lua +++ b/mods/mobs_animal/chicken.lua @@ -81,7 +81,7 @@ stepheight = 0.6, return end - local pos = self.object:get_pos() + local pos = self.object:get_pos() ; if not pos then return end minetest.add_item(pos, "mobs:egg") diff --git a/mods/stamina/init.lua b/mods/stamina/init.lua index cdccd884..8678831a 100644 --- a/mods/stamina/init.lua +++ b/mods/stamina/init.lua @@ -405,13 +405,13 @@ local function stamina_globaltimer(dtime) local name = player:get_player_name() -- damage player by 1 hp if saturation is < 2 (of 30) - if h < STAMINA_STARVE_LVL + if h and h < STAMINA_STARVE_LVL and hp > 0 then player:set_hp(hp - STAMINA_STARVE, {hunger = true}) end -- don't heal if drowning or dead or poisoned - if h >= STAMINA_HEAL_LVL + if h and h >= STAMINA_HEAL_LVL and h >= hp and hp > 0 and air > 0 -- 2.25.1 From 033ffd868f1d88e4f2ee0593509395c63b0a4f9f Mon Sep 17 00:00:00 2001 From: root Date: Fri, 12 Feb 2021 17:08:38 +0100 Subject: [PATCH 4/7] update --- mods/moreblocks/circular_saw.lua | 3 ++- mods/protector/hud.lua | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mods/moreblocks/circular_saw.lua b/mods/moreblocks/circular_saw.lua index 174f344c..60231fc9 100644 --- a/mods/moreblocks/circular_saw.lua +++ b/mods/moreblocks/circular_saw.lua @@ -89,8 +89,9 @@ circular_saw.names = { } function circular_saw:get_cost(inv, stackname) + local name = minetest.registered_aliases[stackname] or stackname for i, item in pairs(inv:get_list("output")) do - if item:get_name() == stackname then + if item:get_name() == name then return circular_saw.cost_in_microblocks[i] end end diff --git a/mods/protector/hud.lua b/mods/protector/hud.lua index e33901e0..4a5d7112 100644 --- a/mods/protector/hud.lua +++ b/mods/protector/hud.lua @@ -1,13 +1,13 @@ local S = protector.intllib -local radius = (tonumber(minetest.setting_get("protector_radius")) or 5) +local radius = (tonumber(minetest.settings:get("protector_radius")) or 5) -- radius limiter (minetest cannot handle node volume of more than 4096000) if radius > 22 then radius = 22 end local hud = {} local hud_timer = 0 -local hud_interval = (tonumber(minetest.setting_get("protector_hud_interval")) or 5) +local hud_interval = (tonumber(minetest.settings:get("protector_hud_interval")) or 5) if hud_interval > 0 then minetest.register_globalstep(function(dtime) -- 2.25.1 From 067fadf85d34776f187fbba76269314f4d620bf5 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 15 Feb 2021 16:43:50 +0100 Subject: [PATCH 5/7] update --- mods/blox/init.lua | 14 +- mods/gloopblocks/depends.txt | 7 + mods/gloopblocks/init.lua | 940 +----------------- mods/gloopblocks/lava-handling.lua | 306 ++++++ mods/gloopblocks/main.lua | 839 ++++++++++++++++ .../models/gloopblocks_ash_pile.obj | 197 ++++ .../textures/gloopblocks_ashes.png | Bin 0 -> 564 bytes mods/skinsdb/meta/character_1948.txt | 3 + mods/skinsdb/textures/character_1948.png | Bin 0 -> 7276 bytes mods/techpack/gravelsieve/init.lua | 213 ++-- mods/vehicle_mash/README.md | 14 +- mods/vehicle_mash/framework.lua | 6 +- 12 files changed, 1531 insertions(+), 1008 deletions(-) create mode 100644 mods/gloopblocks/lava-handling.lua create mode 100644 mods/gloopblocks/main.lua create mode 100644 mods/gloopblocks/models/gloopblocks_ash_pile.obj create mode 100644 mods/gloopblocks/textures/gloopblocks_ashes.png create mode 100644 mods/skinsdb/meta/character_1948.txt create mode 100644 mods/skinsdb/textures/character_1948.png diff --git a/mods/blox/init.lua b/mods/blox/init.lua index 7515685d..5b6b67a7 100644 --- a/mods/blox/init.lua +++ b/mods/blox/init.lua @@ -113,7 +113,7 @@ for _, nodeclass in ipairs(NodeClass) do paramtype = "light", paramtype2 = "color", is_ground_content = true, - groups = {cracky=3, ud_param2_colorable = 1}, + groups = {cracky=3, stone=1, ud_param2_colorable = 1}, sounds = default.node_sound_stone_defaults(), on_construct = unifieddyes.on_construct, on_dig = unifieddyes.on_dig @@ -131,7 +131,7 @@ for _, nodeclass in ipairs(NodeClass) do paramtype = "light", paramtype2 = "color", is_ground_content = true, - groups = {cracky=3, ud_param2_colorable = 1}, + groups = {cracky=3, stone=2, ud_param2_colorable = 1}, sounds = default.node_sound_stone_defaults(), on_construct = unifieddyes.on_construct, on_dig = unifieddyes.on_dig @@ -149,7 +149,7 @@ for _, nodeclass in ipairs(NodeClass) do paramtype = "light", paramtype2 = "color", is_ground_content = true, - groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,flammable=3, ud_param2_colorable = 1}, + groups = {snappy=2, choppy=2, wood=1, oddly_breakable_by_hand=2,flammable=3, ud_param2_colorable = 1}, sounds = default.node_sound_wood_defaults(), on_construct = unifieddyes.on_construct, on_dig = unifieddyes.on_dig @@ -169,7 +169,7 @@ minetest.register_node("blox:wood_tinted", { paramtype = "light", paramtype2 = "color", is_ground_content = true, - groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,flammable=3, ud_param2_colorable = 1}, + groups = {snappy=2, choppy=2, wood=1, oddly_breakable_by_hand=2,flammable=3, ud_param2_colorable = 1}, sounds = default.node_sound_wood_defaults(), on_construct = unifieddyes.on_construct, on_dig = unifieddyes.on_dig @@ -182,7 +182,7 @@ minetest.register_node("blox:stone_square", { paramtype = "light", paramtype2 = "color", is_ground_content = true, - groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,flammable=3, ud_param2_colorable = 1}, + groups = {snappy=2, choppy=2, stone=1, oddly_breakable_by_hand=2,flammable=3, ud_param2_colorable = 1}, sounds = default.node_sound_wood_defaults(), on_construct = unifieddyes.on_construct, on_dig = unifieddyes.on_dig @@ -195,7 +195,7 @@ minetest.register_node("blox:cobble_tinted", { paramtype = "light", paramtype2 = "color", is_ground_content = true, - groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,flammable=3, not_in_creative_inventory = 1, ud_param2_colorable = 1}, + groups = {snappy=2, choppy=2, stone=2, oddly_breakable_by_hand=2,flammable=3, not_in_creative_inventory = 1, ud_param2_colorable = 1}, sounds = default.node_sound_wood_defaults(), on_construct = unifieddyes.on_construct, on_dig = unifieddyes.on_dig @@ -208,7 +208,7 @@ minetest.register_node("blox:stone_tinted", { paramtype = "light", paramtype2 = "color", is_ground_content = true, - groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,flammable=3, not_in_creative_inventory = 1, ud_param2_colorable = 1}, + groups = {snappy=2, choppy=2, stone=1, oddly_breakable_by_hand=2,flammable=3, not_in_creative_inventory = 1, ud_param2_colorable = 1}, sounds = default.node_sound_wood_defaults(), on_construct = unifieddyes.on_construct, on_dig = unifieddyes.on_dig, diff --git a/mods/gloopblocks/depends.txt b/mods/gloopblocks/depends.txt index 57849e5d..dfc42992 100644 --- a/mods/gloopblocks/depends.txt +++ b/mods/gloopblocks/depends.txt @@ -13,3 +13,10 @@ nyancat? usesdirt? worldedit? signs_lib? +bakedclay? +farming? +wool? +bushes_classic? +dryplants? +bedrock? +cottages? diff --git a/mods/gloopblocks/init.lua b/mods/gloopblocks/init.lua index 570235d0..7a220e45 100644 --- a/mods/gloopblocks/init.lua +++ b/mods/gloopblocks/init.lua @@ -12,942 +12,8 @@ gloopblocks = {} local MP = minetest.get_modpath(minetest.get_current_modname()) local S, NS = dofile(MP.."/intllib.lua") --- Nodes - -minetest.register_node("gloopblocks:rainbow_block_diagonal", { - description = S("Diagonal Rainbow Block"), - tiles = {"gloopblocks_rainbow_block.png"}, - is_ground_content = true, - groups = {cracky=3}, - sounds = default.node_sound_defaults(), -}) -minetest.register_alias("gloopblocks:rainbow_block", "gloopblocks:rainbow_block_diagonal") - -minetest.register_node("gloopblocks:rainbow_block_horizontal", { - description = S("Horizontal Rainbow Block"), - tiles = { - "gloopblocks_rainbow_horizontal.png^[transformR90", - "gloopblocks_rainbow_horizontal.png^[transformR90", - "gloopblocks_rainbow_horizontal.png" - }, - paramtype = "light", - light_source = default.LIGHT_MAX, - paramtype2 = "facedir", - groups = {cracky = 2}, - is_ground_content = false, - sounds = default.node_sound_defaults(), -}) - -minetest.register_node("gloopblocks:evil_block", { - description = S("Evil Block"), - tiles = {"gloopblocks_evil_block.png"}, - light_source = 5, - is_ground_content = true, - groups = {cracky=2}, - sounds = default.node_sound_stone_defaults(), -}) - -minetest.register_node("gloopblocks:basalt", { - description = S("Basalt"), - tiles = {"gloopblocks_basalt.png"}, - groups = {cracky=2}, - sounds = default.node_sound_stone_defaults(), -}) - -minetest.register_node("gloopblocks:pumice", { - description = S("Pumice"), - tiles = {"gloopblocks_pumice.png"}, - groups = {cracky=3}, - sounds = default.node_sound_stone_defaults(), -}) - - -minetest.register_node("gloopblocks:pavement", { - description = S("Pavement"), - tiles = {"gloopblocks_pavement.png"}, - groups = {cracky=3, oddly_breakable_by_hand=3}, - sounds = default.node_sound_stone_defaults(), -}) - -minetest.register_node("gloopblocks:oerkki_block", { - drawtype = "nodebox", - description = S("Oerkki Block"), - paramtype = "light", - paramtype2 = "facedir", - tiles = { - "gloopblocks_oerkkiblock_tb.png", - "gloopblocks_oerkkiblock_tb.png", - "gloopblocks_oerkkiblock_sides.png", - "gloopblocks_oerkkiblock_sides.png", - "gloopblocks_oerkkiblock_sides.png", - "gloopblocks_oerkkiblock_front.png" - }, - groups = {cracky=3, oddly_breakable_by_hand=3}, - sounds = default.node_sound_stone_defaults(), - selection_box = { - type = "fixed", - fixed = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } - }, - node_box = { - type = "fixed", - fixed = { - {-0.5, -0.5, -0.1875, 0.5, 0.5, 0.1875}, -- NodeBox1 - {-0.5, -0.5, -0.5, -0.4375, 0.5, 0.5}, -- NodeBox2 - {0.4375, -0.5, -0.5, 0.5, 0.5, 0.5}, -- NodeBox3 - {-0.5, 0.4375, -0.5, 0.5, 0.5, 0.5}, -- NodeBox4 - {-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5}, -- NodeBox5 - {-0.5, -0.0625, -0.5, 0.5, 0.0625, 0.5}, -- NodeBox6 - } - } -}) - -minetest.register_node("gloopblocks:stone_brick_mossy", { - description = S("Mossy Stone Brick"), - tiles = {"gloopblocks_stone_brick_mossy.png"}, - groups = {cracky=3, stone=1}, - sounds = default.node_sound_stone_defaults(), -}) - -minetest.register_node("gloopblocks:stone_mossy", { - description = S("Mossy Stone"), - tiles = {"gloopblocks_stone_mossy.png"}, - groups = {cracky=3, stone=1}, - sounds = default.node_sound_stone_defaults(), - drop = "default:mossycobble" -}) - -minetest.register_node("gloopblocks:cobble_road", { - description = S("Cobblestone Road Bed"), - tiles = {"gloopblocks_cobble_road.png"}, - groups = {cracky=3, stone=1}, - sounds = default.node_sound_stone_defaults(), -}) - -minetest.register_node("gloopblocks:cobble_road_mossy", { - description = S("Mossy Cobblestone Road Bed"), - tiles = {"gloopblocks_cobble_road_mossy.png"}, - groups = {cracky=3, stone=1}, - sounds = default.node_sound_stone_defaults(), -}) - -minetest.register_node("gloopblocks:scaffolding", { - description = S("Wooden Scaffold"), - drawtype = "allfaces", - paramtype = "light", - sunlight_propagates = true, - tiles = {"gloopblocks_scaffold.png"}, - groups = {choppy=3, oddly_breakable_by_hand=3}, - sounds = default.node_sound_wood_defaults(), -}) - -minetest.register_alias("moreblocks:oerkkiblock", "gloopblocks:oerkki_block") -minetest.register_alias("gloopblocks:obsidian", "default:obsidian") - --- Nodes imported from Usesdirt ================================================================================ - -if not minetest.get_modpath("usesdirt") then - - local dirt_brick_tex = "default_dirt.png^gloopblocks_dirt_brick_overlay.png" - local dirt_cobble_tex = "default_cobble.png^(default_dirt.png^[mask:gloopblocks_dirt_cobble_mask.png)" - local dirt_stone_tex = "default_stone.png^(default_dirt.png^[mask:gloopblocks_dirt_stone_mask.png)" - - local dirt_ladder_tex = "(default_dirt.png^[mask:gloopblocks_ladder_mask.png)^gloopblocks_ladder_overlay.png" - local dirt_brick_ladder_tex = "(("..dirt_brick_tex..")^[mask:gloopblocks_ladder_mask.png)^gloopblocks_ladder_overlay.png" - local dirt_cobble_ladder_tex = "(("..dirt_cobble_tex..")^[mask:gloopblocks_ladder_mask.png)^gloopblocks_ladder_overlay.png" - local dirt_stone_ladder_tex = "(("..dirt_stone_tex..")^[mask:gloopblocks_ladder_mask.png)^gloopblocks_ladder_overlay.png" - - minetest.register_node(":usesdirt:dirt_brick", { - tiles = { dirt_brick_tex }, - description = "Dirt Brick", - groups = {snappy=2,choppy=1,oddly_breakable_by_hand=2}, - }) - - minetest.register_node(":usesdirt:dirt_brick_ladder", { - description = "Dirt Brick Ladder", - drawtype = "signlike", - tiles = { dirt_brick_ladder_tex }, - inventory_image = dirt_brick_ladder_tex, - wield_image = dirt_brick_ladder_tex, - paramtype = "light", - paramtype2 = "wallmounted", - is_ground_content = true, - walkable = false, - climbable = true, - selection_box = { - type = "wallmounted", - --wall_top = = - --wall_bottom = = - --wall_side = = - }, - groups = {cracky=3, stone=2}, - legacy_wallmounted = true, - }) - minetest.register_craft({ - output = 'usesdirt:dirt_brick_ladder 3', - recipe = { - {'usesdirt:dirt_brick', '', 'usesdirt:dirt_brick'}, - {'usesdirt:dirt_brick', 'usesdirt:dirt_brick','usesdirt:dirt_brick'}, - {'usesdirt:dirt_brick','','usesdirt:dirt_brick'}, - } - }) - - default.register_fence(":usesdirt:dirt_brick_fence", { - description = "Dirt Brick Fence", - texture = dirt_brick_tex, - inventory_image = "default_fence_overlay.png^("..dirt_brick_tex..")^default_fence_overlay.png^[makealpha:255,126,126", - wield_image = "default_fence_overlay.png^("..dirt_brick_tex..")^default_fence_overlay.png^[makealpha:255,126,126", - material = "usesdirt:dirt_brick", - groups = {cracky=3, stone=2}, - sounds = default.node_sound_stone_defaults(), - check_for_pole = true - }) - - if minetest.get_modpath("moreblocks") then - minetest.register_craft({ - output = 'usesdirt:dirt_brick 24', - recipe = { - {'moreblocks:dirt_compressed', 'moreblocks:dirt_compressed', '' }, - {'moreblocks:dirt_compressed', 'moreblocks:dirt_compressed', '' } - } - }) - else - minetest.register_craft({ - output = 'usesdirt:dirt_brick 6', - recipe = { - {'default:dirt', 'default:dirt', 'default:dirt'}, - {'default:dirt', 'default:dirt', 'default:dirt'}, - {'default:dirt', 'default:dirt', 'default:dirt'}, - } - }) - end - - minetest.register_node(":usesdirt:dirt_ladder", { - description = "Dirt Ladder", - drawtype = "signlike", - tiles = { dirt_ladder_tex }, - inventory_image = dirt_ladder_tex, - wield_image = dirt_ladder_tex, - paramtype = "light", - paramtype2 = "wallmounted", - is_ground_content = true, - walkable = false, - climbable = true, - selection_box = { - type = "wallmounted", - --wall_top = = - --wall_bottom = = - --wall_side = = - }, - groups = {snappy=2,choppy=2,oddly_breakable_by_hand=3}, - legacy_wallmounted = true, - }) - minetest.register_craft({ - output = 'usesdirt:dirt_ladder 3', - recipe = { - {'usesdirt:dirt_brick', '', 'usesdirt:dirt_brick'}, - {'usesdirt:dirt_brick', 'usesdirt:dirt_brick','usesdirt:dirt_brick'}, - {'usesdirt:dirt_brick','','usesdirt:dirt_brick'}, - } - }) - - default.register_fence(":usesdirt:dirt_fence", { - description = "Dirt Fence", - texture = "default_dirt.png", - inventory_image = "default_fence_overlay.png^default_dirt.png^default_fence_overlay.png^[makealpha:255,126,126", - wield_image = "default_fence_overlay.png^default_dirt.png^default_fence_overlay.png^[makealpha:255,126,126", - material = "default:dirt", - groups = {snappy=2,choppy=1,oddly_breakable_by_hand=3}, - sounds = default.node_sound_dirt_defaults(), - check_for_pole = true - }) - ----- - - minetest.register_node(":usesdirt:dirt_cobble_stone", { - tiles = { dirt_cobble_tex }, - description = "Dirt Cobble Stone", - is_ground_content = true, - groups = {cracky=3, stone=2}, - }) - minetest.register_craft({ - output = '"usesdirt:dirt_cobble_stone" 3', - recipe = { - {'usesdirt:dirt_brick', 'usesdirt:dirt_brick', 'usesdirt:dirt_brick'}, - {'usesdirt:dirt_brick', 'usesdirt:dirt_brick', 'usesdirt:dirt_brick'}, - {'usesdirt:dirt_brick', 'usesdirt:dirt_brick', 'usesdirt:dirt_brick'}, - } - }) - - minetest.register_node(":usesdirt:dirt_cobble_stone_ladder", { - description = "Dirt Cobble Stone Ladder", - drawtype = "signlike", - tiles = { dirt_cobble_ladder_tex }, - inventory_image = dirt_cobble_ladder_tex, - wield_image = dirt_cobble_ladder_tex, - paramtype = "light", - paramtype2 = "wallmounted", - is_ground_content = true, - walkable = false, - climbable = true, - selection_box = { - type = "wallmounted", - --wall_top = = - --wall_bottom = = - --wall_side = = - }, - groups = {cracky=3, stone=2}, - legacy_wallmounted = true, - }) - minetest.register_craft({ - output = 'usesdirt:dirt_cobble_stone_ladder 3', - recipe = { - {'usesdirt:dirt_cobble_stone', '', 'usesdirt:dirt_cobble_stone'}, - {'usesdirt:dirt_cobble_stone', 'usesdirt:dirt_cobble_stone','usesdirt:dirt_cobble_stone'}, - {'usesdirt:dirt_cobble_stone','','usesdirt:dirt_cobble_stone'}, - } - }) - - default.register_fence(":usesdirt:dirt_cobble_stone_fence", { - description = "Dirt Cobble Stone Fence", - texture = dirt_cobble_tex, - inventory_image = "default_fence_overlay.png^("..dirt_cobble_tex..")^default_fence_overlay.png^[makealpha:255,126,126", - wield_image = "default_fence_overlay.png^("..dirt_cobble_tex..")^default_fence_overlay.png^[makealpha:255,126,126", - material = "usesdirt:dirt_cobble_stone", - groups = {cracky=3, stone=2}, - sounds = default.node_sound_stone_defaults(), - check_for_pole = true - }) - ----- - - minetest.register_node(":usesdirt:dirt_stone", { - tiles = { dirt_stone_tex }, - description = "Dirt Stone", - is_ground_content = true, - groups = {cracky=3, stone=2}, - }) - - minetest.register_node(":usesdirt:dirt_stone_ladder", { - description = "Dirt Stone Ladder", - drawtype = "signlike", - tiles = { dirt_stone_ladder_tex }, - inventory_image = dirt_stone_ladder_tex, - wield_image = dirt_stone_ladder_tex, - paramtype = "light", - paramtype2 = "wallmounted", - is_ground_content = true, - walkable = false, - climbable = true, - selection_box = { - type = "wallmounted", - --wall_top = = - --wall_bottom = = - --wall_side = = - }, - groups = {cracky=3, stone=2}, - legacy_wallmounted = true, - }) - minetest.register_craft({ - output = 'usesdirt:dirt_stone_ladder 3', - recipe = { - {'usesdirt:dirt_stone', '', 'usesdirt:dirt_stone'}, - {'usesdirt:dirt_stone', 'usesdirt:dirt_stone','usesdirt:dirt_stone'}, - {'usesdirt:dirt_stone','','usesdirt:dirt_stone'}, - } - }) - - default.register_fence(":usesdirt:dirt_stone_fence", { - description = "Dirt Stone Fence", - texture = dirt_stone_tex, - inventory_image = "default_fence_overlay.png^("..dirt_stone_tex..")^default_fence_overlay.png^[makealpha:255,126,126", - wield_image = "default_fence_overlay.png^("..dirt_stone_tex..")^default_fence_overlay.png^[makealpha:255,126,126", - material = "usesdirt:dirt_stone", - groups = {cracky=3, stone=2}, - sounds = default.node_sound_stone_defaults(), - check_for_pole = true - }) -end - --- Stairs/slabs defs, conversion of normal -> mossy items - -if minetest.setting_getbool("gloopblocks_mossy_conversion") ~= false then - - function gloopblocks_register_mossy_conversion(mossyobjects) - for i in ipairs(mossyobjects) do - minetest.register_abm({ - nodenames = { mossyobjects[i][1] }, - neighbors = {"default:water_source", "default:water_flowing"}, - interval = 120, - chance = 50, - action = function(pos, node) - if minetest.find_node_near(pos, 2, "air") then - local fdir = node.param2 - minetest.add_node(pos, {name = mossyobjects[i][2], param2 = fdir}) - end - end, - }) - end - end -end - -if minetest.get_modpath("moreblocks") then - - stairsplus:register_all("gloopblocks", "oerkki_block", "gloopblocks:oerkki_block", { - description = S("Oerkki Block"), - tiles = { - "gloopblocks_oerkkiblock_tb.png", - "gloopblocks_oerkkiblock_tb.png", - "gloopblocks_oerkkiblock_sides.png", - "gloopblocks_oerkkiblock_sides.png", - "gloopblocks_oerkkiblock_sides.png", - "gloopblocks_oerkkiblock_front.png" - }, - groups = {cracky=2, not_in_creative_inventory=1}, - sounds = default.node_sound_stone_defaults(), - sunlight_propagates = true, - }) - - stairsplus:register_all("gloopblocks", "stone_brick_mossy", "gloopblocks:stone_brick_mossy", { - description = S("Mossy Stone Brick"), - tiles = {"gloopblocks_stone_brick_mossy.png"}, - groups = {cracky=1, not_in_creative_inventory=1}, - sounds = default.node_sound_stone_defaults(), - sunlight_propagates = true, - }) - - stairsplus:register_all("gloopblocks", "stone_mossy", "gloopblocks:stone_mossy", { - description = S("Mossy Stone"), - tiles = {"gloopblocks_stone_mossy.png"}, - groups = {cracky=1, not_in_creative_inventory=1}, - sounds = default.node_sound_stone_defaults(), - sunlight_propagates = true, - }) - - stairsplus:register_all("gloopblocks", "cobble_road", "gloopblocks:cobble_road", { - description = S("Cobblestone Roadbed"), - tiles = {"gloopblocks_cobble_road.png"}, - groups = {cracky=3, stone=1, not_in_creative_inventory=1}, - sounds = default.node_sound_stone_defaults(), - sunlight_propagates = true, - }) - - stairsplus:register_all("gloopblocks", "cobble_road_mossy", "gloopblocks:cobble_road_mossy", { - description = S("Mossy Cobblestone Roadbed"), - tiles = {"gloopblocks_cobble_road_mossy.png"}, - groups = {cracky=3, stone=1, not_in_creative_inventory=1}, - sounds = default.node_sound_stone_defaults(), - sunlight_propagates = true, - }) - - stairsplus:register_all("gloopblocks", "pavement", "gloopblocks:pavement", { - description = S("Pavement"), - tiles = {"gloopblocks_pavement.png"}, - groups = {cracky=2, not_in_creative_inventory=1}, - sounds = default.node_sound_stone_defaults(), - sunlight_propagates = true, - }) - - stairsplus:register_all("gloopblocks", "rainbow_block", "gloopblocks:rainbow_block", { - description = S("Rainbow Block"), - tiles = {"gloopblocks_rainbow_block.png"}, - groups = {cracky=3, not_in_creative_inventory=1}, - sounds = default.node_sound_defaults(), - sunlight_propagates = true, - }) - - stairsplus:register_all("gloopblocks", "evil_block", "gloopblocks:evil_block", { - description = S("Evil Block"), - tiles = {"gloopblocks_evil_block.png"}, - groups = {cracky=3, not_in_creative_inventory=1}, - sounds = default.node_sound_defaults(), - light_source = 5, - sunlight_propagates = true, - }) - - stairsplus:register_all("gloopblocks", "basalt", "gloopblocks:basalt", { - description = S("Basalt"), - tiles = {"gloopblocks_basalt.png"}, - groups = {cracky=2, not_in_creative_inventory=1}, - sounds = default.node_sound_stone_defaults(), - sunlight_propagates = true, - }) - - stairsplus:register_all("gloopblocks", "pumice", "gloopblocks:pumice", { - description = S("Pumice"), - tiles = {"gloopblocks_pumice.png"}, - groups = {cracky=3, not_in_creative_inventory=1}, - sounds = default.node_sound_stone_defaults(), - sunlight_propagates = true, - }) - - stairsplus:register_all("gloopblocks", "gravel", "default:gravel", { - description = S("Gravel"), - tiles = {"default_gravel.png"}, - groups = {crumbly = 2, falling_node = 1, not_in_creative_inventory=1}, - sounds = default.node_sound_stone_defaults(), - sunlight_propagates = false, - }) - - if minetest.get_modpath("caverealms") then - stairsplus:register_all("caverealms", "glow_crystal", "caverealms:glow_crystal", { - description = S("Glow Crystal"), - tiles = {"caverealms_glow_crystal.png"}, - groups = {cracky=3, not_in_creative_inventory=1}, - sounds = default.node_sound_glass_defaults(), - light_source = 12, - use_texture_alpha = true, - paramtype="light", - sunlight_propagates = true, - }) - - stairsplus:register_all("caverealms", "glow_emerald", "caverealms:glow_emerald", { - description = S("Glow Emerald"), - tiles = {"caverealms_glow_emerald.png"}, - groups = {cracky=3, not_in_creative_inventory=1}, - sounds = default.node_sound_glass_defaults(), - light_source = 12, - use_texture_alpha = true, - paramtype="light", - sunlight_propagates = true, - }) - - stairsplus:register_all("caverealms", "glow_mese", "caverealms:glow_mese", { - description = S("Glow Mese"), - tiles = {"caverealms_glow_mese.png"}, - groups = {cracky=3, not_in_creative_inventory=1}, - sounds = default.node_sound_glass_defaults(), - light_source = 12, - use_texture_alpha = true, - paramtype="light", - sunlight_propagates = true, - }) - end - - -- ABMs for mossy objects - - if minetest.setting_getbool("gloopblocks_mossy_conversion") ~= false then - - gloopblocks_register_mossy_conversion({ - { "moreblocks:stair_cobble", "moreblocks:stair_mossycobble" }, - { "moreblocks:stair_cobble_inner", "moreblocks:stair_mossycobble_inner" }, - { "moreblocks:stair_cobble_outer", "moreblocks:stair_mossycobble_outer" }, - { "moreblocks:stair_cobble_half", "moreblocks:stair_mossycobble_half" }, - { "moreblocks:slab_cobble_quarter", "moreblocks:slab_mossycobble_quarter" }, - { "moreblocks:slab_cobble", "moreblocks:slab_mossycobble" }, - { "moreblocks:slab_cobble_three_quarter", "moreblocks:slab_mossycobble_three_quarter" }, - { "moreblocks:panel_cobble", "moreblocks:panel_mossycobble" }, - { "moreblocks:micro_cobble", "moreblocks:micro_mossycobble" }, - { "moreblocks:stair_cobble_alt", "moreblocks:stair_mossycobble_alt" }, - - { "gloopblocks:cobble_road", "gloopblocks:cobble_road_mossy" }, - { "gloopblocks:stair_cobble_road", "gloopblocks:stair_cobble_road_mossy" }, - { "gloopblocks:slab_cobble_road", "gloopblocks:slab_cobble_road_mossy" }, - { "gloopblocks:stair_cobble_road", "gloopblocks:stair_cobble_road_mossy" }, - { "gloopblocks:stair_cobble_road_inner", "gloopblocks:stair_cobble_road_mossy_inner" }, - { "gloopblocks:stair_cobble_road_outer", "gloopblocks:stair_cobble_road_mossy_outer" }, - { "gloopblocks:stair_cobble_road_half", "gloopblocks:stair_cobble_road_mossy_half" }, - { "gloopblocks:slab_cobble_road_quarter", "gloopblocks:slab_cobble_road_mossy_quarter" }, - { "gloopblocks:slab_cobble_road", "gloopblocks:slab_cobble_road_mossy" }, - { "gloopblocks:slab_cobble_road_three_quarter", "gloopblocks:slab_cobble_road_mossy_three_quarter" }, - { "gloopblocks:panel_cobble_road", "gloopblocks:panel_cobble_road_mossy" }, - { "gloopblocks:micro_cobble_road", "gloopblocks:micro_cobble_road_mossy" }, - { "gloopblocks:stair_cobble_road_alt", "gloopblocks:stair_cobble_road_mossy_alt" }, - - { "default:stonebrick", "gloopblocks:stone_brick_mossy" }, - { "default:stair_stonebrick", "gloopblocks:stair_stone_brick_mossy" }, - { "default:slab_stonebrick", "gloopblocks:slab_stone_brick_mossy" }, - { "moreblocks:stair_stonebrick", "gloopblocks:stair_stone_brick_mossy" }, - { "moreblocks:stair_stonebrick_inner", "gloopblocks:stair_stone_brick_mossy_inner" }, - { "moreblocks:stair_stonebrick_outer", "gloopblocks:stair_stone_brick_mossy_outer" }, - { "moreblocks:stair_stonebrick_half", "gloopblocks:stair_stone_brick_mossy_half" }, - { "moreblocks:slab_stonebrick_quarter", "gloopblocks:slab_stone_brick_mossy_quarter" }, - { "moreblocks:slab_stonebrick", "gloopblocks:slab_stone_brick_mossy" }, - { "moreblocks:slab_stonebrick_three_quarter", "gloopblocks:slab_stone_brick_mossy_three_quarter" }, - { "moreblocks:panel_stonebrick", "gloopblocks:panel_stone_brick_mossy" }, - { "moreblocks:micro_stonebrick", "gloopblocks:micro_stone_brick_mossy" }, - { "moreblocks:stair_stonebrick_alt", "gloopblocks:stair_stone_brick_mossy_alt" }, - - { "default:stone", "gloopblocks:stone_mossy" }, - { "default:stair_stone", "gloopblocks:stair_stone_mossy" }, - { "default:slab_stone", "gloopblocks:slab_stone_mossy" }, - { "moreblocks:stair_stone", "gloopblocks:stair_stone_mossy" }, - { "moreblocks:stair_stone_inner", "gloopblocks:stair_stone_mossy_inner" }, - { "moreblocks:stair_stone_outer", "gloopblocks:stair_stone_mossy_outer" }, - { "moreblocks:stair_stone_half", "gloopblocks:stair_stone_mossy_half" }, - - { "moreblocks:slab_stone_quarter", "gloopblocks:slab_stone_mossy_quarter" }, - { "moreblocks:slab_stone", "gloopblocks:slab_stone_mossy" }, - { "moreblocks:slab_stone_three_quarter", "gloopblocks:slab_stone_mossy_three_quarter" }, - { "moreblocks:panel_stone", "gloopblocks:panel_stone_mossy" }, - { "moreblocks:micro_stone", "gloopblocks:micro_stone_mossy" }, - { "moreblocks:stair_stone_alt", "gloopblocks:stair_stone_mossy_alt" }, - }) - end - -elseif minetest.get_modpath("stairs") then - - --stairs.register_stair(subname, recipeitem, groups, images, description, sounds) - - -- stairs:xxxx_stone_mossy ; xxxx = stair or slab - stairs.register_stair_and_slab("stone_mossy", "gloopblocks:stone_mossy", - {cracky=3}, - {"gloopblocks_stone_mossy.png"}, - S("Mossy Stone Stair"), - S("Mossy Stone Slab"), - default.node_sound_stone_defaults()) - - -- stairs:xxxx_mossycobble - stairs.register_stair_and_slab("mossycobble", "default:mossycobble", - {cracky=3}, - {"default_mossycobble.png"}, - S("Mossy Cobble Stair"), - S("Mossy Cobble Slab"), - default.node_sound_stone_defaults()) - - -- stairs:xxxx_stone_brick_mossy - stairs.register_stair_and_slab("stone_brick_mossy", "gloopblocks:stone_brick_mossy", - {cracky=3}, - {"gloopblocks_stone_brick_mossy.png"}, - S("Mossy Stone Brick Stair"), - S("Mossy Stone Brick Slab"), - default.node_sound_stone_defaults()) - - -- stairs:xxxx_cobble_road - stairs.register_stair_and_slab("cobble_road", "gloopblocks:cobble_road", - {cracky=3}, - {"gloopblocks_cobble_road.png"}, - S("Cobble Roadbed Stair"), - S("Cobble Roadbed Slab"), - default.node_sound_stone_defaults()) - - -- stairs:xxxx_cobble_road_mossy - stairs.register_stair_and_slab("cobble_road_mossy", "gloopblocks:cobble_road_mossy", - {cracky=3}, - {"gloopblocks_cobble_road_mossy.png"}, - S("Mossy Cobble Roadbed Stair"), - S("Mossy Cobble Roadbed Slab"), - default.node_sound_stone_defaults()) - - -- stairs:xxxx_cement - stairs.register_stair_and_slab("cement", "gloopblocks:cement", - {cracky=2}, - {"basic_materials_cement_block.png"}, - S("Cement Stair"), - S("Cement Slab"), - default.node_sound_stone_defaults()) - - -- stairs:xxxx_pavement - stairs.register_stair_and_slab("pavement", "gloopblocks:pavement", - {cracky=3, oddly_breakable_by_hand=3}, - {"gloopblocks_pavement.png"}, - S("Pavement Stair"), - S("Pavement Slab"), - default.node_sound_stone_defaults()) - - stairs.register_stair_and_slab("basalt", "gloopblocks:basalt", - {cracky=2}, - {"gloopblocks_basalt.png"}, - S("Basalt Stair"), - S("Basalt Slab"), - default.node_sound_stone_defaults()) - - stairs.register_stair_and_slab("pumice", "gloopblocks:pumice", - {cracky=3}, - {"gloopblocks_pumice.png"}, - S("Pumice Stair"), - S("Pumice Slab"), - default.node_sound_stone_defaults()) - - stairs.register_stair_and_slab("rainbow_block", "gloopblocks:rainbow_block", - {cracky=3}, - {"gloopblocks_rainbow_block.png"}, - S("Rainbow Block Stair"), - S("Rainbow Block Slab"), - default.node_sound_defaults()) - - if minetest.setting_getbool("gloopblocks_mossy_conversion") ~= false then - - gloopblocks_register_mossy_conversion({ - { "default:cobble", "default:mossycobble" }, - { "stairs:stair_cobble", "stairs:stair_mossycobble" }, - { "stairs:slab_cobble", "stairs:slab_mossycobble" }, - { "gloopblocks:cobble_road", "gloopblocks:cobble_road_mossy" }, - { "stairs:stair_cobble_road", "stairs:stair_cobble_road_mossy" }, - { "stairs:slab_cobble_road", "stairs:slab_cobble_road_mossy" }, - { "default:stonebrick", "gloopblocks:stone_brick_mossy" }, - { "stairs:stair_stonebrick", "stairs:stair_stone_brick_mossy" }, - { "stairs:slab_stonebrick", "stairs:slab_stone_brick_mossy" }, - { "default:stone", "gloopblocks:stone_mossy" }, - { "stairs:stair_stone", "stairs:stair_stone_mossy" }, - { "stairs:slab_stone", "stairs:slab_stone_mossy" }, - }) - end - - minetest.register_alias("default:stair_mossycobble", "stairs:stair_mossycobble") - minetest.register_alias("default:slab_mossycobble", "stairs:slab_mossycobble") - minetest.register_alias("gloopblocks:stair_cobble_road", "stairs:stair_cobble_road") - minetest.register_alias("gloopblocks:slab_cobble_road", "stairs:slab_cobble_road") - minetest.register_alias("gloopblocks:stair_cobble_road_mossy", "stairs:stair_cobble_road_mossy") - minetest.register_alias("gloopblocks:slab_cobble_road_mossy", "stairs:slab_cobble_road_mossy") - minetest.register_alias("gloopblocks:stair_stone_brick_mossy", "stairs:stair_stone_brick_mossy") - minetest.register_alias("gloopblocks:slab_stone_brick_mossy", "stairs:slab_stone_brick_mossy") - minetest.register_alias("gloopblocks:stair_stone_mossy", "stairs:stair_stone_mossy") - minetest.register_alias("gloopblocks:slab_stone_mossy", "stairs:slab_stone_mossy") - minetest.register_alias("gloopblocks:stair_cement", "stairs:stair_cement") - minetest.register_alias("gloopblocks:slab_cement", "stairs:slab_cement") - minetest.register_alias("gloopblocks:stair_pavement", "stairs:stair_pavement") - minetest.register_alias("gloopblocks:slab_pavement", "stairs:slab_pavement") - minetest.register_alias("gloopblocks:stair_pumice", "stairs:stair_pumice") - minetest.register_alias("gloopblocks:slab_pumice", "stairs:slab_pumice") - minetest.register_alias("gloopblocks:stair_basalt", "stairs:stair_basalt") - minetest.register_alias("gloopblocks:slab_basalt", "stairs:slab_basalt") - minetest.register_alias("gloopblocks:stair_rainbow_block", "stairs:stair_rainbow_block") - minetest.register_alias("gloopblocks:slab_rainbow_block", "stairs:slab_rainbow_block") -end - --- Tools - -minetest.register_tool("gloopblocks:pick_cement", { - description = S("Cement Pickaxe"), - inventory_image = "gloopblocks_cement_pick.png", - tool_capabilities = { - full_punch_interval = 1.0, - max_drop_level=1, - groupcaps={ - cracky={times={[1]=3.50, [2]=1.40, [3]=0.90}, uses=25, maxlevel=2} - }, - damage_groups = {fleshy=4}, - }, -}) - -minetest.register_tool("gloopblocks:shovel_cement", { - description = S("Cement Shovel"), - inventory_image = "gloopblocks_cement_shovel.png", - tool_capabilities = { - full_punch_interval = 1.0, - max_drop_level=1, - groupcaps={ - crumbly={times={[1]=1.50, [2]=0.60, [3]=0.45}, uses=25, maxlevel=2} - }, - damage_groups = {fleshy=4}, - }, -}) - -minetest.register_tool("gloopblocks:axe_cement", { - description = S("Cement Axe"), - inventory_image = "gloopblocks_cement_axe.png", - tool_capabilities = { - full_punch_interval = 1.0, - max_drop_level=1, - groupcaps={ - choppy={times={[1]=3.00, [2]=1.30, [3]=0.80}, uses=25, maxlevel=2}, - fleshy={times={[2]=1.20, [3]=0.65}, uses=30, maxlevel=1} - }, - damage_groups = {fleshy=4}, - }, -}) - -minetest.register_tool("gloopblocks:sword_cement", { - description = S("Cement Sword"), - inventory_image = "gloopblocks_cement_sword.png", - tool_capabilities = { - full_punch_interval = 1.0, - max_drop_level=1, - groupcaps={ - fleshy={times={[1]=1.60, [2]=0.80, [3]=0.40}, uses=15, maxlevel=2}, - snappy={times={[2]=0.75, [3]=0.35}, uses=30, maxlevel=1}, - choppy={times={[3]=0.80}, uses=30, maxlevel=0} - }, - damage_groups = {fleshy=6}, - } -}) - -minetest.register_tool("gloopblocks:pick_evil", { - description = S("Evil Pickaxe"), - inventory_image = "gloopblocks_evil_pick.png", - tool_capabilities = { - full_punch_interval = 1.0, - max_drop_level=3, - groupcaps={ - cracky={times={[1]=0.10, [2]=0.10, [3]=0.10}, uses=10, maxlevel=2} - }, - damage_groups = {fleshy=6}, - }, -}) - -minetest.register_tool("gloopblocks:shovel_evil", { - description = S("Evil Shovel"), - inventory_image = "gloopblocks_evil_shovel.png", - tool_capabilities = { - full_punch_interval = 1.0, - max_drop_level=3, - groupcaps={ - crumbly={times={[1]=0.05, [2]=0.05, [3]=0.05}, uses=10, maxlevel=2} - }, - damage_groups = {fleshy=6}, - }, -}) - -minetest.register_tool("gloopblocks:axe_evil", { - description = S("Evil Axe"), - inventory_image = "gloopblocks_evil_axe.png", - tool_capabilities = { - full_punch_interval = 1.0, - max_drop_level=3, - groupcaps={ - choppy={times={[1]=0.15, [2]=0.15, [3]=0.15}, uses=10, maxlevel=2}, - fleshy={times={[1]=0.15, [2]=0.15, [3]=0.15}, uses=10, maxlevel=2} - }, - damage_groups = {fleshy=6}, - }, -}) - -minetest.register_tool("gloopblocks:sword_evil", { - description = S("Evil Sword"), - inventory_image = "gloopblocks_evil_sword.png", - tool_capabilities = { - full_punch_interval = 1.0, - max_drop_level=3, - groupcaps={ - fleshy={times={[1]=0.20, [2]=0.20, [3]=0.20}, uses=10, maxlevel=2}, - snappy={times={[1]=0.20, [2]=0.20, [3]=0.20}, uses=10, maxlevel=2}, - choppy={times={[1]=0.20, [2]=0.20, [3]=0.20}, uses=10, maxlevel=2} - }, - damage_groups = {fleshy=8}, - } -}) - --- Other items - -minetest.register_craftitem("gloopblocks:evil_stick", { - description = S("Evil Stick"), - inventory_image = "gloopblocks_evil_stick.png", -}) - --- define lava-cooling-based nodes and hook into the default lavacooling --- functions to generate basalt, pumice, and obsidian - -if minetest.setting_getbool("gloopblocks_lavacooling") ~= false then - - minetest.register_node("gloopblocks:obsidian_cooled", { - description = S("Obsidian"), - tiles = {"default_obsidian.png"}, - is_ground_content = true, - sounds = default.node_sound_stone_defaults(), - groups = {cracky=1, level=2, not_in_creative_inventory=1}, - drop = "default:obsidian", - after_place_node = function(pos, placer, itemstack, pointed_thing) - minetest.add_node(pos, {name = "default:obsidian"}) - end - }) - - minetest.register_node("gloopblocks:basalt_cooled", { - description = S("Basalt"), - tiles = {"gloopblocks_basalt.png"}, - groups = {cracky=2, not_in_creative_inventory=1}, - sounds = default.node_sound_stone_defaults(), - drop = "gloopblocks:basalt", - after_place_node = function(pos, placer, itemstack, pointed_thing) - minetest.add_node(pos, {name = "gloopblocks:basalt"}) - end - }) - - minetest.register_node("gloopblocks:pumice_cooled", { - description = S("Pumice"), - tiles = {"gloopblocks_pumice.png"}, - groups = {cracky=3, not_in_creative_inventory=1}, - sounds = default.node_sound_stone_defaults(), - drop = "gloopblocks:pumice", - after_place_node = function(pos, placer, itemstack, pointed_thing) - minetest.add_node(pos, {name = "gloopblocks:pumice"}) - end - }) - - local gloopblocks_search_nearby_nodes = function(pos, node) - if minetest.get_node({x=pos.x-1, y=pos.y, z=pos.z}).name == node then return true end - if minetest.get_node({x=pos.x+1, y=pos.y, z=pos.z}).name == node then return true end - if minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == node then return true end - if minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name == node then return true end - if minetest.get_node({x=pos.x, y=pos.y, z=pos.z-1}).name == node then return true end - if minetest.get_node({x=pos.x, y=pos.y, z=pos.z+1}).name == node then return true end - return false - end - - default.cool_lava = function(pos, node) - if node.name == "default:lava_source" then - if gloopblocks_search_nearby_nodes(pos,"default:water_source") - or gloopblocks_search_nearby_nodes(pos,"default:water_flowing") then - minetest.set_node(pos, {name="gloopblocks:obsidian_cooled"}) - end - else -- Lava flowing - if gloopblocks_search_nearby_nodes(pos,"default:water_source") then - minetest.set_node(pos, {name="gloopblocks:basalt_cooled"}) - elseif gloopblocks_search_nearby_nodes(pos,"default:water_flowing") then - minetest.set_node(pos, {name="gloopblocks:pumice_cooled"}) - end - end - end -end - -local fence_texture = - "default_fence_overlay.png^default_steel_block.png^default_fence_overlay.png^[makealpha:255,126,126" - -minetest.register_node("gloopblocks:fence_steel", { - description = S("Steel Fence"), - drawtype = "fencelike", - tiles = {"default_steel_block.png"}, - inventory_image = fence_texture, - wield_image = fence_texture, - paramtype = "light", - sunlight_propagates = true, - is_ground_content = false, - selection_box = { - type = "fixed", - fixed = {-1/7, -1/2, -1/7, 1/7, 1/2, 1/7}, - }, - groups = {choppy = 2, oddly_breakable_by_hand = 2 }, - sounds = default.node_sound_stone_defaults(), -}) - -if minetest.get_modpath("worldedit") then - function gloopblocks.liquid_ungrief(pos1, pos2, name) - local count - local p1to2 = minetest.pos_to_string(pos1).." and "..minetest.pos_to_string(pos2) - local volume = worldedit.volume(pos1, pos2) - minetest.chat_send_player(name, "Cleaning-up lava/water griefing between "..p1to2.."...") - if volume > 1000000 then - minetest.chat_send_player(name, "This operation could affect up to "..volume.." nodes. It may take a while.") - end - minetest.log("action", name.." performs lava/water greifing cleanup between "..p1to2..".") - count = worldedit.replace(pos1, pos2, "default:lava_source", "air") - count = worldedit.replace(pos1, pos2, "default:lava_flowing", "air") - count = worldedit.replace(pos1, pos2, "default:water_source", "air") - count = worldedit.replace(pos1, pos2, "default:water_flowing", "air") - count = worldedit.replace(pos1, pos2, "default:river_water_source", "air") - count = worldedit.replace(pos1, pos2, "default:river_water_flowing", "air") - count = worldedit.replace(pos1, pos2, "gloopblocks:pumice_cooled", "air") - count = worldedit.replace(pos1, pos2, "gloopblocks:basalt_cooled", "air") - count = worldedit.replace(pos1, pos2, "gloopblocks:obsidian_cooled", "air") - count = worldedit.fixlight(pos1, pos2) - minetest.chat_send_player(name, "Operation completed.") - end - - minetest.register_chatcommand("/liquid_ungrief", { - params = "[size]", - privs = {worldedit = true}, - description = "Repairs greifing caused by spilling lava and water (and their \"cooling\" results)", - func = function(name, params) - local pos1 = worldedit.pos1[name] - local pos2 = worldedit.pos2[name] - if not pos1 or not pos2 then return end - gloopblocks.liquid_ungrief(pos1, pos2, name) - end - }) -end - -dofile(minetest.get_modpath("gloopblocks").."/crafts.lua") - -minetest.register_alias("nyancat:nyancat_rainbow", "gloopblocks:rainbow_block_horizontal") -minetest.register_alias("default:nyancat_rainbow", "gloopblocks:rainbow_block_horizontal") +dofile(MP.."/main.lua") +dofile(MP.."/crafts.lua") +dofile(MP.."/lava-handling.lua") print(S("Gloopblocks Loaded!")) diff --git a/mods/gloopblocks/lava-handling.lua b/mods/gloopblocks/lava-handling.lua new file mode 100644 index 00000000..a2c083d6 --- /dev/null +++ b/mods/gloopblocks/lava-handling.lua @@ -0,0 +1,306 @@ +-- Load support for intllib. +local MP = minetest.get_modpath(minetest.get_current_modname()) +local S, NS = dofile(MP.."/intllib.lua") + +-- define lava-cooling-based nodes and hook into the default lavacooling +-- functions to generate basalt, pumice, and obsidian + +if minetest.setting_getbool("gloopblocks_lavacooling") ~= false then + + minetest.register_node("gloopblocks:obsidian_cooled", { + description = S("Obsidian"), + tiles = {"default_obsidian.png"}, + is_ground_content = true, + sounds = default.node_sound_stone_defaults(), + groups = {cracky=1, level=2, not_in_creative_inventory=1}, + drop = "default:obsidian", + after_place_node = function(pos, placer, itemstack, pointed_thing) + minetest.add_node(pos, {name = "default:obsidian"}) + end + }) + + minetest.register_node("gloopblocks:basalt_cooled", { + description = S("Basalt"), + tiles = {"gloopblocks_basalt.png"}, + groups = {cracky=2, not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + drop = "gloopblocks:basalt", + after_place_node = function(pos, placer, itemstack, pointed_thing) + minetest.add_node(pos, {name = "gloopblocks:basalt"}) + end + }) + + minetest.register_node("gloopblocks:pumice_cooled", { + description = S("Pumice"), + tiles = {"gloopblocks_pumice.png"}, + groups = {cracky=3, not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + drop = "gloopblocks:pumice", + after_place_node = function(pos, placer, itemstack, pointed_thing) + minetest.add_node(pos, {name = "gloopblocks:pumice"}) + end + }) + + local gloopblocks_search_nearby_nodes = function(pos, node) + if minetest.get_node({x=pos.x-1, y=pos.y, z=pos.z}).name == node then return true end + if minetest.get_node({x=pos.x+1, y=pos.y, z=pos.z}).name == node then return true end + if minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == node then return true end + if minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name == node then return true end + if minetest.get_node({x=pos.x, y=pos.y, z=pos.z-1}).name == node then return true end + if minetest.get_node({x=pos.x, y=pos.y, z=pos.z+1}).name == node then return true end + return false + end + + default.cool_lava = function(pos, node) + if node.name == "default:lava_source" then + if gloopblocks_search_nearby_nodes(pos,"default:water_source") + or gloopblocks_search_nearby_nodes(pos,"default:water_flowing") then + minetest.set_node(pos, {name="gloopblocks:obsidian_cooled"}) + end + else -- Lava flowing + if gloopblocks_search_nearby_nodes(pos,"default:water_source") then + minetest.set_node(pos, {name="gloopblocks:basalt_cooled"}) + elseif gloopblocks_search_nearby_nodes(pos,"default:water_flowing") then + minetest.set_node(pos, {name="gloopblocks:pumice_cooled"}) + end + end + end +end + +-- Allows lava to "bake" neighboring nodes (or reduce them to ashes) +-- disabled by default. You probably don't want this on a creative server :-P + +if minetest.setting_getbool("gloopblocks_lava_damage") then + minetest.register_node("gloopblocks:ash_block", { + description = S("Block of ashes"), + tiles = {"gloopblocks_ashes.png"}, + groups = {crumbly = 3}, + sounds = default.node_sound_dirt_defaults(), + }) + + local cbox = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, -0.125, 0.5} + } + + minetest.register_node("gloopblocks:ash_pile", { + description = S("Pile of ashes"), + drawtype = "mesh", + mesh = "gloopblocks_ash_pile.obj", + tiles = {"gloopblocks_ashes.png"}, + selection_box = cbox, + collision_box = cbox, + groups = {crumbly = 3}, + sounds = default.node_sound_dirt_defaults(), + }) + + gloopblocks.lava_damage_nodes = { + ["default:cactus"] = "gloopblocks:ash_block", + ["default:coalblock"] = "gloopblocks:ash_block", + ["default:desert_cobble"] = "default:desert_stone", + ["default:desert_sandstone"] = "default:desert_sandstone_block", + ["default:gravel"] = "default:cobble", + ["default:ice"] = "default:snowblock", + ["default:permafrost"] = "default:dirt", + ["default:permafrost_with_moss"] = "default:dirt", + ["default:sandstone"] = "default:sandstone_block", + ["default:silver_sandstone"] = "default:silver_sandstone_block", + ["default:snowblock"] = "default:water_source", + + ["basic_materials:cement_block"] = "basic_materials:concrete_block", + ["bedrock:deepstone"] = "default:stone", + ["building_blocks:hardwood"] = "default:coalblock", + ["building_blocks:Tar"] = "gloopblocks:pavement", + ["bushes:basket_empty"] = "gloopblocks:ash_pile", + ["bushes:basket_blackberry"] = "gloopblocks:ash_pile", + ["bushes:basket_blueberry"] = "gloopblocks:ash_pile", + ["bushes:basket_gooseberry"] = "gloopblocks:ash_pile", + ["bushes:basket_mixed_berry"] = "gloopblocks:ash_pile", + ["bushes:basket_raspberry"] = "gloopblocks:ash_pile", + ["bushes:basket_strawberry"] = "gloopblocks:ash_pile", + ["caverealms:thin_ice"] = "default:water_source", + ["castle_masonry:rubble"] = "default:desert_stone", + ["usesdirt:dirt_stone"] = "default:stone", + ["usesdirt:dirt_cobble_stone"] = "default:stone", + ["wool:dark_grey"] = "gloopblocks:ash_pile" + } + + gloopblocks.lava_damage_groups = { + ["wood"] = "default:coalblock", + ["tree"] = "default:coalblock", + ["soil"] = "gloopblocks:basalt", + ["leaves"] = "gloopblocks:ash_pile", + ["fence"] = "gloopblocks:ash_pile", + ["stone"] = "default:stone", + } + + if minetest.get_modpath("cottages") then + gloopblocks.lava_damage_nodes["cottages:hay"] = "cottages:reet" + gloopblocks.lava_damage_nodes["cottages:hay_bale"] = "cottages:reet" + gloopblocks.lava_damage_nodes["cottages:hay_mat"] = "cottages:straw_mat" + gloopblocks.lava_damage_nodes["cottages:reet"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_black"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_brown"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_red"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_reet"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_straw"] = "cottages:roof_reet" + gloopblocks.lava_damage_nodes["cottages:roof_wood"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_connector_black"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_connector_brown"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_connector_red"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_connector_reet"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_connector_straw"] = "cottages:roof_connector_reet" + gloopblocks.lava_damage_nodes["cottages:roof_connector_wood"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_flat_black"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_flat_brown"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_flat_red"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_flat_reet"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:roof_flat_straw"] = "cottages:roof_flat_reet" + gloopblocks.lava_damage_nodes["cottages:roof_flat_wood"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["cottages:straw_ground"] = "cottages:loam" + gloopblocks.lava_damage_nodes["cottages:loam"] = "default:dirt" + gloopblocks.lava_damage_nodes["cottages:feldweg"] = "default:dirt" + gloopblocks.lava_damage_nodes["cottages:feldweg_crossing"] = "default:dirt" + gloopblocks.lava_damage_nodes["cottages:feldweg_curve"] = "default:dirt" + gloopblocks.lava_damage_nodes["cottages:feldweg_end"] = "default:dirt" + gloopblocks.lava_damage_nodes["cottages:feldweg_slope"] = "default:dirt" + gloopblocks.lava_damage_nodes["cottages:feldweg_slope_long"] = "default:dirt" + gloopblocks.lava_damage_nodes["cottages:feldweg_t_junction"] = "default:dirt" + end + + if minetest.get_modpath("dryplants") then + gloopblocks.lava_damage_nodes["dryplants:wetreed"] = "dryplants:reed" + gloopblocks.lava_damage_nodes["dryplants:wetreed_slab"] = "dryplants:reed_slab" + gloopblocks.lava_damage_nodes["dryplants:wetreed_roof"] = "dryplants:reed_roof" + gloopblocks.lava_damage_nodes["dryplants:wetreed_roof_corner"] = "dryplants:reed_roof_corner" + gloopblocks.lava_damage_nodes["dryplants:wetreed_roof_corner_2"] = "dryplants:reed_roof_corner_2" + gloopblocks.lava_damage_nodes["dryplants:reed"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["dryplants:reed_slab"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["dryplants:reed_roof"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["dryplants:reed_roof_corner"] = "gloopblocks:ash_pile" + gloopblocks.lava_damage_nodes["dryplants:reed_roof_corner_2"] = "gloopblocks:ash_pile" + end + + if minetest.get_modpath("wool") then + gloopblocks.lava_damage_groups["wool"] = "wool:dark_grey" + end + + if minetest.get_modpath("bakedclay") then + gloopblocks.lava_damage_nodes["default:clay"] = "bakedclay:dark_grey" + gloopblocks.lava_damage_groups["bakedclay"] = "bakedclay:dark_grey" + else + gloopblocks.lava_damage_nodes["default:clay"] = "gloopblocks:basalt" + end + + if minetest.get_modpath("moreblocks") then + gloopblocks.lava_damage_groups["sand"] = "moreblocks:coal_glass" + else + gloopblocks.lava_damage_groups["sand"] = "default:obsidian_glass" + end + + if minetest.get_modpath("farming") then + gloopblocks.lava_damage_nodes["farming:soil_wet"] = "farming:soil" + end + + gloopblocks.lava_neighbors = { + { x=-1, y=-1, z=-1 }, + { x=-1, y=-1, z= 0 }, + { x=-1, y=-1, z= 1 }, + { x=-1, y= 0, z=-1 }, + { x=-1, y= 0, z= 0 }, + { x=-1, y= 0, z= 1 }, + { x=-1, y= 1, z=-1 }, + { x=-1, y= 1, z= 0 }, + { x=-1, y= 1, z= 1 }, + + { x= 0, y=-1, z=-1 }, + { x= 0, y=-1, z= 0 }, + { x= 0, y=-1, z= 1 }, + { x= 0, y= 0, z=-1 }, +-- { x= 0, y= 0, z= 0 }, -- will always be the lava node, so ignore this space + { x= 0, y= 0, z= 1 }, + { x= 0, y= 1, z=-1 }, + { x= 0, y= 1, z= 0 }, + { x= 0, y= 1, z= 1 }, + + { x= 1, y=-1, z=-1 }, + { x= 1, y=-1, z= 0 }, + { x= 1, y=-1, z= 1 }, + { x= 1, y= 0, z=-1 }, + { x= 1, y= 0, z= 0 }, + { x= 1, y= 0, z= 1 }, + { x= 1, y= 1, z=-1 }, + { x= 1, y= 1, z= 0 }, + { x= 1, y= 1, z= 1 }, + } + + minetest.register_abm({ + nodenames = {"default:lava_source", "default:lava_flowing"}, + interval = 5, + chance = 2, + action = function(pos, node, active_object_count, active_object_count_wider) + local r=gloopblocks.lava_neighbors[math.random(1, 26)] + local pos2 = { + x = pos.x + r.x, + y = pos.y + r.y, + z = pos.z + r.z + } + local newnode + local chknode = minetest.get_node(pos2) + local def = minetest.registered_items[chknode.name] + + if gloopblocks.lava_damage_nodes[chknode.name] then + newnode = gloopblocks.lava_damage_nodes[chknode.name] + elseif def and def.drawtype == "plantlike" then + newnode = "air" + else + for group, new in pairs(gloopblocks.lava_damage_groups) do + if minetest.get_item_group(chknode.name, group) > 0 then + newnode = new + break + end + end + end + + if newnode then + minetest.set_node(pos2, {name = newnode, param2 = chknode.param2}) + end + end + }) +end + +if minetest.get_modpath("worldedit") then + function gloopblocks.liquid_ungrief(pos1, pos2, name) + local count + local p1to2 = minetest.pos_to_string(pos1).." and "..minetest.pos_to_string(pos2) + local volume = worldedit.volume(pos1, pos2) + minetest.chat_send_player(name, "Cleaning-up lava/water griefing between "..p1to2.."...") + if volume > 1000000 then + minetest.chat_send_player(name, "This operation could affect up to "..volume.." nodes. It may take a while.") + end + minetest.log("action", name.." performs lava/water greifing cleanup between "..p1to2..".") + count = worldedit.replace(pos1, pos2, "default:lava_source", "air") + count = worldedit.replace(pos1, pos2, "default:lava_flowing", "air") + count = worldedit.replace(pos1, pos2, "default:water_source", "air") + count = worldedit.replace(pos1, pos2, "default:water_flowing", "air") + count = worldedit.replace(pos1, pos2, "default:river_water_source", "air") + count = worldedit.replace(pos1, pos2, "default:river_water_flowing", "air") + count = worldedit.replace(pos1, pos2, "gloopblocks:pumice_cooled", "air") + count = worldedit.replace(pos1, pos2, "gloopblocks:basalt_cooled", "air") + count = worldedit.replace(pos1, pos2, "gloopblocks:obsidian_cooled", "air") + count = worldedit.fixlight(pos1, pos2) + minetest.chat_send_player(name, "Operation completed.") + end + + minetest.register_chatcommand("/liquid_ungrief", { + params = "[size]", + privs = {worldedit = true}, + description = "Repairs greifing caused by spilling lava and water (and their \"cooling\" results)", + func = function(name, params) + local pos1 = worldedit.pos1[name] + local pos2 = worldedit.pos2[name] + if not pos1 or not pos2 then return end + gloopblocks.liquid_ungrief(pos1, pos2, name) + end + }) +end diff --git a/mods/gloopblocks/main.lua b/mods/gloopblocks/main.lua new file mode 100644 index 00000000..ae6ffe42 --- /dev/null +++ b/mods/gloopblocks/main.lua @@ -0,0 +1,839 @@ +-- Load support for intllib. +local MP = minetest.get_modpath(minetest.get_current_modname()) +local S, NS = dofile(MP.."/intllib.lua") + +-- Nodes + +minetest.register_node("gloopblocks:rainbow_block_diagonal", { + description = S("Diagonal Rainbow Block"), + tiles = {"gloopblocks_rainbow_block.png"}, + is_ground_content = true, + groups = {cracky=3}, + sounds = default.node_sound_defaults(), +}) +minetest.register_alias("gloopblocks:rainbow_block", "gloopblocks:rainbow_block_diagonal") + +minetest.register_node("gloopblocks:rainbow_block_horizontal", { + description = S("Horizontal Rainbow Block"), + tiles = { + "gloopblocks_rainbow_horizontal.png^[transformR90", + "gloopblocks_rainbow_horizontal.png^[transformR90", + "gloopblocks_rainbow_horizontal.png" + }, + paramtype = "light", + light_source = default.LIGHT_MAX, + paramtype2 = "facedir", + groups = {cracky = 2}, + is_ground_content = false, + sounds = default.node_sound_defaults(), +}) + +minetest.register_node("gloopblocks:evil_block", { + description = S("Evil Block"), + tiles = {"gloopblocks_evil_block.png"}, + light_source = 5, + is_ground_content = true, + groups = {cracky=2}, + sounds = default.node_sound_stone_defaults(), +}) + +minetest.register_node("gloopblocks:basalt", { + description = S("Basalt"), + tiles = {"gloopblocks_basalt.png"}, + groups = {cracky=2}, + sounds = default.node_sound_stone_defaults(), +}) + +minetest.register_node("gloopblocks:pumice", { + description = S("Pumice"), + tiles = {"gloopblocks_pumice.png"}, + groups = {cracky=3}, + sounds = default.node_sound_stone_defaults(), +}) + + +minetest.register_node("gloopblocks:pavement", { + description = S("Pavement"), + tiles = {"gloopblocks_pavement.png"}, + groups = {cracky=3, oddly_breakable_by_hand=3}, + sounds = default.node_sound_stone_defaults(), +}) + +minetest.register_node("gloopblocks:oerkki_block", { + drawtype = "nodebox", + description = S("Oerkki Block"), + paramtype = "light", + paramtype2 = "facedir", + tiles = { + "gloopblocks_oerkkiblock_tb.png", + "gloopblocks_oerkkiblock_tb.png", + "gloopblocks_oerkkiblock_sides.png", + "gloopblocks_oerkkiblock_sides.png", + "gloopblocks_oerkkiblock_sides.png", + "gloopblocks_oerkkiblock_front.png" + }, + groups = {cracky=3, oddly_breakable_by_hand=3}, + sounds = default.node_sound_stone_defaults(), + selection_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } + }, + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.1875, 0.5, 0.5, 0.1875}, -- NodeBox1 + {-0.5, -0.5, -0.5, -0.4375, 0.5, 0.5}, -- NodeBox2 + {0.4375, -0.5, -0.5, 0.5, 0.5, 0.5}, -- NodeBox3 + {-0.5, 0.4375, -0.5, 0.5, 0.5, 0.5}, -- NodeBox4 + {-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5}, -- NodeBox5 + {-0.5, -0.0625, -0.5, 0.5, 0.0625, 0.5}, -- NodeBox6 + } + } +}) + +minetest.register_node("gloopblocks:stone_brick_mossy", { + description = S("Mossy Stone Brick"), + tiles = {"gloopblocks_stone_brick_mossy.png"}, + groups = {cracky=3, stone=1}, + sounds = default.node_sound_stone_defaults(), +}) + +minetest.register_node("gloopblocks:stone_mossy", { + description = S("Mossy Stone"), + tiles = {"gloopblocks_stone_mossy.png"}, + groups = {cracky=3, stone=1}, + sounds = default.node_sound_stone_defaults(), + drop = "default:mossycobble" +}) + +minetest.register_node("gloopblocks:cobble_road", { + description = S("Cobblestone Road Bed"), + tiles = {"gloopblocks_cobble_road.png"}, + groups = {cracky=3, stone=1}, + sounds = default.node_sound_stone_defaults(), +}) + +minetest.register_node("gloopblocks:cobble_road_mossy", { + description = S("Mossy Cobblestone Road Bed"), + tiles = {"gloopblocks_cobble_road_mossy.png"}, + groups = {cracky=3, stone=1}, + sounds = default.node_sound_stone_defaults(), +}) + +minetest.register_node("gloopblocks:scaffolding", { + description = S("Wooden Scaffold"), + drawtype = "allfaces", + paramtype = "light", + sunlight_propagates = true, + tiles = {"gloopblocks_scaffold.png"}, + groups = {choppy=3, oddly_breakable_by_hand=3}, + sounds = default.node_sound_wood_defaults(), +}) + +minetest.register_alias("moreblocks:oerkkiblock", "gloopblocks:oerkki_block") +minetest.register_alias("gloopblocks:obsidian", "default:obsidian") + +-- Nodes imported from Usesdirt ================================================================================ + +if not minetest.get_modpath("usesdirt") then + + local dirt_brick_tex = "default_dirt.png^gloopblocks_dirt_brick_overlay.png" + local dirt_cobble_tex = "default_cobble.png^(default_dirt.png^[mask:gloopblocks_dirt_cobble_mask.png)" + local dirt_stone_tex = "default_stone.png^(default_dirt.png^[mask:gloopblocks_dirt_stone_mask.png)" + + local dirt_ladder_tex = "(default_dirt.png^[mask:gloopblocks_ladder_mask.png)^gloopblocks_ladder_overlay.png" + local dirt_brick_ladder_tex = "(("..dirt_brick_tex..")^[mask:gloopblocks_ladder_mask.png)^gloopblocks_ladder_overlay.png" + local dirt_cobble_ladder_tex = "(("..dirt_cobble_tex..")^[mask:gloopblocks_ladder_mask.png)^gloopblocks_ladder_overlay.png" + local dirt_stone_ladder_tex = "(("..dirt_stone_tex..")^[mask:gloopblocks_ladder_mask.png)^gloopblocks_ladder_overlay.png" + + minetest.register_node(":usesdirt:dirt_brick", { + tiles = { dirt_brick_tex }, + description = "Dirt Brick", + groups = {snappy=2,choppy=1,oddly_breakable_by_hand=2}, + }) + + minetest.register_node(":usesdirt:dirt_brick_ladder", { + description = "Dirt Brick Ladder", + drawtype = "signlike", + tiles = { dirt_brick_ladder_tex }, + inventory_image = dirt_brick_ladder_tex, + wield_image = dirt_brick_ladder_tex, + paramtype = "light", + paramtype2 = "wallmounted", + is_ground_content = true, + walkable = false, + climbable = true, + selection_box = { + type = "wallmounted", + --wall_top = = + --wall_bottom = = + --wall_side = = + }, + groups = {cracky=3, stone=2}, + legacy_wallmounted = true, + }) + minetest.register_craft({ + output = 'usesdirt:dirt_brick_ladder 3', + recipe = { + {'usesdirt:dirt_brick', '', 'usesdirt:dirt_brick'}, + {'usesdirt:dirt_brick', 'usesdirt:dirt_brick','usesdirt:dirt_brick'}, + {'usesdirt:dirt_brick','','usesdirt:dirt_brick'}, + } + }) + + default.register_fence(":usesdirt:dirt_brick_fence", { + description = "Dirt Brick Fence", + texture = dirt_brick_tex, + inventory_image = "default_fence_overlay.png^("..dirt_brick_tex..")^default_fence_overlay.png^[makealpha:255,126,126", + wield_image = "default_fence_overlay.png^("..dirt_brick_tex..")^default_fence_overlay.png^[makealpha:255,126,126", + material = "usesdirt:dirt_brick", + groups = {cracky=3, stone=2}, + sounds = default.node_sound_stone_defaults(), + check_for_pole = true + }) + + if minetest.get_modpath("moreblocks") then + minetest.register_craft({ + output = 'usesdirt:dirt_brick 24', + recipe = { + {'moreblocks:dirt_compressed', 'moreblocks:dirt_compressed', '' }, + {'moreblocks:dirt_compressed', 'moreblocks:dirt_compressed', '' } + } + }) + else + minetest.register_craft({ + output = 'usesdirt:dirt_brick 6', + recipe = { + {'default:dirt', 'default:dirt', 'default:dirt'}, + {'default:dirt', 'default:dirt', 'default:dirt'}, + {'default:dirt', 'default:dirt', 'default:dirt'}, + } + }) + end + + minetest.register_node(":usesdirt:dirt_ladder", { + description = "Dirt Ladder", + drawtype = "signlike", + tiles = { dirt_ladder_tex }, + inventory_image = dirt_ladder_tex, + wield_image = dirt_ladder_tex, + paramtype = "light", + paramtype2 = "wallmounted", + is_ground_content = true, + walkable = false, + climbable = true, + selection_box = { + type = "wallmounted", + --wall_top = = + --wall_bottom = = + --wall_side = = + }, + groups = {snappy=2,choppy=2,oddly_breakable_by_hand=3}, + legacy_wallmounted = true, + }) + minetest.register_craft({ + output = 'usesdirt:dirt_ladder 3', + recipe = { + {'usesdirt:dirt_brick', '', 'usesdirt:dirt_brick'}, + {'usesdirt:dirt_brick', 'usesdirt:dirt_brick','usesdirt:dirt_brick'}, + {'usesdirt:dirt_brick','','usesdirt:dirt_brick'}, + } + }) + + default.register_fence(":usesdirt:dirt_fence", { + description = "Dirt Fence", + texture = "default_dirt.png", + inventory_image = "default_fence_overlay.png^default_dirt.png^default_fence_overlay.png^[makealpha:255,126,126", + wield_image = "default_fence_overlay.png^default_dirt.png^default_fence_overlay.png^[makealpha:255,126,126", + material = "default:dirt", + groups = {snappy=2,choppy=1,oddly_breakable_by_hand=3}, + sounds = default.node_sound_dirt_defaults(), + check_for_pole = true + }) + +---- + + minetest.register_node(":usesdirt:dirt_cobble_stone", { + tiles = { dirt_cobble_tex }, + description = "Dirt Cobble Stone", + is_ground_content = true, + groups = {cracky=3, stone=2}, + }) + minetest.register_craft({ + output = '"usesdirt:dirt_cobble_stone" 3', + recipe = { + {'usesdirt:dirt_brick', 'usesdirt:dirt_brick', 'usesdirt:dirt_brick'}, + {'usesdirt:dirt_brick', 'usesdirt:dirt_brick', 'usesdirt:dirt_brick'}, + {'usesdirt:dirt_brick', 'usesdirt:dirt_brick', 'usesdirt:dirt_brick'}, + } + }) + + minetest.register_node(":usesdirt:dirt_cobble_stone_ladder", { + description = "Dirt Cobble Stone Ladder", + drawtype = "signlike", + tiles = { dirt_cobble_ladder_tex }, + inventory_image = dirt_cobble_ladder_tex, + wield_image = dirt_cobble_ladder_tex, + paramtype = "light", + paramtype2 = "wallmounted", + is_ground_content = true, + walkable = false, + climbable = true, + selection_box = { + type = "wallmounted", + --wall_top = = + --wall_bottom = = + --wall_side = = + }, + groups = {cracky=3, stone=2}, + legacy_wallmounted = true, + }) + minetest.register_craft({ + output = 'usesdirt:dirt_cobble_stone_ladder 3', + recipe = { + {'usesdirt:dirt_cobble_stone', '', 'usesdirt:dirt_cobble_stone'}, + {'usesdirt:dirt_cobble_stone', 'usesdirt:dirt_cobble_stone','usesdirt:dirt_cobble_stone'}, + {'usesdirt:dirt_cobble_stone','','usesdirt:dirt_cobble_stone'}, + } + }) + + default.register_fence(":usesdirt:dirt_cobble_stone_fence", { + description = "Dirt Cobble Stone Fence", + texture = dirt_cobble_tex, + inventory_image = "default_fence_overlay.png^("..dirt_cobble_tex..")^default_fence_overlay.png^[makealpha:255,126,126", + wield_image = "default_fence_overlay.png^("..dirt_cobble_tex..")^default_fence_overlay.png^[makealpha:255,126,126", + material = "usesdirt:dirt_cobble_stone", + groups = {cracky=3, stone=2}, + sounds = default.node_sound_stone_defaults(), + check_for_pole = true + }) + +---- + + minetest.register_node(":usesdirt:dirt_stone", { + tiles = { dirt_stone_tex }, + description = "Dirt Stone", + is_ground_content = true, + groups = {cracky=3, stone=2}, + }) + + minetest.register_node(":usesdirt:dirt_stone_ladder", { + description = "Dirt Stone Ladder", + drawtype = "signlike", + tiles = { dirt_stone_ladder_tex }, + inventory_image = dirt_stone_ladder_tex, + wield_image = dirt_stone_ladder_tex, + paramtype = "light", + paramtype2 = "wallmounted", + is_ground_content = true, + walkable = false, + climbable = true, + selection_box = { + type = "wallmounted", + --wall_top = = + --wall_bottom = = + --wall_side = = + }, + groups = {cracky=3, stone=2}, + legacy_wallmounted = true, + }) + minetest.register_craft({ + output = 'usesdirt:dirt_stone_ladder 3', + recipe = { + {'usesdirt:dirt_stone', '', 'usesdirt:dirt_stone'}, + {'usesdirt:dirt_stone', 'usesdirt:dirt_stone','usesdirt:dirt_stone'}, + {'usesdirt:dirt_stone','','usesdirt:dirt_stone'}, + } + }) + + default.register_fence(":usesdirt:dirt_stone_fence", { + description = "Dirt Stone Fence", + texture = dirt_stone_tex, + inventory_image = "default_fence_overlay.png^("..dirt_stone_tex..")^default_fence_overlay.png^[makealpha:255,126,126", + wield_image = "default_fence_overlay.png^("..dirt_stone_tex..")^default_fence_overlay.png^[makealpha:255,126,126", + material = "usesdirt:dirt_stone", + groups = {cracky=3, stone=2}, + sounds = default.node_sound_stone_defaults(), + check_for_pole = true + }) +end + +-- Stairs/slabs defs, conversion of normal -> mossy items + +if minetest.setting_getbool("gloopblocks_mossy_conversion") ~= false then + + function gloopblocks_register_mossy_conversion(mossyobjects) + for i in ipairs(mossyobjects) do + minetest.register_abm({ + nodenames = { mossyobjects[i][1] }, + neighbors = {"default:water_source", "default:water_flowing"}, + interval = 120, + chance = 50, + action = function(pos, node) + if minetest.find_node_near(pos, 2, "air") then + local fdir = node.param2 + minetest.add_node(pos, {name = mossyobjects[i][2], param2 = fdir}) + end + end, + }) + end + end +end + +if minetest.get_modpath("moreblocks") then + + stairsplus:register_all("gloopblocks", "oerkki_block", "gloopblocks:oerkki_block", { + description = S("Oerkki Block"), + tiles = { + "gloopblocks_oerkkiblock_tb.png", + "gloopblocks_oerkkiblock_tb.png", + "gloopblocks_oerkkiblock_sides.png", + "gloopblocks_oerkkiblock_sides.png", + "gloopblocks_oerkkiblock_sides.png", + "gloopblocks_oerkkiblock_front.png" + }, + groups = {cracky=2, not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = true, + }) + + stairsplus:register_all("gloopblocks", "stone_brick_mossy", "gloopblocks:stone_brick_mossy", { + description = S("Mossy Stone Brick"), + tiles = {"gloopblocks_stone_brick_mossy.png"}, + groups = {cracky=1, not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = true, + }) + + stairsplus:register_all("gloopblocks", "stone_mossy", "gloopblocks:stone_mossy", { + description = S("Mossy Stone"), + tiles = {"gloopblocks_stone_mossy.png"}, + groups = {cracky=1, not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = true, + }) + + stairsplus:register_all("gloopblocks", "cobble_road", "gloopblocks:cobble_road", { + description = S("Cobblestone Roadbed"), + tiles = {"gloopblocks_cobble_road.png"}, + groups = {cracky=3, stone=1, not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = true, + }) + + stairsplus:register_all("gloopblocks", "cobble_road_mossy", "gloopblocks:cobble_road_mossy", { + description = S("Mossy Cobblestone Roadbed"), + tiles = {"gloopblocks_cobble_road_mossy.png"}, + groups = {cracky=3, stone=1, not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = true, + }) + + stairsplus:register_all("gloopblocks", "pavement", "gloopblocks:pavement", { + description = S("Pavement"), + tiles = {"gloopblocks_pavement.png"}, + groups = {cracky=2, not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = true, + }) + + stairsplus:register_all("gloopblocks", "rainbow_block", "gloopblocks:rainbow_block", { + description = S("Rainbow Block"), + tiles = {"gloopblocks_rainbow_block.png"}, + groups = {cracky=3, not_in_creative_inventory=1}, + sounds = default.node_sound_defaults(), + sunlight_propagates = true, + }) + + stairsplus:register_all("gloopblocks", "evil_block", "gloopblocks:evil_block", { + description = S("Evil Block"), + tiles = {"gloopblocks_evil_block.png"}, + groups = {cracky=3, not_in_creative_inventory=1}, + sounds = default.node_sound_defaults(), + light_source = 5, + sunlight_propagates = true, + }) + + stairsplus:register_all("gloopblocks", "basalt", "gloopblocks:basalt", { + description = S("Basalt"), + tiles = {"gloopblocks_basalt.png"}, + groups = {cracky=2, not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = true, + }) + + stairsplus:register_all("gloopblocks", "pumice", "gloopblocks:pumice", { + description = S("Pumice"), + tiles = {"gloopblocks_pumice.png"}, + groups = {cracky=3, not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = true, + }) + + stairsplus:register_all("gloopblocks", "gravel", "default:gravel", { + description = S("Gravel"), + tiles = {"default_gravel.png"}, + groups = {crumbly = 2, falling_node = 1, not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = false, + }) + + if minetest.get_modpath("caverealms") then + stairsplus:register_all("caverealms", "glow_crystal", "caverealms:glow_crystal", { + description = S("Glow Crystal"), + tiles = {"caverealms_glow_crystal.png"}, + groups = {cracky=3, not_in_creative_inventory=1}, + sounds = default.node_sound_glass_defaults(), + light_source = 12, + use_texture_alpha = true, + paramtype="light", + sunlight_propagates = true, + }) + + stairsplus:register_all("caverealms", "glow_emerald", "caverealms:glow_emerald", { + description = S("Glow Emerald"), + tiles = {"caverealms_glow_emerald.png"}, + groups = {cracky=3, not_in_creative_inventory=1}, + sounds = default.node_sound_glass_defaults(), + light_source = 12, + use_texture_alpha = true, + paramtype="light", + sunlight_propagates = true, + }) + + stairsplus:register_all("caverealms", "glow_mese", "caverealms:glow_mese", { + description = S("Glow Mese"), + tiles = {"caverealms_glow_mese.png"}, + groups = {cracky=3, not_in_creative_inventory=1}, + sounds = default.node_sound_glass_defaults(), + light_source = 12, + use_texture_alpha = true, + paramtype="light", + sunlight_propagates = true, + }) + end + + -- ABMs for mossy objects + + if minetest.setting_getbool("gloopblocks_mossy_conversion") ~= false then + + gloopblocks_register_mossy_conversion({ + { "moreblocks:stair_cobble", "moreblocks:stair_mossycobble" }, + { "moreblocks:stair_cobble_inner", "moreblocks:stair_mossycobble_inner" }, + { "moreblocks:stair_cobble_outer", "moreblocks:stair_mossycobble_outer" }, + { "moreblocks:stair_cobble_half", "moreblocks:stair_mossycobble_half" }, + { "moreblocks:slab_cobble_quarter", "moreblocks:slab_mossycobble_quarter" }, + { "moreblocks:slab_cobble", "moreblocks:slab_mossycobble" }, + { "moreblocks:slab_cobble_three_quarter", "moreblocks:slab_mossycobble_three_quarter" }, + { "moreblocks:panel_cobble", "moreblocks:panel_mossycobble" }, + { "moreblocks:micro_cobble", "moreblocks:micro_mossycobble" }, + { "moreblocks:stair_cobble_alt", "moreblocks:stair_mossycobble_alt" }, + + { "gloopblocks:cobble_road", "gloopblocks:cobble_road_mossy" }, + { "gloopblocks:stair_cobble_road", "gloopblocks:stair_cobble_road_mossy" }, + { "gloopblocks:slab_cobble_road", "gloopblocks:slab_cobble_road_mossy" }, + { "gloopblocks:stair_cobble_road", "gloopblocks:stair_cobble_road_mossy" }, + { "gloopblocks:stair_cobble_road_inner", "gloopblocks:stair_cobble_road_mossy_inner" }, + { "gloopblocks:stair_cobble_road_outer", "gloopblocks:stair_cobble_road_mossy_outer" }, + { "gloopblocks:stair_cobble_road_half", "gloopblocks:stair_cobble_road_mossy_half" }, + { "gloopblocks:slab_cobble_road_quarter", "gloopblocks:slab_cobble_road_mossy_quarter" }, + { "gloopblocks:slab_cobble_road", "gloopblocks:slab_cobble_road_mossy" }, + { "gloopblocks:slab_cobble_road_three_quarter", "gloopblocks:slab_cobble_road_mossy_three_quarter" }, + { "gloopblocks:panel_cobble_road", "gloopblocks:panel_cobble_road_mossy" }, + { "gloopblocks:micro_cobble_road", "gloopblocks:micro_cobble_road_mossy" }, + { "gloopblocks:stair_cobble_road_alt", "gloopblocks:stair_cobble_road_mossy_alt" }, + + { "default:stonebrick", "gloopblocks:stone_brick_mossy" }, + { "default:stair_stonebrick", "gloopblocks:stair_stone_brick_mossy" }, + { "default:slab_stonebrick", "gloopblocks:slab_stone_brick_mossy" }, + { "moreblocks:stair_stonebrick", "gloopblocks:stair_stone_brick_mossy" }, + { "moreblocks:stair_stonebrick_inner", "gloopblocks:stair_stone_brick_mossy_inner" }, + { "moreblocks:stair_stonebrick_outer", "gloopblocks:stair_stone_brick_mossy_outer" }, + { "moreblocks:stair_stonebrick_half", "gloopblocks:stair_stone_brick_mossy_half" }, + { "moreblocks:slab_stonebrick_quarter", "gloopblocks:slab_stone_brick_mossy_quarter" }, + { "moreblocks:slab_stonebrick", "gloopblocks:slab_stone_brick_mossy" }, + { "moreblocks:slab_stonebrick_three_quarter", "gloopblocks:slab_stone_brick_mossy_three_quarter" }, + { "moreblocks:panel_stonebrick", "gloopblocks:panel_stone_brick_mossy" }, + { "moreblocks:micro_stonebrick", "gloopblocks:micro_stone_brick_mossy" }, + { "moreblocks:stair_stonebrick_alt", "gloopblocks:stair_stone_brick_mossy_alt" }, + + { "default:stone", "gloopblocks:stone_mossy" }, + { "default:stair_stone", "gloopblocks:stair_stone_mossy" }, + { "default:slab_stone", "gloopblocks:slab_stone_mossy" }, + { "moreblocks:stair_stone", "gloopblocks:stair_stone_mossy" }, + { "moreblocks:stair_stone_inner", "gloopblocks:stair_stone_mossy_inner" }, + { "moreblocks:stair_stone_outer", "gloopblocks:stair_stone_mossy_outer" }, + { "moreblocks:stair_stone_half", "gloopblocks:stair_stone_mossy_half" }, + + { "moreblocks:slab_stone_quarter", "gloopblocks:slab_stone_mossy_quarter" }, + { "moreblocks:slab_stone", "gloopblocks:slab_stone_mossy" }, + { "moreblocks:slab_stone_three_quarter", "gloopblocks:slab_stone_mossy_three_quarter" }, + { "moreblocks:panel_stone", "gloopblocks:panel_stone_mossy" }, + { "moreblocks:micro_stone", "gloopblocks:micro_stone_mossy" }, + { "moreblocks:stair_stone_alt", "gloopblocks:stair_stone_mossy_alt" }, + }) + end + +elseif minetest.get_modpath("stairs") then + + --stairs.register_stair(subname, recipeitem, groups, images, description, sounds) + + -- stairs:xxxx_stone_mossy ; xxxx = stair or slab + stairs.register_stair_and_slab("stone_mossy", "gloopblocks:stone_mossy", + {cracky=3}, + {"gloopblocks_stone_mossy.png"}, + S("Mossy Stone Stair"), + S("Mossy Stone Slab"), + default.node_sound_stone_defaults()) + + -- stairs:xxxx_mossycobble + stairs.register_stair_and_slab("mossycobble", "default:mossycobble", + {cracky=3}, + {"default_mossycobble.png"}, + S("Mossy Cobble Stair"), + S("Mossy Cobble Slab"), + default.node_sound_stone_defaults()) + + -- stairs:xxxx_stone_brick_mossy + stairs.register_stair_and_slab("stone_brick_mossy", "gloopblocks:stone_brick_mossy", + {cracky=3}, + {"gloopblocks_stone_brick_mossy.png"}, + S("Mossy Stone Brick Stair"), + S("Mossy Stone Brick Slab"), + default.node_sound_stone_defaults()) + + -- stairs:xxxx_cobble_road + stairs.register_stair_and_slab("cobble_road", "gloopblocks:cobble_road", + {cracky=3}, + {"gloopblocks_cobble_road.png"}, + S("Cobble Roadbed Stair"), + S("Cobble Roadbed Slab"), + default.node_sound_stone_defaults()) + + -- stairs:xxxx_cobble_road_mossy + stairs.register_stair_and_slab("cobble_road_mossy", "gloopblocks:cobble_road_mossy", + {cracky=3}, + {"gloopblocks_cobble_road_mossy.png"}, + S("Mossy Cobble Roadbed Stair"), + S("Mossy Cobble Roadbed Slab"), + default.node_sound_stone_defaults()) + + -- stairs:xxxx_cement + stairs.register_stair_and_slab("cement", "gloopblocks:cement", + {cracky=2}, + {"basic_materials_cement_block.png"}, + S("Cement Stair"), + S("Cement Slab"), + default.node_sound_stone_defaults()) + + -- stairs:xxxx_pavement + stairs.register_stair_and_slab("pavement", "gloopblocks:pavement", + {cracky=3, oddly_breakable_by_hand=3}, + {"gloopblocks_pavement.png"}, + S("Pavement Stair"), + S("Pavement Slab"), + default.node_sound_stone_defaults()) + + stairs.register_stair_and_slab("basalt", "gloopblocks:basalt", + {cracky=2}, + {"gloopblocks_basalt.png"}, + S("Basalt Stair"), + S("Basalt Slab"), + default.node_sound_stone_defaults()) + + stairs.register_stair_and_slab("pumice", "gloopblocks:pumice", + {cracky=3}, + {"gloopblocks_pumice.png"}, + S("Pumice Stair"), + S("Pumice Slab"), + default.node_sound_stone_defaults()) + + stairs.register_stair_and_slab("rainbow_block", "gloopblocks:rainbow_block", + {cracky=3}, + {"gloopblocks_rainbow_block.png"}, + S("Rainbow Block Stair"), + S("Rainbow Block Slab"), + default.node_sound_defaults()) + + if minetest.setting_getbool("gloopblocks_mossy_conversion") ~= false then + + gloopblocks_register_mossy_conversion({ + { "default:cobble", "default:mossycobble" }, + { "stairs:stair_cobble", "stairs:stair_mossycobble" }, + { "stairs:slab_cobble", "stairs:slab_mossycobble" }, + { "gloopblocks:cobble_road", "gloopblocks:cobble_road_mossy" }, + { "stairs:stair_cobble_road", "stairs:stair_cobble_road_mossy" }, + { "stairs:slab_cobble_road", "stairs:slab_cobble_road_mossy" }, + { "default:stonebrick", "gloopblocks:stone_brick_mossy" }, + { "stairs:stair_stonebrick", "stairs:stair_stone_brick_mossy" }, + { "stairs:slab_stonebrick", "stairs:slab_stone_brick_mossy" }, + { "default:stone", "gloopblocks:stone_mossy" }, + { "stairs:stair_stone", "stairs:stair_stone_mossy" }, + { "stairs:slab_stone", "stairs:slab_stone_mossy" }, + }) + end + + minetest.register_alias("default:stair_mossycobble", "stairs:stair_mossycobble") + minetest.register_alias("default:slab_mossycobble", "stairs:slab_mossycobble") + minetest.register_alias("gloopblocks:stair_cobble_road", "stairs:stair_cobble_road") + minetest.register_alias("gloopblocks:slab_cobble_road", "stairs:slab_cobble_road") + minetest.register_alias("gloopblocks:stair_cobble_road_mossy", "stairs:stair_cobble_road_mossy") + minetest.register_alias("gloopblocks:slab_cobble_road_mossy", "stairs:slab_cobble_road_mossy") + minetest.register_alias("gloopblocks:stair_stone_brick_mossy", "stairs:stair_stone_brick_mossy") + minetest.register_alias("gloopblocks:slab_stone_brick_mossy", "stairs:slab_stone_brick_mossy") + minetest.register_alias("gloopblocks:stair_stone_mossy", "stairs:stair_stone_mossy") + minetest.register_alias("gloopblocks:slab_stone_mossy", "stairs:slab_stone_mossy") + minetest.register_alias("gloopblocks:stair_cement", "stairs:stair_cement") + minetest.register_alias("gloopblocks:slab_cement", "stairs:slab_cement") + minetest.register_alias("gloopblocks:stair_pavement", "stairs:stair_pavement") + minetest.register_alias("gloopblocks:slab_pavement", "stairs:slab_pavement") + minetest.register_alias("gloopblocks:stair_pumice", "stairs:stair_pumice") + minetest.register_alias("gloopblocks:slab_pumice", "stairs:slab_pumice") + minetest.register_alias("gloopblocks:stair_basalt", "stairs:stair_basalt") + minetest.register_alias("gloopblocks:slab_basalt", "stairs:slab_basalt") + minetest.register_alias("gloopblocks:stair_rainbow_block", "stairs:stair_rainbow_block") + minetest.register_alias("gloopblocks:slab_rainbow_block", "stairs:slab_rainbow_block") +end + +-- Tools + +minetest.register_tool("gloopblocks:pick_cement", { + description = S("Cement Pickaxe"), + inventory_image = "gloopblocks_cement_pick.png", + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=1, + groupcaps={ + cracky={times={[1]=3.50, [2]=1.40, [3]=0.90}, uses=25, maxlevel=2} + }, + damage_groups = {fleshy=4}, + }, +}) + +minetest.register_tool("gloopblocks:shovel_cement", { + description = S("Cement Shovel"), + inventory_image = "gloopblocks_cement_shovel.png", + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=1, + groupcaps={ + crumbly={times={[1]=1.50, [2]=0.60, [3]=0.45}, uses=25, maxlevel=2} + }, + damage_groups = {fleshy=4}, + }, +}) + +minetest.register_tool("gloopblocks:axe_cement", { + description = S("Cement Axe"), + inventory_image = "gloopblocks_cement_axe.png", + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=1, + groupcaps={ + choppy={times={[1]=3.00, [2]=1.30, [3]=0.80}, uses=25, maxlevel=2}, + fleshy={times={[2]=1.20, [3]=0.65}, uses=30, maxlevel=1} + }, + damage_groups = {fleshy=4}, + }, +}) + +minetest.register_tool("gloopblocks:sword_cement", { + description = S("Cement Sword"), + inventory_image = "gloopblocks_cement_sword.png", + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=1, + groupcaps={ + fleshy={times={[1]=1.60, [2]=0.80, [3]=0.40}, uses=15, maxlevel=2}, + snappy={times={[2]=0.75, [3]=0.35}, uses=30, maxlevel=1}, + choppy={times={[3]=0.80}, uses=30, maxlevel=0} + }, + damage_groups = {fleshy=6}, + } +}) + +minetest.register_tool("gloopblocks:pick_evil", { + description = S("Evil Pickaxe"), + inventory_image = "gloopblocks_evil_pick.png", + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=3, + groupcaps={ + cracky={times={[1]=0.10, [2]=0.10, [3]=0.10}, uses=10, maxlevel=2} + }, + damage_groups = {fleshy=6}, + }, +}) + +minetest.register_tool("gloopblocks:shovel_evil", { + description = S("Evil Shovel"), + inventory_image = "gloopblocks_evil_shovel.png", + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=3, + groupcaps={ + crumbly={times={[1]=0.05, [2]=0.05, [3]=0.05}, uses=10, maxlevel=2} + }, + damage_groups = {fleshy=6}, + }, +}) + +minetest.register_tool("gloopblocks:axe_evil", { + description = S("Evil Axe"), + inventory_image = "gloopblocks_evil_axe.png", + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=3, + groupcaps={ + choppy={times={[1]=0.15, [2]=0.15, [3]=0.15}, uses=10, maxlevel=2}, + fleshy={times={[1]=0.15, [2]=0.15, [3]=0.15}, uses=10, maxlevel=2} + }, + damage_groups = {fleshy=6}, + }, +}) + +minetest.register_tool("gloopblocks:sword_evil", { + description = S("Evil Sword"), + inventory_image = "gloopblocks_evil_sword.png", + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=3, + groupcaps={ + fleshy={times={[1]=0.20, [2]=0.20, [3]=0.20}, uses=10, maxlevel=2}, + snappy={times={[1]=0.20, [2]=0.20, [3]=0.20}, uses=10, maxlevel=2}, + choppy={times={[1]=0.20, [2]=0.20, [3]=0.20}, uses=10, maxlevel=2} + }, + damage_groups = {fleshy=8}, + } +}) + +-- Other items + +minetest.register_craftitem("gloopblocks:evil_stick", { + description = S("Evil Stick"), + inventory_image = "gloopblocks_evil_stick.png", +}) + + +local fence_texture = + "default_fence_overlay.png^default_steel_block.png^default_fence_overlay.png^[makealpha:255,126,126" + +minetest.register_node("gloopblocks:fence_steel", { + description = S("Steel Fence"), + drawtype = "fencelike", + tiles = {"default_steel_block.png"}, + inventory_image = fence_texture, + wield_image = fence_texture, + paramtype = "light", + sunlight_propagates = true, + is_ground_content = false, + selection_box = { + type = "fixed", + fixed = {-1/7, -1/2, -1/7, 1/7, 1/2, 1/7}, + }, + groups = {choppy = 2, oddly_breakable_by_hand = 2 }, + sounds = default.node_sound_stone_defaults(), +}) + +minetest.register_alias("nyancat:nyancat_rainbow", "gloopblocks:rainbow_block_horizontal") +minetest.register_alias("default:nyancat_rainbow", "gloopblocks:rainbow_block_horizontal") diff --git a/mods/gloopblocks/models/gloopblocks_ash_pile.obj b/mods/gloopblocks/models/gloopblocks_ash_pile.obj new file mode 100644 index 00000000..5b9c084e --- /dev/null +++ b/mods/gloopblocks/models/gloopblocks_ash_pile.obj @@ -0,0 +1,197 @@ +# Blender v2.73 (sub 0) OBJ File: 'anthill.blend' +# www.blender.org +o Cylinder_Cylinder.001 +v 0.099056 -0.499969 -0.498228 +v 0.038417 -0.200463 -0.141682 +v 0.255808 -0.499933 -0.402046 +v 0.095605 -0.174690 -0.147239 +v 0.423075 -0.499913 -0.296918 +v 0.102439 -0.169033 -0.075679 +v 0.444026 -0.499843 -0.095234 +v 0.125298 -0.217477 -0.063343 +v 0.468682 -0.499958 0.074790 +v 0.157655 -0.214352 0.001348 +v 0.396548 -0.500000 0.246048 +v 0.133778 -0.189245 0.108513 +v 0.280708 -0.500000 0.383197 +v 0.070517 -0.218946 0.104754 +v 0.089852 -0.499943 0.434316 +v 0.048523 -0.205247 0.128681 +v -0.093309 -0.499902 0.467111 +v -0.039037 -0.211895 0.149030 +v -0.272965 -0.499875 0.396496 +v -0.108297 -0.175918 0.104100 +v -0.388317 -0.499877 0.239075 +v -0.139068 -0.179051 0.073370 +v -0.437531 -0.499999 0.063918 +v -0.141812 -0.255882 0.005117 +v -0.458429 -0.499805 -0.104397 +v -0.189265 -0.217436 -0.065303 +v -0.385597 -0.499914 -0.288584 +v -0.112692 -0.207830 -0.096879 +v -0.248347 -0.499927 -0.384586 +v -0.083136 -0.202256 -0.170048 +v -0.095346 -0.499958 -0.514449 +v -0.023049 -0.216681 -0.204058 +v 0.071880 -0.343843 -0.343933 +v 0.189128 -0.354687 -0.277980 +v 0.311273 -0.378789 -0.248498 +v 0.296760 -0.346318 -0.056661 +v 0.332231 -0.342427 0.044933 +v 0.259921 -0.360316 0.147910 +v 0.213270 -0.362883 0.253745 +v 0.059007 -0.360067 0.351374 +v -0.068448 -0.357957 0.335642 +v -0.164888 -0.343166 0.232553 +v -0.269761 -0.352370 0.140734 +v -0.367168 -0.370891 0.062326 +v -0.294491 -0.324099 -0.079712 +v -0.276314 -0.352585 -0.236032 +v -0.206169 -0.372829 -0.314307 +v -0.065547 -0.371444 -0.355380 +v 0.000709 -0.156135 -0.047193 +vt 0.572002 0.826281 +vt 0.535907 0.620231 +vt 0.597591 0.625892 +vt 0.604963 0.552988 +vt 0.830215 0.729053 +vt 0.629619 0.540419 +vt 0.814561 0.533613 +vt 0.664520 0.474514 +vt 0.638766 0.365335 +vt 0.774826 0.325198 +vt 0.570532 0.369165 +vt 0.724507 0.217375 +vt 0.546808 0.344788 +vt 0.452364 0.324057 +vt 0.420641 0.133939 +vt 0.377660 0.369831 +vt 0.316619 0.238965 +vt 0.344469 0.401138 +vt 0.203502 0.332509 +vt 0.341509 0.470674 +vt 0.290325 0.542416 +vt 0.176827 0.557096 +vt 0.372919 0.574586 +vt 0.196433 0.716353 +vt 0.404798 0.649130 +vt 0.469609 0.683778 +vt 0.272092 0.796098 +vt 0.770390 0.885486 +vt 0.973405 0.572910 +vt 0.591386 0.033412 +vt 0.226599 0.867698 +vt 0.423770 0.837943 +vt 0.601314 0.983475 +vt 0.078559 0.769893 +vt 0.000000 0.582245 +vt 0.098436 0.412390 +vt 0.075624 0.232320 +vt 0.200045 0.071942 +vt 0.558116 0.117912 +vt 0.922195 0.225217 +vt 0.852821 0.430110 +vt 0.698467 0.759089 +vt 0.495235 0.523967 +vt 0.391629 1.000000 +vt 0.022541 0.410768 +vt 0.797247 0.085491 +vt 0.393825 0.000000 +vt 0.950807 0.778383 +vt 1.000000 0.399692 +g Cylinder_Cylinder.001_None +s 1 +f 33/1 2/2 4/3 +f 4/3 6/4 35/5 +f 35/5 6/4 8/6 +f 36/7 8/6 10/8 +f 10/8 12/9 38/10 +f 12/9 14/11 39/12 +f 39/12 14/11 16/13 +f 16/13 18/14 41/15 +f 18/14 20/16 42/17 +f 20/16 22/18 43/19 +f 43/19 22/18 24/20 +f 24/20 26/21 45/22 +f 26/21 28/23 46/24 +f 46/24 28/23 30/25 +f 32/26 2/2 33/1 +f 47/27 30/25 32/26 +f 3/28 7/29 15/30 +f 29/31 47/27 48/32 +f 48/32 33/1 1/33 +f 27/34 46/24 47/27 +f 25/35 45/22 46/24 +f 44/36 45/22 25/35 +f 21/37 43/19 44/36 +f 42/17 43/19 21/37 +f 41/15 42/17 19/38 +f 15/30 40/39 41/15 +f 39/12 40/39 15/30 +f 11/40 38/10 39/12 +f 37/41 38/10 11/40 +f 7/29 36/7 37/41 +f 35/5 36/7 7/29 +f 3/28 34/42 35/5 +f 33/1 34/42 3/28 +f 4/3 2/2 49/43 +f 2/2 32/26 49/43 +f 32/26 30/25 49/43 +f 30/25 28/23 49/43 +f 28/23 26/21 49/43 +f 26/21 24/20 49/43 +f 24/20 22/18 49/43 +f 22/18 20/16 49/43 +f 20/16 18/14 49/43 +f 18/14 16/13 49/43 +f 16/13 14/11 49/43 +f 14/11 12/9 49/43 +f 12/9 10/8 49/43 +f 10/8 8/6 49/43 +f 8/6 6/4 49/43 +f 6/4 4/3 49/43 +f 34/42 33/1 4/3 +f 34/42 4/3 35/5 +f 36/7 35/5 8/6 +f 37/41 36/7 10/8 +f 37/41 10/8 38/10 +f 38/10 12/9 39/12 +f 40/39 39/12 16/13 +f 40/39 16/13 41/15 +f 41/15 18/14 42/17 +f 42/17 20/16 43/19 +f 44/36 43/19 24/20 +f 44/36 24/20 45/22 +f 45/22 26/21 46/24 +f 47/27 46/24 30/25 +f 48/32 32/26 33/1 +f 48/32 47/27 32/26 +f 29/31 31/44 1/33 +f 23/45 27/34 29/31 +f 27/34 23/45 25/35 +f 15/30 19/38 21/37 +f 11/40 13/46 15/30 +f 15/30 17/47 19/38 +f 3/28 23/45 29/31 +f 29/31 1/33 3/28 +f 3/28 5/48 7/29 +f 7/29 9/49 11/40 +f 23/45 15/30 21/37 +f 15/30 23/45 3/28 +f 15/30 7/29 11/40 +f 31/44 29/31 48/32 +f 31/44 48/32 1/33 +f 29/31 27/34 47/27 +f 27/34 25/35 46/24 +f 23/45 44/36 25/35 +f 23/45 21/37 44/36 +f 19/38 42/17 21/37 +f 17/47 41/15 19/38 +f 17/47 15/30 41/15 +f 13/46 39/12 15/30 +f 13/46 11/40 39/12 +f 9/49 37/41 11/40 +f 9/49 7/29 37/41 +f 5/48 35/5 7/29 +f 5/48 3/28 35/5 +f 1/33 33/1 3/28 diff --git a/mods/gloopblocks/textures/gloopblocks_ashes.png b/mods/gloopblocks/textures/gloopblocks_ashes.png new file mode 100644 index 0000000000000000000000000000000000000000..38a300087684b9804239eef4908ff554cdb6ea4d GIT binary patch literal 564 zcmV-40?Yl0P)nQsb0|Wgh@cuuN-az6Ax%6(aE8P2 z4u1d7_m9u#^XYVISr&$2k|b%GCI~{UR@-bgQ55k!4_4A1kru9r$B&+{mXVp;a_cmzRkxm^1F z{_%JO0ALtKQB)8FpwVb3iV{UpB9U0H*BFMGrg=J@T-P0s$G6+9*=(AoiR1X|^@0!r z2qDX|EXyVm3D5HwhDoJTj^hl6Lq$v|LgsC$v=HSoOfIw;QM|M1cD$u9uLp+ z-tTv@SoD2gQIy|1mdoY){a&e5IF7Sz8^n3X_4xw=e|i6P#;+&<0000 zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3&sa^%X9g#YI$bcEcOPPqa3hm`cqpXUk7)vH8wPwa?FUbT;09?@xTc;`49U zjsJY%xfD2t=VRXQ{hjOS>w)r)iOGt-oNoad}p?QevXA;ti*W18^41K_WtXinS%aY==az;i`@8}>$@I8NPou9{0iM) z0$Be={Oo-12w&lN2KsC(|A^Cj-KD?B??&nSikyFM@n2uu6>Yoi_n&X^J7?8%_OrVl z!BLC(-PC7`_lz3{;SBe&%x~c@abE6k!f`AOhOgnr%e#e^1CsN`dkxxi)rYc1~1+cY1ORc2m}JH2Bta{T+R z`FY|0`up2J=LqJ`DVX(%73=cC7t2uQ^e=aj5O>~~rW;>po`e1Qqr?U>m~NOW8|-#G zLyY9UuoZ5egH488<6F|MtakuH#N3I+xIhMMb|Ja!Z1KK0M;t5p>8#uX`#}a=GRZGi z>0=0)R$FVmGii^Vu{!s6E(|}yh$D?W z%BZ7_K7r4SGtE59th3F&{0a*SFe|UJ>T0WRw}H}*JMFy7uDk7iz}g8Xo^B?$5maC2Ol+ zx(zo$szPE4Lk7z4l+}IZKjh>&hHX77<@c3(!)v@(;~0xWw+wYoTzA&tdbOvrD}D02FtIB-@5_*~-lt7D z^qk0TE<2u;N6K!@Gu9bHA8UyR)DmPp=5h%d{v9Oc?agr$l(FT?uAZ;YJ9}#p-72d! z$C}HE#gzj3MyuKV*rhX{?ULDhn(CWtFoEvb!m4J9W$53SyiVO0kR`(uv)^GVWKNHMRRP(po|8`56Gp$WI zRjT16Z@y#{`le+ss~zk zKWm5Sa4-9ABSzNCns0&Ren!*=TMi=_@J+6?9c6a`5||OTQgYYcdBt1nwA$f>ibj>73wi zaV|kGdw}_|_g)offMp+dO^}o)0yCd()*-c8pigk37tgwq*?!-fXG8NwyFSaCF*s1Pg7Aw39gf5E8R2G+X1rD zve~=VJ<5S&A^n*&b2enlDKM8$jhdPhuq>J=5ISoPciS7ynNN6_;gjj!i4hvQr4|f= za>b%S(tjF6L_?H`%Za_&&`kR~w7(sh)KX*jVPfP60})Ij)+GT1q-H&(=k@lK-p9LQKd2@XUTSV7XD!BJ%=J5(P*S(KPPcpNND z4zqa$%pYeofPzY1Hia4>s`-F%0=A>|Q;p!s492GTOhBw#od>aVZTk_sZAC>B$Ou8d z->`OZK+PUHYmfFpAkYpzY9>{x!DD9GnlFPDm`uwLmBkBSm&^zjd$R)$BPX-%wnS23 z(}_|bHcAOMcM*IN#k&9iZa{aRh8QcXW591?4!l%J>T0NaOc1M*jztv=Mk}I$TdPNh zho5VOo2{{vxMX+H)#vA+COdLFodHa@&1Mq1HhvvPD~sJYcaY|8x0s>qZ^({ zwrEqYn6aVG>A3_onA{r{8(UO`84N0JeGSxov_j5?Fp61{JsQANoUKrkO{;HDs59q= z9NE>x*`)CDRG#>5#3W)q5Jr?88qVzvH;OO$$JY({9SC4KLV3cNrb{Um`$`t30*g~4 zH3y$bFd;P0`2}Gr&?BLk@{F(#YxTL}Y@jx0`f_Xb8W&U$V!;DJ6=i!Spu-r_MyQRdP#85v5f9Qs z^j$TNOn2`h&2Qc=u1pMkqwCnTG&|WwOQd=(cWoH?qhRAH!Chd5?0d~^;9Po)v5|^2 zS48=;DiN*4i{IkiW8uH(lly6b`o1__m(;`+bYQzihhxJw;AQ8vx^6#@ChECJf-k+$ zOr+WIpBZ!lUmO7gx6mG+IMVl%MEMJW0=J(XGLA6ua> z*ufyz=QFAX?E%LK=upM;jnpV$vY@cMc(Na8(4nx^X&!>2|IIY1+pBcj4`$qzl)_<` zH~Fed+1@AyI%9c=BZj2csK62X9t({SicEADnn}0<6df;fi=;@E(0)AJ?VPBUz!ZDB+;+@l4NFHr*lk3N=~wk`8XXo> zz#6MirwEcTHPDBs(vZRh)Zhv(L$mEN&3*kKbLOsc2K04wn_Ej59Srl>_hrbS_eRF2 z-j!VAwe`rJ0dw3}_2C-!cD-_1F5Et5^KbZ4>AT?M^1!r%ib zw<;-05LJ=(5fox^naqfv`3BKeCy5U#MG&IvmmAT`9ppf5A9CXJoRI6p^HIZXR}w6B z6DCc{9^ywjI!fQ5bmmWBsnJk1fgM9Nqg{e#n*c`dzrjR{&Z~`;P+@$FS)mq57=z~9 zaMJMW<;6w?=t;q+3f|IJ!Cv3o80AgJ3@OoB-K|YvMFM(LSCp2@BR_p)yL-p`BLU5; z4sp>qCTu;+0*g>Q&yXwfh|`DmV31AeJh;HUC#`=*ZfdQG~!GfgXR|3j+}N*Ryt6075{vS?pX zjn$Q-DXb8jk6VJ7**2R1Ax3yf7h32RRdPhx_twps^g;%BTr;B=Rcs40=7M?y zXxFPPI0Mj6ah8*Dp43tdESYL}y(W z5X;-=SG~{N>($jh5lK35b#kPOY(X+AqI1(fXrSu;h-S}m*-2!X6pMc2;`~-2s+GTH zjFzj7nN-s-V!H1~&AY%oBQadhYtg2cMPfkqOtUnxeH6|E3LFCX>GXdLYlGsv$vN6j zlI{(4Tv(3e3K&Nz?p4fvXpaS3`k#CWRwacPm!-))=LKj^?zplCGMjR`zHR?;Q9XbI*WTEdMObaXn8(fLo7 zQS0?DMlC^ABPTfOt(GQ?@Rq-AaxKq7xQd>vubHfRyrq_k{ir$qK9m186P5G451rdP z&ZL)f>HRuh;cgLqJvlv*>;dh^yFc&No4m#2Uo)1NHZFNmk#Gj^f2QNfc3=lUSLQ~f zJ8t9}?Dvxmtpnx|8yeB@`!Z%V^G`;wxAJ+*NUQ(=0fcEoLr_UWLm+T+Z)Rz1WdHzp zoPCi!NW(xJ#b48kA50X4BF+?-PeuQBsJ{ ziN_4OAn_yDWtZPL7aSINX2?h<=ZQnaVxf)YHfBXbC7vb@E2>8MLdIo<^A=~dTxHFB z@)rhk+DeM+G=~wx65>cegp4XmD8oX8R*e)BN!pKk_=g;Sf?P7WN?_zzKm{r!#}EDo zzq>W_Qz7U)@Xdu#6F^Z`gySIalR!67hOpzL*zcXze- z_V1Zye?Leja+ZXJAZh>r00v@9M??Vs0RI60puMM)00009a7bBm000ie000ie0hKEb z8vp^^DvVw$gVi5&d&I<$)q{uv2SP4WZ0y}w0qzDLW%u0v|Y!nj7@Ia6vkRl)# z@?sGpOe~SLgLh*uli8h}nLd4PRrT?3dU|_1-krr8D=SJWb@w@Sx~u-*|NsBKs#YNc zZq$rP1Qb`h%4@|oZISyuW9quk+~MgiUj_RE&NqUL>{_>xje^Jbed=7#rw>ERE` z_Vxr3!8t>}?{JA>G|K4@GXCIGA5}?~UH5r=^b{130C53;Lofov++mEyI!*4n$(DdN zk$#@=R=3^VlCtywG)<)S0j)J{8>!0n$meeo06mZR)z$&hOD%)kvN1~NrxpQRTVm1BL(wjwGsfL46 z)3*AS00Cf8wx zqHZIV7baCes}=F~oX+etyC=27w8!R;5Ae}CM-w#~^7HAhDX_qG0E=25b5whS5H)EP= z>6+X&0O+e4*9(SsI6*sOhcNla#}~lhh)AlX&H`w1oviXh1Hdm))GQP~5eSGh4BmAI z7yjze4utFzh?Fzd9I_`a(BCgGN){LpXXE`se@oGjqq@B|g3C0WPqJH@z^l(a%3Z&{ z7-_QIs3kds1)0SKuQ5FN&B7_CtXCX<@sFk|b)D*D>!T&?r}^G_c_tFF{7 z%7$s#P?R-ARa2A=McK@M?ZsyvTGIY97-r@rc9vc2oH-&wk|dlxd-ew<2l<(|zlUST zNBqeBcX8i+C%ErzTiki-7^`aoTw*zSYK=TkSXmjMmd^w7JeO`mqYx1ueDFc;x%(cB zFpA)-QUe`j)J>#qBO;)bfRfHUl-xQ1bL&!y z7$aJ1(j>)bgSrWX&z-x-`mrIC%Qd}z1_&{FUi#J!Nn%J+Ax5xPsH=u@>N(hNh%w^B z(Gxy-YQSJvlVy%Pw;W7cWM-^I<^S({fzfCrZQBw;nA84nq1RimQVL@X&N()Zy^~AZ zp1h|yej?%IsUZMg`1?QOTYvtm2*Qv3+F$VQcYS~?v%LP=0d*bN-0E@vk8bhu%a_nf z(H~@Jtq38awPIsqOqLn`;fpWfeWb1<#wfN<^f-BPl`M03ADB!kilRZO?%5C`Nn%+) zHehRO%#*+OJDt&7j{)9$y!R}cp@_WU`$Ygk2zc)ifh1M5t>6;F*T1quJ?)I5f~0r>bhlRoO9vTlCp@zASewx z+cg(opE4LY1gJ_+U3V3x)`}Q}yl1H@PdROlmVo!3Mb}?8!|UdnnNc3!%yF*9IYpLP ztW(f~gFR@QfSHM`X#xl&iN^atl4`OnVZ4&^dCJYL0LANK(hf#sCl$ z24gf)uGSEjcPG5#!PA`kuWcrimL$<6sbxIQ7>#o3x+}!?_bbY>#ad0jpRl>L!rJP9 z$xWQf+9XLZ#w<{}D@eFtnVwW55$1I>Xn# z`faZ4R-FBlFH=kcr{6Y4Yek)TLJ-=v1Nc3U+>iId=bn2J@I3zEpTqme&i8g14*T@` zDI(w!!(fmw8u!pjao1fNWO+hS)a>sS?Cni)t^=|tDzYrOIRMf$MMS8oiWnnlnsO)& zfPTMEjFGY|QA&}fDb6{(_f%645v*0TZRDPN$A~DN`^&FW*MX)ED6JT+T2@zkyz=rT zrc+On8rs(5oWXneyXRj*p%5&8_{o3a{lD>3SgZNQH_lT`TIwobokDBH>RQRx)`;CJ z6IRs#Yc);d(OR>=UlF5_=LzN}>I&PoEh1e>T9#KSv&aCgH8Do&x}Hno&^+5V(zZg9 zbVZHUitoI#$IkyWcrWw@hT+IEUP-CzZhQCx|J?C(#xv@@ZqS`H2>dc6ea497QD81%EF0jR2qMIQj>QaEgf zpAWA!O*7k71&q@)bw_Dy72n$~sH#8+f=d*~Hd4kbDaVg@TAxk>RT)ULz{QJun3--N z@V@u|B*6#%`q^(HQ80;SJWkoz=&`$7;e8}Y46Ca-BEn=+Qk4x&(-l)82zBil3^I&S zSbKCytc)?TY;uo0@(4+i@a(hCUSo-8GukGyzvpS& z4v_x9vT?je2!V}_9{={jHpVKlOmpw)F?pV1t;HpVx(=vW#!yO7T1b*`9 z3|U|>N?Bd$F&gDKXW8GMa&S;#onbi0P`V4~nNNTGnmS-Pv)Lz}cmnS|#&qQ_zyl9F z0Kn$v=3EYkSt83aoO6_AN!zw)y+a5B0!Bm82vr%GP6EDx9nCoyrYTx$s;a{K z&PZN(;RUqT7}Mq1!^$sB(>VanIrjGUm`+<_fVP$HIK1^li74G^IeKWKu(#WC<;sNM zBgR5qdr*N37Yek}G)=_&$Y`8kj3P}HA$q>}v3HVKix1F*hypU#rAr?p3L$d_ABDzu z(aoGeB;sSZ@&ArWVGr|tF)5f76Pmi2m&HDK6bh|1+Gs|@5o_yftgo-nvxL?iRh5EE zI}P`q?y*(|iXu`Rc$!-9Ua(Hl)B$6KrWUNx)Kv>a%Chr}JhvDl42Bk^pw}~8-fyrr z5CZtv{f@H=i84#eg0q?!!3RN5IID<}xu-2xv9mWQ;C}(D1ARi3wXAUf0000 b end end local s = {} for k, v in pairs(t) do @@ -146,13 +146,14 @@ local function add_ores() local count drop, count = parse_drop(drop) - local probability = calculate_probability(item) / count + local probability = calculate_probability(item) if probability > 0 then + local probabilityFraction = count / probability local cur_probability = gravelsieve.ore_probability[drop] if cur_probability then - gravelsieve.ore_probability[drop] = harmonic_sum(cur_probability, probability) + gravelsieve.ore_probability[drop] = cur_probability+probabilityFraction else - gravelsieve.ore_probability[drop] = probability + gravelsieve.ore_probability[drop] = probabilityFraction end end end @@ -161,13 +162,117 @@ local function add_ores() minetest.log("action", "[gravelsieve] ore probabilties:") local overall_probability = 0.0 for name,probability in pairs_by_values(gravelsieve.ore_probability) do - minetest.log("action", ("[gravelsieve] %-32s: 1 / %.02f"):format(name, probability)) - overall_probability = overall_probability + 1.0/probability + minetest.log("action", ("[gravelsieve] %-32s: 1 / %.02f"):format(name, 1.0/probability)) + overall_probability = overall_probability + probability end minetest.log("action", ("[gravelsieve] Overall probability %f"):format(overall_probability)) end -minetest.after(1, add_ores) +local function default_configuration() + local normal_gravel = "default:gravel" + local sieved_gravel = "gravelsieve:sieved_gravel" + local gravel_probabilities = table.copy(gravelsieve.ore_probability) + local overall_probability = 0 + for _,v in pairs(gravel_probabilities) do + overall_probability = overall_probability+v + end + local remainder_probability = 0 + if overall_probability < 1 then + remainder_probability = 1-overall_probability + end + gravel_probabilities[normal_gravel] = remainder_probability/2.0 + gravel_probabilities[sieved_gravel] = remainder_probability/2.0 + + return { + [normal_gravel] = gravel_probabilities, + [sieved_gravel] = { + [sieved_gravel] = 1 + } + } +end + +local function normalize_probabilities(conf) + local total = 0 + for _,val in pairs(conf) do + if val >= 0 then + total = total + val + end + end + local normalized = {} + for key,val in pairs(conf) do + if val >= 0 then + normalized[key] = val/total + end + end + return normalized +end + +local function normalize_config(current_config) + local normalized_config = {} + -- Normalize all inputs so their output probabilities always add up to 1 + for input, output_probabilities in pairs(current_config) do + if output_probabilities then + normalized_config[input] = normalize_probabilities(output_probabilities) + end + end + return normalized_config +end + +local function merge_config(def_conf, new_conf) + local result_conf = table.copy(def_conf) + for key,val in pairs(new_conf) do + if type(val) == 'table' and type(result_conf[key]) == 'table' then + result_conf[key] = merge_config(result_conf[key], val) + else + result_conf[key] = val + end + end + return result_conf +end + +local function configure_probabilities_step(current_config, funct_or_table) + local var_type = type(funct_or_table) + local conf + if var_type == 'function' then + conf = funct_or_table() + elseif var_type == 'table' then + conf = funct_or_table + end + if conf then + return merge_config(current_config, conf) + end + return current_config +end + +local configured = false +local set_probabilities = {default_configuration} + +function gravelsieve.set_probabilities(funct_or_table) + if configured then + -- This is here so you can do hard overrides after everything has loaded if you need to + -- Otherwise the order mods are loaded may cause them to override your configs + local current_config = gravelsieve.process_probabilities + current_config = configure_probabilities_step(current_config, funct_or_table) + gravelsieve.process_probabilities = normalize_config(current_config) + else + -- Build up a list of callbacks to be run after all mods are loaded + table.insert(set_probabilities, funct_or_table) + end +end + +local function configure_probabilities() + configured = true + add_ores() + local current_config = {} + + -- Run through all configs in order and merge them + for _,funct_or_table in ipairs(set_probabilities) do + current_config = configure_probabilities_step(current_config, funct_or_table) + end + gravelsieve.process_probabilities = normalize_config(current_config) +end + +minetest.after(1, configure_probabilities) local sieve_formspec = "size[8,8]".. @@ -240,47 +345,34 @@ local function swap_node(pos, meta, start) end -- place ores to dst according to the calculated probability -local function random_ore(inv, src) - local num - for ore, probability in pairs(gravelsieve.ore_probability) do - if math.random(probability) == 1 then - local item = ItemStack(ore) - if inv:room_for_item("dst", item) then - inv:add_item("dst", item) - return true -- ore placed +local function move_random_ore(inv, item) + local running_total = 0 + local probabilities = gravelsieve.process_probabilities[item] + local chosen = math.random() + for ore, probability in pairs(probabilities) do + running_total = running_total + probability + if chosen < running_total then + local ore_item = ItemStack(ore) + if not inv:room_for_item("dst", ore_item) then + return false end + inv:add_item("dst", ore_item) + return true end end - return false -- gravel has to be moved + return false -- Failure, this shouldn't really happen but might due to floating point errors end - -local function add_gravel_to_dst(meta, inv) - -- maintain a counter for gravel kind selection - local gravel_cnt = meta:get_int("gravel_cnt") + 1 - meta:set_int("gravel_cnt", gravel_cnt) - - if (gravel_cnt % 2) == 0 then -- gravel or sieved gravel? - inv:add_item("dst", ItemStack("default:gravel")) -- add to dest - else - inv:add_item("dst", ItemStack("gravelsieve:sieved_gravel")) -- add to dest - end -end - - -- move gravel and ores to dst -local function move_src2dst(meta, pos, inv, src, dst) +local function move_src2dst(meta, pos, inv, item, dst) + local src = ItemStack(item) if inv:room_for_item("dst", dst) and inv:contains_item("src", src) then local res = swap_node(pos, meta, false) if res then -- time to move one item? - if src:get_name() == "default:gravel" then -- will we find ore? - if not random_ore(inv, src) then -- no ore found? - add_gravel_to_dst(meta, inv) - end - else - inv:add_item("dst", ItemStack("gravelsieve:sieved_gravel")) -- add to dest + local processed = move_random_ore(inv, item) + if processed then + inv:remove_item("src", src) end - inv:remove_item("src", src) end return true -- process finished end @@ -291,19 +383,16 @@ end local function sieve_node_timer(pos, elapsed) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() - local gravel = ItemStack("default:gravel") - local gravel_sieved = ItemStack("gravelsieve:sieved_gravel") - if move_src2dst(meta, pos, inv, gravel) then - aging(pos, meta) - return true - elseif move_src2dst(meta, pos, inv, gravel_sieved) then - aging(pos, meta) - return true - else - minetest.get_node_timer(pos):stop() - return false + for item,probabilities in pairs(gravelsieve.process_probabilities) do + if probabilities and move_src2dst(meta, pos, inv, item) then + aging(pos, meta) + return true + end end + + minetest.get_node_timer(pos):stop() + return false end @@ -356,7 +445,7 @@ for idx = 0,4 do local meta = minetest.get_meta(pos) swap_node(pos, meta, true) else - minetest.get_node_timer(pos):start(1.0) + minetest.get_node_timer(pos):start(STEP_DELAY) end return inv:add_item("src", stack) end, @@ -425,7 +514,7 @@ for idx = 0,4 do local meta = minetest.get_meta(pos) swap_node(pos, meta, true) else - minetest.get_node_timer(pos):start(1.0) + minetest.get_node_timer(pos):start(STEP_DELAY) end end, @@ -440,7 +529,7 @@ for idx = 0,4 do meta:set_int("gravel_cnt", 0) end else - minetest.get_node_timer(pos):start(1.0) + minetest.get_node_timer(pos):start(STEP_DELAY) end end, @@ -449,7 +538,7 @@ for idx = 0,4 do local meta = minetest.get_meta(pos) swap_node(pos, meta, true) else - minetest.get_node_timer(pos):start(1.0) + minetest.get_node_timer(pos):start(STEP_DELAY) end end, @@ -559,7 +648,7 @@ if minetest.global_exists("tubelib") then return tubelib.get_item(meta, "dst") end, on_push_item = function(pos, side, item) - minetest.get_node_timer(pos):start(1.0) + minetest.get_node_timer(pos):start(STEP_DELAY) local meta = minetest.get_meta(pos) return tubelib.put_item(meta, "src", item) end, @@ -568,7 +657,7 @@ if minetest.global_exists("tubelib") then return tubelib.put_item(meta, "dst", item) end, on_node_load = function(pos) - minetest.get_node_timer(pos):start(1.0) + minetest.get_node_timer(pos):start(STEP_DELAY) end, on_node_repair = function(pos) local meta = minetest.get_meta(pos) @@ -579,7 +668,7 @@ if minetest.global_exists("tubelib") then inv:set_size('src', 1) inv:set_size('dst', 16) swap_node(pos, meta, false) - minetest.get_node_timer(pos):start(1.0) + minetest.get_node_timer(pos):start(STEP_DELAY) return true end, }) diff --git a/mods/vehicle_mash/README.md b/mods/vehicle_mash/README.md index 872184c1..82148703 100755 --- a/mods/vehicle_mash/README.md +++ b/mods/vehicle_mash/README.md @@ -1,6 +1,6 @@ # Vehicle Mash [![Build status](https://github.com/minetest-mods/vehicle_mash/workflows/build/badge.svg)](https://github.com/minetest-mods/vehicle_mash/actions) [![ContentDB](https://content.minetest.net/packages/Panquesito7/vehicle_mash/shields/downloads/)](https://content.minetest.net/packages/Panquesito7/vehicle_mash/) -- Current version: 2.2.2 +- Current version: 2.3.0 - By [blert2112](https://github.com/blert2112), and handed over to [Panquesito7](https://github.com/Panquesito7). ![Screenshot](https://raw.githubusercontent.com/minetest-mods/vehicle_mash/master/screenshot.png) @@ -67,6 +67,18 @@ There are no pending tasks to do yet. ## Changelog +v2.3.0 2/12/2021 + +- Improved formatting in `README.md`. +- Added [API Mode](https://github.com/minetest-mods/vehicle_mash/commit/6b3bdac4d880a6fde298a286b3bd5043750e904e) setting. +- Removed F1 and 126r cars due to closed-source license. +- Improved vehicle drops. + - Vehicles can now drop multiple items. +- Add option for vehicles to fly (setting per vehicle). +- Can enable/disable crash separately for each vehicle. +- Added ContentDB badge on `README.md`. +- Improved GitHub workflow. + v2.2.2 6/02/2020 - Fix passengers not detaching when driver gets out. diff --git a/mods/vehicle_mash/framework.lua b/mods/vehicle_mash/framework.lua index 5348e99f..38be829b 100644 --- a/mods/vehicle_mash/framework.lua +++ b/mods/vehicle_mash/framework.lua @@ -26,7 +26,7 @@ function vehicle_mash.register_vehicle(name, def) passenger3_eye_offset = def.passenger3_eye_offset, passenger3_detach_pos_offset = def.passenger3_detach_pos_offset, - enable_crash = def.enable_crash or true, + enable_crash = def.enable_crash, visual = def.visual, mesh = def.mesh, textures = def.textures, @@ -140,6 +140,10 @@ function vehicle_mash.register_vehicle(name, def) end end, on_step = function(self, dtime) + -- Automatically set `enable_crash` to true if there's no value found + if def.enable_crash == nil then + def.enable_crash = true + end drive(self, dtime, false, nil, nil, 0, def.can_fly, def.can_go_down, def.can_go_up, def.enable_crash) end }) -- 2.25.1 From 42a97930ec1a25dae56072c60a178548895acf4e Mon Sep 17 00:00:00 2001 From: root Date: Fri, 19 Feb 2021 14:15:18 +0100 Subject: [PATCH 6/7] update --- mods/advtrains/advtrains/api_doc.txt | 4 +- mods/advtrains/advtrains/atc.lua | 93 ++-- mods/advtrains/advtrains/copytool.lua | 132 +++--- mods/advtrains/advtrains/couple.lua | 18 +- mods/advtrains/advtrains/debugringbuffer.lua | 5 +- mods/advtrains/advtrains/init.lua | 138 ++++-- mods/advtrains/advtrains/lzb.lua | 285 +++++++----- mods/advtrains/advtrains/nodedb.lua | 17 +- mods/advtrains/advtrains/occupation.lua | 1 - mods/advtrains/advtrains/path.lua | 50 ++- mods/advtrains/advtrains/settingtypes.txt | 11 + mods/advtrains/advtrains/signals.lua | 43 +- mods/advtrains/advtrains/trackplacer.lua | 8 +- mods/advtrains/advtrains/tracks.lua | 2 +- mods/advtrains/advtrains/trainhud.lua | 25 +- mods/advtrains/advtrains/trainlogic.lua | 411 ++++++++++++------ mods/advtrains/advtrains/wagons.lua | 82 ++-- .../advtrains_interlocking/approach.lua | 79 ++-- .../advtrains_interlocking/database.lua | 33 ++ .../advtrains_interlocking/demosignals.lua | 30 +- .../advtrains_interlocking/route_prog.lua | 3 +- .../advtrains_interlocking/route_ui.lua | 2 +- .../advtrains_interlocking/routesetting.lua | 17 +- .../advtrains_interlocking/signal_api.lua | 339 +++++++-------- .../advtrains_interlocking/tcb_ts_ui.lua | 9 +- .../advtrains_line_automation/stoprail.lua | 6 +- .../{README.txt => README.md} | 241 ++++++---- .../advtrains_luaautomation/active_common.lua | 26 +- .../advtrains_luaautomation/atc_rail.lua | 171 +++++--- .../advtrains_luaautomation/chatcmds.lua | 68 ++- .../advtrains_luaautomation/environment.lua | 55 ++- .../advtrains_luaautomation/interrupt.lua | 35 +- .../advtrains_luaautomation/passive_api.txt | 2 +- mods/advtrains/advtrains_signals_ks/init.lua | 62 ++- .../init_degrotate_nodes.lua | 2 +- .../advtrains_signals_ks_sign_pam.png | Bin 0 -> 211 bytes mods/advtrains/atc_command.txt | 13 +- mods/builtin_item/README.md | 2 +- mods/builtin_item/init.lua | 132 ++++-- mods/farming/README.md | 2 +- mods/farming/food.lua | 77 +++- mods/farming/license.txt | 19 +- .../farming/textures/farming_salt_crystal.png | Bin 0 -> 175 bytes mods/gloopblocks/crafts.lua | 15 + mods/playerplus/init.lua | 2 +- mods/playerplus/settingtypes.txt | 2 +- mods/signs_lib/api.lua | 89 +++- mods/signs_lib/encoding.lua | 59 ++- mods/signs_lib/init.lua | 2 +- mods/signs_lib/nonascii-de.lua | 7 + mods/signs_lib/nonascii-fr.lua | 16 + mods/signs_lib/nonascii-pl.lua | 16 + .../textures/signs_lib_font_15px_00c0.png | Bin 0 -> 337 bytes .../textures/signs_lib_font_15px_00c4.png | Bin 0 -> 337 bytes .../textures/signs_lib_font_15px_00c6.png | Bin 0 -> 345 bytes .../textures/signs_lib_font_15px_00c7.png | Bin 0 -> 334 bytes .../textures/signs_lib_font_15px_00c8.png | Bin 0 -> 323 bytes .../textures/signs_lib_font_15px_00c9.png | Bin 0 -> 324 bytes .../textures/signs_lib_font_15px_00ca.png | Bin 0 -> 325 bytes .../textures/signs_lib_font_15px_00d3.png | Bin 0 -> 331 bytes .../textures/signs_lib_font_15px_00d4.png | Bin 0 -> 341 bytes .../textures/signs_lib_font_15px_00d6.png | Bin 0 -> 341 bytes .../textures/signs_lib_font_15px_00d9.png | Bin 0 -> 324 bytes .../textures/signs_lib_font_15px_00dc.png | Bin 0 -> 326 bytes .../textures/signs_lib_font_15px_00df.png | Bin 0 -> 332 bytes .../textures/signs_lib_font_15px_00e0.png | Bin 0 -> 332 bytes .../textures/signs_lib_font_15px_00e4.png | Bin 0 -> 328 bytes .../textures/signs_lib_font_15px_00e6.png | Bin 0 -> 340 bytes .../textures/signs_lib_font_15px_00e7.png | Bin 0 -> 329 bytes .../textures/signs_lib_font_15px_00e8.png | Bin 0 -> 337 bytes .../textures/signs_lib_font_15px_00e9.png | Bin 0 -> 333 bytes .../textures/signs_lib_font_15px_00ea.png | Bin 0 -> 337 bytes .../textures/signs_lib_font_15px_00f3.png | Bin 0 -> 330 bytes .../textures/signs_lib_font_15px_00f4.png | Bin 0 -> 334 bytes .../textures/signs_lib_font_15px_00f6.png | Bin 0 -> 332 bytes .../textures/signs_lib_font_15px_00f9.png | Bin 0 -> 327 bytes .../textures/signs_lib_font_15px_00fc.png | Bin 0 -> 319 bytes .../textures/signs_lib_font_15px_0104.png | Bin 0 -> 339 bytes .../textures/signs_lib_font_15px_0105.png | Bin 0 -> 331 bytes .../textures/signs_lib_font_15px_0106.png | Bin 0 -> 334 bytes .../textures/signs_lib_font_15px_0107.png | Bin 0 -> 329 bytes .../textures/signs_lib_font_15px_0118.png | Bin 0 -> 323 bytes .../textures/signs_lib_font_15px_0119.png | Bin 0 -> 332 bytes .../textures/signs_lib_font_15px_0141.png | Bin 0 -> 319 bytes .../textures/signs_lib_font_15px_0142.png | Bin 0 -> 310 bytes .../textures/signs_lib_font_15px_015a.png | Bin 0 -> 340 bytes .../textures/signs_lib_font_15px_015b.png | Bin 0 -> 330 bytes .../textures/signs_lib_font_15px_0179.png | Bin 0 -> 329 bytes .../textures/signs_lib_font_15px_017a.png | Bin 0 -> 324 bytes .../textures/signs_lib_font_15px_017b.png | Bin 0 -> 329 bytes .../textures/signs_lib_font_15px_017c.png | Bin 0 -> 326 bytes .../textures/signs_lib_font_15px_21.png | Bin 83 -> 305 bytes .../textures/signs_lib_font_15px_22.png | Bin 83 -> 296 bytes .../textures/signs_lib_font_15px_23.png | Bin 97 -> 323 bytes .../textures/signs_lib_font_15px_24.png | Bin 112 -> 332 bytes .../textures/signs_lib_font_15px_25.png | Bin 125 -> 347 bytes .../textures/signs_lib_font_15px_26.png | Bin 120 -> 341 bytes .../textures/signs_lib_font_15px_27.png | Bin 78 -> 299 bytes .../textures/signs_lib_font_15px_28.png | Bin 88 -> 312 bytes .../textures/signs_lib_font_15px_29.png | Bin 88 -> 312 bytes .../textures/signs_lib_font_15px_2a.png | Bin 90 -> 313 bytes .../textures/signs_lib_font_15px_2b.png | Bin 84 -> 309 bytes .../textures/signs_lib_font_15px_2c.png | Bin 79 -> 302 bytes .../textures/signs_lib_font_15px_2d.png | Bin 77 -> 298 bytes .../textures/signs_lib_font_15px_2e.png | Bin 77 -> 298 bytes .../textures/signs_lib_font_15px_2f.png | Bin 93 -> 313 bytes .../textures/signs_lib_font_15px_30.png | Bin 97 -> 316 bytes .../textures/signs_lib_font_15px_31.png | Bin 87 -> 318 bytes .../textures/signs_lib_font_15px_32.png | Bin 113 -> 332 bytes .../textures/signs_lib_font_15px_33.png | Bin 109 -> 334 bytes .../textures/signs_lib_font_15px_34.png | Bin 103 -> 326 bytes .../textures/signs_lib_font_15px_35.png | Bin 109 -> 325 bytes .../textures/signs_lib_font_15px_36.png | Bin 104 -> 331 bytes .../textures/signs_lib_font_15px_37.png | Bin 95 -> 321 bytes .../textures/signs_lib_font_15px_38.png | Bin 104 -> 328 bytes .../textures/signs_lib_font_15px_39.png | Bin 110 -> 332 bytes .../textures/signs_lib_font_15px_3a.png | Bin 77 -> 298 bytes .../textures/signs_lib_font_15px_3b.png | Bin 80 -> 305 bytes .../textures/signs_lib_font_15px_3c.png | Bin 96 -> 322 bytes .../textures/signs_lib_font_15px_3d.png | Bin 80 -> 302 bytes .../textures/signs_lib_font_15px_3e.png | Bin 95 -> 324 bytes .../textures/signs_lib_font_15px_3f.png | Bin 102 -> 329 bytes .../textures/signs_lib_font_15px_40.png | Bin 128 -> 359 bytes .../textures/signs_lib_font_15px_41.png | Bin 117 -> 332 bytes .../textures/signs_lib_font_15px_42.png | Bin 97 -> 324 bytes .../textures/signs_lib_font_15px_43.png | Bin 113 -> 330 bytes .../textures/signs_lib_font_15px_44.png | Bin 104 -> 330 bytes .../textures/signs_lib_font_15px_45.png | Bin 92 -> 315 bytes .../textures/signs_lib_font_15px_46.png | Bin 91 -> 311 bytes .../textures/signs_lib_font_15px_47.png | Bin 118 -> 335 bytes .../textures/signs_lib_font_15px_48.png | Bin 89 -> 313 bytes .../textures/signs_lib_font_15px_49.png | Bin 77 -> 300 bytes .../textures/signs_lib_font_15px_4a.png | Bin 91 -> 319 bytes .../textures/signs_lib_font_15px_4b.png | Bin 114 -> 336 bytes .../textures/signs_lib_font_15px_4c.png | Bin 82 -> 305 bytes .../textures/signs_lib_font_15px_4d.png | Bin 108 -> 333 bytes .../textures/signs_lib_font_15px_4e.png | Bin 103 -> 329 bytes .../textures/signs_lib_font_15px_4f.png | Bin 116 -> 333 bytes .../textures/signs_lib_font_15px_50.png | Bin 99 -> 321 bytes .../textures/signs_lib_font_15px_51.png | Bin 122 -> 338 bytes .../textures/signs_lib_font_15px_52.png | Bin 100 -> 330 bytes .../textures/signs_lib_font_15px_53.png | Bin 111 -> 337 bytes .../textures/signs_lib_font_15px_54.png | Bin 85 -> 312 bytes .../textures/signs_lib_font_15px_55.png | Bin 95 -> 317 bytes .../textures/signs_lib_font_15px_56.png | Bin 103 -> 326 bytes .../textures/signs_lib_font_15px_57.png | Bin 107 -> 328 bytes .../textures/signs_lib_font_15px_58.png | Bin 115 -> 341 bytes .../textures/signs_lib_font_15px_59.png | Bin 105 -> 323 bytes .../textures/signs_lib_font_15px_5a.png | Bin 108 -> 326 bytes .../textures/signs_lib_font_15px_5b.png | Bin 80 -> 301 bytes .../textures/signs_lib_font_15px_5d.png | Bin 80 -> 297 bytes .../textures/signs_lib_font_15px_5e.png | Bin 96 -> 321 bytes .../textures/signs_lib_font_15px_5f.png | Bin 76 -> 290 bytes .../textures/signs_lib_font_15px_60.png | Bin 78 -> 301 bytes .../textures/signs_lib_font_15px_61.png | Bin 102 -> 324 bytes .../textures/signs_lib_font_15px_62.png | Bin 99 -> 324 bytes .../textures/signs_lib_font_15px_63.png | Bin 98 -> 324 bytes .../textures/signs_lib_font_15px_64.png | Bin 105 -> 328 bytes .../textures/signs_lib_font_15px_65.png | Bin 98 -> 327 bytes .../textures/signs_lib_font_15px_66.png | Bin 89 -> 315 bytes .../textures/signs_lib_font_15px_67.png | Bin 101 -> 332 bytes .../textures/signs_lib_font_15px_68.png | Bin 93 -> 322 bytes .../textures/signs_lib_font_15px_69.png | Bin 82 -> 296 bytes .../textures/signs_lib_font_15px_6a.png | Bin 83 -> 302 bytes .../textures/signs_lib_font_15px_6b.png | Bin 103 -> 326 bytes .../textures/signs_lib_font_15px_6c.png | Bin 77 -> 294 bytes .../textures/signs_lib_font_15px_6d.png | Bin 99 -> 315 bytes .../textures/signs_lib_font_15px_6e.png | Bin 93 -> 318 bytes .../textures/signs_lib_font_15px_6f.png | Bin 97 -> 320 bytes .../textures/signs_lib_font_15px_70.png | Bin 100 -> 320 bytes .../textures/signs_lib_font_15px_71.png | Bin 100 -> 325 bytes .../textures/signs_lib_font_15px_72.png | Bin 87 -> 312 bytes .../textures/signs_lib_font_15px_73.png | Bin 100 -> 325 bytes .../textures/signs_lib_font_15px_74.png | Bin 92 -> 315 bytes .../textures/signs_lib_font_15px_75.png | Bin 91 -> 309 bytes .../textures/signs_lib_font_15px_76.png | Bin 98 -> 319 bytes .../textures/signs_lib_font_15px_77.png | Bin 107 -> 332 bytes .../textures/signs_lib_font_15px_78.png | Bin 99 -> 326 bytes .../textures/signs_lib_font_15px_79.png | Bin 102 -> 330 bytes .../textures/signs_lib_font_15px_7a.png | Bin 95 -> 319 bytes .../textures/signs_lib_font_15px_7b.png | Bin 88 -> 321 bytes .../textures/signs_lib_font_15px_7c.png | Bin 67 -> 289 bytes .../textures/signs_lib_font_15px_7d.png | Bin 87 -> 317 bytes .../textures/signs_lib_font_15px_7e.png | Bin 87 -> 311 bytes .../textures/signs_lib_font_31px_00c0.png | Bin 0 -> 391 bytes .../textures/signs_lib_font_31px_00c4.png | Bin 0 -> 391 bytes .../textures/signs_lib_font_31px_00c6.png | Bin 0 -> 393 bytes .../textures/signs_lib_font_31px_00c7.png | Bin 0 -> 412 bytes .../textures/signs_lib_font_31px_00c8.png | Bin 0 -> 346 bytes .../textures/signs_lib_font_31px_00c9.png | Bin 0 -> 343 bytes .../textures/signs_lib_font_31px_00ca.png | Bin 0 -> 346 bytes .../textures/signs_lib_font_31px_00d3.png | Bin 0 -> 387 bytes .../textures/signs_lib_font_31px_00d4.png | Bin 0 -> 391 bytes .../textures/signs_lib_font_31px_00d6.png | Bin 0 -> 391 bytes .../textures/signs_lib_font_31px_00d9.png | Bin 0 -> 360 bytes .../textures/signs_lib_font_31px_00dc.png | Bin 0 -> 360 bytes .../textures/signs_lib_font_31px_00df.png | Bin 0 -> 389 bytes .../textures/signs_lib_font_31px_00e0.png | Bin 0 -> 392 bytes .../textures/signs_lib_font_31px_00e4.png | Bin 0 -> 384 bytes .../textures/signs_lib_font_31px_00e6.png | Bin 0 -> 411 bytes .../textures/signs_lib_font_31px_00e7.png | Bin 0 -> 390 bytes .../textures/signs_lib_font_31px_00e8.png | Bin 0 -> 395 bytes .../textures/signs_lib_font_31px_00e9.png | Bin 0 -> 390 bytes .../textures/signs_lib_font_31px_00ea.png | Bin 0 -> 391 bytes .../textures/signs_lib_font_31px_00f3.png | Bin 0 -> 383 bytes .../textures/signs_lib_font_31px_00f4.png | Bin 0 -> 388 bytes .../textures/signs_lib_font_31px_00f6.png | Bin 0 -> 376 bytes .../textures/signs_lib_font_31px_00f9.png | Bin 0 -> 362 bytes .../textures/signs_lib_font_31px_00fc.png | Bin 0 -> 358 bytes .../textures/signs_lib_font_31px_0104.png | Bin 0 -> 398 bytes .../textures/signs_lib_font_31px_0105.png | Bin 0 -> 389 bytes .../textures/signs_lib_font_31px_0106.png | Bin 0 -> 398 bytes .../textures/signs_lib_font_31px_0107.png | Bin 0 -> 390 bytes .../textures/signs_lib_font_31px_0118.png | Bin 0 -> 346 bytes .../textures/signs_lib_font_31px_0119.png | Bin 0 -> 389 bytes .../textures/signs_lib_font_31px_0141.png | Bin 0 -> 356 bytes .../textures/signs_lib_font_31px_0142.png | Bin 0 -> 326 bytes .../textures/signs_lib_font_31px_015a.png | Bin 0 -> 415 bytes .../textures/signs_lib_font_31px_015b.png | Bin 0 -> 395 bytes .../textures/signs_lib_font_31px_0179.png | Bin 0 -> 385 bytes .../textures/signs_lib_font_31px_017a.png | Bin 0 -> 368 bytes .../textures/signs_lib_font_31px_017b.png | Bin 0 -> 382 bytes .../textures/signs_lib_font_31px_017c.png | Bin 0 -> 363 bytes .../textures/signs_lib_font_31px_21.png | Bin 89 -> 307 bytes .../textures/signs_lib_font_31px_22.png | Bin 91 -> 309 bytes .../textures/signs_lib_font_31px_23.png | Bin 133 -> 351 bytes .../textures/signs_lib_font_31px_24.png | Bin 160 -> 405 bytes .../textures/signs_lib_font_31px_25.png | Bin 181 -> 420 bytes .../textures/signs_lib_font_31px_26.png | Bin 162 -> 406 bytes .../textures/signs_lib_font_31px_27.png | Bin 82 -> 301 bytes .../textures/signs_lib_font_31px_28.png | Bin 117 -> 333 bytes .../textures/signs_lib_font_31px_29.png | Bin 114 -> 331 bytes .../textures/signs_lib_font_31px_2a.png | Bin 119 -> 351 bytes .../textures/signs_lib_font_31px_2b.png | Bin 89 -> 321 bytes .../textures/signs_lib_font_31px_2c.png | Bin 90 -> 318 bytes .../textures/signs_lib_font_31px_2d.png | Bin 80 -> 299 bytes .../textures/signs_lib_font_31px_2e.png | Bin 78 -> 301 bytes .../textures/signs_lib_font_31px_2f.png | Bin 109 -> 336 bytes .../textures/signs_lib_font_31px_30.png | Bin 125 -> 371 bytes .../textures/signs_lib_font_31px_31.png | Bin 99 -> 341 bytes .../textures/signs_lib_font_31px_32.png | Bin 148 -> 382 bytes .../textures/signs_lib_font_31px_33.png | Bin 149 -> 393 bytes .../textures/signs_lib_font_31px_34.png | Bin 130 -> 361 bytes .../textures/signs_lib_font_31px_35.png | Bin 133 -> 376 bytes .../textures/signs_lib_font_31px_36.png | Bin 146 -> 395 bytes .../textures/signs_lib_font_31px_37.png | Bin 123 -> 350 bytes .../textures/signs_lib_font_31px_38.png | Bin 146 -> 376 bytes .../textures/signs_lib_font_31px_39.png | Bin 144 -> 392 bytes .../textures/signs_lib_font_31px_3a.png | Bin 78 -> 300 bytes .../textures/signs_lib_font_31px_3b.png | Bin 93 -> 320 bytes .../textures/signs_lib_font_31px_3c.png | Bin 130 -> 368 bytes .../textures/signs_lib_font_31px_3d.png | Bin 87 -> 306 bytes .../textures/signs_lib_font_31px_3e.png | Bin 121 -> 368 bytes .../textures/signs_lib_font_31px_3f.png | Bin 143 -> 371 bytes .../textures/signs_lib_font_31px_40.png | Bin 201 -> 462 bytes .../textures/signs_lib_font_31px_41.png | Bin 141 -> 382 bytes .../textures/signs_lib_font_31px_42.png | Bin 121 -> 377 bytes .../textures/signs_lib_font_31px_43.png | Bin 146 -> 396 bytes .../textures/signs_lib_font_31px_44.png | Bin 133 -> 369 bytes .../textures/signs_lib_font_31px_45.png | Bin 101 -> 328 bytes .../textures/signs_lib_font_31px_46.png | Bin 95 -> 318 bytes .../textures/signs_lib_font_31px_47.png | Bin 160 -> 394 bytes .../textures/signs_lib_font_31px_48.png | Bin 93 -> 325 bytes .../textures/signs_lib_font_31px_49.png | Bin 79 -> 303 bytes .../textures/signs_lib_font_31px_4a.png | Bin 111 -> 354 bytes .../textures/signs_lib_font_31px_4b.png | Bin 146 -> 392 bytes .../textures/signs_lib_font_31px_4c.png | Bin 88 -> 316 bytes .../textures/signs_lib_font_31px_4d.png | Bin 130 -> 376 bytes .../textures/signs_lib_font_31px_4e.png | Bin 129 -> 367 bytes .../textures/signs_lib_font_31px_4f.png | Bin 148 -> 386 bytes .../textures/signs_lib_font_31px_50.png | Bin 122 -> 356 bytes .../textures/signs_lib_font_31px_51.png | Bin 169 -> 401 bytes .../textures/signs_lib_font_31px_52.png | Bin 119 -> 380 bytes .../textures/signs_lib_font_31px_53.png | Bin 163 -> 406 bytes .../textures/signs_lib_font_31px_54.png | Bin 93 -> 320 bytes .../textures/signs_lib_font_31px_55.png | Bin 119 -> 350 bytes .../textures/signs_lib_font_31px_56.png | Bin 139 -> 375 bytes .../textures/signs_lib_font_31px_57.png | Bin 151 -> 396 bytes .../textures/signs_lib_font_31px_58.png | Bin 161 -> 403 bytes .../textures/signs_lib_font_31px_59.png | Bin 135 -> 370 bytes .../textures/signs_lib_font_31px_5a.png | Bin 132 -> 372 bytes .../textures/signs_lib_font_31px_5b.png | Bin 83 -> 309 bytes .../textures/signs_lib_font_31px_5d.png | Bin 83 -> 311 bytes .../textures/signs_lib_font_31px_5e.png | Bin 116 -> 361 bytes .../textures/signs_lib_font_31px_5f.png | Bin 85 -> 299 bytes .../textures/signs_lib_font_31px_60.png | Bin 88 -> 316 bytes .../textures/signs_lib_font_31px_61.png | Bin 133 -> 371 bytes .../textures/signs_lib_font_31px_62.png | Bin 127 -> 369 bytes .../textures/signs_lib_font_31px_63.png | Bin 126 -> 373 bytes .../textures/signs_lib_font_31px_64.png | Bin 130 -> 370 bytes .../textures/signs_lib_font_31px_65.png | Bin 132 -> 371 bytes .../textures/signs_lib_font_31px_66.png | Bin 102 -> 327 bytes .../textures/signs_lib_font_31px_67.png | Bin 166 -> 390 bytes .../textures/signs_lib_font_31px_68.png | Bin 106 -> 350 bytes .../textures/signs_lib_font_31px_69.png | Bin 86 -> 306 bytes .../textures/signs_lib_font_31px_6a.png | Bin 90 -> 318 bytes .../textures/signs_lib_font_31px_6b.png | Bin 130 -> 372 bytes .../textures/signs_lib_font_31px_6c.png | Bin 78 -> 303 bytes .../textures/signs_lib_font_31px_6d.png | Bin 125 -> 354 bytes .../textures/signs_lib_font_31px_6e.png | Bin 107 -> 346 bytes .../textures/signs_lib_font_31px_6f.png | Bin 124 -> 367 bytes .../textures/signs_lib_font_31px_70.png | Bin 126 -> 370 bytes .../textures/signs_lib_font_31px_71.png | Bin 131 -> 368 bytes .../textures/signs_lib_font_31px_72.png | Bin 101 -> 325 bytes .../textures/signs_lib_font_31px_73.png | Bin 136 -> 380 bytes .../textures/signs_lib_font_31px_74.png | Bin 100 -> 338 bytes .../textures/signs_lib_font_31px_75.png | Bin 108 -> 343 bytes .../textures/signs_lib_font_31px_76.png | Bin 128 -> 360 bytes .../textures/signs_lib_font_31px_77.png | Bin 145 -> 382 bytes .../textures/signs_lib_font_31px_78.png | Bin 141 -> 382 bytes .../textures/signs_lib_font_31px_79.png | Bin 131 -> 379 bytes .../textures/signs_lib_font_31px_7a.png | Bin 120 -> 354 bytes .../textures/signs_lib_font_31px_7b.png | Bin 108 -> 354 bytes .../textures/signs_lib_font_31px_7c.png | Bin 68 -> 300 bytes .../textures/signs_lib_font_31px_7d.png | Bin 106 -> 359 bytes .../textures/signs_lib_font_31px_7e.png | Bin 108 -> 333 bytes mods/signs_lib/util/LICENSE | 167 +++++++ mods/signs_lib/util/README.md | 36 ++ .../util/create-signs-lib-overlay.sh | 8 + mods/signs_lib/util/nonascii-de | 7 + mods/signs_lib/util/nonascii-fr | 16 + mods/signs_lib/util/nonascii-pl | 16 + mods/signs_lib/util/unicode-numbers.sh | 22 + mods/signs_lib/util/write-ascii.sh | 70 +++ mods/signs_lib/util/write-nonascii.sh | 57 +++ mods/skinsdb/meta/character_1949.txt | 3 + mods/skinsdb/textures/character_1949.png | Bin 0 -> 759 bytes 327 files changed, 2306 insertions(+), 1054 deletions(-) rename mods/advtrains/advtrains_luaautomation/{README.txt => README.md} (68%) mode change 100755 => 100644 create mode 100644 mods/advtrains/advtrains_signals_ks/textures/advtrains_signals_ks_sign_pam.png create mode 100644 mods/farming/textures/farming_salt_crystal.png create mode 100644 mods/signs_lib/nonascii-de.lua create mode 100644 mods/signs_lib/nonascii-fr.lua create mode 100644 mods/signs_lib/nonascii-pl.lua create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00c0.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00c4.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00c6.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00c7.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00c8.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00c9.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00ca.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00d3.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00d4.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00d6.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00d9.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00dc.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00df.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00e0.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00e4.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00e6.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00e7.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00e8.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00e9.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00ea.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00f3.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00f4.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00f6.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00f9.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_00fc.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_0104.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_0105.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_0106.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_0107.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_0118.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_0119.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_0141.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_0142.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_015a.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_015b.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_0179.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_017a.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_017b.png create mode 100644 mods/signs_lib/textures/signs_lib_font_15px_017c.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00c0.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00c4.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00c6.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00c7.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00c8.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00c9.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00ca.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00d3.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00d4.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00d6.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00d9.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00dc.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00df.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00e0.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00e4.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00e6.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00e7.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00e8.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00e9.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00ea.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00f3.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00f4.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00f6.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00f9.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_00fc.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_0104.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_0105.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_0106.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_0107.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_0118.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_0119.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_0141.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_0142.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_015a.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_015b.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_0179.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_017a.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_017b.png create mode 100644 mods/signs_lib/textures/signs_lib_font_31px_017c.png create mode 100644 mods/signs_lib/util/LICENSE create mode 100644 mods/signs_lib/util/README.md create mode 100644 mods/signs_lib/util/create-signs-lib-overlay.sh create mode 100644 mods/signs_lib/util/nonascii-de create mode 100644 mods/signs_lib/util/nonascii-fr create mode 100644 mods/signs_lib/util/nonascii-pl create mode 100644 mods/signs_lib/util/unicode-numbers.sh create mode 100644 mods/signs_lib/util/write-ascii.sh create mode 100644 mods/signs_lib/util/write-nonascii.sh create mode 100644 mods/skinsdb/meta/character_1949.txt create mode 100644 mods/skinsdb/textures/character_1949.png diff --git a/mods/advtrains/advtrains/api_doc.txt b/mods/advtrains/advtrains/api_doc.txt index 02567131..8ac49860 100644 --- a/mods/advtrains/advtrains/api_doc.txt +++ b/mods/advtrains/advtrains/api_doc.txt @@ -182,9 +182,11 @@ minetest.register_node(nodename, { ^- called when a train leaves the rail -- The following function is only in effect when interlocking is enabled: - on_train_approach = function(pos, train_id, train, index, lzbdata) + on_train_approach = function(pos, train_id, train, index, has_entered, lzbdata) ^- called when a train is approaching this position, called exactly once for every path recalculation (which can happen at any time) ^- This is called so that if the train would start braking now, it would come to halt about(wide approx) 5 nodes before the rail. + ^- has_entered: when true, the train is already standing on this node with its front tip, and the enter callback has already been called. + Possibly, some actions need not to be taken in this case. Only set if it's the very first node the train is standing on. ^- lzbdata should be ignored and nothing should be assigned to it } }) diff --git a/mods/advtrains/advtrains/atc.lua b/mods/advtrains/advtrains/atc.lua index 2fa39296..4f8b937f 100644 --- a/mods/advtrains/advtrains/atc.lua +++ b/mods/advtrains/advtrains/atc.lua @@ -72,6 +72,12 @@ function atc.send_command(pos, par_tid) end else atwarn("ATC rail at", pos, ": Sending command failed: There's no train at this position. This seems to be a bug.") + -- huch + --local train = advtrains.trains[train_id_temp_debug] + --atlog("Train speed is",train.velocity,", have moved",train.dist_moved_this_step,", lever",train.lever) + --advtrains.path_print(train, atlog) + -- TODO track again when ATC bugs occur... + end else atwarn("ATC rail at", pos, ": Sending command failed: Entry for controller not found.") @@ -108,57 +114,53 @@ advtrains.atc_function = function(def, preset, suffix, rotation) return { after_place_node=apn_func, after_dig_node=function(pos) - return advtrains.pcall(function() - advtrains.invalidate_all_paths(pos) - advtrains.ndb.clear(pos) - local pts=minetest.pos_to_string(pos) - atc.controllers[pts]=nil - end) + advtrains.invalidate_all_paths(pos) + advtrains.ndb.clear(pos) + local pts=minetest.pos_to_string(pos) + atc.controllers[pts]=nil end, on_receive_fields = function(pos, formname, fields, player) - return advtrains.pcall(function() - if advtrains.is_protected(pos, player:get_player_name()) then - minetest.record_protection_violation(pos, player:get_player_name()) + if advtrains.is_protected(pos, player:get_player_name()) then + minetest.record_protection_violation(pos, player:get_player_name()) + return + end + local meta=minetest.get_meta(pos) + if meta then + if not fields.save then + --[[--maybe only the dropdown changed + if fields.mode then + meta:set_string("mode", idxtrans[fields.mode]) + if fields.mode=="digiline" then + meta:set_string("infotext", attrans("ATC controller, mode @1\nChannel: @2", fields.mode, meta:get_string("command")) ) + else + meta:set_string("infotext", attrans("ATC controller, mode @1\nCommand: @2", fields.mode, meta:get_string("command")) ) + end + meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta)) + end]]-- return end - local meta=minetest.get_meta(pos) - if meta then - if not fields.save then - --maybe only the dropdown changed - if fields.mode then - meta:set_string("mode", idxtrans[fields.mode]) - if fields.mode=="digiline" then - meta:set_string("infotext", attrans("ATC controller, mode @1\nChannel: @2", (fields.mode or "?"), meta:get_string("command")) ) - else - meta:set_string("infotext", attrans("ATC controller, mode @1\nCommand: @2", (fields.mode or "?"), meta:get_string("command")) ) - end - meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta)) - end - return - end - meta:set_string("mode", idxtrans[fields.mode]) - meta:set_string("command", fields.command) - meta:set_string("command_on", fields.command_on) - meta:set_string("channel", fields.channel) - if fields.mode=="digiline" then - meta:set_string("infotext", attrans("ATC controller, mode @1\nChannel: @2", (fields.mode or "?"), meta:get_string("command")) ) - else - meta:set_string("infotext", attrans("ATC controller, mode @1\nCommand: @2", (fields.mode or "?"), meta:get_string("command")) ) - end - meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta)) - - local pts=minetest.pos_to_string(pos) - local _, conns=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes) - atc.controllers[pts]={command=fields.command} - if #advtrains.occ.get_trains_at(pos) > 0 then - atc.send_command(pos) - end + --meta:set_string("mode", idxtrans[fields.mode]) + meta:set_string("command", fields.command) + --meta:set_string("command_on", fields.command_on) + meta:set_string("channel", fields.channel) + --if fields.mode=="digiline" then + -- meta:set_string("infotext", attrans("ATC controller, mode @1\nChannel: @2", fields.mode, meta:get_string("command")) ) + --else + meta:set_string("infotext", attrans("ATC controller, mode @1\nCommand: @2", "-", meta:get_string("command")) ) + --end + meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta)) + + local pts=minetest.pos_to_string(pos) + local _, conns=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes) + atc.controllers[pts]={command=fields.command} + if #advtrains.occ.get_trains_at(pos) > 0 then + atc.send_command(pos) end - end) + end end, advtrains = { on_train_enter = function(pos, train_id) - atc.send_command(pos) + atc.send_command(pos, train_id) end, }, } @@ -256,6 +258,11 @@ local matchptn={ end return 1 end, + ["A([01])"]=function(id, train, match) + if not advtrains.interlocking then return 2 end + advtrains.interlocking.ars_set_disable(train, match=="0") + return 2 + end, } eval_conditional = function(command, arrow, speed) diff --git a/mods/advtrains/advtrains/copytool.lua b/mods/advtrains/advtrains/copytool.lua index dc180814..0c1cdfe9 100644 --- a/mods/advtrains/advtrains/copytool.lua +++ b/mods/advtrains/advtrains/copytool.lua @@ -13,76 +13,74 @@ minetest.register_tool("advtrains:copytool", { -- The front of the train is used as the start of the new train and it proceeds backwards from -- the direction of travel. on_place = function(itemstack, placer, pointed_thing) - return advtrains.pcall(function() - if ((not pointed_thing.type == "node") or (not placer.get_player_name)) then - return - end - local pname = placer:get_player_name() - - local node=minetest.get_node_or_nil(pointed_thing.under) - if not node then atprint("[advtrains]Ignore at placer position") return itemstack end - local nodename=node.name - if(not advtrains.is_track_and_drives_on(nodename, {default=true})) then - atprint("no track here, not placing.") - return itemstack - end - if not minetest.check_player_privs(placer, {train_operator = true }) then - minetest.chat_send_player(pname, "You don't have the train_operator privilege.") - return itemstack - end - if not minetest.check_player_privs(placer, {train_admin = true }) and minetest.is_protected(pointed_thing.under, placer:get_player_name()) then - return itemstack - end - local tconns=advtrains.get_track_connections(node.name, node.param2) - local yaw = placer:get_look_horizontal() - local plconnid = advtrains.yawToClosestConn(yaw, tconns) - - local prevpos = advtrains.get_adjacent_rail(pointed_thing.under, tconns, plconnid, {default=true}) - if not prevpos then - minetest.chat_send_player(pname, "The track you are trying to place the wagon on is not long enough!") - return - end - - local meta = itemstack:get_meta() - if not meta then - minetest.chat_send_player(pname, attrans("The clipboard couldn't access the metadata. Paste failed.")) + if ((not pointed_thing.type == "node") or (not placer.get_player_name)) then return - end - local clipboard = meta:get_string("clipboard") - if (clipboard == "") then - minetest.chat_send_player(pname, "The clipboard is empty."); - return - end - clipboard = minetest.deserialize(clipboard) - if (clipboard.wagons == nil) then - minetest.chat_send_player(pname, "The clipboard is empty."); - return - end + end + local pname = placer:get_player_name() - local wagons = {} - local n = 1 - for _, wagonProto in pairs(clipboard.wagons) do - local wagon = advtrains.create_wagon(wagonProto.type, pname) - advtrains.wagons[wagon].wagon_flipped = wagonProto.wagon_flipped - wagons[n] = wagon - n = n + 1 - end - - local id=advtrains.create_new_train_at(pointed_thing.under, plconnid, 0, wagons) - local train = advtrains.trains[id] - train.off_track = train.end_index ringbuflen then ringbufcnt[tid]=0 diff --git a/mods/advtrains/advtrains/init.lua b/mods/advtrains/advtrains/init.lua index 6e622e56..7cc0ccdb 100644 --- a/mods/advtrains/advtrains/init.lua +++ b/mods/advtrains/advtrains/init.lua @@ -26,15 +26,37 @@ minetest.log("action", "[advtrains] Loading...") attrans = minetest.get_translator ("advtrains") --advtrains +advtrains = {trains={}, player_to_train_mapping={}} -DUMP_DEBUG_SAVE = false -GENERATE_ATRICIFIAL_LAG = false +-- =======================Development/debugging settings===================== +-- DO NOT USE FOR NORMAL OPERATION +local DUMP_DEBUG_SAVE = false +-- dump the save files in human-readable format into advtrains_DUMP + +local GENERATE_ATRICIFIAL_LAG = false +local HOW_MANY_LAG = 1.0 +-- Simulate a higher server step interval, as it occurs when the server is on high load + +advtrains.IGNORE_WORLD = false +-- Run advtrains without respecting the world map +-- - No world collision checks occur +-- - The NDB forcibly places all nodes stored in it into the world regardless of the world's content. +-- - Rails do not set the 'attached_node' group +-- This mode can be useful for debugging/testing a world without the map data available +-- In this case, choose 'singlenode' as mapgen + +local NO_SAVE = false +-- Do not save any data to advtrains save files + +-- ========================================================================== + +-- Use a global slowdown factor to slow down train movements. Now a setting +advtrains.DTIME_LIMIT = tonumber(minetest.settings:get("advtrains_dtime_limit")) or 0.2 +advtrains.SAVE_INTERVAL = tonumber(minetest.settings:get("advtrains_save_interval")) or 60 --Constant for maximum connection value/division of the circle AT_CMAX = 16 -advtrains = {trains={}, player_to_train_mapping={}} - -- get wagon loading range advtrains.wagon_load_range = tonumber(minetest.settings:get("advtrains_wagon_load_range")) if not advtrains.wagon_load_range then @@ -61,25 +83,6 @@ local function reload_saves() end) end -function advtrains.pcall(fun) - if no_action then return end - - local succ, return1, return2, return3, return4=xpcall(fun, function(err) - atwarn("Lua Error occured: ", err) - atwarn(debug.traceback()) - if advtrains.atprint_context_tid then - advtrains.path_print(advtrains.trains[advtrains.atprint_context_tid], atdebug) - atwarn(advtrains.trains[advtrains.atprint_context_tid].debug) - end - end) - if not succ then - reload_saves() - else - return return1, return2, return3, return4 - end -end - - advtrains.modpath = minetest.get_modpath("advtrains") --Advtrains dump (special treatment of pos and sigd) @@ -464,7 +467,8 @@ advtrains.avt_save = function(remove_players_from_wagons) "trainparts", "recently_collided_with_env", "atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open", "text_outside", "text_inside", "line", "routingcode", - "il_sections", "speed_restriction", "is_shunt", "points_split", "autocouple" + "il_sections", "speed_restriction", "is_shunt", + "points_split", "autocouple", "ars_disable", }) --then save it tmp_trains[id]=v @@ -560,14 +564,17 @@ end --## MAIN LOOP ##-- --Calls all subsequent main tasks of both advtrains and atlatc local init_load=false -local save_interval=60 -local save_timer=save_interval +local save_timer = advtrains.SAVE_INTERVAL advtrains.mainloop_runcnt=0 - +advtrains.global_slowdown = 1 local t = 0 minetest.register_globalstep(function(dtime_mt) - return advtrains.pcall(function() + if no_action then + -- the advtrains globalstep is skipped by command. Return immediately + return + end + advtrains.mainloop_runcnt=advtrains.mainloop_runcnt+1 --atprint("Running the main loop, runcnt",advtrains.mainloop_runcnt) --call load once. see advtrains.load() comment @@ -575,24 +582,30 @@ minetest.register_globalstep(function(dtime_mt) advtrains.load() end - local dtime + local dtime = dtime_mt * advtrains.global_slowdown if GENERATE_ATRICIFIAL_LAG then - dtime = 0.2 + dtime = HOW_MANY_LAG if os.clock()0.2 then - atprint("Limiting dtime to 0.2!") - dtime=0.2 + t = os.clock()+HOW_MANY_LAG + end + -- if dtime is too high, decrease global slowdown + if advtrains.DTIME_LIMIT~=0 then + if dtime > advtrains.DTIME_LIMIT then + if advtrains.global_slowdown > 0.1 then + advtrains.global_slowdown = advtrains.global_slowdown - 0.05 + else + advtrains.global_slowdown = advtrains.global_slowdown / 2 + end + dtime = advtrains.DTIME_LIMIT end + -- recover global slowdown slowly over time + advtrains.global_slowdown = math.min(advtrains.global_slowdown*1.02, 1) end - advtrains.mainloop_trainlogic(dtime) + advtrains.mainloop_trainlogic(dtime,advtrains.mainloop_runcnt) if advtrains_itm_mainloop then advtrains_itm_mainloop(dtime) end @@ -610,10 +623,9 @@ minetest.register_globalstep(function(dtime_mt) local t=os.clock() --save advtrains.save() - save_timer=save_interval + save_timer = advtrains.SAVE_INTERVAL atprintbm("saving", t) end - end) end) --if something goes wrong in these functions, there is no help. no pcall here. @@ -642,12 +654,27 @@ function advtrains.save(remove_players_from_wagons) atwarn("Instructed to save() but load() was never called!") return end + + if advtrains.IGNORE_WORLD then + advtrains.ndb.restore_all() + end + + if NO_SAVE then + return + end + if no_action then + atlog("[save] Saving requested externally, but Advtrains step is disabled. Not saving any data as state may be inconsistent.") + return + end + + local t1 = os.clock() advtrains.avt_save(remove_players_from_wagons) --saving advtrains. includes ndb at advtrains.ndb.save_data() if atlatc then atlatc.save() end - atprint("[save_all]Saved advtrains save files") + atlog("Saved advtrains save files, took",math.floor((os.clock()-t1) * 1000),"ms") + -- Cleanup actions --TODO very simple yet hacky workaround for the "green signals" bug advtrains.invalidate_all_paths() end @@ -662,11 +689,9 @@ minetest.register_chatcommand("at_empty_seats", description = "Detach all players, especially the offline ones, from all trains. Use only when no one serious is on a train.", -- Full description privs = {train_operator=true, server=true}, -- Require the "privs" privilege to run func = function(name, param) - return advtrains.pcall(function() atwarn("Data is being saved. While saving, advtrains will remove the players from trains. Save files will be reloaded afterwards!") advtrains.save(true) reload_saves() - end) end, }) -- This chat command solves another problem: Trains getting randomly stuck. @@ -676,13 +701,36 @@ minetest.register_chatcommand("at_reroute", description = "Delete all train routes, force them to recalculate", privs = {train_operator=true}, -- Only train operator is required, since this is relatively safe. func = function(name, param) - return advtrains.pcall(function() advtrains.invalidate_all_paths() return true, "Successfully invalidated train routes" - end) end, }) +minetest.register_chatcommand("at_disable_step", + { + params = "", + description = "Disable the advtrains globalstep temporarily", + privs = {server=true}, + func = function(name, param) + if minetest.is_yes(param) then + -- disable everything, and turn off saving + no_action = true; + atwarn("The advtrains globalstep has been disabled. Trains are not moving, and no data is saved! Run '/at_disable_step no' to enable again!") + return true, "Disabled advtrains successfully" + elseif no_action then + atwarn("Re-enabling advtrains globalstep...") + reload_saves() + return true + else + return false, "Advtrains is already running normally!" + end + end, +}) + +advtrains.is_no_action = function() + return no_action +end + local tot=(os.clock()-lot)*1000 minetest.log("action", "[advtrains] Loaded in "..tot.."ms") diff --git a/mods/advtrains/advtrains/lzb.lua b/mods/advtrains/advtrains/lzb.lua index 6cbf4ab8..cbdc4221 100644 --- a/mods/advtrains/advtrains/lzb.lua +++ b/mods/advtrains/advtrains/lzb.lua @@ -4,20 +4,36 @@ --[[ Documentation of train.lzb table train.lzb = { - trav = Current index that the traverser has advanced so far - oncoming = table containing oncoming signals, in order of appearance on the path + trav_index = Current index that the traverser has advanced so far + checkpoints = table containing oncoming signals, in order of index { pos = position of the point - idx = where this is on the path - spd = speed allowed to pass - fun = function(pos, id, train, index, speed, lzbdata) + index = where this is on the path + speed = speed allowed to pass. nil = no effect + callback = function(pos, id, train, index, speed, lzbdata) -- Function that determines what to do on the train in the moment it drives over that point. + -- When spd==0, called instead when train has stopped in front + -- nil = no effect + lzbdata = {} + -- Table of custom data filled in by approach callbacks + -- Whenever an approach callback inserts an LZB checkpoint with changed lzbdata, + -- all consecutive approach callbacks will see these passed as lzbdata table. + + udata = arbitrary user data, no official way to retrieve (do not use) } + trav_lzbdata = currently active lzbdata table at traverser index } -each step, for every item in "oncoming", we need to determine the location to start braking (+ some safety margin) -and, if we passed this point for at least one of the items, initiate brake. -When speed has dropped below, say 3, decrease the margin to zero, so that trains actually stop at the signal IP. -The spd variable and travsht need to be updated on every aspect change. it's probably best to reset everything when any aspect changes +The LZB subsystem keeps track of "checkpoints" the train will pass in the future, and has two main tasks: +1. run approach callbacks, and run callbacks when passing LZB checkpoints +2. keep track of the permitted speed at checkpoints, and make sure that the train brakes accordingly +To perform 2, it populates the train.path_speed table which is handled along with the path subsystem. +This table is used in trainlogic.lua/train_step_b() and applied to the velocity calculations. + +Note: in contrast to node enter callbacks, which are called when the train passes the .5 index mark, LZB callbacks are executed on passing the .0 index mark! +If an LZB checkpoint has speed 0, the train will still enter the node (the enter callback will be called), but will stop at the 0.9 index mark (for details, see SLOW_APPROACH in trainlogic.lua) + +The start point for the LZB traverser (and thus the first node that will receive an approach callback) is floor(train.index) + 1. This means, once the LZB checkpoint callback has fired, +this path node will not receive any further approach callbacks for the same approach situation ]] @@ -45,42 +61,130 @@ function advtrains.set_lzb_param(par, val) end end +local function resolve_latest_lzbdata(ckp, index) + local i = #ckp + local ckpi + while i>0 do + ckpi = ckp[i] + if ckpi.index <= index and ckpi.lzbdata then + return ckpi.lzbdata + end + i=i-1 + end + return {} +end local function look_ahead(id, train) + local lzb = train.lzb + if lzb.zero_checkpoint then + -- if the checkpoints list contains a zero checkpoint, don't look ahead + -- in order to not trigger approach callbacks on the wrong path + return + end local acc = advtrains.get_acceleration(train, 1) - local vel = train.velocity + -- worst-case: the starting point is maximum speed + local vel = train.max_speed or train.velocity local brakedst = ( -(vel*vel) / (2*acc) ) * params.DST_FACTOR - local brake_i = advtrains.path_get_index_by_offset(train, train.index, brakedst + params.BRAKE_SPACE) + --local brake_i = advtrains.path_get_index_by_offset(train, train.index, brakedst + params.BRAKE_SPACE) + -- worst case (don't use index_by_offset) + local brake_i = atfloor(train.index + brakedst + params.BRAKE_SPACE) + atprint("LZB: looking ahead up to ", brake_i) + --local aware_i = advtrains.path_get_index_by_offset(train, brake_i, AWARE_ZONE) - local lzb = train.lzb - local trav = lzb.trav + local trav = lzb.trav_index + -- retrieve latest lzbdata + if not lzb.trav_lzbdata then + lzb.trav_lzbdata = resolve_latest_lzbdata(lzb.checkpoints, trav) + end - --train.debug = lspd + if lzb.trav_lzbdata.off_track then + --previous position was off track, do not scan any further + end - while trav <= brake_i do - trav = trav + 1 + while trav <= brake_i and not lzb.zero_checkpoint do local pos = advtrains.path_get(train, trav) -- check offtrack - if trav > train.path_trk_f then - table.insert(lzb.oncoming, { - pos = pos, - idx = trav-1, - spd = 0, - }) + if trav - 1 == train.path_trk_f then + lzb.trav_lzbdata.off_track = true + advtrains.lzb_add_checkpoint(train, trav - 1, 0, nil, lzb.trav_lzbdata) else -- run callbacks -- Note: those callbacks are defined in trainlogic.lua for consistency with the other node callbacks - advtrains.tnc_call_approach_callback(pos, id, train, trav, lzb.data) + advtrains.tnc_call_approach_callback(pos, id, train, trav, lzb.trav_lzbdata) end + trav = trav + 1 + end - lzb.trav = trav + lzb.trav_index = trav end +advtrains.lzb_look_ahead = look_ahead + + +local function call_runover_callbacks(id, train) + if not train.lzb then return end + + local i = 1 + local idx = atfloor(train.index) + local ckp = train.lzb.checkpoints + while ckp[i] do + if ckp[i].index <= idx then + atprint("LZB: checkpoint run over: i=",ckp[i].index,"s=",ckp[i].speed) + -- call callback + local it = ckp[i] + if it.callback then + it.callback(it.pos, id, train, it.index, it.speed, train.lzb.lzbdata) + end + -- note: lzbdata is always defined as look_ahead was called before + table.remove(ckp, i) + else + i = i + 1 + end + end +end + +-- Flood-fills train.path_speed, based on this checkpoint +local function apply_checkpoint_to_path(train, checkpoint) + if not checkpoint.speed then + return + end + atprint("LZB: applying checkpoint: i=",checkpoint.index,"s=",checkpoint.speed) + + if checkpoint.speed == 0 then + train.lzb.zero_checkpoint = true + end + + -- make sure path exists until checkpoint + local pos = advtrains.path_get(train, checkpoint.index) + + local brake_accel = advtrains.get_acceleration(train, 11) + + -- start with the checkpoint index at specified speed + local index = checkpoint.index + local p_speed -- speed in path_speed + local c_speed = checkpoint.speed -- calculated speed at current index + while true do + p_speed = train.path_speed[index] + if (p_speed and p_speed <= c_speed) or index < train.index then + --we're done. train already slower than wanted at this position + return + end + -- insert calculated target speed + train.path_speed[index] = c_speed + -- calculate c_speed at previous index + advtrains.path_get(train, index-1) + local eldist = train.path_dist[index] - train.path_dist[index-1] + -- Calculate the start velocity the train would have if it had a end velocity of c_speed and accelerating with brake_accel, after a distance of eldist: + -- v0² = v1² - 2*a*s + c_speed = math.sqrt( (c_speed * c_speed) - (2 * brake_accel * eldist) ) + index = index - 1 + end +end --[[ Distance needed to accelerate from v0 to v1 with constant acceleration a: @@ -90,95 +194,74 @@ s = v0 * ------- + - * | ------- | = ----------- a 2 \ a / 2*a ]] -local function apply_control(id, train) - local lzb = train.lzb - - local i = 1 - while i<=#lzb.oncoming do - if lzb.oncoming[i].idx < train.index then - local ent = lzb.oncoming[i] - if ent.fun then - ent.fun(ent.pos, id, train, ent.idx, ent.spd, lzb.data) - end - - table.remove(lzb.oncoming, i) - else - i = i + 1 - end - end - - for i, it in ipairs(lzb.oncoming) do - local a = advtrains.get_acceleration(train, 1) --should be negative - local v0 = train.velocity - local v1 = it.spd - if v1 and v1 <= v0 then - local s = (v1*v1 - v0*v0) / (2*a) - - local st = s + params.ADD_SLOW - if v0 > 3 then - st = s + params.ADD_FAST - end - if v0<=0 then - st = s + params.ADD_STAND - end - - local i = advtrains.path_get_index_by_offset(train, it.idx, -st) - - --train.debug = dump({v0f=v0*f, aff=a*f*f,v0=v0, v1=v1, f=f, a=a, s=s, st=st, i=i, idx=train.index}) - if i <= train.index then - -- Gotcha! Braking... - train.ctrl.lzb = 1 - --train.debug = train.debug .. "BRAKE!!!" - return - end - - i = advtrains.path_get_index_by_offset(train, i, -params.ZONE_ROLL) - if i <= train.index and v0>1 then - -- roll control - train.ctrl.lzb = 2 - return - end - i = advtrains.path_get_index_by_offset(train, i, -params.ZONE_HOLD) - if i <= train.index and v0>1 then - -- hold speed - train.ctrl.lzb = 3 - return - end - end - end - train.ctrl.lzb = nil -end - -local function invalidate(train) +-- Removes all LZB checkpoints and restarts the traverser at the current train index +function advtrains.lzb_invalidate(train) train.lzb = { - trav = atfloor(train.index), - data = {}, - oncoming = {}, + trav_index = atfloor(train.index) + 1, + checkpoints = {}, } end -function advtrains.lzb_invalidate(train) - invalidate(train) +-- LZB part of path_invalidate_ahead. Clears all checkpoints that are ahead of start_idx +-- in contrast to path_inv_ahead, doesn't complain if start_idx is behind train.index, clears everything then +function advtrains.lzb_invalidate_ahead(train, start_idx) + if train.lzb then + local idx = atfloor(start_idx) + local i = 1 + while train.lzb.checkpoints[i] do + if train.lzb.checkpoints[i].index >= idx then + table.remove(train.lzb.checkpoints, i) + else + i=i+1 + end + end + train.lzb.trav_index = idx + -- FIX reset trav_lzbdata (look_ahead fetches these when required) + train.lzb.trav_lzbdata = nil + -- re-apply all checkpoints to path_speed + train.path_speed = {} + train.lzb.zero_checkpoint = false + for _,ckp in ipairs(train.lzb.checkpoints) do + apply_checkpoint_to_path(train, ckp) + end + end end -- Add LZB control point --- udata: User-defined additional data -function advtrains.lzb_add_checkpoint(train, index, speed, callback, udata) +-- lzbdata: If you modify lzbdata in an approach callback, you MUST add a checkpoint AND pass the (modified) lzbdata into it. +-- If you DON'T modify lzbdata, you MUST pass nil as lzbdata. Always modify the lzbdata table in place, never overwrite it! +-- udata: user-defined data, do not use externally +function advtrains.lzb_add_checkpoint(train, index, speed, callback, lzbdata, udata) local lzb = train.lzb local pos = advtrains.path_get(train, index) - table.insert(lzb.oncoming, { + local lzbdata_c = nil + if lzbdata then + -- make a shallow copy of lzbdata + lzbdata_c = {} + for k,v in pairs(lzbdata) do lzbdata_c[k] = v end + end + local ckp = { pos = pos, - idx = index, - spd = speed, - fun = callback, + index = index, + speed = speed, + callback = callback, + lzbdata = lzbdata_c, udata = udata, - }) + } + table.insert(lzb.checkpoints, ckp) + + apply_checkpoint_to_path(train, ckp) end advtrains.te_register_on_new_path(function(id, train) - invalidate(train) - look_ahead(id, train) + advtrains.lzb_invalidate(train) + -- Taken care of in pre-move hook (see train_step_b) + --look_ahead(id, train) +end) + +advtrains.te_register_on_invalidate_ahead(function(id, train, start_idx) + advtrains.lzb_invalidate_ahead(train, start_idx) end) advtrains.te_register_on_update(function(id, train) @@ -186,6 +269,8 @@ advtrains.te_register_on_update(function(id, train) atprint("LZB run: no path on train, skip step") return end - look_ahead(id, train) - apply_control(id, train) + -- Note: look_ahead called from train_step_b before applying movement + -- TODO: if more pre-move hooks are added, make a separate callback hook + --look_ahead(id, train) + call_runover_callbacks(id, train) end, true) diff --git a/mods/advtrains/advtrains/nodedb.lua b/mods/advtrains/advtrains/nodedb.lua index 878ed88b..c6647926 100644 --- a/mods/advtrains/advtrains/nodedb.lua +++ b/mods/advtrains/advtrains/nodedb.lua @@ -246,7 +246,7 @@ function ndb.update(pos, pnode) local resid = (nid * 4) + (l2b(node.param2 or 0)) ndbset(pos.x, pos.y, pos.z, resid ) --atdebug("nodedb: updating node", pos, "stored nid",nid,"assigned",ndb_nodeids[nid],"resulting cid",resid) - minetest.after(0, advtrains.invalidate_all_paths, pos) + advtrains.invalidate_all_paths_ahead(pos) else --at this position there is no longer a node that needs to be tracked. --atdebug("nodedb: updating node", pos, "cleared") @@ -281,8 +281,9 @@ function advtrains.get_rail_info_at(pos, drives_on) return true, conns, railheight end +local IGNORE_WORLD = advtrains.IGNORE_WORLD + ndb.run_lbm = function(pos, node) - return advtrains.pcall(function() local cid=ndbget(pos.x, pos.y, pos.z) if cid then --if in database, detect changes and apply. @@ -310,7 +311,6 @@ ndb.run_lbm = function(pos, node) ndb.update(pos, node) end return false - end) end @@ -327,6 +327,7 @@ minetest.register_lbm({ --used when restoring stuff after a crash ndb.restore_all = function() --atlog("Updating the map from the nodedb, this may take a while") + local t1 = os.clock() local cnt=0 local dcnt=0 for y, ny in pairs(ndb_nodes) do @@ -337,7 +338,7 @@ ndb.restore_all = function() if node then local ori_ndef=minetest.registered_nodes[node.name] local ndbnode=ndb.get_node_raw(pos) - if ori_ndef and ori_ndef.groups.save_in_at_nodedb then --check if this node has been worldedited, and don't replace then + if (ori_ndef and ori_ndef.groups.save_in_at_nodedb) or IGNORE_WORLD then --check if this node has been worldedited, and don't replace then if (ndbnode.name~=node.name or ndbnode.param2~=node.param2) then minetest.swap_node(pos, ndbnode) --atlog("Replaced",node.name,"@",pos,"with",ndbnode.name) @@ -352,15 +353,13 @@ ndb.restore_all = function() end end end - local text="Restore node database: Replaced "..cnt.." nodes, removed "..dcnt.." ghost nodes." + local text="Restore node database: Replaced "..cnt.." nodes, removed "..dcnt.." ghost nodes. (took "..math.floor((os.clock()-t1) * 1000).."ms)" atlog(text) return text end minetest.register_on_dignode(function(pos, oldnode, digger) - return advtrains.pcall(function() ndb.clear(pos) - end) end) function ndb.get_nodes() @@ -381,14 +380,12 @@ minetest.register_chatcommand("at_sync_ndb", description = "Write node db back to map and find ghost nodes", -- Full description privs = {train_operator=true}, func = function(name, param) - return advtrains.pcall(function() - if os.time() < ptime+30 then + if os.time() < ptime+30 and not minetest.get_player_privs(name, "server") then return false, "Please wait at least 30s from the previous execution of /at_restore_ndb!" end local text = ndb.restore_all() ptime=os.time() return true, text - end) end, }) diff --git a/mods/advtrains/advtrains/occupation.lua b/mods/advtrains/advtrains/occupation.lua index da602789..db399910 100644 --- a/mods/advtrains/advtrains/occupation.lua +++ b/mods/advtrains/advtrains/occupation.lua @@ -196,7 +196,6 @@ function o.get_trains_over(ppos) local r = {} local i = 1 while t[i] do - local train = advtrains.trains[t[i]] local idx = t[i+1] r[t[i]] = idx i = i + 2 diff --git a/mods/advtrains/advtrains/path.lua b/mods/advtrains/advtrains/path.lua index ee82c06c..714781ad 100644 --- a/mods/advtrains/advtrains/path.lua +++ b/mods/advtrains/advtrains/path.lua @@ -19,6 +19,8 @@ -- When the day comes on that path!=node, these will only be set if this index represents a transition between rail nodes -- path_dist - The total distance of this path element from path element 0 -- path_dir - The direction of this path item's transition to the next path item, which is the angle of conns[path_cn[i]].c +-- path_speed- Populated by the LZB system. The maximum speed (velocity) permitted in the moment this path item is passed. +-- (this saves brake distance calculations every step to determine LZB control). nil means no limit. --Variables: -- path_ext_f/b - how far path[i] is set -- path_trk_f/b - how far the path extends along a track. beyond those values, paths are generated in a straight line. @@ -52,6 +54,8 @@ function advtrains.path_create(train, pos, connid, rel_index) [0] = advtrains.conn_angle_median(conns[mconnid].c, conns[connid].c) } + train.path_speed = { } + train.path_ext_f=0 train.path_ext_b=0 train.path_trk_f=0 @@ -123,6 +127,7 @@ function advtrains.path_invalidate(train, ignore_lock) train.path_cp = nil train.path_cn = nil train.path_dir = nil + train.path_speed = nil train.path_ext_f=0 train.path_ext_b=0 train.path_trk_f=0 @@ -131,6 +136,40 @@ function advtrains.path_invalidate(train, ignore_lock) train.path_req_b=0 train.dirty = true + --atdebug(train.id, "Path invalidated") +end + +-- Keeps the path intact, but invalidates all path nodes from the specified index (inclusive) +-- onwards. This has the advantage that we don't need to recalculate the whole path, and we can do it synchronously. +function advtrains.path_invalidate_ahead(train, start_idx, ignore_when_passed) + if not train.path then + -- the path wasn't even initialized. Nothing to do + return + end + + local idx = atfloor(start_idx) + --atdebug("Invalidate_ahead:",train.id,"start_index",start_idx,"cur_idx",train.index) + + if(idx <= train.index - 0.5) then + if ignore_when_passed then + --atdebug("ignored passed") + return + end + advtrains.path_print(train, atwarn) + error("Train "+train.id+": Cannot path_invalidate_ahead start_idx="+idx+" as train has already passed!") + end + + -- leave current node in path, it won't change. What might change is the path onward from here (e.g. switch) + local i = idx + 1 + while train.path[i] do + advtrains.occ.clear_item(train.id, advtrains.round_vector_floor_y(train.path[i])) + i = i+1 + end + train.path_ext_f=idx + train.path_trk_f=math.min(idx, train.path_trk_f) + + -- callbacks called anyway for current node, because of LZB + advtrains.run_callbacks_invahead(train.id, train, idx) end -- Prints a path using the passed print function @@ -141,12 +180,12 @@ function advtrains.path_print(train, printf) printf("path_print: Path is invalidated/inexistant.") return end - printf("i: CP Position Dir CN Dist") + printf("i: CP Position Dir CN Dist Speed") for i = train.path_ext_b, train.path_ext_f do if i==train.path_trk_b then printf("--Back on-track border here--") end - printf(i,": ",train.path_cp[i]," ",train.path[i]," ",train.path_dir[i]," ",train.path_cn[i]," ",train.path_dist[i],"") + printf(i,": ",train.path_cp[i]," ",train.path[i]," ",train.path_dir[i]," ",train.path_cn[i]," ",train.path_dist[i]," ",train.path_speed[i]) if i==train.path_trk_f then printf("--Front on-track border here--") end @@ -350,6 +389,7 @@ function advtrains.path_clear_unused(train) train.path_ext_b = i + 1 end + --[[ Why exactly are we clearing path from the front? This doesn't make sense! for i = train.path_ext_f,train.path_req_f + PATH_CLEAR_KEEP,-1 do advtrains.occ.clear_item(train.id, advtrains.round_vector_floor_y(train.path[i])) train.path[i] = nil @@ -358,14 +398,16 @@ function advtrains.path_clear_unused(train) train.path_cn[i] = nil train.path_dir[i+1] = nil train.path_ext_f = i - 1 - end + end ]] train.path_trk_b = math.max(train.path_trk_b, train.path_ext_b) - train.path_trk_f = math.min(train.path_trk_f, train.path_ext_f) + --train.path_trk_f = math.min(train.path_trk_f, train.path_ext_f) train.path_req_f = math.ceil(train.index) train.path_req_b = math.floor(train.end_index or train.index) end +-- Scan the path of the train for position, without querying the occupation table +-- returns index, or nil if pos is not on the path function advtrains.path_lookup(train, pos) local cp = advtrains.round_vector_floor_y(pos) for i = train.path_ext_b, train.path_ext_f do diff --git a/mods/advtrains/advtrains/settingtypes.txt b/mods/advtrains/advtrains/settingtypes.txt index d8eb44a8..6acff807 100644 --- a/mods/advtrains/advtrains/settingtypes.txt +++ b/mods/advtrains/advtrains/settingtypes.txt @@ -45,3 +45,14 @@ advtrains_overrun_mode (Overrun mode) enum drop none,drop,normal # When a wagon leaves this range + 32 nodes, it is unloaded # If unset, defaults to active_block_range*16 advtrains_wagon_load_range (Wagon Entity Load/Unload Range) int 96 32 512 + +# Simulation DTime Limit after which slow-down becomes effective +# When the dtime value (time since last server step) is higher than this value, +# advtrains applies a global slow-down factor to the dtime and to the velocity and +# acceleration of wagons to decrease server load. +# A value of 0 (default) disables this behavior. +advtrains_dtime_limit (DTime Limit for slow-down) float 0.2 0 5 + +# Time interval in seconds in which advtrains stores its save data to disk +# Nevertheless, advtrains saves all data when shutting down the server. +advtrains_save_interval (Save Interval) int 60 20 3600 diff --git a/mods/advtrains/advtrains/signals.lua b/mods/advtrains/advtrains/signals.lua index e144aa65..9df2f998 100644 --- a/mods/advtrains/advtrains/signals.lua +++ b/mods/advtrains/advtrains/signals.lua @@ -12,22 +12,26 @@ end local function aspect(b) return { - main = { - free = b, - speed = -1, - }, - shunt = { - free = false, - proceed_as_main = true - }, - dst = { - free = true, - speed = -1, - }, + main = (not b) and 0, -- b ? false : 0 + shunt = false, + proceed_as_main = true, + dst = false, info = {} } end +local suppasp = { + main = {0, false}, + dst = {false}, + shunt = nil, + proceed_as_main = true, + info = { + call_on = false, + dead_end = false, + w_speed = nil, + } +} + for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", als="green"}}) do advtrains.trackplacer.register_tracktype("advtrains:retrosignal", "") @@ -63,6 +67,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", rules=advtrains.meseconrules, ["action_"..f.as] = function (pos, node) advtrains.ndb.swap_node(pos, {name = "advtrains:retrosignal_"..f.as..rotation, param2 = node.param2}, true) + advtrains.interlocking.signal_on_aspect_changed(pos) end }}, on_rightclick=function(pos, node, player) @@ -74,12 +79,13 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", advtrains.interlocking.show_ip_form(pos, pname) elseif advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then advtrains.ndb.swap_node(pos, {name = "advtrains:retrosignal_"..f.as..rotation, param2 = node.param2}, true) + advtrains.interlocking.signal_on_aspect_changed(pos) end end, -- new signal API advtrains = { set_aspect = function(pos, node, asp) - if asp.main.free then + if asp.main ~= 0 then advtrains.ndb.swap_node(pos, {name = "advtrains:retrosignal_on"..rotation, param2 = node.param2}, true) else advtrains.ndb.swap_node(pos, {name = "advtrains:retrosignal_off"..rotation, param2 = node.param2}, true) @@ -87,7 +93,8 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", end, get_aspect = function(pos, node) return aspect(r=="on") - end + end, + supported_aspects = suppasp, }, can_dig = can_dig_func, }) @@ -120,6 +127,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", rules=advtrains.meseconrules, ["action_"..f.as] = function (pos, node) advtrains.setstate(pos, f.als, node) + advtrains.interlocking.signal_on_aspect_changed(pos) end }}, on_rightclick=function(pos, node, player) @@ -131,12 +139,13 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", advtrains.interlocking.show_ip_form(pos, pname) elseif advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then advtrains.setstate(pos, f.als, node) + advtrains.interlocking.signal_on_aspect_changed(pos) end end, -- new signal API advtrains = { set_aspect = function(pos, node, asp) - if asp.main.free then + if asp.main ~= 0 then advtrains.ndb.swap_node(pos, {name = "advtrains:signal_on"..rotation, param2 = node.param2}, true) else advtrains.ndb.swap_node(pos, {name = "advtrains:signal_off"..rotation, param2 = node.param2}, true) @@ -145,6 +154,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", get_aspect = function(pos, node) return aspect(r=="on") end, + supported_aspects = suppasp, getstate = f.ls, setstate = function(pos, node, newstate) if newstate == f.als then @@ -204,7 +214,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", -- new signal API advtrains = { set_aspect = function(pos, node, asp) - if asp.main.free then + if asp.main ~= 0 then advtrains.ndb.swap_node(pos, {name = "advtrains:signal_wall_"..loc.."_on", param2 = node.param2}, true) else advtrains.ndb.swap_node(pos, {name = "advtrains:signal_wall_"..loc.."_off", param2 = node.param2}, true) @@ -213,6 +223,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", get_aspect = function(pos, node) return aspect(r=="on") end, + supported_aspects = suppasp, getstate = f.ls, setstate = function(pos, node, newstate) if newstate == f.als then diff --git a/mods/advtrains/advtrains/trackplacer.lua b/mods/advtrains/advtrains/trackplacer.lua index 904d8515..356df15f 100644 --- a/mods/advtrains/advtrains/trackplacer.lua +++ b/mods/advtrains/advtrains/trackplacer.lua @@ -275,8 +275,7 @@ function tp.register_track_placer(nnprefix, imgprefix, dispname, def) groups={advtrains_trackplacer=1, digtron_on_place=1}, liquids_pointable = def.liquids_pointable, on_place = function(itemstack, placer, pointed_thing) - return advtrains.pcall(function() - local name = placer:get_player_name() + local name = placer:get_player_name() if not name then return itemstack, false end @@ -303,7 +302,6 @@ function tp.register_track_placer(nnprefix, imgprefix, dispname, def) end end return itemstack, true - end) end, }) end @@ -317,7 +315,6 @@ minetest.register_craftitem("advtrains:trackworker",{ wield_image = "advtrains_trackworker.png", stack_max = 1, on_place = function(itemstack, placer, pointed_thing) - return advtrains.pcall(function() local name = placer:get_player_name() if not name then return @@ -382,10 +379,8 @@ minetest.register_craftitem("advtrains:trackworker",{ advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[modpos+1], param2=node.param2}) end end - end) end, on_use=function(itemstack, user, pointed_thing) - return advtrains.pcall(function() local name = user:get_player_name() if not name then return @@ -430,7 +425,6 @@ minetest.register_craftitem("advtrains:trackworker",{ else atprint(name, dump(tp.tracks)) end - end) end, }) diff --git a/mods/advtrains/advtrains/tracks.lua b/mods/advtrains/advtrains/tracks.lua index 70372443..ba597202 100644 --- a/mods/advtrains/advtrains/tracks.lua +++ b/mods/advtrains/advtrains/tracks.lua @@ -469,7 +469,7 @@ function advtrains.register_tracks(tracktype, def, preset) tiles = {def.shared_texture or (def.texture_prefix.."_"..img_suffix..".png"), def.second_texture}, groups = { - attached_node=1, + attached_node = advtrains.IGNORE_WORLD and 0 or 1, advtrains_track=1, ["advtrains_track_"..tracktype]=1, save_in_at_nodedb=1, diff --git a/mods/advtrains/advtrains/trainhud.lua b/mods/advtrains/advtrains/trainhud.lua index db328247..6e69455a 100644 --- a/mods/advtrains/advtrains/trainhud.lua +++ b/mods/advtrains/advtrains/trainhud.lua @@ -43,7 +43,7 @@ function advtrains.on_control_change(pc, train, flip) else local act=false if pc.jump then - train.ctrl.user = 1 + train.ctrl_user = 1 act=true end -- If atc command set, only "Jump" key can clear command. To prevent accidental control. @@ -51,15 +51,15 @@ function advtrains.on_control_change(pc, train, flip) return end if pc.up then - train.ctrl.user=4 + train.ctrl_user=4 act=true end if pc.down then if train.velocity>0 then if pc.jump then - train.ctrl.user = 0 + train.ctrl_user = 0 else - train.ctrl.user = 2 + train.ctrl_user = 2 end act=true else @@ -82,7 +82,7 @@ function advtrains.on_control_change(pc, train, flip) end end if not act then - train.ctrl.user = nil + train.ctrl_user = nil end end end @@ -186,6 +186,9 @@ function advtrains.hud_train_format(train, flip) local tlev=train.lever or 1 if train.velocity==0 and not train.active_control then tlev=1 end + if train.hud_lzb_effect_tmr then + tlev=1 + end local ht = {"[combine:440x110:0,0=(advtrains_hud_bg.png^[resize\\:440x110)"} local st = {} @@ -245,7 +248,7 @@ function advtrains.hud_train_format(train, flip) if train.tarvelocity or train.atc_command then ht[#ht+1] = "10,10=(advtrains_hud_atc.png^[resize\\:30x30^[multiply\\:cyan)" end - if train.ctrl.lzb then + if train.hud_lzb_effect_tmr then ht[#ht+1] = "50,10=(advtrains_hud_lzb.png^[resize\\:30x30^[multiply\\:red)" end if train.is_shunt then @@ -274,10 +277,10 @@ function advtrains.hud_train_format(train, flip) ht[#ht+1] = sformat("%d,85=(advtrains_hud_arrow.png^[multiply\\:cyan^[transformFY^[makealpha\\:#000000)", 1+train.tarvelocity*11) end local lzb = train.lzb - if lzb and lzb.oncoming then - local oc = lzb.oncoming + if lzb and lzb.checkpoints then + local oc = lzb.checkpoints for i = 1, #oc do - local spd = oc[i].spd + local spd = oc[i].speed local c = not spd and "lime" or (type(spd) == "number" and (spd == 0) and "red" or "orange") or nil if c then ht[#ht+1] = sformat("130,10=(advtrains_hud_bg.png^[resize\\:30x5^[colorize\\:%s)",c) @@ -286,7 +289,7 @@ function advtrains.hud_train_format(train, flip) ht[#ht+1] = sformat("%d,50=(advtrains_hud_arrow.png^[multiply\\:red^[makealpha\\:#000000)", 1+spd*11) end local floor = math.floor - local dist = floor(((oc[i].idx or train.index)-train.index)) + local dist = floor(((oc[i].index or train.index)-train.index)) dist = math.max(0, math.min(999, dist)) for j = 1, 3, 1 do sevenseg(floor((dist/10^(3-j))%10), 119+j*11, 18, 4, 2, "[colorize\\:"..c) @@ -326,4 +329,4 @@ minetest.register_craft { {"default:paper", "advtrains:trackworker", "default:paper"}, {"default:paper", "default:paper", "default:paper"}, } -} \ No newline at end of file +} diff --git a/mods/advtrains/advtrains/trainlogic.lua b/mods/advtrains/advtrains/trainlogic.lua index 76bbb7a6..c9c7e769 100644 --- a/mods/advtrains/advtrains/trainlogic.lua +++ b/mods/advtrains/advtrains/trainlogic.lua @@ -36,6 +36,7 @@ end local t_accel_all={ [0] = -10, [1] = -3, + [11] = -2, -- calculation base for LZB [2] = -0.5, [4] = 0.5, } @@ -43,19 +44,35 @@ local t_accel_all={ local t_accel_eng={ [0] = 0, [1] = 0, + [11] = 0, [2] = 0, [4] = 1.5, } +local VLEVER_EMERG = 0 +local VLEVER_BRAKE = 1 +local VLEVER_LZBCALC = 11 +local VLEVER_ROLL = 2 +local VLEVER_HOLD = 3 +local VLEVER_ACCEL = 4 + +-- How far in front of a whole index with LZB 0 restriction the train should come to a halt +-- value must be between 0 and 0.5, exclusively +local LZB_ZERO_APPROACH_DIST = 0.1 +-- Speed the train temporarily approaches the stop point with +local LZB_ZERO_APPROACH_SPEED = 0.2 + + + tp_player_tmr = 0 -advtrains.mainloop_trainlogic=function(dtime) +advtrains.mainloop_trainlogic=function(dtime, stepno) --build a table of all players indexed by pts. used by damage and door system. advtrains.playersbypts={} for _, player in pairs(minetest.get_connected_players()) do if not advtrains.player_to_train_mapping[player:get_player_name()] then --players in train are not subject to damage - local ptspos=minetest.pos_to_string(vector.round(player:getpos())) + local ptspos=minetest.pos_to_string(vector.round(player:get_pos())) advtrains.playersbypts[ptspos]=player end end @@ -81,6 +98,7 @@ advtrains.mainloop_trainlogic=function(dtime) for k,v in pairs(advtrains.trains) do advtrains.atprint_context_tid=k + --atprint("=== Step",stepno,"===") advtrains.train_ensure_init(k, v) end @@ -113,11 +131,10 @@ function advtrains.tp_player_to_train(player) --set the player to the train position. --minetest will emerge the area and load the objects, which then will call reattach_all(). --because player is in mapping, it will not be subject to dying. - player:setpos(train.last_pos) + player:set_pos(train.last_pos) end end minetest.register_on_joinplayer(function(player) - return advtrains.pcall(function() advtrains.hud[player:get_player_name()] = nil advtrains.hhud[player:get_player_name()] = nil --independent of this, cause all wagons of the train which are loaded to reattach their players @@ -127,12 +144,10 @@ minetest.register_on_joinplayer(function(player) wagon:reattach_all() end end - end) end) minetest.register_on_dieplayer(function(player) - return advtrains.pcall(function() local pname=player:get_player_name() local id=advtrains.player_to_train_mapping[pname] if id then @@ -146,7 +161,6 @@ minetest.register_on_dieplayer(function(player) end end end - end) end) --[[ @@ -190,6 +204,8 @@ end function advtrains.get_acceleration(train, lever) local acc_all = t_accel_all[lever] + if not acc_all then return 0 end + local acc_eng = t_accel_eng[lever] local nwagons = #train.trainparts if nwagons == 0 then @@ -215,14 +231,16 @@ local function mkcallback(name) assertt(func, "function") table.insert(callt, func) end - return callt, function(id, train) + return callt, function(id, train, param1, param2, param3) for _,f in ipairs(callt) do - f(id, train) + f(id, train, param1, param2, param3) end end end local callbacks_new_path, run_callbacks_new_path = mkcallback("new_path") +local callbacks_invahead +callbacks_invahead, advtrains.run_callbacks_invahead = mkcallback("invalidate_ahead") -- (id, train, start_idx) local callbacks_update, run_callbacks_update = mkcallback("update") local callbacks_create, run_callbacks_create = mkcallback("create") local callbacks_remove, run_callbacks_remove = mkcallback("remove") @@ -240,21 +258,25 @@ function advtrains.train_ensure_init(id, train) end train.dirty = true - if train.no_step then return nil end + if train.no_step then + --atprint("in ensure_init: no_step set, train step ignored!") + return nil + end assertdef(train, "velocity", 0) --assertdef(train, "tarvelocity", 0) assertdef(train, "acceleration", 0) assertdef(train, "id", id) - assertdef(train, "ctrl", {}) if not train.drives_on or not train.max_speed then + --atprint("in ensure_init: missing properties, updating!") advtrains.update_trainpart_properties(id) end --restore path if not train.path then + --atprint("in ensure_init: Needs restoring path...") if not train.last_pos then atlog("Train",id,": Restoring path failed, no last_pos set! Train will be disabled. You can try to fix the issue in the save file.") train.no_step = true @@ -277,6 +299,8 @@ function advtrains.train_ensure_init(id, train) local result = advtrains.path_create(train, train.last_pos, train.last_connid or 1, train.last_frac or 0) + --atprint("in ensure_init: path_create result ",result) + if result==false then atlog("Train",id,": Restoring path failed, node at",train.last_pos,"is gone! Train will be disabled. You can try to place a rail at this position and restart the server.") train.no_step = true @@ -304,6 +328,10 @@ function advtrains.train_ensure_init(id, train) return true end +local function v_target_apply(v_targets, lever, vel) + v_targets[lever] = v_targets[lever] and math.min(v_targets[lever], vel) or vel +end + function advtrains.train_step_b(id, train, dtime) if train.no_step or train.wait_for_path or not train.path then return end @@ -311,25 +339,49 @@ function advtrains.train_step_b(id, train, dtime) advtrains.path_get(train, atfloor(train.index + 2)) advtrains.path_get(train, atfloor(train.end_index - 1)) + -- run pre-move hooks + -- TODO: if more pre-move hooks are added, make a separate callback hook + advtrains.lzb_look_ahead(id, train) + + --[[ again, new velocity control: + There are two heterogenous means of control: + -> set a fixed acceleration and ignore speed (user) + -> steer towards a target speed, distance doesn't matter + -> needs to specify the maximum acceleration/deceleration values they are willing to accelerate/brake with + -> Reach a target speed after a certain distance (LZB, handled specially) + + ]]-- + --- 3. handle velocity influences --- - local train_moves=(train.velocity~=0) - local tarvel_cap = train.speed_restriction + + local v0 = train.velocity + local sit_v_cap = train.max_speed -- Maximum speed in current situation (multiple limit factors) + -- The desired speed change issued by the active control (user or atc) + local ctrl_v_tar -- desired speed which should not be crossed by braking or accelerating + local ctrl_accelerating = false -- whether the train should accelerate + local ctrl_braking = false -- whether the train should brake + local ctrl_lever -- the lever value to use to calculate the acceleration + -- the final speed change after applying LZB + local v_cap -- absolute maximum speed + local v_tar -- desired speed which should not be crossed by braking or accelerating + local accelerating = false-- whether the train should accelerate + local braking = false -- whether the train should brake + local lever -- the lever value to use to calculate the acceleration + local train_moves = (v0 > 0) if train.recently_collided_with_env then - tarvel_cap=0 if not train_moves then train.recently_collided_with_env=nil--reset status when stopped end - end - if train.locomotives_in_train==0 then - tarvel_cap=0 - end - - --- 3a. this can be useful for debugs/warnings and is used for check_trainpartload --- - local t_info, train_pos=sid(id), advtrains.path_get(train, atfloor(train.index)) - if train_pos then - t_info=t_info.." @"..minetest.pos_to_string(train_pos) - --atprint("train_pos:",train_pos) + --atprint("in train_step_b: applying collided_with_env") + sit_v_cap = 0 + elseif train.locomotives_in_train==0 then + --atprint("in train_step_b: applying no_locomotives") + sit_v_cap = 0 + -- interlocking speed restriction + elseif train.speed_restriction then + --atprint("in train_step_b: applying interlocking speed restriction",train.speed_restriction) + sit_v_cap = train.speed_restriction end --apply off-track handling: @@ -337,38 +389,47 @@ function advtrains.train_step_b(id, train, dtime) local back_off_track=train.end_index 1) then + --atprint("in train_step_b: applying back_off_track") + sit_v_cap = 1 + elseif front_off_track then + --atprint("in train_step_b: applying front_off_track") + sit_v_cap = 0 end - -- Driving control rework: - --[[ - Items are only defined when something is controlling them. - In order of precedence. - train.ctrl = { - lzb = restrictive override from LZB - user = User input from driverstand - atc = ATC command override (determined here) - } - The code here determines the precedence and writes the final control into train.lever - ]] --interpret ATC command and apply auto-lever control when not actively controlled - local trainvelocity = train.velocity - - if train.ctrl.user then + local userc = train.ctrl_user + if userc then + --atprint("in train_step_b: ctrl_user active",userc) advtrains.atc.train_reset_command(train) + + if userc >= VLEVER_ACCEL then + ctrl_accelerating = true + else + ctrl_braking = true + end + ctrl_lever = userc else + if train.atc_command then + if (not train.atc_delay or train.atc_delay<=0) and not train.atc_wait_finish then + advtrains.atc.execute_atc_command(id, train) + else + train.atc_delay=train.atc_delay-dtime + end + elseif train.atc_delay then + train.atc_delay = nil + end + local braketar = train.atc_brake_target local emerg = false -- atc_brake_target==-1 means emergency brake (BB command) if braketar == -1 then braketar = 0 emerg = true end - if braketar and braketar>=trainvelocity then + --atprint("in train_step_b: ATC: brake state braketar=",braketar,"emerg=",emerg) + if braketar and braketar>=v0 then + --atprint("in train_step_b: ATC: brake target cleared") train.atc_brake_target=nil braketar = nil end @@ -380,111 +441,175 @@ function advtrains.train_step_b(id, train, dtime) train.atc_wait_finish=nil end end - if train.atc_command then - if (not train.atc_delay or train.atc_delay<=0) and not train.atc_wait_finish then - advtrains.atc.execute_atc_command(id, train) - else - train.atc_delay=train.atc_delay-dtime - end - elseif train.atc_delay then - train.atc_delay = nil - end - train.ctrl.atc = nil - if train.tarvelocity and train.tarvelocity>trainvelocity then - train.ctrl.atc=4 - end - if train.tarvelocity and train.tarvelocityv0 then + --atprint("in train_step_b: applying ATC ACCEL", train.tarvelocity) + ctrl_accelerating = true + ctrl_lever = VLEVER_ACCEL + elseif train.tarvelocity and train.tarvelocitytarvel_cap then - tmp_lever = 0 - end - - train.lever = tmp_lever - - --- 3a. actually calculate new velocity --- - if tmp_lever~=3 then - local accel = advtrains.get_acceleration(train, tmp_lever) - local vdiff = accel*dtime - - -- This should only be executed when we are accelerating - -- I suspect that this causes the braking bugs - if tmp_lever == 4 then - - -- ATC control exception: don't cross tarvelocity if - -- atc provided a target_vel - if train.tarvelocity then - local tvdiff = train.tarvelocity - trainvelocity - if tvdiff~=0 and math.abs(vdiff) > math.abs(tvdiff) then - --applying this change would cross tarvelocity - --atdebug("In Tvdiff condition, clipping",vdiff,"to",tvdiff) - --atdebug("vel=",trainvelocity,"tvel=",train.tarvelocity) - vdiff=tvdiff - end - end - if tarvel_cap and trainvelocity<=tarvel_cap and trainvelocity+vdiff>tarvel_cap then - vdiff = tarvel_cap - train.velocity - end - local mspeed = (train.max_speed or 10) - if trainvelocity+vdiff > mspeed then - vdiff = mspeed - trainvelocity + local dst_curr_v = v0 * dtime + new_index_curr_tv = advtrains.path_get_index_by_offset(train, train.index, dst_curr_v) + local i = atfloor(train.index) + local psp + while true do + psp = train.path_speed[i] + if psp then + lzb_v_cap = lzb_v_cap and math.min(lzb_v_cap, psp) or psp + if psp == 0 and not lzb_next_zero_barrier then + --atprint("in train_step_b: Found zero barrier: ",i) + lzb_next_zero_barrier = i - LZB_ZERO_APPROACH_DIST end end - - if trainvelocity+vdiff < 0 then - vdiff = - trainvelocity + if i > new_index_curr_tv then + break end - - - train.acceleration=vdiff - train.velocity=train.velocity+vdiff - --if train.ctrl.user then - -- train.tarvelocity = train.velocity - --end - else + i = i + 1 + end + + if lzb_next_zero_barrier and train.index < lzb_next_zero_barrier then + lzb_v_cap = LZB_ZERO_APPROACH_SPEED + end + + --atprint("in train_step_b: LZB calculation yields newindex=",new_index_curr_tv,"lzbtarget=",lzb_v_cap,"zero_barr=",lzb_next_zero_barrier,"") + + -- LZB HUD: decrement timer and delete when 0 + if train.hud_lzb_effect_tmr then + if train.hud_lzb_effect_tmr <=0 then + train.hud_lzb_effect_tmr = nil + else + train.hud_lzb_effect_tmr = train.hud_lzb_effect_tmr - 1 + end + end + + -- We now need to bring ctrl_*, sit_v_cap and lzb_v_cap together to determine the final controls. + local v_cap = sit_v_cap -- always defined, by default train.max_speed + if lzb_v_cap and lzb_v_cap < v_cap then + v_cap = lzb_v_cap + lever = VLEVER_BRAKE -- actually irrelevant, acceleration is not considered anyway unless v_tar is also set. + -- display LZB control override in the HUD + if lzb_v_cap <= v0 then + train.hud_lzb_effect_tmr = 1 + -- This is to signal the HUD that LZB is active. This works as a timer to avoid HUD blinking + end + end + + v_tar = ctrl_v_tar + -- if v_cap is smaller than the current speed, we need to brake in all cases. + if v_cap < v0 then + braking = true + lever = VLEVER_BRAKE + -- set v_tar to v_cap to not slow down any further than required. + -- unless control wants us to brake too, then we use control's v_tar. + if not ctrl_v_tar or ctrl_v_tar > v_cap then + v_tar = v_cap + end + else -- else, use what the ctrl says + braking = ctrl_braking + accelerating = ctrl_accelerating and not braking + lever = ctrl_lever + end + train.lever = lever + + --atprint("in train_step_b: final control: accelerating",accelerating,"braking",braking,"lever", lever, "target", v_tar) + + -- reset train acceleration when holding speed + if not braking and not accelerating then train.acceleration = 0 end + --- 3b. if braking, modify the velocity BEFORE the movement + if braking then + local dv = advtrains.get_acceleration(train, lever) * dtime + local v1 = v0 + dv + if v_tar and v1 < v_tar then + --atprint("in train_step_b: Braking: Hit v_tar!") + v1 = v_tar + end + if v1 > v_cap then + --atprint("in train_step_b: Braking: Hit v_cap!") + v1 = v_cap + end + if v1 < 0 then + --atprint("in train_step_b: Braking: Hit 0!") + v1 = 0 + end + + train.acceleration = (v1 - v0) / dtime + train.velocity = v1 + --atprint("in train_step_b: Braking: New velocity",v1," (yields acceleration",train.acceleration,")") + -- make saved new_index_curr_tv invalid because speed has changed + new_index_curr_tv = nil + end + --- 4. move train --- + -- if we have calculated the new end index before, don't do that again + if not new_index_curr_tv then + local dst_curr_v = train.velocity * dtime + new_index_curr_tv = advtrains.path_get_index_by_offset(train, train.index, dst_curr_v) + --atprint("in train_step_b: movement calculation (re)done, yields newindex=",new_index_curr_tv) + else + --atprint("in train_step_b: movement calculation reusing from LZB newindex=",new_index_curr_tv) + end - local idx_floor = math.floor(train.index) - local pdist = (train.path_dist[idx_floor+1] - train.path_dist[idx_floor]) - local distance = (train.velocity*dtime) / pdist - - --debugging code - --train.debug = atdump(train.ctrl).."step_dist: "..math.floor(distance*1000) - - train.index=train.index+distance + -- if the zeroappr mechanism has hit, go no further than zeroappr index + if lzb_next_zero_barrier and new_index_curr_tv > lzb_next_zero_barrier then + --atprint("in train_step_b: Zero barrier hit, clipping to newidx_tv=",new_index_curr_tv, "zb_idx=",lzb_next_zero_barrier) + new_index_curr_tv = lzb_next_zero_barrier + end + train.index = new_index_curr_tv recalc_end_index(train) - + --atprint("in train_step_b: New index",train.index,"end",train.end_index,"vel",train.velocity) + + --- 4a. if accelerating, modify the velocity AFTER the movement + if accelerating then + local dv = advtrains.get_acceleration(train, lever) * dtime + local v1 = v0 + dv + if v_tar and v1 > v_tar then + --atprint("in train_step_b: Accelerating: Hit v_tar!") + v1 = v_tar + end + if v1 > v_cap then + --atprint("in train_step_b: Accelerating: Hit v_cap!") + v1 = v_cap + end + + train.acceleration = (v1 - v0) / dtime + train.velocity = v1 + --atprint("in train_step_b: Accelerating: New velocity",v1," (yields acceleration",train.acceleration,")") + end end function advtrains.train_step_c(id, train, dtime) @@ -609,8 +734,9 @@ local callbacks_enter_node, run_callbacks_enter_node = mknodecallback("enter") local callbacks_leave_node, run_callbacks_leave_node = mknodecallback("leave") -- Node callback for approaching --- Might be called multiple times, whenever path is recalculated --- signature is function(pos, id, train, index, lzbdata) +-- Might be called multiple times, whenever path is recalculated. Also called for the first node the train is standing on, then has_entered is true. +-- signature is function(pos, id, train, index, has_entered, lzbdata) +-- has_entered: true if the "enter" callback has already been executed for this train in this location -- lzbdata: arbitrary data (shared between all callbacks), deleted when LZB is restarted. -- These callbacks are called in order of distance as train progresses along tracks, so lzbdata can be used to -- keep track of a train's state once it passes this point @@ -666,16 +792,19 @@ end function advtrains.tnc_call_approach_callback(pos, train_id, train, index, lzbdata) --atdebug("tnc approach",pos,train_id, lzbdata) + local has_entered = atround(train.index) == index + local node = advtrains.ndb.get_node(pos) --this spares the check if node is nil, it has a name in any case local mregnode=minetest.registered_nodes[node.name] if mregnode and mregnode.advtrains and mregnode.advtrains.on_train_approach then - mregnode.advtrains.on_train_approach(pos, train_id, train, index, lzbdata) + mregnode.advtrains.on_train_approach(pos, train_id, train, index, has_entered, lzbdata) end -- call other registered callbacks - run_callbacks_approach_node(pos, train_id, train, index, lzbdata) + run_callbacks_approach_node(pos, train_id, train, index, has_entered, lzbdata) end +-- === te callback definition for tnc node callbacks === advtrains.te_register_on_new_path(function(id, train) train.tnc = { @@ -865,7 +994,7 @@ function advtrains.spawn_wagons(train_id) atwarn("Train",train_id,"Wagon #",i,": Saved train ID",data.train_id,"did not match!") data.train_id = train_id end - if not advtrains.wagon_objects[w_id] or not advtrains.wagon_objects[w_id]:getyaw() then + if not advtrains.wagon_objects[w_id] or not advtrains.wagon_objects[w_id]:get_yaw() then -- eventually need to spawn new object. check if position is loaded. local index = advtrains.path_get_index_by_offset(train, train.index, -data.pos_in_train) local pos = advtrains.path_get(train, atfloor(index)) @@ -1017,7 +1146,7 @@ end function advtrains.train_check_couples(train) --atdebug("rechecking couples") if train.cpl_front then - if not train.cpl_front:getyaw() then + if not train.cpl_front:get_yaw() then -- objectref is no longer valid. reset. train.cpl_front = nil end @@ -1047,7 +1176,7 @@ function advtrains.train_check_couples(train) end end if train.cpl_back then - if not train.cpl_back:getyaw() then + if not train.cpl_back:get_yaw() then -- objectref is no longer valid. reset. train.cpl_back = nil end @@ -1195,6 +1324,18 @@ function advtrains.invalidate_all_paths(pos) advtrains.invalidate_path(id) end end + +-- Calls invalidate_path_ahead on all trains occupying (having paths over) this node +-- Can be called during train step. +function advtrains.invalidate_all_paths_ahead(pos) + local tab = advtrains.occ.get_trains_over(pos) + + for id,index in pairs(tab) do + local train = advtrains.trains[id] + advtrains.path_invalidate_ahead(train, index, true) + end +end + function advtrains.invalidate_path(id) --atdebug("Path invalidate:",id) local v=advtrains.trains[id] diff --git a/mods/advtrains/advtrains/wagons.lua b/mods/advtrains/advtrains/wagons.lua index 1c663feb..f918571d 100644 --- a/mods/advtrains/advtrains/wagons.lua +++ b/mods/advtrains/advtrains/wagons.lua @@ -10,6 +10,8 @@ -- TP delay when getting off wagon local GETOFF_TP_DELAY = 0.5 +local IGNORE_WORLD = advtrains.IGNORE_WORLD + advtrains.wagons = {} advtrains.wagon_prototypes = {} advtrains.wagon_objects = {} @@ -154,7 +156,7 @@ function wagon:ensure_init() atwarn("wagon",self.id,"uninitialized, removing") self:destroy() else - self.object:setvelocity({x=0,y=0,z=0}) + self.object:set_velocity({x=0,y=0,z=0}) end return false end @@ -166,7 +168,6 @@ end -- Remove the wagon function wagon:on_punch(puncher, time_from_last_punch, tool_capabilities, direction) - return advtrains.pcall(function() if not self:ensure_init() then return end local data = advtrains.wagons[self.id] @@ -223,7 +224,6 @@ function wagon:on_punch(puncher, time_from_last_punch, tool_capabilities, direct for _,item in ipairs(self.drops or {self.name}) do inv:add_item("main", item) end - end) end function wagon:destroy() --some rules: @@ -268,11 +268,15 @@ function wagon:is_driver_stand(seat) end function wagon:on_step(dtime) - return advtrains.pcall(function() if not self:ensure_init() then return end + if advtrains.is_no_action() then + self.object:remove() + return + end + local t=os.clock() - local pos = self.object:getpos() + local pos = self.object:get_pos() local data = advtrains.wagons[self.id] if not pos then @@ -400,8 +404,8 @@ function wagon:on_step(dtime) --for path to be available. if not, skip step if not train.path or train.no_step then - self.object:setvelocity({x=0, y=0, z=0}) - self.object:setacceleration({x=0, y=0, z=0}) + self.object:set_velocity({x=0, y=0, z=0}) + self.object:set_acceleration({x=0, y=0, z=0}) return end if not data.pos_in_train then @@ -444,7 +448,7 @@ function wagon:on_step(dtime) end --checking for environment collisions(a 3x3 cube around the center) - if is_in_loaded_area and not train.recently_collided_with_env then + if not IGNORE_WORLD and is_in_loaded_area and not train.recently_collided_with_env then local collides=false local exh = self.extent_h or 1 local exv = self.extent_v or 2 @@ -470,7 +474,7 @@ function wagon:on_step(dtime) -- FIX: Need to do this after the yaw calculation if is_in_loaded_area and data.pos_in_trainparts and data.pos_in_trainparts>1 then if train.velocity==0 then - if not self.discouple or not self.discouple.object:getyaw() then + if not self.discouple or not self.discouple.object:get_yaw() then atprint(self.id,"trying to spawn discouple") local dcpl_pos = vector.add(pos, {y=0, x=-math.sin(yaw)*self.wagon_span, z=math.cos(yaw)*self.wagon_span}) local object=minetest.add_entity(dcpl_pos, "advtrains:discouple") @@ -483,7 +487,7 @@ function wagon:on_step(dtime) end end else - if self.discouple and self.discouple.object:getyaw() then + if self.discouple and self.discouple.object:get_yaw() then self.discouple.object:remove() atprint(self.id," removing discouple") end @@ -491,8 +495,8 @@ function wagon:on_step(dtime) end --FIX: use index of the wagon, not of the train. - local velocity = train.velocity - local acceleration = (train.acceleration or 0) + local velocity = train.velocity * advtrains.global_slowdown + local acceleration = (train.acceleration or 0) * (advtrains.global_slowdown*advtrains.global_slowdown) local velocityvec = vector.multiply(vdir, velocity) local accelerationvec = vector.multiply(vdir, acceleration) @@ -539,9 +543,9 @@ function wagon:on_step(dtime) or self.old_yaw~=yaw or updatepct_timer_elapsed then--only send update packet if something changed - self.object:setpos(pos) - self.object:setvelocity(velocityvec) - self.object:setacceleration(accelerationvec) + self.object:set_pos(pos) + self.object:set_velocity(velocityvec) + self.object:set_acceleration(accelerationvec) if #self.seats > 0 and self.old_yaw ~= yaw then if not self.player_yaw then @@ -574,7 +578,7 @@ function wagon:on_step(dtime) end self.object:set_rotation({x=pitch, y=yaw, z=0}) else - self.object:setyaw(yaw) + self.object:set_yaw(yaw) end if self.update_animation then @@ -595,11 +599,9 @@ function wagon:on_step(dtime) self.old_acceleration_vector=accelerationvec self.old_yaw=yaw atprintbm("wagon step", t) - end) end function wagon:on_rightclick(clicker) - return advtrains.pcall(function() if not self:ensure_init() then return end if not clicker or not clicker:is_player() then return @@ -687,7 +689,6 @@ function wagon:on_rightclick(clicker) self:show_get_on_form(pname) end end - end) end function wagon:get_on(clicker, seatno) @@ -770,7 +771,7 @@ function wagon:get_off(seatno) --atdebug("platpos:", platpos, "offpos:", offpos) if minetest.get_item_group(minetest.get_node(platpos).name, "platform")>0 then - minetest.after(GETOFF_TP_DELAY, function() clicker:setpos(offpos) end) + minetest.after(GETOFF_TP_DELAY, function() clicker:set_pos(offpos) end) --atdebug("tp",offpos) return end @@ -790,7 +791,7 @@ function wagon:get_off(seatno) offp=vector.add({x=isx and r*2 or 0, y=1, z=not isx and r*2 or 0}, objpos) --atdebug("platpos:", p, "offpos:", offp) if minetest.get_item_group(minetest.get_node(p).name, "platform")>0 then - minetest.after(GETOFF_TP_DELAY, function() clicker:setpos(offp) end) + minetest.after(GETOFF_TP_DELAY, function() clicker:set_pos(offp) end) --atdebug("tp",offp) return end @@ -987,10 +988,10 @@ function wagon:show_bordcom(pname) -- Interlocking functionality: If the interlocking module is loaded, you can set the signal aspect -- from inside the train - if advtrains.interlocking and train.lzb and #train.lzb.oncoming > 0 then + if advtrains.interlocking and train.lzb and #train.lzb.checkpoints > 0 then local i=1 - while train.lzb.oncoming[i] do - local oci = train.lzb.oncoming[i] + while train.lzb.checkpoints[i] do + local oci = train.lzb.checkpoints[i] if oci.udata and oci.udata.signal_pos then if advtrains.interlocking.db.get_sigd_for_signal(oci.udata.signal_pos) then form = form .. "button[4.5,8;5,1;ilrs;Remote Routesetting]" @@ -999,6 +1000,9 @@ function wagon:show_bordcom(pname) end i=i+1 end + if train.ars_disable then + form = form .. "button[4.5,7;5,1;ilarsenable;Clear 'Disable ARS' flag]" + end end minetest.show_formspec(pname, "advtrains_bordcom_"..self.id, form) @@ -1071,18 +1075,23 @@ function wagon:handle_bordcom_fields(pname, formname, fields) -- Interlocking functionality: If the interlocking module is loaded, you can set the signal aspect -- from inside the train - if fields.ilrs and advtrains.interlocking and train.lzb and #train.lzb.oncoming > 0 then - local i=1 - while train.lzb.oncoming[i] do - local oci = train.lzb.oncoming[i] - if oci.udata and oci.udata.signal_pos then - local sigd = advtrains.interlocking.db.get_sigd_for_signal(oci.udata.signal_pos) - if sigd then - advtrains.interlocking.show_signalling_form(sigd, pname) - return + if advtrains.interlocking then + if fields.ilrs and train.lzb and #train.lzb.checkpoints > 0 then + local i=1 + while train.lzb.checkpoints[i] do + local oci = train.lzb.checkpoints[i] + if oci.udata and oci.udata.signal_pos then + local sigd = advtrains.interlocking.db.get_sigd_for_signal(oci.udata.signal_pos) + if sigd then + advtrains.interlocking.show_signalling_form(sigd, pname) + return + end end + i=i+1 end - i=i+1 + end + if fields.ilarsenable then + advtrains.interlocking.ars_set_disable(train, false) end end @@ -1093,7 +1102,6 @@ function wagon:handle_bordcom_fields(pname, formname, fields) end minetest.register_on_player_receive_fields(function(player, formname, fields) - return advtrains.pcall(function() local uid=string.match(formname, "^advtrains_geton_(.+)$") if uid then for _,wagon in pairs(minetest.luaentities) do @@ -1177,7 +1185,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end end end - end) end) function wagon:seating_from_key_helper(pname, fields, no) local data = advtrains.wagons[self.id] @@ -1381,7 +1388,6 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati groups = { not_in_creative_inventory = nincreative and 1 or 0}, on_place = function(itemstack, placer, pointed_thing) - return advtrains.pcall(function() if not pointed_thing.type == "node" then return end @@ -1419,8 +1425,6 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati itemstack:take_item() end return itemstack - - end) end, }) end diff --git a/mods/advtrains/advtrains_interlocking/approach.lua b/mods/advtrains/advtrains_interlocking/approach.lua index 8e90b5a7..f60468a4 100644 --- a/mods/advtrains/advtrains_interlocking/approach.lua +++ b/mods/advtrains/advtrains_interlocking/approach.lua @@ -19,38 +19,50 @@ local function get_over_function(speed, shunt) if speed == 0 and minetest.settings:get_bool("at_il_force_lzb_halt") then atwarn(id,"overrun LZB 0 restriction (red signal) ",pos) -- Set train 1 index backward. Hope this does not lead to bugs... - train.index = index - 0.5 - train.velocity = 0 - train.ctrl.lzb = 0 - minetest.after(0, advtrains.invalidate_path, id) + --train.index = index - 0.5 + train.speed_restriction = 0 + + --TODO temporary + --advtrains.drb_dump(id) + --error("Debug: "..id.." triggered LZB-0") else train.speed_restriction = speed train.is_shunt = shunt end + --atdebug("train drove over IP: speed=",speed,"shunt=",shunt) end end -advtrains.tnc_register_on_approach(function(pos, id, train, index, lzbdata) +advtrains.tnc_register_on_approach(function(pos, id, train, index, has_entered, lzbdata) --atdebug(id,"IL ApprC",pos,index,lzbdata) --train.debug = advtrains.print_concat_table({train.is_shunt,"|",index,"|",lzbdata}) local pts = advtrains.roundfloorpts(pos) local cn = train.path_cn[index] - local travsht = lzbdata.travsht + local travsht = lzbdata.il_shunt + + local travspd = lzbdata.il_speed if travsht==nil then - travsht = train.is_shunt + -- lzbdata has reset + travspd = train.speed_restriction + travsht = train.is_shunt or false end - local travspd = lzbdata.travspd - local travwspd = lzbdata.travwspd + -- check for signal local asp, spos = il.db.get_ip_signal_asp(pts, cn) -- do ARS if needed - if spos then + local ars_enabled = not train.ars_disable + -- Note on ars_disable: + -- Theoretically, the ars_disable flag would need to behave like the speed restriction field: it should be + -- stored in lzbdata and updated once the train drives over. However, for the sake of simplicity, it is simply + -- a value in the train. In this case, this is sufficient because once a train triggers ARS for the first time, + -- resetting the path does not matter to the set route and ARS doesn't need to be called again. + if spos and ars_enabled then --atdebug(id,"IL Spos (ARS)",spos,asp) local sigd = il.db.get_sigd_for_signal(spos) if sigd then @@ -60,22 +72,22 @@ advtrains.tnc_register_on_approach(function(pos, id, train, index, lzbdata) --atdebug("trav: ",pos, cn, asp, spos, "travsht=", lzb.travsht) local lspd if asp then - --atdebug(id,"IL Signal",spos,asp) + --atdebug(id,"IL Signal",spos, asp, lzbdata, "trainstate", train.speed_restriction, train.is_shunt) local nspd = 0 --interpreting aspect and determining speed to proceed if travsht then --shunt move - if asp.shunt.free then + if asp.shunt then nspd = SHUNT_SPEED_MAX - elseif asp.shunt.proceed_as_main and asp.main.free then - nspd = asp.main.speed + elseif asp.proceed_as_main and asp.main ~= 0 then + nspd = asp.main travsht = false end else --train move - if asp.main.free then - nspd = asp.main.speed - elseif asp.shunt.free then + if asp.main ~= 0 then + nspd = asp.main + elseif asp.shunt then nspd = SHUNT_SPEED_MAX travsht = true end @@ -89,25 +101,26 @@ advtrains.tnc_register_on_approach(function(pos, id, train, index, lzbdata) end end - local nwspd = asp.info.w_speed - if nwspd then - if nwspd == -1 then - travwspd = nil - else - travwspd = nwspd - end - end - --atdebug("ns,wns,ts,wts", nspd, nwspd, travspd, travwspd) + --atdebug("ns,ts", nspd, travspd) + lspd = travspd - if travwspd and (not lspd or lspd>travwspd) then - lspd = travwspd - end local udata = {signal_pos = spos} local callback = get_over_function(lspd, travsht) - advtrains.lzb_add_checkpoint(train, index, lspd, callback, udata) + lzbdata.il_shunt = travsht + lzbdata.il_speed = travspd + --atdebug("new lzbdata",lzbdata) + advtrains.lzb_add_checkpoint(train, index, lspd, callback, lzbdata, udata) end - lzbdata.travsht = travsht - lzbdata.travspd = travspd - lzbdata.travwspd = travwspd end) + +-- Set the ars_disable flag to the value passed +-- Triggers a path invalidation if set to false +function advtrains.interlocking.ars_set_disable(train, value) + if value then + train.ars_disable = true + else + train.ars_disable = nil + minetest.after(0, advtrains.path_invalidate, train) + end +end diff --git a/mods/advtrains/advtrains_interlocking/database.lua b/mods/advtrains/advtrains_interlocking/database.lua index 82c7e251..68d41382 100644 --- a/mods/advtrains/advtrains_interlocking/database.lua +++ b/mods/advtrains/advtrains_interlocking/database.lua @@ -131,6 +131,37 @@ function ildb.load(data) if data.npr_rails then advtrains.interlocking.npr_rails = data.npr_rails end + + --COMPATIBILITY to Signal aspect format + -- TODO remove in time... + for pts,tcb in pairs(track_circuit_breaks) do + for connid, tcbs in ipairs(tcb) do + if tcbs.routes then + for _,route in ipairs(tcbs.routes) do + if route.aspect then + -- transform the signal aspect format + local asp = route.aspect + if type(asp.main) == "table" then + atwarn("Transforming route aspect of signal",pts,"/",connid,"") + if asp.main.free then + asp.main = asp.main.speed + else + asp.main = 0 + end + if asp.dst.free then + asp.dst = asp.dst.speed + else + asp.dst = 0 + end + asp.proceed_as_main = asp.shunt.proceed_as_main + asp.shunt = asp.shunt.free + -- Note: info table not transferred, it's not used right now + end + end + end + end + end + end end function ildb.save() @@ -149,6 +180,7 @@ end --[[ TCB data structure { +-- This is the "A" side of the TCB [1] = { -- Variant: with adjacent TCs. ts_id = -- ID of the assigned track section signal = -- optional: when set, routes can be set from this tcb/direction and signal @@ -164,6 +196,7 @@ TCB data structure routes = { } -- a collection of routes from this signal route_auto = -- When set, we will automatically re-set the route (designated by routeset) }, +-- This is the "B" side of the TCB [2] = { -- Variant: end of track-circuited area (initial state of TC) ts_id = nil, -- this is the indication for end_of_interlocking section_free = , --this can be set by an exit node via mesecons or atlatc, diff --git a/mods/advtrains/advtrains_interlocking/demosignals.lua b/mods/advtrains/advtrains_interlocking/demosignals.lua index ab7a8b61..fe60a73d 100644 --- a/mods/advtrains/advtrains_interlocking/demosignals.lua +++ b/mods/advtrains/advtrains_interlocking/demosignals.lua @@ -6,10 +6,10 @@ local setaspect = function(pos, node, asp) - if not asp.main.free then + if asp.main == 0 then advtrains.ndb.swap_node(pos, {name="advtrains_interlocking:ds_danger"}) else - if asp.dst.free and asp.main.speed == -1 then + if asp.dst ~= 0 and asp.main == -1 then advtrains.ndb.swap_node(pos, {name="advtrains_interlocking:ds_free"}) else advtrains.ndb.swap_node(pos, {name="advtrains_interlocking:ds_slow"}) @@ -22,18 +22,10 @@ local setaspect = function(pos, node, asp) end local suppasp = { - main = { - free = nil, - speed = {6, -1}, - }, - dst = { - free = nil, - speed = nil, - }, - shunt = { - free = false, - proceed_as_main = true, - }, + main = {0, 6, -1}, + dst = {0, false}, + shunt = false, + proceed_as_main = true, info = { call_on = false, dead_end = false, @@ -74,10 +66,7 @@ minetest.register_node("advtrains_interlocking:ds_free", { supported_aspects = suppasp, get_aspect = function(pos, node) return { - main = { - free = true, - speed = -1, - } + main = -1, } end, }, @@ -98,10 +87,7 @@ minetest.register_node("advtrains_interlocking:ds_slow", { supported_aspects = suppasp, get_aspect = function(pos, node) return { - main = { - free = true, - speed = 6, - } + main = 6, } end, }, diff --git a/mods/advtrains/advtrains_interlocking/route_prog.lua b/mods/advtrains/advtrains_interlocking/route_prog.lua index eadfd93b..6abe431b 100644 --- a/mods/advtrains/advtrains_interlocking/route_prog.lua +++ b/mods/advtrains/advtrains_interlocking/route_prog.lua @@ -112,7 +112,8 @@ route = { next = , -- of the next (note: next) TCB on the route locks = { = "state"} -- route locks of this route segment } - terminal = + terminal = , + aspect = ,--note, might change in future } The first item in the TCB path (namely i=0) is always the start signal of this route, so this is left out. diff --git a/mods/advtrains/advtrains_interlocking/route_ui.lua b/mods/advtrains/advtrains_interlocking/route_ui.lua index 71fed097..64e45ee3 100644 --- a/mods/advtrains/advtrains_interlocking/route_ui.lua +++ b/mods/advtrains/advtrains_interlocking/route_ui.lua @@ -129,7 +129,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) advtrains.interlocking.show_route_edit_form(pname, sigd, routeid) end - advtrains.interlocking.show_signal_aspect_selector(pname, suppasp, route.name, callback, route.aspect) + advtrains.interlocking.show_signal_aspect_selector(pname, suppasp, route.name, callback, route.aspect or advtrains.interlocking.GENERIC_FREE) return end if fields.delete then diff --git a/mods/advtrains/advtrains_interlocking/routesetting.lua b/mods/advtrains/advtrains_interlocking/routesetting.lua index 575b053e..67efaea8 100644 --- a/mods/advtrains/advtrains_interlocking/routesetting.lua +++ b/mods/advtrains/advtrains_interlocking/routesetting.lua @@ -6,21 +6,6 @@ local function sigd_to_string(sigd) return minetest.pos_to_string(sigd.p).." / "..lntrans[sigd.s] end -local asp_generic_free = { - main = { - free = true, - speed = -1, - }, - shunt = { - free = false, - }, - dst = { - free = true, - speed = -1, - }, - info = {} -} - local ildb = advtrains.interlocking.db local ilrs = {} @@ -127,7 +112,7 @@ function ilrs.set_route(signal, route, try) } if c_tcbs.signal then c_tcbs.route_committed = true - c_tcbs.aspect = route.aspect or asp_generic_free + c_tcbs.aspect = route.aspect or advtrains.interlocking.GENERIC_FREE c_tcbs.route_origin = signal advtrains.interlocking.update_signal_aspect(c_tcbs) end diff --git a/mods/advtrains/advtrains_interlocking/signal_api.lua b/mods/advtrains/advtrains_interlocking/signal_api.lua index 9729195e..a44eda6d 100644 --- a/mods/advtrains/advtrains_interlocking/signal_api.lua +++ b/mods/advtrains/advtrains_interlocking/signal_api.lua @@ -3,42 +3,46 @@ --[[ Signal aspect table: +Note: All speeds are measured in m/s, aka the number of + signs in the HUD. asp = { - main = { - free = , - speed = , - }, - shunt = { - free = , + main = , + -- Main signal aspect, tells state and permitted speed of next section + -- 0 = section is blocked + -- >0 = section is free, speed limit is this value + -- -1 = section is free, maximum speed permitted + -- false/nil = Signal doesn't provide main signal information, retain current speed limit. + shunt = , -- Whether train may proceed as shunt move, on sight -- main aspect takes precedence over this - proceed_as_main = , - -- If an approaching train is a shunt move and "main.free" is set, + -- When main==0, train switches to shunt move and is restricted to speed 6 + proceed_as_main = , + -- If an approaching train is a shunt move and 'shunt' is false, -- the train may proceed as a train move under the "main" aspect + -- if the main aspect permits it (i.e. main!=0) -- If this is not set, shunt moves are NOT allowed to switch to - -- a train move, and must stop even if "main.free" is set. + -- a train move, and must stop even if "main" would permit passing. -- This is intended to be used for "Halt for shunt moves" signs. - } - dst = { - free = , - speed = , - } - info = { - call_on = , -- Call-on route, expect train in track ahead (not implemented yet) - dead_end = , -- Route ends on a dead end (e.g. bumper) (not implemented yet) - w_speed = , - -- "Warning speed restriction". Supposed for short-term speed - -- restrictions which always override any other restrictions - -- imposed by "speed" fields, until lifted by a value of -1 - -- (Example: german Langsamfahrstellen-Signale) + + dst = , + -- Distant signal aspect, tells state and permitted speed of the section after next section + -- The character of these information is purely informational + -- At this time, this field is not actively used + -- 0 = section is blocked + -- >0 = section is free, speed limit is this value + -- -1 = section is free, maximum speed permitted + -- false/nil = Signal doesn't provide distant signal information. + + -- the character of call_on and dead_end is purely informative + call_on = , -- Call-on route, expect train in track ahead (not implemented yet) + dead_end = , -- Route ends on a dead end (e.g. bumper) (not implemented yet) + + w_speed = , + -- "Warning speed restriction". Supposed for short-term speed + -- restrictions which always override any other restrictions + -- imposed by "speed" fields, until lifted by a value of -1 + -- (Example: german Langsamfahrstellen-Signale) } } --- For "speed" and "w_speed" fields, a value of -1 means that the --- restriction is lifted. If they are omitted, the value imposed at --- the last aspect received remains valid. --- The "dst" subtable can be completely omitted when no explicit dst --- aspect should be signalled to the train. In this case, the last --- signalled dst aspect remains valid. == How signals actually work in here == Each signal (in the advtrains universe) is some node that has at least the @@ -60,10 +64,16 @@ advtrains = { -- This function gets called whenever the signal should display -- a new or changed signal aspect. It is not required that -- the signal actually displays the exact same aspect, since - -- some signals can not do this by design. - -- Example: pure shunt signals can not display a "main" aspect - -- and have no effect on train moves, so they will only ever - -- honor the shunt.free field for their aspect. + -- some signals can not do this by design. However, it must + -- display an aspect that is at least as restrictive as the passed + -- aspect as far as it is capable of doing so. + -- Examples: + -- - pure shunt signals can not display a "main" aspect + -- and have no effect on train moves, so they will only ever + -- honor the shunt.free field for their aspect. + -- - the german Hl system can only signal speeds of 40, 60 + -- and 100 km/h, a speed of 80km/h should then be signalled + -- as 60 km/h instead. -- In turn, it is not guaranteed that the aspect will fulfill the -- criteria put down in supported_aspects. -- If set_aspect is present, supported_aspects should also be declared. @@ -87,51 +97,52 @@ advtrains = { false: always shows "blocked", unchangable true: always shows "free", unchangable -- Any of the "speed" fields should contain a list of possible values - -- to be set as restriction. If omitted, this signal should never - -- set the corresponding "speed" field in the aspect, which means - -- that the previous speed limit stays valid + -- to be set as restriction. If omitted, the value of the described + -- field is always assumed to be false (no information) + -- A speed of 0 means that the signal can show a "blocked" aspect + -- (which is probably the case for most signals) + -- If the signal can signal "no information" on one of the fields + -- (thus false is an acceptable value), include false in the list -- If your signal can only display a single speed (may it be -1), -- always enclose that single value into a list. (such as {-1}) - main = { - free = , - speed = {, ..., } or nil, - }, - dst = { - free = , - speed = {, ..., } or nil, - }, - shunt = { - free = , - }, - info = { - call_on = , - dead_end = , - w_speed = {, ..., } or nil, - } + main = {, ..., } or nil, + dst = {, ..., } or nil, + shunt = , + + call_on = , + dead_end = , + w_speed = {, ..., } or nil, }, + Example for supported_aspects: + supported_aspects = { + main = {0, 6, -1}, -- can show either "Section blocked", "Proceed at speed 6" or "Proceed at maximum speed" + dst = {0, false}, -- can show only if next signal shows "blocked", no other information. + shunt = false, -- shunting by this signal is never allowed. + + call_on = false, + dead_end = false, + w_speed = nil, + -- none of the information can be shown by the signal + + }, + get_aspect = function(pos, node) -- This function gets called by the train safety system. It should return the aspect that this signal actually displays, not preferably the input of set_aspect. -- For regular, full-featured light signals, they will probably honor all entries in the original aspect, however, e.g. - simple shunt signals always return main.free=true regardless of + simple shunt signals always return main=false regardless of the set_aspect input because they can not signal "Halt" to train moves. -- advtrains.interlocking.DANGER contains a default "all-danger" aspect. -- If your signal does not cover certain sub-tables of the aspect, the following reasonable defaults are automatically assumed: - main = { - free = true, - } - dst = { - free = true, - } - shunt = { - free = false, - proceed_as_main = false, - } + main = false (unchanged) + dst = false (unchanged) + shunt = false (shunting not allowed) + info = {} (no further information) end, } on_rightclick = advtrains.interlocking.signal_rc_handler @@ -155,51 +166,37 @@ This function will query get_aspect to retrieve the new aspect. ]]-- local DANGER = { - main = { - free = false, - speed = 0, - }, - shunt = { - free = false, - }, - dst = { - free = false, - speed = 0, - }, - info = {} + main = 0, + dst = false, + shunt = false, } advtrains.interlocking.DANGER = DANGER -local function fillout_aspect(asp) - if not asp.main then - asp.main = { - free = true, - } - elseif type(asp.main) ~= "table" then - asp.main = { - free = asp.main~=0, - speed = asp.main, - } - end - if not asp.dst then - asp.dst = { - free = true, - } - end - if not asp.shunt then - asp.shunt = { - free = false, - proceed_as_main = false, - } - elseif type(asp.shunt) ~= "table" then - asp.shunt = { - free = asp.shunt, - proceed_as_main = asp.proceed_as_main, - } - end - if not asp.info then - asp.info = {} +advtrains.interlocking.GENERIC_FREE = { + main = -1, + shunt = false, + dst = false, +} + +local function convert_aspect_if_necessary(asp) + if type(asp.main) == "table" then + local newasp = {} + if asp.main.free then + newasp.main = asp.main.speed + else + newasp.main = 0 + end + if asp.dst and asp.dst.free then + newasp.dst = asp.dst.speed + else + newasp.dst = 0 + end + newasp.proceed_as_main = asp.shunt.proceed_as_main + newasp.shunt = asp.shunt.free + -- Note: info table not transferred, it's not used right now + return newasp end + return asp end function advtrains.interlocking.update_signal_aspect(tcbs) @@ -219,7 +216,7 @@ function advtrains.interlocking.signal_after_dig(pos) end function advtrains.interlocking.signal_set_aspect(pos, asp) - fillout_aspect(asp) + asp = convert_aspect_if_necessary(asp) local node=advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] if ndef and ndef.advtrains and ndef.advtrains.set_aspect then @@ -234,17 +231,17 @@ function advtrains.interlocking.signal_on_aspect_changed(pos) if not ipts then return end local ipos = minetest.string_to_pos(ipts) - local tns = advtrains.occ.get_trains_over(ipos) - for id, sidx in pairs(tns) do --- local train = advtrains.trains[id] - --if train.index <= sidx then - minetest.after(0, advtrains.invalidate_path, id) - --end - end + advtrains.invalidate_all_paths_ahead(ipos) end function advtrains.interlocking.signal_rc_handler(pos, node, player, itemstack, pointed_thing) local pname = player:get_player_name() + local control = player:get_player_control() + if control.aux1 then + advtrains.interlocking.show_ip_form(pos, pname) + return + end + local sigd = advtrains.interlocking.db.get_sigd_for_signal(pos) if sigd then advtrains.interlocking.show_signalling_form(sigd, pname) @@ -252,7 +249,16 @@ function advtrains.interlocking.signal_rc_handler(pos, node, player, itemstack, local ndef = minetest.registered_nodes[node.name] if ndef.advtrains and ndef.advtrains.set_aspect then -- permit to set aspect manually - minetest.show_formspec(pname, "at_il_sigasp_"..minetest.pos_to_string(pos), "field[aspect;Set Aspect ('A' to assign IP);D0D0D]") + local function callback(pname, aspect) + advtrains.interlocking.signal_set_aspect(pos, aspect) + end + local isasp = ndef.advtrains.get_aspect(pos, node) + + advtrains.interlocking.show_signal_aspect_selector( + pname, + ndef.advtrains.supported_aspects, + "Set aspect manually", callback, + isasp) else --static signal - only IP advtrains.interlocking.show_ip_form(pos, pname) @@ -260,45 +266,13 @@ function advtrains.interlocking.signal_rc_handler(pos, node, player, itemstack, end end -minetest.register_on_player_receive_fields(function(player, formname, fields) - local pname = player:get_player_name() - local pts = string.match(formname, "^at_il_sigasp_(.+)$") - local pos - if pts then pos = minetest.string_to_pos(pts) end - if pos and fields.aspect then - if fields.aspect == "A" then - advtrains.interlocking.show_ip_form(pos, pname) - return - end - local mfs, msps, dfs, dsps, shs = string.match(fields.aspect, "^([FD])([-0-9]+)([FD])([-0-9]+)([FD])$") - local asp = { - main = { - free = mfs=="F", - speed = tonumber(msps), - }, - shunt = { - free = shs=="F", - }, - dst = { - free = dfs=="F", - speed = tonumber(dsps), - }, - info = { - call_on = false, -- Call-on route, expect train in track ahead - dead_end = false, -- Route ends on a dead end (e.g. bumper) - } - } - advtrains.interlocking.signal_set_aspect(pos, asp) - end -end) - -- Returns the aspect the signal at pos is supposed to show function advtrains.interlocking.signal_get_supposed_aspect(pos) local sigd = advtrains.interlocking.db.get_sigd_for_signal(pos) if sigd then local tcbs = advtrains.interlocking.db.get_tcbs(sigd) if tcbs.aspect then - return tcbs.aspect + return convert_aspect_if_necessary(tcbs.aspect) end end return DANGER; @@ -312,8 +286,7 @@ function advtrains.interlocking.signal_get_aspect(pos) if ndef and ndef.advtrains and ndef.advtrains.get_aspect then local asp = ndef.advtrains.get_aspect(pos, node) if not asp then asp = DANGER end - fillout_aspect(asp) - return asp + return convert_aspect_if_necessary(asp) end return nil end @@ -447,42 +420,45 @@ local players_aspsel = {} suppasp: "supported_aspects" table purpose: form title string callback: func(pname, aspect) called on form submit +isasp: aspect currently set ]] -function advtrains.interlocking.show_signal_aspect_selector(pname, p_suppasp, p_purpose, callback, p_isasp) +function advtrains.interlocking.show_signal_aspect_selector(pname, p_suppasp, p_purpose, callback, isasp) local suppasp = p_suppasp or { - main = {}, dst = {}, shunt = {}, info = {}, + main = {0, -1}, dst = {false}, shunt = false, info = {}, } local purpose = p_purpose or "" - local isasp = p_isasp and fillout_aspect(p_isasp) local form = "size[7,5]label[0.5,0.5;Select Signal Aspect:]" form = form.."label[0.5,1;"..purpose.."]" form = form.."label[0.5,1.5;== Main Signal ==]" - if suppasp.main.free == nil then - local st = 2 - if isasp and not isasp.main.free then st=1 end - form = form.."dropdown[0.5,2;2;main_free;danger,free;"..st.."]" - end - if suppasp.main.speed then - local selid = 1 - if isasp and isasp.main.speed then - for idx, spv in ipairs(suppasp.main.speed) do - if spv == isasp.main.speed then - selid = idx - break - end - end + local selid = 1 + local entries = {} + for idx, spv in ipairs(suppasp.main) do + local entry + if spv == 0 then + entry = "Halt" + elseif spv == -1 then + entry = "Continue at maximum speed" + elseif not spv then + entry = "Continue\\, speed limit unchanged (no info)" + else + entry = "Continue at speed of "..spv + end + -- hack: the crappy formspec system returns the label, not the index. save the index in it. + entries[idx] = idx.."| "..entry + if isasp and spv == (isasp.main or false) then + selid = idx end - form = form.."label[2.3,1;Speed:]" - form = form.."dropdown[3,2;2;main_speed;"..table.concat(suppasp.main.speed, ",")..";"..selid.."]" end + form = form.."dropdown[0.5,2;6;main;"..table.concat(entries, ",")..";"..selid.."]" + form = form.."label[0.5,3;== Shunting ==]" - if suppasp.shunt.free == nil then + if suppasp.shunt == nil then local st = 1 - if isasp and isasp.shunt.free then st=2 end - form = form.."dropdown[0.5,3.5;2;shunt_free;---,allowed;"..st.."]" + if isasp and isasp.shunt then st=2 end + form = form.."dropdown[0.5,3.5;6;shunt_free;---,allowed;"..st.."]" end form = form.."button_exit[0.5,4.5; 5,1;save;OK]" @@ -507,12 +483,10 @@ local function usebool(sup, val, free) return sup end end -local function usespeed(sup, val) - if sup then - return tonumber(val) - else - return nil - end + +-- other side of hack: extract the index +local function ddindex(val) + return tonumber(string.match(val, "^(%d+)|")) end -- TODO use non-hacky way to parse outputs @@ -523,17 +497,12 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if psl then if formname == "at_il_sigaspdia_"..psl.token then if fields.save then + local maini = ddindex(fields.main) + if not maini then return end local asp = { - main = { - free = usebool(psl.suppasp.main.free, fields.main_free, "free"), - speed = usespeed(psl.suppasp.main.speed, fields.main_speed), - }, - dst = { - free = true, speed = -1, - }, - shunt = { - free = usebool(psl.suppasp.shunt.free, fields.shunt_free, "allowed"), - }, + main = psl.suppasp.main[maini], + dst = false, + shunt = usebool(psl.suppasp.shunt, fields.shunt_free, "allowed"), info = {} } psl.callback(pname, asp) diff --git a/mods/advtrains/advtrains_interlocking/tcb_ts_ui.lua b/mods/advtrains/advtrains_interlocking/tcb_ts_ui.lua index da318a7f..3952f91d 100644 --- a/mods/advtrains/advtrains_interlocking/tcb_ts_ui.lua +++ b/mods/advtrains/advtrains_interlocking/tcb_ts_ui.lua @@ -558,7 +558,7 @@ local sig_pselidx = {} -- Players having a signalling form open local p_open_sig_form = {} -function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte) +function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, called_from_form_update) if not minetest.check_player_privs(pname, "train_operator") then minetest.chat_send_player(pname, "Insufficient privileges to use this!") return @@ -651,7 +651,10 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte) p_open_sig_form[pname] = sigd -- always a good idea to update the signal aspect - advtrains.interlocking.update_signal_aspect(tcbs) + if not called_from_form_update then + -- FIX prevent a callback loop + advtrains.interlocking.update_signal_aspect(tcbs) + end end function advtrains.interlocking.update_player_forms(sigd) @@ -763,7 +766,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) tcbs.route_auto = false end - advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte) + advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, true) return end diff --git a/mods/advtrains/advtrains_line_automation/stoprail.lua b/mods/advtrains/advtrains_line_automation/stoprail.lua index dfc9b0c7..9c1470a8 100644 --- a/mods/advtrains/advtrains_line_automation/stoprail.lua +++ b/mods/advtrains/advtrains_line_automation/stoprail.lua @@ -169,7 +169,8 @@ local adefunc = function(def, preset, suffix, rotation) show_stoprailform(pos, player) end, advtrains = { - on_train_approach = function(pos,train_id, train, index) + on_train_approach = function(pos,train_id, train, index, has_entered) + if has_entered then return end -- do not stop again! if train.path_cn[index] == 1 then local pe = advtrains.encode_pos(pos) local stdata = advtrains.lines.stops[pe] @@ -184,6 +185,7 @@ local adefunc = function(def, preset, suffix, rotation) local stn = advtrains.lines.stations[stdata.stn] local stnname = stn and stn.name or "Unknown Station" train.text_inside = "Next Stop:\n"..stnname + advtrains.interlocking.ars_set_disable(train, true) end end end @@ -201,7 +203,7 @@ local adefunc = function(def, preset, suffix, rotation) local stnname = stn and stn.name or "Unknown Station" -- Send ATC command and set text - advtrains.atc.train_set_command(train, "B0 W O"..stdata.doors..(stdata.kick and "K" or "").." D"..stdata.wait.." OC "..(stdata.reverse and "R" or "").."D"..(stdata.ddelay or 1) .. "S" ..(stdata.speed or "M"), true) + advtrains.atc.train_set_command(train, "B0 W O"..stdata.doors..(stdata.kick and "K" or "").." D"..stdata.wait.." OC "..(stdata.reverse and "R" or "").."D"..(stdata.ddelay or 1) .. " A1 S" ..(stdata.speed or "M"), true) train.text_inside = stnname if tonumber(stdata.wait) then minetest.after(tonumber(stdata.wait), function() train.text_inside = "" end) diff --git a/mods/advtrains/advtrains_luaautomation/README.txt b/mods/advtrains/advtrains_luaautomation/README.md old mode 100755 new mode 100644 similarity index 68% rename from mods/advtrains/advtrains_luaautomation/README.txt rename to mods/advtrains/advtrains_luaautomation/README.md index c320d313..5232c22f --- a/mods/advtrains/advtrains_luaautomation/README.txt +++ b/mods/advtrains/advtrains_luaautomation/README.md @@ -1,7 +1,9 @@ # Advtrains - Lua Automation features -This mod offers components that run LUA code and interface with each other through a global environment. It makes complex automated railway systems possible. The mod is sometimes abbreviated as 'atlatc'. This stands for AdvTrainsLuaATC. This short name has been chosen for user convenience, since the name of this mod ('advtrains_luaautomation') is very long. +This mod offers components that run LUA code and interface with each other through a global environment. It makes complex automated railway systems possible. The mod is sometimes abbreviated as 'LuaATC' or 'atlatc'. This stands for AdvTrainsLuaATC. This short name has been chosen for user convenience, since the name of this mod ('advtrains_luaautomation') is very long. + +A probably more complete documentation of LuaATC is found on the [Advtrains Wiki](http://advtrains.de/wiki/doku.php?id=usage:atlatc:start) ## Privileges To perform any operations using this mod (except executing operation panels), players need the "atlatc" privilege. @@ -18,6 +20,13 @@ Create environment with the given name. To be able to do anything, you first nee - `/env_setup `: Invoke the form to edit the environment's initialization code. For more information, see the section on active components. You can also delete an environment from here. + - `/env_subscribe `, `/env_unsubscribe `: +Subscribe or unsubscribe from log/error messages originating from this environment + + - `/env_subscriptions [env_name]`: +List your subscriptions or players subscribed to an environment. + + ## Functions and variables ### General Functions and Variables The following standard Lua libraries are available: @@ -40,41 +49,6 @@ The following standard Lua functions are available: Any attempt to overwrite the predefined values results in an error. -## Components and Events - -### Components -Atlac components introduce automation-capable components that fall within two categories: - - Active Components are components that are able to run Lua code, triggered by specific events. - - Passive Components can't perform actions themselves. Their state can be read and set by active components or manually by the player. - - - -## Functions and Variables - -### Events -The event table is a variable created locally by the component being triggered. It is a table with the following format: -```lua -event = { - type = "", - = true, - --additional event-specific content -} -``` -You can check the event type by using the following: -```lua -if event.type == "wanted" then - --do stuff -end -``` -or -```lua -if event.wanted then - --do stuff -end -```` -where `wanted` is the event type to check for. -See the "Active Components" section below for details on the various event types as not all of them are applicable to all components. - ### LuaAutomation Global Variables - `S` The variable 'S' contains a table which is shared between all components of the environment. Its contents are persistent over server restarts. May not contain functions, every other value is allowed. @@ -104,11 +78,17 @@ Set the state of the passive component at position `pos`. Checks whether there is a passive component at the position pos (and/or whether a passive component with this name exists) - `interrupt(time, message)` -Cause LuaAutomation to trigger an `int` event on this component after the given time in seconds with the specified `message` field. `message` can be of any Lua data type. *Not available in init code.* +Cause LuaAutomation to trigger an `int` event on this component after the given time in seconds with the specified `message` field. `message` can be of any Lua data type. Returns true. *Not available in init code.* + + - `interrupt_safe(time, message)` +Like `interrupt()`, but does not add an interrupt and returns false when an interrupt (of any type) is already present for this component. Returns true when interrupt was successfully added. - `interrupt_pos(pos, message)` Immediately trigger an `ext_int` event on the active component at position pos. `message` is like in interrupt(). Use with care, or better **_don't use_**! Incorrect use can result in **_expotential growth of interrupts_**. + - `clear_interrupts()` +Removes any pending interrupts of this node. + - `digiline_send(channel, message)` Make this active component send a digiline message on the specified channel. Not available in init code. @@ -128,52 +108,105 @@ Cancels the route that is set from the signal at pos. Has the same effect as cli - `get_aspect(pos)` Returns the signal aspect of the signal at pos. A signal aspect has the following format: ```lua -{ - main = { -- the next track section in line. Shows blocked for shunt routes - free = , - speed = , - }, - shunt = { -- whether a "shunting allowed" aspect should be shown - free = , - }, - dst = { -- the aspect of the next main signal on (at end of) route - free = , - speed = , - }, - info = { - call_on = , -- Call-on route, expect train in track ahead - dead_end = , -- Route ends on a dead end (e.g. bumper) - } +asp = { + main = , + -- Main signal aspect, tells state and permitted speed of next section + -- 0 = section is blocked + -- >0 = section is free, speed limit is this value + -- -1 = section is free, maximum speed permitted + -- false = Signal doesn't provide main signal information, retain current speed limit. + shunt = , + -- Whether train may proceed as shunt move, on sight + -- main aspect takes precedence over this + -- When main==0, train switches to shunt move and is restricted to speed 8 + proceed_as_main = , + -- If an approaching train is a shunt move and 'shunt' is false, + -- the train may proceed as a train move under the "main" aspect + -- if the main aspect permits it (i.e. main!=0) + -- If this is not set, shunt moves are NOT allowed to switch to + -- a train move, and must stop even if "main" would permit passing. + -- This is intended to be used for "Halt for shunt moves" signs. + + dst = , + -- Distant signal aspect, tells state and permitted speed of the section after next section + -- The character of these information is purely informational + -- At this time, this field is not actively used + -- 0 = section is blocked + -- >0 = section is free, speed limit is this value + -- -1 = section is free, maximum speed permitted + -- false = Signal doesn't provide distant signal information. + + -- the character of call_on and dead_end is purely informative + call_on = , -- Call-on route, expect train in track ahead (not implemented yet) + dead_end = , -- Route ends on a dead end (e.g. bumper) (not implemented yet) + + w_speed = , + -- "Warning speed restriction". Supposed for short-term speed + -- restrictions which always override any other restrictions + -- imposed by "speed" fields, until lifted by a value of -1 + -- (Example: german Langsamfahrstellen-Signale) } ``` -As of August 2018 (git commit d837e7e), only the aspect.main.free field is ever used by the interlocking system. +As of January 2020, the 'dst', 'call_on' and 'dead_end' fields are not used. -### Active Component -#### Lua ATC Rails -Lua ATC rails are the only components that can actually interface with trains. The following event types are available to the Lua ATC rails: - - ```lua -{type="train", train=true, id=""} +#### Lines + +The advtrains_line_automation component adds a few contraptions that should make creating timeable systems easier. +Part of its functionality is also available in LuaATC: + +- `rwt.*` - all Railway Time functions are included as documented in [the wiki](https://advtrains.de/wiki/doku.php?id=dev:lines:rwt) + + - `schedule(rw_time, msg)`, `schedule_in(rw_dtime, msg)` +Schedules an event of type {type="schedule", schedule=true, msg=msg} at (resp. after) the specified railway time (which can be in any format). You can only schedule one event this way. (uses the new lines-internal scheduler) + +Note: Using the lines scheduler is preferred over using `interrupt()`, as it's more performant and safer to use. + +## Events +The event table is a variable created locally by the component being triggered. It is a table with the following format: +```lua +event = { + type = "", + = true, + --additional event-specific content +} ``` +You can check the event type by using the following: +```lua +if event.type == "wanted" then + --do stuff +end +``` +or +```lua +if event.wanted then + --do stuff +end +``` +where `wanted` is the event type to check for. +See the "Active Components" section below for details on the various event types as not all of them are applicable to all components. + +## Components +Atlac components introduce automation-capable components that fall within two categories: + - Active Components are components that are able to run Lua code, triggered by specific events. + - Passive Components can't perform actions themselves. Their state can be read and set by active components or manually by the player. + +### Lua ATC Rails +Lua ATC rails are the only components that can actually interface with trains. The following event types are available to the Lua ATC rails: + - `{type="train", train=true, id=""}` * This event is fired when a train enters the rail. The field `id` is the unique train ID, which is 6-digit random numerical string. * If the world contains trains from an older advtrains version, this string may be longer and contain a dot `.` - - ```lua -{type="int", int=true, msg=} -``` + - `{type="int", int=true, msg=}` * Fired when an interrupt set by the `interrupt` function runs out. `` is the message passed to the interrupt function. * For backwards compatiblity reasons, `` is also contained in an `event.message` variable. - - ```lua -{type="ext_int", ext_int=true, message=} -``` + - `{type="ext_int", ext_int=true, message=}` * Fired when another node called `interrupt_pos` on this position. `message` is the message passed to the interrupt_pos function. - - ```lua -{type="digiline", digiline=true, channel=, msg=} -``` + - `{type="digiline", digiline=true, channel=, msg=}` * Fired when the controller receives a digiline message. -##### Basic Lua Rail Functions and Variables +#### Basic Lua Rail Functions and Variables In addition to the above environment functions, the following functions are available to whilst the train is in contact with the LuaATC rail: - `atc_send()` @@ -215,7 +248,7 @@ In addition to the above environment functions, the following functions are avai Sets the "Routingcode" property of the train (a string). The interlocking system uses this property for Automatic Routesetting. -##### Shunting Functions and Variables +#### Shunting Functions and Variables There are several functions available especially for shunting operations. Some of these functions make use of Freight Codes (FC) set in the Wagon Properties of each wagon and/or locomotive: - `split_at_index(index, atc_command)` @@ -241,8 +274,6 @@ There are several functions available especially for shunting operations. Some o Result: `"foo" "foo" "foo"` and `"foo" "bar" "bar"` The function returns `"foo"` in this case. - - - `split_off_locomotive(command, len)` Splits off the locomotives at the front of the train, which are identified by an empty FC. `command` specifies the ATC command to be @@ -269,10 +300,56 @@ There are several functions available especially for shunting operations. Some o Unsets autocouple mode Deprecated: + - `set_shunt()`, `unset_shunt()` deprecated aliases for set_autocouple() and unset_autocouple(), will be removed from a later release. -##### Timetable Automation + +#### Interlocking +This additional function is available when advtrains_interlocking is enabled: + + - `atc_set_disable_ars(boolean)` + Disables (true) or enables (false) the use of ARS for this train. The train will not trigger ARS (automatic route setting) on signals then. + + Note: If you want to disable ARS from an approach callback, the call to `atc_set_disable_ars(true)` *must* happen during the approach callback, and may not be deferred to an interrupt(). Else the train might trigger an ARS before the interrupt fires. + +#### Approach callbacks +The LuaATC interface provides a way to hook into the approach callback system, which is for example used in the TSR rails (provided by advtrains_interlocking) or the station tracks (provided by advtrains_lines). However, for compatibility reasons, this behavior needs to be explicitly enabled. + +Enabling the receiving of approach events works by setting a variable in the local environment of the ATC rail, by inserting the following code: + +```lua +__approach_callback_mode = 1 +-- to receive approach callbacks only in arrow direction +-- or alternatively +__approach_callback_mode = 2 +-- to receive approach callbacks in both directions +``` + +The following event will be emitted when a train approaches: +```lua +{type="approach", approach=true, id=""} +``` + +Please note these important considerations when using approach callbacks: + + - Approach events might be generated multiple times for the same approaching train. If you are using atc_set_lzb_tsr(), you need to call this function on every run of the approach callback, even if you issued it before for the same train. + - A reference to the train is available while executing this event, so that functions such as atc_send() or atc_set_text_outside() can be called. On any consecutive interrupts, that reference will no longer be available until the train enters the track ("train" event) + - Unlike all other callbacks, approach callbacks are executed synchronous during the train step. This may cause unexpected side effects when performing certain actions (such as switching turnouts, setting signals/routes) from inside such a callback. I strongly encourage you to only run things that are absolutely necessary at this point in time, and defer anything else to an interrupt(). Be aware that certain things might trigger unexpected behavior. + +Operations that are safe to execute in approach callbacks: + + - anything related only to the global environment (setting things in S) + - digiline_send() + - atc_set_text_*() + - atc_set_lzb_tsr() (see below) + +In the context of approach callbacks, one more function is available: + + - `atc_set_lzb_tsr(speed)` +Impose a Temporary Speed Restriction at the location of this rail, making the train pass this rail at the specified speed. (Causes the same behavior as the TSR rail) + +#### Timetable Automation The advtrains_line_automation component adds a few contraptions that should make creating timeable systems easier. Part of its functionality is also available in LuaATC: @@ -284,12 +361,12 @@ All Railway Time functions are included as documented in https://advtrains.de/wi - `schedule_in(rw_dtime, msg)` Schedules the following event `{type="schedule", schedule=true, msg=msg}` at (resp. after) the specified railway time (which can be in any format). You can only schedule one event this way. Uses the new lines-internal scheduler. -#### Operator panel +### Operator panel This simple node executes its actions when punched. It can be used to change a switch and update the corresponding signals or similar applications. It can also be connected to by the`digilines` mod. The event fired is `{type="punch", punch=true}` by default. In case of an interrupt or a digiline message, the events are similar to the ones of the ATC rail. -#### Init code +### Init code The initialization code is not a component as such, but rather a part of the whole environment. It can (and should) be used to make definitions that other components can refer to. A basic example function to define behavior for trains in stations: ```lua @@ -304,12 +381,12 @@ function F.station(station_name) atc_send("OCD1SM") end end -```` +``` The corresponding Lua ATC Rail(s) would then contain the following or similar: -````lua +```lua F.station("Main Station") -```` +``` The init code is run whenever the F table needs to be refilled with data. This is the case on server startup and whenever the init code is changed and you choose to run it. The event table of the init code is always `{type="init", init=true}` and can not be anything else. @@ -322,15 +399,18 @@ Each node below has been mapped to specific "states": #### Signals The red/green light signals `advtrains:signal_on/off` are interfaceable. Others such as `advtrains:retrosignal_on/off` are not. If advtrains_interlocking is enabled, trains will obey the signal if the influence point is set. + - "green" - Signal shows green light - "red" - Signal shows red light #### Switches/Turnouts -All default rail switches are interfaceable, independent of orientation. +All default rail switches are interfaceable, independent of orientation. + - "cr" The switch is set in the direction that is not straight. - "st" The switch is set in the direction that is straight. The "Y" and "3-Way" switches have custom states. Looking from the convergence point: + - "l" The switch is set towards the left. - "c" The switch is set towards the center (3-way only). - "r" The switch is set towards the right. @@ -338,10 +418,12 @@ The "Y" and "3-Way" switches have custom states. Looking from the convergence po #### Mesecon Switch The Mesecon switch can be switched using LuaAutomation. Note that this is not possible on levers or protected mesecon switches, only the unprotected full-node 'Switch' block `mesecons_switch:mesecon_switch_on/off`. + - "on" - the switch is switched on. - "off" - the switch is switched off. #### Andrew's Cross + - "on" - it blinks. - "off" - it does not blink. @@ -356,4 +438,3 @@ Use `setstate("Stn_P1_out", "green")` instead of `setstate(POS(1,2,3), "green")` If `advtrains_interlocking` is enabled, PC-Naming can also be used to name interlocking signals for route setting via the `set_route()` functions. **Important**: The "Signal Name" field in the signalling formspec is completely independent from PC-Naming and can't be used to look up the position. You need to explicitly use the PC-Naming tool. ---TODO: Ein paar mehr Codebeispiele wären schön, insbesondere mit os.date und so... diff --git a/mods/advtrains/advtrains_luaautomation/active_common.lua b/mods/advtrains/advtrains_luaautomation/active_common.lua index 7db3eafc..d168badb 100644 --- a/mods/advtrains/advtrains_luaautomation/active_common.lua +++ b/mods/advtrains/advtrains_luaautomation/active_common.lua @@ -109,8 +109,9 @@ function ac.run_in_env(pos, evtdata, customfct_p) atwarn("LuaAutomation component at",ph,": Not an existing environment: "..(nodetbl.env or "")) return false end + local env = atlatc.envs[nodetbl.env] if not nodetbl.code or nodetbl.code=="" then - atwarn("LuaAutomation component at",ph,": No code to run! (insert -- to suppress warning)") + env:log("warning", "LuaAutomation component at",ph,": No code to run! (insert -- to suppress warning)") return false end @@ -121,6 +122,18 @@ function ac.run_in_env(pos, evtdata, customfct_p) assert(t >= 0) atlatc.interrupt.add(t, pos, {type="int", int=true, message=imesg, msg=imesg}) --Compatiblity "message" field. end + customfct.interrupt_safe=function(t, imesg) + assertt(t, "number") + assert(t >= 0) + if atlatc.interrupt.has_at_pos(pos) then + return false + end + atlatc.interrupt.add(t, pos, {type="int", int=true, message=imesg, msg=imesg}) --Compatiblity "message" field. + return true + end + customfct.clear_interrupts=function() + atlatc.interrupt.clear_ints_at_pos(pos) + end -- add digiline_send function, if digiline is loaded if minetest.global_exists("digiline") then customfct.digiline_send=function(channel, msg) @@ -141,15 +154,20 @@ function ac.run_in_env(pos, evtdata, customfct_p) end local datain=nodetbl.data or {} - local succ, dataout = atlatc.envs[nodetbl.env]:execute_code(datain, nodetbl.code, evtdata, customfct) + local succ, dataout = env:execute_code(datain, nodetbl.code, evtdata, customfct) if succ then atlatc.active.nodes[ph].data=atlatc.remove_invalid_data(dataout) else atlatc.active.nodes[ph].err=dataout - atwarn("LuaAutomation ATC interface rail at",ph,": LUA Error:",dataout) + env:log("error", "LuaATC component at",ph,": LUA Error:",dataout) if meta then - meta:set_string("infotext", "LuaAutomation ATC interface rail, ERROR:"..dataout) + meta:set_string("infotext", "LuaATC component, ERROR:"..dataout) end + --TODO temporary + --if customfct.atc_id then + -- advtrains.drb_dump(customfct.atc_id) + -- error("Debug: LuaATC error hit!") + --end end if meta then meta:set_string("formspec", ac.getform(pos, meta)) diff --git a/mods/advtrains/advtrains_luaautomation/atc_rail.lua b/mods/advtrains/advtrains_luaautomation/atc_rail.lua index 6083dfc1..0dee0a56 100644 --- a/mods/advtrains/advtrains_luaautomation/atc_rail.lua +++ b/mods/advtrains/advtrains_luaautomation/atc_rail.lua @@ -5,7 +5,10 @@ --Using subtable local r={} -function r.fire_event(pos, evtdata) +-- Note on appr_internal: +-- The Approach callback is a special corner case: the train is not on the node, and it is executed synchronized +-- (in the train step right during LZB traversal). We therefore need access to the train id and the lzbdata table +function r.fire_event(pos, evtdata, appr_internal) local ph=minetest.pos_to_string(pos) local railtbl = atlatc.active.nodes[ph] @@ -15,37 +18,34 @@ function r.fire_event(pos, evtdata) return end - - local arrowconn = railtbl.arrowconn - if not arrowconn then - atwarn("LuaAutomation ATC interface rail at",ph,": Incomplete Data! Please visit position and click 'Save'!") - return - end - --prepare ingame API for ATC. Regenerate each time since pos needs to be known --If no train, then return false. - local train_id=advtrains.get_train_at_pos(pos) - local train, atc_arrow, tvel - if train_id then train=advtrains.trains[train_id] end - if train then - if not train.path then - --we happened to get in between an invalidation step - --delay - atlatc.interrupt.add(0,pos,evtdata) - return - end - local index = advtrains.path_lookup(train, pos) - - local iconnid = 1 - if index then - iconnid = train.path_cn[index] - else - atwarn("ATC rail at", pos, ": Rail not on train's path! Can't determine arrow direction. Assuming +!") - end - atc_arrow = iconnid == 1 - + + -- try to get the train from the event data + -- This workaround is required because the callback is one step delayed, and a fast train may have already left the node. + -- Also used for approach callback + local train_id = evtdata._train_id + local atc_arrow = evtdata._train_arrow + local train, tvel + + if train_id then + train=advtrains.trains[train_id] + -- speed tvel=train.velocity + -- if still no train_id available, try to get the train at my position + else + train_id=advtrains.get_train_at_pos(pos) + if train_id then + train=advtrains.trains[train_id] + advtrains.train_ensure_init(train_id, train) + -- look up atc_arrow + local index = advtrains.path_lookup(train, pos) + atc_arrow = (train.path_cn[index] == 1) + -- speed + tvel=train.velocity + end end + local customfct={ atc_send = function(cmd) if not train_id then return false end @@ -92,12 +92,13 @@ function r.fire_event(pos, evtdata) advtrains.train_step_fc(train) end, set_shunt = function() + -- enable shunting mode if not train_id then return false end - train.autocouple = true + train.is_shunt = true end, unset_shunt = function() if not train_id then return false end - train.autocouple = nil + train.is_shunt = nil end, set_autocouple = function () if not train_id then return false end @@ -106,7 +107,7 @@ function r.fire_event(pos, evtdata) unset_autocouple = function () if not train_id then return false end train.autocouple = nil - end, + end, set_line = function(line) if type(line)~="string" and type(line)~="number" then return false @@ -150,45 +151,89 @@ function r.fire_event(pos, evtdata) advtrains.trains[train_id].text_inside=text return true end, + atc_set_lzb_tsr = function(speed) + if not appr_internal then + error("atc_set_lzb_tsr() can only be used during 'approach' events!") + end + assert(tonumber(speed), "Number expected!") + + local index = appr_internal.index + advtrains.lzb_add_checkpoint(train, index, speed, nil) + + return true + end, } + -- interlocking specific + if advtrains.interlocking then + customfct.atc_set_ars_disable = function(value) + advtrains.interlocking.ars_set_disable(train, value) + end + end atlatc.active.run_in_env(pos, evtdata, customfct) end -if minetest.get_modpath("advtrains_train_track") ~= nil then - advtrains.register_tracks("default", { - nodename_prefix="advtrains_luaautomation:dtrack", - texture_prefix="advtrains_dtrack_atc", - models_prefix="advtrains_dtrack", - models_suffix=".b3d", - shared_texture="advtrains_dtrack_shared_atc.png", - description=atltrans("LuaAutomation ATC Rail"), - formats={}, - get_additional_definiton = function(def, preset, suffix, rotation) - return { - after_place_node = atlatc.active.after_place_node, - after_dig_node = atlatc.active.after_dig_node, - on_receive_fields = function(pos, ...) - atlatc.active.on_receive_fields(pos, ...) - --set arrowconn (for ATC) - local ph=minetest.pos_to_string(pos) - local _, conns=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes) - atlatc.active.nodes[ph].arrowconn=conns[1].c +advtrains.register_tracks("default", { + nodename_prefix="advtrains_luaautomation:dtrack", + texture_prefix="advtrains_dtrack_atc", + models_prefix="advtrains_dtrack", + models_suffix=".b3d", + shared_texture="advtrains_dtrack_shared_atc.png", + description=atltrans("LuaAutomation ATC Rail"), + formats={}, + get_additional_definiton = function(def, preset, suffix, rotation) + return { + after_place_node = atlatc.active.after_place_node, + after_dig_node = atlatc.active.after_dig_node, + + on_receive_fields = function(pos, ...) + atlatc.active.on_receive_fields(pos, ...) + + --set arrowconn (for ATC) + local ph=minetest.pos_to_string(pos) + local _, conns=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes) + atlatc.active.nodes[ph].arrowconn=conns[1].c + end, + + advtrains = { + on_train_enter = function(pos, train_id, train, index) + --do async. Event is fired in train steps + atlatc.interrupt.add(0, pos, {type="train", train=true, id=train_id, + _train_id = train_id, _train_arrow = (train.path_cn[index] == 1)}) end, - advtrains = atlatc.active.trackdef_advtrains_defs, - luaautomation = { - fire_event=r.fire_event + on_train_approach = function(pos, train_id, train, index, has_entered, lzbdata) + -- Insert an event only if the rail indicated that it supports approach callbacks + local ph=minetest.pos_to_string(pos) + local railtbl = atlatc.active.nodes[ph] + -- uses a "magic variable" in the local environment of the node + -- This hack is necessary because code might not be prepared to get approach events... + if railtbl and railtbl.data and railtbl.data.__approach_callback_mode then + local acm = railtbl.data.__approach_callback_mode + local in_arrow = (train.path_cn[index] == 1) + if acm==2 or (acm==1 and in_arrow) then + local evtdata = {type="approach", approach=true, id=train_id, has_entered = has_entered, + _train_id = train_id, _train_arrow = in_arrow} -- reuses code from train_enter + -- This event is *required* to run synchronously, because it might set the ars_disable flag on the train and add LZB checkpoints, + -- although this is generally discouraged because this happens right in a train step + -- At this moment, I am not aware whether this may cause side effects, and I must encourage users not to do expensive calculations here. + r.fire_event(pos, evtdata, {train_id = train_id, train = train, index = index, lzbdata = lzbdata}) + end + end + end, + }, + luaautomation = { + fire_event=r.fire_event + }, + digiline = { + receptor = {}, + effector = { + action = atlatc.active.on_digiline_receive }, - digiline = { - receptor = {}, - effector = { - action = atlatc.active.on_digiline_receive - }, - }, - } - end, - }, advtrains.trackpresets.t_30deg_straightonly) -end + }, + } + end, +}, advtrains.trackpresets.t_30deg_straightonly) + atlatc.rail = r diff --git a/mods/advtrains/advtrains_luaautomation/chatcmds.lua b/mods/advtrains/advtrains_luaautomation/chatcmds.lua index 2d0c69d7..468698be 100644 --- a/mods/advtrains/advtrains_luaautomation/chatcmds.lua +++ b/mods/advtrains/advtrains_luaautomation/chatcmds.lua @@ -43,12 +43,78 @@ core.register_chatcommand("env_create", { privs = {atlatc=true}, func = function(name, param) if not param or param=="" then return false, "Name required!" end + if string.find(param, "[^a-zA-Z0-9-_]") then return false, "Invalid name (only common characters)" end if atlatc.envs[param] then return false, "Environment already exists!" end atlatc.envs[param] = atlatc.env_new(param) + atlatc.envs[param].subscribers = {name} return true, "Created environment '"..param.."'. Use '/env_setup "..param.."' to define global initialization code, or start building LuaATC components!" end, }) - +core.register_chatcommand("env_subscribe", { + params = "", + description = "Subscribe to the log of an Advtrains LuaATC environment", + privs = {atlatc=true}, + func = function(name, param) + local env=atlatc.envs[param] + if not env then return false,"Invalid environment name!" end + for _,pname in ipairs(env.subscribers) do + if pname==name then + return false, "Already subscribed!" + end + end + table.insert(env.subscribers, name) + return true, "Subscribed to environment '"..param.."'." + end, +}) +core.register_chatcommand("env_unsubscribe", { + params = "", + description = "Unubscribe to the log of an Advtrains LuaATC environment", + privs = {atlatc=true}, + func = function(name, param) + local env=atlatc.envs[param] + if not env then return false,"Invalid environment name!" end + for index,pname in ipairs(env.subscribers) do + if pname==name then + table.remove(env.subscribers, index) + return true, "Successfully unsubscribed!" + end + end + return false, "Not subscribed to environment '"..param.."'." + end, +}) +core.register_chatcommand("env_subscriptions", { + params = "[environment name]", + description = "List Advtrains LuaATC environments you are subscribed to (no parameters) or subscribers of an environment (giving an env name).", + privs = {atlatc=true}, + func = function(name, param) + if not param or param=="" then + local none=true + for envname, env in pairs(atlatc.envs) do + for _,pname in ipairs(env.subscribers) do + if pname==name then + none=false + minetest.chat_send_player(name, envname) + end + end + end + if none then + return false, "Not subscribed to any!" + end + return true + end + local env=atlatc.envs[param] + if not env then return false,"Invalid environment name!" end + local none=true + for index,pname in ipairs(env.subscribers) do + none=false + minetest.chat_send_player(name, pname) + end + if none then + return false, "No subscribers!" + end + return true + end, +}) minetest.register_on_player_receive_fields(function(player, formname, fields) diff --git a/mods/advtrains/advtrains_luaautomation/environment.lua b/mods/advtrains/advtrains_luaautomation/environment.lua index 3e7787b6..9ef320c0 100644 --- a/mods/advtrains/advtrains_luaautomation/environment.lua +++ b/mods/advtrains/advtrains_luaautomation/environment.lua @@ -33,12 +33,12 @@ local env_proto={ self.sdata=data.sdata and atlatc.remove_invalid_data(data.sdata) or {} self.fdata={} self.init_code=data.init_code or "" - self.step_code=data.step_code or "" + self.subscribers=data.subscribers or {} end, save = function(self) -- throw any function values out of the sdata table self.sdata = atlatc.remove_invalid_data(self.sdata) - return {sdata = self.sdata, init_code=self.init_code, step_code=self.step_code} + return {sdata = self.sdata, init_code=self.init_code, subscribers=self.subscribers} end, } @@ -50,14 +50,6 @@ local safe_globals = { "tonumber", "tostring", "type", "unpack", "_VERSION" } ---print is actually minetest.chat_send_all() ---using advtrains.print_concat_table because it's cool -local function safe_print(t, ...) - local str=advtrains.print_concat_table({t, ...}) - minetest.log("action", "[atlatc] "..str) - minetest.chat_send_all(str) -end - local function safe_date(f, t) if not f then -- fall back to old behavior @@ -95,7 +87,6 @@ local mp=minetest.get_modpath("advtrains_luaautomation") local static_env = { --core LUA functions - print = safe_print, string = { byte = string.byte, char = string.char, @@ -252,7 +243,6 @@ for _, name in pairs(safe_globals) do static_env[name] = _G[name] end - --The environment all code calls get is a table that has set static_env as metatable. --In general, every variable is local to a single code chunk, but kept persistent over code re-runs. Data is also saved, but functions and userdata and circular references are removed --Init code and step code's environments are not saved @@ -265,6 +255,14 @@ local proxy_env={} -- returns: true, fenv if successful; nil, error if error function env_proto:execute_code(localenv, code, evtdata, customfct) + -- create us a print function specific for this environment + if not self.safe_print_func then + local myenv = self + self.safe_print_func = function(...) + myenv:log("info", ...) + end + end + local metatbl ={ __index = function(t, i) if i=="S" then @@ -277,6 +275,8 @@ function env_proto:execute_code(localenv, code, evtdata, customfct) return customfct[i] elseif localenv and localenv[i] then return localenv[i] + elseif i=="print" then + return self.safe_print_func end return static_env[i] end, @@ -306,35 +306,39 @@ function env_proto:run_initcode() if self.init_code and self.init_code~="" then local old_fdata=self.fdata self.fdata = {} - atprint("[atlatc]Running initialization code for environment '"..self.name.."'") + --atprint("[atlatc]Running initialization code for environment '"..self.name.."'") local succ, err = self:execute_code({}, self.init_code, {type="init", init=true}) if not succ then - atwarn("[atlatc]Executing InitCode for '"..self.name.."' failed:"..err) + self:log("error", "Executing InitCode for '"..self.name.."' failed:"..err) self.init_err=err if old_fdata then self.fdata=old_fdata - atwarn("[atlatc]The 'F' table has been restored to the previous state.") + self:log("warning", "The 'F' table has been restored to the previous state.") end end end end -function env_proto:run_stepcode() - if self.step_code and self.step_code~="" then - local succ, err = self:execute_code({}, self.step_code, nil, {}) - if not succ then - --TODO - end + +-- log to environment subscribers. severity can be "error", "warning" or "info" (used by internal print) +function env_proto:log(severity, ...) + local text=advtrains.print_concat_table({"[atlatc "..self.name.." "..severity.."]", ...}) + minetest.log("action", text) + for _, pname in ipairs(self.subscribers) do + minetest.chat_send_player(pname, text) end end +-- env.subscribers table may be directly altered by callers. + + --- class interface function atlatc.env_new(name) local newenv={ name=name, init_code="", - step_code="", - sdata={} + sdata={}, + subscribers={}, } setmetatable(newenv, {__index=env_proto}) return newenv @@ -351,11 +355,6 @@ function atlatc.run_initcode() env:run_initcode() end end -function atlatc.run_stepcode() - for envname, env in pairs(atlatc.envs) do - env:run_stepcode() - end -end diff --git a/mods/advtrains/advtrains_luaautomation/interrupt.lua b/mods/advtrains/advtrains_luaautomation/interrupt.lua index 525c3b4e..2e54ad88 100644 --- a/mods/advtrains/advtrains_luaautomation/interrupt.lua +++ b/mods/advtrains/advtrains_luaautomation/interrupt.lua @@ -16,6 +16,30 @@ function iq.save() return {queue = queue, timer=timer} end +function iq.has_at_pos(pos) + for i=1,#queue do + local qe=queue[i] + if vector.equals(pos, qe.p) then + return true + end + end + return false +end + +function iq.clear_ints_at_pos(pos) + local i=1 + while i<=#queue do + local qe=queue[i] + if not qe then + table.remove(queue, i) + elseif vector.equals(pos, qe.p) and (qe.e.int or qe.e.ext_int) then + table.remove(queue, i) + else + i=i+1 + end + end +end + function iq.add(t, pos, evtdata) queue[#queue+1]={t=t+timer, p=pos, e=evtdata} run=true @@ -23,13 +47,14 @@ end function iq.mainloop(dtime) timer=timer + math.min(dtime, 0.2) - for i=1,#queue do + local i=1 + while i<=#queue do local qe=queue[i] if not qe then table.remove(queue, i) - i=i-1 elseif timer>qe.t then - local pos, evtdata=queue[i].p, queue[i].e + table.remove(queue, i) + local pos, evtdata=qe.p, qe.e local node=advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] if ndef and ndef.luaautomation and ndef.luaautomation.fire_event then @@ -37,8 +62,8 @@ function iq.mainloop(dtime) else atwarn("[atlatc][interrupt] Couldn't run event",evtdata.type,"on",pos,", something wrong with the node",node) end - table.remove(queue, i) - i=i-1 + else + i=i+1 end end end diff --git a/mods/advtrains/advtrains_luaautomation/passive_api.txt b/mods/advtrains/advtrains_luaautomation/passive_api.txt index 9852e947..5ae1df40 100644 --- a/mods/advtrains/advtrains_luaautomation/passive_api.txt +++ b/mods/advtrains/advtrains_luaautomation/passive_api.txt @@ -7,7 +7,7 @@ Displays Mesecon Transmitter Those passive components can also be used inside interlocking systems. -All passive components have a table called 'advtrains' in their node definition and have the group 'save_in_nodedb' set, so they work in unloaded chunks. +All passive components have a table called 'advtrains' in their node definition and have the group 'save_in_at_nodedb' set, so they work in unloaded chunks. Example for a switch: advtrains = { getstate = function(pos, node) diff --git a/mods/advtrains/advtrains_signals_ks/init.lua b/mods/advtrains/advtrains_signals_ks/init.lua index c65d5f8b..08bbb75c 100644 --- a/mods/advtrains/advtrains_signals_ks/init.lua +++ b/mods/advtrains/advtrains_signals_ks/init.lua @@ -6,14 +6,14 @@ local setaspectf = function(rot) return function(pos, node, asp) - if not asp.main.free then - if asp.shunt.free then + if asp.main == 0 then + if asp.shunt then advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_shunt_"..rot, param2 = node.param2}) else advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_danger_"..rot, param2 = node.param2}) end else - if asp.dst.free and asp.main.speed == -1 then + if asp.dst ~= 0 and asp.main == -1 then advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_free_"..rot, param2 = node.param2}) else advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_slow_"..rot, param2 = node.param2}) @@ -22,19 +22,12 @@ local setaspectf = function(rot) end end + local suppasp = { - main = { - free = nil, - speed = {6, -1}, - }, - dst = { - free = nil, - speed = nil, - }, - shunt = { - free = nil, - proceed_as_main = true, - }, + main = {0, 6, -1}, + dst = {0, false}, + shunt = nil, + proceed_as_main = true, info = { call_on = false, dead_end = false, @@ -45,7 +38,7 @@ local suppasp = { --Rangiersignal local setaspectf_ra = function(rot) return function(pos, node, asp) - if asp.shunt.free then + if asp.shunt then advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:ra_shuntd_"..rot, param2 = node.param2}) else advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:ra_danger_"..rot, param2 = node.param2}) @@ -58,17 +51,11 @@ local setaspectf_ra = function(rot) end local suppasp_ra = { - main = { - free = true, - }, - dst = { - free = nil, - speed = nil, - }, - shunt = { - free = nil, - proceed_as_main = false, - }, + main = { false }, + dst = { false }, + shunt = nil, + proceed_as_main = false, + info = { call_on = false, dead_end = false, @@ -90,9 +77,9 @@ for _, rtab in ipairs({ local rot = rtab.rot for typ, prts in pairs({ danger = {asp = advtrains.interlocking.DANGER, n = "slow", ici=true}, - slow = {asp = { main = { free = true, speed = 6 }, shunt = {proceed_as_main = true}} , n = "free"}, - free = {asp = { main = { free = true, speed = -1 }, shunt = {proceed_as_main = true}} , n = "shunt"}, - shunt = {asp = { main = {free = false}, shunt = {free = true} } , n = "danger"}, + slow = {asp = { main = 6, proceed_as_main = true} , n = "free"}, + free = {asp = { main = -1, proceed_as_main = true} , n = "shunt"}, + shunt = {asp = { main = 0, shunt = true} , n = "danger"}, }) do minetest.register_node("advtrains_signals_ks:hs_"..typ.."_"..rot, { description = "Ks Main Signal", @@ -136,8 +123,8 @@ for _, rtab in ipairs({ --Rangiersignale: for typ, prts in pairs({ - danger = {asp = { main = {free = true}, shunt = {free = false} }, n = "shuntd", ici=true}, - shuntd = {asp = { main = {free = true}, shunt = {free = true} } , n = "danger"}, + danger = {asp = { main = false, shunt = false }, n = "shuntd", ici=true}, + shuntd = {asp = { main = false, shunt = true } , n = "danger"}, }) do minetest.register_node("advtrains_signals_ks:ra_"..typ.."_"..rot, { description = "Ks Shunting Signal", @@ -181,13 +168,14 @@ for _, rtab in ipairs({ --Schilder: for typ, prts in pairs({ -- Speed restrictions: - ["8"] = {asp = { main = {free = true, speed = 8}, shunt = {free = true} }, n = "12", ici=true}, - ["12"] = {asp = { main = {free = true, speed = 12}, shunt = {free = true} }, n = "16"}, - ["16"] = {asp = { main = {free = true, speed = 16}, shunt = {free = true} }, n = "e"}, + ["8"] = {asp = { main = 8, shunt = true }, n = "12", ici=true}, + ["12"] = {asp = { main = 12, shunt = true }, n = "16"}, + ["16"] = {asp = { main = 16, shunt = true }, n = "e"}, -- Speed restriction lifted - ["e"] = {asp = { main = {free = true, speed = -1}, shunt = {free = true} }, n = "hfs"}, + ["e"] = {asp = { main = -1, shunt = true }, n = "hfs"}, -- Halt for shunt moves: - ["hfs"] = {asp = { main = {free = true}, shunt = {free = false} }, n = "8"}, + ["hfs"] = {asp = { main = false, shunt = false }, n = "pam"}, + ["pam"] = {asp = { main = -1, shunt = false, proceed_as_main = true}, n = "8"}, }) do minetest.register_node("advtrains_signals_ks:sign_"..typ.."_"..rot, { description = "Signal Sign", diff --git a/mods/advtrains/advtrains_signals_ks/init_degrotate_nodes.lua b/mods/advtrains/advtrains_signals_ks/init_degrotate_nodes.lua index a4380d23..da1c980c 100644 --- a/mods/advtrains/advtrains_signals_ks/init_degrotate_nodes.lua +++ b/mods/advtrains/advtrains_signals_ks/init_degrotate_nodes.lua @@ -1,5 +1,5 @@ -- Ks Signals for advtrains --- will implement the advtrains signal API (which does not exist yet) +-- will implement the advtrains signal API local function place_degrotate(pos, placer, itemstack, pointed_thing) local yaw = placer:get_look_horizontal() diff --git a/mods/advtrains/advtrains_signals_ks/textures/advtrains_signals_ks_sign_pam.png b/mods/advtrains/advtrains_signals_ks/textures/advtrains_signals_ks_sign_pam.png new file mode 100644 index 0000000000000000000000000000000000000000..c4229fd43b9660116fe6705c6cfe5aa541610e7f GIT binary patch literal 211 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$efS0K&spW*-i|DHQJ;y{80 z9+AZi4BWyX%*Zfnjs#GUy~NYkmHi2agrGLJ#4Igkpir!*i(`ny<>UxfRvwOHOl%4d zn2f|4f5finnHm{z?2?8?a+bstK`E}pH9bCOnT)5UrMWdq28XA$HcDO&OY?O$ZkJ$N yW-ONBC>gu@f@FcFLhCUHkA;#P-;Js=7#PlPnch&Lrt}qP5re0zpUXO@geCy 6 then + if (param2 - param2_testing) > 6 then return -direction else return direction end - elseif param2_testing > node.param2 then + elseif param2_testing > param2 then - if (param2_testing - node.param2) > 6 then + if (param2_testing - param2) > 6 then return direction else return -direction @@ -92,13 +104,12 @@ local function quick_flow_logic(node, pos_testing, direction) end +-- reciprocal of the length of an unit square's diagonal +local DIAG_WEIGHT = 2 / math.sqrt(2) + local function quick_flow(pos, node) - if not minetest.registered_nodes[node.name].groups.liquid then - return {x = 0, y = 0, z = 0} - end - - local x, z = 0, 0 + local x, z = 0.0, 0.0 x = x + quick_flow_logic(node, {x = pos.x - 1, y = pos.y, z = pos.z},-1) x = x + quick_flow_logic(node, {x = pos.x + 1, y = pos.y, z = pos.z}, 1) @@ -131,6 +142,10 @@ local function add_effects(pos) end +local water_force = 0.8 +local water_friction = 0.8 +local dry_friction = 2.5 + core.register_entity(":__builtin:item", { initial_properties = { @@ -270,7 +285,7 @@ core.register_entity(":__builtin:item", { return true end, - on_step = function(self, dtime) + on_step = function(self, dtime, moveresult) local pos = self.object:get_pos() @@ -295,11 +310,22 @@ core.register_entity(":__builtin:item", { self.def_inside = self.node_inside and core.registered_nodes[self.node_inside.name] - self.node_under = minetest.get_node_or_nil({ - x = pos.x, - y = pos.y + self.object:get_properties().collisionbox[2] - 0.05, - z = pos.z - }) + -- get ground node for collision + self.node_under = nil + + if moveresult.touching_ground then + + for _, info in ipairs(moveresult.collisions) do + + if info.axis == "y" then + + self.node_under = core.get_node(info.node_pos) + + break + end + end + end + self.def_under = self.node_under and core.registered_nodes[self.node_under.name] @@ -352,10 +378,39 @@ core.register_entity(":__builtin:item", { -- water flowing if def and def.liquidtype == "flowing" then + -- force applies on acceleration over time, thus multiply + local force = water_force * dtime + -- friction applies on velocity over time, thus exponentiate + local friction = (1.0 + water_friction) ^ dtime + + -- get flow velocity and current vel/acc state local vec = quick_flow(pos, node) + local a = self.object:get_acceleration() + + self.object:set_acceleration({ + x = a.x + vec.x * force, + y = a.y, + z = a.z + vec.z * force + }) + + -- apply friction to prevent items going too fast, and also to make + -- water flow override previous horizontal momentum more quickly + local v = self.object:get_velocity() - self.object:set_velocity({x = vec.x, y = v.y, z = vec.z}) + -- adjust friction for going against the current + local v_horz = { x = v.x, y = 0, z = v.z } + local v_dir = to_unit_vector(v_horz) + local flow_dot = v_dir.x * vec.x + v_dir.y * vec.y + + -- also maps flow_dot from [-1,0] to [0.5,2.5] + friction = 1.0 + ((friction - 1.0) * (flow_dot + 1.5)) + + self.object:set_velocity({ + x = v.x / friction, + y = v.y / friction, + z = v.z / friction + }) return end @@ -412,11 +467,26 @@ core.register_entity(":__builtin:item", { self.moving_state = is_moving self.slippery_state = is_slippery + local a_curr = self.object:get_acceleration() + local v_curr = self.object:get_velocity() + if is_moving then - self.object:set_acceleration({x = 0, y = -gravity, z = 0}) + + self.object:set_acceleration({ + x = a_curr.x, + y = a_curr.y - gravity, + z = a_curr.z + }) else self.object:set_acceleration({x = 0, y = 0, z = 0}) - self.object:set_velocity({x = 0, y = 0, z = 0}) + + -- preserve *some* velocity so items don't get stuck on the very ledges + -- of nodes once they move just enough to leave the hitbox of flowing water + self.object:set_velocity({ + x = v_curr.x / dry_friction, + y = v_curr.y / dry_friction, + z = v_curr.z / dry_friction + }) end --Only collect items if not moving diff --git a/mods/farming/README.md b/mods/farming/README.md index e442aacb..281b35fb 100644 --- a/mods/farming/README.md +++ b/mods/farming/README.md @@ -13,7 +13,7 @@ This mod works by adding your new plant to the {growing=1} group and numbering t ### Changelog: -- 1.46 - Added min/max default light settings, added lettuce and blackberries with food items (thanks OgelGames), added soya and vanilla (thanks Felfa), added tofu +- 1.46 - Added min/max default light settings, added lettuce and blackberries with food items (thanks OgelGames), added soya and vanilla (thanks Felfa), added tofu, added salt crystals (thanks gorlock) - 1.45 - Dirt and Hoes are more in line with default by using dry/wet/base, added cactus juice, added pasta, spaghetti, cabbage, korean bibimbap, code tidy options, onion soup added (thanks edcrypt), Added apple pie, added wild cotton to savanna - 1.44 - Added 'farming_stage_length' in mod settings for speed of crop growth, also thanks to TheDarkTiger for translation updates diff --git a/mods/farming/food.lua b/mods/farming/food.lua index 70892461..7d30fe61 100644 --- a/mods/farming/food.lua +++ b/mods/farming/food.lua @@ -33,7 +33,48 @@ minetest.register_node("farming:salt", { selection_box = { type = "fixed", fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25} - } + }, + -- special function to make salt crystals form inside water + dropped_step = function(self, pos, dtime) + + self.ctimer = (self.ctimer or 0) + dtime + if self.ctimer < 15.0 then return end + self.ctimer = 0 + + local needed + + if self.node_inside + and self.node_inside.name == "default:water_source" then + needed = 8 + + elseif self.node_inside + and self.node_inside.name == "default:river_water_source" then + needed = 9 + end + + if not needed then return end + + local objs = core.get_objects_inside_radius(pos, 0.5) + + if not objs or #objs ~= 1 then return end + + local salt, ent = nil, nil + + for k, obj in pairs(objs) do + + ent = obj:get_luaentity() + + if ent and ent.name == "__builtin:item" + and ent.itemstring == "farming:salt " .. needed then + + obj:remove() + + core.add_item(pos, "farming:salt_crystal") + + return false -- return with no further action + end + end + end }) minetest.register_craft({ @@ -44,6 +85,40 @@ minetest.register_craft({ replacements = {{"bucket:bucket_water", "bucket:bucket_empty"}} }) +--= Salt Crystal + +minetest.register_node("farming:salt_crystal", { + description = ("Salt crystal"), + inventory_image = "farming_salt_crystal.png", + wield_image = "farming_salt_crystal.png", + drawtype = "plantlike", + visual_scale = 0.8, + paramtype = "light", + light_source = 1, + tiles = {"farming_salt_crystal.png"}, + groups = { dig_immediate = 3, attached_node = 1}, + sounds = default.node_sound_defaults(), + selection_box = { + type = "fixed", + fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25} + }, +}) +minetest.register_craft({ + type = "shapeless", + output = "farming:salt 9", + recipe = {"farming:salt_crystal", "farming:mortar_pestle"}, + replacements = {{"farming:mortar_pestle", "farming:mortar_pestle"}} +}) + +minetest.register_craft({ + output = "farming:salt_crystal", + recipe = { + {"farming:salt", "farming:salt", "farming:salt"}, + {"farming:salt", "farming:salt", "farming:salt"}, + {"farming:salt", "farming:salt", "farming:salt"} + } +}) + --= Rose Water minetest.register_node("farming:rose_water", { diff --git a/mods/farming/license.txt b/mods/farming/license.txt index 6f5bf4a4..49606b68 100644 --- a/mods/farming/license.txt +++ b/mods/farming/license.txt @@ -145,13 +145,16 @@ Created by mDiyo (Natura), modified by TenPlus1 (License: CC BY-SA 3.0): farming_barley.png Created by OgelGames (CC BY-SA 4.0) - farming_berry_smoothie.png - farming_cactus_juice.png - farming_salad.png + farming_berry_smoothie.png + farming_cactus_juice.png + farming_salad.png Created by Felfa (CC0) - farming_blackberry*.png - farming_lettuce*.png - farming_burger.png - farming_soy*.png - farming_vanilla*.png + farming_blackberry*.png + farming_lettuce*.png + farming_burger.png + farming_soy*.png + farming_vanilla*.png + +Created by gorlock (CC0) + farming_salt_crystal.png diff --git a/mods/farming/textures/farming_salt_crystal.png b/mods/farming/textures/farming_salt_crystal.png new file mode 100644 index 0000000000000000000000000000000000000000..e94ed7b391daa72dfc0a1de32fc9e4546930e089 GIT binary patch literal 175 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa4)6(aHDq8|e&XV~OAoi-dA;ZU zt5Z+jpL_A?*2@p~-hSEC^=>Cn8DmM1UoeBivm0qZj+3X0V+hCf= (line_width - cwidth_tab[" "]) then + width = 0 + else + maxw = math_max(width, maxw) + end + if #chars < MAX_INPUT_CHARS then + table.insert(chars, { + off = ch_offs, + tex = char_tex_wide(font_name, wide_c), + col = ("%X"):format(cur_color), + }) + end + ch_offs = ch_offs + w + end + i = i + #wide_c + 3 else local w = cwidth_tab[c] if w then @@ -578,6 +652,7 @@ function signs_lib.make_sign_texture(lines, pos) local line_width local line_height local char_width + local char_width_wide local colorbgw local widemult = 1 @@ -590,12 +665,14 @@ function signs_lib.make_sign_texture(lines, pos) line_width = math.floor(signs_lib.avgwidth31 * def.chars_per_line) * (def.horiz_scaling * widemult) line_height = signs_lib.lineheight31 char_width = signs_lib.charwidth31 + char_width_wide = signs_lib.charwidth_wide31 colorbgw = signs_lib.colorbgw31 else font_size = 15 line_width = math.floor(signs_lib.avgwidth15 * def.chars_per_line) * (def.horiz_scaling * widemult) line_height = signs_lib.lineheight15 char_width = signs_lib.charwidth15 + char_width_wide = signs_lib.charwidth_wide15 colorbgw = signs_lib.colorbgw15 end @@ -604,7 +681,7 @@ function signs_lib.make_sign_texture(lines, pos) local lineno = 0 for i = 1, #lines do if lineno >= def.number_of_lines then break end - local linetex, ln = make_line_texture(lines[i], lineno, pos, line_width, line_height, char_width, font_size, colorbgw) + local linetex, ln = make_line_texture(lines[i], lineno, pos, line_width, line_height, char_width, font_size, colorbgw, char_width_wide) table.insert(texture, linetex) lineno = ln + 1 end diff --git a/mods/signs_lib/encoding.lua b/mods/signs_lib/encoding.lua index b398c464..26b1beaf 100644 --- a/mods/signs_lib/encoding.lua +++ b/mods/signs_lib/encoding.lua @@ -203,6 +203,32 @@ local utf8_decode = { [210] = {[144] = "\165", [145] = "\180"} } +local wide_character_codes = { +} + +signs_lib.unicode_install = function( + numbers +) + local scope = utf8_decode + for i = 1,#numbers-2 do + if not scope[numbers[i]] then + scope[numbers[i]] = {} + end + scope = scope[numbers[i]] + end + scope[numbers[#numbers-1]] = "&#x" .. numbers[#numbers] .. ";" + table.insert( + wide_character_codes, + numbers[#numbers] + ) +end + +signs_lib.unicode_install({38,"26"}) + +dofile(signs_lib.path.."/nonascii-de.lua") +dofile(signs_lib.path.."/nonascii-fr.lua") +dofile(signs_lib.path.."/nonascii-pl.lua") + local nmdc = { [36] = "$", [124] = "|" @@ -230,36 +256,33 @@ function AnsiToUtf8(s) end function Utf8ToAnsi(s) - local a, j, r, b = 0, 0, "" + local a, j, r, b, scope = 0, 0, "" for i = 1, s and s:len() or 0 do b = s:byte(i) - if b < 128 then + if b == 0x26 then + r = r .. "&" + elseif b < 128 then if nmdc[b] then r = r .. nmdc[b] else r = r .. string.char(b) end - elseif a == 2 then - a, j = a - 1, b - elseif a == 1 then - --if j == nil or b == nil then return r end - --print(j) - --print(b) - --local ansi = utf8_decode[j] - --if ansi == nil then return r end - --if ansi[b] == nil then return r end - if utf8_decode[j] then - if utf8_decode[j][b] then - a, r = a - 1, r .. utf8_decode[j][b] + elseif scope then + if scope[b] then + scope = scope[b] + if "string" == type(scope) then + r, scope = r .. scope end + else + r, scope = r .. "_" end - elseif b == 226 then - a = 2 - elseif b == 194 or b == 208 or b == 209 or b == 210 then - j, a = b, 1 + elseif utf8_decode[b] then + scope = utf8_decode[b] else r = r .. "_" end end return r end + +signs_lib.wide_character_codes = wide_character_codes diff --git a/mods/signs_lib/init.lua b/mods/signs_lib/init.lua index fd6c8e75..e0ff3d12 100644 --- a/mods/signs_lib/init.lua +++ b/mods/signs_lib/init.lua @@ -10,7 +10,7 @@ signs_lib.path = minetest.get_modpath(minetest.get_current_modname()) local S, NS = dofile(signs_lib.path .. "/intllib.lua") signs_lib.gettext = S -dofile(signs_lib.path.."/api.lua") dofile(signs_lib.path.."/encoding.lua") +dofile(signs_lib.path.."/api.lua") dofile(signs_lib.path.."/standard_signs.lua") dofile(signs_lib.path.."/compat.lua") diff --git a/mods/signs_lib/nonascii-de.lua b/mods/signs_lib/nonascii-de.lua new file mode 100644 index 00000000..5ca5f901 --- /dev/null +++ b/mods/signs_lib/nonascii-de.lua @@ -0,0 +1,7 @@ +signs_lib.unicode_install({195,132,"00c4"}) +signs_lib.unicode_install({195,150,"00d6"}) +signs_lib.unicode_install({195,156,"00dc"}) +signs_lib.unicode_install({195,159,"00df"}) +signs_lib.unicode_install({195,164,"00e4"}) +signs_lib.unicode_install({195,182,"00f6"}) +signs_lib.unicode_install({195,188,"00fc"}) diff --git a/mods/signs_lib/nonascii-fr.lua b/mods/signs_lib/nonascii-fr.lua new file mode 100644 index 00000000..185bd869 --- /dev/null +++ b/mods/signs_lib/nonascii-fr.lua @@ -0,0 +1,16 @@ +signs_lib.unicode_install({195,128,"00c0"}) +signs_lib.unicode_install({195,134,"00c6"}) +signs_lib.unicode_install({195,135,"00c7"}) +signs_lib.unicode_install({195,136,"00c8"}) +signs_lib.unicode_install({195,137,"00c9"}) +signs_lib.unicode_install({195,138,"00ca"}) +signs_lib.unicode_install({195,148,"00d4"}) +signs_lib.unicode_install({195,153,"00d9"}) +signs_lib.unicode_install({195,160,"00e0"}) +signs_lib.unicode_install({195,166,"00e6"}) +signs_lib.unicode_install({195,167,"00e7"}) +signs_lib.unicode_install({195,168,"00e8"}) +signs_lib.unicode_install({195,169,"00e9"}) +signs_lib.unicode_install({195,170,"00ea"}) +signs_lib.unicode_install({195,180,"00f4"}) +signs_lib.unicode_install({195,185,"00f9"}) diff --git a/mods/signs_lib/nonascii-pl.lua b/mods/signs_lib/nonascii-pl.lua new file mode 100644 index 00000000..0924f8f8 --- /dev/null +++ b/mods/signs_lib/nonascii-pl.lua @@ -0,0 +1,16 @@ +signs_lib.unicode_install({195,147,"00d3"}) +signs_lib.unicode_install({195,179,"00f3"}) +signs_lib.unicode_install({196,132,"0104"}) +signs_lib.unicode_install({196,133,"0105"}) +signs_lib.unicode_install({196,134,"0106"}) +signs_lib.unicode_install({196,135,"0107"}) +signs_lib.unicode_install({196,152,"0118"}) +signs_lib.unicode_install({196,153,"0119"}) +signs_lib.unicode_install({197,129,"0141"}) +signs_lib.unicode_install({197,130,"0142"}) +signs_lib.unicode_install({197,154,"015a"}) +signs_lib.unicode_install({197,155,"015b"}) +signs_lib.unicode_install({197,185,"0179"}) +signs_lib.unicode_install({197,186,"017a"}) +signs_lib.unicode_install({197,187,"017b"}) +signs_lib.unicode_install({197,188,"017c"}) diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00c0.png b/mods/signs_lib/textures/signs_lib_font_15px_00c0.png new file mode 100644 index 0000000000000000000000000000000000000000..87bff365debab70c8004b8e6e657aea2d8b4f358 GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPN8tK+Z-Az%mbgZgq$HN4S|t~y0x1R~10w@nLnB=S(-1=oD^n9IQ*&(tLn{M= ix3Ta4qiD#@PsvQH#I0ctL%1_g1B0ilpUXO@geCy(Qe-~> literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00c4.png b/mods/signs_lib/textures/signs_lib_font_15px_00c4.png new file mode 100644 index 0000000000000000000000000000000000000000..a1706bff001d7eceb17df2179e5c8565fc3dc5df GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPN#?07Q^NU@|l`Z_W&Z0zU$lgJ9>GZqKA zJ29*~C-V}>QAqX(@?~JCQe$9fXklRZ1r%y{!N5>zz`*b-fq}tl1_Oh5!JJ)zHb4oc zByV>YhX3vTXZ8bmoCO|{#X#BvjNMLV+W{Fto-U3d8t3Qs8}c16;9x!<`0sye`H29h z%;r-KE=gx1XE^sxW=NA+^G7#d&)>0VqeI+ZeeXN__}5Ku>n>o^jkq^SW!eeB@Dz#A zGfhu-OLa<3;+B3UuE?!w3bIDE#5JNMC9x#cD!C{XNHG{07#Zjq8tEFCh8S8{nVMLc pT4);>S{WEfi_RBA(U6;;l9^VCTSJzI`YNCX22WQ%mvv4FO#mk3VxRy3 literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00c7.png b/mods/signs_lib/textures/signs_lib_font_15px_00c7.png new file mode 100644 index 0000000000000000000000000000000000000000..171b9a178ca7b077e680dab7409d58f70591703c GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^+(69F!2%>_nEc%hq*&4&eH|GXHuiJ>Nn{1`8HO4AQXKh=d_xh;J<^UkLKAI~W(OfBDb`(nnU zXlcdlOHsFhMyi&$MwFx^mZVxG7o`Fz1|tI_16@NST?5k)LklZY6Dv~-Z39Cq0|RN% g`C=#FVdQ&MBb@0N8_Kg8%>k literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00c8.png b/mods/signs_lib/textures/signs_lib_font_15px_00c8.png new file mode 100644 index 0000000000000000000000000000000000000000..16d70aeb467b55f28fdd40e6af483cc0897a0c51 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPNuqM+&pki)?d-KT+t_EW=2gye-f03fN43N? zq9i4;B-JXpC>2OC7#SED=o%X78kmL{T3DHySeaUC8yH#{80<}&vIs>(ZhlH;S|x4` UXY6(4fEpM)UHx3vIVCg!0CTKcQvd(} literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00c9.png b/mods/signs_lib/textures/signs_lib_font_15px_00c9.png new file mode 100644 index 0000000000000000000000000000000000000000..d11c258b1df34df96ed35ec7790c355cf055051d GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPN`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPN%Z2P&_tsl?6*i*px<0QXwVEp$#K$BEU zTq8Nn{1`8Hp0*}aIAngIhZYQ(tfD9K;7sn8Z%WM5D`4|*9vOE9(H`1HqD4uM- zfL&FDP4&Qx8SQUz3B4Gf;HelF{r5}E+is$3QT literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00d4.png b/mods/signs_lib/textures/signs_lib_font_15px_00d4.png new file mode 100644 index 0000000000000000000000000000000000000000..084acc0740cb0b233226f87667bf03172666ab34 GIT binary patch literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CP!2%?!UOYPlq*&4&eH|GXHuiJ>Nn{1`8Hp0*}aIAngIhZYQ(tfDAuR7sn8Z%WL}$`5Fv(nBQyt`=4sOrEyya z>qEuPr07Bw27!ZLxDo`d`=pZI^DTT5CwAtE!RpOdZ$=6%{Mh8*;=OLyj~|b@4vH05 zewZJkF0@EW`j>dYF`&t+C9V-ADTyViR>?)FK#IZ0z{o(?&`8(7G{n%t%GA`#z);)3 m(8|C-bN&ALC>nC}Q!>*kachY9#I6j~z~JfX=d#Wzp$PyoL}i!& literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00d6.png b/mods/signs_lib/textures/signs_lib_font_15px_00d6.png new file mode 100644 index 0000000000000000000000000000000000000000..e3120cfe5b77e8f6d9055f09ff09dba9e0387847 GIT binary patch literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CP!2%?!UOYPlq*&4&eH|GXHuiJ>Nn{1`8Hp0*}aIAngIhZYQ(tfDAuR7sn8Z%WL}$`5Fv(nBQyt`=4sOrEyya z>qEuPr07Bw27!ZLxDo`d`=pZI^DTT5CwAtE!RpOdZ$=6%{Mh8*;=OLyj~|b@4vH05 zewZJkF0@EW`j>dYF`&t+C9V-ADTyViR>?)FK#IZ0z{o(?&`8(7G{n%t%GA`#&`8_B m(8|Ez%G;%LP&DM`r(~v8;?}TqgRBBj1B0ilpUXO@geCxJ&Sr)H literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00d9.png b/mods/signs_lib/textures/signs_lib_font_15px_00d9.png new file mode 100644 index 0000000000000000000000000000000000000000..759f825285fc8727e0f565aa932c0382a49a1d43 GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^+(69F!2%>_nEc%hq*&4&eH|GXHuiJ>Nn{1`8HmdKI;Vst0BreO+5i9m literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00dc.png b/mods/signs_lib/textures/signs_lib_font_15px_00dc.png new file mode 100644 index 0000000000000000000000000000000000000000..b167f8a95378ad67fc1391f9a9e2f7010ea4a951 GIT binary patch literal 326 zcmeAS@N?(olHy`uVBq!ia0vp^+(69F!2%>_nEc%hq*&4&eH|GXHuiJ>Nn{1`8HPZ!4!iOWaNJ9057aJXEwzx)5(WhYlI zuBfL@GuydE*)}-z@hy0;mn|a9c?o0tTmKmKYa;I^Jh?M1e2?w_1HzRWLgEdN1s4L1 zQY~?fC`m~yNwrEYN(E93Mg~R(x`sx&2Bsl~7FMRFR)$8}28LD!23OuLor9twH$Npa YtrE9}r5j`wfEpM)UHx3vIVCg!0Km>&6951J literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00df.png b/mods/signs_lib/textures/signs_lib_font_15px_00df.png new file mode 100644 index 0000000000000000000000000000000000000000..52c4beeb30f19caa47050ee892f16c0b822d1931 GIT binary patch literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)!r;B5V#N}RpLm>tQ4yJYg>u<81^NCJ6 z=&=K`Mqu0Q_p?&Tt6n5@yr)i zZ1~Ds0yI#y#5JNMC9x#cD!C{XNHG{07#Zjq8tEFCh8S8{nVMP|8fY6BS{WEP7j4;! dq9HdwB{QuOw+1799#B{@c)I$ztaD0e0sxQUU6}v? literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00e0.png b/mods/signs_lib/textures/signs_lib_font_15px_00e0.png new file mode 100644 index 0000000000000000000000000000000000000000..0e4ec8a29a06201d17aa2fcd3515beff415f875d GIT binary patch literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fISR_!C8<`)MX5lF!N|bKK-bVn*T6Ky(89{p#LCo2+rZGuz+ivsfd~{0 cx%nxXX_dG&oU^ES0@T3Z>FVdQ&MBb@0L}GUxBvhE literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00e4.png b/mods/signs_lib/textures/signs_lib_font_15px_00e4.png new file mode 100644 index 0000000000000000000000000000000000000000..b058f1693387156664ec4f38167d77e8e791d194 GIT binary patch literal 328 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIIA|I>G~yNIzb ze9PgyMo4JU?)>{^LJXUVSnaa?CjNS2$08QwG%x$Y1`Im$L?;|N;ubGY@ zhpLviMwFx^mZVxG7o`Fz1|tI_16@NST?5k)LklZYQ!4{YZ39Cq0|P0Ck3Uc}FVdQ&MBb@0A(;*jQ{`u literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00e6.png b/mods/signs_lib/textures/signs_lib_font_15px_00e6.png new file mode 100644 index 0000000000000000000000000000000000000000..76dea7e92bc4fc992e26632979439c88a7e3d0a1 GIT binary patch literal 340 zcmeAS@N?(olHy`uVBq!ia0vp@K+Mm<0wkwu_5J};Ea{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR z+ueoXe|!I#{XiaPfk$L9koEv$x0Bg+K!&fUi(`ny<+T$I@*ObXaFS2^|Nr!x2R(0Z z-FwB!!WlT@Fw32(atzv?b3E7t^b%zxukfz@q&|zuoyG9-Qa85J2itF7XRy4b`Tgwr zhjZQczHgV7eqwu|18A^niEBhjN@7W>RdP`(kYX@0Ff!0JG}1LN4KcK^GBvR>HP$vT lv@$S|6gvF|MMG|WN@iLmZVeg!#Q{JK44$rjF6*2UngCQfWZVD% literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00e7.png b/mods/signs_lib/textures/signs_lib_font_15px_00e7.png new file mode 100644 index 0000000000000000000000000000000000000000..8527bdee034adb5ff73e6356ac5caf7223c41ae3 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIpI3A3=Q$Zif=V0 zHUdpkEpd$~Nl7e8wMs5Z1yT$~21W+DhDN#urXhwFR;DIarpDR^hE@g!l0v87plHa= aPsvQH#H}I2zc>J>fx*+&&t;ucLK6UGU|l=_ literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00e8.png b/mods/signs_lib/textures/signs_lib_font_15px_00e8.png new file mode 100644 index 0000000000000000000000000000000000000000..b2608ead76dfba52acbb835e7f3c547bde9e2fd7 GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)gr;B5V#O2&RN1+1-98A-F{{4UYR?*k( zcEv$P#%2aKC59f>!i%k|QYM@~!@B;R;kzl#N*&d+WAl6W|Cn+wVf)dG`H#L{_5RaZ z#gIH%R;cUU-Fl#@swJ)wB`Jv|saDBFsX&Us$iT=z*U(7Uz%<0r!phVHh_nq1tqctA iZ2g*qq9HdwB{QuOw}!PZeD47@FnGH9xvXI(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)kr;B5V#O2&RPd)|%4yN{H|Nk4=mIO-g z%y0{6wcO;;_OZF0sX?j2^l)gC^pY%|W7}t!&eJn{J@p;e^%*v+-1FjdubF2sMo*R% zN=R+=2b!o_;u=wsl30>zm0Xkxq!^40j0|)QjdTr6LkumfOih4D+rZGuz~Ii-uSqBx ca`RI%(<*UmSo^~F9#8{=r>mdKI;Vst0D8q=F#rGn literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00ea.png b/mods/signs_lib/textures/signs_lib_font_15px_00ea.png new file mode 100644 index 0000000000000000000000000000000000000000..22b35fdd29a38adec62cbb2bb26f85fc6503b36b GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)gr;B5V#O2&RPd)|(4(8>@{?}L9>~L8W z!=*cgjgiNJC1cI3#|wR0c9dDZT4(q0I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)+r;B5V#O2;TN3H`30?g`{{?}L9Y}s`! z$Y6SGn~KT_WoE%!d}>+@D<514T^Ig=?X;+)O#I`;#v*HOrT&$9dH%}gUwlag(tL6L zjW>bDsg}4#l%yncptHiA#yWJ%csDZ)L)z4*}Q$iB}{tI4q literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00f4.png b/mods/signs_lib/textures/signs_lib_font_15px_00f4.png new file mode 100644 index 0000000000000000000000000000000000000000..17dc13fc842c1e6a892408d03c59aa59a38475a2 GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)^r;B5V#O2;TL%stBJWTwn|Ns9~S}@7Y zt9?U4GB*d4L<2_v&zD^)!is(I*GeB{TJ4Ft5y4XEceK%3^T*Ayw6|wx*RQ&FbH7`I z44)*&-7uh$swJ)wB`Jv|saDBFsX&Us$iT=z*U(7Uz%<0r!phXd%G6Zbz|hLTpz6@S fYbY9W^HVa@DsgMzp6`|g)WG2B>gTe~DWM4f*bZP) literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_00f6.png b/mods/signs_lib/textures/signs_lib_font_15px_00f6.png new file mode 100644 index 0000000000000000000000000000000000000000..4ab0cdcb1c017bcb06a90d7ab218765442c2e732 GIT binary patch literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)!r;B5V#O2<8Prd^NJWTB?{{R2<j~dP+i^eU!65Qr?fBf-kj<3_Df~+{UrGc z-X$;s4OA_0jVMV;EJ?LWE=mPb3`Pb<2D*kux(22ph89+)rd9@)+6IPJ1_n|NAAg`| c$jwj5OsmALAzRkd1*n0+)78&qol`;+09I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)Mr;B5V#O0;^hI|YP9L(#F{IB21*EO-_ zpo`dxKqii6RwHYsXI(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)Or;B5V#O36aALkp`W=H_RKjVMtEfWJ2 zLk@I=D*G_^w7M#rwj@m3u%Kw+Dv5=9&6h3ycm!}TtUJvw{nOVb7-)uSiEBhjN@7W> zRdP`(kYX@0Ff!0JG}1LN4KcK^GBvd_G|)CMv@$SoF50pcMMG|WN@iLmZVg8IJfPrV N@O1TaS?83{1OQqxRyP0u literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_0104.png b/mods/signs_lib/textures/signs_lib_font_15px_0104.png new file mode 100644 index 0000000000000000000000000000000000000000..0072d7bba3e16f411390443750c8a8dab96f4305 GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^+(69F!2%>_nEc%hq*&4&eH|GXHuiJ>Nn{1`8HQ=9h~9B9S!dsOaXZSLr8iPYHYdI3_Urg}veIcgGiA zl6cAZOI$+s6Kl#$pt-6gt`Q|Ei6yC4$wjF^iowXh$UxW7NY}tL#L&XZ)WpizQrp1L k%D|wScdjamhTQy=%(P0}8n^;fK{haWy85}Sb4q9e0HFn8@c;k- literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_0105.png b/mods/signs_lib/textures/signs_lib_font_15px_0105.png new file mode 100644 index 0000000000000000000000000000000000000000..f202a12113a0feb10a1a67b78d5007972a5346b1 GIT binary patch literal 331 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIWNl8+jfdxTExQ@ot^hneEoDdW%0SJ`tU{=+o(2v!Xr)eMu5dWD!+e zbn><$&^*-=*NBpo#FA92(5gZ d4Y~O#nQ4`{HDtHDL;^K1c)I$ztaD0e0sz#`U|awI literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_0106.png b/mods/signs_lib/textures/signs_lib_font_15px_0106.png new file mode 100644 index 0000000000000000000000000000000000000000..52b868fc76c2c77cca68c7d78185ab995d3227a3 GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^+(69F!2%>_nEc%hq*&4&eH|GXHuiJ>Nn{1`8H^*w6b+(1e`kJ|sHIMwn&MCD&ow?^y{SW`2yH)tL zq9vsbOg!X(Myi&$MwFx^mZVxG7o`Fz1|tI_16@NST?5k)LklZY6DwnLZ39Cq0|RZN gXB8+Ka`RI%(<*Umh{}&U0@T3Z>FVdQ&MBb@0C*>3T>t<8 literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_0107.png b/mods/signs_lib/textures/signs_lib_font_15px_0107.png new file mode 100644 index 0000000000000000000000000000000000000000..f125d25a7dc7061dbb93b2a379ecefee75af6ac1 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIYw%w4AvZmpEeC-PE32`c*X9*p8evO3w<)4Zc+X`bH@|Kbu$)GRUS#RnaL zE@n_Iag8WRNi0dVN-jzTQVd20Mh3cuM!E*3A%+%KrY2U#M%o63Rt5%@Tqp0NXvob^ Z$xN%nt$`!FFd3+U!PC{xWt~$(699|eSWy4~ literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_0118.png b/mods/signs_lib/textures/signs_lib_font_15px_0118.png new file mode 100644 index 0000000000000000000000000000000000000000..68fe1d7058389734c8e754692a5698ff857c7cd8 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPNe0EfF z%91AUO_QmvAUQh^kMk%5tcuAz~xfoX`Lg_Ws^m5G72fuWUw!IOZC?@=`5=BH$)RpQn# Tl{YgOsDZ)L)z4*}Q$iB}cw<|Y literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_0119.png b/mods/signs_lib/textures/signs_lib_font_15px_0119.png new file mode 100644 index 0000000000000000000000000000000000000000..7d251b598845c4a6b53b3644a984ffcaefd3d6b7 GIT binary patch literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)!r;B5V#O1ktmV6BkJj};e|NTF`U5ROu zu7=0s6Vqj$>|p)BA~u2H(POPe3ppPBeY>*$`f^^ra}hC@h5HkBM(@oGj=yw(_4x&9 ziTis~p8*Y2Epd$~Nl7e8wMs5Z1yT$~21W+DhDN#urXhwFR;DIa#-`c^hE@g!d)9sr fMA49&pOTqYiCe?j5B_g~8W=oX{an^LB{Ts5b%`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPNRI8g+ zf=;|$YbH&I$~Y5U+z=@!>S@t`(X;rE)!ZMO&Ygd6Dm~{Zx3o^8Y(3Bn)e_f;l9a@f zRIB8oR3OD*WME{VYiOivU>ag*VP$G!Wn!RhU}$Av@Fd{kdlU`1`6-!cmAExb<;@HR PYGCkm^>bP0l+XkK4`*6P literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_0142.png b/mods/signs_lib/textures/signs_lib_font_15px_0142.png new file mode 100644 index 0000000000000000000000000000000000000000..ddf4ed28e9e0f536f19e458b3bcb2268daf284d7 GIT binary patch literal 310 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1q!2%@P{+{IkQY`6?zK#qG8~eHcB!VOvi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfDC<47sn8e>%Bc2c^M3N4!!yF-&l5*qW2Y} zNHK+l!2-#TH(0x^u$H{$FmpXSLuCnn^b8K^^;Y|j1GTD_xJHzuB$lLFB^RXvDF!10 zBLiJSBV7a25JL+qQxhv=Q*8r7D+7Z)YrhAgXvob^$xN%nt>Nqk|F=L544$rjF6*2U Fng9V`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPN9{exQH@znCSR4^#iK|MimX%d&!J zatJs`9AJ`k(2QAA!d-O0zm0Xkxq!^40j0|)QjdTr6LkumfOiiqe&9w~-tqcsbjh)5S4_<9cteqY#4v2b1{n|MfTdA|Ed8 zyxr8~;iVbi=HAh_;P)nzuwALL$3KZ`-_6iob@~N|(*N)^k28Hzopr03^^`g#Z8m literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_017b.png b/mods/signs_lib/textures/signs_lib_font_15px_017b.png new file mode 100644 index 0000000000000000000000000000000000000000..15f8ae9cf6944c26b1513948c9af0940f51e87d2 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fISR4^#iK|MimX%d&!J zatJs`9AJ`k(2QAA!d-O0zm0Xkxq!^40j0|)QjdTr6LkumfOiiqe&9n^+tqcr$UEiKT(U6;; Zl9^VCTf-lT&;pMDJk8k7n$1-fG2u>dUEKX9@lk01B0ilpUXO@geCy1!&;00 literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_21.png b/mods/signs_lib/textures/signs_lib_font_15px_21.png index 01929d488591ef60ff9002dcde947dfbe92aee32..c7f20dae7678712e3a36b4cfc1838a59d122156f 100644 GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c90U|T)mzjYC(j9#r85lP9bN@+X1@ak-gWR1M z)}51i3FIgwdj$D1FjT2AFf_Ckr_Wm>bfjrIvkH}&m?E%JaC$sH<3@uL=#}JO|$tge19{__R4DA2^8~;g9_`xr( z*m;n{Sm3gZ8_(_sJPekXxOwk$9(WDZrCQ<|QIe8al4_M)lnSI6j0}tnbPbJk4NOA} vEv$@9tc*>y4GgUe3_>Jqg-|r)=BH$)RpQp5>e{*vsDZ)L)z4*}Q$iB}cWzQn literal 83 zcmeAS@N?(olHy`uVBq!ia0vp^%s|Y~!2%?^AMf=CQc|8Sjv*Y;$q5XN{}Uz|e3hTf gBq*V^u<3*dgIKrZb5kK+OQ0$SPgg&ebxsLQ0K@PTl>h($ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_22.png b/mods/signs_lib/textures/signs_lib_font_15px_22.png index 2acde25d4182ab0b90e0013c7e9c5bcf1e80c1f5..ca55c0e5404da8084abe2228656658b4ec98fda8 100644 GIT binary patch literal 296 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)V!2%?kIAl$M6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gv~u>Eal|aXmTZ$N2`984?!`{QuAM|Dnn( zojN_`xXCY%u`+bs;1t^Pt#c1hv1*BHL`h0wNvc(HQ7VvPFfuSQ&^0vDH82e^w6HQZ ru`)K*HZZg@FbI*b6++RFo1c=IR*74Ks%z^ypaup{S3j3^P6tR< gy_zHqEFQ=(%&hj_Dq4E(Do_=Jr>mdKI;Vst0HrAuH2?qr diff --git a/mods/signs_lib/textures/signs_lib_font_15px_23.png b/mods/signs_lib/textures/signs_lib_font_15px_23.png index ace1437613a28f2796eecafafb39165437359e15..9a5644cda0a4719b12b46392b9b0bf28805c3643 100644 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)Wr;B5V#O0~|j$8~1Jcon+|9@T~P)t#+O}ZE05kvxc+tX#w@0N4)Tm;3k7!q%~36J zjVMV;EJ?LWE=mPb3`Pb<2D*kux(22ph89-FCRT=)+6IPJ1_l@B21ui5$jwj5OsmAL VVZnhH%YhmgJYD@<);T3K0RUN3UUmQg literal 97 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%X?VIghDcmaPWZv!rof>5-*|#b u2VVjAqU>X;9V;cLD=bSBVl`B}*u+q37`nQ^f5l^<9tKZWKbLh*2~7Z10UGT9 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_24.png b/mods/signs_lib/textures/signs_lib_font_15px_24.png index 909b015ec7e4866ad691ce76673b6313da6ff584..7cff26a228d6cc8d9dd854803ba90007157c6233 100644 GIT binary patch literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIo>z40H{RbPY^H3@xmTO{|Ozv<(cc3=B?n32CEf d$jwj5OsmALVfXb_(}5ZoJYD@<);T3K0RZpkT;2cx delta 82 zcmX@ZR4_rs$K2D!F@z&JIpN3o28REE6#FVdQ&MBb@06-2H_y7O^ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_25.png b/mods/signs_lib/textures/signs_lib_font_15px_25.png index 30a78295a279c164c010d1af5f067f65e944a771..a725803f55e3eeffe7e59e5095cfde983652ff1a 100644 GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^d_c_4!2%@fWX=8qDVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fINkd+@33t$T4cBS_nEc%hq*&4&eH|GXHuiJ>Nn{1`8H_Q}NC<1$lLo z;>|02%qLBdlu!7>u>feYYKdz^NlIc#s#S7PDv)9@GB7gGH8j#SFby%ZurfBWGBVUQ nFtjo-$oVTdA4NlMeoAIqC2kF}3l=H^H86O(`njxgN@xNA55{5a delta 90 zcmV-g0Hy!c0(g)lR6j{XK~xyim5)gd03Zkh`~Odm2Nfwn6X8HJ>=HuT2v0C47AD0v wzRbqpRJIb2lq9v?bc6k!7~*w0mvsJx2jjD1o~dpGJ^%m!07*qoM6N<$f-;38kr_Wm>bfjrIvkH}&m?E%JaC$sH<3>8lo#}JO|OHXg)WnkcFIdJ)Jd7ZVi_eu^< zRflLH#prcccFr@JwUp0*}aIAngIhZYQ(tfDA)V7sn8e>r4AAxfl!tnA}hP-=EWE>oGr5 zL@=b~*%X%thFy_1k>X~5x1TbOSuxMGfU)Wam+XPLpR9nIRZCnWN>UO_QmvAUQh^kM zk%5tcuAz~xfoX`Lg_W_1m65TwfuWUw!S5uFZ73RY^HVa@DsgM*vfls-BL+`bKbLh* G2~7aut5om+ delta 58 zcmdnN6fr@?MBdZIF@z&JIpGI?i^2!_o`9JKmIlpjJ}S2Z?l6e5Gc@1Ox+dZEK!pJa NJYD@<);T3K0RTr;6L|mt diff --git a/mods/signs_lib/textures/signs_lib_font_15px_29.png b/mods/signs_lib/textures/signs_lib_font_15px_29.png index e5ff2b76c05b39e47f19db732a1c2a689942c898..912d9d5a6e132bca50dd3fc58473fd4e9326b40e 100644 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^Y(UJ_E)V!2%?kIAl$M6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gtz<>Eal|aXmTZ$N2`984?l(JN`@lH%^+G z`ltU;V#*KxKn}rn?KTc0M^VSG2147WTg5O)g!71RR*(X@Otr){q9i4;B-JXpC>2OC z7#SED=o%X78kmL{T38vISQ(jU8yH#{7}y;(vp~_1o1c=IR*74K|BODM_ZS#FUHx3v IIVCg!0Fg;i5&!@I literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^Y(UJI(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)nr;B5V#O36aALkp`W=KeQ2>v?%WBx>u z-X5O+iBca{H%Xp9aNx&$mB*T21eh2Y-f?q^n;+8K2-K-s;u=wsl30>zm0Xkxq!^40 zj0|)QjdTr6Lkumfj7_YJOtcLQtqct8j+$AZXvob^$xN%nt-*grAJA(I44$rjF6*2U FngC*@RN4Rl delta 54 zcmdnW6f!}@K-$yAF+}2Wa>9>(Mom#BMxoXVjAe?OdetvGGYCXxO*^&jgcbu3c)I$z JtaD0e0s!a05##^> diff --git a/mods/signs_lib/textures/signs_lib_font_15px_2c.png b/mods/signs_lib/textures/signs_lib_font_15px_2c.png index cb3eae05e450652f4567046dc969cb7f25baf822..0c7d02af5a34b9f4bd498c9879e86d292d45128e 100644 GIT binary patch literal 302 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c90U|T)mzjYC(j9#r85lP9bN@+X1@ak-gWR1M z)}51i3FIgwdj$D1FjT2AFf_Ckr_Wm>bfjrIvkH}&m?E%JaC$sH<40TTz#}JO|YtL@vWKa+|aG?78eM>VgzJ&4# zO3Dcz#izXRz3j+b{9Zch9fv5>(iI?As+PD$l%ynzopr0I*jS@&Et; diff --git a/mods/signs_lib/textures/signs_lib_font_15px_2d.png b/mods/signs_lib/textures/signs_lib_font_15px_2d.png index c252f37df74c1dd199d8e53858f29e907e8d87a9..abca8ef52c0650a26e0d9365a0dd370e7e79b698 100644 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1q!2%@P{+{IkQY`6?zK#qG8~eHcB!VOvi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfDC0%7sn8e>&YoU&NHz3@bHKjMM_BgGd3~+ zf`9HpsY`BfG4#J;k+s@h!wFQbTH+c}l9E`GYL#4+3Zxi}42%qP4UKdSOhXJUtc*>p rj7+r+46O_dW^A(ULD7(#pOTqYiCe?V_pLxbFfe$!`njxgN@xNAy9G>M delta 47 zcmZ3*5V(_K<`_3|fzmvv4FO#pqq B55E8a diff --git a/mods/signs_lib/textures/signs_lib_font_15px_2e.png b/mods/signs_lib/textures/signs_lib_font_15px_2e.png index d3aab5be8449801ed6c8673db9d1017098e2461e..858c169d64b463df0c8c2e4319749e3f36df66de 100644 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c90U|T)mzjYC(j9#r85lP9bN@+X1@ak-gWR1M z)}51i3FIgwdj$D1FjT2AFf_Ckr_Wm>bfjrIvkH}&m?E%JaC$sH<3}sIj#}JO|YtJeQF(~jH*wFL;|4s{;ymjK2 z1q*KQdVNXxx1QVW6q~43hxaj{a@7*oh?11Vl2ohYqEsNoU}RuqplfKPYhW5;Xkle+ sVr68eZD43+V6ZYuT@Xb>ZhlH;S|x4`H`wQ|1!`dMboFyt=akR{0N=h&x&QzG literal 77 zcmeAS@N?(olHy`uVBq!ia0vp^%s|Y~!2%?^AMf=CQX-x%jv*Y;$q7IB+ol95G%VPl a!N{;mU*pEP)+cg6c?M5cKbLh*2~7ZKi4%SR diff --git a/mods/signs_lib/textures/signs_lib_font_15px_2f.png b/mods/signs_lib/textures/signs_lib_font_15px_2f.png index 48c25f2e290d0de090375bf5ccbf6b54f44a3551..1b64846b4f54f6ed3927658cc1ab5ec29274df3b 100644 GIT binary patch literal 313 zcmeAS@N?(olHy`uVBq!ia0vp^Y(UJgV|me@UVCkM>iTFE{%0D~oMUe8|A?){jGagO!yLP`7G{YeY#(Vo9o1a#1Rf zVlXl=GSD?N(lsy*F|@EUHnB1?(>5@)GB8*fr7nn~AvZrIGp!Q0h8yhj*8(*#c)I$z JtaD0e0sto{Q-}Zn literal 93 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1q!2%@P{+{IkQYxM-M8FVdQ&MBb@0A{xxPyhe` diff --git a/mods/signs_lib/textures/signs_lib_font_15px_30.png b/mods/signs_lib/textures/signs_lib_font_15px_30.png index 56ec3e79a6d1541d8f3faf17e3ab253f5a675635..6d1131c995a2b848f76088f08047fa9753006e8a 100644 GIT binary patch literal 316 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIge|B0r5mM<2VrM$sHband$#Xu(p>sNl8Ud_2U9jJ%F)78&qol`;+0H*96{r~^~ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_31.png b/mods/signs_lib/textures/signs_lib_font_15px_31.png index c526e8678ed8d80581694e7cf496d5e1d6399a43..2d1103840d2f36b0b9f940cb3bb3faffa4388d68 100644 GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI49OfL^uvExfpx#}+=|PpW|B<&Z*uT8xlD;_0cni=7)e_f;l9a@f zRIB8oR3OD*WME{VYiOivU>ag*VP$M$WoV*pU}$Avu))jlHj0Ma{FKbJO57R_ig%_1 PH86O(`njxgN@xNA)Vx`4 literal 87 zcmeAS@N?(olHy`uVBq!ia0vp^Y(UJ)4g}c-_txZ~Uge|B0r5jw^qWcV%$pIO$W;_@76D$>W`qx$x1AH(LHBJ1lBp&=c|B`1ogh63`3= MPgg&ebxsLQ0Ki8iDF6Tf diff --git a/mods/signs_lib/textures/signs_lib_font_15px_33.png b/mods/signs_lib/textures/signs_lib_font_15px_33.png index aba5466e9243b40734c038f8c4707988d832c976..2070a7d1c58908ad6339b0e52c007b61593dd130 100644 GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI&!;nU+)aW<#}$0qe$MzW$qAg3mnr`1$nK3dVG0 zVZ}RhK3oMFsaoP1QIe8al4_M)lnSI6j0}tnbPbJk4NOA}Ev$@9tPD-H4GgUe48&}$ f@=-M8=BH$)RpQo=p3rm|sDZ)L)z4*}Q$iB}AV*;q literal 109 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQYM}*jv*44lM{aMw-|hoKjh4D zfW>ge|B0r5+ByHa3pxln88R#vP<*`6f~h-rV-<(2kSYtq{*r(VGbg#n1NAd_y85}S Ib4q9e0Lj@N>Hq)$ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_34.png b/mods/signs_lib/textures/signs_lib_font_15px_34.png index 9e71d1025486c4954063a0f1c3be22afe4d1a272..366548b6246cfe49e4caa9cb12d2d72bedeee8b2 100644 GIT binary patch literal 326 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)`r;B5V#O2z4Pc8-n4rcXB|LZMnrzqW0 z6*uHD(Bb6P&@Ts{gC2CsCno|xDQ(sDd`nss>H_wm2`||qNSh}C_Nir{t2fBzs zwZt`|BqgyV)hf9t6-Y4{85kMp8XD;un1&cySQ(pG8JcPv7+M(^h}l}@qiD#@PsvQH W#H}Gcq3JSE1B0ilpUXO@geCwwHdwp> delta 73 zcmX@cls-YlS5V(Rsn`IMQ#O7M~fe=4}5H#4A^D~7#-02B7bz_|C54E d-h#?33~M%qu3qf2ZxI6!c)I$ztaD0e0syyo8W{ip diff --git a/mods/signs_lib/textures/signs_lib_font_15px_35.png b/mods/signs_lib/textures/signs_lib_font_15px_35.png index c12370fff31b0c5f0784da4453ae7ac6162b3017..186c53f3977da9915bcc1b0da4d4e8d5733835e4 100644 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fISR2lM)4|Lb@1@n}rA z(OV=U@a*EEjOM9JZ3HiBy7in?z0x$dB0#sKu~dJa(^r}G@Ac1GFuCxnYO&q(1e&B; z;u=wsl30>zm0Xkxq!^40j0|)QjdTr6Lkumfj7_Wz&9n^+tqcs*uPS^((U6;;l9^VC VTSHjK3_qX-22WQ%mvv4FO#lYASs(xa literal 109 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQYM}*jv*44d;2!>G8k|i{`3Fx zyRbz~0VmT~nLD1GXxlS0P|wsw@o~q?0>_6dt}WPZ|M3~OZ2y7awOM~3Sp)Smc)I$z JtaD0e0szQZCdvQ+ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_36.png b/mods/signs_lib/textures/signs_lib_font_15px_36.png index bebb32a8bd14a4a670af9ef0367b13d9423276c2..f0ed10603521db84bb09082cc30715a5ea2370c6 100644 GIT binary patch literal 331 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIp_{yP;^v b%}>cptHiD0!~e-3-!gc*`njxgN@xNA+lgKe literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQu>}Qjv*44lM{aMw-|hoKjh4D zfW>ge|B0pt6gKf}639$@DDHH*is>!H>^W2YqsTMQPSdK}a^;dn0Fq{|$?Se+RdTs3&)*(1#LfTpOHxJHzu zB$lLFB^RXvDF!10BLiJSBV7a25JL+qV-qVwb8Q1dD+7bZMcQsC8glbfGSez?YxwYg QGRTh%p00i_>zopr0CZtitN;K2 literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQfi(qjv*44lM@`+|4VM*{M+u_ t!BD3-gTYR*g~8M51d|HqLZ?M742H!?^FDW!Sps!1c)I$ztaD0e0s!Vv7}Nj& diff --git a/mods/signs_lib/textures/signs_lib_font_15px_38.png b/mods/signs_lib/textures/signs_lib_font_15px_38.png index baf7f6f822ad20b6ed2c3aec1b05a817544b1de1..b95f853d73ca874794751a7fb15d57063e06c2ca 100644 GIT binary patch literal 328 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI9rr{@35MUa%^9 z_sX3P4n+zlypJy8KCq=T;Br}bvUt73!QPEtf-+x!_obJZW;qrANtM2{n_W!!PE*(; zpkb;dt`Q|Ei6yC4$wjF^iowXh$UxW7NY}tL#L&XZ*u=`vLfgR5%D|xfRrGok4Y~O# ZnQ4`{HLz`eEDY4Z;OXk;vd$@?2>_(2UbO%K literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQu>}Qjv*44lM{aMw-|hoKjh4D zfW>ge|B0r5+ByHa2eO)WR~<_ZY(1*8#%z)Eq85fb@?P7@H;82ewK90R`njxgN@xNA Dfg>Oc diff --git a/mods/signs_lib/textures/signs_lib_font_15px_39.png b/mods/signs_lib/textures/signs_lib_font_15px_39.png index 95729472b0801b9612f4bc3fcb590813d92cdfc3..ed8ef4a578eca12a1054a0c1d1a959b0a04fcdd5 100644 GIT binary patch literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIge|B0r5)D>Em30|#OA+YM;f5B%HlCIT diff --git a/mods/signs_lib/textures/signs_lib_font_15px_3a.png b/mods/signs_lib/textures/signs_lib_font_15px_3a.png index 23ba0cd086620a1706c1632a557216a230d310a5..b368a66a78ca693b71e3579400762c3f88028303 100644 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c90U|T)mzjYC(j9#r85lP9bN@+X1@ak-gWR1M z)}51i3FIgwdj$D1FjT2AFf_Ckr_Wm>bfjrIvkH}&m?E%JaC$sH<3}sIj#}JO|Yfo?FWl-QbU@-lEJ)g96^!5`$ zZU-KUPkC`NCtjSFgPV7|n8Qk-a@7*oh?11Vl2ohYqEsNoU}RuqplfKPYhW5;Xkle+ sVr68mZD43+V8E}dvlK-`ZhlH;S|x4`bp=x-ff^V*UHx3vIVCg!0P}-PIRF3v literal 77 zcmeAS@N?(olHy`uVBq!ia0vp^%s|Y~!2%?^AMf=CQX-x%jv*Y^lM{aMx82Yba0n1t a$-*$vO6ATm)zzFpc?M5cKbLh*2~7ZAcoLZa diff --git a/mods/signs_lib/textures/signs_lib_font_15px_3b.png b/mods/signs_lib/textures/signs_lib_font_15px_3b.png index c4b467faa57587966f53736f413bca154a29aaa1..ade33c1e956d3cb4b7365e44827592e72c5c37af 100644 GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c90U|T)mzjYC(j9#r85lP9bN@+X1@ak-gWR1M z)}51i3FIgwdj$D1FjT2AFf_Ckr_Wm>bfjrIvkH}&m?E%JaC$sH<3@uL=#}JO|bI%xZF(?QeIdJp$|M}P5Sh%Hk z3wSI#@PR36>G3D4r7rQF{TivL!^_+B$bTkKmuiV?L`h0wNvc(HQ7VvPFfuSQ&^0vD zH82e^w6HQZu`)8(HZZg@FyPnKS&E_|H$NpatrE9}x`HW^Kn)C@u6{1-oD!M<|4C8x literal 80 zcmeAS@N?(olHy`uVBq!ia0vp^%s|Y~!2%?^AMf=CQsSO2jv*Y^lM{aMx82Yba0pnk d!e!ZkE{4J=#rx8E$*Mpl44$rjF6*2UngG0|6wLqt diff --git a/mods/signs_lib/textures/signs_lib_font_15px_3c.png b/mods/signs_lib/textures/signs_lib_font_15px_3c.png index 566ba4968c3c019787f33ebd9a42ca05614b7dc8..7423e9acfb7920b57ca8a810d37887b107526251 100644 GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h);r;B5V#O0;^hFlB=JWS^&{ja~tr>Y>y zwKT6wM(fOlrtc@3yoy6I9r~u#9OR$I^J=B<6!z0y*Pbgj@P2s6r+nnlY>>-UOI#yL zQW8s2t&)pUffR$0fsui(p^>hEX^5ePm9dGHk-4^kp_PFFzpl9>(#+Aw}Odd`K45Cg26DwZay4boQ<4B?npZkOtiVP;s VIa4m@EqliR1fH&bF6*2UngA}}7_9&R diff --git a/mods/signs_lib/textures/signs_lib_font_15px_3d.png b/mods/signs_lib/textures/signs_lib_font_15px_3d.png index 50e6c6f084c3e7084bdd54e66addf1e4a6522ea4..1c8320c2a878830799aee50570377e3dec3c495e 100644 GIT binary patch literal 302 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)@r;B5V#O36aALkp`W=Ke^P&;zyz=!#Q zkqsa1#X@^#^eIFuo5u1pRQIyW#-x5}1Zq(&ag8WRNi0dVN-jzTQVd20Mh3cuM!E*3 xA%+%K#wJ!q7TN}eRt5$?Q)7HkH00)|WTsW(*3e<`QAPj& delta 50 zcmZ3-6fi+WN8HoJF+}2Wa>9>(#+6zvd>gng-q%TLVff>eHY>I!+LQqZJYD@<);T3K F0RYau5z7Do diff --git a/mods/signs_lib/textures/signs_lib_font_15px_3e.png b/mods/signs_lib/textures/signs_lib_font_15px_3e.png index 090f8ca339e6cb7b2383dd473cd65add02f08818..bab7978d813c6a8237d815292af0e599c8e25430 100644 GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)$r;B5V#O1mDhI|YP9L&*||JO^3uXd2> zxw}JIRiJSiW8l+m{ z8c~vxSdwa$T$Bo=7>o>z40H{RbPY^H3@xmTO{|P8v<(cc3=Dpz#`vIU$jwj5OsmAL Up~K?I2cQN9Pgg&ebxsLQ0IM5WSO5S3 delta 65 zcmX@Y6hA@5TFukNF+}2Wa>9>(#*^Yqj5zopr03cWxNB{r; diff --git a/mods/signs_lib/textures/signs_lib_font_15px_3f.png b/mods/signs_lib/textures/signs_lib_font_15px_3f.png index dce472764f3fb5d921d271cc6266931b6ef3fbed..13e02eb82e63072499f29908128d81939f962515 100644 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)cr;B5V#O2=pgIo*>9M0w+|JPT_o?$W0 znEo<2MaXIL!%6L(53k(w5}4W^X!?)FK#IZ0z{o(?&`8(7G{n%t%Gkup$Wq(D(8|CdUMTzriiX_$ al+3hB+#2-!-@5=cFnGH9xvXzopr01$H> AuK)l5 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_40.png b/mods/signs_lib/textures/signs_lib_font_15px_40.png index 65533fdc49958ac47482cf6e551023b935e88e5f..56ae56b362c07fef0c292f9d8b963d3240fa1dc8 100644 GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0vp^{2p0*}aIAngIhZYQ(tfQ$rB7sn8Z%dHaw`3@-XI329`uf4z4gm<>o zb$Q32jH^!5rFLE8IdU*!R6) zItL%-EN$P+qNN-%fyv3dt;9TeyP!)?=6lYK2dl)Te`NnUrQV{tZ`#`D cmmdVMYnQiI{uH?t2Q-qw)78&qol`;+01<2}S^xk5 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_41.png b/mods/signs_lib/textures/signs_lib_font_15px_41.png index e30c27ca5f3dc21f13dc1407701faa8ba71ceaab..beca716083fae9ecbe5762e59d72adebbd287d04 100644 GIT binary patch literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPNj^w6a3o zxEpsErwZsva+#V7GOS?FJh_zJQ#M6VeD2~j$J@8%K3;rpwtj1A@sIECpKf3_kPwnx z=e_M5&_LA^*NBpo#FA92O)fz~JfX=d#Wzp$P!_c3%?! literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CP!2%?!UOYPlq-;E0977~7Pd(?z$DqK$eDL4@ z%dZ`k0}PLSYwA<_nEc%hq*&4&eH|GXHuiJ>Nn{1`8HTTIxW_7)6WA^Py_iwX)Z(gu|zRU-*UZhlH;S|x4` UKR>N~1=PUc>FVdQ&MBb@0AWyG4*&oF literal 97 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%X?VIghDcmaPHgTe~DWM4fr6L|0 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_43.png b/mods/signs_lib/textures/signs_lib_font_15px_43.png index db57d8dc232e7247f9dd6f5b1907d9731001c892..9dbd4f6c22f15bb33b9acfe9b4f6c669a2522d20 100644 GIT binary patch literal 330 zcmeAS@N?(olHy`uVBq!ia0vp^+(69F!2%>_nEc%hq*&4&eH|GXHuiJ>Nn{1`8HeXZzX zzR!znxRjkTQZk<2KEiNiuAjur3!GX3ap9NSPucrqh;N_nEc%hq*&4&eH|GXHuiJ>Nn{1`8HUO_QmvAUQh^kMk%5tcuAz~xfoX`Lg_W_1m4TtQfuWUwf!+gTe~DWM4fnY>*f delta 74 zcmX@blrcfYMc>oKF+}2Wa)JZf|Azw13Y?2q9TfQ2?>~bv_=mmcA)XzroR$LZ`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPN+~YcGdLEA{0t^!>eYRw6yix~L&fw|l=d#Wzp$P!aml^T^ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_46.png b/mods/signs_lib/textures/signs_lib_font_15px_46.png index 24de187a47e2ed6ebc9fe591d757ee9492b26a12..e1adea4137a761f27ead38d527f68443588b993e 100644 GIT binary patch literal 311 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)Kr;B5V#O36aALkp`W=I$?a5EpScS~VB z_Wwqx;}edVM-MdQ$g!pgsvq%~BEOM?k>N-ahq7o!10ztcYKdz^NlIc#s#S7PDv)9@ zGB7gGH8j#SFby%ZurfBWGBDCMFtjo-kT+ndN70a*pOTqYiCaTn?w-Ry4Gf;HelF{r G5}E+qF;P1J delta 61 zcmdna6g@%3T*=eLF+?IfIl+Pb|3%gZPX7ZHIGs2e{5iVavN#tOb&4@DaGOW0Sl6r} P$p8eNu6{1-oD!MNn{1`8Hp0*}aIAngIhZYQ(tKnzb8#}J9jQzsncV^H95l3)A(f2x(q<|w&G zOFEoIo^`r4%C(A4_nEc%hq-;H1977~7Cnx;iZ{uKix|r*b z%7dm8yB-|+|4=~dOoLj_lGpZii7jzDVvjZpEoZ*Cms#9x`x|?+_nEc%hq*&4&eH|GXHuiJ>Nn{1`8H8W$gYjVMV;EJ?LWE=mPb z3`Pb<2D*kux(22ph89-FCRPSU+6IPJ1_ts5EcGZFa`RI%(<*Um$jjYx7^s24)78&q Iol`;+0P($42LJ#7 delta 59 zcmdnV6gfe~RKe55F+}2Wasor+e-D8}%jX$b9nkmjo-UyOM_yaSQ-a~`_KX?v=_k?| OfWXt$&t;ucLK6UcD-`Jf diff --git a/mods/signs_lib/textures/signs_lib_font_15px_49.png b/mods/signs_lib/textures/signs_lib_font_15px_49.png index 1f027283c2304946e92c02322736a3310b8883e7..7d7c9d999eb74b055bd00217a9f8c4acaaa8b583 100644 GIT binary patch literal 300 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c90U|T)mzjYC(j9#r85lP9bN@+X1@ak-gWR1M z)}51i3FIgwdj$D1FjT2AFf_Ckr_Wm>bfjrIvkH}&m?E%JaC$sH<3{_7T#}JO|$tge19{__R4DA2^8~;g9_`xr} zP^?+-u$~1oL#ig5=$5z3*Ml^axJHzuB$lLFB^RXvDF!10BLiJSBV7a25JL+qV-qU_ pV{HRND+7a_?);}wH00)|WTsW()^I{I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)Or;B5V#O36aALkp`W=I$?aJT$A&#_SQ ze{$$imdUAq`j6{;YW-(?NT%VDUWlVx+y4{iTDT^rD>K~K!Xx`=?*! zC8<`)MX5lF!N|bKK-bVn*T6Ky(89{t#LB=#+rZGuz@X-Vp(~1p-29Zxv`X9>c=vYx Q1ZrULboFyt=akR{07N=lQ2+n{ literal 91 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DJ4%A#}JO|$q7IB+Z8^{Ph7yF pAfm{~@}pntoBY)a|BrAoFw`9kUR(6@ZXZxJgQu&X%Q~loCIGNl8Z`g_ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_4b.png b/mods/signs_lib/textures/signs_lib_font_15px_4b.png index e8d52d60d6e5bf4284b0fe8ad93a2a27eb2e557f..2aefbab8f69749a48f5abb862121e73adee52032 100644 GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CP!2%?!UOYPlq*&4&eH|GXHuiJ>Nn{1`8Hp0*}aIAngIhZYQ(tfDBJh7sn8Z%Tp&f3LP-uV4B|Z|G$y#*3KTw zD~r1gG|pIbpB9N&@ctargw?ONWt`1kv8CffjC|OqZs`faTR#Z99_&5#Ozg$?_3Ium zie^eEItJXH2Q*Z*#5JNMC9x#cD!C{XNHG{07#Zjq8tEFCh8S8{8Jk!cm}naqS{WGB hJTP=c(U6;;l9^VCTLbUj&YwUH44$rjF6*2UngC=iW>EkD delta 84 zcmV-a0IUDd0&ICK=g3lMjzm&GsssSI(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)fr;B5V#O36aALkp`W=KeE;P{*V=e$RR z=-k!_1(8FkJ^weZNK(1h547T)9-Hj#ov)q(b*YxPMwFx^mZVxG7o`Fz1|tI_16@NS zT?5k)LklZo6DtE#Z39Cq1A|-Btv;e?$jwj5OsmALVfCpdp!XOUJYD@<);T3K0RW6h BRn!0g delta 52 zcmdnU6f{9aPtw!HF+}2Wasor+e~p3_oQlkEoc!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR z+ueoXe|!I#{XiaPfk$L9koEv$x0Bg+K!%&Ai(`ny<+&3)`4|*9n3o^>U%ykXXA%3< z6Ri%H69u0Mv?hmaU@*D6Sg%_7ljx6WPx>|`Wr;~>=Uh5)M9^}zm0Xkxq!^40j0|)QjdTr6Lkumfj7_WzOtlRRtqcrqO}F}p eq9HdwB{QuOw}#cHnt)zsVDNPHb6Mw<&;$U7i(n7{ literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CP!2%?!UOYPlq>MdX9780gCMPsB{4d~mJX!Z( zgOX3gBl}55>Pt9tRO~osDE{B*X)r;f@r}`jBlR*9QaBlozE7H`_isxEP&_nEc%hq*&4&eH|GXHuiJ>Nn{1`8Hm z>FHaB4Hw&rj2k(X4*JPC^1SSAc1$e)pR~cOE0*21y8V8^uSZ^g{-vy9ou9xjU1&ZN z=l}-Q64!{5l*E!$tK_0oAjM#0U}T_cXryak8e(W+Wo%+)V5V(gXk}pVx?Uj%MMG|W aN@iLmZVj`PW?TSjVDNPHb6Mw<&;$Ugm|dp; delta 73 zcmX@fls-YlS!8Srg9#KHNfWg=^bU|Ug#Sexe`cQL0n c38o({jBi8Z7G<(pSuy~Dr>mdKI;Vst02zcE0ssI2 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_4f.png b/mods/signs_lib/textures/signs_lib_font_15px_4f.png index b278ccc5e525df7783278b34a1ffb7f02cc3a1e0..7e7654bf0b7f468b265db78dbbcd50051ba7e195 100644 GIT binary patch literal 333 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CP!2%?!UOYPlq*&4&eH|GXHuiJ>Nn{1`8Hp0*}aIAngIhZYQ(tfDAWJ7sn8Z%WM5D`4|*&P%-_!hPZS%yX zzTVsdhr}4!UCfi#>Bw_zUFcXUo;FLQ$onhHN2PyT9y~bR<=vOXH2JLJ1Nm@HvCpEi z8`&4;0Zmjbag8WRNi0dVN-jzTQVd20Mh3cuM!E*3A%+%K#wJzlJcP dH00)|WTsW()-X$H#s#1T22WQ%mvv4FO#ms)UP}M~ delta 86 zcmX@hR5C#&z}nNrF+}2Wa>5V(HjWSSYE4=_6Pmb{U%O2D(QnYicvK{WbBE>sKm|jg qh~7h)mU7P@eNmXFaFES&8Uw?%jm5n_+4-*-fWXt$&t;ucLK6VR<{_K_ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_50.png b/mods/signs_lib/textures/signs_lib_font_15px_50.png index 33b52fd6bca3f2c61954b157dd0652c90aac2c8b..5ca302bc8b4cc7b695892c7acac33638b972e310 100644 GIT binary patch literal 321 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPN~WJOw+x@K=?mJ!<;u^ZL)5InI6c+Y6W_g1Jorl^*a`RI%(<*UmunC=< Q0@T3Z>FVdQ&MBb@06p(nBme*a delta 69 zcmX@elsrMjUdz+PF+^f&a)JZv|APX|2U!0vUg048$A61LSJ@h|#L`RkCLSvlb}@K1 ZF&udqyI7uObteN5c)I$ztaD0e0sx^i8V~>g diff --git a/mods/signs_lib/textures/signs_lib_font_15px_51.png b/mods/signs_lib/textures/signs_lib_font_15px_51.png index 892747c7f672097c353450696a240a1d53c19ee3..1367e892f89154edcd38c1aa90f4aee9633a967d 100644 GIT binary patch literal 338 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CP!2%?!UOYPlq*&4&eH|GXHuiJ>Nn{1`8Hp0*}aIAngIhZYQ(tfDCU>7sn8Z%X0%P`4|j1gf9QDpUF2ZqMA4L zBF7`f#j+2}9D|))jubQ)b~9O&dT35`=Q_vq$nekX6MIcQ?$Udt>N%Bp^+~rY+kd>$ zElFH2BVKt@;5X1%)e_f;l9a@fRIB8oR3OD*WME{VYiOivU>ag*VP$M$WnivtU}$Av j;LD+X14Tn_eoAIqC2kEip_5a98W=oX{an^LB{Ts57e!%A delta 92 zcmV-i0HgoX0(y`nRzXQbK~xyijgLVR03Zkg`TwWslz`Th-q;ZkAP7Rkt)whevR@jY yED$aU%7?K(K+y(9T((N|dhm=|Ble5AH?RPY&TN#2o$XBk0000Nn{1`8Hp0*}aIAngIhZYQ(tfDC6(7sn8Z%Tp(KaxoZiFi(E;fBzggufT4u zuQQGcaxR?Hn#Lor*~PS1c*~5U%CsYQ4(#w2R{nNvcHV=$so|Xr`|GbtN&Eg3RK8`A zJqKu_nEc%hq_jO<977~7Cnq?t|34_e-N607 y-8rb`B9G#sQ~z0b70;`3Bo}c0KhEVT#Kw?vD1M<6V@f4Z8-u5-pUXO@geCyL4;#w> diff --git a/mods/signs_lib/textures/signs_lib_font_15px_53.png b/mods/signs_lib/textures/signs_lib_font_15px_53.png index 028f2841ec9da8fab68a217b7679146b3bb80b79..57b6a392ae909dad40775b6952e9a07f496bb6b2 100644 GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPN~}N!@4FW< z?_Dk?)FK#IZ0z{o(?&`8(7G{n%t%Gkupz*5`5(8|C- j);s{@WrT*@{FKbJO57T9vR+sMH86O(`njxgN@xNAv+H4g delta 81 zcmcb}ls`em+sxC&F+}2Wa>5V(7LE_{hup=QI2W&K*fg;v;n4q!zK65aVgxSNh2*+K lv@8=^{kX6~SXfAxgW=fQ@Rd(;d)_brfv2mV%Q~loCIEBjAz}ak diff --git a/mods/signs_lib/textures/signs_lib_font_15px_54.png b/mods/signs_lib/textures/signs_lib_font_15px_54.png index 3bd0a2b9e5ec2d46d38c916719a0886c75097228..a566d478b8bffb3080c82e81e2ccaf3e45daec30 100644 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPNmdK II;Vst0FXgdO#lD@ literal 85 zcmeAS@N?(olHy`uVBq!ia0vp^+(69F!2%>_nEc%hq+~o@977~7Cnp?W`)B+>=pTQp jfZiN)pVmM{&qECVjB8p>uT;AMRL9`y>gTe~DWM4fMS>UO diff --git a/mods/signs_lib/textures/signs_lib_font_15px_55.png b/mods/signs_lib/textures/signs_lib_font_15px_55.png index 81643f94cc61bb096dcf953e67ace5476ad794c1..82543f570b05a95129367c24d47867c6f5e825fd 100644 GIT binary patch literal 317 zcmeAS@N?(olHy`uVBq!ia0vp^+(69F!2%>_nEc%hq*&4&eH|GXHuiJ>Nn{1`8H8WW68pt UDH7U($qYc?>FVdQ&MBb@0Qs{PX#fBK diff --git a/mods/signs_lib/textures/signs_lib_font_15px_56.png b/mods/signs_lib/textures/signs_lib_font_15px_56.png index 8726f5bc1b1202c4ef1111f6c87c333afb2fb4b2..36bd8e686198926a69c524b4958fdf3b2253fe16 100644 GIT binary patch literal 326 zcmeAS@N?(olHy`uVBq!ia0vp^+(69F!2%>_nEc%hq*&4&eH|GXHuiJ>Nn{1`8HPZ!4!iOW+bT;yU<;9=VO|9^UQM9{&O zPpNMvB=-o+;!#Klyt822on;K)kKQV_PRd?WF>y}1p3hxlj~~A$>j{4@6qL3)bXgH- zlxm4zFiH3+Dv^t_TgbZCWu cGsAoX1|_SC4zatI(F{P~>FVdQ&MBb@0DwFfqyPW_ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_57.png b/mods/signs_lib/textures/signs_lib_font_15px_57.png index 5e8d9d0f45ec86701a6959a0c355324967709853..5bfc0eb1cff16c5dbb30588eb5a1efdd00e63a24 100644 GIT binary patch literal 328 zcmeAS@N?(olHy`uVBq!ia0vp^{2p0*}aIAngIhZYQ(tfDA`Z7sn8Z%WEe%axo}yu%s{kUtek6@u5jeJh)$uB#fYMC_s_#qQn-SUT`N!39=rhoXpJ%nd*n~1dh&zf66 z!&FOLBT7;dOH!?pi&B9UgOP!efv%yEu7PQYp@o&PiIt(Dwt=CQfx)99xf&D=x%nxX YX_dG&Ox9m^0H}e%)78&qol`;+0O`V9*8l(j delta 77 zcmX@Xls!Sk-N@6$F+^f&asor+|A3B@%L1e#1tzziNl9=>6jtvoI99LGnZjvSyTmj3 gvykZ0LdUKpj8Dp@Wp#hxWMcpVPgg&ebxsLQ0Dlu4>i_@% diff --git a/mods/signs_lib/textures/signs_lib_font_15px_58.png b/mods/signs_lib/textures/signs_lib_font_15px_58.png index 2abbda39cfc0edad8201f682a1a33253f0f9ec3d..a7805ccd354ccae2ade5a51903c27323b4891bae 100644 GIT binary patch literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CP!2%?!UOYPlq*&4&eH|GXHuiJ>Nn{1`8Hp0*}aIAngIhZYQ(tfDAuR7sn8Z%X23f@*ObXU_Srn|M_+|Yr+xQpql51S8%77-TmbgZgq$HN4S|t~y0x1R~10w@nLnB=S(-1=oD`OKYLnCbi mLn{M=%d=P>qG-s?PsvQH#I0e`@jbCX4Gf;HelF{r5}E)WVrQlR literal 115 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%S$VoRhDcoQ?RVs3P~bTH>%af? zX17)yx3b1bt&9wLXEU!lDpbF|YC2i;(n8j~30vBo6@z%>@0+}k=JUIjIRCvz`vagU N44$rjF6*2UngA-%C6NFC diff --git a/mods/signs_lib/textures/signs_lib_font_15px_59.png b/mods/signs_lib/textures/signs_lib_font_15px_59.png index ff45093067334e7937f0818f8cf2b1a324367e80..af6734c0c928cf425590f9173f55f5c3d029678b 100644 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPNPx# literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^+(69F!2%>_nEc%hqzpV=9780+lM@&k|9c1=YG+Du z-0-2E=iz^WL>0amM!Uovq8x`ma4nAVQBMr2S|M%PQyKyEx z@-vWPJ0!w7oh{<#DSfB5CtQm1hi|3a7A)lpOip~0bhF?3%ipDv!uKxmDZY9q!VEM@ zwZt`|BqgyV)hf9t6-Y4{85kMp8XD;un1&cySQ(pG85(OF7+M(^l)mK;MbVI(pOTqY WiCY89hV3A~GkCiCxvX+Ad7!-Jz4*veX ze4~)(70!~|3}0Rdu@u=aS;DJkrOKkYvZ>zoMM_n?n0nOnsGxN=RmbIk+8I1u{an^L HB{Ts5oa`S@ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_5b.png b/mods/signs_lib/textures/signs_lib_font_15px_5b.png index 2592f1ff71cc36c7a5a6ab47e6f30630a6ac4727..91a108dcc820fb3ff0522c6eb34e542fff86144a 100644 GIT binary patch literal 301 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1q!2%@P{+{IkQY`6?zK#qG8~eHcB!VOvi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfDAQH7sn8e>wC{_EuCDzhlB(SE)Ts6(~HHKHUXu_V85poB2yI2tkei>9nO2EgLwW5gPM`(`Pgg&ebxsLQ0PCJoKmY&$ delta 50 zcmZ3>6fi+WN8HoJF@)oKazaDnf1Vd-{`352Z|i&~!%%xj<&Iw2XJ-Z=@O1TaS?83{ F1OWa`6R-dP diff --git a/mods/signs_lib/textures/signs_lib_font_15px_5d.png b/mods/signs_lib/textures/signs_lib_font_15px_5d.png index a5efa37d09b34cad427ac7ac081006217f0f578e..82a39dfd031db36bcb69099c874d2cf2a3c42bc0 100644 GIT binary patch literal 297 zcmeAS@N?(olHy`uVBq!ia0vp^Y(UJI5Ssod#)!14^Jgu&C*&t;ucLK6V~$QRK7 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_5e.png b/mods/signs_lib/textures/signs_lib_font_15px_5e.png index 7f610d8724ce14320ab7d27b85ddea53490e2d07..fbbf800f9bed4ea13bffeef1a7205146ae09315d 100644 GIT binary patch literal 321 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)er;B5V#O36aALkp`W=I$?aJT$Af8qcT z{E%5V(HiZxJ$BrqoFc&CFu=^zoIvKV$GPYl+=dqAzVR)*a VH))3JylMs@@O1TaS?83{1OW2J78w8l diff --git a/mods/signs_lib/textures/signs_lib_font_15px_5f.png b/mods/signs_lib/textures/signs_lib_font_15px_5f.png index 07cce5a145368adc8ac32e97479f4ba3f37858f7..a343b6bc2057050aa01d60d09aea40db0bc1209a 100644 GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)-r;B5V#O36aALkp`W=Kf1?G<=j&%@|; zW&+U6FcwLU^dlgXR7+eVN>UO_QmvAUQh^kMk%5tcuAz~xfoX`Lg_W_1m9dewfuWUw j!NmQ{b5Jzo=BH$)RpQq0;L&acpaup{S3j3^P6`THmwy%346LYhDcmaPWaK!+Q+qsJE`eE ZgX`Cxk|(ofumPnRJYD@<);T3K0RVWX6lwqf diff --git a/mods/signs_lib/textures/signs_lib_font_15px_60.png b/mods/signs_lib/textures/signs_lib_font_15px_60.png index cd4e0fb31a98a20d259b248f0eaafc9c581481d5..c2c4e89d20f09ffe370d9344541ff0f733df792c 100644 GIT binary patch literal 301 zcmeAS@N?(olHy`uVBq!ia0vp^Y(UJOEvWU&=1clW~1FP={)XYeY#(Vo9o1a#1RfVlXl=GSD?N(lsy* xF|@EUHnB1`(>5@)GB8N}px%$7AvZrIGp!Q029dS%je!~%JYD@<);T3K0RUG*P)Yy* literal 78 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c90U|T)mze=6QBN1g5RT~N1ct`{4jhUJJUcjQ aB^cCIEl#LU^EL%4VDNPHb6Mw<&;$SvDi8wz diff --git a/mods/signs_lib/textures/signs_lib_font_15px_61.png b/mods/signs_lib/textures/signs_lib_font_15px_61.png index dc019ba5a35e63b245c441780f2f983d3049bcf5..53244187c9e2e10967350c45c4d3b0e83c187128 100644 GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI)5S4_LL z5hW>!C8<`)MX5lF!N|bKK-bVn*T6Ky(89{t*viC2+rZGuz(A@@F-29Zxv`X9> UvbE<_0W~mqy85}Sb4q9e05S1bu>b%7 literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQo5cljv*44lM{aQGj@tOF{}{K zYT#B(2|SbJAa-cgM8;5MvCSK9bQnnZO@8UlaOrLMN?vX|NuWjsPgg&ebxsLQ0Kq;S A2LJ#7 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_62.png b/mods/signs_lib/textures/signs_lib_font_15px_62.png index 285d0b2f194f5caefae94c97004e9a1358541802..f673dc81731e6b78337ac488303600c55854218a 100644 GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)$r;B5V#O1mEr@0smI4<4z|9_Kpi{Qn? zGr=?XRazPuTnYoavmX8MFb-WcFU+m$RQQY^IVCmOZz5yN?E=I(bok^it>fzi8l+m{ z8c~vxSdwa$T$Bo=7>o>z40H{RbPY^H3@xmTjjc>fwG9ld3=H-#>KCDC$jwj5OsmAL U;cU$Gb3hFYp00i_>zopr07U#-761SM delta 69 zcmX@YlsrMjUdz+PF+?IfIf0?^zs3X=#S~4G29=hCMKfJD35abLV3@u;;hBO$8-tl5 Z!@@lQ8_sXr`-}kyJYD@<);T3K0RTiA7^naM diff --git a/mods/signs_lib/textures/signs_lib_font_15px_63.png b/mods/signs_lib/textures/signs_lib_font_15px_63.png index 8781b8a84822cc6b26648cfb2ca1dbb05a3c2e3a..9eb20a98eb60b5b5324cd95f6dc87aacf04dcbf7 100644 GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI)5S4_8{~0$ zp@9BzN$%*R%MHPgnNIw?p+3>znPIge_mBLOESXyyayx80H@`G@y2da2#@KQ<&>+rfpzoWnj?z()2xwhTQy=%(P0} V8vbnQ4F+mp@O1TaS?83{1OQgjTFVdQ&MBb@0D}V@UjP6A diff --git a/mods/signs_lib/textures/signs_lib_font_15px_64.png b/mods/signs_lib/textures/signs_lib_font_15px_64.png index 16c9a286d052649014292788ad3b384259f67d05..4cb561bd5b0a38fc03059b2f3f8ece2cff1dce87 100644 GIT binary patch literal 328 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)sr;B5V#O2n0N3H_~0!+s*{I9<$r?O;8 zTSZi?s7Tu3A3~>ZEqTN>kA>mMd~JRS%ha7EQxgi$>OFK7(vRJhW8Dq8w}LI;OXk;vd$@?2>`CiT<`z@ delta 75 zcmX@XlsQ4g)xgumF+?IfIpIe?i{k@(4nge}o&!!R7|yw`XuXt?CaB+%CMG6*@of{= eLMI-^94Ce#9{-IOtNa}qfWXt$&t;ucLK6V#h8chW diff --git a/mods/signs_lib/textures/signs_lib_font_15px_65.png b/mods/signs_lib/textures/signs_lib_font_15px_65.png index 810d9c93a9f10d59264c7ec18f09d0ae69e48401..743dcebfc1bc5e3a52f6bd50d8820efba00cec63 100644 GIT binary patch literal 327 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)Mr;B5V#O1mDhI|JMIGE21{{R1})FY^s zPxeq!3LkeG8e)akP4;gm$-%&DiJG*yPzF=(rASSYFVew|5 zS*j(j5hW>!C8<`)MX5lF!N|bKK-bVn*T6Ky(89{t*viCQ+rZGuz(9MRT{Mb@-29Zx Yv`X9>q7Jt`2WnvOboFyt=akR{0Q@^$%m4rY delta 68 zcmX@klr%xbPSexHF+}2Wa>9>(Mo)nz#vKAi4cZOai4NgT4jgCQOp*(4bX<*1`6ag*VP$M=Wn!*vU}$Avpgqqn8bw2HeoAIqC2kE-hufY5H86O( L`njxgN@xNA$TC#5 literal 89 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1q!2%@P{+{IkQVO0fjv*Y;$q7IBTNFOX_XNx| nu$-YGB<#s(I>Vr2Dkp=nwC?3o0juPIY8gCT{an^LB{Ts5LWdQ~ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_67.png b/mods/signs_lib/textures/signs_lib_font_15px_67.png index d8820dd1ca5a678df710115b06b7c14f92e1969d..f67e7358074457a2907c451c6f791e6292df5470 100644 GIT binary patch literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)!r;B5V#O1lYhI|JMc$oT6{Qqwx8KkAY z%IZirBeU4E8I0vYj1df*Sc{6+GWW2i{#>m6=>PGOtA6s~R-0B&4u7Rs$<5|#8YisE zwQ;^R&_LA^*NBpo#FA92p>1GjWnggkn%^cA d4Y~O#nQ4`{HLU6W#s}2E;OXk;vd$@?2>>ogTzmik delta 71 zcmX@ZlsZAhQODE8F+}2Wa>9>(Mo)pJhW`daY6lvW4mPY5OXOPVl#!OWQE>I{f0J{> b0=O7X-1gYhK%G diff --git a/mods/signs_lib/textures/signs_lib_font_15px_68.png b/mods/signs_lib/textures/signs_lib_font_15px_68.png index 5b51d05a2c08ff6bb9441f6f6d861afacdc3292b..6fcf60022e3e656324ddaab97eb9aca1cef76a70 100644 GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h);r;B5V#O1mDj$8~1Jcp$|{*PbBKJ$fy z(l-+)X^Blivr>GVT(y@UH#}ak^-$V2#bfQ<@n7$Ed^*lkr_Wm>bfjrIvkH}&m?E%JaC$sH<3`I{D#}JO|$tge1GqC>uZ~P}c;m3KF$HtGQ zDfKg&3j}j9Wd7#ny|R9@Dp0X%iEBhjN@7W>RdP`(kYX@0Ff!0JG}1LN4KcK^GB&m{ qvD7v&v@$TLUg*k(q9HdwB{QuOw+601e|G^jFnGH9xvX|*k gKCyJcGKFAp0*}aIAngIhZYQ(tfDCm{7sn8e>&YoU&NHz3@bLVX{BP_u)8K%I z2V?0>fyWOQ_57EVkdR=Ay}%)T&RcgiP>X7bYeY#(Vo9o1a#1RfVlXl=GSD?N(lsy* xF|@EUHnuV~&^9o%GB8k@%;1fpAvZrIGp!Q0hTwBMz5_Kdc)I$ztaD0e0suYEPoDq) literal 83 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c90U|T)mze=6DNh&25RT~NgdgV_nEoH+IM(2> gCMYD$;XpmZY9F~rJ9E2l0#z}1y85}Sb4q9e0O-pWqyPW_ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_6b.png b/mods/signs_lib/textures/signs_lib_font_15px_6b.png index fc34fc50768c5f64332bb84efe1f09deec7139eb..2fc09249a35c8eb730a8cbe6ae0230578faf3795 100644 GIT binary patch literal 326 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)`r;B5V#O2=pi(Cu}9L(Ea{I9RHZJFt; zH2=vCUR9Raj2(*>9{V(N=Q|5inK=nfmt3b-X`MOk^<$s5%{KeG1*~Z`g0lS&E(2Y| zpjzS@QIe8al4_M)lnSI6j0}tnbPbJk4NOA}Ev$@cp XtHiA#_}q@~Kn)C@u6{1-oD!Mkr_Wm>bfjrIvkH}&m?E%JaC$sH<40%r%#}JO|$tge1GqC>uZ~P}c;m3KF$H8+C za%|=f=3?mh%qA+4!J-RPs#@Y2QIe8al4_M)lnSI6j0}tnbPbJk4NOA}Ev$@Nn{1`8Hp0*}aIAngIhZYQ(tfD98)7sn8Z%WEfCaxoYPFdhHI(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)?r;B5V#O1mDj$8~1Jcoro{*PbBp143g zR=@Q^UdW-PjJ76M5LeY?$pOTqYiCe>wz?Jua P8W=oX{an^LB{Ts5MjKc> delta 63 zcmdnT6gxr1QpMB7F+}2Wa>9>(#!e9?MvbEf8U&o!{!dK(ugv{-`D%fgbu0{QC!&}B SIa?{l00f?{elF{r5}E+*xEEjm diff --git a/mods/signs_lib/textures/signs_lib_font_15px_6f.png b/mods/signs_lib/textures/signs_lib_font_15px_6f.png index 921c611903b84976d778de996b43ba94fe81400d..e1d3618b5a141eeaee81f575a31e933d97c142c6 100644 GIT binary patch literal 320 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)ur;B5V#O1mDmRt-5JcplL`d=R@>%?!R z*4@M@$oJ`NL!1dWo5H-+Tyk9s@7Ct>+}r+CCVbz_yyL80XGH{o>z40H{RbPY^H3@xmTjjc?Lv<(cc3=FpN2qvLu$jwj5OsmAL;Yi@h Qdq52gp00i_>zopr05M`$RR910 delta 67 zcmX@WlsG}fR>RZ9F+}2Wa>9>(Mo)nz#vKAi4nYkG|J<*Am|vo3vU$Uej;paLKLr`& X_eL%IP<3N50}yz+`njxgN@xNAkfI(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)ur;B5V#O0;E)?5t%0!M^C{tNFr${e{> zaIVqk$vZNe^E296ycw*6xnsK0wym-6FRrt>rEL0e_fO{eOnl0@(UlW`hNzafMwFx^ zmZVxG7o`Fz1|tI_16@NST?5k)LklZoV=Gf*Z39Cq0|Vh|scR@2a`RI%(<*UmNK#vr Q1=PUc>FVdQ&MBb@0RF63umAu6 delta 70 zcmX@WlrllZLEF>CF+?IfIpIe?W2XocqeiPv3xkK#|A`?=nLqq@35abLV3@yq!!Eh~ Z0t{c)2W-gG;O}Gr0#8>zmvv4FO#ogR7v diff --git a/mods/signs_lib/textures/signs_lib_font_15px_71.png b/mods/signs_lib/textures/signs_lib_font_15px_71.png index c02171f054ed76afb4c885a083df2e77a3b9dd2f..c334de0a81821e8912ec9cc0800b31f4096db7c0 100644 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)mr;B5V#O1kthI|YL98CSk{@2gsJCCF+?IfIpIe?qo+Vq!+!%IH3sJYf;=HxIf6Yzos7A=dn4|)KFNF3 Z%1~n#uwnJDj`s{e;OXk;vd$@?2>@oQ8I%A3 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_72.png b/mods/signs_lib/textures/signs_lib_font_15px_72.png index 757b9c858acff3bcc9cbb570e88730807314f1e0..fddbb4981f952f752c6dbbbbddfddd537100caa0 100644 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^Y(UJ9>(mX8Gv5A20b9%wk_80e+rNmV;<*^SQUqry$DSvR%k(MIoe12x}$IE{)I@Sv+7TyyCIZU<0 zHKHUXu_V*r# delta 70 zcmX@glrllZLEF>CF@)oKa>9>(woW03hW{EiD+FSm*>7TS5|}Odf1=3)bLMqS%OzcY avoeHi_TD;aJwqr15O})!xvX2OC7#SED=o%X78kmL{T38tyTbY__8yH#{7!<75e}keSH$NpatrE8e#&6RDfEpM) MUHx3vIVCg!09xuwLk7@hwe6I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)nr;B5V#O36aALkp`W=Ke!5c_rh$9%y< zjT9>(#!e9?#uPr=R*4C%6Asp=T>Q_WxakiEL+Ik@rDx6` QZ)5-hPgg&ebxsLQ0J?Y=DF6Tf diff --git a/mods/signs_lib/textures/signs_lib_font_15px_76.png b/mods/signs_lib/textures/signs_lib_font_15px_76.png index dc558d3a4035c309caadb578d3c89dbe7d7bc926..f6adc12be126ef2ae3447ae3808626f7a7e67552 100644 GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPN!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR z+ueoXe|!I#{XiaPfk$L9koEv$x0Bg+K!&TQi(`ny<+T$Wxfm3AnAMN|ueX#7Gg$HZ zq@0&xiih%<^CEkuN<}Cfu4+9!tD0eJ>YqDP`@DH9Ij2rI!s~h5O|SlCX}fG+oUkmX z$H!ctfvP305hW>!C8<`)MX5lF!N|bKK-bVn*T6Ky(89{t*viyg+rZGuz~H%w-BA<` cx%nxXX_dG&Ov`Mm1ZrULboFyt=akR{0N*8DC;$Ke delta 77 zcmX@Zls!Sk-N@6$F+}2Wa>9>(;YpgTOdM)P-19}8IGWX*xYz=g2pr#XR$p>m fQKe(zq9_R_h9rZYlB06^3?Sg?>gTe~DWM4ftmYSp diff --git a/mods/signs_lib/textures/signs_lib_font_15px_78.png b/mods/signs_lib/textures/signs_lib_font_15px_78.png index 38b4be03642d99e04947130b7ce618911c66d2b0..b7cd127df852b43b3813c792441288a59cb1bc42 100644 GIT binary patch literal 326 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPNS=|KcG>n zC9V-ADTyViR>?)FK#IZ0z{o(?&`8(7G{n%t%GlV-)Lh%Z(8|EzxryCT6b-rgDVb@N WxHU}6Y^wxnVDNPHb6Mw<&;$T>++2?U literal 99 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DJ@SI#}JO|$q7ID**XOn7+Hj8 xGi*9j-@?GW=|DZ3NN+^Qf|-szTUCCsGCcART36cbxEH94!PC{xWt~$(697O58v_6U diff --git a/mods/signs_lib/textures/signs_lib_font_15px_79.png b/mods/signs_lib/textures/signs_lib_font_15px_79.png index 8859fb41f251f8fea3dbd8d37a3f754882382797..78e8cc643c47dffbd12a08907a459b6b7aa3f397 100644 GIT binary patch literal 330 zcmeAS@N?(olHy`uVBq!ia0vp^AT~b-3y>`THmwy%v7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPN*A@0_%+0M4L(L5t*JcG%s%VUu{*q5y2UG`rnpz`YLmB3O$@uwxo*0kEPHOC zJJ2}Q64!{5l*E!$tK_0oAjM#0U}T_cXryak8e(W+Wo&F^YN2glXk}m^SmURIq9Hdw aB{QuOw}u48ZxetT7(8A5T-G@yGywoZKUx_8 literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRa!2%@b9Mo+CQo5cljv*44lM{aQGj@tFF{bd9 zE&T7%B;iybb(P1-$wN(PCu{Hv`;|^B?0)bw>9;lJQ)78&qol`;+0J-=a A2mk;8 diff --git a/mods/signs_lib/textures/signs_lib_font_15px_7a.png b/mods/signs_lib/textures/signs_lib_font_15px_7a.png index c42c84a396e00f96437deb033c92a0bb1a7ac617..d327ea23d6d6264ccb66899523d4aaf44b5085e2 100644 GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^96-#^!2%?Unca2(DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fID zoxOHdr$M;XpDw9>(woU;D)*CDVQxCBw#E3AeL`wv)PS~ju>AfYMp=h!1 U=KftN=NW*&)78&qol`;+0Nh6wQ2+n{ diff --git a/mods/signs_lib/textures/signs_lib_font_15px_7b.png b/mods/signs_lib/textures/signs_lib_font_15px_7b.png index c0ee072c8c64246ca60c6bb80fd8448928c77d76..9ff2f1294324aafc32ff02ed51a2bf5eaf355d04 100644 GIT binary patch literal 321 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)V!2%?kIAl$M6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gtz=>Eal|aeZ#DBNu}K$Kjxx|M%aK?K(4; z?etPHRW9QQPHu;|*p!Axk0KXy8kPh|{#tbI+4GAoJe&70PFc+-+oe8-4`_;NiEBhj zN@7W>RdP`(kYX@0Ff!0JG}1LN4KcK^GB&X?HqtgQv@$T5xSx3riiX_$l+3hB+!`J{ S+N}W8z~JfX=d#Wzp$PyuC0L38 literal 88 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1q!2%@P{+{IkQu3ZIjv*Y^lM{aMw7V*k&g2RCOkL6o9x*K5p>@q6Ju3pJl)=;0&t;ucLK6U!X&B@H diff --git a/mods/signs_lib/textures/signs_lib_font_15px_7c.png b/mods/signs_lib/textures/signs_lib_font_15px_7c.png index 6e9949de31b6d3e743ccf3a3e7d7fea5e5e5e613..d9371406be07de9c302dd63775bfd8bf83fe32fc 100644 GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c90U|T)mzjYC(j9#r85lP9bN@+X1@ak-gWR1M z)}51i3FIgwdj$D1FjT2AFf_Ckr_Wm>bfjrIvkH}&m?E%JaC$sH<3@J|+#}JO|$tge1GqC>uZ~P}c;m3KF$CoEF zG8Cw@iXS#VV+mBHTH+c}l9E`GYL#4+3Zxi}42%qP4UKdSOhXJUtc*>pjE%Jo46O_d i%ujG=plHa=PsvQH#I3V_#m4Gf;HelF{r5}E+b=1V^S literal 67 zcmeAS@N?(olHy`uVBq!ia0vp^OhC-f2qYMu1uKUGDK1YJ#}E$L_E)V!2%?kIAl$M6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gtz>>Eal|aXmTZ$N2^piT}#MJUu-BB_;kD zA7Ysy5x_9<&i|eQy(2UJ_XOyI*NBpo#FA92 zcptHiCL*{DwnsDZ)L L)z4*}Q$iB}75Y?; literal 87 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1q!2%@P{+{IkQgWUyjv*Y^lM@&k|0i&;COoSz lnrXndQ_Wz3(Lp_ChW;~J*P0kw76DZI(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)Kr;B5V#O36aALkp`W=Ke^P&;zyz=!#Q zhf@CVi#IWLh&-+ro1x>Q%gn5td)IZ207KO;4#mcWGGBpuRZCnWN>UO_QmvAUQh^kM zk%5tcuAz~xfoX`Lg_W@h5NR72S{WF8$~Rkvq9HdwB{QuOw}xh;J}ICE22WQ%mvv4F FO#nl2Q_=tc delta 57 zcmdna6h1-4SkBYMF+}2Wa>9>(#!P({#sIyR|MFTrYAtJ~z4K#bcz36&O=7F%0|p@Q MboFyt=akR{08qOWumAu6 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00c0.png b/mods/signs_lib/textures/signs_lib_font_31px_00c0.png new file mode 100644 index 0000000000000000000000000000000000000000..6c0a93ff3283d4b826899b5b73fcfea62ea0a666 GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^qChOq!2%=~wfa>9DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIbF3V}koW1SASE3GWMQ^H_W`WRd%>`g2l|r@1=&I!unvVv&eGxb0s0S4~;XX9nO2Eg!yJZiXP^cKPgg&ebxsLQ0F29k6#xJL literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00c4.png b/mods/signs_lib/textures/signs_lib_font_31px_00c4.png new file mode 100644 index 0000000000000000000000000000000000000000..64d3840b77f3ab1e2823249a229a95a3d46e21e4 GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^qChOq!2%=~wfa>9DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI#lE7*(?dOSKbY~eU?4NKINQgR_4K1wi6{E z&OZNF{UxjW7iIg!)xTB)-J)9J8c~vxSdwa$T$Bo=7>o>z40H{RbPY^H3@xloO|1+K owG9ld3=E#K?q@{Nkei>9nO2Eg!;}d2y+92Np00i_>zopr0G%~{c>n+a literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00c6.png b/mods/signs_lib/textures/signs_lib_font_31px_00c6.png new file mode 100644 index 0000000000000000000000000000000000000000..a07d02030ba6c76c1986c23e70e5cb1451d0bd2a GIT binary patch literal 393 zcmeAS@N?(olHy`uVBq!ia0vp^3P3E+!2%?8;@R1O6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gxxF>Eak-ar$kjHy48<$JH1A!pqDo6*7Nj zE;zb_Xa4)e0!)r8qj>8MH>|T2s#@R?ANk>1GjWndsJI$sP$LvDUbW?Cg~4Ot%QtAH99JYD@<);T3K0RRnMdI$gj literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00c7.png b/mods/signs_lib/textures/signs_lib_font_31px_00c7.png new file mode 100644 index 0000000000000000000000000000000000000000..927b483e3f06488cc3c941d8df11c38a38a858d3 GIT binary patch literal 412 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8gbH+`)DQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0k5dPZ!4!i_>SPc=9zEaJc^L{l4EwFDF$) zEXm~7+^>dpTpcTGqGW4@@BLwQu0I&UqIn@{qUY(rpVw`(MG|!izUxd+n5#O6ZJG28 zmQ8_|uF3uo6g-mtYvl*~iNAv*Jl)o8d9Hfu`{fzx{=aqoW5sKE{%6f=xBQ~j!K)(l z=bpws$83SEh7Glmo#}=fe@ymPYg}*T=(2@5RLMp+<->=MKnJRpxJHzuB$lLFB^RXv zDF!10BLiJSBV7a25JL+qQxhvw3vB~KD+2>*(fOdDL}O>_45U54*zIJt9gq?1>Eak-aXLBW$N2`ff5uK3ZX%LuY&;CX z43`;1kD3TtCn)(zGBa~8Q@z3PxPFnZ%Gs=v|3N8_7_?kI@~r!i^2fh;b$gWsU%;6Q z$Fg3fUthRDfT6^M&)K}bXeH2i)e_f;l9a@fRIB8oR3OD*WME{VYiOivU>ag*VP$G+ pWniFfU literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00c9.png b/mods/signs_lib/textures/signs_lib_font_31px_00c9.png new file mode 100644 index 0000000000000000000000000000000000000000..cd3d910be6232c4bebba867eb5080fa1bed3da1a GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$I6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gq>=>Eak-aXLBW$N2`ff5uK3ZX%LukER$J z7$nW=kTnoo-qYB~deiDo!$4)YuxQ{4v}xA1k^F!8&Z~uTeas@pTQ<)6 zb+c4MgN32OgwJ_T7Iz%bY}FFih?11Vl2ohYqEsNoU}RuqplfKPYhW5;Xkle)Vr6Qn oZD43+V6Zo7$|4jEx%nxXX_dG&oUzxD18QLKboFyt=akR{0BXQr@c;k- literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00ca.png b/mods/signs_lib/textures/signs_lib_font_31px_00ca.png new file mode 100644 index 0000000000000000000000000000000000000000..a974fe57a2bb8b970b905abfc6148e3924dd9f30 GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$I6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gq?1>Eak-ar)|HZ$1VA0q5w#|Jv72r8l)0 z2;QxVvXXSlP&w4`)TGBii}|b4+Q%`8yv&bYr0!jjdVKGTeLc*_+ZX&iv&R3F?XT~0 z^1jE^fBoC_k3sF}ZUN^Pf9HejQ7v(eC`m~yNwrEYN(E93Mg~R(x`sx&2Bsl~7FMRF qRt5&z28KYg|Hc+=6b-rgDVb@NxHbH1<(UrDz~JfX=d#Wzp$PziJZWD5 literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00d3.png b/mods/signs_lib/textures/signs_lib_font_31px_00d3.png new file mode 100644 index 0000000000000000000000000000000000000000..66ad46517477aebfa244e7114939a4bd28dc19c8 GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^;y^6V!2%?g70h!3QY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC0W`2+&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfQ%YX7sn8b(@!TKOv9XbM9 ze(Q@28`&o@wJ6Rk+~c!x8#8mr)#umB5*D0~y2!gTO=(52T@BmuDdOJ^p4K1so>89u zF-b>5c`DyNU&Ux!*Z1c0LiTe!Ps-kNLH%sV*T(|Ye4BPOY_44&^u+Y#lt*Fp+Qsbu z81gEO^{@76z5%*JwZt`|BqgyV)hf9t6-Y4{85kMp8XD;un1&cySecqw8Cz-_7+M(^ iRP)YNMbVI(pOTqYiCY6#fa*-31_n=8KbLh*2~7Yn{&`0L literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00d4.png b/mods/signs_lib/textures/signs_lib_font_31px_00d4.png new file mode 100644 index 0000000000000000000000000000000000000000..548d63829cd5d66fe2396cd63679413404393295 GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^;y^6V!2%?g70h!3QY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC0W`2+&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfQ$xD7sn8b(@%pvg$^iiDEIyUZ)95{*<`XU z?x~uJj$=Yz3SV9GqqS^@^Cd1%+?<_Ve<01)I_P7FwaMi6H5&YXc+X7XmOH5NdT!hd zcXPJ67H+2&2!yW7Ow-K^>VFw=a-X2gzm0Xkxq!^40j0|)QjdTr6LkumfOiir}47Cjm ltqcq_*YBT?q9HdwB{QuOw}yyM?8-n544$rjF6*2UngAl6c6a~) literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00d6.png b/mods/signs_lib/textures/signs_lib_font_31px_00d6.png new file mode 100644 index 0000000000000000000000000000000000000000..ddfbc11ef7ecb1672a177ce2baeab8bdea6b84e9 GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^;y^6V!2%?g70h!3QY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC0W`2+&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfQ$xD7sn8b(@%p9g$^iic-#E{pK5hu^Ma0} zp=Qn;F)U6CoH!Un-m@~Wu3Qj$-!*7&pTq3!=JHjm6Ll`?zx*P4bK0H~-(|PgFKo$} zG1=cNea^zmG+}Ud{y3OYietFw}P4T3ItaIL0hdhd#94~a| zRet)r1@9DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI-rUM4%Z2r=JWI^oD`6jd~dmRk_~I)>v!e%swY-mXs&Bt=PR&a-3bxX zrRz3a>hH_D+PN+C&sMhJ9DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIU^ol==5Ay<0%bR7+eVN>UO_QmvAUQh^kM zk%5tcuAz~xfoX`Lg_WtPm7$TgfuWUw!Iig5=b&iF%}>cptHiBg=>}N^paup{S3j3^ HP6 literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00df.png b/mods/signs_lib/textures/signs_lib_font_31px_00df.png new file mode 100644 index 0000000000000000000000000000000000000000..782c68430a16e6a65fb65163c0eceb6529d820e0 GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gtDy>Eak-ar*3JN4^6J94wKK{_pqUKf(~D zurfEue}yvl>ZX=k2W_29{p1V^(Pv*ZA8$SX z)BOe0pJ)x+GD*1_pi5LsTq8#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fj>r;B5V#p$z?9Qh6?aIiG~_^*Gt`C!BD zX=-m5#)-&Ga1Du>W%}rWRe7sGw{r}u*97B~n-3;j+Km>}0-29Zxv`X9>&RJAE0cv3IboFyt=akR{0OG=VJ^%m! literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00e4.png b/mods/signs_lib/textures/signs_lib_font_31px_00e4.png new file mode 100644 index 0000000000000000000000000000000000000000..2373e02cbd15402f64dd33ef4d62ac62b942716f GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fj@r;B5V#p$z?4)Qe^a5zUF`v2cZ?g}qk zvD&)_e#~57R0Z0OPM*qe;de3%LsVa!&rRiraf{9s_U2!{trXvvSmG8fEpM)UHx3vIVCg!06g_}AOHXW literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00e6.png b/mods/signs_lib/textures/signs_lib_font_31px_00e6.png new file mode 100644 index 0000000000000000000000000000000000000000..e61364a8efbb3b0c4890801f3c61fca27c8524a4 GIT binary patch literal 411 zcmeAS@N?(olHy`uVBq!ia0vp^GC(ZP!2%@XCZuizQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0k4yPZ!4!i_>pI9Qh6?aAf!X|8HcS!>x4G zW%Au;nTN%^9XStQ%u3%f{|E2JetWn7%dQ$SD6k}KjVrpn*mBZ_iEfquWP4XkV_Ye9 zdgE~!JvQ5AAAs< zS~ju!koM(EC(eF-wQBy}nzd;=_D%dF|AfCo{9d@VeYnWd0-*a;OI#yLQW8s2t&)pU zffR$0fsui(p^>hEX^5ePm8pr9sj;?!p_PGwq|oU%C>nC}Q!>*kacju%FAe}|VDNPH Kb6Mw<&;$Ss?27vU literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00e7.png b/mods/signs_lib/textures/signs_lib_font_31px_00e7.png new file mode 100644 index 0000000000000000000000000000000000000000..069df6dd4dfd79bbb2f0a9eb6d7939181b78e18d GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fkGr;B5V#p%0~y@d`aa5xJe`yD@1?+Q~> z>8{sTrp^~<6IK;zS5$w{@9~*?>DkKPM>FTz_sw|IxbwEsh0;KUog3aeb9Q8|kn}TO zrB!FqkR$CN`ueW)v*$sYi*G9*vs&EeQC7UQ|DU|7?sqrOuGGXHImtr1O*zS{3m zD$THi;n^)++oa$x7C@({mbgZgq$HN4S|t~y0x1R~10w@nLnB=S(-1=oD^n9IQ)6ud mLn{LVNukqkP&DM`r(~v8;?|JiUmO6`z~JfX=d#Wzp$PynCVMmh literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00e8.png b/mods/signs_lib/textures/signs_lib_font_31px_00e8.png new file mode 100644 index 0000000000000000000000000000000000000000..e1ac6661100960281f87f51984ecc051440b062f GIT binary patch literal 395 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjpr;B5V#p$y_j(i6cID|L-ub(L^bL*JY zw$%1Y!3_<%5#3>PlzTVS-JbL)^GUE1YYKl+iOC5|=f*W@Ped6!iYu4cNv%y0erC#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fkGr;B5V#p$z?y!j3&aJaBP`n%po{1%r* z+m(_)bGMp5Y%Fb$OwvqVZkJ%lU=>hd=HA4_naH3}>K?_o@}+g4&sUXM_a!gOKIm#+ z%lRle^2LoUMW)*>eXNSAk@NcQ7rXJXhNG2y`mGoHT$URii#?pju;)r1Z}jtI-{tvY zpZ!m;N);KJ_x#`V73dVz64!{5l*E!$tK_0oAjM#0U}T_cXryak8e(W+WoiOM+6IPJ l1_pPweoaErkei>9nO2Eg!`c_V_kbE0JYD@<);T3K0RXMMdcptz literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00ea.png b/mods/signs_lib/textures/signs_lib_font_31px_00ea.png new file mode 100644 index 0000000000000000000000000000000000000000..e2e9494f2766ecd37d874a7bcf0c117bed7dea11 GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjhr;B5V#p$y_j(i6cI5r>oUq4fJTY{o# zN?LnmfFdgw>tXleG&9-n+*~HC58@j$c7&?Sw9XAZu&X)z{>0LTOJ5e9s97YieP-e| zW|3W69k%%{JvZ5K?ddS(v*~G{3rgNExaYfN0W~mqy85}Sb4q9e02XI_SO5S3 literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00f3.png b/mods/signs_lib/textures/signs_lib_font_31px_00f3.png new file mode 100644 index 0000000000000000000000000000000000000000..5dd54a820e2b205ee1db517e297737736a9d7ecc GIT binary patch literal 383 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gtDs>Eak-ar)|HYrX>p9L~8{e#g(``x|&% zP}XWoq>`$>1dpQ7+o(T5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gtD$>Eak-ar){cZ=nVQ4rk8Cf7kbPui~B0 z7rP@s{Fc>v6BP%aThBj4AO3Mj_A1xI(56?+d{X-pJ+w@fKHFv|F1LO=F@do=HT8Vy zzD)jCQi|C}W8_!r>2S=q3eqW!izzgTe~DWM4fjZ1cb literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00f6.png b/mods/signs_lib/textures/signs_lib_font_31px_00f6.png new file mode 100644 index 0000000000000000000000000000000000000000..854233ff76b1715f9d2d87c2ececd348ecfd7867 GIT binary patch literal 376 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gtDz>Eak-ar*2eZ@vZt4wv+f@B2UP$kbJ0 z6JN4%^(8xrx|RUB)q)RZhzl~TIP*(nC4W+V>FQ;Q4@LAW`CTsDoA}l1gmTT1rB08u z`R`?!iHFQ=-chUbTX9+Q$KH)^l&yLgpKqS6^{iKhb9Usr%ll{DWSRT+u)68&rLR^3 zEmtjZjVMV;EJ?LWE=mPb3`Pb<2D*kux(22ph89+)rdEaq+6IPJ1_sVWTehNT$jwj5 YOsmAL!APHn6R3f~)78&qol`;+04Kk6ZvX%Q literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00f9.png b/mods/signs_lib/textures/signs_lib_font_31px_00f9.png new file mode 100644 index 0000000000000000000000000000000000000000..91313cd57b3094c058476710a2ddaff04c9f094e GIT binary patch literal 362 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gvai>Eak-ar*7#vqB6494*n0|HfOgU;c6O zQg5@KRIOH|z|_S{jg=;y4ZI?{>tu>!v!`VrudQKDR!y&>QPY|HYh}*Gzb=HXsQ-O$ zzENa`rs#UN6~T<#Ru#!F{PlR@1f%)$EjBYvRhF|B2zs;zXq{?_YeY#(Vo9o1a#1Rf zVlXl=GSD?N(lsy*F|@EUHL)@^(>5@)GBEJgdg6_uAvZrIGp!Q02CMRz??4Rzopr0P&G*!vFvP literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_00fc.png b/mods/signs_lib/textures/signs_lib_font_31px_00fc.png new file mode 100644 index 0000000000000000000000000000000000000000..358fb03dbaa07cb124059de04c08ad7d068d3060 GIT binary patch literal 358 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gq?4>Eak-ar*5fN3I3~9+vd(|No0@JZ^32 znksap*;4goO5#hdd!<#8gciq-+IlbbN{L`b~yD#t^@0YM%JvDa&&??mu*NBpo#FA929DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIB{tGs5|8;LuSUAP|)@MnEBknJj#LP=pXNanD z*|9XPQab+3fn(e(mv)Aq7Hr6U_GbGRGy4hivj5F|y=p1vYI7x9rgTe~DWM4fbe4U5 literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_0105.png b/mods/signs_lib/textures/signs_lib_font_31px_0105.png new file mode 100644 index 0000000000000000000000000000000000000000..5177c0f1836cf5a079b478eb13d41e4011d480ad GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fj*r;B5V#p%0~5Aq#Q;BeM__`iOpY|mt_ zGdjD^PCg_Y9nx_+@df7(<)p%g5yf}@9?FUJFSmHYrUG^oh^FN{nG2h zML|XXhK|(Jzn3X&{~T)dsM%D#ELC9r5ha(cmkvz)BC$!kB>t>np)F&+Z~5V0S5~m< zuio&I`>3q0ZTH_R*+7@5mbgZgq$HN4S|t~y0x1R~10w@nLnB=S(-1=oD^n9IV-sxy mLn{LVsat=ZqG-s?PsvQH#H}H_-6ayJfx*+&&t;ucLK6VMYk`LV literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_0106.png b/mods/signs_lib/textures/signs_lib_font_31px_0106.png new file mode 100644 index 0000000000000000000000000000000000000000..6a8bd82eedbb0cd43a5d3de4bb3af84d9a4745b9 GIT binary patch literal 398 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8gbH+`)DQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fkEr;B5V#p%1jj(i6cII_?F`=44Cpv>WS zCs0oyUvXJ5Nslq8XA{AjGN=jXAt*)A>{GsyerkYMk)c0C#qo+CR zsm|QMWag* vVP$G!Wo)5sU}$AvaJOpOL=+9V`6-!cmAEymQPbP0l+XkK^E`j| literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_0107.png b/mods/signs_lib/textures/signs_lib_font_31px_0107.png new file mode 100644 index 0000000000000000000000000000000000000000..0dd9aa920951cea2f12634d81a2605dd9cf28a39 GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fkGr;B5V#p%719Qh6?aIj48{r}&{HbPrt z%9702u1(Dcnj8Y>i0uyjrOUN}$>|6)<0dBQP0S5fWH&NRTjnk`|CLwDeA{C(68D}p z$~|Y^QJ?cVfN@4f;+vEn^H+9L-pQ)ymVY}Lxm)zitsbSlx1LKpmfZPO>}*5o>#o|L zQM>L>VD9~eNQ)WG2B>gTe~DWM4fIV63< literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_0118.png b/mods/signs_lib/textures/signs_lib_font_31px_0118.png new file mode 100644 index 0000000000000000000000000000000000000000..5893e5556e63daad678073385b010ae8eb896c7e GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$I6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gq?1>Eak-ar)|%gIo*>9M0x1|JPT}RkBJ^ z@_735;f*PRP8m9Fp$)tYM}*x(J^dTiAD^6g^Qq@l@Bi~2FFk$5z6iRz`WBr48n0U78c~vxSdwa$T$Bo=7>o>z40H{RbPY^H3@xlo sO{`1|v<(cc3=EzGTzrqBAvZrIGp!Q0hN--n!9WcRp00i_>zopr09rL@K>z>% literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_0119.png b/mods/signs_lib/textures/signs_lib_font_31px_0119.png new file mode 100644 index 0000000000000000000000000000000000000000..57268fc3c87fa37e7418376870bf5a0d0dda0b8d GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fj*r;B5V#p$~tj(i6cI2Nb;|6f#Iz$U7hGU1dW>WJJgz9 zta{?Vi+f)h=i1LU&$xA#on((qzQb9@yuw>Hj$^fp9na5|f@gb*LjB*rJ7s!Fb=n%< zzvl~>T+(#S*FE?e26TyPiEBhjN@7W>RdP`(kYX@0Ff!0JG}1LN4KcK^GBvR>Hq|yT mv@$T*v-W!+iiX_$l+3hB+#1e)@P7-`z~JfX=d#Wzp$PzkMSSZ3 literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_0141.png b/mods/signs_lib/textures/signs_lib_font_31px_0141.png new file mode 100644 index 0000000000000000000000000000000000000000..db90e716bf6329ffe80a751ad387c233461b37ac GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$I6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gq?0>Eak-ar)|%gIos;IGlxF{{O$pdP>~0 z809m)mBDfnLK6!-Ql+jj@-Y;gYcsF1zw$$9M-0ceHwzfj0z4mgEPh?%ciG0}@`hRc zQ}XVZta*DVJoV%S>#)!4{0}NWF!&wjcfJ%j(HUrwYKdz^NlIc#s#S7PDv)9@GB7gG zH8j#SFby%Zurf8VGBMCLFtjo-coJ~&J&K0h{FKbJO57Tz@@57DH86O(`njxgN@xNA DTTX1P literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_0142.png b/mods/signs_lib/textures/signs_lib_font_31px_0142.png new file mode 100644 index 0000000000000000000000000000000000000000..95b92ed6f1b5ce4999057408e55ee032ba294d38 GIT binary patch literal 326 zcmeAS@N?(olHy`uVBq!ia0vp^oIotk!2%@bi|fk*DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fImmI1+l5uPP3nsxIT-H@DX1N26 zQY~?fC`m~yNwrEYN(E93Mg~R(x`sx&2Bsl~7FMPvR>o%928LD!2EDFt&!A|?%}>cp XtHiD0k3?tzPy>UftDnm{r-UW|nNwWT literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_015a.png b/mods/signs_lib/textures/signs_lib_font_31px_015a.png new file mode 100644 index 0000000000000000000000000000000000000000..c934e8fb23510a25da5692d693d19f939b97b549 GIT binary patch literal 415 zcmeAS@N?(olHy`uVBq!ia0vp^qChOq!2%=~wfa>9DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI6=xo;W%?d8o3} z%=>HF6~xRfSFFCP@$R~wH&wyYTo1T^S(7c^$rECK@TjUD!}61tTpt|Kw&*Z>yyRp> zY{0XUMLTNP^==hzYiV4yb5iJjrpKnI51IG>_J6@Vt=3N8WftRQpc_?7Tq8mAm4U(Cs%aBZH00)|WTsW(*04rhPZy|x N!PC{xWt~$(696lgikbib literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_015b.png b/mods/signs_lib/textures/signs_lib_font_31px_015b.png new file mode 100644 index 0000000000000000000000000000000000000000..c660b6e6375d089fe389fc40462fc105465bc3a2 GIT binary patch literal 395 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjpr;B5V#p$z?4)PsP;Be;t_`iOptQm90 z#J6VpQZ<pZj7HUO_QmvAUQh^kMk%5tcuAz~xfoX`Lg_Ws^ rm9eq5fuWUw!Ts7p*(e%v^HVa@DsgLAr%-hrsDZ)L)z4*}Q$iB}^C5if literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_0179.png b/mods/signs_lib/textures/signs_lib_font_31px_0179.png new file mode 100644 index 0000000000000000000000000000000000000000..5521fc2fc6a5270869e437dc63aa6d0f59f7170b GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv~!2%@L&$hDxQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSdF$RMU9 zZ+91l|Ly%}_5*pG1s;*bK-vS0-A-oP0U1@EE{-7g|`Nv1FT>%LFDHGiY< zg!9Vgr@p8I9nPRy;u=wsl30>zm0Xkxq!^40j0|)QjdTr6LkumfOiiqe&9w~-tqcsb hjh**0kCKDVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIHSETU{XULD%dA$ZpGg*0Earbg?rDXoX6 zFYdcLy{Rf@Sw!?UIs2w^o{0YCi`RB7nVUftDnm{r-UW|GOBQ` literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_017b.png b/mods/signs_lib/textures/signs_lib_font_31px_017b.png new file mode 100644 index 0000000000000000000000000000000000000000..b15f04d50d70165b982bd78f4b47570f384e3a75 GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv~!2%@L&$hDxQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSdF$RMU9 zZ+91l|Ly%}_5*pG1s;*bK-vS0-A-oP0U70n!^X9Bk4e9R!BG*B6z7O}?}K<}n8o-^tgDbHZ%cdNzW@8gTk|&xPxeqW z*F4g<1Ly?R64!{5l*E!$tK_0oAjM#0U}T_cXryak8e(W+Wolw&Y^H5sXk}o~>-zQ# eiiX_$l+3hB+#3E!gcblbFnGH9xvX**0kCKDVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIiiX_$l+3hB+!`$RXa56gVDNPH Kb6Mw<&;$T^IB$yp literal 0 HcmV?d00001 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_21.png b/mods/signs_lib/textures/signs_lib_font_31px_21.png index d3b9f61865255cb639701a33061a8079d970a729..93ffb34e2cd1035d8447512d98a5351053a22be7 100644 GIT binary patch literal 307 zcmeAS@N?(olHy`uVBq!ia0vp^96&73!2%=;uDU1#DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIzm0Xkxq!^40j0|)Q zjdTr6Lkumfj7_YJO|=aStqcr8By5FHH00)|WTsW()}ZRzx(=v;!PC{xWt~$(697M< BPjdhO literal 89 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol}!2%@nWJ)FgDFsg##}J9j$q5b(|9P4lKFgn5 m!pP1TXc}Pn)CwDVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI5evNgNYq(X*6Wg$f;Jee5y_p{lmnFiVdb*h%QMwFx^mZVxG7o`Fz1|tI_ z16@NST?5k)LklZo6DwmgZ39Cq1B28L>isAha`RI%(<*Um5Lr9l7^s24)78&qol`;+ E0H+{Pc>n+a literal 91 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eZ!2%>J?VdyeDJ4%A#}JM4$q5aO{}VbM@CJ4M p_c-)_V#N=Y4Tl3e134vF7z*T#?!05WdjqJN!PC{xWt~$(6965J8{Yr` diff --git a/mods/signs_lib/textures/signs_lib_font_31px_23.png b/mods/signs_lib/textures/signs_lib_font_31px_23.png index eded52033509c2a67bf9cc8df5e2a1c91c4fd53a..49e9ac97f74d64b41494f52b5ae7cf0c2828a5a7 100644 GIT binary patch literal 351 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjir;B5V#p$z?4stOla5%^Q|9}3qNN13w zcmA#u8ZI}w0f_|+yzrT8TX!2Y`U;*!{Wu7y$hyaeRa0Ct@Qbck5|u5 z2=4qd!=dY+xplhD`rn;Pne0Ey8S}ZeUjW*nTH+c}l9E`GYL#4+3Zxi}42%qP4UKdS zOhXJUtc*>pj106546O_dPIU=sqiD#@PsvQH#I0fX^;Oe>8W=oX{an^LB{Ts54%=;; literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv~!2%@L&$hDxQa+w8jv*GOlM{aUi?}>>U^MCv zN{!e$VNFkCP3nKoFgFRFIYx)%4g`Fg&vr_}V5;Eb#>ODG9`=960zR26Q~oXwkj&He h40cOeCm(Z)VVj)KA;}593V`M^c)I$ztaD0e0szXFD+2%k diff --git a/mods/signs_lib/textures/signs_lib_font_31px_24.png b/mods/signs_lib/textures/signs_lib_font_31px_24.png index 9225f94a97bd7206cedc5ed0aef29891c53fa1e1..0b027ed63e25e94186b64e20dd768c150acf83b4 100644 GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gxxI>Eak-aeC|IK)wb84rk4e|H6;)&q>x! zc3WJ(iM_;^-SB4JE_V(ii8w!}%O?H}7ggefv}Y+Nhd%CK&oEP{<-488s=ChQea%uzTu-)NAt^+n#AhckvkIdb zR!?k~JpRLicXo={see_^&}FJ6t`Q|Ei6yC4$wjF^iowXh$UxW7 zNY}tL#L&XZ*u=`nK-<93%D~`MmykA!hTQy=%(P0}8g^e_H65sd!PC{xWt~$(69DGZ BeD(kU literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQt6&9jv*GO*G@jj#h}39{QbXu z?)HG&IgY|sM^@)(38*q`nR|fy(p7<_y*^fY9b1A_mf!AwT3)Ln!SuHKSJua;Y@V-s zm_*8#U*TcdCCSqg^}XkURN|@BNw-UPm7koj!l_QqR66k^Ya~O4)R*nNp7ViLGI+ZB KxvX`nVtcFv3dptwysc*$^mDLyCVq^JtXywG~zqq(cAIw}LX|#mBYw?U(OVsP44_}N` zYVm!$wJP{Tzj3RQ%NNc58?sk+Dtc&nCVY@e{pM4tmZ5iW)-T&NZ^NI-dN0U2bS$w% z<@_UyfWDf|yoLqsKe&w+%^4rEzqH=C9V-A zDTyViR>?)FK#IZ0z{o(?&`8(7G{n%t%Gkup$WYtB(8|Cd=da{^6b-rgDVb@NxHZTw SSf~utz~JfX=d#Wzp$Py5TZ=~k literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^(m*WF!2%@r_|%;MQZ=3~jv*GO-%i;mbU=Z_`SX8! z-}bT(T%H2fVdC!}Fbc7DT(mp-&UMbDR7Zz^D-m&e*PAw;SjF@(?EZ~}83}uK2lrTe zsqSQu5h^;Iyzk>lsYSsDvkUvT@2fPv{`=0Usmys#vJy6SCpNwO?-qT?K(pb`$(TIb h-5(y#`Li)SUQ?@R)q#|q`+@FY@O1TaS?83{1OPICOLPDL diff --git a/mods/signs_lib/textures/signs_lib_font_31px_26.png b/mods/signs_lib/textures/signs_lib_font_31px_26.png index b7a977867030111455ecdd35ca086783acb0744e..06b7933287f1b5c034e8ac135e2b8e73edf34c78 100644 GIT binary patch literal 406 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8gbH+`)DQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fkIr;B5V#p$b44)PsP;BapJ@qhmrJ>>*P zlR~*|mz(%Az0I;NZIi#}o_|P|+v%6vLEg${wr9LC3nRQuCkIGrq`y$l^hvmC<)?Ys z!LhYx#a-Q__h-+3vy-8|(X^;Ft9c&(tX#?D-C>f+pDg@rV!6B+n_ssu=d4Sv$?xzD zyLi)PUcavW>YKaHYW)46Ud&&|VCG|L8Mg9i5723?)FK#IZ0z{o(? z&`8(7G{n%t%Gkup$Vl73(8|CdR+O0uMMG|WN@iLmZVfsfyY~S#FnGH9xvX9sZ387#}JFtPp>%g9Z=wK34B-o zvM^H6?uu0S+SRkBb2MM{xm;zZs-1X5(CyFMwEDhVqPrfw-FB`xlzZZ%gq=axb8I!2 zh(v2_?AFapX%3PyIr3`@-*xw&QJU8~xL0|^vzo+De_9Bf!2%>3@5!$NQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)jr;B5V#O36aALkobW=KeMJl|ws@F%^+ zK=S|O71M?Elv(rSzQr)u&1JED5L)vPs6(~HHKHUXu_VgTe~DWM4fCsr5m diff --git a/mods/signs_lib/textures/signs_lib_font_31px_28.png b/mods/signs_lib/textures/signs_lib_font_31px_28.png index 8641fe1c8b3633bc6df1a9f96b973a5c5c6cb5e2..203eadb6a1e1f38a411028c1dcb85f47e72c7508 100644 GIT binary patch literal 333 zcmeAS@N?(olHy`uVBq!ia0vp^oIotk!2%@bi|fk*DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIvE zUvdFXJ*rsy|0cEVQS?#L?%9(ivt3eLn%) zMDghvKoeC5V(c7YG`8GRW%ITRbBIU*Y-T&QmmV6Jp}!Q|}FA$9MV rmP^i!|HpM(gtq=KgTe~DWM4ftBWAV diff --git a/mods/signs_lib/textures/signs_lib_font_31px_29.png b/mods/signs_lib/textures/signs_lib_font_31px_29.png index 044366c1864fe7d6df8fff8004890233cdf7ec0a..dd69f61569ba4e3ffb80a38a122dc916dc81872f 100644 GIT binary patch literal 331 zcmeAS@N?(olHy`uVBq!ia0vp^+(0bP!2%>_Kl-l#q*&4&eH|GXHuiJ>Nn{1`8H8W<+9_WZvnDR9-` zUA>zUPoh(Xdsu(8soB>bA(ORw@~lkH%6&Ox;D4B@u_|rx>>hv9Wl=$w6&R+>6}FsZ zxKR&io@$9}L`h0wNvc(HQ7VvPFfuSQ&^0vDH82e^w6HQZu`)8&HZZg@F!-Isu?gTe~DWM4fchg;1 literal 114 zcmeAS@N?(olHy`uVBq!ia0vp^oIotk!2%@bi|fk*DN9cm#}JK)$q5Y&|2+iwCbaxZ z=13BE5!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR z+ueoXe|!I#{XiaPfk$L9koEv$x0Bg+Kt_b8i(`n!`L_Y5`3@-XXr2A{fBMbF4OJfm zh08B@2k2Z2w58)nMQNH!6(_{n|CEppmLt;E~GI=2&ZmwJ73 zS~aO{QR}{z*|YawT7QW`%;Ycl`< literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^+(0bP!2%>_Kl-l#r0hIh978nDCnx;q7gdtr;c?+K zUcjMT!NXIK$R;Ai`{%e?bBgLFff$KcT|4Iq7Aw+}tGUijw>Xp%Qt^S4nIX|o{ClkR Rz8auO44$rjF6*2UngD+rAV&ZI diff --git a/mods/signs_lib/textures/signs_lib_font_31px_2b.png b/mods/signs_lib/textures/signs_lib_font_31px_2b.png index 1c5be462320879719d5b440b0b09e8f56a4a3d44..b7a6d165b10fbd58f94d08de287a052ffbcb1a40 100644 GIT binary patch literal 321 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gtz=>Eak-aXLBW$9V?<1Hmw(7SW9hivAlL z834gQ^}|aJuIQNf(Ef`3=AD5-n$+wq*rl^*(Ka`RI%(<*Um@So8K Q^dmdKI;Vst02ZiO82|tP literal 89 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQVO0fjv*GOlM{aU3-oCzI&t#w nK>0B53Yr)^Yod44}ZL80h@B@udEpd$~Nl7e8 zwMs5Z1yT$~21W+DhDN#urXhwFR>me)MyA>ZhE@g!Gd9`wplHa=PsvQH#I51w`&OX8 P7#KWV{an^LB{Ts5LWWl{ literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol}!2%@nWJ)FgDMe2g#}J9|9N_r`M#s;?U&#K*bE6u6{1-oD!M^Pm?8(HSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfD9E+7sn8d^T{bc&Nnd5kdSa=<>cCAVDKm1 zMKtM;|H7F)$`)1((YIM_-NYSR-h*s7(8A5T-G@yGywoD15Nh; delta 50 zcmZ3@6fi+WN8HoJF+}5ha>9>(*1il!9|z@w7bmzkGO)hkVE-b-BgX&)p00i_>zopr E0JMA%PXGV_ diff --git a/mods/signs_lib/textures/signs_lib_font_31px_2e.png b/mods/signs_lib/textures/signs_lib_font_31px_2e.png index 860df5dba34f091f3cd18e10520351e96c078096..59529d4004e0be923fd26f1c01c593c6aeeac5aa 100644 GIT binary patch literal 301 zcmeAS@N?(olHy`uVBq!ia0vp^96&73!2%=;uDU1#DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI< zew^ocXz*`&-@=}fP7MZ;-7K~olk3(3b*PrOMwFx^mZVxG7o`Fz1|tI_16@NST?5k) vLklZo6DuP#Z39Cq1A~=O>Vha5a`RI%(<*UmxWPUjWCMeztDnm{r-UW|m=R9r literal 78 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol}!2%@nWJ)FgDN#=s#}J9j$q7IDS=_bQ8BaV3 bxNOO=)oMY4Z1{&bpaKR@S3j3^P6 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_2f.png b/mods/signs_lib/textures/signs_lib_font_31px_2f.png index 91b0e1c75205d71bc5f7bdeae22c67d321a2aacc..fa4baf3013d803ef20b2ed707ded4d2009781eda 100644 GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^AhtXQ3y>^Pm?8(HSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfDBJh7sn8d^J^!0@-ZlIFh@W7zdxq`n(m~8 ze4mDg42n6NGMDxUFgA3F#vU)8P*uw3>*yl+rFZFLa}UWmruME=4u%Gc8U9sty}|h8 z3$N{!KfC4t4OK01jVMV;EJ?LWE=mPb3`Pb<2D*kux(22ph89-FCRRpf+6IPJ1_mpm g)CEyACdM3a)WXJB=e4PITWA6tA5LMB%*)UYy=@PGb7>{aYC}$vu>>NxdBn)X(7Q>gTe~ HDWM4f^=l%5 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_30.png b/mods/signs_lib/textures/signs_lib_font_31px_30.png index c34aaf878177f10cfebdf46343ee3cd8a35bf52d..21dbecde32a1247d9f52a483432ceecbe8f24441 100644 GIT binary patch literal 371 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjsr;B5V#p$b)4)PsP;Bd~|{QrMy*$lr6 zQu^E{Z5r)1u58^YE9QS7{Di2q`+5P9MWtj}gexnBu> z_U^wxN5;PR8UHh$8(qE2v)$t*XFtm^H%7%7mDA4THI|y5;5~j($<*cIUZArXR7+eV zN>UO_QmvAUQh^kMk%5tcuAz~xfoX`Lg_W_1m7$5YfuWUw!3HnG+b9}x^HVa@DsgK# TDBhV4)WG2B>gTe~DWM4fcA|7% literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^0zfR!!2%>**0kD#C{Gv15RLQ62|xT9lq575oEg;| z0vluxh(2JG;JUEZ+4!%$7<+IiW7LP92v!rGtfq^;E=`Ivo^*I@aZ#yOGCHRa#=xN2 W&ChVSV*V4Lc?_PeelF{r5}E)k=OR)7 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_31.png b/mods/signs_lib/textures/signs_lib_font_31px_31.png index 091e6c9b94850ed4925e3c4a4ed36792399cb31e..cdaae717e749dc73f51882d9b4798d428035dbdf 100644 GIT binary patch literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^0zfR!!2%>**0kCKDVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI#G8i> z0gMbEdU+lBeCH$rO;#;&jVMV;EJ?LWE=mPb3`Pb<2D*kux(22ph89-FCRTmdKI;Vst0Kr&b(*OVf literal 99 zcmeAS@N?(olHy`uVBq!ia0vp^+(0bP!2%>_Kl-l#q_jL;978nDCnx;q7ZpdD44$rjF6*2UngFQb9UA}u diff --git a/mods/signs_lib/textures/signs_lib_font_31px_32.png b/mods/signs_lib/textures/signs_lib_font_31px_32.png index e43a58f15df505899dc97efcc02da5ccaffec1df..076d92c7cba8d430c2dfe42198ad7f2865af33fa 100644 GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fkCr;B5V#p$z?z4;C(aJbCn{J!5PRw8PJ zg6HE!>q6xA3mTS~bjucSO-x_?f$ffI(lqI_g2}u$_NLTb?ELrQll7GBmL7*aDjvJXzvU@nJfooI z>hg_06X*oh64!{5l*E!$tK_0oAjM#0U}T_cXryak8e(W+Wo%+)XsT^sXk}m^W^0v? dq9HdwB{QuOw}$kDrprJL44$rjF6*2UngBS$bK?L2 delta 119 zcmV--0Eqwo0+a!eByd|vL_t(Ijn$G#3IHGs1O5M}#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjxr;B5V#p$b)toaTYa5x)2`WL>;+1?>* z){0k`d^qF|S~TwP={wi3UZDGepy4E^H$}yjN4794Wv_X!WA#8us&hvFqpP>vX8ibl zZP%)E5uHB{`Dx?`9yjg#J6(b!e}Y!!*!^(&7$#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjwr;B5V#p%719Jv|{1enb){jax_TcVNo zC@Ayx<)AiCK1YMD@{j{MOP=a4ieIqh&Vm1WHx2W4$}DgV>EL0~eI#>|Dau8>R>AIx zC`;6n+k%Y=t!HM6T-j5-W#*M@dfH9f6xAPm6SJHopY8y(O|`@|q9i4;B-JXpC>2OC z7#SED=o%X78kmL{T38vISQ(mW8yH#{7^q)W_=KV%H$NpatrE9}u#OpiKn)C@u6{1- HoD!M<-^^?K delta 101 zcmV-r0Gj{l0)hdMBwk5LL_t(I%gxg<3IH$&L(zZ#OQ%~qNQjhD)J-2w5fr-)cHI*a z;Q=9$vj{|<&?WMOM9Rn!c|w<{bH&w9BAYuK%vmJ9+Gw%>Z`Dt~Ed;ZZ00000NkvXX Hu0mjf2Tv$y diff --git a/mods/signs_lib/textures/signs_lib_font_31px_35.png b/mods/signs_lib/textures/signs_lib_font_31px_35.png index 4297837c4f9b350b336a1025a9573f3d294f0e01..a3190c7ca6b5d39503cf93b3edebc12ba088e4af 100644 GIT binary patch literal 376 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjHq(yZyuQ4 zl6JjYAsRi^TCNu=wA#!a8R70W~mqy85}Sb4q9e0MIaW%m4rY literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^0zfR!!2%>**0kCKDIZT4#}JK)$q7IF8Jsv|8vbz= zSWRl2$0e~rL+t_k9xe%wFox}-uAF7lgV#K;_vE@Tw$(JUmOjs2-$u^DQ h|M8FpZa!94hDvAo_r792ra*HUJYD@<);T3K0RZiCCiegU diff --git a/mods/signs_lib/textures/signs_lib_font_31px_36.png b/mods/signs_lib/textures/signs_lib_font_31px_36.png index 71c6e4b65f1cd82c8621055942b9420b5e5459b7..8d312a673893bf25b42532625ddda05ca4c77c2d 100644 GIT binary patch literal 395 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjpr;B5V#p$cTj(i6cIHEiM|2MKW*lICB z^>*q!0j{;Yk1i~>2x8pVWU@~qt!JTNtlo5652FKTPTu02E5asp?7PyO@Lu&J8;@As z`*BEkuD<2OgWFuL-C1O3AHJjJyX!nBwyngDbH_d&T8|6+n z{SVx@yFcy=`w7lhZF<(5p2;r&x<|FdHKHUXu_V9nO2Eg!-xNqL7~Oq>FVdQ&MBb@09@OExBvhE literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^0zfR!!2%>**0kCKsYp*3#}JK)XD1u-F(_~_|NOta zu%L0v(!@)t<8 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_37.png b/mods/signs_lib/textures/signs_lib_font_31px_37.png index c73dc109a6ada0e151b0aacfa31a8efe2578c1e8..40a4e5378b5af38320058c3d8d2c7abb7d6ab244 100644 GIT binary patch literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fkBr;B5V#p$z?J^2_EIG8m*{*OO4xsX$o zKjVqb%PA}hY6mk|QWRZ}Y+z2vRN9eUZtI!J(4(Nd;q4_Zjq?j)(@s9TB$cYu!5(A5 z7C%`pX;%C5-u^gU_LT*H#q8%f2R{Q^p<3b^QIe8al4_M)lnSI6j0}tnbPbJk4NOA} vEv$@9tPIVy4GgUe3>p_{yP;^v%}>cptHiD0!~e;k0ATQR^>bP0l+XkKFwkV` delta 93 zcmcb|R6Ri@+{x3$F~s8Z)ysxl3FVdQ&MBb@0Ikp?P5=M^ diff --git a/mods/signs_lib/textures/signs_lib_font_31px_38.png b/mods/signs_lib/textures/signs_lib_font_31px_38.png index 40282983dd72d496a7d109f930853582ddb58e00..d46d4c90becac28c4febf4fef6e1f76a6b22b09e 100644 GIT binary patch literal 376 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjhTSTLf$Qh&-JtY?WA0VgZo%CyrRFiB>BSvk$Gi96miiTcinljZ&(Kriq$SXD z)e_f;l9a@fRIB8oR3OD*WME{VYiOivU>ag*VP$M$WoV&oU}$AvQ2r`bP0l+XkKmxy!h literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&gRHUbiV~EA+tCJ1+7!){|fBs)y zxOCYAUaOAo3Ei23NzO_>iJ$qqllI8R+!8pHEhNIt^`-!Bn vtNy~kV5`%AS3Ec=qwu3VW9f&YI#ylIN7k1oGnDQGTEgJz>gTe~DWM4fVv;hR diff --git a/mods/signs_lib/textures/signs_lib_font_31px_39.png b/mods/signs_lib/textures/signs_lib_font_31px_39.png index a240984b4b4409f0ae0a836b7e23da938ea6fc89..0c02600030d07fb3026a9b9fdad01d1886f37a42 100644 GIT binary patch literal 392 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fj>r;B5V#p$a-j(i6cI5xNZub(N~v)Fx7ro!c8exc#g)-|6!tR`2**0kCKsc=sh#}JM4XD4qIVlZHF{`=qm z^|KWM%gn@{-xHYCrJ;F$7Q+Nl1|8-sRffvOYkzpGuDdgsc3u-HTcNoiL#FX|C8J1o s5W}(+^=H-iPrKwgS$F(>@wkRt#=wW4!RUC)TA&pSp00i_>zopr0L?-#4*&oF diff --git a/mods/signs_lib/textures/signs_lib_font_31px_3a.png b/mods/signs_lib/textures/signs_lib_font_31px_3a.png index a3d967c85fcf89012957803e8eca82be813e1cf6..a0fc2de08df6f3951e32943f07e77294c713043d 100644 GIT binary patch literal 300 zcmeAS@N?(olHy`uVBq!ia0vp^96&73!2%=;uDU1#DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI5*=@If?7aojP~sXpjLfwS46O_d_;q!bqG-s?PsvQH#I2#OV2UJA1B0ilpUXO@geCwU*iXv< literal 78 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol}!2%@nWJ)FgDN#=s#}J9j$q7IDSu#&LG8kDZ bAI)Xhb-cY&PH0&rPyvIdtDnm{r-UW|Ubhnh diff --git a/mods/signs_lib/textures/signs_lib_font_31px_3b.png b/mods/signs_lib/textures/signs_lib_font_31px_3b.png index becc877da3c34482179b58ef0b250f76e4eb6690..ae42100448690b7de2c5c32a3ebd7263770ec308 100644 GIT binary patch literal 320 zcmeAS@N?(olHy`uVBq!ia0vp^96&73!2%=;uDU1#DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIFVdQ&MBb@0DWdwjQ{`u literal 93 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol}!2%@nWJ)FgDHTr_#}J9j$q7IDSu#&LG8kDl r-_PA);c+VA%zqw_Gygf*1eh55u2;6t)4JgVRL|h)>gTe~DWM4f_O=>s diff --git a/mods/signs_lib/textures/signs_lib_font_31px_3c.png b/mods/signs_lib/textures/signs_lib_font_31px_3c.png index 0d3d291c1a93a89b99e1953bd1c96bb5ce7f5790..9ffe234d005b718e49e6eb814772d27770df11d5 100644 GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gvaf>Eak-ar)_HZ@vQx9Ik=u3jaqhV-{{c zvHbEfKTF0Qf0w1Ui`C^_yH2b*{rU`F%L|?E1$?dtN=}`UzWU%+=aY@@{(Mi4t34Lm zZN14UT)*Ep&F$mIUWLMAx~`K~EGS#8r1eJo<9q$DQnnxXm0YJi+ZP42RJFu4q9i4; zB-JXpC>2OC7#SED=o%X78kmL{T38vISQ%Mp8yH#{82n6)@j=m$o1c=IR*73fhsBc* PKn)C@u6{1-oD!M<5-W4A literal 130 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQl6eJjv*Gk$q7IF1^ToUojExk zgfuZkOkKcaqI!d2lF%E5S1~aR>(grTlpk0pO-bo7$&9kHM~E(Z3WO!22WQ%mvv4FO#q_6C%6Cr diff --git a/mods/signs_lib/textures/signs_lib_font_31px_3d.png b/mods/signs_lib/textures/signs_lib_font_31px_3d.png index 952ffca2d179b864f4a30b6d41b8e0ae921648f6..3b2f9f36b5400ea7215db05526439eaba6d73fbe 100644 GIT binary patch literal 306 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gv~z>Eak-aXLBW$9V?<1Hmw(RUM6ujjfFj z?Un0Pd;YIXmwmjUZ}-ImGS9jgn2)gAW*_<=1=OZm;u=wsl30>zm0Xkxq!^40j0|)Q zjdTr6Lkumfj7_YJEVK;_tqcr)rpEZ7Xvob^$xN%nt)au>$p@eY22WQ%mvv4FO#pvZ BRE_`u literal 87 zcmeAS@N?(olHy`uVBq!ia0vp^0zfR!!2%>**0kCKDLGFU#}JM4$q7IF8Tzyq%wqb} lV8`WlIPpWv;RD(X4EZ<9W-Rng6a=bd@O1TaS?83{1OQz57y1AI diff --git a/mods/signs_lib/textures/signs_lib_font_31px_3e.png b/mods/signs_lib/textures/signs_lib_font_31px_3e.png index 4367ba0c177807f59601f4adc521f6c2ef8d6803..e7ba33a1ddb1e6ee59b5c75d497ac05f77aa434b 100644 GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gvaf>Eak-ar*9MYrX>p9LxbRh5xm82Wtu0 z#aV@3U(5ct(8Q%n0H63g5O~5veSfth%V?e~Zuf z+m%H#o_sFse0BY2jm)GgM{3o-PKs@0cl;yq=dbtPmb{WgCD&&+@45jkRV{IiC`m~y zNwrEYN(E93Mg~R(x`sx&2Bsl~7FNb4Rz{ZE28LD!2Ju4SKTtH}=BH$)RpQp5=l|XX PsDZ)L)z4*}Q$iB}s!wwY literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQVyOjjv*GOlM{aU3-oCnT*$)G z5zrJbDW%}VY1XI(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSdF$RMU9 zZ+91l|Ly%}_5*pG1s;*bK-vS0-A-oP0U0@-E{-7kB4oWdS!hkC}$C^t(*a&bZ%v#mQsKLd8R6%&o5{_Z9?}?4J;G zwB2gO(SV@WYkZ3?drp6L;i2#Sg|k`{zI;Dd^_yk3?vwL3n0s@S9Jfz%Jp{B@wZt`| zBqgyV)hf9t6-Y4{85kMp8XD;un1&cySQ(pG8Chx@7+M(^#0!Q0K+%w!pOTqYiCcr7 S|9cmp1_n=8KbLh*2~7Z>op#j# literal 143 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQemDhjv*GkM=u=YVo=~<4*36n z`E}J5CB{lC%ev%DOr6hH8MN9|s~vRERIEP|_Kq(qR-m9sn@Q;QM1w#!jZOvC1eZ4* rf*MNYB`zW7Jbb68FG+iGe+lEOhly+VCbI_uZD8bP0l+XkKQhP3I diff --git a/mods/signs_lib/textures/signs_lib_font_31px_40.png b/mods/signs_lib/textures/signs_lib_font_31px_40.png index 5003e81db7213f1a9806a0601ddf3cbe5b3f41f6..f03aeff7121c2bfd7380ca79c2d4f6b3e5b6fb5c 100644 GIT binary patch literal 462 zcmeAS@N?(olHy`uVBq!ia0vp^vOp})!2%>V2J!U+DVB6cUq>LXpZiZDE0E7v9OUlA zua@a2CEqi4B`cIb_Lo1C76=D z-CY>|xA&jf59DzcctjQhX%8@VJDF_G9G3R4T&qP1izu@&3g^qF+zkrKJHr#S-lF~VLv+A-?2yelUgpZ~U_RMG9 zbk(#kW(e|beDpQuZXestUms$17afTCxw(Azj;5H+3eUDY7Q1^SWv`^F7+>!V#q4J# zyC*IBcGt$b#OL<8*C$up;Y;OT?XbskvRG6y$Lu2(7pJb@<#EHmf8HP4-m3HW)G!++<$V-1!_(Vu+!@j{@NR7+eVN>UO_QmvAU zQh^kMk%5tcuAz~xfoX`Lg_W_1m9c@gfuWUw0h@x*Rum1n`6-!cmAEyO*RJ9OYGCkm L^>bP0l+XkKjd!NK literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^azHH4!2%?sQn&U1sR^Dgjv*GOw_XVpYEa-{33ykZ z`74{LEb@rw|E&35CbKMO7Eb6%x+|32VX<_wP=ZTsYg2WHG5eNhhn!uF^S}MQCh^TV zVmnWQU*zw5pF?^Un?5w_*mcOJqT#Ka{|nJ?@f-4Deog%)_xStMh{+EnjrH<{!j`}J ze=_s|M}B4T714Fx8&VTJwsIsLWliJmm?i$1Q8z~aEq}s^uRymkc)I$ztaD0e0s!kf BQJMe% diff --git a/mods/signs_lib/textures/signs_lib_font_31px_41.png b/mods/signs_lib/textures/signs_lib_font_31px_41.png index 22542bf1ba839015f881d577b013663a6c56e69d..1fbc4fe6d4178576d2477ed21b33e714abc98e89 100644 GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^qChOq!2%=~wfa>9DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIhEX^5ePm9epvsin4op_PHbc5YXo f_mDK?=BH$)RpQogEbOlePy>UftDnm{r-UW|ZXur?aO=@9xU_STg7evL*6->`~7v@&%6Yh&*16m=d#Wzp$P!{bTXI# diff --git a/mods/signs_lib/textures/signs_lib_font_31px_42.png b/mods/signs_lib/textures/signs_lib_font_31px_42.png index 8250ba6f79ef98894b0f6e3bcf2ac14e40b3756a..c28bf8f8ce19fbeee7c9e3f0be26c8febd1472ea 100644 GIT binary patch literal 377 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$I6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gtDv>Eak-ar)|%K)wbA9_Q%8f7i#@pO~Vt zY0`quKffZjn=>m$q<`LEet?PL(dBeGVHMG%8c8nUTfQ_$u?Vb8Jo@d?ak<6ruZ(=| zr@uAn?Q0A&n6mzxhT6q%{)ts{82mS1OJg{7&hstVZoKPtGNxD&<+ zv|Y8tHKHUXu_V4=jf69(c4H>OGA{u}CFZ))A{*!0o^5mPx*em&pm4DSG v#dQ-Hr#me=JTa-&#Z_@q_kUr|_Q_5R-K_HOHT#OY7=Xaj)z4*}Q$iB}SLPxW diff --git a/mods/signs_lib/textures/signs_lib_font_31px_43.png b/mods/signs_lib/textures/signs_lib_font_31px_43.png index 60df4ce1b323e58f13dc8205f9fc9b4b14554af5..2d424a2b4108d42d9608d4ceb0ac5a62d5702153 100644 GIT binary patch literal 396 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8gbH+`)DQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fj}r;B5V#p%0Ky!jdwcwDSoe#ckFFl=LG zx_Trdg?&%ma)yO1;a!XU5AC#9c*D0&DWg$t_RJ-=tIDr#b~Wr}4Le`OaZBf7=7U|0 zjtcUrw|6y7?+}>xGQahI$DQ?u+>91poaa5|`(+9B^S^lgV@3D!{?D2>+wx7gf%yfG z7yo-7NbkAPYk!D+-$f(cl}rzsfeunFag8WRNi0dVN-jzTQVd20Mh3cuM!E*3A%+%K t#wJz3nXvob^$xN%nts%a3SsYLUgQu&X%Q~loCICWvfwcet delta 117 zcmV-*0E+*N1CjxdByL$rL_t(IjqTIH5&$3s1W^C~(>j*5!Zcl)a_lKH5K$9&;5LRn zA*CxX(8&qqe-W$@4#(8Ko?<<~dm0w?@y(`S|HCS!KXuJ{Zf#1&6>)33d4g+7JzmEH XK>4yM`00000NkvXXu0mjfom?_^ diff --git a/mods/signs_lib/textures/signs_lib_font_31px_44.png b/mods/signs_lib/textures/signs_lib_font_31px_44.png index 3efe8512efbd89c02f18ef7acd638cf39dd0481f..f5a9ca7daca820590786c70d206ef52185060458 100644 GIT binary patch literal 369 zcmeAS@N?(olHy`uVBq!ia0vp^qChOq!2%=~wfa>9DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fID(;KilzJNs70gPqqJLbZ&v@_N&tFnQ?pm18r3;ag8WR zNi0dVN-jzTQVd20Mh3cuM!E*3A%+%K#wJz3nXvob^$xN%nts%a3 RSsYLUgQu&X%Q~loCIIyablU&` literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8gbH+`)DQa+w8jv*GO-(EK4V^H8=KJf4V z_gWE`z75pUXO@geCw2LNXBm diff --git a/mods/signs_lib/textures/signs_lib_font_31px_45.png b/mods/signs_lib/textures/signs_lib_font_31px_45.png index edc2321805e5fd9ac4e4345e34005a30d51d1259..c7d551019af50ac684f17cf085486170d67f7c08 100644 GIT binary patch literal 328 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$I6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gyMZ>Eak-aXLBW$9V^l1SLO7U6D-&K=3DB zWl7IR``$Hf5e6E~?KbBhaQPqmZ?e5=Mf+ohqdd85(qx!e8NP}#F{~Bgbj{Ro*#$IA zwZt`|BqgyV)hf9t6-Y4{85kMp8XD;un1&cySQ(pG85n9C7+M(^=-rTegrXrgKP5A* W61Rr<)@5-(4Gf;HelF{r5}E)v>{zD& literal 101 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv~!2%@L&$hDxQaYY4jv*GOlM@tp{xLsv(Ei=e z&ZnQcqdED()ZRG}3p6$5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gtz}>Eak-aXLBW$9V?<1HmvSUsoL-Aowr& zGE0`n;NS8COAfB!I9k4gsno=PeW}th#~GF@mvb<@En#zJziSV41%qmdYeY#(Vo9o1 za#1RfVlXl=GSD?N(lsy*F|@EUHnB1=(l#)(GBA)gV5vvZkei>9nO2EgLtgHl!$1uT Mp00i_>zopr0ABo4H2?qr literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQfi(qjv*GOlM@tJ{u%SMO!{x} u;6iBA-P6pAQ+~9*n-K76zJg4Y7Xx3V&84@2Tb}`SFnGH9xvXI(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fk6r;B5V#p$P$9mN_HI9z1ozVA2E^(gl7 ziFu+_&R4_8sN%a&+3>r5!(vg98uwu3SBs*b%Y`xApE;3x#odQTOkyM2iq2J(cpiHe zwK-jV-_;2+(w@amGo&W*&V42{|7woU$=BQOEZd$L<S`Fi^dkW=D z?!5e<|CiN*v0U58kg;+_E6_QrC9V-ADTyViR>?)FK#IZ0z{o(?&`8(7G{n%t%Gkup qz)0J`(8|C--hibZMMG|WN@iLmZVh?4dkzCNFnGH9xvX&5tciM%a)9&XsPBkSJj z&p~%jxu-s|JYLTCbWOCbTF;y3?)+uuO#jZDQu9Hn{;+(!+l(@)gw9DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI%AcStLmKgg5y@`{{bxxqljfc-)D4M%~9#a@!_0TUgimol*Eaym-PT~P}(Nwvf^ zq9i4;B-JXpC>2OC7#SED=o%X78kmL{T38vISQ!{=8yH#{80>WCKaHXxH$NpatrE9} U6H?pDff^V*UHx3vIVCg!0DL@GNdN!< literal 93 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$Il!~W|V~EA+ppZ*LuL`ze__t{$xaNtzkLol*6aTSs%P+Y^>bP0l+XkK#^M>d diff --git a/mods/signs_lib/textures/signs_lib_font_31px_49.png b/mods/signs_lib/textures/signs_lib_font_31px_49.png index a07c15abc5e026500de0c9a5a638f88908758108..268095966ecdf632722f58d4eb1e6be4d1ff4003 100644 GIT binary patch literal 303 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bf!2%>3@5!$NQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)Pr;B5V#O36aALkobW=KeMJl|vh1b@<7 z3MBqdUQ*stEUC#+_9up+QiR3!)ZAV-pdQr{*NBpo#FA921QAz*+ literal 79 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol}!2%@nWJ)FgDKSqM#}J9|Okj4b~P c+H_em{85o-Z1nKX0jgl|boFyt=akR{09z3fK>z>% diff --git a/mods/signs_lib/textures/signs_lib_font_31px_4a.png b/mods/signs_lib/textures/signs_lib_font_31px_4a.png index ae61bf1719918ac3e566810a08f2b73f051a32ba..f53f2d1d843ba7718eae9d2ffc90c35585a25442 100644 GIT binary patch literal 354 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gq?2>Eak-ar*6KOFjk#4wlGA|M&My<&wLw zV&jEAgB^1e7Jew~dDAkd5lL!58ia)wDW zZ#(&w`Z7O#_a=W^m`%l;-wSwlW{BE;eQpi3g+aB%HKHUXu_V85q<&Fmy%Hkei>9nO2Eg1Ml9>pCBtdUHx3vIVCg!0EORb Ap8x;= literal 111 zcmeAS@N?(olHy`uVBq!ia0vp^0zfR!!2%>**0kCKDKk$O#}JM4$q7IDS(Ogdw*|5u z_F^$vFyUB01K&UALyZfX{#PuS=p;1zNqvmt-}(+s28REA7T0+H-be?Uz~JfX K=d#Wzp$PzS%On>7 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_4b.png b/mods/signs_lib/textures/signs_lib_font_31px_4b.png index 87d9c78e465f40b6ea87bf835044b826d3c09dfe..81beabc26f25363f0ef283690d6fe893d0a6d728 100644 GIT binary patch literal 392 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8gbH+`)DQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fj>r;B5V#p$b8Hu4=%;9vB|xWxSKZu)Ydgz#Cq&YY^-hl zK4U%MD;+C8{xndqyE2b^&ANYE=T@FBk<L zqQ4LQpUKrR!~|(OS1+rr2RcTz#5JNMC9x#cD!C{XNHG{07#Zjq8tEFCh8S8{8Jk!c pm}naqS{WGBJTP=c(U6;;l9^VCTLbUj&YwUH44$rjF6*2UngGw;gZTge literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^qChOq!2%=~wfa>9sYp*3#}JFtcP|_AF(_~_ANcqG zvW1kOR__iC={pWdjL(e23pVrZ@)wf&>Rk1vD5GR?P4#^PzrdwD>w>wgHRJ;2=U4qFGOWP3Ft^R6M&rv$+ar34^DrpUXO@geCwqW-){S diff --git a/mods/signs_lib/textures/signs_lib_font_31px_4c.png b/mods/signs_lib/textures/signs_lib_font_31px_4c.png index bafd6d2b9f8e7132e1a173c74b5aef4147222471..4e1dad036aad0ff317ad786c10696f29c8e6024d 100644 GIT binary patch literal 316 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gtz_>Eak-aXLBW$9V?<1HmvSUsoL-Aowq- zD0A$;$PANJ86kpKgVlHr1ZliolPuFRb8=M|!;>^t`^0qme)2Bz8uhE@g!x29WtMA49&pOTqYiCe?!Q%yjhGB9|$ L`njxgN@xNACPh@C literal 88 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDaXeidLo7}wCpa|xw|KB(QlRQ# l2hK7Ff7Sn-hZZhnVR)vRvPy<~(>|b522WQ%mvv4FO#q827@PnA diff --git a/mods/signs_lib/textures/signs_lib_font_31px_4d.png b/mods/signs_lib/textures/signs_lib_font_31px_4d.png index efc8814823316ba58d7a34a1b10be9d36850eef7..39cb028f1f952caa2fcc675ce79ae3ae44c26fc3 100644 GIT binary patch literal 376 zcmeAS@N?(olHy`uVBq!ia0vp^5I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjNw!c!#Z z$=U4S_;p`stwGpK6~~sYZ@Vt8@X}_HQwo3EoFB#IS9J5cd`-%CZoZwrC2b>o5BLBr zS1oakC`m~yNwrEYN(E93Mg~R(x`sx&2Bsl~7FNb4Rt9F;28LD!2CwTCa!@qn=BH$) XRpQn#OKHXhpaup{S3j3^P69DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIhEX^5ePm9dGHftj{}p_PHb>w1M86b-rgDVb@NxHZgDnsEWB Ofx*+&&t;ucLK6TnGI3b| literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$Il!vE_V~EA+yB7@k8XS0-5B~kX ze7X?dgh?+7nq#Z94ok}K&GX*Z&Z5BRAs^)Ud;*tMd&mXLB~9NJu0Q|Ik@*6H2}6GS d?KkruFcu|hJd5RP-2*g}!PC{xWt~$(696k!D*XTe diff --git a/mods/signs_lib/textures/signs_lib_font_31px_4f.png b/mods/signs_lib/textures/signs_lib_font_31px_4f.png index 9698926a2952dc4445f398c29cead45efcb858d2..3794449467abc99aa1cdcee0e1786b0a61e157c5 100644 GIT binary patch literal 386 zcmeAS@N?(olHy`uVBq!ia0vp^;y^6V!2%?g70h!3QY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC0W`2+&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfQ)KS7sn8b(@!T~?2 y5B?n&+`VP*S{J!(!tN=vc1RtGJ@iHC0>hO*dxCbwO1=VG!{F)a=d#Wzp$PzFoHmC5 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_50.png b/mods/signs_lib/textures/signs_lib_font_31px_50.png index 67ebc51f0f6f9ef42b36fe7dc551d15023c53e59..5703cd770edd5877105b13783653fb50f2ad2373 100644 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv~!2%@L&$hDxQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSdF$RMU9 zZ+91l|Ly%}_5*pG1s;*bK-vS0-A-oP0U5ELE{-7H*&G+e)iX=Su`{OMmF9 zA=k!MG`si9Tiu(t`3>y;%zd6@oo6rP?(cjGU delta 92 zcmaFDR5d{*%+b@uF~p)bIpF~BKV?Uz29H#pBU;H0;ccgNE2b>eKC<%7e}yo&DdHE7 wb~0S)(oqWH@Z(>|eqx1@md0Uq%Q;gR8Je#J?Wr!D&B6c#p00i_>zopr0GA;n5&!@I diff --git a/mods/signs_lib/textures/signs_lib_font_31px_51.png b/mods/signs_lib/textures/signs_lib_font_31px_51.png index 83e28f0be1ddc11b81c78ede21618df23173a47c..ea4682fa1ac6b915fa71b2e4b3c2f4a987600ea4 100644 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^;y^6V!2%?g70h!3QY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC0W`2+&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfQ&9r7sn8b(`To6^EDW7xL7awzTZgi75j?` zZ7V$QcJ|-5(4DpIkh18H{5{7T4((ISX-f~~|1?GVe8T*qM`CPm%@^Hm|GVbGjnGHW zb9yF*UH_ZaeuQt^zc95MyvGljhP^O9yy4fu|EBI@fAxyb%9OSDmvgE&#Cq>^Upe9D z{D>EJz0>YatZ84b!nC}Q!>*kacejw`?wdVfx*+&&t;ucLK6Up7KhjX literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^5-CgfAy@)@%q{azRu*@SqCshc!JPVjbsnOB}R6q+Bs)%9J3Rl>IB$+eZC) z^O2it8dHBO$Ghb#vn;*0Leeu=LWM%e21v2Zz23V7-$lB`=`os5!47 T=_d0fpxq3fu6{1-oD!ML diff --git a/mods/signs_lib/textures/signs_lib_font_31px_52.png b/mods/signs_lib/textures/signs_lib_font_31px_52.png index d651ab264fab7d66f99f8081dcd34cce9049ba71..b872146b4073949b52c3ec7736cbff9fbbfa6770 100644 GIT binary patch literal 380 zcmeAS@N?(olHy`uVBq!ia0vp^qChOq!2%=~wfa>9DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIfb_V4R4zQ7&tBk#JD zH*Yb}0jedg5hW>!C8<`)MX5lF!N|bKK-bVn*T6Ky(89{t#LB=z+rZGuz+ksSv>}Ry c-29Zxv`X9>PRTy*1!`dMboFyt=akR{0P9b6zW@LL literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$Il%1!GV~EA+9DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI@)jZ)eO; z_f{>)&O5YgKhyMVGwvT3r+;Mo%dqs2rQw6My$^s+Q!R0gC`m~yNwrEYN(E93Mg~R( zx`sx&2Bsl~7FNb4RtA>Z28LD!2D0V>ttc9D^HVa@DsgMb$$DW4)WG2B>gTe~DWM4f DVZnrG literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$IRFE=0B)f%0te)EmJL>6e;zqp=M@@PtA)Q0(a239AUKK;nM=kq}<=wQdLZz;KHcjuYO zs5jfb?vW43onX*q_WQ&kf+|sXy3TOJfF7EwT8mfPg|D8$p;#|?_vp`!J NJYD@<);T3K0RSj(J+S}) diff --git a/mods/signs_lib/textures/signs_lib_font_31px_54.png b/mods/signs_lib/textures/signs_lib_font_31px_54.png index ad38df3d81d0f48c1ff010784afa13cbfc1791c5..8e5a1794082850ddb54e1b7928f3b7e1c88ccc9d 100644 GIT binary patch literal 320 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$I6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gtz^>Eak-aXLBW$9V^l1SLO7U6D-&27l63 z*7SU||GGBKg;@HXqJ3H_@rsWHG#FN_7hs62XSd!jR4xxRM76{2OC7#SED=o%X78kmL{T38vISQ#2<8yH#{7`U*Co(_16= SNCdSr0D-5gpUXO@geCy=uNNu+ diff --git a/mods/signs_lib/textures/signs_lib_font_31px_55.png b/mods/signs_lib/textures/signs_lib_font_31px_55.png index 80f1ba4071fd00570eaa32aba1bae605eefc93d3..c6aae8bd4cafc77794f43c493502a767bba0f87f 100644 GIT binary patch literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^qChOq!2%=~wfa>9DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI0UF5=HN{x-kemYnywgw9MwU`+b+MEZnQgv)K1(^sa7gjq~!6EzSP$ zR>EYRZNC0cptHiCrG-7QDPy>UftDnm{r-UW|9cg8X literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$Il%1!GV~EA+hSfpNLf1}BrP5h9L93|KZYt~m7HMdNq>U9FsV#~xProKNHwc~fAa$-9DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fI|#^L;2o^ zbpF*hdde@Ub8m|`Uhti@?faT}|GO-r4a<9eoy@6Bc~@c^)_*UO_QmvAUQh^kMk%5tcuAz~xfoX`Lg_W_1m7$@wfuWUw!J{I%8Wat=`6-!c XmAExb)?ao2sDZ)L)z4*}Q$iB}d1QH6 delta 110 zcmV-!0FnRq0*e8VBxh1dL_t(I%iYs43IHGsL($&<(%(_VG@@V!+cA#}g+}y2?3kWV z44#u`lr3eYVLHz#mZE8-oi~(}Qbp%bUZjeSlTa)yp%_?1^XEZ-zurG-16ixLS5>2> Q5&!@I07*qoM6N<$f|Fn`jQ{`u diff --git a/mods/signs_lib/textures/signs_lib_font_31px_57.png b/mods/signs_lib/textures/signs_lib_font_31px_57.png index 7b43529d7eb9d63a07073d63192d34ef7230660f..a8caf8e2340e4fc5be4bae98692ddbadc8773de5 100644 GIT binary patch literal 396 zcmeAS@N?(olHy`uVBq!ia0vp^@*vE?0wlLCzqbiUv7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBWNcITwWnidMV_;}#VPNp@Q7pzh8|T(JfRZ4JYH#8?n-a*UGv?qd|fK(%-eS%Eh7P z@vY@S^?!V?EW7{sfTnH!o=|?EgH%ggBT7;dOH!?pi&B9UgOP!efv%yEu7PQYp@o&P siIt(Dwt=CQfx)99xf&D=x%nxXX_dG&Ox9m^0H}e%)78&qol`;+0HSSxbpQYW literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^azHH4!2%?sQn&U1sW?v;#}JFtZ?9PM9Z=w54!HmS zQrZ#^Gv23{c_yfKeVWF?@amzmz^e0!bw|!LDXv`ix&DmojV%-+mfe(>UYb=hT^FRx60cyULC4wtc(=4Wo3g?oWEF?hQAxvXI(3)EF2VS{N990fib~Fff!FFfhDIU|_JC0W`2+&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfQ%kb7sn8b(^sb$iXBkka8_LZegCG|SHdbC ze0*=yezr*DhR%|)v1rVH-0yLDU%)Q@==N5(#>4Yx?n#{2bCYeh!K)eZ1#exAWRnCX z?npnXT)Cg6aF2OssNuSeVcOeIHT!({GvkuN_N$Qp42`r646O_dF3)0lh@v4kKP5A*61Rp$$M?hnH86O(`njxgN@xNA>?wr` literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^qChOq!2%=~wfa>9sSHmS#}JF&yAwV67!){|fBs+o zF=f%E#GP8^R)$MWt>@bpYhORaAhTd!An$S6KMLj#ydxH6@79>J^04G$zl@gK87pQ+ z>0dawK6iaH%dMUBHnlzcBz9`y#(;&9lAg{pS1x+OQu|Qh^Pf(=?;(8+ONIC60PSS( MboFyt=akR{0NFl1umAu6 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_59.png b/mods/signs_lib/textures/signs_lib_font_31px_59.png index 647bdb8a7ccdaeb4746655ba0c88eab1e443e30f..2b12a2e9b2af0ac227d60c931a9c6bdb84f37b37 100644 GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz9!2%?G-Bn$I6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gvaj>Eak-ar)_$vwRH(9L<^^|He!5|1*f< z>%J(VY`)+p*KMPS8zDdDyy1M9BxWIWVNde$t!o<csZa#60t4aGW@`zdfz~4inZ#t#zfBK%B2((tU#5JNM zC9x#cD!C{XNHG{07#Zjq8tEFCh8S8{8Jk!c8fhCCS{WEzp2hMIMMG|WN@iLmZVii$ S?}-I!VDNPHb6Mw<&;$Uej&+s* literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^qChOq!2%=~wfa>9DL+pa#}JFtZ!etYVo>04x%l({ z{C&A^4V5k`DaBUFxM+$wf8VU+nsKXiX2!<7=jN=)N$V8StiBTeUM_g?x5_0udKH;vftaE_E#-;=ad6}4054yK$96fUHx3vIVCg!03o3;9{>OV diff --git a/mods/signs_lib/textures/signs_lib_font_31px_5a.png b/mods/signs_lib/textures/signs_lib_font_31px_5a.png index 7b3ba636165144c1f5dce6ccd49f53132b3cf6f2..fbb7864582a094f741ab8b05e4f5bdc7604b07e0 100644 GIT binary patch literal 372 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv~!2%@L&$hDxQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSdF$RMU9 zZ+91l|Ly%}_5*pG1s;*bK-vS0-A-oP0U5cTE{-7* zP8O8>{QF|ds+J2D7ae!sWMo*ReC1t0828SufV5jT%xo4(-PJIDdvjI7Prk)YQxYwu zB5E@yDy~Z5Q@uMQF78a!-5LBft(*SXwWKvNe7*QOcGkD_GN#vFa+c|iLYzR0RZCnW zN>UO_QmvAUQh^kMk%5tcuAz~xfoX`Lg_W_1m7%e=fuWUwLFrrmP!tWh`6-!cmAEyq SY}gJ8DF#nhKbLh*2~7Y#9(3>k literal 132 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&gl((mgV~EA+tCt+P7!(AU9RB~$ z+6p-BRwP42RqE7YHROytbGq@=~t|E-0?qsyl9 g|3?nP7wa<^T+JNM7N>pt2sD<#)78&qol`;+0H-%A@Bjb+ diff --git a/mods/signs_lib/textures/signs_lib_font_31px_5b.png b/mods/signs_lib/textures/signs_lib_font_31px_5b.png index 2ba87b66d70f596d1a6ca3dcd7a9a089198b53d6..7eb1e64a6568fdd10d9c9da98223ba7cab7cdebe 100644 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^oIotk!2%@bi|fk*DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIo>z z40H{RbPY^H3@xmTO{|O!v<(cc3=G&5gtnq+$jwj5OsmALp}ck#C{P$YUHx3vIVCg! E01)&~a{vGU delta 53 zcmdnW6g)viU&_JI5MZHPE2942?G##y85}S Ib4q9e0PhPC^8f$< diff --git a/mods/signs_lib/textures/signs_lib_font_31px_5d.png b/mods/signs_lib/textures/signs_lib_font_31px_5d.png index 06575b793156803129f69948086fbd60f463b993..b7aecb99c189e6ea9cdd3e1ab7922692e8b93b36 100644 GIT binary patch literal 311 zcmeAS@N?(olHy`uVBq!ia0vp^AhtXQ3y>^Pm?8(HSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfD8jq7sn8d^T{bc&Nnd5kl4T=#@6<~XN6PG z|Bb7TES)QuC3;BW(bj%0zB)%8%@&cj41fQ#Id9&uavM;uYKdz^NlIc#s#S7PDv)9@ zGB7gGH8j#SFby%ZurfBWGB(sUFtjo-SP(ABh@v4kKP5A*61RqnTnqOCH86O(`njxg HN@xNAoQ74Y literal 83 zcmeAS@N?(olHy`uVBq!ia0vp^oIotk!2%@bi|fk*DJf4E#}JM4$q5eZ|0O#_e(|?1 gb~^0WamIv^;o-`ry2dX>?Lbuwp00i_>zopr0Lx1i`~Uy| diff --git a/mods/signs_lib/textures/signs_lib_font_31px_5e.png b/mods/signs_lib/textures/signs_lib_font_31px_5e.png index 5ac99a6a880a3c288cc54a410f69e625ae2bc082..c70de5958a929853fab531238ade96cb7296ba0c 100644 GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gvaa>Eak-ar*5fL%stFJj{hx{@34>UBqSX z>8fm4q9M#uEY2b!b2{<$iE|egawnZTsJ2qNNb-eJ=y#7QqcEnEp$VR+WY$JKOS$&@ zSoY03f|p_i=RKWSym8I5mh74j>Hik?E)<^sQNq@xuh?11Vl2ohYqEsNo zU}RuqplfKPYhW5;Xkle+Vr6WoZD43+V6Y%uk`YBiZhlH;S|x4`7r7Sh1!`dMboFyt I=akR{08)f)IRF3v literal 116 zcmeAS@N?(olHy`uVBq!ia0vp^{6H+v!2%>FamGghDQiy`#}JM4$q7ID#f9{FnIo1? zWSqM6BBSP|6HP0)I;Ojos>IA|!S3j3^P6I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSdF$RMU9 zZ+91l|Ly%}_5*pG1s;*bK-vS0-A-oP0U0WuE{-7zm0Xkxq!^40j0|)QjdTr6Lkumf uj7_YJjkFC6tqcq%?q{BZq9HdwB{QuOw}uCgb}IliFnGH9xvX5UP5t&f4RXHIyR~U6o5oGQNWn^Pm?8(HSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfDBVl7sn8d^T{bc&Nnd5kl4T=#@6<~M?mdy zy~-C|~rG5|#05Vwh~mV;lb2$r5OQYKdz^NlIc#s#S7P zDv)9@GB7gGH8j#SFby%ZurfBWGB(#XFtjo-INYvdjiMnpKP5A*61Rp;x2CiMH86O( L`njxgN@xNAF{M$+ literal 88 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol}!2%@nWJ)H0IG!$!ArhC96B-)+CvdPQoU6}~ lVdHpiuf@*hZaJlx;hV{dh;N!-vVlq&JYD@<);T3K0RS?^7P|ld diff --git a/mods/signs_lib/textures/signs_lib_font_31px_61.png b/mods/signs_lib/textures/signs_lib_font_31px_61.png index 8591054e290d8917a3e799310dd419e3fda878d9..d68941600ece5f427f68e7fa4078e2abceeb050a 100644 GIT binary patch literal 371 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjsr;B5V#p%1jhC&AvIJ_Sag8WR zNi0dVN-jzTQVd20Mh3cuM!E*3A%+%K#>Q4ArrHLERt5%p81;)#H00)|WTsW()^Ijv R`Z=Hm22WQ%mvv4FO#r-+Z_xk% literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^0zfR!!2%>**0kCKDIZT4#}JL+yAv##7!)`T|MD_c0ZmZ53#`98YO+_zO hZ+xi}^0ldeVP?P1Be{brH-P3cc)I$ztaD0e0syJCD_Z~n diff --git a/mods/signs_lib/textures/signs_lib_font_31px_62.png b/mods/signs_lib/textures/signs_lib_font_31px_62.png index 63b6c29e22bd54a319fe05179ab9461be139bff9..bec2a407043d31b4d7140a8728e42f8ec76177f1 100644 GIT binary patch literal 369 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gvab>Eak-ar*4!gIos;IGmF|{;$6&+ZEyK z&42sAy(!C+f>_&LOP8|*Fc{2iywU9^tN3)vd#T&6I6ru-={fE3Bx6p01ottyldt-1 zCsmh){88`lof$O6uW>DFiuc!k9y{5lBH91yKi^nbJMmwAD(h}>!$J~ht7?gBL`h0w zNvc(HQ7VvPFfuSQ&^0vDH82e^w6HQZwlXo*HZZg@FxbPWUxcC|H$NpatrE9}voX`p Q0W~mqy85}Sb4q9e0A${A9RL6T literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQf{6ujv*Gk$q5aO|1BOGgg5bQ z&^pNS-_T^zVwTHQKDRGUP58>1=P$hQ$$y0)r*-`s++-pJ8+;k>9cfU$npi6Nj>Xbs bDg(o^--dVFIJPSRO=R$N^>bP0l+XkKI(#Zb diff --git a/mods/signs_lib/textures/signs_lib_font_31px_63.png b/mods/signs_lib/textures/signs_lib_font_31px_63.png index f0d6995d6b7aa30890eac0bb9043b66fe1a11839..334f707d811c9a197eb6dfb266a8a0ee398eab13 100644 GIT binary patch literal 373 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fj+r;B5V#p%0~z4;C(aIjYD-}`^6BvCiO zV9hO)(x>SP78))~CEqmID;?GsF+2X0+k38kpTzeAw`2up6dE>IZd~uI=+xbqW^s4L zsUHv7QgW37qTa^Mn7_HJXWMzRYqqmEHlN*X_oM#Gp6Sc4?roDfqOWY*Q#)lF&}P*V z*NBpo#FA92rfpzoWnj?z()2xwhTQy=%(P0} V8vbnQ4F+mp@O1TaS?83{1OOP=c6|T< literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^0zfR!!2%>**0kCKDOXPy#}JM4$q7IF8ThPOPcS$$ znl&t85LXCeTz2+^lE{<~jnab^^|{9+wLx3Xk`rh?)Ek3R08MYB6tjJJGd aWmw-Cv27v8%NIZc89ZJ6T-G@yGywns7ACp? diff --git a/mods/signs_lib/textures/signs_lib_font_31px_64.png b/mods/signs_lib/textures/signs_lib_font_31px_64.png index f73979c91ace6c1340908993740cc6c6aa9f499b..5b6ed537399a8cd1468c32d404528ec11fe2d106 100644 GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv~!2%@L&$hDxQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSdF$RMU9 zZ+91l|Ly%}_5*pG1s;*bK-vS0-A-oP0U6nzE{-7oaTWZ&e^aDK@;-&w zl7+LE{i<;_l#JEc+1RmVztOk3Z=-UJzn%V)@@(hS2!-b@8PX!MTlv}pg1Q}kmNxmW zjJbC`SG;ZNu5DmwWniE^&n_B8LvDUbW?Cg~4N-^N Ro&z;7c)I$ztaD0e0su1AbxQyM literal 130 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQl6eJjv*GkcP|<8F(_~_ANcqG za;cHxQl-MfyXJ9*GRU3d`)Js?(PgrS=p!bfkHwM>JJT9Xq`bN=^)An@ZE)5#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fjsr;B5V#p%1jj(i6cI2Nb;|6f#ogU8iS z&wI}c&kZ6`NU+Sys8eN^ zRAu+>2l>-d=6-U~+t{L}TXo$+SciLsd+jEJu-+{k$7{Dr+pJbIPkgv(63|}N64!{5 zl*E!$tK_0oAjM#0U}T_cXryak8e(W+Wo&F^Vy^Pm?8(HSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfD8vu7sn8d^T{bc&Nnd5kl4T=#`4)-xy`FZ zAVwgP!_}G@2p-qZ5la+JN%_&AC3o`H#JMi3-YUCHnE2v|1Ggi?Q6_F{LA%}IK(ka! zTq8mAm4U(CYkr$hH00)|WTsW( V*084g8y`>ugQu&X%Q~loCIEyZScd=r literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^+(0bP!2%>_Kl-l#q;x%9978nDCnx;iZ|C?hpRrqE zk^!?~qK16v5BthPHyBPH3Mo9f!ay&v#G^iup-cR_=F4bPgg&ebxsLQ04?|) AX8-^I diff --git a/mods/signs_lib/textures/signs_lib_font_31px_67.png b/mods/signs_lib/textures/signs_lib_font_31px_67.png index ba5de8d45dac5cc1aa0782d41dd9aae85ad51dd2..d1706162caa41fb2f111390ee2d2222b7b69d438 100644 GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv~!2%@L&$hDxQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSdF$RMU9 zZ+91l|Ly%}_5*pG1s;*bK-vS0-A-oP0U7n4E{-7zm0Xkxq!^40j0|)QjdTr6LkumfjE${KEVK;_ mtqctAUh~_8q9HdwB{QuOw}v&{-}rzU7(8A5T-G@yGywn?#=e=VDQn{Wkjv*GO?@m0(cR+!|S@Yxn z`kmG~dVXCyQg)x2Ji#fRt0&CH{P)ZyvGzQ%e5SD+%TBc>yxJk6qBB=9r&Zw2@0uyx zOP{i{AJCd!#C=rd(~Aik3)s!OT=X&vl)baQpOaK}U2*$Rg|_&-;58Tcg+ryRQl-@D Qffh4(y85}Sb4q9e08rOD82|tP diff --git a/mods/signs_lib/textures/signs_lib_font_31px_68.png b/mods/signs_lib/textures/signs_lib_font_31px_68.png index 726598b2aebdc78cb862746d36cad6ec32f7188f..66a10a499c3f9d23fa5b6b69050097514099c433 100644 GIT binary patch literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gq?3>Eak-ar*5fL#_i394ziT|JUCXQF`Wc z;89S-5wFyO@IZrG7vvgQ6CSnRIJl(qLe;jU>vzJmCwM&Sos-;jm(?lh{S?oKN&ENi zQ#74l@lpPhzQnVa)-RaSj|tm;>H8iDv_iGSHKHUXu_V9nO2Eg1J|FwyMP)PJYD@<);T3K0RVNwY)b$D literal 106 zcmeAS@N?(olHy`uVBq!ia0vp^0zfR!!2%>**0kCKDML>e#}JM4$q5aO|1BPD2x(X; zzopr E0B@ikegFUf diff --git a/mods/signs_lib/textures/signs_lib_font_31px_69.png b/mods/signs_lib/textures/signs_lib_font_31px_69.png index b790d77b60b1cae6c89a740b1a4bd07ea1a54b86..2034e6ccb0d6bd50648df6b775ac464879f0351a 100644 GIT binary patch literal 306 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bf!2%>3@5!$NQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)(wa-rmQnH>djv*44lM@;m|MRrW{Qpp3 kre_zYb5rNt*++~SMVajm^{FVdQ&MBb@0B!ylxBvhE diff --git a/mods/signs_lib/textures/signs_lib_font_31px_6a.png b/mods/signs_lib/textures/signs_lib_font_31px_6a.png index 3e735fee9a11070632cd26952b38eb36d7893a10..3573727a7ed24719b699359da25efc3fe515c23e 100644 GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^AhtXQ3y>^Pm?8(HSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfDCg_7sn8d^T{bc&Nnd5kl4T=#_@H&pp)^x z<0~gsI38o%S{pLK$T1@200Z|fhPJX}|0SAwK8P?deCgnFWcw zRdP`(kYX@0Ff!0JG}1LN4KcK^GB&m{HPALNv@$SIn#|yhq9HdwB{QuOw}#+zJH7)o OFnGH9xvX_9Bf!2%>3@5!$NQi`4~jv*44lM{aMw-|hw-&mr@ ol=L_#>63=|F;})9I~;NuK1jwd?EK=@3RKMC>FVdQ&MBb@0M>09djJ3c diff --git a/mods/signs_lib/textures/signs_lib_font_31px_6b.png b/mods/signs_lib/textures/signs_lib_font_31px_6b.png index d03c19936838468e94e871a022c469e4c8289adb..411d354fad2fa917eae6700392b9ca9d1087d2b0 100644 GIT binary patch literal 372 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fk1r;B5V#p$z`z4;C(aIjpEeDrs{kNA-Q zQI)?sZ`Qp$%^~cq(dDkiV8Re^i~DQpDbFRT@-^No9f|_jU+VC!@mhJnDa>FZN6pH2 z`+{dZ%E-8`CJ}w}+@(y1XS=uGJyGQJ$nuoQ)4)=%f1g&*b**0kCKDNj!q#}JM4$q5aO|1BOEgf-}N zxiYSjXk#i7jEQ-ZcOYA_EHfogMlMZZNsA3DPl}d;l1xW{gTac4tsGhj3f8s@G=KOr c@UgNoG&*QKDe{n31{%uX>FVdQ&MBb@06icg{{R30 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_6c.png b/mods/signs_lib/textures/signs_lib_font_31px_6c.png index 836db1a0d193eca43c4ad1c015f6b49f96c2ccd8..568dbee9cec2c948361ab6ba01edf3e3f213b3ce 100644 GIT binary patch literal 303 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bf!2%>3@5!$NQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0h)Pr;B5V#O36aALkobW=I4ua5FPAAFg-f zX#Z$G>y5_r96jZG3Cml!8MX$n*rw&0?gr{nEpd$~Nl7e8wMs5Z1yT$~21W+DhDN#u yrXhwFR>sCwriR)EhE@g!El;@rqiD#@PsvQH#I51$&dtt14Gf;HelF{r5}E*ZyHI!l literal 78 zcmeAS@N?(olHy`uVBq!ia0vp^tUxT!!2%>(wa-rmQlg$Njv*4^$q5aO{|l~lr2lJo b{xpL@v%u_>RpGAXKm`n*u6{1-oD!MI(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fk7r;B5V#p$V!Z literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^l0Yoa!2%?A>|FO1NV#~rIEGl9PEPpYZzOZoX_J_Q z!_%a|248Ng10snI#w{8SZDKsT|0f%=UUrYz^Id-ZjryEP|2aE)vm~!N&6;+xsKzopr0Ky|E;{X5v diff --git a/mods/signs_lib/textures/signs_lib_font_31px_6e.png b/mods/signs_lib/textures/signs_lib_font_31px_6e.png index f8a8dc6895d5767592e9ef82fcc67ea177d9d57e..9ae15e7e3079889b28045bafb5cc084d38439d0a 100644 GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gq?1>Eak-ar*5fM=l0M9%l7T|Nj@+h+GU^ zD9*nr$DfzSGgI3qO4WTIpDjZeM`ehwzF(NT)x0CDYBp?ZCMx**<#O%Siz+*D=l+h5 z@?H8na+Vbbur78JwvOVx2Q-~QwZt`|BqgyV)hf9t6-Y4{85kMp8XD;un1&cySQ#5z pnHp&u7+M(^Y~>M5LeY?$pOTqYiCe>wz?EPtJYD@<);T3K0RX^BT`>Rv literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^0zfR!!2%>**0kCKDI-r8#}JM4$q7IF8Tf=*4H}Le zUB)2%=eU+v7ZXqM|KvhWvCI_J{~NvgwIn214=ctqFepU1A75~Ewgpf(gQu&X%Q~lo FCICOJ9Y6p8 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_6f.png b/mods/signs_lib/textures/signs_lib_font_31px_6f.png index 8982e750cf2ecb2cf69718fbb026b15759d87dc3..e23eba3c147956d562e9e3d3eb09a9d719672b05 100644 GIT binary patch literal 367 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gvaX>Eak-ar*8gYrX>tJkF0-eBZxmx5!c7 z*o_7XGdT9tq_7{HF>j9Ya_8x6E_W4wC3dWIVE-(?GMq*9;BvhiZ0jvQ6qzj5h-KQi z{E@d}L~_WC5_#K)hBvCscP(L)n;81?>l?ebs?U^Ou-(d4GQColTm!UIwZt`|BqgyV z)hf9t6-Y4{85kMp8XD;un1&cySQ#5znHp;w7+M(^2v5UP78%2?07fy_8;o5_cNo@j*dGXJIa`}yw(uv1=NuE) y2&eP|qJi(M7cosfk)f#7)aj$;qPFYd%=Zk_qDy8iuFb#000f?{elF{r5}E+K^CYnV diff --git a/mods/signs_lib/textures/signs_lib_font_31px_70.png b/mods/signs_lib/textures/signs_lib_font_31px_70.png index 60caef99b1784046efbf46756dcc9d82c1849e48..854bbec4ac6f70164ce8a6496245420fe7beaef3 100644 GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gvaj>Eak-ar*A$gIos;IGiVM`v3pwn+u(O zy0*NhY)qeK9@x^dVeLlue|)hF3Vx2RslOWc$QZb)?lzzFCTV7?X~&fp6Dz#RLhL^u z>8)qE8t_c(lFIQU=T6n<;Y?{i<32A-5kGje`qgvU{U1Z`E)|n^Pgq@00JK)M#5JNM zC9x#cD!C{XNHG{07#Zjq8tEFCh8S8{85>)f8fzOES{WD!S4&+((U6;;l9^VCTSJoC RqAZ{W22WQ%mvv4FO#m&UbfN$N literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQm&pZjv*Gk$q7IF1^Ap*4H}Le zUB@DupmC6`Bj8ZON|wtRCaMv&j*En178(k8t$3`Q;<`eKg<<7I50@kbElI(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSdF$RMU9 zZ+91l|Ly%}_5*pG1s;*bK-vS0-A-oP0U4Q|E{-7#=e=VDQeK`ejv*GOlM{aU3-D#Dax|Q2 z)^=o<@cPjBpNB;xLE~rt(Ods{B19Hg%dTcJk>?Fmt+4TRxgaRY`2S>Zlj`0DxBEjm e<^1_IRT_Kl-l#q*&4&eH|GXHuiJ>Nn{1`8HJyTF~ zomsGOAJ4)=B2pKu=P_I}E4m{tdtmjGl&4M8x`m$R)SCSiSbg@lPAET@{ko&O<^xSq zEpd$~Nl7e8wMs5Z1yT$~21W+DhDN#urXhwFR>sCwrY713hE@g!*Y2o9plHa=PsvQH W#I0d@9>(Q9h+a2?sF;VYdw%4Fhkea3>dXGMBL%Jt+VFK}1gH aB@4rXFCY1Tz28{L00f?{elF{r5}E*odl~rv diff --git a/mods/signs_lib/textures/signs_lib_font_31px_73.png b/mods/signs_lib/textures/signs_lib_font_31px_73.png index 43ec4518d5ec2558be145fbaf511d23c8536ee7c..a80a4a7943d67a17cd5aa01799930893b30908a5 100644 GIT binary patch literal 380 zcmeAS@N?(olHy`uVBq!ia0vp^f#=e=VDQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9 z$=lt9;eUJonf*W>XMsm#F_88EW4Dvpc0fj{r;B5V#p%0~5Arn_a5!t;{Quubt|w?q zPL=UHmj_D&4kaXZKi7WHf8vC}0oFOc5AE9(wQk1u0~6a_nKaK??myKPv3kog<}9s< z7lrXN+c?EVn|4{Xb!Yl*-tHKkv+hRlw5Q&y&z1DO-Ymv_dHdC~_omk!U`}B^p>3ec zJ9*`ApaWD(Tq8SBxFxXL_t(I%iWVP4geqs1N;9^*M&i)g|JfBi{Xj_Y|m=sO+s`o z#3zt^xkV`Fnj-Mh&V;>Ds;-n~iJ2XJh#hi-=w57fg%SG4ps>aN=m6s-V6Fz?*qi_W N002ovPDHLkV1i@vG4TKZ diff --git a/mods/signs_lib/textures/signs_lib_font_31px_74.png b/mods/signs_lib/textures/signs_lib_font_31px_74.png index b4f222db4a5ab4654d0b70fe0809869d63b435e0..998466899b1cd825a69094bdc179aec0d6a1e267 100644 GIT binary patch literal 338 zcmeAS@N?(olHy`uVBq!ia0vp^AhtXQ3y>^Pm?8(HSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(tfDCU>7sn8d^Jga=*!Rzw!%os*s#)5>pzNRA2zOO zH$U=}&-xydGRT#xC9V-ADTyViR>?)FK#IZ0z{o(?&`8(7G{n%t%GlV-)KuHR(8|D| iV72}m6b-rgDVb@NxHT|-n;rnvz~JfX=d#Wzp$P!l8DgCP delta 70 zcmcb_lrllZLEF>CF+?LcIpIe?>m&^h<|{%+SX4NL@-J=>Z1H?3<|6v9KZVcCF~vjQ Zk>OeIQEPkl1M3-pz|+;wWt~$(697=J7r+1j diff --git a/mods/signs_lib/textures/signs_lib_font_31px_75.png b/mods/signs_lib/textures/signs_lib_font_31px_75.png index 54696efdebf73f32c2cf75e44dc8047e2c5eae15..8b3d212c28349d683db945c32323bb5054c89f1a 100644 GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gq>=>Eak-ar*6KZ!QJ}4%X+c-}i6Qb-L7a z%k9aj^BNQF5@puTnRtC6SHi2tOY?i*^z#1?Xse0dZ14Li$i*R6*OF5qdYwab;?#?h z%b%#(>YiiUVkvChB-|+qG+VXAHKHUXu_VmdKI;Vst01g9T_y7O^ literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^0zfR!!2%>**0kCKDPvC;#}JL+q5K%Aox#)9&t;uc GLK6TkLLC7B diff --git a/mods/signs_lib/textures/signs_lib_font_31px_76.png b/mods/signs_lib/textures/signs_lib_font_31px_76.png index 3cc3dc966728a8d09e0f28fb401d678db226a637..d41020641bcfe8eca2e54555821f6770c42f0558 100644 GIT binary patch literal 360 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv~!2%@L&$hDxQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSdF$RMU9 zZ+91l|Ly%}_5*pG1s;*bK-vS0-A-oP0U3#&E{-7?;14QJJ3 zbHBLwWL{=!S@dBE(=JZ8vtA4hm;SdlSMY|2)Mln!`M+_($z#)6R|KBuQQmNNk%raX zM#;TKlWpv(>}T5b-TRxLee=|j1C?hj?K=ac%n$i}+61&rwZt`|BqgyV)hf9t6-Y4{ z85kMp8XD;un1&cySQ#5znVM@G7+M(^JU6jBilQMmKP5A*61RqFnQfIo4Gf;HelF{r G5}E*SD{(jg literal 128 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&gl)I;kV~9m>a>5UP7MW*V0u0kx zHg^3>4sFwNTeIkYg~(s^U_s`v)BhH8CqKUEAh?M|EI%M#(92|z#=?n8ZvuViDa915 c&|+e^vS)Vj4}+)GKqDDEUHx3vIVCg!0F!?xmjD0& diff --git a/mods/signs_lib/textures/signs_lib_font_31px_77.png b/mods/signs_lib/textures/signs_lib_font_31px_77.png index 948ae218dee10d6527407a3e48b632651f389006..6a22a6b9a1bd75c1d09e451e4b5b9dbdb336729e 100644 GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^Qa~)v!2%?M`$WG1DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIuFF1y*_|^3!_4B+yM;~72UvJqi_q>|zd%XC54O7EO=@T=WW_Hc{zS%}#uhc~) zTM>_2Yk*ErEpd$~Nl7e8wMs5Z1yT$~21W+DhDN#urXhwFR>sCwrsmoPhE@g!&rR%( eqG-s?PsvQH#I0dkW?Lmt1B0ilpUXO@geCyn;CiG0 delta 116 zcmV-)0E_?r0+9ibByCtpL_t(I%k9)b3IHGo1VI1)>FrqJT9{NGvfI`WXe5G-^-&7- zVj<7=5P}FA$ppy?>2eSP2nP@%$WFsS_9(k^=;bRk>!U%Sn{Ij^vDfaUSyb|4DUBLo W0xs@?#oF-z0000I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSdF$RMU9 zZ+91l|Ly%}_5*pG1s;*bK-vS0-A-oP0U701GjWnds!#=e=VDQX!r$jv*GOlM{aU3-CFsax}zB zxNdWEFEvK4ccZkivrq`R%YsUi~hMa|s#wDDy4mqq6(mAL4B2%fU oFM&m%$4yCySb%7 diff --git a/mods/signs_lib/textures/signs_lib_font_31px_79.png b/mods/signs_lib/textures/signs_lib_font_31px_79.png index dbab5114872ccbf4a46025b71aa1c785c20279ed..a85ec647304e33b7b983cb3616e16d77d41913a3 100644 GIT binary patch literal 379 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv~!2%@L&$hDxQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|6p}rHd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSdF$RMU9 zZ+91l|Ly%}_5*pG1s;*bK-vS0-A-oP0U0HpE{-7$w)*CBeqkEqZZ&irFUJhQ#;9QQP;Puilz$lI>csN!g0`qj_a%aMYGPsk^HTJZLjQ3S*NGI=~=pFsr9t$Rv{BYHI`NKgt;8x+-IR+`)tWw zC7}JPC9V-ADTyViR>?)FK#IZ0z{o(?&`8(7G{n%t%GlV-)I!_9(8|C-u*OdZMMG|W aN@iLmZVd^F-zESxFnGH9xvX#=e=VDQeK`ejv*GOlM{aU3-CFsax}!w zkn&oPcQE8ogEuF$rPl---zK3Pn>}6^oTl&c+Q6!^?Zl#4LNYH~Z+ZQ@9K@-|Dsj**0kCKDVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIFamGghDSJ;B#}JM4$q7ID#rYC5YZ|Uy z+9BI~^y!L88JBo|EHPA_xMZW}p`{zWlO`S$dbUI5zwv{qf6h0A7fm>NBf#@HL(pW+ Vr?vOadH{`L@O1TaS?83{1OT<}Eb#yU diff --git a/mods/signs_lib/textures/signs_lib_font_31px_7b.png b/mods/signs_lib/textures/signs_lib_font_31px_7b.png index 81cb103110371fb9c22bb6d4be871d76b5a414df..1cb931a443710527e1016209324ae30db3ca896f 100644 GIT binary patch literal 354 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eZ!2%>J?VdyeDVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIde!ADZw~v)i(Oe^cPHdG@8k^L zAX;;H`Wykl(twU6rL1pD3SKe#2#7jfyZ9^-XpL%#YeY#(Vo9o1a#1RfVlXl=GSD?N z(lsy*F|@EUHnB1`);2J-GB7Yd!J&boAvZrIGp!Q02DhmjrT{fCc)I$ztaD0e0s#Gi BYeN74 literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^AhtXQ3y>^Pm?8(Hj6Gc(Lp07OC;Z@V<@hk4(V0W< zL_@s5D*nh1{|y9F4ygZ-x0U$6*x`*<;f$a465Nlx6BwfT)`ZNT-})M;ox#)9&t;uc GLK6VD#~|kb diff --git a/mods/signs_lib/textures/signs_lib_font_31px_7c.png b/mods/signs_lib/textures/signs_lib_font_31px_7c.png index fc6a6262117140eba8fb872bf32f40b62d8e2021..24b35532cf6188fe57cfc2275c4c6e943a912b8d 100644 GIT binary patch literal 300 zcmeAS@N?(olHy`uVBq!ia0vp^96&73!2%=;uDU1#DVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIJ?VdyeDVB6cUq=Rpjs4tz5?O(K#^NA% zCx&(BWL^R}3dtTpz6=aiY77hwEes65fIxrk{&hFC}J-}Kd+I}$&to;vBfbh04hx$i61Txwh^ z@>O!*Jnfk8m5O>t-ux=u*X*|H5I;Y&c<+93*9iM(%Yb&NmbgZgq$HN4S|t~y0x1R~ z10w@nLnB=S(-1=oD`OKN(l#)(GBEg*Z-%NNH$NpatrE9}W}`kSpbZS3u6{1-oD!M< DoeFK> literal 106 zcmeAS@N?(olHy`uVBq!ia0vp^AhtXQ3y>^Pm?8(H3_V>OLp07OCpa|xFX&*}z;&qQ zV#)-T|NP00Y$*r--(VFK`VngMKv;&)vEB4$f@cE5xmjyMj&vFVdQ&MBb@ E0EFNmF8}}l diff --git a/mods/signs_lib/textures/signs_lib_font_31px_7e.png b/mods/signs_lib/textures/signs_lib_font_31px_7e.png index cf63d5d3dbea436980423ef131fd26ad8980869f..00d7b6cbce92abb8b093de68b5d11e1848466687 100644 GIT binary patch literal 333 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9f!2%>5B14&g6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~g=CK)Uj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G& z@^*J&_}|`tWO>_45U54*zIJt9gyMX>Eak-aXLBW$9V?<1Hmw(RUQAjA{4IF zyUk!wp0*<;zm0Xkxq!^40j0|)QjdTr6Lkumfj7_YJO|=aStqcr8By2%` eM`*~+PsvQH#H~TqwRIg(1B0ilpUXO@geCxUlv~yS literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^{6H+v!2%>FamGghDPvC;#}JM4$q7ID#rwSY{W3WY zDE9J9P?5Osbix#a1z!J;uli(frX08>p^$IVw2K@|_n9y}wOg3`ezn;TpmqjNS3j3^ HP6 + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/mods/signs_lib/util/README.md b/mods/signs_lib/util/README.md new file mode 100644 index 00000000..5bbc9246 --- /dev/null +++ b/mods/signs_lib/util/README.md @@ -0,0 +1,36 @@ +# signs-font-generate + +This is a collection of helper shell scripts to create textures for +international characters to be used with the +[signs_lib](https://gitlab.com/VanessaE/signs_lib) Minetest mod. + +They currently expect the +[Liberation Fonts](https://github.com/liberationfonts/liberation-fonts) to be +installed at "/usr/share/fonts/truetype/liberation". + +ImageMagick is also required. + +## Basic usage + +sh create-signs-lib-overlay.sh + +For example, this command will write textures for the non-ASCII characters +of the French language to "/home/user/signs_lib": + +sh create-signs-lib-overlay.sh /home/user/signs_lib fr + +Currently, there is support for German (de), French (fr) and Polish (pl) +non-ASCII characters. + +## Character alignment + +I chose the image processing parameters in order fairly match the alignment of +the existing signs_lib textures. In order to get even better alignment at +the expense of slightly smaller textures, it is possible to also replace +existing ASCII character textures: + +sh write-ascii.sh + +For example, with signs_lib residing at "/home/user/signs_lib": + +sh write-ascii.sh /home/user/signs_lib/textures diff --git a/mods/signs_lib/util/create-signs-lib-overlay.sh b/mods/signs_lib/util/create-signs-lib-overlay.sh new file mode 100644 index 00000000..caed6757 --- /dev/null +++ b/mods/signs_lib/util/create-signs-lib-overlay.sh @@ -0,0 +1,8 @@ +mkdir -p "$1/textures" +cat nonascii-$2| +sh write-nonascii.sh "$1/textures" +cat nonascii-$2| +sed 's,.*,sh unicode-numbers.sh "&",'| +sh| +sed 's/.*/signs_lib.unicode_install(&)/'| +sort > "$1/nonascii-$2.lua" diff --git a/mods/signs_lib/util/nonascii-de b/mods/signs_lib/util/nonascii-de new file mode 100644 index 00000000..0b5dfce4 --- /dev/null +++ b/mods/signs_lib/util/nonascii-de @@ -0,0 +1,7 @@ +ä +ö +ü +ß +Ä +Ö +Ü diff --git a/mods/signs_lib/util/nonascii-fr b/mods/signs_lib/util/nonascii-fr new file mode 100644 index 00000000..01747254 --- /dev/null +++ b/mods/signs_lib/util/nonascii-fr @@ -0,0 +1,16 @@ +à +æ +ç +é +è +ê +ô +ù +À +Æ +Ç +É +È +Ê +Ô +Ù diff --git a/mods/signs_lib/util/nonascii-pl b/mods/signs_lib/util/nonascii-pl new file mode 100644 index 00000000..c43767be --- /dev/null +++ b/mods/signs_lib/util/nonascii-pl @@ -0,0 +1,16 @@ +ż +ź +ć +ś +ó +ą +ę +ł +Ż +Ź +Ć +Ś +Ó +Ą +Ę +Ł diff --git a/mods/signs_lib/util/unicode-numbers.sh b/mods/signs_lib/util/unicode-numbers.sh new file mode 100644 index 00000000..c928643b --- /dev/null +++ b/mods/signs_lib/util/unicode-numbers.sh @@ -0,0 +1,22 @@ +( + echo -n "$1"| + xxd -ps| + sed 's/../echo $((0x&))\n/g'| + sh + echo -n "$1"| + iconv -f utf-8 -t utf-32| + xxd -ps| + sed s/fffe0000//| + sed 's/../&\n/g'| + grep .| + tac| + tr " +" " "| + sed 's/ //g'| + sed s/^00//| + sed s/^00//| + sed 's/.*/"&"/' +)| +tr " +" ","| +sed 's/.*/{&}\n/' diff --git a/mods/signs_lib/util/write-ascii.sh b/mods/signs_lib/util/write-ascii.sh new file mode 100644 index 00000000..9ff862bd --- /dev/null +++ b/mods/signs_lib/util/write-ascii.sh @@ -0,0 +1,70 @@ +( + seq $((0x$(echo -n a | xxd -ps))) $((0x$(echo -n z | xxd -ps))) + seq $((0x$(echo -n A | xxd -ps))) $((0x$(echo -n Z | xxd -ps))) + seq $((0x$(echo -n 0 | xxd -ps))) $((0x$(echo -n 9 | xxd -ps))) + echo -n " #$%&'()*+,-./:;<=>?@[]^_{|}~!\"\\\`"| + xxd -ps| + sed 's/../&\n/g'| + grep .| + sed 's/.*/echo $((0x&))/'| + sh +)| +sed 's<^'"'"'"'"'"'"'"'"'>\&"\&"\&>'"'"'\ +/bin/echo -n -e "'"'"'\\\ + "'"$1"'/im-out.png" 2> "'"$1"'/im.err"\ +grep '"'"' width: '"'"' "'"$1"'/im.err"|\ +sed '"'"'s/.* width: //'"'"'|\ +sed '"'"'s/;.*//'"'"'|\ +sed '"'"'s|^|printf \\\"%.0f\\\" |'"'"'|\ +sh|\ +sed '"'"'s%.*%convert\\\ + '"$1"'/im-out.png\\\ + -negate\\\ + -monochrome\\\ + -transparent white\\\ + -crop \\$((\&+1))x15+0+2\\\ + +repage\\\ + '"$1"'/signs_lib_font_15px_&.png%'"'"'|\ +sh -e -x\ +convert\\\ + -debug annotate\\\ + -size 180x180 xc:white\\\ + -font /usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf\\\ + -gravity northwest\\\ + -pointsize 31\\\ + +antialias\\\ + -annotate 0 '"'"'"\ +/bin/echo -n -e "\\x&"|\ +sed '"'"'s>'"'"'"'"'"'"'"'"'>\&"\&"\&>'"'"'\ +/bin/echo -n -e "'"'"'\\\ + "'"$1"'/im-out.png" 2> "'"$1"'/im.err"\ +grep '"'"' width: '"'"' "'"$1"'/im.err"|\ +sed '"'"'s/.* width: //'"'"'|\ +sed '"'"'s/;.*//'"'"'|\ +sed '"'"'s|^|printf \\\"%.0f\\\" |'"'"'|\ +sh|\ +sed '"'"'s%.*%convert\\\ + '"$1"'/im-out.png\\\ + -negate\\\ + -monochrome\\\ + -transparent white\\\ + -crop \\$((\&+1))x31+0+4\\\ + +repage\\\ + '"$1"'/signs_lib_font_31px_&.png%'"'"'|\ +sh -e -x\ +"<'| +sh| +sh -e -x +rm -f "$1/im-out.png" +rm -f "$1/im.err" diff --git a/mods/signs_lib/util/write-nonascii.sh b/mods/signs_lib/util/write-nonascii.sh new file mode 100644 index 00000000..0b3971a0 --- /dev/null +++ b/mods/signs_lib/util/write-nonascii.sh @@ -0,0 +1,57 @@ +sed 's,.*,sh unicode-numbers.sh "&",'| +sh| +sed 's/'"'"'/&"&"&/g'| +sed 's/%/&&/g'| +sed "s,.*,printf '&\\\n',"| +sed "s/\([0-9]*\),/'\nprintf '\\\x%.02x' \1\nprintf '/g"| +sh| +sed 's<{\(.*\)"\(.*\)"} "'"$1"'/im.err"\ +grep '"'"' width: '"'"' "'"$1"'/im.err"|\ +sed '"'"'s/.* width: //'"'"'|\ +sed '"'"'s/;.*//'"'"'|\ +sed '"'"'s|^|printf \\\"%.0f\\\" |'"'"'|\ +sh|\ +sed '"'"'s%.*%convert\\\ + '"$1"'/im-out.png\\\ + -negate\\\ + -monochrome\\\ + -transparent white\\\ + -crop \\$((\&+1))x15+0+2\\\ + +repage\\\ + '"$1"'/signs_lib_font_15px_\2.png%'"'"'|\ +sh -e -x\ +convert\\\ + -debug annotate\\\ + -size 180x180 xc:white\\\ + -font /usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf\\\ + -gravity northwest\\\ + -pointsize 31\\\ + +antialias\\\ + -annotate 0 '"'"'\1'"'"'\\\ + "'"$1"'/im-out.png" 2> "'"$1"'/im.err"\ +grep '"'"' width: '"'"' "'"$1"'/im.err"|\ +sed '"'"'s/.* width: //'"'"'|\ +sed '"'"'s/;.*//'"'"'|\ +sed '"'"'s|^|printf \\\"%.0f\\\" |'"'"'|\ +sh|\ +sed '"'"'s%.*%convert\\\ + '"$1"'/im-out.png\\\ + -negate\\\ + -monochrome\\\ + -transparent white\\\ + -crop \\$((\&+1))x31+0+4\\\ + +repage\\\ + '"$1"'/signs_lib_font_31px_\2.png%'"'"'|\ +sh -e -x"<'| +sh| +sh -e -x +rm -f "$1/im-out.png" +rm -f "$1/im.err" diff --git a/mods/skinsdb/meta/character_1949.txt b/mods/skinsdb/meta/character_1949.txt new file mode 100644 index 00000000..a8861c75 --- /dev/null +++ b/mods/skinsdb/meta/character_1949.txt @@ -0,0 +1,3 @@ +VampireKitty +xXv4mpyrepr1nceXx +CC 0 (1.0) diff --git a/mods/skinsdb/textures/character_1949.png b/mods/skinsdb/textures/character_1949.png new file mode 100644 index 0000000000000000000000000000000000000000..7ec6dac1bbd6b3a9f050dc88611c7f31a7a70fbc GIT binary patch literal 759 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0*pySK~!i%?U=Dn z95E1v*T)e7(iKorB#39AKs2fH0#OWbsK&o`9(nNU-pr9f& zCjsJ)HS^ESEXL=(JA`ldlK7JbFJ7N^XXdwe>@1N;Boc|le~Xc};H8<%;1+^s(3s7!pdbqsL$u8G1)1ZFm!wjiU6qOk@tS4KVP=wa8B12wmLOa^vSS3Fa|ADhd_{xJ^R3XkeBkEMJ5h9w?%+x z!Qug5<`?jC_B`+1`h9ovNJVf&@A)8b{&=9%5cl!hm1fs`>)cinfCe0gqcq?6#Z-oV zKxm~lFwD!>bPq~^QbJtV>uh7T!D@ox8hwM51K>Q?l&YKu1{u?=s0@`*wtzd%AA`A0 z0pjTW*k0hiH~W{|Le?SYFiog&BW_}UaubO#r83jS(On3EE?7cTsZLBCFbH=ci#<2Z+Kds{<-|$S~Y>1$BU2 zR>GtNptd?7`a`_01ZPwnWU6v(RHDnxna6(xeE~ozJ80JikWpkBw!3$b<77w8-z|zF zRN}?&)G($_`T~GDo@|&*S<-M6X9ORCAaLP=lT|XkauL p{yw7)#u9+CbA?gQ8>%DA?g1=8Hwn461$_Vj002ovPDHLkV1gQrPOJa` literal 0 HcmV?d00001 -- 2.25.1 From 829ac8a39029cb0fa9a1fc927a32e1cde7be9920 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 25 Feb 2021 20:49:03 +0100 Subject: [PATCH 7/7] update --- mods/advtrains/advtrains/crafting.lua | 26 + .../advtrains_interlocking/tcb_ts_ui.lua | 10 + .../advtrains_interlocking/tsr_rail.lua | 12 +- mods/advtrains/advtrains_signals_ks/init.lua | 39 +- .../advtrains_train_industrial/init.lua | 42 ++ mods/advtrains/advtrains_train_japan/init.lua | 22 + mods/advtrains/advtrains_train_track/init.lua | 25 +- mods/ambience/init.lua | 2 +- mods/bonemeal/init.lua | 24 +- mods/builtin_item/init.lua | 400 ++++++++----- mods/builtin_item/init.lua_ | 541 ++++++++++++++++++ mods/builtin_item/settingtypes.txt | 40 ++ mods/cottages/nodes_anvil.lua | 6 +- mods/cottages/nodes_straw.lua | 14 +- mods/farming/food.lua | 8 +- mods/farming/locale/zh_CN.txt | 238 ++++---- mods/farming/soil.lua | 2 +- .../homedecor_books/init.lua | 2 +- .../homedecor_lighting/init.lua | 5 +- mods/ilights/init.lua | 5 +- mods/intllib/init.lua | 3 +- mods/skinsdb/meta/character_1950.txt | 3 + mods/skinsdb/textures/character_1950.png | Bin 0 -> 10494 bytes mods/stamina/init.lua | 391 +++++++------ 24 files changed, 1363 insertions(+), 497 deletions(-) create mode 100644 mods/builtin_item/init.lua_ create mode 100644 mods/builtin_item/settingtypes.txt create mode 100644 mods/skinsdb/meta/character_1950.txt create mode 100644 mods/skinsdb/textures/character_1950.png diff --git a/mods/advtrains/advtrains/crafting.lua b/mods/advtrains/advtrains/crafting.lua index cb0813ca..7626d55b 100644 --- a/mods/advtrains/advtrains/crafting.lua +++ b/mods/advtrains/advtrains/crafting.lua @@ -20,6 +20,32 @@ minetest.register_craft({ {'', '', 'default:steel_ingot'}, }, }) +--Wallmounted Signal +minetest.register_craft({ + output = 'advtrains:signal_wall_r_off 2', + recipe = { + {'dye:red', 'default:steel_ingot', 'default:steel_ingot'}, + {'', 'default:steel_ingot', ''}, + {'dye:dark_green', 'default:steel_ingot', 'default:steel_ingot'}, + }, +}) + +--Wallmounted Signals can be converted into every orientation by shapeless crafting +minetest.register_craft({ + output = 'advtrains:signal_wall_l_off', + type = "shapeless", + recipe = {'advtrains:signal_wall_r_off'}, +}) +minetest.register_craft({ + output = 'advtrains:signal_wall_t_off', + type = "shapeless", + recipe = {'advtrains:signal_wall_l_off'}, +}) +minetest.register_craft({ + output = 'advtrains:signal_wall_r_off', + type = "shapeless", + recipe = {'advtrains:signal_wall_t_off'}, +}) --trackworker minetest.register_craft({ diff --git a/mods/advtrains/advtrains_interlocking/tcb_ts_ui.lua b/mods/advtrains/advtrains_interlocking/tcb_ts_ui.lua index 3952f91d..38d4453e 100644 --- a/mods/advtrains/advtrains_interlocking/tcb_ts_ui.lua +++ b/mods/advtrains/advtrains_interlocking/tcb_ts_ui.lua @@ -118,6 +118,16 @@ minetest.register_node("advtrains_interlocking:tcb_node", { end, }) + +-- Crafting +minetest.register_craft({ + output = 'advtrains_interlocking:tcb_node 4', + recipe = { + {'mesecons:wire_00000000_off', 'basic_materials:ic', 'mesecons:wire_00000000_off'}, + }, +}) + + minetest.register_on_punchnode(function(pos, node, player, pointed_thing) local pname = player:get_player_name() if not minetest.check_player_privs(pname, "interlocking") then diff --git a/mods/advtrains/advtrains_interlocking/tsr_rail.lua b/mods/advtrains/advtrains_interlocking/tsr_rail.lua index a500c8f2..f3025406 100644 --- a/mods/advtrains/advtrains_interlocking/tsr_rail.lua +++ b/mods/advtrains/advtrains_interlocking/tsr_rail.lua @@ -23,6 +23,16 @@ local adefunc = function(def, preset, suffix, rotation) advtrains.interlocking.npr_rails[pe] = nil end, on_receive_fields = function(pos, formname, fields, player) + local pname = player:get_player_name() + if not minetest.check_player_privs(pname, {interlocking=true}) then + minetest.chat_send_player(pname, "Interlocking privilege required!") + return + end + if minetest.is_protected(pos, pname) then + minetest.chat_send_player(pname, "This rail is protected!") + minetest.record_protection_violation(pos, pname) + return + end if fields.npr then local pe = advtrains.encode_pos(pos) advtrains.interlocking.npr_rails[pe] = tonumber(fields.npr) @@ -53,4 +63,4 @@ if minetest.get_modpath("advtrains_train_track") ~= nil then formats={}, get_additional_definiton = adefunc, }, advtrains.trackpresets.t_30deg_straightonly) -end \ No newline at end of file +end diff --git a/mods/advtrains/advtrains_signals_ks/init.lua b/mods/advtrains/advtrains_signals_ks/init.lua index 08bbb75c..1c60a0eb 100644 --- a/mods/advtrains/advtrains_signals_ks/init.lua +++ b/mods/advtrains/advtrains_signals_ks/init.lua @@ -199,7 +199,7 @@ for _, rtab in ipairs({ save_in_at_nodedb = 1, not_in_creative_inventory = (rtab.ici and prts.ici) and 0 or 1, }, - drop = "advtrains_signals_ks:sign_e_0", + drop = "advtrains_signals_ks:sign_8_0", inventory_image = "advtrains_signals_ks_sign_8.png", sounds = default.node_sound_stone_defaults(), advtrains = { @@ -241,3 +241,40 @@ for _, rtab in ipairs({ advtrains.trackplacer.add_worked("advtrains_signals_ks:mast","mast", "_"..rot) end +-- Crafting + +minetest.register_craft({ + output = "advtrains_signals_ks:hs_danger_0 2", + recipe = { + {'default:steel_ingot', 'dye:red', 'default:steel_ingot'}, + {'dye:yellow', 'default:steel_ingot', 'dye:dark_green'}, + {'default:steel_ingot', 'advtrains_signals_ks:mast_mast_0', 'default:steel_ingot'}, + }, +}) + +minetest.register_craft({ + output = "advtrains_signals_ks:mast_mast_0 10", + recipe = { + {'default:steel_ingot'}, + {'dye:cyan'}, + {'default:steel_ingot'}, + }, +}) + +minetest.register_craft({ + output = "advtrains_signals_ks:ra_danger_0 2", + recipe = { + {'dye:red', 'dye:white', 'dye:red'}, + {'dye:white', 'default:steel_ingot', 'default:steel_ingot'}, + {'default:steel_ingot', 'advtrains_signals_ks:mast_mast_0', 'default:steel_ingot'}, + }, +}) + +minetest.register_craft({ + output = "advtrains_signals_ks:sign_8_0 2", + recipe = { + {'basic_materials:plastic_sheet', 'dye:black'}, + {'default:stick', ''}, + {'default:stick', ''}, + }, +}) diff --git a/mods/advtrains/advtrains_train_industrial/init.lua b/mods/advtrains/advtrains_train_industrial/init.lua index beec5b34..dde7d83f 100644 --- a/mods/advtrains/advtrains_train_industrial/init.lua +++ b/mods/advtrains/advtrains_train_industrial/init.lua @@ -105,3 +105,45 @@ advtrains.register_wagon("wagon_wood", { box=8*3, }, }, S("Industrial wood wagon"), "advtrains_wagon_wood_inv.png") + +-- Craftings + +minetest.register_craft({ + output = 'advtrains:engine_industrial', + recipe = { + {'default:steelblock', 'default:steelblock', 'default:steelblock'}, + {'advtrains:driver_cab', 'default:steelblock', 'default:steelblock'}, + {'advtrains:wheel', '', 'advtrains:wheel'}, + }, +}) + +--Engine Industrial Big +minetest.register_craft({ + output = 'advtrains:engine_industrial_big', + recipe = { + {'default:glass', 'default:steelblock', 'default:steelblock'}, + {'advtrains:driver_cab', 'default:steelblock', 'default:steelblock'}, + {'advtrains:wheel', 'advtrains:wheel', 'advtrains:wheel'}, + }, +}) + + +--Industrial tank wagon +minetest.register_craft({ + output = 'advtrains:wagon_tank', + recipe = { + {'default:steelblock', 'default:steel_ingot', 'default:steelblock'}, + {'advtrains:steelblock', '', 'default:steelblock'}, + {'advtrains:wheel', 'default:steelblock', 'advtrains:wheel'}, + }, +}) + +--Industrial wood wagon +minetest.register_craft({ + output = 'advtrains:wagon_wood', + recipe = { + {'default:steel_ingot', '', 'default:steel_ingot'}, + {'advtrains:steelblock', 'default:steelblock', 'default:steelblock'}, + {'advtrains:wheel', '', 'advtrains:wheel'}, + }, +}) diff --git a/mods/advtrains/advtrains_train_japan/init.lua b/mods/advtrains/advtrains_train_japan/init.lua index 1aa27713..a7848454 100644 --- a/mods/advtrains/advtrains_train_japan/init.lua +++ b/mods/advtrains/advtrains_train_japan/init.lua @@ -138,3 +138,25 @@ advtrains.register_wagon("wagon_japan", { drops={"default:steelblock 4"}, }, S("Japanese Train Wagon"), "advtrains_wagon_japan_inv.png") +-- Crafting + +minetest.register_craft({ + output = 'advtrains:engine_japan', + recipe = { + {'default:steelblock', 'default:steelblock', ''}, + {'xpanes:pane_flat', 'default:steelblock', 'xpanes:pane_flat'}, + {'advtrains:wheel', 'advtrains:wheel', 'advtrains:wheel'}, + }, +}) + +minetest.register_craft({ +output = 'advtrains:wagon_japan', + recipe = { + {'default:steelblock', 'default:steelblock', 'default:steelblock'}, + {'xpanes:pane_flat', 'default:steelblock', 'xpanes:pane_flat'}, + {'advtrains:wheel', '', 'advtrains:wheel'}, + }, +}) + + + diff --git a/mods/advtrains/advtrains_train_track/init.lua b/mods/advtrains/advtrains_train_track/init.lua index 7f1f73c4..78d1392b 100644 --- a/mods/advtrains/advtrains_train_track/init.lua +++ b/mods/advtrains/advtrains_train_track/init.lua @@ -298,6 +298,29 @@ advtrains.register_tracks("default", { end }, advtrains.trackpresets.t_30deg_straightonly) +minetest.register_craft({ + type="shapeless", + output = 'advtrains:dtrack_load_placer', + recipe = { + "advtrains:dtrack_placer", + "basic_materials:ic", + "default:chest" + }, +}) +minetest.register_craft({ + type="shapeless", + output = 'advtrains:dtrack_unload_placer', + recipe = { + "advtrains:dtrack_load_placer", + }, +}) +minetest.register_craft({ + type="shapeless", + output = 'advtrains:dtrack_load_placer', + recipe = { + "advtrains:dtrack_unload_placer", + }, +}) if mesecon then @@ -361,7 +384,7 @@ if mesecon then } end }, advtrains.ap.t_30deg_straightonly_noplacer) - minetest.register_craft({ +minetest.register_craft({ type="shapeless", output = 'advtrains:dtrack_detector_off_placer', recipe = { diff --git a/mods/ambience/init.lua b/mods/ambience/init.lua index e9cac034..1f7bb4f0 100644 --- a/mods/ambience/init.lua +++ b/mods/ambience/init.lua @@ -125,7 +125,7 @@ local get_ambience = function(player, tod, name) -- get foot and head level nodes at player position - local pos = player:get_pos() + local pos = player:get_pos() ; if not pos then return end pos.y = pos.y + 1.4 -- head level diff --git a/mods/bonemeal/init.lua b/mods/bonemeal/init.lua index 6f289224..71cff14c 100644 --- a/mods/bonemeal/init.lua +++ b/mods/bonemeal/init.lua @@ -63,24 +63,22 @@ local dry_grass = { "default:dry_grass_5", "", "" } --- add all in-game flowers except waterlily +-- loads mods then add all in-game flowers except waterlily local flowers = {} -for node, def in pairs(minetest.registered_nodes) do +minetest.after(0.1, function() - if def.groups.flower and not node:find("waterlily") then - flowers[#flowers + 1] = node + for node, def in pairs(minetest.registered_nodes) do + + if def.groups + and def.groups.flower + and not node:find("waterlily") + and not node:find("xdecor:potted_") then + flowers[#flowers + 1] = node + end end -end +end) --- add additional bakedclay flowers if enabled -if minetest.get_modpath("bakedclay") then - flowers[#flowers + 1] = "bakedclay:delphinium" - flowers[#flowers + 1] = "bakedclay:thistle" - flowers[#flowers + 1] = "bakedclay:lazarus" - flowers[#flowers + 1] = "bakedclay:mannagrass" - flowers[#flowers + 1] = "" -end -- default biomes deco local deco = { diff --git a/mods/builtin_item/init.lua b/mods/builtin_item/init.lua index f98efdee..84124875 100644 --- a/mods/builtin_item/init.lua +++ b/mods/builtin_item/init.lua @@ -22,28 +22,30 @@ end -- If item_entity_ttl is not set, enity will have default life time -- Setting it to -1 disables the feature - local time_to_live = tonumber(core.settings:get("item_entity_ttl")) or 900 local gravity = tonumber(core.settings:get("movement_gravity")) or 9.81 local destroy_item = core.settings:get_bool("destroy_item") ~= false --- water flow functions by QwertyMine3, edited by TenPlus1 -local inv_roots = { - [0] = 1 -} +-- localize some math functions +local abs = math.abs +local sqrt = math.sqrt + + +-- water flow functions by QwertyMine3, edited by TenPlus1 and Gustavo6046 +local inv_roots = {[0] = 1} local function to_unit_vector(dir_vector) local sum = dir_vector.x * dir_vector.x + dir_vector.z * dir_vector.z - local invr_sum = 0 + local invr_sum -- find inverse square root if possible if inv_roots[sum] ~= nil then invr_sum = inv_roots[sum] else -- not found, compute and save the inverse square root - invr_sum = 1.0 / math.sqrt(sum) + invr_sum = 1.0 / sqrt(sum) inv_roots[sum] = invr_sum end @@ -104,9 +106,6 @@ local function quick_flow_logic(node, pos_testing, direction) end --- reciprocal of the length of an unit square's diagonal -local DIAG_WEIGHT = 2 / math.sqrt(2) - local function quick_flow(pos, node) local x, z = 0.0, 0.0 @@ -118,7 +117,6 @@ local function quick_flow(pos, node) return to_unit_vector({x = x, y = 0, z = z}) end --- END water flow functions -- particle effects for when item is destroyed @@ -141,10 +139,19 @@ local function add_effects(pos) }) end +-- print vector, helpful when debugging +local function vec_print(head, vec) + print(head, vec.x, vec.y, vec.z) +end + + +local water_force = tonumber(minetest.settings:get("builtin_item.waterflow_force") or 1.6) +local water_drag = tonumber(minetest.settings:get("builtin_item.waterflow_drag") or 0.8) +local dry_friction = tonumber(minetest.settings:get("builtin_item.friction_dry") or 2.5) +local air_drag = tonumber(minetest.settings:get("builtin_item.air_drag") or 0.4) +local items_collect_on_slippery = tonumber( + minetest.settings:get("builtin_item.items_collect_on_slippery") or 1) ~= 0 -local water_force = 0.8 -local water_friction = 0.8 -local dry_friction = 2.5 core.register_entity(":__builtin:item", { @@ -159,14 +166,17 @@ core.register_entity(":__builtin:item", { spritediv = {x = 1, y = 1}, initial_sprite_basepos = {x = 0, y = 0}, is_visible = false, - infotext = "", + infotext = "" }, itemstring = "", - moving_state = true, + falling_state = true, slippery_state = false, + waterflow_state = false, age = 0, + accel = {x = 0, y = 0, z = 0}, + set_item = function(self, item) local stack = ItemStack(item or self.itemstring) @@ -187,8 +197,8 @@ core.register_entity(":__builtin:item", { local c1, c2 = "","" if not(stack:get_count() == 1) then - c1 = " x"..tostring(stack:get_count()) - c2 = " "..tostring(stack:get_count()) + c1 = " x" .. tostring(stack:get_count()) + c2 = " " .. tostring(stack:get_count()) end local name1 = stack:get_meta():get_string("description") @@ -200,11 +210,14 @@ core.register_entity(":__builtin:item", { name = name1 end + -- small random size bias to counter Z-fighting + local bias = math.random() * 1e-3 + self.object:set_properties({ is_visible = true, visual = "wielditem", textures = {itemname}, - visual_size = {x = size, y = size}, + visual_size = {x = size + bias, y = size + bias, z = size + bias}, collisionbox = {-size, -col_height, -size, size, col_height, size}, selectionbox = {-size, -size, -size, size, size, size}, automatic_rotate = 0.314 / size, @@ -217,11 +230,13 @@ core.register_entity(":__builtin:item", { get_staticdata = function(self) - return core.serialize({ + local data = { itemstring = self.itemstring, age = self.age, dropped_by = self.dropped_by - }) + } + + return core.serialize(data) end, on_activate = function(self, staticdata, dtime_s) @@ -240,8 +255,6 @@ core.register_entity(":__builtin:item", { end self.object:set_armor_groups({immortal = 1}) - self.object:set_velocity({x = 0, y = 2, z = 0}) - self.object:set_acceleration({x = 0, y = -gravity, z = 0}) self:set_item() end, @@ -271,11 +284,23 @@ core.register_entity(":__builtin:item", { -- Merge the remote stack into this one local pos = object:get_pos() + pos.y = pos.y + ((total_count - count) / max_count) * 0.15 self.object:move_to(pos) self.age = 0 -- Handle as new entity + -- Merge velocities + local vel_a = self.object:get_velocity() + local vel_b = object:get_velocity() + + self.object:set_velocity({ + x = (vel_a.x + vel_b.x) / 2, + y = (vel_a.y + vel_b.y) / 2, + z = (vel_a.z + vel_b.z) / 2 + }) + + -- Merge stacks own_stack:set_count(total_count) self:set_item(own_stack) @@ -285,22 +310,10 @@ core.register_entity(":__builtin:item", { return true end, - on_step = function(self, dtime, moveresult) + step_update_node_state = function(self, moveresult, dtime) local pos = self.object:get_pos() - self.age = self.age + dtime - - if time_to_live > 0 and self.age > time_to_live then - - self.itemstring = "" - self.object:remove() - - add_effects(pos) - - return - end - -- get nodes every 1/4 second self.timer = (self.timer or 0) + dtime @@ -312,6 +325,7 @@ core.register_entity(":__builtin:item", { -- get ground node for collision self.node_under = nil + self.falling_state = true if moveresult.touching_ground then @@ -320,6 +334,7 @@ core.register_entity(":__builtin:item", { if info.axis == "y" then self.node_under = core.get_node(info.node_pos) + self.falling_state = false break end @@ -327,12 +342,17 @@ core.register_entity(":__builtin:item", { end self.def_under = self.node_under - and core.registered_nodes[self.node_under.name] + and core.registered_nodes[self.node_under.name] self.timer = 0 end + end, + step_node_inside_checks = function(self) + + local pos = self.object:get_pos() local node = self.node_inside + local def = self.def_inside -- Delete in 'ignore' nodes if node and node.name == "ignore" then @@ -340,24 +360,23 @@ core.register_entity(":__builtin:item", { self.itemstring = "" self.object:remove() - return + return true end - -- do custom step function - local name = ItemStack(self.itemstring):get_name() or "" - local custom = core.registered_items[name] - and core.registered_items[name].dropped_step + -- item inside block, move to vacant space + if def and (def.walkable == nil or def.walkable == true) + and (def.collision_box == nil or def.collision_box.type == "regular") + and (def.node_box == nil or def.node_box.type == "regular") then - if custom and custom(self, pos, dtime) == false then - return -- skip further checks if false + local npos = minetest.find_node_near(pos, 1, "air") + + if npos then + self.object:move_to(npos) + end + + self.node_inside = nil -- force get_node end - local vel = self.object:get_velocity() - local def = self.def_inside - local is_slippery = false - local is_moving = (def and not def.walkable) or - vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0 - -- destroy item when dropped into lava (if enabled) if destroy_item and def and def.groups and def.groups.lava then @@ -372,125 +391,156 @@ core.register_entity(":__builtin:item", { add_effects(pos) + return true + end + + return false + end, + + step_check_slippery = function(self) + + -- don't check for slippery ground if we're not on + -- any ground to begin with + local node = self.node_under + local def = self.def_under + + if self.falling_state or not node then + self.slippery_state = false return end - -- water flowing - if def and def.liquidtype == "flowing" then - - -- force applies on acceleration over time, thus multiply - local force = water_force * dtime - -- friction applies on velocity over time, thus exponentiate - local friction = (1.0 + water_friction) ^ dtime - - -- get flow velocity and current vel/acc state - local vec = quick_flow(pos, node) - local a = self.object:get_acceleration() - - self.object:set_acceleration({ - x = a.x + vec.x * force, - y = a.y, - z = a.z + vec.z * force - }) - - -- apply friction to prevent items going too fast, and also to make - -- water flow override previous horizontal momentum more quickly - - local v = self.object:get_velocity() - - -- adjust friction for going against the current - local v_horz = { x = v.x, y = 0, z = v.z } - local v_dir = to_unit_vector(v_horz) - local flow_dot = v_dir.x * vec.x + v_dir.y * vec.y - - -- also maps flow_dot from [-1,0] to [0.5,2.5] - friction = 1.0 + ((friction - 1.0) * (flow_dot + 1.5)) - - self.object:set_velocity({ - x = v.x / friction, - y = v.y / friction, - z = v.z / friction - }) - - return - end - - -- item inside block, move to vacant space - if def and (def.walkable == nil or def.walkable == true) - and (def.collision_box == nil or def.collision_box.type == "regular") - and (def.node_box == nil or def.node_box.type == "regular") then - - local npos = minetest.find_node_near(pos, 1, "air") - - if npos then - self.object:move_to(npos) - end - - self.node_inside = nil -- force get_node - - return - end - - -- Switch locals to node under - node = self.node_under - def = self.def_under - - - -- Slippery node check - if def and def.walkable then + if node and def and def.walkable then local slippery = core.get_item_group(node.name, "slippery") - is_slippery = slippery ~= 0 + self.slippery_state = slippery ~= 0 + end + end, - if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then + step_water_physics = function(self) - -- Horizontal deceleration + local pos = self.object:get_pos() + local vel = self.object:get_velocity() + local node = self.node_inside + local def = self.def_inside + + self.waterflow_state = def and def.liquidtype == "flowing" + + if self.waterflow_state then + + -- get flow velocity + local flow_vel = quick_flow(pos, node) + + -- calculate flow force and drag + local flow_force_x = flow_vel.x * water_force + local flow_force_z = flow_vel.z * water_force + + local flow_drag_x = (flow_force_x - vel.x) * water_drag + local flow_drag_z = (flow_force_z - vel.z) * water_drag + + -- apply water force and friction + self.accel.x = self.accel.x + flow_force_x + flow_drag_x + self.accel.z = self.accel.z + flow_force_z + flow_drag_z + end + end, + + step_air_drag_physics = function(self) + + local vel = self.object:get_velocity() + + -- apply air drag + if self.falling_state or (self.slippery_state and not self.waterflow_state) then + self.accel.x = self.accel.x - vel.x * air_drag + self.accel.z = self.accel.z - vel.z * air_drag + end + end, + + step_gravity = function(self) + + if self.falling_state then + self.accel.y = self.accel.y - gravity + end + end, + + step_ground_friction = function(self) + + -- don't apply ground friction when falling! + if self.falling_state then + return + end + + local vel = self.object:get_velocity() + + if self.slippery_state then + + local node = self.node_under + + -- apply slip factor (tiny friction that depends on the actual block type) + if (abs(vel.x) > 0.2 or abs(vel.z) > 0.2) then + + local slippery = core.get_item_group(node.name, "slippery") local slip_factor = 4.0 / (slippery + 4) - self.object:set_acceleration({ - x = -vel.x * slip_factor, - y = 0, - z = -vel.z * slip_factor - }) - - elseif vel.y == 0 then - is_moving = false + self.accel.x = self.accel.x - vel.x * slip_factor + self.accel.z = self.accel.z - vel.z * slip_factor end - end - if self.moving_state == is_moving - and self.slippery_state == is_slippery then - return -- No further updates until moving state changes - end - - self.moving_state = is_moving - self.slippery_state = is_slippery - - local a_curr = self.object:get_acceleration() - local v_curr = self.object:get_velocity() - - if is_moving then - - self.object:set_acceleration({ - x = a_curr.x, - y = a_curr.y - gravity, - z = a_curr.z - }) else - self.object:set_acceleration({x = 0, y = 0, z = 0}) + self.accel.x = self.accel.x - vel.x * dry_friction + self.accel.z = self.accel.z - vel.z * dry_friction + end + end, - -- preserve *some* velocity so items don't get stuck on the very ledges - -- of nodes once they move just enough to leave the hitbox of flowing water - self.object:set_velocity({ - x = v_curr.x / dry_friction, - y = v_curr.y / dry_friction, - z = v_curr.z / dry_friction - }) + step_apply_forces = function(self) + self.object:set_acceleration(self.accel) + end, + + step_check_timeout = function(self, dtime) + + local pos = self.object:get_pos() + + self.age = self.age + dtime + + if time_to_live > 0 and self.age > time_to_live then + + self.itemstring = "" + self.object:remove() + + add_effects(pos) + + return true end - --Only collect items if not moving - if is_moving then + return false + end, + + step_check_custom_step = function(self, dtime, moveresult) + + local pos = self.object:get_pos() + + -- do custom step function + local name = ItemStack(self.itemstring):get_name() or "" + local custom = core.registered_items[name] + and core.registered_items[name].dropped_step + + if custom and custom(self, pos, dtime, moveresult) == false then + return true -- skip further checks if false + end + + return false + end, + + step_try_collect = function(self) + + local self_pos = self.object:get_pos() + + -- Don't collect items if falling + if self.falling_state then + return + end + + -- Check if we should collect items while sliding + if self.slippery_state and not items_collect_on_slippery then return end @@ -501,16 +551,19 @@ core.register_entity(":__builtin:item", { return end - local objects = core.get_objects_inside_radius(pos, 1.0) + local objects = core.get_objects_inside_radius(self_pos, 1.0) - for k, obj in pairs(objects) do + for _, obj in pairs(objects) do local entity = obj:get_luaentity() - if entity and entity.name == "__builtin:item" then + if entity and entity.name == "__builtin:item" and not entity.is_falling then if self:try_merge_with(own_stack, obj, entity) then + -- item will be moved up due to try_merge_with + self.falling_state = true + own_stack = ItemStack(self.itemstring) if own_stack:get_free_space() == 0 then @@ -521,6 +574,41 @@ core.register_entity(":__builtin:item", { end end, + on_step = function(self, dtime, moveresult) + + -- reset acceleration + self.accel = {x = 0, y = 0, z = 0} + + -- check item timeout + if self:step_check_timeout(dtime) then + return -- deleted, stop here + end + + -- check custom step function + if self:step_check_custom_step(dtime, moveresult) then + return -- overriden + end + + -- do general checks + self:step_update_node_state(moveresult, dtime) + + if self:step_node_inside_checks() then + return -- destroyed + end + + self:step_check_slippery() + + -- do physics checks, then apply + self:step_water_physics() + self:step_ground_friction() + self:step_gravity() + + self:step_apply_forces() + + -- do item checks + self:step_try_collect() + end, + on_punch = function(self, hitter) local inv = hitter:get_inventory() diff --git a/mods/builtin_item/init.lua_ b/mods/builtin_item/init.lua_ new file mode 100644 index 00000000..f98efdee --- /dev/null +++ b/mods/builtin_item/init.lua_ @@ -0,0 +1,541 @@ +-- Minetest: builtin/item_entity.lua + +-- override ice to make slippery for 0.4.16 +if not minetest.raycast then + minetest.override_item("default:ice", { + groups = {cracky = 3, puts_out_fire = 1, cools_lava = 1, slippery = 3}}) +end + + +function core.spawn_item(pos, item) + + local stack = ItemStack(item) + local obj = core.add_entity(pos, "__builtin:item") + + if obj then + obj:get_luaentity():set_item(stack:to_string()) + end + + return obj +end + + +-- If item_entity_ttl is not set, enity will have default life time +-- Setting it to -1 disables the feature + +local time_to_live = tonumber(core.settings:get("item_entity_ttl")) or 900 +local gravity = tonumber(core.settings:get("movement_gravity")) or 9.81 +local destroy_item = core.settings:get_bool("destroy_item") ~= false + + +-- water flow functions by QwertyMine3, edited by TenPlus1 +local inv_roots = { + [0] = 1 +} + +local function to_unit_vector(dir_vector) + + local sum = dir_vector.x * dir_vector.x + dir_vector.z * dir_vector.z + local invr_sum = 0 + + -- find inverse square root if possible + if inv_roots[sum] ~= nil then + invr_sum = inv_roots[sum] + else + -- not found, compute and save the inverse square root + invr_sum = 1.0 / math.sqrt(sum) + inv_roots[sum] = invr_sum + end + + return { + x = dir_vector.x * invr_sum, + y = dir_vector.y, + z = dir_vector.z * invr_sum + } +end + + +local function node_ok(pos) + + local node = minetest.get_node_or_nil(pos) + + if node and minetest.registered_nodes[node.name] then + return node + end + + return minetest.registered_nodes["default:dirt"] +end + + +local function quick_flow_logic(node, pos_testing, direction) + + local node_testing = node_ok(pos_testing) + local param2 = node.param2 + + if not minetest.registered_nodes[node.name].groups.liquid then + param2 = 0 + end + + if minetest.registered_nodes[node_testing.name].liquidtype ~= "flowing" + and minetest.registered_nodes[node_testing.name].liquidtype ~= "source" then + return 0 + end + + local param2_testing = node_testing.param2 + + if param2_testing < param2 then + + if (param2 - param2_testing) > 6 then + return -direction + else + return direction + end + + elseif param2_testing > param2 then + + if (param2_testing - param2) > 6 then + return direction + else + return -direction + end + end + + return 0 +end + + +-- reciprocal of the length of an unit square's diagonal +local DIAG_WEIGHT = 2 / math.sqrt(2) + +local function quick_flow(pos, node) + + local x, z = 0.0, 0.0 + + x = x + quick_flow_logic(node, {x = pos.x - 1, y = pos.y, z = pos.z},-1) + x = x + quick_flow_logic(node, {x = pos.x + 1, y = pos.y, z = pos.z}, 1) + z = z + quick_flow_logic(node, {x = pos.x, y = pos.y, z = pos.z - 1},-1) + z = z + quick_flow_logic(node, {x = pos.x, y = pos.y, z = pos.z + 1}, 1) + + return to_unit_vector({x = x, y = 0, z = z}) +end +-- END water flow functions + + +-- particle effects for when item is destroyed +local function add_effects(pos) + + minetest.add_particlespawner({ + amount = 1, + time = 0.25, + minpos = pos, + maxpos = pos, + minvel = {x = -1, y = 2, z = -1}, + maxvel = {x = 1, y = 4, z = 1}, + minacc = {x = 0, y = 0, z = 0}, + maxacc = {x = 0, y = 0, z = 0}, + minexptime = 1, + maxexptime = 3, + minsize = 1, + maxsize = 4, + texture = "tnt_smoke.png", + }) +end + + +local water_force = 0.8 +local water_friction = 0.8 +local dry_friction = 2.5 + +core.register_entity(":__builtin:item", { + + initial_properties = { + hp_max = 1, + physical = true, + collide_with_objects = false, + collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3}, + visual = "wielditem", + visual_size = {x = 0.4, y = 0.4}, + textures = {""}, + spritediv = {x = 1, y = 1}, + initial_sprite_basepos = {x = 0, y = 0}, + is_visible = false, + infotext = "", + }, + + itemstring = "", + moving_state = true, + slippery_state = false, + age = 0, + + set_item = function(self, item) + + local stack = ItemStack(item or self.itemstring) + + self.itemstring = stack:to_string() + + if self.itemstring == "" then + return + end + + local itemname = stack:is_known() and stack:get_name() or "unknown" + local max_count = stack:get_stack_max() + local count = math.min(stack:get_count(), max_count) + local size = 0.2 + 0.1 * (count / max_count) ^ (1 / 3) + local col_height = size * 0.75 + local def = core.registered_nodes[itemname] + local glow = def and def.light_source + local c1, c2 = "","" + + if not(stack:get_count() == 1) then + c1 = " x"..tostring(stack:get_count()) + c2 = " "..tostring(stack:get_count()) + end + + local name1 = stack:get_meta():get_string("description") + local name + + if name1 == "" then + name = core.registered_items[itemname].description + else + name = name1 + end + + self.object:set_properties({ + is_visible = true, + visual = "wielditem", + textures = {itemname}, + visual_size = {x = size, y = size}, + collisionbox = {-size, -col_height, -size, size, col_height, size}, + selectionbox = {-size, -size, -size, size, size, size}, + automatic_rotate = 0.314 / size, + wield_item = self.itemstring, + glow = glow, + infotext = name .. c1 .. "\n(" .. itemname .. c2 .. ")" + }) + + end, + + get_staticdata = function(self) + + return core.serialize({ + itemstring = self.itemstring, + age = self.age, + dropped_by = self.dropped_by + }) + end, + + on_activate = function(self, staticdata, dtime_s) + + if string.sub(staticdata, 1, string.len("return")) == "return" then + + local data = core.deserialize(staticdata) + + if data and type(data) == "table" then + self.itemstring = data.itemstring + self.age = (data.age or 0) + dtime_s + self.dropped_by = data.dropped_by + end + else + self.itemstring = staticdata + end + + self.object:set_armor_groups({immortal = 1}) + self.object:set_velocity({x = 0, y = 2, z = 0}) + self.object:set_acceleration({x = 0, y = -gravity, z = 0}) + self:set_item() + end, + + try_merge_with = function(self, own_stack, object, entity) + + if self.age == entity.age then + return false -- Can not merge with itself + end + + local stack = ItemStack(entity.itemstring) + local name = stack:get_name() + + if own_stack:get_name() ~= name + or own_stack:get_meta() ~= stack:get_meta() + or own_stack:get_wear() ~= stack:get_wear() + or own_stack:get_free_space() == 0 then + return false -- Can not merge different or full stack + end + + local count = own_stack:get_count() + local total_count = stack:get_count() + count + local max_count = stack:get_stack_max() + + if total_count > max_count then + return false + end + + -- Merge the remote stack into this one + local pos = object:get_pos() + pos.y = pos.y + ((total_count - count) / max_count) * 0.15 + + self.object:move_to(pos) + self.age = 0 -- Handle as new entity + + own_stack:set_count(total_count) + self:set_item(own_stack) + + entity.itemstring = "" + object:remove() + + return true + end, + + on_step = function(self, dtime, moveresult) + + local pos = self.object:get_pos() + + self.age = self.age + dtime + + if time_to_live > 0 and self.age > time_to_live then + + self.itemstring = "" + self.object:remove() + + add_effects(pos) + + return + end + + -- get nodes every 1/4 second + self.timer = (self.timer or 0) + dtime + + if self.timer > 0.25 or not self.node_inside then + + self.node_inside = minetest.get_node_or_nil(pos) + self.def_inside = self.node_inside + and core.registered_nodes[self.node_inside.name] + + -- get ground node for collision + self.node_under = nil + + if moveresult.touching_ground then + + for _, info in ipairs(moveresult.collisions) do + + if info.axis == "y" then + + self.node_under = core.get_node(info.node_pos) + + break + end + end + end + + self.def_under = self.node_under + and core.registered_nodes[self.node_under.name] + + self.timer = 0 + end + + local node = self.node_inside + + -- Delete in 'ignore' nodes + if node and node.name == "ignore" then + + self.itemstring = "" + self.object:remove() + + return + end + + -- do custom step function + local name = ItemStack(self.itemstring):get_name() or "" + local custom = core.registered_items[name] + and core.registered_items[name].dropped_step + + if custom and custom(self, pos, dtime) == false then + return -- skip further checks if false + end + + local vel = self.object:get_velocity() + local def = self.def_inside + local is_slippery = false + local is_moving = (def and not def.walkable) or + vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0 + + -- destroy item when dropped into lava (if enabled) + if destroy_item and def and def.groups and def.groups.lava then + + minetest.sound_play("builtin_item_lava", { + pos = pos, + max_hear_distance = 6, + gain = 0.5 + }) + + self.itemstring = "" + self.object:remove() + + add_effects(pos) + + return + end + + -- water flowing + if def and def.liquidtype == "flowing" then + + -- force applies on acceleration over time, thus multiply + local force = water_force * dtime + -- friction applies on velocity over time, thus exponentiate + local friction = (1.0 + water_friction) ^ dtime + + -- get flow velocity and current vel/acc state + local vec = quick_flow(pos, node) + local a = self.object:get_acceleration() + + self.object:set_acceleration({ + x = a.x + vec.x * force, + y = a.y, + z = a.z + vec.z * force + }) + + -- apply friction to prevent items going too fast, and also to make + -- water flow override previous horizontal momentum more quickly + + local v = self.object:get_velocity() + + -- adjust friction for going against the current + local v_horz = { x = v.x, y = 0, z = v.z } + local v_dir = to_unit_vector(v_horz) + local flow_dot = v_dir.x * vec.x + v_dir.y * vec.y + + -- also maps flow_dot from [-1,0] to [0.5,2.5] + friction = 1.0 + ((friction - 1.0) * (flow_dot + 1.5)) + + self.object:set_velocity({ + x = v.x / friction, + y = v.y / friction, + z = v.z / friction + }) + + return + end + + -- item inside block, move to vacant space + if def and (def.walkable == nil or def.walkable == true) + and (def.collision_box == nil or def.collision_box.type == "regular") + and (def.node_box == nil or def.node_box.type == "regular") then + + local npos = minetest.find_node_near(pos, 1, "air") + + if npos then + self.object:move_to(npos) + end + + self.node_inside = nil -- force get_node + + return + end + + -- Switch locals to node under + node = self.node_under + def = self.def_under + + + -- Slippery node check + if def and def.walkable then + + local slippery = core.get_item_group(node.name, "slippery") + + is_slippery = slippery ~= 0 + + if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then + + -- Horizontal deceleration + local slip_factor = 4.0 / (slippery + 4) + + self.object:set_acceleration({ + x = -vel.x * slip_factor, + y = 0, + z = -vel.z * slip_factor + }) + + elseif vel.y == 0 then + is_moving = false + end + end + + if self.moving_state == is_moving + and self.slippery_state == is_slippery then + return -- No further updates until moving state changes + end + + self.moving_state = is_moving + self.slippery_state = is_slippery + + local a_curr = self.object:get_acceleration() + local v_curr = self.object:get_velocity() + + if is_moving then + + self.object:set_acceleration({ + x = a_curr.x, + y = a_curr.y - gravity, + z = a_curr.z + }) + else + self.object:set_acceleration({x = 0, y = 0, z = 0}) + + -- preserve *some* velocity so items don't get stuck on the very ledges + -- of nodes once they move just enough to leave the hitbox of flowing water + self.object:set_velocity({ + x = v_curr.x / dry_friction, + y = v_curr.y / dry_friction, + z = v_curr.z / dry_friction + }) + end + + --Only collect items if not moving + if is_moving then + return + end + + -- Collect the items around to merge with + local own_stack = ItemStack(self.itemstring) + + if own_stack:get_free_space() == 0 then + return + end + + local objects = core.get_objects_inside_radius(pos, 1.0) + + for k, obj in pairs(objects) do + + local entity = obj:get_luaentity() + + if entity and entity.name == "__builtin:item" then + + if self:try_merge_with(own_stack, obj, entity) then + + own_stack = ItemStack(self.itemstring) + + if own_stack:get_free_space() == 0 then + return + end + end + end + end + end, + + on_punch = function(self, hitter) + + local inv = hitter:get_inventory() + + if inv and self.itemstring ~= "" then + + local left = inv:add_item("main", self.itemstring) + + if left and not left:is_empty() then + self:set_item(left) + return + end + end + + self.itemstring = "" + self.object:remove() + end, +}) diff --git a/mods/builtin_item/settingtypes.txt b/mods/builtin_item/settingtypes.txt new file mode 100644 index 00000000..c35098e7 --- /dev/null +++ b/mods/builtin_item/settingtypes.txt @@ -0,0 +1,40 @@ +# Controls how much force should be exerted on +# dropped items when they are pushed by flowing water. +# +# The larger this number, the faster items become when +# carried by water. +waterflow_force (Force of water flow on dropped items) float 1.6 + +# Controls how much drag force should be exerted on +# dropped items when they are submerged in flowing water +# but have a different momentum vector than the flow velocity. +# +# The larger this number, the larger the resistance of water +# to the push of an item. In other words, items thrown at +# flowing water in a direction opposite that of the flow will +# be pushed more quickly in the other direction with higher drag, +# even if the actual flow force remains the same. +waterflow_drag (Drag of water flow on dropped items) float 0.8 + +# Controls how much friction force should be exerted on +# dropped items when they move horizontally on the +# ground. +# +# The larger this number, the quickier items will come to +# a halt horizontally after falling on the floor. +friction_dry (Friction of dry ground on dropped items) float 2.5 + +# Controls how much horizontal drag force should be exerted on +# dropped items when they move horizontally in air. +# +# The larger this number, the quickier horizontal velocity tends +# toward zero. +air_drag (Horizontal drag of air on falling items) float 0.4 + +# Allow items on the floor to collect even on slippery floors. +# +# Dropped items can 'collect', that is, to have their +# stacks merged if they're close enough and are of the same item +# type. By default they can do this even on a slippery floor, like +# ice, but this setting allows disabling that. +builtin_item.items_collect_on_slippery (Collect items on slippery ground) bool true diff --git a/mods/cottages/nodes_anvil.lua b/mods/cottages/nodes_anvil.lua index 9456ed18..cfe04c3a 100644 --- a/mods/cottages/nodes_anvil.lua +++ b/mods/cottages/nodes_anvil.lua @@ -229,9 +229,9 @@ minetest.register_node("cottages:anvil", { end minetest.after(2, function() if( puncher ) then - puncher:hud_remove(hud1); - puncher:hud_remove(hud2); - puncher:hud_remove(hud3); + if(hud1) then puncher:hud_remove(hud1); end + if(hud2) then puncher:hud_remove(hud2); end + if(hud3) then puncher:hud_remove(hud3); end end end) diff --git a/mods/cottages/nodes_straw.lua b/mods/cottages/nodes_straw.lua index d26f6b81..2ac27474 100644 --- a/mods/cottages/nodes_straw.lua +++ b/mods/cottages/nodes_straw.lua @@ -333,13 +333,13 @@ minetest.register_node("cottages:threshing_floor", { minetest.after(2, function() if( puncher ) then - puncher:hud_remove(hud1); - puncher:hud_remove(hud2); - puncher:hud_remove(hud3); - puncher:hud_remove(hud4); - puncher:hud_remove(hud5); - puncher:hud_remove(hud6); - puncher:hud_remove(hud0); + if(hud1) then puncher:hud_remove(hud1); end + if(hud2) then puncher:hud_remove(hud2); end + if(hud3) then puncher:hud_remove(hud3); end + if(hud4) then puncher:hud_remove(hud4); end + if(hud5) then puncher:hud_remove(hud5); end + if(hud6) then puncher:hud_remove(hud6); end + if(hud0) then puncher:hud_remove(hud0); end end end) end, diff --git a/mods/farming/food.lua b/mods/farming/food.lua index 7d30fe61..7f63b8a2 100644 --- a/mods/farming/food.lua +++ b/mods/farming/food.lua @@ -348,7 +348,6 @@ minetest.register_craftitem("farming:pasta", { groups = {food_pasta = 1} }) -if minetest.get_modpath("mobs_animal") or minetest.get_modpath("xanadu")then minetest.register_craft({ output = "farming:pasta", type = "shapeless", @@ -358,7 +357,7 @@ minetest.register_craft({ }, replacements = {{"group:food_mixing_bowl", "farming:mixing_bowl"}} }) -else + minetest.register_craft({ output = "farming:pasta", type = "shapeless", @@ -371,7 +370,6 @@ minetest.register_craft({ {"group:food_oil", "vessels:glass_bottle"} } }) -end -- Spaghetti @@ -399,7 +397,6 @@ minetest.register_craftitem("farming:bibimbap", { on_use = minetest.item_eat(8, "farming:bowl") }) -if minetest.get_modpath("mobs_animal") or minetest.get_modpath("xanadu")then minetest.register_craft({ output = "farming:bibimbap", type = "shapeless", @@ -410,7 +407,7 @@ minetest.register_craft({ }, replacements = {{"group:food_skillet", "farming:skillet"}} }) -else + minetest.register_craft({ output = "farming:bibimbap", type = "shapeless", @@ -421,7 +418,6 @@ minetest.register_craft({ }, replacements = {{"group:food_skillet", "farming:skillet"}} }) -end -- Burger diff --git a/mods/farming/locale/zh_CN.txt b/mods/farming/locale/zh_CN.txt index 302338f2..2ec4e554 100644 --- a/mods/farming/locale/zh_CN.txt +++ b/mods/farming/locale/zh_CN.txt @@ -1,119 +1,119 @@ -Seed=种子 -Banana=香蕉 -Banana Leaves=香蕉叶 -Orange=橙色 -Strawberry=草莓 -Sugar=糖 -Salt=盐 -Rose Water=玫瑰汁 -Turkish Delight=土耳其软糖 -Garlic Bread=蒜香面包 -Donut=甜甜圈 -Chocolate Donut=巧克力甜甜圈 -Apple Donut=苹果甜甜圈 -Porridge=粥 -Jaffa Cake=佳发饼 -Hoe=锄头 -Wooden Hoe=木锄 -Stone Hoe=石锄 -Steel Hoe=钢锄头 -Bronze Hoe=青铜锄头 -Mese Hoe=黄石锄头 -Diamond Hoe=钻石锄 -Hoe Bomb (use or throw on grassy areas to hoe land)=锄弹(在草地上使用或扔在锄地上) -Mithril Scythe (Right-click to harvest and replant crops)=秘银镰刀(右击可收获并重新种植作物) -Soil=土壤 -Wet Soil=湿土 -Wooden Bowl=木碗 -Saucepan=平底锅 -Cooking Pot=锅 -Baking Tray=烤盘 -Skillet=平底锅 -Mortar and Pestle=研钵 -Cutting Board=砧板 -Juicer=榨汁机 -Glass Mixing Bowl=搅拌杯 -Barley Seed=大麦种子 -Barley=大麦 -Green Beans=青豆 -Bean Pole (place on soil before planting beans)=豆杆(种豆前先放在土上) -Beetroot=甜菜根 -Beetroot Soup=甜菜根汤 -Blueberries=蓝莓 -Blueberry Muffin=蓝莓松糕 -Blueberry Pie=蓝莓派 -Carrot=胡萝卜 -Carrot Juice=胡萝卜汁 -Golden Carrot=金萝卜 -Chili Pepper=辣椒 -Bowl of Chili=一碗辣椒 -Cocoa Beans=可可豆 -Cookie=曲奇 -Bar of Dark Chocolate=黑巧克力条 -Chocolate Block=巧克力块 -Coffee Beans=咖啡豆 -Cup of Coffee=一杯咖啡 -Corn=玉米 -Corn on the Cob=玉米棒 -Cornstarch=玉米淀粉 -Bottle of Ethanol=一瓶乙醇 -Cotton Seed=棉籽 -Cotton=棉花 -String=字符串 -Cucumber=黄瓜 -Garlic clove=蒜瓣 -Garlic=大蒜 -Garlic Braid=蒜辫 -Grapes=葡萄 -Trellis (place on soil before planting grapes)=棚架(种植葡萄前先放在土壤上) -Hemp Seed=大麻籽 -Hemp Leaf=大麻叶 -Bottle of Hemp Oil=一瓶大麻油 -Hemp Fibre=大麻纤维 -Hemp Block=麻块 -Hemp Rope=麻绳 -Melon Slice=西瓜片 -Melon=甜瓜 -Onion=洋葱 -Pea Pod=豌豆荚 -Peas=豌豆 -Pea Soup=豌豆汤 -Peppercorn=胡椒粉 -Pepper=胡椒粉 -Ground Pepper=胡椒粉 -Pineapple Top=菠萝上衣 -Pineapple=菠萝 -Pineapple Ring=菠萝圈 -Pineapple Juice=菠萝汁 -Potato=土豆 -Baked Potato=焗马铃薯 -Cucumber and Potato Salad=黄瓜土豆沙拉 -Pumpkin Slice=南瓜片 -Jack 'O Lantern (punch to turn on and off)=杰克灯(按一下开关) -Scarecrow Bottom=稻草人屁股 -Pumpkin Bread=南瓜面包 -Pumpkin Dough=南瓜面团 -Pumpkin=南瓜 -Raspberries=覆盆子 -Raspberry Smoothie=覆盆子冰沙 -Rhubarb=大黄 -Rhubarb Pie=大黄派 -Rye=黑麦 -Rye seed=黑麦种子 -Oat=燕麦 -Oat seed=燕麦籽 -Rice=大米 -Rice grains=稻谷 -Rice Bread=米饭面包 -Rice Flour=米粉 -Multigrain Flour=多粒面粉 -Multigrain Bread=杂粮面包 -Tomato=番茄 -Wheat Seed=小麦种子 -Wheat=小麦 -Straw=稻草 -Flour=面粉 -Bread=面包 -Sliced Bread=切片面包 -Toast=烤面包片 -Toast Sandwich=三明治面包 +Seed=种子 +Banana=香蕉 +Banana Leaves=香蕉叶 +Orange=橙色 +Strawberry=草莓 +Sugar=糖 +Salt=盐 +Rose Water=玫瑰汁 +Turkish Delight=土耳其软糖 +Garlic Bread=蒜香面包 +Donut=甜甜圈 +Chocolate Donut=巧克力甜甜圈 +Apple Donut=苹果甜甜圈 +Porridge=粥 +Jaffa Cake=佳发饼 +Hoe=锄头 +Wooden Hoe=木锄 +Stone Hoe=石锄 +Steel Hoe=钢锄头 +Bronze Hoe=青铜锄头 +Mese Hoe=黄石锄头 +Diamond Hoe=钻石锄 +Hoe Bomb (use or throw on grassy areas to hoe land)=锄弹(在草地上使用或扔在锄地上) +Mithril Scythe (Right-click to harvest and replant crops)=秘银镰刀(右击可收获并重新种植作物) +Soil=土壤 +Wet Soil=湿土 +Wooden Bowl=木碗 +Saucepan=平底锅 +Cooking Pot=锅 +Baking Tray=烤盘 +Skillet=平底锅 +Mortar and Pestle=研钵 +Cutting Board=砧板 +Juicer=榨汁机 +Glass Mixing Bowl=搅拌杯 +Barley Seed=大麦种子 +Barley=大麦 +Green Beans=青豆 +Bean Pole (place on soil before planting beans)=豆杆(种豆前先放在土上) +Beetroot=甜菜根 +Beetroot Soup=甜菜根汤 +Blueberries=蓝莓 +Blueberry Muffin=蓝莓松糕 +Blueberry Pie=蓝莓派 +Carrot=胡萝卜 +Carrot Juice=胡萝卜汁 +Golden Carrot=金萝卜 +Chili Pepper=辣椒 +Bowl of Chili=一碗辣椒 +Cocoa Beans=可可豆 +Cookie=曲奇 +Bar of Dark Chocolate=黑巧克力条 +Chocolate Block=巧克力块 +Coffee Beans=咖啡豆 +Cup of Coffee=一杯咖啡 +Corn=玉米 +Corn on the Cob=玉米棒 +Cornstarch=玉米淀粉 +Bottle of Ethanol=一瓶乙醇 +Cotton Seed=棉籽 +Cotton=棉花 +String=线 +Cucumber=黄瓜 +Garlic clove=蒜瓣 +Garlic=大蒜 +Garlic Braid=蒜辫 +Grapes=葡萄 +Trellis (place on soil before planting grapes)=棚架(种植葡萄前先放在土壤上) +Hemp Seed=大麻籽 +Hemp Leaf=大麻叶 +Bottle of Hemp Oil=一瓶大麻油 +Hemp Fibre=大麻纤维 +Hemp Block=麻块 +Hemp Rope=麻绳 +Melon Slice=西瓜片 +Melon=甜瓜 +Onion=洋葱 +Pea Pod=豌豆荚 +Peas=豌豆 +Pea Soup=豌豆汤 +Peppercorn=胡椒粉 +Pepper=胡椒粉 +Ground Pepper=胡椒粉 +Pineapple Top=菠萝上衣 +Pineapple=菠萝 +Pineapple Ring=菠萝圈 +Pineapple Juice=菠萝汁 +Potato=土豆 +Baked Potato=焗马铃薯 +Cucumber and Potato Salad=黄瓜土豆沙拉 +Pumpkin Slice=南瓜片 +Jack 'O Lantern (punch to turn on and off)=杰克灯(按一下开关) +Scarecrow Bottom=稻草人屁股 +Pumpkin Bread=南瓜面包 +Pumpkin Dough=南瓜面团 +Pumpkin=南瓜 +Raspberries=覆盆子 +Raspberry Smoothie=覆盆子冰沙 +Rhubarb=大黄 +Rhubarb Pie=大黄派 +Rye=黑麦 +Rye seed=黑麦种子 +Oat=燕麦 +Oat seed=燕麦籽 +Rice=大米 +Rice grains=稻谷 +Rice Bread=米饭面包 +Rice Flour=米粉 +Multigrain Flour=多粒面粉 +Multigrain Bread=杂粮面包 +Tomato=番茄 +Wheat Seed=小麦种子 +Wheat=小麦 +Straw=稻草 +Flour=面粉 +Bread=面包 +Sliced Bread=切片面包 +Toast=烤面包片 +Toast Sandwich=三明治面包 diff --git a/mods/farming/soil.lua b/mods/farming/soil.lua index ab8be15b..fbb11f87 100644 --- a/mods/farming/soil.lua +++ b/mods/farming/soil.lua @@ -148,7 +148,7 @@ minetest.register_abm({ if minetest.registered_nodes[nn] and minetest.registered_nodes[nn].walkable and minetest.get_item_group(nn, "plant") == 0 then - minetest.set_node(pos, {name = "default:dirt"}) + minetest.set_node(pos, {name = ndef.soil.base}) return end diff --git a/mods/homedecor_modpack/homedecor_books/init.lua b/mods/homedecor_modpack/homedecor_books/init.lua index 28dd0cbb..59ed57b4 100644 --- a/mods/homedecor_modpack/homedecor_books/init.lua +++ b/mods/homedecor_modpack/homedecor_books/init.lua @@ -27,7 +27,7 @@ for _, c in ipairs(bookcolors) do local color, hue = unpack(c) local function book_dig(pos, node, digger) - if minetest.is_protected(pos, digger:get_player_name()) then return end + if not digger or minetest.is_protected(pos, digger:get_player_name()) then return end local meta = minetest.get_meta(pos) local data = minetest.serialize({ title = meta:get_string("title") or "", diff --git a/mods/homedecor_modpack/homedecor_lighting/init.lua b/mods/homedecor_modpack/homedecor_lighting/init.lua index 9a1cf7d4..ab473868 100644 --- a/mods/homedecor_modpack/homedecor_lighting/init.lua +++ b/mods/homedecor_modpack/homedecor_lighting/init.lua @@ -162,7 +162,10 @@ if minetest.get_modpath("digilines") then if puncher:get_player_control().sneak then local name = puncher:get_player_name() player_last_clicked[name] = pos - local form = "field[channel;Channel;]" + local form = "formspec_version[4]".. + "size[8,4]".. + "button_exit[3,2.5;2,0.5;proceed;Proceed]".. + "field[1.75,1.5;4.5,0.5;channel;Channel;]" minetest.show_formspec(name, "homedecor:lamp_set_channel", form) end end diff --git a/mods/ilights/init.lua b/mods/ilights/init.lua index fe75d4c8..d8e8316b 100644 --- a/mods/ilights/init.lua +++ b/mods/ilights/init.lua @@ -141,7 +141,10 @@ if minetest.get_modpath("digilines") then local name = puncher:get_player_name() player_last_clicked[name] = pos local meta = minetest.get_meta(pos) - local form = "field[channel;Channel;]" + local form = "formspec_version[4]".. + "size[8,4]".. + "button_exit[3,2.5;2,0.5;proceed;Proceed]".. + "field[1.75,1.5;4.5,0.5;channel;Channel;]" minetest.show_formspec(name, "ilights:set_channel", form) end end diff --git a/mods/intllib/init.lua b/mods/intllib/init.lua index 0778a736..7565e013 100644 --- a/mods/intllib/init.lua +++ b/mods/intllib/init.lua @@ -201,7 +201,8 @@ function intllib.get_strings(modname, langcode) local modpath = minetest.get_modpath(modname) msgstr = { } for _, l in ipairs(get_locales(langcode)) do - local t = intllib.load_strings(modpath.."/locale/"..l..".txt") or { } + local t = intllib.load_strings(modpath.."/locale/"..modname.."."..l..".tr") + or intllib.load_strings(modpath.."/locale/"..l..".txt") or { } for k, v in pairs(t) do msgstr[k] = msgstr[k] or v end diff --git a/mods/skinsdb/meta/character_1950.txt b/mods/skinsdb/meta/character_1950.txt new file mode 100644 index 00000000..09d1d103 --- /dev/null +++ b/mods/skinsdb/meta/character_1950.txt @@ -0,0 +1,3 @@ +Effy +aonymous +CC BY-SA 3.0 diff --git a/mods/skinsdb/textures/character_1950.png b/mods/skinsdb/textures/character_1950.png new file mode 100644 index 0000000000000000000000000000000000000000..99c29f17181fef0888866885b49f89010a7b35cb GIT binary patch literal 10494 zcmeHrXIPWlwr=PMN)wPKgrd?DIz)OE5J5l$q=h6vXbDN^RY1B_l`bG4Md>0aAYByc zy>}H`F1Y2aAlbZ3U66&JKY`v0_=n=pg>*5hqH#$pG*X0o6-TT7ReKzM*66O_B<(^z zxr1PqLI)q-?nC6~65pmhZ@;Ez;j5O#tUJ9k)eD|GI}Vy9`wGS5JAj>{bv{3q{HWV1 z$76by1~nV~iY3W)MmgP^5_-Pp7ABoaO9;j$hZ5}HXH@kJ`(|)l<=Yuv)aA8IJp8Z| z_1y-}zB;inq;TLmHA&)eXgWW>*MqyuTGahntJdE#2pYTkZOg~>;ohjgs;+`(?!j9= z`N^wiFT7z9tDCN`bDq~7wj@e{&FPBmum4zhV_`Y@Bcp0_y=F(yX4TbwSh*=@sj?tO z=&|m^h{!92NxG5_)B;w%r2QGw6Ze^oy{NoRmY1e&6XT>;ohrtQH|4)sg*OT%db&H$ z@R|$A*L(@_KkG-~HM(40;`bx)m~`d4nd@rhh!{$)|Js>^WVqs zZX3P3BLI8kATaciK3GuYalhqC6Q`Sh%S~C*Bag!a?s_j-rkG?(R!7}>l`T8VvRvtn zw%*6A+^bT-HB>XM}dTVvxu zA9W^|oHz}U>}bi!t@CL~$WJCV=}x0+yhWvRS^_2IU+h!$#{EJsx{rA#n!9^@ccy$D zva~p!aM*5kSn<%3`cyT%n6lYMV}z#rC?@+Uuyx*q9hjN!vrW$$D2BoR8fqA+w()1D zi51C)kTsVJJMV8#Qg{2Vr=FQr*ht-9ON;w@#QInaGl`Pjc{crKeax_uIYz2YMN5VG z`+5$C)blfI z12Cfb`02rwTg&aQwx`_J!z1pvZAVsK4UuxI6bY&*-l=VBSa>M?wfk(xKt9&Di8(e+F$k zs)S6`J%Zyd+m+|)SAuMIe#km}tu^{GU*NsZ$|y(6HJNZI?|i`_-1!pbW!L06d5|}u zfM?~%q!veJQ&)YX0Q;_IVYXt7!FiB@$`rQf(`E#CfsR0r!~8>8uWf=1JEXtR+cpb*sUZ zyxi0)xCrl?&bDRxjK_X@w^pbI zofuioyzq7Tx=di*9Z833-^S}TQv!Le?&mmIUJai+2=1oDva^7*91j6BsX_J&_Kpf_ z!(suVp|4yZ2~Q*-BNP>*&S$?h+oR#>ijFAFbzopcrluG?@th+$fx);>w3xA3Dj#*q z8;4ms0O1^nX^({v9iW%dxwoMcBp-CS9=TT;y096Ir7p@Wlnd7)<_~_ zEX~tbz)Ao$-%+tfy5qbg))(rJ+^wdXP(oD1be5EVOd`8Y)%1A2 zy-IFOr1-I7Mrd7Cgk$wYUk$4^f&YB z+eTGpRbHceAA8X;zDwz+U*%}H#Kkhm=AsatOEqH~93Jn?(ZUm~OGibUU%#d4eHHdbK|{KqOWrDx+89iBlGPTuY#P49XG4eOs#wH z#Dr8zh5;UxuK{f~FLsxmEmvKhn6u6q6BBA{@jeisuMKVrmc+qx@&sixPFawMXQZZHU|5f{z+xbh?oMMUNK z&^J;+NILz@m@*vuGFK|d+96^$?gWR z(>N$s;{56ub`5m7j6)^uECJ@R&8TIHm`&hS}Op!J1KKPDFe}lb= zntEwjtm`t#B5AJ>g|c))SqHXGY=$=J?m^VX!qcNLvBuFgmdk>AB{!aj-Z}r=$Tt)X zcd@SYHp_!U>CN1yaF?9(&GbGaa#ZEph)L!KZUs+YKBv1Ebq>NqIMlai;TAPptmEQ! zFJpnqZE)|t$8KcZciy8wx9b$9J;h)Sh*0VqmKtHUf{R z-7J{`EjPlksURda3~*i+@X|HxLPQYxDnmet3g-qXkdc@tjOPsKr{pRS?j6G057Wclqm$ucDetOP>rsdN1gaX)= z_z`DbA5CTJE2BL3wAsqM?iK;`B~oa}st{2^A@BHu6Ehtl_W)V~{Mr{sXCxGr>1js? zgI_ytNXsItDdB6A_dE$}IiB!;(prDwNZbxrHfc70S9NBUQ%+r&8))D6^vQ}Rqf0MU z#)B_GfwHqbrz1mQbx^e~7cS_0JFUXoE; zSiZCIb$`>gN>t{(FX@NCG%z)LS$f+MX_0@Z4v{|De0w+L`%Y@(%hRDHga9*&qPwKl zj#*?5t~68TUp~xB3A!2+9Cx$@sf(2Jn8(Yh8f#EVQgiS`2OH=wO$2l(c{g9)KTE92 ztgS1Q=||Z|WthS{JK%Gz=zHd-q)Cz;aeRcT89n>W!DrDG$==bVlD+B61CcLNWSQ%W zxX;xxf5?7z2~|FKR$?b>BgICI|`O)bC9LdZyxtd`Sy)tq^XJHHShDW}p# z1&8*!nD-;8WG6vA3FZE(lLe(57GVG4(s9}qYj5un!k3_)lpX}7Dkvvw6v2rIPHfy# zETbo?3Jaf{XCQy2cy~^?KsLtkQF8HvZR0n75Y8koiuHE{%!kd@dcA3BJgk_9{B{*u zq&XarYEx2H;CQHA?EL&?mp-ENFV(rBYIG_J+96DO#4Jm|ThoyXk>I1C^6} zBYK-VJM9JeJbSe{>qU=-R(kDpZ8lRUiw6-Nq$vsa*#*dMeKO-6;yKQ`I!M*?c_$ZG zE|C;f^!YvWd5f?NuLr(hE~5OxF0{mMgE?#OnYW*hUO*yw!7pf={HWhj3I8xX_IN7e zB;ceqRPrE0@NF*9g(%WeCQ8s@Kc5#BjYtvYOwa4`<62>Y%4-Y{A05W3?0@@Y#l9zN zmhfbprRD9Ri^ZxO7EluR=Yd2*>B~?Nth2HB^U03^R7zI0n zu`+El=hy$t$#XM0zNg+Uc&00X#ZJTlx~tC$9uvK0tNGE!m5cip#e`LhS`*FZ(wl^g zvAs&^5g#PV!2Hei>}%XKv$dFP+G7u`mpw;1EZL%1%kVwNITv8)sYX zXIv!bOm>rjtB^}6b0|h{*Qd9Zm>z7T-4&BBpUW0y5>3wXe8E=lklmn@)sUchMXt|o zlufnbv*$=TChJSO=t6~AnQH`D{$nmREzZ@3JiB1Vk5AN$6-v3(O1bDbH%CY`UklR` zw&gGE@1lM*$0fhN&3s4t;|-EHs%iK_=JTdxJ|4y*$sD6ioI#AgW(S2zqxX+tR-W*} zqKOiiUwcKNjOGnZt~VDLmcJEdz`Cypyx6Yj)4ULMKwh%_;)$IAIZ0u!iKjddW$_gQ zorZ4TfN8laTI-L=RJX}QMehs{ENPt$Bl0N_OE#i468^$L87AGsPP1Kka7l`fT2(vm zg6d=9*%a5bzzzK0kNJKV4!h(q-BugXDcdT2)%Yp% z{%2Yi#lte0^vUDM&c+d&u=d`?a&7bO@Izm!3}sJ+k)irH*_b_ljcyP@By2q%03ZlL zs;KB`s;K;N_JluiO7o4AyVk78)@s>ruf~7z8*nZ*3t~dU;4;8ZpQW77VCo8fwMCi2 z6i7=DJYGDiD@b9^D`+}&zQRE3&QObmgYHdhjg## zF}E7tiNu_i5&idtg=7A4UxlS2>WW-w$-9-?pqw_Ko3mND^E_hRaX;;~Rq&6n>(V{J=BvAM;4 zQVorqVErfGBr@E0aNFCf$wvMPb4D1aYnpJSSm!zfhH?^y!co=;VGk!X z{-_WDkX7(NLtzdG9MBqJi*%ObTCJ()0wUpZT(>23z&dCZgdOsl7Y1SAb;A(mA>@OAZdV)NlXpo37806&iHw!FI z&FwFL|Iz|$h(D19=_9ZxR}2iH=7w;_asTcV?dXdA-KQ%Sanf}fwf3XZ3ONr^yZq~M}L){+P)ov47fGFu{%5jMbga7K$bA;k-P#7mUuIor=SC79243SO< z103{3G!aP=F=;U|39uAcL|Q~t<}Z*D0)xdT`3a{8SXfl_bOa8AsN)%-_+&#mL2VHr zw6pE$z{#>e@RPv{3q7d~Jo9Nkel8Fd3<8QnVGL0yM>(#OSb-;$rzHiH{Z%ZG>nPZ% z;VBpaKdHB06{iff1)Vl!LH`c?-`w0KZjs;P-j~Nez*NqYJc=2|3w-@#Sl;#umnsPqUBj@3FYsA@DgO02YOS!CXI= z7bpul*--zOp6tn%qoV`)T>#mWEeWD|l6eNMXtW~|f%&^Ie|o#572kLU_mkA#aO=8v|6h@ZJ&mkmR;7vN6OYO?nPJ~21(F98)x^GL9I}!W?|)! z-_1C--B50B&c_oLDLvHDe~VIe{vufzUF(@M!IYa=WKs2U7aNeJo|G!{!RxF1+cHf| z-04j0)C656ma_q(Xou2#pYO%(Jx*$hSK^x>iC|(LS7rVt#{7M0OV`~JYT^Mxww{4Q zF>s+@)yB@nsDQEby8t?t&$pm@ssXabb_(NHu_>qgwqB4Vnp`u@Ce zNbTMEz%71a4}NJ|_E8T_CRhvj>@#n2nx+vssmOe4xS6XjkZ3}Xu+r;8l4!t9Zc{uh zf*9RZ7xJk*jyf5c60C3Essy+>IBi|iYv*BYS7~~Q({@ZNX*akF_JYi(5L%aIN z$2LGfjnqn5tCrl&YlRo1h6<(axkw)9Z^_mA`rZoi`7FG%H*|DmxqNr+wh$5Hh1ahw z4u?T>b<^hw;>|njYHqShx4f6pjRxrSKcAYixYVJQOGnO`Z}dz)+D@Ehn`+?e6!pXp zdUPvs``Kfv=+X3@3*U}!66paI+dm1C%{?hAlw}9>Es68ydVITgyFq4Wk~3uLOvKyw z@$cb=v+9?1N{G^)#~6UVeuZR`dp;rZ^FWU*iy1u{KDyB(-f8@?Fpb53WABosWlfBz zlv9Z7oQHtyax%c&?An9R8ZOF(tk1uxC{{FJde^UF_YKLdbRE~3r~yOa^FZ&*vKpUW zaw_(V0~CAK?P|gd%!i1{$XjDqx!qR?so043T7$ob&91yTFJg3&Am!=awWp@ft>E*d z)4_!wNRk!RsL&UI4<_VW$f>yeE6X)t2xc>g=(E6pFRv(LcT8AWRA(nhs)W9_N_HZ~ zF#*&B%hHO%iPKllZdM+~(KI}@0e0nc>;W&6@sb+W@6&SYqSR*l_eR(hu_mPnc?4Q_ zXtR-Nk3aknR;%_|T^wK}qY5ONiHT{Qn6F-<5Dg;>d3^?(mVX6OdrWh_A0 zvM$sxUP>6mckaR_{Z7+meWA?!(aJ0(R)W>~aazJHGe*ZH*%4hGGFiA{H{u~|X)bU% z*f*gllDg~e9xOAGvf9}M7~EigM8-VbTUq@S8Qy+dhN9Ybt+fv9=2(%Cmb=+-Ad;A4 z$cta0?JZ`34>$P7-Il@P1109F(`z19{09m|+TuPni+rp2eGs6jc0;vT*(&hA0ATUF AZvX%Q literal 0 HcmV?d00001 diff --git a/mods/stamina/init.lua b/mods/stamina/init.lua index 8678831a..8acc1575 100644 --- a/mods/stamina/init.lua +++ b/mods/stamina/init.lua @@ -31,7 +31,7 @@ SPRINT_DRAIN = 0.35 -- how fast to drain satation while sprinting (0-1) local function get_int_attribute(player) -- pipeworks fake player check - if not player.get_attribute then + if not player or not player.get_attribute then return nil end @@ -204,207 +204,62 @@ local function set_sprinting(name, sprinting) end --- Time based stamina functions -local stamina_timer, health_timer, action_timer, poison_timer, drunk_timer = 0,0,0,0,0 +local function drunk_tick() -local function stamina_globaltimer(dtime) + for _,player in ipairs(minetest.get_connected_players()) do - stamina_timer = stamina_timer + dtime - health_timer = health_timer + dtime - action_timer = action_timer + dtime - poison_timer = poison_timer + dtime - drunk_timer = drunk_timer + dtime + local name = player:get_player_name() - local players = minetest.get_connected_players() + if name + and stamina.players[name] + and stamina.players[name].drunk then - -- simulate drunk walking (thanks LumberJ) - if drunk_timer > 1.0 then + -- play burp sound every 20 seconds when drunk + local num = stamina.players[name].drunk - for _,player in pairs(players) do + if num and num > 0 and math.floor(num / 20) == num / 20 then + minetest.sound_play("stamina_burp", + {to_player = name, gain = 0.7}, true) + end - local name = player:get_player_name() + stamina.players[name].drunk = stamina.players[name].drunk - 1 - if stamina.players[name] - and stamina.players[name].drunk then + if stamina.players[name].drunk < 1 then - -- play burp sound every 20 seconds when drunk - local num = stamina.players[name].drunk + stamina.players[name].drunk = nil + stamina.players[name].units = 0 - if num and num > 0 and math.floor(num / 20) == num / 20 then - minetest.sound_play("stamina_burp", - {to_player = name, gain = 0.7}, true) - end - - stamina.players[name].drunk = stamina.players[name].drunk - 1 - - if stamina.players[name].drunk < 1 then - - stamina.players[name].drunk = nil - stamina.players[name].units = 0 + if not stamina.players[name].poisoned then player:hud_change(stamina.players[name].hud_id, - "text", "stamina_hud_fg.png") - end - - -- effect only works when not riding boat/cart/horse etc. - if not player:get_attach() then - - local yaw = player:get_look_horizontal() - - yaw = yaw + math.random(-0.5, 0.5) - - player:set_look_horizontal(yaw) + "text", "stamina_hud_fg.png") end end - drunk_timer = 0 + -- effect only works when not riding boat/cart/horse etc. + if not player:get_attach() then + + local yaw = player:get_look_horizontal() + math.random(-0.5, 0.5) + + player:set_look_horizontal(yaw) + end end end +end - -- hurt player when poisoned - if poison_timer > STAMINA_POISON_TICK then +local function health_tick() - for _,player in pairs(players) do + for _,player in ipairs(minetest.get_connected_players()) do - local name = player:get_player_name() + local air = player:get_breath() or 0 + local hp = player:get_hp() + local h = get_int_attribute(player) + local name = player:get_player_name() - if stamina.players[name] - and stamina.players[name].poisoned - and stamina.players[name].poisoned > 0 then + if name then - stamina.players[name].poisoned = - stamina.players[name].poisoned - 1 - - local hp = player:get_hp() - 1 - - if hp > 0 then - player:set_hp(hp, {poison = true}) - end - - elseif stamina.players[name] - and stamina.players[name].poisoned then - - player:hud_change(stamina.players[name].hud_id, - "text", "stamina_hud_fg.png") - - stamina.players[name].poisoned = nil - end - - poison_timer = 0 - end - end - - - -- sprint control and particle animation - if action_timer > STAMINA_MOVE_TICK then - - for _,player in pairs(players) do - - local controls = player:get_player_control() - - -- Determine if the player is walking or jumping - if controls then - - if controls.jump then - exhaust_player(player, STAMINA_EXHAUST_JUMP) - - elseif controls.up - or controls.down - or controls.left - or controls.right then - exhaust_player(player, STAMINA_EXHAUST_MOVE) - end - end - - --- START sprint - if enable_sprint then - - local name = player:get_player_name() - - -- check if player can sprint (stamina must be over 6 points) - if stamina.players[name] - and not stamina.players[name].poisoned - and not stamina.players[name].drunk - and controls and controls.aux1 and controls.up - and not minetest.check_player_privs(player, {fast = true}) - and get_int_attribute(player) > 6 then - - set_sprinting(name, true) - - -- create particles behind player when sprinting - if enable_sprint_particles then - - local pos = player:get_pos() - local node = minetest.get_node({ - x = pos.x, y = pos.y - 1, z = pos.z}) - - if node.name ~= "air" then - - minetest.add_particlespawner({ - amount = 5, - time = 0.01, - minpos = {x = pos.x - 0.25, y = pos.y + 0.1, z = pos.z - 0.25}, - maxpos = {x = pos.x + 0.25, y = pos.y + 0.1, z = pos.z + 0.25}, - minvel = {x = -0.5, y = 1, z = -0.5}, - maxvel = {x = 0.5, y = 2, z = 0.5}, - minacc = {x = 0, y = -5, z = 0}, - maxacc = {x = 0, y = -12, z = 0}, - minexptime = 0.25, - maxexptime = 0.5, - minsize = 0.5, - maxsize = 1.0, - vertical = false, - collisiondetection = false, - texture = "default_dirt.png" - }) - - end - end - - -- Lower the player's stamina when sprinting - local level = get_int_attribute(player) - - stamina_update_level(player, - level - (SPRINT_DRAIN * STAMINA_MOVE_TICK)) - else - set_sprinting(name, false) - end - end - -- END sprint - - action_timer = 0 - end - end - - - -- lower saturation by 1 point after STAMINA_TICK - if stamina_timer > STAMINA_TICK then - - for _,player in pairs(players) do - - local h = get_int_attribute(player) - - if h > STAMINA_TICK_MIN then - stamina_update_level(player, h - 1) - end - - stamina_timer = 0 - end - end - - - -- heal or damage player, depending on saturation - if health_timer > STAMINA_HEALTH_TICK then - - for _,player in pairs(players) do - - local air = player:get_breath() or 0 - local hp = player:get_hp() - local h = get_int_attribute(player) - local name = player:get_player_name() - - -- damage player by 1 hp if saturation is < 2 (of 30) + -- damage player by 1 hp if saturation is < 2 if h and h < STAMINA_STARVE_LVL and hp > 0 then player:set_hp(hp - STAMINA_STARVE, {hunger = true}) @@ -421,11 +276,179 @@ local function stamina_globaltimer(dtime) stamina_update_level(player, h - 1) end - - health_timer = 0 end end +end + +local function action_tick() + + for _,player in ipairs(minetest.get_connected_players()) do + + local controls = player and player:get_player_control() + + -- Determine if the player is walking or jumping + if controls then + + if controls.jump then + exhaust_player(player, STAMINA_EXHAUST_JUMP) + + elseif controls.up + or controls.down + or controls.left + or controls.right then + exhaust_player(player, STAMINA_EXHAUST_MOVE) + end + end + + --- START sprint + if enable_sprint then + + local name = player and player:get_player_name() + + -- check if player can sprint (stamina must be over 6 points) + if name + and stamina.players[name] + and not stamina.players[name].poisoned + and not stamina.players[name].drunk + and controls and controls.aux1 and controls.up + and not minetest.check_player_privs(player, {fast = true}) + and get_int_attribute(player) > 6 then + + set_sprinting(name, true) + + -- create particles behind player when sprinting + if enable_sprint_particles then + + local pos = player:get_pos() + local node = minetest.get_node({ + x = pos.x, + y = pos.y - 1, + z = pos.z + }) + + if node.name ~= "air" then + + minetest.add_particlespawner({ + amount = 5, + time = 0.01, + minpos = {x = pos.x - 0.25, y = pos.y + 0.1, z = pos.z - 0.25}, + maxpos = {x = pos.x + 0.25, y = pos.y + 0.1, z = pos.z + 0.25}, + minvel = {x = -0.5, y = 1, z = -0.5}, + maxvel = {x = 0.5, y = 2, z = 0.5}, + minacc = {x = 0, y = -5, z = 0}, + maxacc = {x = 0, y = -12, z = 0}, + minexptime = 0.25, + maxexptime = 0.5, + minsize = 0.5, + maxsize = 1.0, + vertical = false, + collisiondetection = false, + texture = "default_dirt.png" + }) + + end + end + + -- Lower the player's stamina when sprinting + local level = get_int_attribute(player) + + stamina_update_level(player, + level - (SPRINT_DRAIN * STAMINA_MOVE_TICK)) + + elseif name then + set_sprinting(name, false) + end + end + -- END sprint + end +end + + +local function poison_tick() + + for _,player in ipairs(minetest.get_connected_players()) do + + local name = player and player:get_player_name() + + if name + and stamina.players[name] + and stamina.players[name].poisoned + and stamina.players[name].poisoned > 0 then + + stamina.players[name].poisoned = + stamina.players[name].poisoned - 1 + + local hp = player:get_hp() - 1 + + if hp > 0 then + player:set_hp(hp, {poison = true}) + end + + elseif name + and stamina.players[name] + and stamina.players[name].poisoned then + + if not stamina.players[name].drunk then + + player:hud_change(stamina.players[name].hud_id, + "text", "stamina_hud_fg.png") + end + + stamina.players[name].poisoned = nil + end + end +end + + +local function stamina_tick() + + for _,player in ipairs(minetest.get_connected_players()) do + + local h = get_int_attribute(player) + + if h and h > STAMINA_TICK_MIN then + stamina_update_level(player, h - 1) + end + end +end + + +-- Time based stamina functions +local stamina_timer, health_timer, action_timer, poison_timer, drunk_timer = 0,0,0,0,0 + +local function stamina_globaltimer(dtime) + + stamina_timer = stamina_timer + dtime + health_timer = health_timer + dtime + action_timer = action_timer + dtime + poison_timer = poison_timer + dtime + drunk_timer = drunk_timer + dtime + + -- simulate drunk walking (thanks LumberJ) + if drunk_timer > 1.0 then + drunk_tick() ; drunk_timer = 0 + end + + -- hurt player when poisoned + if poison_timer > STAMINA_POISON_TICK then + poison_tick() ; poison_timer = 0 + end + + -- sprint control and particle animation + if action_timer > STAMINA_MOVE_TICK then + action_tick() ; action_timer = 0 + end + + -- lower saturation by 1 point after STAMINA_TICK + if stamina_timer > STAMINA_TICK then + stamina_tick() ; stamina_timer = 0 + end + + -- heal or damage player, depending on saturation + if health_timer > STAMINA_HEALTH_TICK then + health_tick() ; health_timer = 0 + end end @@ -559,8 +582,8 @@ function stamina.eat(hp_change, replace_with_item, itemstack, user, pointed_thin "stamina_hud_poison.png") minetest.chat_send_player(name, - minetest.get_color_escape_sequence("#1eff00") - .. "You suddenly feel tipsy!") + minetest.get_color_escape_sequence("#1eff00") + .. "You suddenly feel tipsy!") end end -- 2.25.1