Merge branch 'stuck_arrow' of http://repo.or.cz/MineClone/MineClone2 into stuck_arrow

This commit is contained in:
Wuzzy 2018-05-09 00:06:29 +02:00
commit 76356ed1e5
3 changed files with 137 additions and 20 deletions

View file

@ -17,6 +17,20 @@ local boxes_on = {
wall_top = { -4/16, 7/16, -2/16, 4/16, 8/16, 2/16 }, wall_top = { -4/16, 7/16, -2/16, 4/16, 8/16, 2/16 },
} }
-- Push the button
mesecon.push_button = function(pos, node)
-- No-op if button is already pushed
if mesecon.is_receptor_on(node) then
return
end
local def = minetest.registered_nodes[node.name]
minetest.set_node(pos, {name="mesecons_button:button_"..def._mcl_button_basename.."_on", param2=node.param2})
mesecon.receptor_on(pos, button_get_output_rules(node))
minetest.sound_play("mesecons_button_push", {pos=pos})
local timer = minetest.get_node_timer(pos)
timer:start(def._mcl_button_timer)
end
local on_button_place = function(itemstack, placer, pointed_thing) local on_button_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" then if pointed_thing.type ~= "node" then
-- no interaction possible with entities -- no interaction possible with entities
@ -66,7 +80,7 @@ end
local buttonuse = "Rightclick the button to push it." local buttonuse = "Rightclick the button to push it."
mesecon.register_button = function(basename, description, texture, recipeitem, sounds, plusgroups, button_timer, longdesc) mesecon.register_button = function(basename, description, texture, recipeitem, sounds, plusgroups, button_timer, push_by_arrow, longdesc)
local groups_off = table.copy(plusgroups) local groups_off = table.copy(plusgroups)
groups_off.attached_node=1 groups_off.attached_node=1
groups_off.dig_by_water=1 groups_off.dig_by_water=1
@ -78,6 +92,11 @@ mesecon.register_button = function(basename, description, texture, recipeitem, s
groups_on.not_in_creative_inventory=1 groups_on.not_in_creative_inventory=1
groups_on.button=2 -- button (on) groups_on.button=2 -- button (on)
if push_by_arrow then
groups_off.button_push_by_arrow = 1
groups_on.button_push_by_arrow = 1
end
minetest.register_node("mesecons_button:button_"..basename.."_off", { minetest.register_node("mesecons_button:button_"..basename.."_off", {
drawtype = "nodebox", drawtype = "nodebox",
tiles = {texture}, tiles = {texture},
@ -98,17 +117,16 @@ mesecon.register_button = function(basename, description, texture, recipeitem, s
on_place = on_button_place, on_place = on_button_place,
node_placement_prediction = "", node_placement_prediction = "",
on_rightclick = function (pos, node) on_rightclick = function (pos, node)
minetest.set_node(pos, {name="mesecons_button:button_"..basename.."_on", param2=node.param2}) mesecon.push_button(pos, node)
mesecon.receptor_on(pos, button_get_output_rules(node))
minetest.sound_play("mesecons_button_push", {pos=pos})
local timer = minetest.get_node_timer(pos)
timer:start(button_timer)
end, end,
sounds = sounds, sounds = sounds,
mesecons = {receptor = { mesecons = {receptor = {
state = mesecon.state.off, state = mesecon.state.off,
rules = button_get_output_rules, rules = button_get_output_rules,
}}, }},
_mcl_button_basename = basename,
_mcl_button_timer = button_timer,
_mcl_blast_resistance = 2.5, _mcl_blast_resistance = 2.5,
_mcl_hardness = 0.5, _mcl_hardness = 0.5,
}) })
@ -134,14 +152,33 @@ mesecon.register_button = function(basename, description, texture, recipeitem, s
state = mesecon.state.on, state = mesecon.state.on,
rules = button_get_output_rules rules = button_get_output_rules
}}, }},
_mcl_button_basename = basename,
_mcl_button_timer = button_timer,
on_timer = function(pos, elapsed) on_timer = function(pos, elapsed)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
if node.name=="mesecons_button:button_"..basename.."_on" then --has not been dug if node.name=="mesecons_button:button_"..basename.."_on" then --has not been dug
-- Is button pushable by arrow?
if push_by_arrow then
-- If there's an arrow stuck in the button, keep it pressed and check
-- it again later.
local objs = minetest.get_objects_inside_radius(pos, 1)
for o=1, #objs do
local entity = objs[o]:get_luaentity()
if entity and entity.name == "mcl_bows:arrow_entity" then
local timer = minetest.get_node_timer(pos)
timer:start(button_timer)
return
end
end
end
-- Normal operation: Un-press the button
minetest.set_node(pos, {name="mesecons_button:button_"..basename.."_off",param2=node.param2}) minetest.set_node(pos, {name="mesecons_button:button_"..basename.."_off",param2=node.param2})
minetest.sound_play("mesecons_button_pop", {pos=pos}) minetest.sound_play("mesecons_button_pop", {pos=pos})
mesecon.receptor_off(pos, button_get_output_rules(node)) mesecon.receptor_off(pos, button_get_output_rules(node))
end end
end, end,
_mcl_blast_resistance = 2.5, _mcl_blast_resistance = 2.5,
_mcl_hardness = 0.5, _mcl_hardness = 0.5,
}) })
@ -160,6 +197,7 @@ mesecon.register_button(
mcl_sounds.node_sound_stone_defaults(), mcl_sounds.node_sound_stone_defaults(),
{material_stone=1,handy=1,pickaxey=1}, {material_stone=1,handy=1,pickaxey=1},
1, 1,
false,
"A stone button is a redstone component made out of stone which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for 1 second. It can only be placed on solid opaque full cubes (like cobblestone).") "A stone button is a redstone component made out of stone which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for 1 second. It can only be placed on solid opaque full cubes (like cobblestone).")
local woods = { local woods = {
@ -180,7 +218,8 @@ for w=1, #woods do
mcl_sounds.node_sound_wood_defaults(), mcl_sounds.node_sound_wood_defaults(),
{material_wood=1,handy=1,axey=1}, {material_wood=1,handy=1,axey=1},
1.5, 1.5,
"A wooden button is a redstone component made out of wood which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for 1.5 seconds. It can only be placed on solid opaque full cubes (like cobblestone).") true,
"A wooden button is a redstone component made out of wood which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for 1.5 seconds. It can only be placed on solid opaque full cubes (like cobblestone). Wooden buttons may also be pushed by arrows.")
minetest.register_craft({ minetest.register_craft({
type = "fuel", type = "fuel",

View file

@ -1,3 +1,6 @@
-- Time in seconds after which a stuck arrow is deleted
local ARROW_TIMEOUT = 60
local mod_mcl_hunger = minetest.get_modpath("mcl_hunger") local mod_mcl_hunger = minetest.get_modpath("mcl_hunger")
local mod_awards = minetest.get_modpath("awards") and minetest.get_modpath("mcl_achievements") local mod_awards = minetest.get_modpath("awards") and minetest.get_modpath("mcl_achievements")
@ -43,25 +46,60 @@ minetest.register_node("mcl_bows:arrow_box", {
groups = {not_in_creative_inventory=1}, groups = {not_in_creative_inventory=1},
}) })
local THROWING_ARROW_ENTITY={ -- FIXME: Arrow velocity is a bit strange. If the arrow flies VERY long, the acceleration can cause the velocity to become negative
physical = false, -- and the arrow flies backwards.
local ARROW_ENTITY={
physical = true,
visual = "wielditem", visual = "wielditem",
visual_size = {x=0.4, y=0.4}, visual_size = {x=0.4, y=0.4},
textures = {"mcl_bows:arrow_box"}, textures = {"mcl_bows:arrow_box"},
collisionbox = {0,0,0,0,0,0}, collisionbox = {-0.1, -0.1, -0.1, 0.1, 0.1, 0.1},
collide_with_objects = false,
_lastpos={}, _lastpos={},
_startpos=nil, _startpos=nil,
_damage=1, -- Damage on impact _damage=1, -- Damage on impact
_stuck=false, -- Whether arrow is stuck
_stucktimer=nil,-- Amount of time (in seconds) the arrow has been stuck so far
_shooter=nil, -- ObjectRef of player or mob who shot it _shooter=nil, -- ObjectRef of player or mob who shot it
} }
THROWING_ARROW_ENTITY.on_step = function(self, dtime) ARROW_ENTITY.on_step = function(self, dtime)
local pos = self.object:getpos() local pos = self.object:getpos()
local node = minetest.get_node(pos) local dpos = table.copy(pos) -- digital pos
dpos = vector.round(dpos)
local node = minetest.get_node(dpos)
if self._stuck then
self._stucktimer = self._stucktimer + dtime
if self._stucktimer > ARROW_TIMEOUT then
self.object:remove()
return
end
local objects = minetest.get_objects_inside_radius(pos, 2)
for _,obj in ipairs(objects) do
if obj:is_player() then
if not minetest.settings:get_bool("creative_mode") then
-- Pickup arrow if player is nearby
if obj:get_inventory():room_for_item("main", "mcl_bows:arrow") then
obj:get_inventory():add_item("main", "mcl_bows:arrow")
minetest.sound_play("item_drop_pickup", {
pos = pos,
max_hear_distance = 16,
gain = 1.0,
})
self.object:remove()
return
end
else
self.object:remove()
return
end
end
end
-- Check for object collision. Done every tick (hopefully this is not too stressing) -- Check for object collision. Done every tick (hopefully this is not too stressing)
do else
local objs = minetest.get_objects_inside_radius(pos, 2) local objs = minetest.get_objects_inside_radius(pos, 2)
local closest_object local closest_object
local closest_distance local closest_distance
@ -123,18 +161,27 @@ THROWING_ARROW_ENTITY.on_step = function(self, dtime)
end end
end end
self.object:remove() self.object:remove()
return
end end
end end
end end
-- Check for node collision -- Check for node collision
if self._lastpos.x~=nil then -- FIXME: Also collides with ignore
if self._lastpos.x~=nil and not self._stuck then
local def = minetest.registered_nodes[node.name] local def = minetest.registered_nodes[node.name]
if (def and def.walkable) or not def then local vel = self.object:get_velocity()
if not minetest.settings:get_bool("creative_mode") then -- Arrow has stopped
minetest.add_item(self._lastpos, 'mcl_bows:arrow') if (math.abs(vel.x) < 0.0001) or (math.abs(vel.z) < 0.0001) or (math.abs(vel.y) < 0.00001) then
-- Arrow is stuck and no longer moves
self._stuck = true
self._stucktimer = 0
self.object:set_velocity({x=0, y=0, z=0})
self.object:set_acceleration({x=0, y=0, z=0})
-- Push the button
if minetest.get_modpath("mesecons_button") and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then
mesecon.push_button(dpos, node)
end end
self.object:remove()
elseif (def and def.liquidtype ~= "none") then elseif (def and def.liquidtype ~= "none") then
-- Slow down arrow in liquids -- Slow down arrow in liquids
local v = def.liquid_viscosity local v = def.liquid_viscosity
@ -142,7 +189,6 @@ THROWING_ARROW_ENTITY.on_step = function(self, dtime)
v = 0 v = 0
end end
local vpenalty = math.max(0.1, 0.98 - 0.1 * v) local vpenalty = math.max(0.1, 0.98 - 0.1 * v)
local vel = self.object:get_velocity()
if math.abs(vel.x) > 0.001 then if math.abs(vel.x) > 0.001 then
vel.x = vel.x * vpenalty vel.x = vel.x * vpenalty
end end
@ -157,7 +203,38 @@ THROWING_ARROW_ENTITY.on_step = function(self, dtime)
self._lastpos={x=pos.x, y=pos.y, z=pos.z} self._lastpos={x=pos.x, y=pos.y, z=pos.z}
end end
minetest.register_entity("mcl_bows:arrow_entity", THROWING_ARROW_ENTITY) ARROW_ENTITY.get_staticdata = function(self)
local out = {
lastpos = self._lastpos,
startpos = self._startpos,
damage = self._damage,
stuck = self._stuck,
stucktimer = self._stucktimer,
}
if self._shooter and self._shooter:is_player() then
out.shootername = self._shooter:get_player_name()
end
return minetest.serialize(out)
end
ARROW_ENTITY.on_activate = function(self, staticdata, dtime_s)
local data = minetest.deserialize(staticdata)
if data then
self._lastpos = data.lastpos
self._startpos = data.startpos
self._damage = data.damage
self._stuck = data.stuck
self._stucktimer = data.stucktimer
if data.shootername then
local shooter = minetest.get_player_by_name(data.shootername)
if shooter and shooter:is_player() then
self._shooter = shooter
end
end
end
end
minetest.register_entity("mcl_bows:arrow_entity", ARROW_ENTITY)
if minetest.get_modpath("mcl_core") and minetest.get_modpath("mcl_mobitems") then if minetest.get_modpath("mcl_core") and minetest.get_modpath("mcl_mobitems") then
minetest.register_craft({ minetest.register_craft({

View file

@ -6,3 +6,4 @@ mcl_core?
mcl_mobitems? mcl_mobitems?
mcl_playerphysics? mcl_playerphysics?
doc? doc?
mesecons_button?