Crafter/mods/bow/init.lua
2020-06-01 19:22:15 -04:00

358 lines
11 KiB
Lua

local arrow = {}
arrow.initial_properties = {
physical = true,
collide_with_objects = false,
collisionbox = {-0.05, -0.05, -0.05, 0.05, 0.05, 0.05},
visual = "mesh",
visual_size = {x = 1 , y = 1},
mesh = "basic_bow_arrow.b3d",
textures = {
"basic_bow_arrow_uv.png"
},
pointable = false,
--automatic_face_movement_dir = 0.0,
--automatic_face_movement_max_rotation_per_sec = 600,
}
arrow.on_activate = function(self, staticdata, dtime_s)
--self.object:set_animation({x=0,y=180}, 15, 0, true)
local vel = nil
if string.sub(staticdata, 1, string.len("return")) == "return" then
local data = minetest.deserialize(staticdata)
if data and type(data) == "table" then
self.spin = data.spin
self.owner = data.owner
self.stuck = data.stuck
self.timer = data.timer
self.collecting = data.collecting
self.check_dir = data.check_dir
vel = data.vel
end
end
if not self.stuck then
self.object:set_acceleration(vector.new(0,-9.81,0))
if vel then
self.object:set_velocity(vel)
end
end
end
arrow.get_staticdata = function(self)
return minetest.serialize({
spin = self.spin,
owner = self.owner,
stuck = self.stuck,
timer = self.timer,
collecting = self.collecting,
check_dir = self.check_dir,
vel = self.object:get_velocity()
})
end
arrow.spin = 0
arrow.owner = ""
arrow.stuck = false
arrow.timer = 0
arrow.collecting = false
arrow.collection_height = 0.5
arrow.radius = 2
arrow.on_step = function(self, dtime,moveresult)
local pos = self.object:get_pos()
local vel = self.object:get_velocity()
self.timer = self.timer + dtime
if self.collecting == true then
for _,object in ipairs(minetest.get_objects_inside_radius(pos, self.radius)) do
local owner = minetest.get_player_by_name(self.owner)
if owner then
self.object:set_acceleration(vector.new(0,0,0))
--get the variables
local pos2 = owner:get_pos()
local player_velocity = owner:get_player_velocity()
pos2.y = pos2.y + self.collection_height
local direction = vector.normalize(vector.subtract(pos2,pos))
local distance = vector.distance(pos2,pos)
--remove if too far away
if distance > self.radius then
distance = 0
end
local multiplier = (self.radius*5) - distance
local velocity = vector.multiply(direction,multiplier)
local velocity = vector.add(player_velocity,velocity)
self.object:set_velocity(velocity)
if distance < 0.2 then
self.object:remove()
end
--self.delete_timer = self.delete_timer + dtime
--this is where the item gets removed from world
--if self.delete_timer > 1 then
-- self.object:remove()
--end
return
else
print(self.owner.." does not exist")
self.object:remove()
end
end
else
for _,object in ipairs(minetest.get_objects_inside_radius(pos, 2)) do
if self.stuck == false and ((object:is_player() and object:get_player_name() ~= self.owner and object:get_hp() > 0) or (object:get_luaentity() and object:get_luaentity().mob == true)) then
object:punch(self.object, 2,
{
full_punch_interval=1.5,
damage_groups = {damage=3},
})
hit = true
self.object:remove()
break
elseif self.timer > 3 and (object:is_player() and object:get_player_name() == self.owner) then
self.collecting = true
local inv = object:get_inventory()
if inv and inv:room_for_item("main", ItemStack("bow:arrow")) then
inv:add_item("main",ItemStack("bow:arrow"))
minetest.sound_play("pickup", {
to_player = object:get_player_name(),
gain = 0.4,
pitch = math.random(60,100)/100
})
else
self.object:remove()
minetest.throw_item(pos,"bow:arrow")
end
end
end
if moveresult and moveresult.collides and moveresult.collisions and moveresult.collisions[1] and moveresult.collisions[1].new_velocity and self.stuck == false then
if moveresult.collisions[1].new_velocity.x == 0 and moveresult.collisions[1].old_velocity.x ~= 0 then
self.check_dir = vector.direction(vector.new(pos.x,0,0),vector.new(moveresult.collisions[1].node_pos.x,0,0))
elseif moveresult.collisions[1].new_velocity.y == 0 and moveresult.collisions[1].old_velocity.y ~= 0 then
self.check_dir = vector.direction(vector.new(0,pos.y,0),vector.new(0,moveresult.collisions[1].node_pos.y,0))
elseif moveresult.collisions[1].new_velocity.z == 0 and moveresult.collisions[1].old_velocity.z ~= 0 then
self.check_dir = vector.direction(vector.new(0,0,pos.z),vector.new(0,0,moveresult.collisions[1].node_pos.z))
end
print(dump(moveresult.collisions[1].new_pos))
self.object:set_pos(moveresult.collisions[1].new_pos)
--print(dump(moveresult.collisions[1].new_pos))
minetest.sound_play("arrow_hit",{object=self.object,gain=1,pitch=math.random(80,100)/100,max_hear_distance=64})
self.stuck = true
self.object:set_velocity(vector.new(0,0,0))
self.object:set_acceleration(vector.new(0,0,0))
elseif self.stuck == true and self.check_dir then
local pos2 = vector.add(pos,vector.multiply(self.check_dir,0.2))
local ray = minetest.raycast(pos, pos2, false, false)
local pointed_thing = ray:next()
if not pointed_thing then
self.stuck = false
self.object:set_acceleration(vector.new(0,-9.81,0))
end
end
if not self.stuck and pos and self.oldpos then
self.spin = self.spin + (dtime*10)
if self.spin > math.pi then
self.spin = -math.pi
end
local dir = vector.normalize(vector.subtract(pos,self.oldpos))
local y = minetest.dir_to_yaw(dir)
local x = (minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(self.oldpos.x,0,self.oldpos.z)),0,pos.y-self.oldpos.y))+(math.pi/2))
self.object:set_rotation(vector.new(x,y,self.spin))
--local frame = self.get_animation_frame(dir)
--self.object:set_animation({x=frame, y=frame}, 0)
end
if self.stuck == false then
self.oldpos = pos
self.oldvel = vel
end
end
end
minetest.register_entity("bow:arrow", arrow)
minetest.register_craftitem("bow:bow_empty", {
description = "Bow",
inventory_image = "bow.png",
stack_max = 1,
groups = {bow=1},
range = 0,
})
for i = 1,5 do
minetest.register_craftitem("bow:bow_"..i, {
description = "Bow",
inventory_image = "bow_"..i..".png",
stack_max = 1,
groups = {bow=1,bow_loaded=i},
range = 0,
on_drop = function(itemstack, dropper, pos)
itemstack = ItemStack("bow:bow_empty")
minetest.item_drop(itemstack, dropper, pos)
return(itemstack)
end,
})
end
minetest.register_craftitem("bow:arrow", {
description = "Arrow",
inventory_image = "arrow_item.png",
})
--this is a very complicated function which makes the bow work
minetest.register_globalstep(function(dtime)
--check if player has bow
for _,player in ipairs(minetest.get_connected_players()) do
local item = player:get_wielded_item():get_name()
local meta = player:get_meta()
--print(meta:get_int("arrow_inventory_index"))
if minetest.get_item_group(item, "bow") > 0 then
--begin to pull the bow back
if player:get_player_control().RMB == true then
local arrow_index = meta:get_int("arrow_inventory_index")
local new_index = player:get_wield_index()
meta:set_int("arrow_inventory_index",new_index)
if arrow_index == new_index then
local inv = player:get_inventory()
if inv:contains_item("main", ItemStack("bow:arrow")) then
local meta = player:get_meta()
local animation = meta:get_float("bow_loading_animation")
if animation <= 5 then
if animation == 0 then
animation = 1
player:set_wielded_item(ItemStack("bow:bow_1"))
end
animation = animation + (dtime*4)
--print(animation)
meta:set_float("bow_loading_animation", animation)
local level = minetest.get_item_group(item, "bow_loaded")
local new_level = math.floor(animation + 0.5)
--print(new_level,level)
if new_level > level then
if new_level == 5 then
minetest.sound_play("bow_pull_back", {object=player, gain = 1.0, max_hear_distance = 60,pitch = math.random(70,110)/100})
end
player:set_wielded_item(ItemStack("bow:bow_"..new_level))
end
end
end
else
--print("trying to set the stack")
--print(arrow_index,new_index)
meta:set_float("bow_loading_animation", 0)
local inv = player:get_inventory()
local stack = inv:get_stack("main", arrow_index)
local name = stack:get_name()
if minetest.get_item_group(name, "bow") > 0 then
--print("SUCCESS")
inv:set_stack("main", arrow_index, ItemStack("bow:bow_empty"))
end
end
else
local arrow_index = meta:get_int("arrow_inventory_index")
local new_index = player:get_wield_index()
meta:set_int("arrow_inventory_index",new_index)
if arrow_index ~= new_index then
meta:set_float("bow_loading_animation", 0)
local inv = player:get_inventory()
local stack = inv:get_stack("main", arrow_index)
local name = stack:get_name()
if minetest.get_item_group(name, "bow") > 0 then
inv:set_stack("main", arrow_index, ItemStack("bow:bow_empty"))
end
else
local power = minetest.get_item_group(item, "bow_loaded")
if power == 5 then
local inv = player:get_inventory()
if inv:contains_item("main", ItemStack("bow:arrow")) then
local dir = player:get_look_dir()
local vel = vector.multiply(dir,power*10)
local pos = player:get_pos()
pos.y = pos.y + 1.5
local add_pos = vector.add(pos,vector.divide(dir,10))
local object = minetest.add_entity(add_pos,"bow:arrow")
object:set_velocity(vel)
object:get_luaentity().owner = player:get_player_name()
object:get_luaentity().oldpos = pos
minetest.sound_play("bow", {object=player, gain = 1.0, max_hear_distance = 60,pitch = math.random(80,100)/100})
inv:remove_item("main", ItemStack("bow:arrow"))
end
end
player:set_wielded_item(ItemStack("bow:bow_empty"))
local meta = player:get_meta()
meta:set_float("bow_loading_animation", 0)
end
end
else
--print("catching the thing")
local arrow_index = meta:get_int("arrow_inventory_index")
local new_index = player:get_wield_index()
meta:set_int("arrow_inventory_index",new_index)
if arrow_index ~= new_index then
meta:set_float("bow_loading_animation", 0)
local inv = player:get_inventory()
local stack = inv:get_stack("main", arrow_index)
local name = stack:get_name()
if minetest.get_item_group(name, "bow") > 0 then
inv:set_stack("main", arrow_index, ItemStack("bow:bow_empty"))
end
end
end
end
end)
minetest.register_craft({
output = "bow:bow_empty",
recipe = {
{"" , "main:stick", "mob:string"},
{"main:stick" , "" , "mob:string"},
{"" , "main:stick", "mob:string"},
},
})
minetest.register_craft({
output = "bow:arrow 16",
recipe = {
{"main:iron", "" , "" },
{"" , "main:stick", "" },
{"" , "" , "mob:feather"},
},
})