2 minetest,math,vector,ipairs,string,type
4 minetest,math,vector,ipairs,string,type
7 local get_connected_players = minetest.get_connected_players
8 local get_player_by_name = minetest.get_player_by_name
9 local get_objects_inside_radius = minetest.get_objects_inside_radius
10 local create_raycast = minetest.raycast
11 local dir_to_yaw = minetest.dir_to_yaw
12 local deserialize = minetest.deserialize
13 local serialize = minetest.serialize
16 local s_sub = string.sub
17 local s_len = string.len
21 local random = math.random
22 local floor = math.floor
25 local new_vec = vector.new
26 local floor_vec = vector.floor
27 local vec_distance = vector.distance
28 local normalize_vec = vector.normalize
29 local add_vec = vector.add
30 local sub_vec = vector.subtract
31 local multiply_vec = vector.multiply
32 local divide_vec = vector.divide
33 local vec_direction = vector.direction
37 ██████╗ ██╗ █████╗ ██╗ ██╗███████╗██████╗ ██████╗ █████╗ ██████╗ ████████╗
38 ██╔══██╗██║ ██╔══██╗╚██╗ ██╔╝██╔════╝██╔══██╗ ██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝
39 ██████╔╝██║ ███████║ ╚████╔╝ █████╗ ██████╔╝ ██████╔╝███████║██████╔╝ ██║
40 ██╔═══╝ ██║ ██╔══██║ ╚██╔╝ ██╔══╝ ██╔══██╗ ██╔═══╝ ██╔══██║██╔══██╗ ██║
41 ██║ ███████╗██║ ██║ ██║ ███████╗██║ ██║ ██║ ██║ ██║██║ ██║ ██║
42 ╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝
49 --this is a very complicated function which makes the bow work
59 local function arrow_check(name,dtime)
60 temp_pool = pool[name]
61 player = get_player_by_name(name)
62 rightclick = player:get_player_control().RMB
63 new_index = player:get_wield_index()
65 -- if player changes selected item
66 if new_index ~= temp_pool.index then
67 inv:set_stack("main", temp_pool.index, ItemStack("bow:bow_empty"))
72 -- if player lets go of rightclick
73 if temp_pool.step ~= 5 and not rightclick then
74 inv:set_stack("main", temp_pool.index, ItemStack("bow:bow_empty"))
79 -- if player isn't holding a bow
80 if minetest.get_item_group(player:get_wielded_item():get_name(), "bow") == 0 then
85 inv = player:get_inventory()
87 -- if player doesn't have any arrows
88 if not inv:contains_item("main", ItemStack("bow:arrow")) then
89 inv:set_stack("main", temp_pool.index, ItemStack("bow:bow_empty"))
94 -- count steps using dtime
95 if temp_pool.step < 5 then
97 temp_pool.float = temp_pool.float + dtime
99 if temp_pool.float > 0.05 then
101 temp_pool.step = temp_pool.step + 1
102 player:set_wielded_item(ItemStack("bow:bow_"..temp_pool.step))
107 if temp_pool.step == 5 and not rightclick then
109 dir = player:get_look_dir()
110 vel = multiply_vec(dir,50)
111 pos = player:get_pos()
114 object = minetest.add_entity(add_vec(pos,divide_vec(dir,10)),"bow:arrow")
115 object:set_velocity(vel)
116 object:get_luaentity().owner = name
117 object:get_luaentity().oldpos = pos
119 minetest.sound_play("bow", {object=player, gain = 1.0, max_hear_distance = 60,pitch = random(80,100)/100})
121 inv:remove_item("main", ItemStack("bow:arrow"))
122 inv:set_stack("main", temp_pool.index, ItemStack("bow:bow_empty"))
128 --add hand fatigue timer
129 --gradually increase fatigue until cap is reached
133 minetest.register_globalstep(function(dtime)
134 for name in pairs(pool) do
135 arrow_check(name,dtime)
141 █████╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗ ███████╗██╗ ██╗███╗ ██╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗███████╗
142 ██╔══██╗██╔══██╗██╔══██╗██╔═══██╗██║ ██║ ██╔════╝██║ ██║████╗ ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║██╔════╝
143 ███████║██████╔╝██████╔╝██║ ██║██║ █╗ ██║ █████╗ ██║ ██║██╔██╗ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║███████╗
144 ██╔══██║██╔══██╗██╔══██╗██║ ██║██║███╗██║ ██╔══╝ ██║ ██║██║╚██╗██║██║ ██║ ██║██║ ██║██║╚██╗██║╚════██║
145 ██║ ██║██║ ██║██║ ██║╚██████╔╝╚███╔███╔╝ ██║ ╚██████╔╝██║ ╚████║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║███████║
146 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝
153 local player_velocity
163 local function arrow_step(self, dtime,moveresult)
164 self.timer = self.timer + dtime
166 pos = self.object:get_pos()
167 vel = self.object:get_velocity()
169 if self.collecting == true then
170 owner = get_player_by_name(self.owner)
171 for _,object in ipairs(get_objects_inside_radius(pos, self.radius)) do
174 self.object:set_acceleration(new_vec(0,0,0))
177 pos2 = owner:get_pos()
178 player_velocity = owner:get_player_velocity()
179 pos2.y = pos2.y + self.collection_height
181 direction = normalize_vec(sub_vec(pos2,pos))
182 distance = vec_distance(pos2,pos)
185 --remove if too far away
186 if distance > self.radius then
190 multiplier = (self.radius*5) - distance
191 velocity = multiply_vec(direction,multiplier)
193 velocity = add_vec(player_velocity,velocity)
195 self.object:set_velocity(velocity)
197 if distance < 0.2 then
203 print(self.owner.." does not exist")
208 for _,object in ipairs(get_objects_inside_radius(pos, 2)) do
209 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().mobname)) then
210 object:punch(self.object, 2,
212 full_punch_interval=1.5,
213 damage_groups = {damage=3},
218 elseif self.timer > 3 and (object:is_player() and object:get_player_name() == self.owner) then
219 self.collecting = true
220 local inv = object:get_inventory()
221 if inv and inv:room_for_item("main", ItemStack("bow:arrow")) then
222 inv:add_item("main",ItemStack("bow:arrow"))
223 minetest.sound_play("pickup", {
224 to_player = object:get_player_name(),
226 pitch = random(60,100)/100
230 minetest.throw_item(pos,"bow:arrow")
235 if moveresult and moveresult.collides and moveresult.collisions and moveresult.collisions[1] and moveresult.collisions[1].new_velocity and self.stuck == false then
237 collision = moveresult.collisions[1]
239 if collision.new_velocity.x == 0 and collision.old_velocity.x ~= 0 then
240 self.check_dir = vec_direction(new_vec(pos.x,0,0),new_vec(collision.node_pos.x,0,0))
241 elseif collision.new_velocity.y == 0 and collision.old_velocity.y ~= 0 then
242 self.check_dir = vec_direction(new_vec(0,pos.y,0),new_vec(0,collision.node_pos.y,0))
243 elseif collision.new_velocity.z == 0 and collision.old_velocity.z ~= 0 then
244 self.check_dir = vec_direction(new_vec(0,0,pos.z),new_vec(0,0,collision.node_pos.z))
246 if collision.new_pos then
247 --print(dump(collision.new_pos))
248 self.object:set_pos(collision.new_pos)
250 --print(dump(collision.new_pos))
251 minetest.sound_play("arrow_hit",{object=self.object,gain=1,pitch=random(80,100)/100,max_hear_distance=64})
253 self.object:set_velocity(new_vec(0,0,0))
254 self.object:set_acceleration(new_vec(0,0,0))
255 elseif self.stuck == true and self.check_dir then
256 pos2 = add_vec(pos,multiply_vec(self.check_dir,0.2))
258 ray = create_raycast(pos, pos2, false, false)
260 if not ray:next() then
262 self.object:set_acceleration(new_vec(0,-9.81,0))
266 if not self.stuck and pos and self.oldpos then
267 self.spin = self.spin + (dtime*10)
268 if self.spin > pi then
272 dir = normalize_vec(sub_vec(pos,self.oldpos))
274 x = (dir_to_yaw(new_vec(vec_distance(new_vec(pos.x,0,pos.z),new_vec(self.oldpos.x,0,self.oldpos.z)),0,pos.y-self.oldpos.y))+(pi/2))
275 self.object:set_rotation(new_vec(x,y,self.spin))
277 if self.stuck == false then
286 █████╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗ ███████╗███╗ ██╗████████╗██╗████████╗██╗ ██╗
287 ██╔══██╗██╔══██╗██╔══██╗██╔═══██╗██║ ██║ ██╔════╝████╗ ██║╚══██╔══╝██║╚══██╔══╝╚██╗ ██╔╝
288 ███████║██████╔╝██████╔╝██║ ██║██║ █╗ ██║ █████╗ ██╔██╗ ██║ ██║ ██║ ██║ ╚████╔╝
289 ██╔══██║██╔══██╗██╔══██╗██║ ██║██║███╗██║ ██╔══╝ ██║╚██╗██║ ██║ ██║ ██║ ╚██╔╝
290 ██║ ██║██║ ██║██║ ██║╚██████╔╝╚███╔███╔╝ ███████╗██║ ╚████║ ██║ ██║ ██║ ██║
291 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
297 arrow.initial_properties = {
299 collide_with_objects = false,
300 collisionbox = {-0.05, -0.05, -0.05, 0.05, 0.05, 0.05},
302 visual_size = {x = 1 , y = 1},
303 mesh = "basic_bow_arrow.b3d",
305 "basic_bow_arrow_uv.png"
308 --automatic_face_movement_dir = 0.0,
309 --automatic_face_movement_max_rotation_per_sec = 600,
311 arrow.on_activate = function(self, staticdata, dtime_s)
312 --self.object:set_animation({x=0,y=180}, 15, 0, true)
314 if s_sub(staticdata, 1, s_len("return")) == "return" then
315 local data = deserialize(staticdata)
316 if data and type(data) == "table" then
317 self.spin = data.spin
318 self.owner = data.owner
319 self.stuck = data.stuck
320 self.timer = data.timer
321 self.collecting = data.collecting
322 self.check_dir = data.check_dir
326 if not self.stuck then
327 self.object:set_acceleration(new_vec(0,-9.81,0))
329 self.object:set_velocity(vel)
334 arrow.get_staticdata = function(self)
340 collecting = self.collecting,
341 check_dir = self.check_dir,
342 vel = self.object:get_velocity()
350 arrow.collecting = false
351 arrow.collection_height = 0.5
354 arrow.on_step = function(self, dtime,moveresult)
355 arrow_step(self, dtime,moveresult)
357 minetest.register_entity("bow:arrow", arrow)
362 ██╗████████╗███████╗███╗ ███╗███████╗
363 ██║╚══██╔══╝██╔════╝████╗ ████║██╔════╝
364 ██║ ██║ █████╗ ██╔████╔██║███████╗
365 ██║ ██║ ██╔══╝ ██║╚██╔╝██║╚════██║
366 ██║ ██║ ███████╗██║ ╚═╝ ██║███████║
367 ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝
371 local function initialize_pullback(player)
372 inv = player:get_inventory()
373 if inv:contains_item("main", ItemStack("bow:arrow")) then
374 name = player:get_player_name()
376 pool[name].index = player:get_wield_index()
379 minetest.sound_play("bow_pull_back", {object=player, gain = 1.0, max_hear_distance = 60,pitch = random(70,110)/100})
384 minetest.register_craftitem("bow:bow_empty", {
386 inventory_image = "bow.png",
390 on_secondary_use = function(itemstack, user, pointed_thing)
391 initialize_pullback(user)
393 on_place = function(itemstack, placer, pointed_thing)
394 initialize_pullback(placer)
399 minetest.register_craftitem("bow:bow_"..i, {
401 inventory_image = "bow_"..i..".png",
403 groups = {bow=1,bow_loaded=i},
405 on_drop = function(itemstack, dropper, pos)
406 itemstack = ItemStack("bow:bow_empty")
407 minetest.item_drop(itemstack, dropper, pos)
413 minetest.register_craftitem("bow:arrow", {
414 description = "Arrow",
415 inventory_image = "arrow_item.png",
421 ██████╗██████╗ █████╗ ███████╗████████╗██╗███╗ ██╗ ██████╗
422 ██╔════╝██╔══██╗██╔══██╗██╔════╝╚══██╔══╝██║████╗ ██║██╔════╝
423 ██║ ██████╔╝███████║█████╗ ██║ ██║██╔██╗ ██║██║ ███╗
424 ██║ ██╔══██╗██╔══██║██╔══╝ ██║ ██║██║╚██╗██║██║ ██║
425 ╚██████╗██║ ██║██║ ██║██║ ██║ ██║██║ ╚████║╚██████╔╝
426 ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝
430 minetest.register_craft({
431 output = "bow:bow_empty",
433 {"" , "main:stick", "mob:string"},
434 {"main:stick" , "" , "mob:string"},
435 {"" , "main:stick", "mob:string"},
439 minetest.register_craft({
440 output = "bow:arrow 16",
442 {"main:iron", "" , "" },
443 {"" , "main:stick", "" },
444 {"" , "" , "mob:feather"},