From 829ac8a39029cb0fa9a1fc927a32e1cde7be9920 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 25 Feb 2021 20:49:03 +0100 Subject: [PATCH] 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 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 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