]> git.lizzy.rs Git - Crafter.git/blob - mods/bow/init.lua
Add in api elements to the train mod
[Crafter.git] / mods / bow / init.lua
1 local 
2 minetest,math,vector,ipairs,string,type
3
4 minetest,math,vector,ipairs,string,type
5
6 -- minetest library
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
14
15 -- string library
16 local s_sub  = string.sub
17 local s_len  = string.len
18
19 -- math library
20 local pi     = math.pi
21 local random = math.random
22 local floor  = math.floor
23
24 -- vector library
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
34
35
36 --[[
37 ██████╗ ██╗      █████╗ ██╗   ██╗███████╗██████╗     ██████╗  █████╗ ██████╗ ████████╗
38 ██╔══██╗██║     ██╔══██╗╚██╗ ██╔╝██╔════╝██╔══██╗    ██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝
39 ██████╔╝██║     ███████║ ╚████╔╝ █████╗  ██████╔╝    ██████╔╝███████║██████╔╝   ██║   
40 ██╔═══╝ ██║     ██╔══██║  ╚██╔╝  ██╔══╝  ██╔══██╗    ██╔═══╝ ██╔══██║██╔══██╗   ██║   
41 ██║     ███████╗██║  ██║   ██║   ███████╗██║  ██║    ██║     ██║  ██║██║  ██║   ██║   
42 ╚═╝     ╚══════╝╚═╝  ╚═╝   ╚═╝   ╚══════╝╚═╝  ╚═╝    ╚═╝     ╚═╝  ╚═╝╚═╝  ╚═╝   ╚═╝   
43 ]]--
44
45
46 -- data pool
47 local pool = {}
48
49 --this is a very complicated function which makes the bow work
50 local temp_pool
51 local player
52 local new_index
53 local rightclick
54 local inv
55 local dir
56 local vel
57 local pos
58 local object
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()
64
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"))
68                 pool[name] = nil
69                 return
70         end
71
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"))
75                 pool[name] = nil
76                 return
77         end
78
79         -- if player isn't holding a bow
80         if minetest.get_item_group(player:get_wielded_item():get_name(), "bow") == 0 then
81                 pool[name] = nil
82                 return
83         end
84
85         inv = player:get_inventory()
86
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"))
90                 pool[name] = nil
91                 return
92         end
93
94         -- count steps using dtime
95         if temp_pool.step < 5 then
96
97         temp_pool.float = temp_pool.float + dtime
98
99         if temp_pool.float > 0.05 then
100                 temp_pool.float = 0
101                 temp_pool.step  = temp_pool.step + 1
102                 player:set_wielded_item(ItemStack("bow:bow_"..temp_pool.step))
103         end
104
105         end
106
107         if temp_pool.step == 5 and not rightclick then
108                 
109                 dir = player:get_look_dir()
110                 vel = multiply_vec(dir,50)
111                 pos = player:get_pos()
112                 pos.y = pos.y + 1.5     
113
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
118                 
119                 minetest.sound_play("bow", {object=player, gain = 1.0, max_hear_distance = 60,pitch = random(80,100)/100})
120
121                 inv:remove_item("main", ItemStack("bow:arrow"))
122                 inv:set_stack("main", temp_pool.index, ItemStack("bow:bow_empty"))
123
124                 pool[name] = nil
125         end
126
127
128         --add hand fatigue timer
129         --gradually increase fatigue until cap is reached
130
131 end
132
133 minetest.register_globalstep(function(dtime)
134         for name in pairs(pool) do
135                 arrow_check(name,dtime)
136         end
137 end)
138
139
140 --[[
141  █████╗ ██████╗ ██████╗  ██████╗ ██╗    ██╗    ███████╗██╗   ██╗███╗   ██╗ ██████╗████████╗██╗ ██████╗ ███╗   ██╗███████╗
142 ██╔══██╗██╔══██╗██╔══██╗██╔═══██╗██║    ██║    ██╔════╝██║   ██║████╗  ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗  ██║██╔════╝
143 ███████║██████╔╝██████╔╝██║   ██║██║ █╗ ██║    █████╗  ██║   ██║██╔██╗ ██║██║        ██║   ██║██║   ██║██╔██╗ ██║███████╗
144 ██╔══██║██╔══██╗██╔══██╗██║   ██║██║███╗██║    ██╔══╝  ██║   ██║██║╚██╗██║██║        ██║   ██║██║   ██║██║╚██╗██║╚════██║
145 ██║  ██║██║  ██║██║  ██║╚██████╔╝╚███╔███╔╝    ██║     ╚██████╔╝██║ ╚████║╚██████╗   ██║   ██║╚██████╔╝██║ ╚████║███████║
146 ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═╝ ╚═════╝  ╚══╝╚══╝     ╚═╝      ╚═════╝ ╚═╝  ╚═══╝ ╚═════╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝  ╚═══╝╚══════╝
147 ]]--
148
149 local pos
150 local vel
151 local owner
152 local pos2
153 local player_velocity
154 local direction
155 local distance
156 local multiplier
157 local velocity
158 local collision
159 local ray
160 local dir
161 local y
162 local x
163 local function arrow_step(self, dtime,moveresult)
164         self.timer = self.timer + dtime
165
166         pos = self.object:get_pos()
167         vel = self.object:get_velocity()
168         
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
172                         
173                         if owner then
174                                 self.object:set_acceleration(new_vec(0,0,0))
175
176                                 --get the variables
177                                 pos2 = owner:get_pos()
178                                 player_velocity = owner:get_player_velocity()
179                                 pos2.y = pos2.y + self.collection_height
180                                                                 
181                                 direction = normalize_vec(sub_vec(pos2,pos))
182                                 distance = vec_distance(pos2,pos)
183                                                                 
184                                 
185                                 --remove if too far away
186                                 if distance > self.radius then
187                                         distance = 0
188                                 end
189                                                                 
190                                 multiplier = (self.radius*5) - distance
191                                 velocity = multiply_vec(direction,multiplier)
192                                 
193                                 velocity = add_vec(player_velocity,velocity)
194                                 
195                                 self.object:set_velocity(velocity)
196                                 
197                                 if distance < 0.2 then
198                                         self.object:remove()
199                                 end
200                                 
201                                 return
202                         else
203                                 print(self.owner.." does not exist")
204                                 self.object:remove()
205                         end
206                 end
207         else
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, 
211                                         {
212                                         full_punch_interval=1.5,
213                                         damage_groups = {damage=3},
214                                 })
215
216                                 self.object:remove()
217                                 return
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(),
225                                                 gain = 0.4,
226                                                 pitch = random(60,100)/100
227                                         })
228                                 else
229                                         self.object:remove()
230                                         minetest.throw_item(pos,"bow:arrow")
231                                 end
232                         end
233                 end
234
235                 if moveresult and moveresult.collides and moveresult.collisions and moveresult.collisions[1] and moveresult.collisions[1].new_velocity and self.stuck == false then
236                         
237                         collision = moveresult.collisions[1]
238
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))
245                         end
246                         if collision.new_pos then
247                                 --print(dump(collision.new_pos))
248                                 self.object:set_pos(collision.new_pos)
249                         end
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})
252                         self.stuck = true
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))
257                         
258                         ray = create_raycast(pos, pos2, false, false)
259
260                         if not ray:next() then
261                                 self.stuck = false
262                                 self.object:set_acceleration(new_vec(0,-9.81,0))
263                         end
264                 end
265                 
266                 if not self.stuck and pos and self.oldpos then
267                         self.spin = self.spin + (dtime*10)
268                         if self.spin > pi then
269                                 self.spin = -pi
270                         end
271
272                         dir = normalize_vec(sub_vec(pos,self.oldpos))
273                         y = dir_to_yaw(dir)
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))
276                 end
277                 if self.stuck == false then
278                         self.oldpos = pos
279                         self.oldvel = vel
280                 end
281         end
282 end
283
284
285 --[[
286  █████╗ ██████╗ ██████╗  ██████╗ ██╗    ██╗    ███████╗███╗   ██╗████████╗██╗████████╗██╗   ██╗
287 ██╔══██╗██╔══██╗██╔══██╗██╔═══██╗██║    ██║    ██╔════╝████╗  ██║╚══██╔══╝██║╚══██╔══╝╚██╗ ██╔╝
288 ███████║██████╔╝██████╔╝██║   ██║██║ █╗ ██║    █████╗  ██╔██╗ ██║   ██║   ██║   ██║    ╚████╔╝ 
289 ██╔══██║██╔══██╗██╔══██╗██║   ██║██║███╗██║    ██╔══╝  ██║╚██╗██║   ██║   ██║   ██║     ╚██╔╝  
290 ██║  ██║██║  ██║██║  ██║╚██████╔╝╚███╔███╔╝    ███████╗██║ ╚████║   ██║   ██║   ██║      ██║   
291 ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═╝ ╚═════╝  ╚══╝╚══╝     ╚══════╝╚═╝  ╚═══╝   ╚═╝   ╚═╝   ╚═╝      ╚═╝   
292 ]]--
293
294
295
296 local arrow = {}
297 arrow.initial_properties = {
298         physical = true,
299         collide_with_objects = false,
300         collisionbox = {-0.05, -0.05, -0.05, 0.05, 0.05, 0.05},
301         visual = "mesh",
302         visual_size = {x = 1 , y = 1},
303         mesh = "basic_bow_arrow.b3d",
304         textures = {
305                 "basic_bow_arrow_uv.png"
306         },
307         pointable = false,
308         --automatic_face_movement_dir = 0.0,
309         --automatic_face_movement_max_rotation_per_sec = 600,
310 }
311 arrow.on_activate = function(self, staticdata, dtime_s)
312         --self.object:set_animation({x=0,y=180}, 15, 0, true)
313         local vel = nil
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
323                         vel             = data.vel
324                 end
325         end
326         if not self.stuck then
327                 self.object:set_acceleration(new_vec(0,-9.81,0))
328                 if vel then
329                         self.object:set_velocity(vel)
330                 end
331         end
332 end
333
334 arrow.get_staticdata = function(self)
335         return serialize({
336                 spin       = self.spin,
337                 owner      = self.owner,
338                 stuck      = self.stuck,
339                 timer      = self.timer,
340                 collecting = self.collecting,
341                 check_dir  = self.check_dir,
342                 vel        = self.object:get_velocity()
343         })
344 end
345
346 arrow.spin = 0
347 arrow.owner = ""
348 arrow.stuck = false
349 arrow.timer = 0
350 arrow.collecting = false
351 arrow.collection_height = 0.5
352 arrow.radius = 2
353
354 arrow.on_step = function(self, dtime,moveresult)
355         arrow_step(self, dtime,moveresult)
356 end
357 minetest.register_entity("bow:arrow", arrow)
358
359
360
361 --[[
362 ██╗████████╗███████╗███╗   ███╗███████╗
363 ██║╚══██╔══╝██╔════╝████╗ ████║██╔════╝
364 ██║   ██║   █████╗  ██╔████╔██║███████╗
365 ██║   ██║   ██╔══╝  ██║╚██╔╝██║╚════██║
366 ██║   ██║   ███████╗██║ ╚═╝ ██║███████║
367 ╚═╝   ╚═╝   ╚══════╝╚═╝     ╚═╝╚══════╝
368 ]]--
369
370 local inv
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()
375                 pool[name] = {}
376                 pool[name].index = player:get_wield_index()
377                 pool[name].float = 0
378                 pool[name].step  = 0
379                 minetest.sound_play("bow_pull_back", {object=player, gain = 1.0, max_hear_distance = 60,pitch = random(70,110)/100})
380         end
381 end
382
383
384 minetest.register_craftitem("bow:bow_empty", {
385         description = "Bow",
386         inventory_image = "bow.png",
387         stack_max = 1,
388         groups = {bow=1},
389         range = 0,
390         on_secondary_use = function(itemstack, user, pointed_thing)
391                 initialize_pullback(user)
392         end,
393         on_place = function(itemstack, placer, pointed_thing)
394                 initialize_pullback(placer)
395         end,
396 })
397
398 for i = 1,5 do
399         minetest.register_craftitem("bow:bow_"..i, {
400                 description = "Bow",
401                 inventory_image = "bow_"..i..".png",
402                 stack_max = 1,
403                 groups = {bow=1,bow_loaded=i},
404                 range = 0,
405                 on_drop = function(itemstack, dropper, pos)
406                         itemstack = ItemStack("bow:bow_empty")
407                         minetest.item_drop(itemstack, dropper, pos)
408                         return(itemstack)
409                 end,
410         })
411 end
412
413 minetest.register_craftitem("bow:arrow", {
414         description = "Arrow",
415         inventory_image = "arrow_item.png",
416 })
417
418
419
420 --[[
421  ██████╗██████╗  █████╗ ███████╗████████╗██╗███╗   ██╗ ██████╗ 
422 ██╔════╝██╔══██╗██╔══██╗██╔════╝╚══██╔══╝██║████╗  ██║██╔════╝ 
423 ██║     ██████╔╝███████║█████╗     ██║   ██║██╔██╗ ██║██║  ███╗
424 ██║     ██╔══██╗██╔══██║██╔══╝     ██║   ██║██║╚██╗██║██║   ██║
425 ╚██████╗██║  ██║██║  ██║██║        ██║   ██║██║ ╚████║╚██████╔╝
426  ╚═════╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝        ╚═╝   ╚═╝╚═╝  ╚═══╝ ╚═════╝ 
427 ]]--
428
429
430 minetest.register_craft({
431         output = "bow:bow_empty",
432         recipe = {
433                 {""           , "main:stick", "mob:string"},
434                 {"main:stick" , ""          , "mob:string"},
435                 {""           , "main:stick", "mob:string"},
436         },
437 })
438
439 minetest.register_craft({
440         output = "bow:arrow 16",
441         recipe = {
442                 {"main:iron", ""          , ""           },
443                 {""         , "main:stick", ""           },
444                 {""         , ""          , "mob:feather"},
445         },
446 })