Move throwing physics to builtin
parent
5b424fd67b
commit
9a65213458
|
@ -435,6 +435,81 @@ function core.item_secondary_use(itemstack, placer)
|
|||
return itemstack
|
||||
end
|
||||
|
||||
local function item_throw_step(entity, dtime)
|
||||
entity.throw_timer = entity.throw_timer + dtime
|
||||
if entity.throw_timer > 20 then
|
||||
entity.object:remove()
|
||||
return
|
||||
end
|
||||
if not entity.thrower then
|
||||
return
|
||||
end
|
||||
local pos = entity.object:get_pos()
|
||||
if not core.is_valid_pos(pos) then
|
||||
entity.object:remove()
|
||||
return
|
||||
end
|
||||
local hit_object = nil
|
||||
local node = minetest.get_node({x=pos.x, y=pos.y - 1, z=pos.z})
|
||||
local objs = minetest.get_objects_inside_radius(pos, 1)
|
||||
for _, obj in pairs(objs) do
|
||||
if obj:is_player() then
|
||||
local name = obj:get_player_name()
|
||||
if name ~= entity.thrower then
|
||||
hit_object = obj
|
||||
end
|
||||
elseif obj:get_luaentity() ~= nil and
|
||||
obj:get_luaentity().name ~= entity.name then
|
||||
hit_object = obj
|
||||
end
|
||||
end
|
||||
if hit_object or (node.name ~= "air" and node.name ~= "ignore") then
|
||||
local player = core.get_player_by_name(entity.thrower)
|
||||
entity.on_impact(player, pos, entity.throw_direction, hit_object)
|
||||
entity.object:remove()
|
||||
end
|
||||
end
|
||||
|
||||
function core.item_throw(name, thrower, speed, accel, on_impact)
|
||||
if not thrower or not thrower:is_player() then
|
||||
return
|
||||
end
|
||||
local pos = thrower:get_pos()
|
||||
if not core.is_valid_pos(pos) then
|
||||
return
|
||||
end
|
||||
pos.y = pos.y + 1.5
|
||||
local obj = nil
|
||||
local properties = {is_visible=true}
|
||||
if core.registered_entities[name] then
|
||||
obj = core.add_entity(pos, name)
|
||||
elseif core.registered_items[name] then
|
||||
obj = core.add_entity(pos, "__builtin:throwing_item")
|
||||
properties.textures = {name}
|
||||
else
|
||||
return
|
||||
end
|
||||
if obj then
|
||||
local ent = obj:get_luaentity()
|
||||
if ent then
|
||||
local s = speed or 19 -- default speed
|
||||
local a = accel or -3 -- default acceleration
|
||||
local dir = thrower:get_look_dir()
|
||||
ent.thrower = thrower:get_player_name()
|
||||
ent.throw_timer = 0
|
||||
ent.throw_direction = dir
|
||||
ent.on_step = item_throw_step
|
||||
ent.on_impact = on_impact and on_impact or function() end
|
||||
obj:set_properties(properties)
|
||||
obj:set_velocity({x=dir.x * s, y=dir.y * s, z=dir.z * s})
|
||||
obj:set_acceleration({x=dir.x * a, y=-9.81, z=dir.z * a})
|
||||
return obj
|
||||
else
|
||||
obj:remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function core.item_drop(itemstack, dropper, pos)
|
||||
local dropper_is_player = dropper and dropper:is_player()
|
||||
local p = table.copy(pos)
|
||||
|
|
|
@ -17,6 +17,22 @@ end
|
|||
local time_to_live = tonumber(core.settings:get("item_entity_ttl")) or 900
|
||||
local gravity = tonumber(core.settings:get("movement_gravity")) or 9.81
|
||||
|
||||
core.register_entity(":__builtin:throwing_item", {
|
||||
physical = true,
|
||||
visual = "wielditem",
|
||||
collisionbox = {0,0,0, 0,0,0},
|
||||
textures = {""},
|
||||
visual_size = {x=0.4, y=0.4},
|
||||
is_visible = false,
|
||||
on_activate = function(self, staticdata)
|
||||
if staticdata == "expired" then
|
||||
self.object:remove()
|
||||
end
|
||||
end,
|
||||
get_staticdata = function()
|
||||
return "expired"
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_entity(":__builtin:item", {
|
||||
initial_properties = {
|
||||
|
|
|
@ -2565,6 +2565,18 @@ and `minetest.auth_reload` call the authetification handler.
|
|||
* Returns `ObjectRef`, or `nil` if failed
|
||||
* `minetest.add_item(pos, item)`: Spawn item
|
||||
* Returns `ObjectRef`, or `nil` if failed
|
||||
* `minetest.item_throw(name, thrower, speed, accel, func(thrower, pos, dir, obj)`
|
||||
* Returns an `ObjectRef` or `nil` if failed
|
||||
* `name`: entity name or itemstring
|
||||
* `thrower`: player `ObjectRef`
|
||||
* `speed`: optional, default = 19
|
||||
* `accel`: optional, default = -3
|
||||
* `func`: optional, function called when the item has landed
|
||||
* `thrower`: player `ObjectRef`
|
||||
* `pos`: landing position
|
||||
* `dir`: direction of travel
|
||||
* `obj`: hit entity or player `ObjectRef`, may be nil
|
||||
Note: the entity will be automatically removed upon landing
|
||||
* `minetest.get_player_by_name(name)`: Get an `ObjectRef` to a player
|
||||
* `minetest.get_objects_inside_radius(pos, radius)`
|
||||
* `radius`: using an euclidean metric
|
||||
|
@ -2725,6 +2737,9 @@ and `minetest.auth_reload` call the authetification handler.
|
|||
unattached `group:attached_node` node to fall.
|
||||
* spread these updates to neighbours and can cause a cascade
|
||||
of nodes to fall.
|
||||
* `minetest.is_valid_pos(pos)`
|
||||
* Returns `true` if the position lies within the range -32000 to 32000
|
||||
|
||||
|
||||
### Inventory
|
||||
`minetest.get_inventory(location)`: returns an `InvRef`
|
||||
|
|
|
@ -516,33 +516,44 @@ minetest.register_abm({
|
|||
--
|
||||
|
||||
-- Shoot snowball
|
||||
snow_shoot_snowball = function (item, player, pointed_thing)
|
||||
local pos = player:get_pos()
|
||||
local obj = minetest.add_entity({x=pos.x, y=pos.y + 1.5, z=pos.z},
|
||||
"default:snowball_entity")
|
||||
if obj then
|
||||
local ent = obj:get_luaentity()
|
||||
if ent then
|
||||
ent.thrower = player:get_player_name()
|
||||
local dir = player:get_look_dir()
|
||||
obj:setvelocity({x = dir.x * 19, y = dir.y * 19, z = dir.z * 19})
|
||||
obj:set_acceleration({x = dir.x * -3, y = -9.81, z = dir.z * -3})
|
||||
item:take_item()
|
||||
else
|
||||
obj:remove()
|
||||
|
||||
local function snowball_impact(thrower, pos)
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name == "air" then
|
||||
local pos_under = vector.subtract(pos, {x=0, y=1, z=0})
|
||||
node = minetest.get_node(pos_under)
|
||||
if node.name then
|
||||
local def = minetest.registered_items[node.name] or {}
|
||||
if def.buildable_to == true then
|
||||
minetest.add_node(pos_under, {name="default:snow"})
|
||||
elseif def.walkable == true then
|
||||
minetest.add_node(pos, {name="default:snow"})
|
||||
end
|
||||
elseif node.name then
|
||||
local def = minetest.registered_items[node.name]
|
||||
if def and def.buildable_to == true then
|
||||
minetest.add_node(pos, {name="default:snow"})
|
||||
end
|
||||
end
|
||||
end
|
||||
return item
|
||||
end
|
||||
|
||||
-- Snowball entity
|
||||
local snowball_entity = {
|
||||
physical = false,
|
||||
function default.snow_shoot_snowball(itemstack, player, pointed_thing)
|
||||
itemstack:take_item()
|
||||
minetest.item_throw("default:snowball_entity", player, 19, -3,
|
||||
snowball_impact)
|
||||
minetest.sound_play("throwing_sound", {
|
||||
pos = pos,
|
||||
gain = 1.0,
|
||||
max_hear_distance = 5,
|
||||
})
|
||||
return itemstack
|
||||
end
|
||||
|
||||
minetest.register_entity("default:snowball_entity", {
|
||||
physical = true,
|
||||
textures = {"default_snowball.png",},
|
||||
visual = "sprite",
|
||||
thrower = nil,
|
||||
timer = 0,
|
||||
lastpos = {},
|
||||
collisionbox = {0,0,0, 0,0,0},
|
||||
on_activate = function(self, staticdata)
|
||||
if staticdata == "expired" then
|
||||
|
@ -552,68 +563,4 @@ local snowball_entity = {
|
|||
get_staticdata = function()
|
||||
return "expired"
|
||||
end,
|
||||
}
|
||||
|
||||
-- Called when snowball is moving.
|
||||
snowball_entity.on_step = function(self, dtime)
|
||||
self.timer = self.timer + dtime
|
||||
if self.timer > 20 then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
if not self.thrower then
|
||||
return
|
||||
end
|
||||
local drop_pos = nil
|
||||
local pos = self.object:getpos()
|
||||
local node = minetest.get_node(pos)
|
||||
local objs = minetest.get_objects_inside_radius({x=pos.x, y=pos.y, z=pos.z}, 1)
|
||||
for _, obj in pairs(objs) do
|
||||
if obj:is_player() then
|
||||
local name = obj:get_player_name()
|
||||
if name ~= self.thrower then
|
||||
drop_pos = obj:getpos()
|
||||
end
|
||||
elseif obj:get_luaentity() ~= nil and
|
||||
obj:get_luaentity().name ~= "default:snowball_entity" then
|
||||
drop_pos = obj:getpos()
|
||||
end
|
||||
end
|
||||
if node.name ~= "air" and node.name ~= "ignore" then
|
||||
for i = 1, 3 do
|
||||
local p = {x=pos.x, y=pos.y + i, z=pos.z}
|
||||
local n = minetest.get_node(p)
|
||||
if n.name == "air" then
|
||||
drop_pos = vector.new(p)
|
||||
break
|
||||
end
|
||||
end
|
||||
if not drop_pos then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
end
|
||||
if drop_pos then
|
||||
node = minetest.get_node(drop_pos)
|
||||
if node.name == "air" then
|
||||
local pos_under = vector.subtract(drop_pos, {x=0, y=1, z=0})
|
||||
node = minetest.get_node(pos_under)
|
||||
if node.name then
|
||||
local def = minetest.registered_items[node.name] or {}
|
||||
if def.buildable_to == true then
|
||||
minetest.add_node(pos_under, {name="default:snow"})
|
||||
elseif def.walkable == true then
|
||||
minetest.add_node(drop_pos, {name="default:snow"})
|
||||
end
|
||||
end
|
||||
elseif node.name then
|
||||
local def = minetest.registered_items[node.name]
|
||||
if def and def.buildable_to == true then
|
||||
minetest.add_node(drop_pos, {name="default:snow"})
|
||||
end
|
||||
end
|
||||
self.object:remove()
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_entity("default:snowball_entity", snowball_entity)
|
||||
})
|
||||
|
|
|
@ -240,7 +240,7 @@ minetest.register_node("default:snow", {
|
|||
},
|
||||
groups = {crumbly = 3, falling_node = 1, snowy = 1, puts_out_fire = 1, misc = 1, speed = -30},
|
||||
sounds = default.node_sound_snow_defaults(),
|
||||
on_use = snow_shoot_snowball,
|
||||
on_use = default.snow_shoot_snowball,
|
||||
on_construct = function(pos)
|
||||
pos.y = pos.y - 1
|
||||
if minetest.get_node(pos).name == "default:dirt_with_grass" then
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
minetest.register_craftitem("throwing:arrow", {
|
||||
description = "Arrow",
|
||||
inventory_image = "throwing_arrow_inv.png",
|
||||
})
|
||||
|
||||
minetest.register_node("throwing:arrow_box", {
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
-- Shaft
|
||||
{-6.5/17, -1.5/17, -1.5/17, 6.5/17, 1.5/17, 1.5/17},
|
||||
--Spitze
|
||||
{-4.5/17, 2.5/17, 2.5/17, -3.5/17, -2.5/17, -2.5/17},
|
||||
{-8.5/17, 0.5/17, 0.5/17, -6.5/17, -0.5/17, -0.5/17},
|
||||
--Federn
|
||||
{6.5/17, 1.5/17, 1.5/17, 7.5/17, 2.5/17, 2.5/17},
|
||||
{7.5/17, -2.5/17, 2.5/17, 6.5/17, -1.5/17, 1.5/17},
|
||||
{7.5/17, 2.5/17, -2.5/17, 6.5/17, 1.5/17, -1.5/17},
|
||||
{6.5/17, -1.5/17, -1.5/17, 7.5/17, -2.5/17, -2.5/17},
|
||||
|
||||
{7.5/17, 2.5/17, 2.5/17, 8.5/17, 3.5/17, 3.5/17},
|
||||
{8.5/17, -3.5/17, 3.5/17, 7.5/17, -2.5/17, 2.5/17},
|
||||
{8.5/17, 3.5/17, -3.5/17, 7.5/17, 2.5/17, -2.5/17},
|
||||
{7.5/17, -2.5/17, -2.5/17, 8.5/17, -3.5/17, -3.5/17},
|
||||
}
|
||||
},
|
||||
tiles = {"throwing_arrow.png", "throwing_arrow.png", "throwing_arrow_back.png", "throwing_arrow_front.png", "throwing_arrow_2.png", "throwing_arrow.png"},
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
local THROWING_ARROW_ENTITY={
|
||||
physical = false,
|
||||
timer=0,
|
||||
visual = "wielditem",
|
||||
visual_size = {x=0.3, y=0.3},
|
||||
textures = {"throwing:arrow_box"},
|
||||
lastpos={},
|
||||
collisionbox = {0,0,0,0,0,0},
|
||||
}
|
||||
|
||||
THROWING_ARROW_ENTITY.on_step = function(self, dtime)
|
||||
self.timer=self.timer+dtime
|
||||
local pos = self.object:getpos()
|
||||
local node = minetest.get_node(pos)
|
||||
|
||||
if self.timer>0.2 then
|
||||
local objs = minetest.get_objects_inside_radius({x=pos.x,y=pos.y,z=pos.z}, 2)
|
||||
for k, obj in pairs(objs) do
|
||||
if obj:get_luaentity() ~= nil then
|
||||
if obj:get_luaentity().name ~= "throwing:arrow_entity" and obj:get_luaentity().name ~= "__builtin:item" then
|
||||
local damage = 5
|
||||
obj:punch(self.object, 1.0, {
|
||||
full_punch_interval=1.0,
|
||||
damage_groups={fleshy=damage},
|
||||
}, nil)
|
||||
self.object:remove()
|
||||
end
|
||||
else
|
||||
local damage = 5
|
||||
obj:punch(self.object, 1.0, {
|
||||
full_punch_interval=1.0,
|
||||
damage_groups={fleshy=damage},
|
||||
}, nil)
|
||||
self.object:remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.lastpos.x~=nil then
|
||||
if node.name ~= "air" then
|
||||
minetest.add_item(self.lastpos, 'throwing:arrow')
|
||||
self.object:remove()
|
||||
end
|
||||
end
|
||||
self.lastpos={x=pos.x, y=pos.y, z=pos.z}
|
||||
end
|
||||
|
||||
minetest.register_entity("throwing:arrow_entity", THROWING_ARROW_ENTITY)
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'throwing:arrow 4',
|
||||
recipe = {
|
||||
{'fire:flint_and_steel'},
|
||||
{'default:stick'},
|
||||
{'default:paper'}
|
||||
}
|
||||
})
|
|
@ -1,42 +1,42 @@
|
|||
arrows = {
|
||||
local arrows = {
|
||||
{"throwing:arrow", "throwing:arrow_entity"},
|
||||
}
|
||||
|
||||
local creative = minetest.settings:get_bool("creative_mode")
|
||||
local wear
|
||||
|
||||
local function valid_pos(pos)
|
||||
if pos then
|
||||
for _, v in pairs({"x", "y", "z"}) do
|
||||
if not pos[v] or pos[v] < -32000 or pos[v] > 32000 then
|
||||
return
|
||||
end
|
||||
end
|
||||
return true
|
||||
local function arrow_impact(thrower, pos, dir, hit_object)
|
||||
if hit_object then
|
||||
local punch_damage = {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy=5},
|
||||
}
|
||||
hit_object:punch(thrower, 1.0, punch_damage, dir)
|
||||
end
|
||||
minetest.add_item(pos, "throwing:arrow")
|
||||
end
|
||||
|
||||
local throwing_shoot_arrow = function(itemstack, player)
|
||||
for _,arrow in ipairs(arrows) do
|
||||
if player:get_inventory():get_stack("main", player:get_wield_index()+1):get_name() == arrow[1] then
|
||||
if player:get_inventory():get_stack("main",
|
||||
player:get_wield_index() + 1):get_name() == arrow[1] then
|
||||
if not creative or not minetest.is_singleplayer()then
|
||||
player:get_inventory():remove_item("main", arrow[1])
|
||||
end
|
||||
local playerpos = player:get_pos()
|
||||
if not valid_pos(playerpos) then
|
||||
if not minetest.is_valid_pos(playerpos) then
|
||||
return
|
||||
end
|
||||
local obj = minetest.add_entity({x=playerpos.x,y=playerpos.y+1.5,z=playerpos.z}, arrow[2])
|
||||
local dir = player:get_look_dir()
|
||||
obj:setvelocity({x=dir.x*19, y=dir.y*19, z=dir.z*19})
|
||||
obj:set_acceleration({x=dir.x*-3, y=-10, z=dir.z*-3})
|
||||
obj:setyaw(player:get_look_yaw()+math.pi)
|
||||
minetest.sound_play("throwing_sound", {pos=playerpos})
|
||||
if obj:get_luaentity().player == "" then
|
||||
obj:get_luaentity().player = player
|
||||
local obj = minetest.item_throw("throwing:arrow_box", player,
|
||||
19, -3, arrow_impact)
|
||||
if obj then
|
||||
local ent = obj:get_luaentity()
|
||||
if ent then
|
||||
minetest.sound_play("throwing_sound", {pos=playerpos})
|
||||
obj:set_yaw(player:get_look_yaw() + math.pi)
|
||||
return true
|
||||
else
|
||||
obj:remove()
|
||||
end
|
||||
end
|
||||
obj:get_luaentity().node = player:get_inventory():get_stack("main", 1):get_name()
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
|
@ -56,7 +56,7 @@ minetest.register_tool("throwing:bow_arrow", {
|
|||
inventory_image = "throwing_bow_arrow.png",
|
||||
groups = {not_in_creative_inventory=1},
|
||||
on_place = function(itemstack, user, pointed_thing)
|
||||
wear = itemstack:get_wear()
|
||||
local wear = itemstack:get_wear()
|
||||
itemstack:replace("throwing:bow")
|
||||
itemstack:add_wear(wear)
|
||||
if throwing_shoot_arrow(itemstack, user, pointed_thing) then
|
||||
|
@ -67,7 +67,7 @@ minetest.register_tool("throwing:bow_arrow", {
|
|||
return itemstack
|
||||
end,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
wear = itemstack:get_wear()
|
||||
local wear = itemstack:get_wear()
|
||||
itemstack:replace("throwing:bow")
|
||||
itemstack:add_wear(wear)
|
||||
if throwing_shoot_arrow(itemstack, user, pointed_thing) then
|
||||
|
@ -75,10 +75,39 @@ minetest.register_tool("throwing:bow_arrow", {
|
|||
itemstack:add_wear(65535/385)
|
||||
end
|
||||
end
|
||||
return itemstack
|
||||
return itemstack
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_node("throwing:arrow_box", {
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
-- Shaft
|
||||
{-6.5/17, -1.5/17, -1.5/17, 6.5/17, 1.5/17, 1.5/17},
|
||||
--Spitze
|
||||
{-4.5/17, 2.5/17, 2.5/17, -3.5/17, -2.5/17, -2.5/17},
|
||||
{-8.5/17, 0.5/17, 0.5/17, -6.5/17, -0.5/17, -0.5/17},
|
||||
--Federn
|
||||
{6.5/17, 1.5/17, 1.5/17, 7.5/17, 2.5/17, 2.5/17},
|
||||
{7.5/17, -2.5/17, 2.5/17, 6.5/17, -1.5/17, 1.5/17},
|
||||
{7.5/17, 2.5/17, -2.5/17, 6.5/17, 1.5/17, -1.5/17},
|
||||
{6.5/17, -1.5/17, -1.5/17, 7.5/17, -2.5/17, -2.5/17},
|
||||
|
||||
{7.5/17, 2.5/17, 2.5/17, 8.5/17, 3.5/17, 3.5/17},
|
||||
{8.5/17, -3.5/17, 3.5/17, 7.5/17, -2.5/17, 2.5/17},
|
||||
{8.5/17, 3.5/17, -3.5/17, 7.5/17, 2.5/17, -2.5/17},
|
||||
{7.5/17, -2.5/17, -2.5/17, 8.5/17, -3.5/17, -3.5/17},
|
||||
}
|
||||
},
|
||||
tiles = {
|
||||
"throwing_arrow.png", "throwing_arrow.png", "throwing_arrow_back.png",
|
||||
"throwing_arrow_front.png", "throwing_arrow_2.png", "throwing_arrow.png"
|
||||
},
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'throwing:bow',
|
||||
recipe = {
|
||||
|
@ -88,8 +117,29 @@ minetest.register_craft({
|
|||
}
|
||||
})
|
||||
|
||||
minetest.register_craftitem("throwing:arrow", {
|
||||
description = "Arrow",
|
||||
inventory_image = "throwing_arrow_inv.png",
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'throwing:arrow 4',
|
||||
recipe = {
|
||||
{'fire:flint_and_steel'},
|
||||
{'default:stick'},
|
||||
{'default:paper'}
|
||||
}
|
||||
})
|
||||
|
||||
-- Legacy support
|
||||
|
||||
minetest.register_entity("throwing:arrow_entity", {
|
||||
is_visible = false,
|
||||
on_activate = function(self)
|
||||
self.object:remove()
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_alias("throwing:bow_0", "throwing:bow_arrow")
|
||||
minetest.register_alias("throwing:bow_1", "throwing:bow_arrow")
|
||||
minetest.register_alias("throwing:bow_2", "throwing:bow_arrow")
|
||||
|
||||
dofile(minetest.get_modpath("throwing").."/arrow.lua")
|
||||
|
|
Loading…
Reference in New Issue