4 ["mcl_throwing:arrow"] = "mcl_throwing:arrow_entity",
8 local BOW_DURABILITY
= 385
9 local BOW_CHARGE_TIME_HALF
= 500000
10 local BOW_CHARGE_TIME_FULL
= 1000000
12 -- TODO: Use Minecraft speed (ca. 53 m/s)
13 -- Currently nerfed because at full speed the arrow would easily get out of the range of the loaded map.
14 local BOW_MAX_SPEED
= 26
18 mcl_throwing
.shoot_arrow
= function(arrow_item
, pos
, dir
, yaw
, shooter
, power
, damage
)
19 local obj
= minetest
.add_entity({x
=pos
.x
,y
=pos
.y
,z
=pos
.z
}, arrows
[arrow_item
])
26 obj
:setvelocity({x
=dir
.x
*power
, y
=dir
.y
*power
, z
=dir
.z
*power
})
27 obj
:setacceleration({x
=dir
.x
*-3, y
=-GRAVITY
, z
=dir
.z
*-3})
28 obj
:setyaw(yaw
-math
.pi
/2)
29 local le
= obj
:get_luaentity()
33 minetest
.sound_play("mcl_throwing_bow_shoot", {pos
=pos
})
34 if shooter
~= nil then
35 if obj
:get_luaentity().player
== "" then
36 obj
:get_luaentity().player
= shooter
38 obj
:get_luaentity().node
= shooter
:get_inventory():get_stack("main", 1):get_name()
43 local get_arrow
= function(player
)
44 local inv
= player
:get_inventory()
45 local arrow_stack
, arrow_stack_id
46 for i
=1, inv
:get_size("main") do
47 local it
= inv
:get_stack("main", i
)
48 if not it
:is_empty() and minetest
.get_item_group(it
:get_name(), "ammo_bow") ~= 0 then
54 return arrow_stack
, arrow_stack_id
57 local player_shoot_arrow
= function(itemstack
, player
, power
, damage
)
58 local arrow_stack
, arrow_stack_id
= get_arrow(player
)
59 local arrow_itemstring
60 if not minetest
.settings
:get_bool("creative_mode") then
61 if not arrow_stack
then
64 arrow_itemstring
= arrow_stack
:get_name()
65 arrow_stack
:take_item()
66 local inv
= player
:get_inventory()
67 inv
:set_stack("main", arrow_stack_id
, arrow_stack
)
69 local playerpos
= player
:getpos()
70 local dir
= player
:get_look_dir()
71 local yaw
= player
:get_look_horizontal()
73 if not arrow_itemstring
then
74 arrow_itemstring
= "mcl_throwing:arrow"
76 mcl_throwing
.shoot_arrow(arrow_itemstring
, {x
=playerpos
.x
,y
=playerpos
.y
+1.5,z
=playerpos
.z
}, dir
, yaw
, player
, power
, damage
)
80 minetest
.register_tool("mcl_throwing:bow", {
82 _doc_items_longdesc
= "Bows are ranged weapons to shoot arrows at your foes.",
83 _doc_items_usagehelp
= [[To use the bow, you first need to have at least one arrow anywhere in your inventory (unless in Creative Mode). Hold down the right mouse button to charge, release to shoot.
85 The arrow speed and damage increase the longer you charge. The minimum damage is 1. At full charge, the damage is 9 with a 20% chance of a critical hit dealing 10 damage instead.]],
86 _doc_items_durability
= BOW_DURABILITY
,
87 inventory_image
= "mcl_throwing_bow.png",
89 -- Trick to disable melee damage to entities.
90 -- Range not set to 0 (unlike the others) so it can be placed into item frames
92 -- Trick to disable digging as well
93 on_use
= function() end,
94 groups
= {weapon
=1,weapon_ranged
=1},
97 minetest
.register_tool("mcl_throwing:bow_0", {
99 _doc_items_create_entry
= false,
100 inventory_image
= "mcl_throwing_bow_0.png",
102 range
= 0, -- Pointing range to 0 to prevent punching with bow :D
103 groups
= {not_in_creative_inventory
=1, not_in_craft_guide
=1},
106 minetest
.register_tool("mcl_throwing:bow_1", {
108 _doc_items_create_entry
= false,
109 inventory_image
= "mcl_throwing_bow_1.png",
112 groups
= {not_in_creative_inventory
=1, not_in_craft_guide
=1},
115 minetest
.register_tool("mcl_throwing:bow_2", {
117 _doc_items_create_entry
= false,
118 inventory_image
= "mcl_throwing_bow_2.png",
121 groups
= {not_in_creative_inventory
=1, not_in_craft_guide
=1},
124 controls
.register_on_release(function(player
, key
, time
)
125 if key
~="RMB" then return end
126 local inv
= minetest
.get_inventory({type="player", name
=player
:get_player_name()})
127 local wielditem
= player
:get_wielded_item()
128 if (wielditem
:get_name()=="mcl_throwing:bow_0" or wielditem
:get_name()=="mcl_throwing:bow_1" or wielditem
:get_name()=="mcl_throwing:bow_2") then
129 local has_shot
= false
132 local charge
= minetest
.get_us_time() - bow_load
[player
:get_player_name()]
133 charge
= math
.max(math
.min(charge
, BOW_CHARGE_TIME_FULL
), 0)
134 local charge_ratio
= charge
/ BOW_CHARGE_TIME_FULL
135 charge_ratio
= math
.max(math
.min(charge_ratio
, 1), 0)
137 -- Calculate damage and speed
139 if charge
>= BOW_CHARGE_TIME_FULL
then
140 speed
= BOW_MAX_SPEED
141 local r
= math
.random(1,5)
142 -- Damage and range have been nerfed because the arrow charges very quickly
144 -- 20% chance for critical hit
151 -- Linear speed and damage increase
152 speed
= math
.max(4, BOW_MAX_SPEED
* charge_ratio
)
153 damage
= math
.max(1, math
.floor(9 * charge_ratio
))
156 has_shot
= player_shoot_arrow(wielditem
, player
, speed
, damage
)
158 wielditem
:set_name("mcl_throwing:bow")
159 if has_shot
and minetest
.settings
:get_bool("creative_mode") == false then
160 wielditem
:add_wear(65535/BOW_DURABILITY
)
162 player
:set_wielded_item(wielditem
)
163 bow_load
[player
:get_player_name()] = false
167 controls
.register_on_hold(function(player
, key
, time
)
171 local name
= player
:get_player_name()
172 local inv
= minetest
.get_inventory({type="player", name
=name
})
173 local wielditem
= player
:get_wielded_item()
174 if wielditem
:get_name()=="mcl_throwing:bow" and (minetest
.settings
:get_bool("creative_mode") or inv
:contains_item("main", "mcl_throwing:arrow")) then
175 wielditem
:set_name("mcl_throwing:bow_0")
176 bow_load
[name
] = minetest
.get_us_time()
178 if type(bow_load
[name
]) == "number" then
179 if wielditem
:get_name() == "mcl_throwing:bow_0" and minetest
.get_us_time() - bow_load
[name
] >= BOW_CHARGE_TIME_HALF
then
180 wielditem
:set_name("mcl_throwing:bow_1")
181 elseif wielditem
:get_name() == "mcl_throwing:bow_1" and minetest
.get_us_time() - bow_load
[name
] >= BOW_CHARGE_TIME_FULL
then
182 wielditem
:set_name("mcl_throwing:bow_2")
185 wielditem
:set_name("mcl_throwing:bow")
188 player
:set_wielded_item(wielditem
)
191 minetest
.register_globalstep(function(dtime
)
192 for _
, player
in pairs(minetest
.get_connected_players()) do
193 local wielditem
= player
:get_wielded_item()
194 local controls
= player
:get_player_control()
195 local inv
= minetest
.get_inventory({type="player", name
= player
:get_player_name()})
196 if bow_load
[player
:get_player_name()] and (wielditem
:get_name()~="mcl_throwing:bow_0" and wielditem
:get_name()~="mcl_throwing:bow_1" and wielditem
:get_name()~="mcl_throwing:bow_2") then
197 local list
= inv
:get_list("main")
198 for place
, stack
in pairs(list
) do
199 if stack
:get_name()=="mcl_throwing:bow_0" or stack
:get_name()=="mcl_throwing:bow_1" or stack
:get_name()=="mcl_throwing:bow_2" then
200 stack
:set_name("mcl_throwing:bow")
205 inv
:set_list("main", list
)
206 bow_load
[player
:get_player_name()] = false
211 if minetest
.get_modpath("mcl_core") and minetest
.get_modpath("mcl_mobitems") then
212 minetest
.register_craft({
213 output
= 'mcl_throwing:bow',
215 {'', 'mcl_core:stick', 'mcl_mobitems:string'},
216 {'mcl_core:stick', '', 'mcl_mobitems:string'},
217 {'', 'mcl_core:stick', 'mcl_mobitems:string'},
220 minetest
.register_craft({
221 output
= 'mcl_throwing:bow',
223 {'mcl_mobitems:string', 'mcl_core:stick', ''},
224 {'mcl_mobitems:string', '', 'mcl_core:stick'},
225 {'mcl_mobitems:string', 'mcl_core:stick', ''},
230 minetest
.register_craft({
232 recipe
= "mcl_throwing:bow",
236 -- Add entry aliases for the Help
237 if minetest
.get_modpath("doc") then
238 doc
.add_entry_alias("tools", "mcl_throwing:bow", "tools", "mcl_throwing:bow_0")
239 doc
.add_entry_alias("tools", "mcl_throwing:bow", "tools", "mcl_throwing:bow_1")
240 doc
.add_entry_alias("tools", "mcl_throwing:bow", "tools", "mcl_throwing:bow_2")