Use minetest.raycast
This commit is contained in:
parent
075cbe2e52
commit
49d6fe5741
4 changed files with 176 additions and 384 deletions
444
shooter/api.lua
444
shooter/api.lua
|
@ -1,16 +1,9 @@
|
||||||
shooter = {
|
shooter = {
|
||||||
time = 0,
|
registered_weapons = {},
|
||||||
objects = {},
|
|
||||||
rounds = {},
|
|
||||||
shots = {},
|
|
||||||
update_time = 0,
|
|
||||||
reload_time = 0,
|
|
||||||
player_offset = {x=0, y=1, z=0},
|
|
||||||
entity_offset = {x=0, y=0, z=0},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shooter.config = {
|
shooter.config = {
|
||||||
admin_weapons = false,
|
admin_weapons = true,
|
||||||
enable_blasting = false,
|
enable_blasting = false,
|
||||||
enable_particle_fx = true,
|
enable_particle_fx = true,
|
||||||
enable_protection = false,
|
enable_protection = false,
|
||||||
|
@ -19,25 +12,66 @@ shooter.config = {
|
||||||
allow_nodes = true,
|
allow_nodes = true,
|
||||||
allow_entities = false,
|
allow_entities = false,
|
||||||
allow_players = true,
|
allow_players = true,
|
||||||
object_reload_time = 1,
|
|
||||||
object_update_time = 0.25,
|
|
||||||
rounds_update_time = 0.4,
|
rounds_update_time = 0.4,
|
||||||
|
camera_height = 1.5,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local rounds = {}
|
||||||
|
local shots = {}
|
||||||
|
local shooting = {}
|
||||||
local config = shooter.config
|
local config = shooter.config
|
||||||
local singleplayer = minetest.is_singleplayer()
|
local server_step = minetest.settings:get("dedicated_server_step")
|
||||||
local allowed_entities = {}
|
|
||||||
|
|
||||||
local function get_dot_product(v1, v2)
|
function shooter:register_weapon(name, def)
|
||||||
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
|
shooter.registered_weapons[name] = def
|
||||||
end
|
-- Fix definition table
|
||||||
|
def.sounds = def.sounds or {}
|
||||||
local function get_particle_pos(p, v, d)
|
def.sounds.reload = def.sounds.reload or "shooter_reload"
|
||||||
return vector.add(p, vector.multiply(v, {x=d, y=d, z=d}))
|
def.sounds.fail_shot = def.sounds.fail_shot or "shooter_click"
|
||||||
end
|
def.reload_item = def.reload_item or "shooter:ammo"
|
||||||
|
def.spec.tool_caps.full_punch_interval = math.max(server_step,
|
||||||
function shooter:set_shootable_entity(name)
|
def.spec.tool_caps.full_punch_interval)
|
||||||
allowed_entities[name] = 1
|
def.spec.wear = math.ceil(65535 / def.spec.rounds)
|
||||||
|
def.spec.unloaded_item = name
|
||||||
|
def.unloaded_item = def.unloaded_item or {
|
||||||
|
description = def.description.." (unloaded)",
|
||||||
|
inventory_image = def.inventory_image,
|
||||||
|
}
|
||||||
|
-- Register loaded item tool
|
||||||
|
minetest.register_tool(name.."_loaded", {
|
||||||
|
description = def.description,
|
||||||
|
inventory_image = def.inventory_image,
|
||||||
|
on_use = function(itemstack, user)
|
||||||
|
if shooter:fire_weapon(user, itemstack, def.spec) then
|
||||||
|
itemstack:add_wear(def.spec.wear)
|
||||||
|
if itemstack:get_count() == 0 then
|
||||||
|
itemstack = def.unloaded_item.name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
|
groups = {not_in_creative_inventory=1},
|
||||||
|
})
|
||||||
|
-- Register unloaded item tool
|
||||||
|
minetest.register_tool(name, {
|
||||||
|
description = def.unloaded_item.description,
|
||||||
|
inventory_image = def.unloaded_item.inventory_image,
|
||||||
|
groups = def.unloaded_item.groups or {},
|
||||||
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
local inv = user:get_inventory()
|
||||||
|
if inv then
|
||||||
|
local stack = def.reload_item
|
||||||
|
if inv:contains_item("main", stack) then
|
||||||
|
minetest.sound_play((def.sounds.reload), {object=user})
|
||||||
|
inv:remove_item("main", stack)
|
||||||
|
itemstack:replace(name.."_loaded 1 1")
|
||||||
|
else
|
||||||
|
minetest.sound_play((def.sounds.fail_shot), {object=user})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function shooter:spawn_particles(pos, texture)
|
function shooter:spawn_particles(pos, texture)
|
||||||
|
@ -68,7 +102,7 @@ function shooter:play_node_sound(node, pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function shooter:punch_node(pos, def)
|
function shooter:punch_node(pos, spec)
|
||||||
local node = minetest.get_node(pos)
|
local node = minetest.get_node(pos)
|
||||||
if not node then
|
if not node then
|
||||||
return
|
return
|
||||||
|
@ -78,12 +112,12 @@ function shooter:punch_node(pos, def)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if config.enable_protection then
|
if config.enable_protection then
|
||||||
if minetest.is_protected(pos, def.name) then
|
if minetest.is_protected(pos, spec.user) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if item.groups then
|
if item.groups then
|
||||||
for k, v in pairs(def.groups) do
|
for k, v in pairs(spec.groups) do
|
||||||
local level = item.groups[k] or 0
|
local level = item.groups[k] or 0
|
||||||
if level >= v then
|
if level >= v then
|
||||||
minetest.remove_node(pos)
|
minetest.remove_node(pos)
|
||||||
|
@ -107,264 +141,105 @@ function shooter:is_valid_object(object)
|
||||||
if config.allow_entities == true then
|
if config.allow_entities == true then
|
||||||
local luaentity = object:get_luaentity()
|
local luaentity = object:get_luaentity()
|
||||||
if luaentity then
|
if luaentity then
|
||||||
if luaentity.name then
|
return luaentity.name ~= "__builtin:item"
|
||||||
if allowed_entities[luaentity.name] then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function shooter:get_intersect_pos(ray, plane, collisionbox)
|
local function process_round(round)
|
||||||
local v = vector.subtract(ray.pos, plane.pos)
|
round.dist = round.dist + round.spec.step
|
||||||
local r1 = get_dot_product(v, plane.normal)
|
if round.dist > round.spec.range then
|
||||||
local r2 = get_dot_product(ray.dir, plane.normal)
|
|
||||||
if r2 ~= 0 then
|
|
||||||
local t = -(r1 / r2)
|
|
||||||
local td = vector.multiply(ray.dir, {x=t, y=t, z=t})
|
|
||||||
local pt = vector.add(ray.pos, td)
|
|
||||||
local pd = vector.subtract(pt, plane.pos)
|
|
||||||
if math.abs(pd.x) < collisionbox[4] and
|
|
||||||
math.abs(pd.y) < collisionbox[5] and
|
|
||||||
math.abs(pd.z) < collisionbox[6] then
|
|
||||||
return pt
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function shooter:process_round(round)
|
|
||||||
local target = {object=nil, distance=10000}
|
|
||||||
local p1 = round.pos
|
|
||||||
local v1 = round.ray
|
|
||||||
for _,ref in ipairs(shooter.objects) do
|
|
||||||
local p2 = vector.add(ref.pos, ref.offset)
|
|
||||||
if p1 and p2 and ref.name ~= round.name then
|
|
||||||
local d = vector.distance(p1, p2)
|
|
||||||
if d < round.def.step and d < target.distance then
|
|
||||||
local ray = {pos=p1, dir=v1}
|
|
||||||
local plane = {pos=p2, normal={x=-1, y=0, z=-1}}
|
|
||||||
local pos = shooter:get_intersect_pos(ray, plane, ref.collisionbox)
|
|
||||||
if pos then
|
|
||||||
target.object = ref.object
|
|
||||||
target.pos = pos
|
|
||||||
target.distance = d
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if target.object and target.pos then
|
|
||||||
local success, pos = minetest.line_of_sight(p1, target.pos, 1)
|
|
||||||
if success then
|
|
||||||
local user = minetest.get_player_by_name(round.name)
|
|
||||||
if user then
|
|
||||||
target.object:punch(user, nil, round.def.tool_caps, v1)
|
|
||||||
shooter:spawn_particles(target.pos, config.explosion_texture)
|
|
||||||
end
|
|
||||||
return 1
|
|
||||||
elseif pos and config.allow_nodes == true then
|
|
||||||
shooter:punch_node(pos, round.def)
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
elseif config.allow_nodes == true then
|
|
||||||
local d = round.def.step
|
|
||||||
local p2 = vector.add(p1, vector.multiply(v1, {x=d, y=d, z=d}))
|
|
||||||
local success, pos = minetest.line_of_sight(p1, p2, 1)
|
|
||||||
if pos then
|
|
||||||
shooter:punch_node(pos, round.def)
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
shooter.registered_weapons = shooter.registered_weapons or {}
|
|
||||||
function shooter:register_weapon(name, def)
|
|
||||||
shooter.registered_weapons[name] = def
|
|
||||||
local shots = def.shots or 1
|
|
||||||
local wear = math.ceil(65534 / def.rounds)
|
|
||||||
local max_wear = (def.rounds - 1) * wear
|
|
||||||
-- Fix sounds table
|
|
||||||
def.sounds = def.sounds or {}
|
|
||||||
-- Default sounds
|
|
||||||
def.sounds.reload = def.sounds.reload or "shooter_reload"
|
|
||||||
def.sounds.fail_shot = def.sounds.fail_shot or "shooter_click"
|
|
||||||
-- Assert reload item
|
|
||||||
def.reload_item = def.reload_item or "shooter:ammo"
|
|
||||||
minetest.register_tool(name, {
|
|
||||||
description = def.description,
|
|
||||||
inventory_image = def.inventory_image,
|
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
|
||||||
if itemstack:get_wear() < max_wear then
|
|
||||||
def.spec.name = user:get_player_name()
|
|
||||||
if shots > 1 then
|
|
||||||
local step = def.spec.tool_caps.full_punch_interval
|
|
||||||
for i = 0, step * shots, step do
|
|
||||||
minetest.after(i, function()
|
|
||||||
shooter:fire_weapon(user, pointed_thing, def.spec)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
shooter:fire_weapon(user, pointed_thing, def.spec)
|
|
||||||
end
|
|
||||||
itemstack:add_wear(wear)
|
|
||||||
else
|
|
||||||
local inv = user:get_inventory()
|
|
||||||
if inv then
|
|
||||||
local stack = def.reload_item .. " 1"
|
|
||||||
if inv:contains_item("main", stack) then
|
|
||||||
minetest.sound_play((def.sounds.reload), {object=user})
|
|
||||||
inv:remove_item("main", stack)
|
|
||||||
if def.unloaded_item then
|
|
||||||
itemstack:replace(def.unloaded_item.name.." 1 1")
|
|
||||||
else
|
|
||||||
itemstack:replace(name.." 1 1")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
minetest.sound_play((def.sounds.fail_shot), {object=user})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- Replace to unloaded item
|
|
||||||
if def.unloaded_item and (itemstack:get_wear() + wear) > 65534 then
|
|
||||||
itemstack:set_name(def.unloaded_item.name)
|
|
||||||
end
|
|
||||||
return itemstack
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
-- Register unloaded item tool
|
|
||||||
if def.unloaded_item then
|
|
||||||
local groups = {}
|
|
||||||
if def.unloaded_item.not_in_creative_inventory == true then
|
|
||||||
groups = {not_in_creative_inventory=1}
|
|
||||||
end
|
|
||||||
minetest.register_tool(def.unloaded_item.name, {
|
|
||||||
description = def.unloaded_item.description,
|
|
||||||
inventory_image = def.unloaded_item.inventory_image,
|
|
||||||
groups = groups,
|
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
|
||||||
local inv = user:get_inventory()
|
|
||||||
if inv then
|
|
||||||
local stack = def.reload_item .. " 1"
|
|
||||||
if inv:contains_item("main", stack) then
|
|
||||||
minetest.sound_play((def.sounds.reload), {object=user})
|
|
||||||
inv:remove_item("main", stack)
|
|
||||||
itemstack:replace(name.." 1 1")
|
|
||||||
else
|
|
||||||
minetest.sound_play((def.sounds.fail_shot), {object=user})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return itemstack
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function shooter:fire_weapon(user, pointed_thing, def)
|
|
||||||
if shooter.shots[def.name] then
|
|
||||||
if shooter.time < shooter.shots[def.name] then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
shooter.shots[def.name] = shooter.time + def.tool_caps.full_punch_interval
|
|
||||||
minetest.sound_play(def.sound, {object=user})
|
|
||||||
local v1 = user:get_look_dir()
|
|
||||||
local p1 = user:getpos()
|
|
||||||
if not v1 or not p1 then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
minetest.add_particle({x=p1.x, y=p1.y + 1.6, z=p1.z},
|
local p1 = round.pos
|
||||||
vector.multiply(v1, {x=30, y=30, z=30}),
|
local p2 = vector.add(p1, vector.multiply(round.dir, round.spec.step))
|
||||||
{x=0, y=0, z=0}, 0.5, 0.25,
|
local ray = minetest.raycast(p1, p2, true, true)
|
||||||
false, def.particle
|
local pointed_thing = ray:next() or {}
|
||||||
)
|
if pointed_thing.type == "node" then
|
||||||
if pointed_thing.type == "node" and config.allow_nodes == true then
|
if config.allow_nodes == true then
|
||||||
local pos = minetest.get_pointed_thing_position(pointed_thing, false)
|
local pos = minetest.get_pointed_thing_position(pointed_thing, false)
|
||||||
shooter:punch_node(pos, def)
|
shooter:punch_node(pos, round.spec)
|
||||||
|
end
|
||||||
|
return
|
||||||
elseif pointed_thing.type == "object" then
|
elseif pointed_thing.type == "object" then
|
||||||
local object = pointed_thing.ref
|
local object = pointed_thing.ref
|
||||||
if shooter:is_valid_object(object) == true then
|
if shooter:is_valid_object(object) == true then
|
||||||
object:punch(user, nil, def.tool_caps, v1)
|
local player = minetest.get_player_by_name(round.spec.user)
|
||||||
local p2 = object:getpos()
|
if player then
|
||||||
local pp = get_particle_pos(p1, v1, vector.distance(p1, p2))
|
object:punch(player, nil, round.spec.tool_caps, round.dir)
|
||||||
pp.y = pp.y + 1.75
|
local pos = pointed_thing.intersection_point or object:get_pos()
|
||||||
shooter:spawn_particles(pp, config.explosion_texture)
|
shooter:spawn_particles(pos, config.explosion_texture)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
return
|
||||||
shooter:update_objects()
|
|
||||||
table.insert(shooter.rounds, {
|
|
||||||
name = def.name,
|
|
||||||
pos = vector.add(p1, {x=0, y=1.75, z=0}),
|
|
||||||
ray = v1,
|
|
||||||
dist = 0,
|
|
||||||
def = def,
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
|
round.pos = p2
|
||||||
|
minetest.after(shooter.config.rounds_update_time, function(round)
|
||||||
|
process_round(round)
|
||||||
|
end, round)
|
||||||
end
|
end
|
||||||
|
|
||||||
function shooter:load_objects()
|
local function fire_weapon(player, itemstack, spec, extended)
|
||||||
local objects = {}
|
if not player then
|
||||||
if config.allow_players == true then
|
return
|
||||||
local players = minetest.get_connected_players()
|
end
|
||||||
for _,player in ipairs(players) do
|
local dir = player:get_look_dir()
|
||||||
local pos = player:getpos()
|
local pos = player:get_pos()
|
||||||
local name = player:get_player_name()
|
if not dir or not pos then
|
||||||
local hp = player:get_hp() or 0
|
return
|
||||||
if pos and name and hp > 0 then
|
end
|
||||||
table.insert(objects, {
|
pos.y = pos.y + config.camera_height
|
||||||
name = name,
|
minetest.sound_play(spec.sound, {object=player})
|
||||||
object = player,
|
minetest.add_particle({
|
||||||
pos = pos,
|
pos = pos,
|
||||||
collisionbox = {-0.25,-1.0,-0.25, 0.25,0.8,0.25},
|
velocity = vector.multiply(dir, 30),
|
||||||
offset = shooter.player_offset,
|
acceleration = {x=0, y=0, z=0},
|
||||||
})
|
expirationtime = 0.5,
|
||||||
end
|
size = 0.25,
|
||||||
|
texture = spec.particle,
|
||||||
|
})
|
||||||
|
process_round({
|
||||||
|
spec = spec,
|
||||||
|
pos = vector.add(pos, dir),
|
||||||
|
dir = dir,
|
||||||
|
dist = 0,
|
||||||
|
})
|
||||||
|
if extended then
|
||||||
|
itemstack:add_wear(spec.wear)
|
||||||
|
if itemstack:get_count() == 0 then
|
||||||
|
itemstack = spec.unloaded_item
|
||||||
|
player:set_wielded_item(itemstack)
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
player:set_wielded_item(itemstack)
|
||||||
end
|
end
|
||||||
if config.allow_entities == true then
|
if not spec.automatic or not shooting[spec.user] then
|
||||||
for _,ref in pairs(minetest.luaentities) do
|
return
|
||||||
if ref.object and ref.name then
|
end
|
||||||
if allowed_entities[ref.name] then
|
local interval = spec.tool_caps.full_punch_interval
|
||||||
local pos = ref.object:getpos()
|
shots[spec.user] = minetest.get_us_time() / 1000000 + interval
|
||||||
local hp = ref.object:get_hp() or 0
|
minetest.after(interval, function(player, itemstack, spec)
|
||||||
if pos and hp > 0 then
|
if shooting[spec.user] then
|
||||||
local def = minetest.registered_entities[ref.name]
|
fire_weapon(player, itemstack, spec, true)
|
||||||
table.insert(objects, {
|
|
||||||
name = ref.name,
|
|
||||||
object = ref.object,
|
|
||||||
pos = pos,
|
|
||||||
collisionbox = def.collisionbox or {0,0,0, 0,0,0},
|
|
||||||
offset = shooter.entity_offset,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end, player, itemstack, spec)
|
||||||
shooter.reload_time = shooter.time
|
|
||||||
shooter.update_time = shooter.time
|
|
||||||
shooter.objects = {}
|
|
||||||
for _,v in ipairs(objects) do
|
|
||||||
table.insert(shooter.objects, v)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function shooter:update_objects()
|
function shooter:fire_weapon(player, itemstack, spec)
|
||||||
if shooter.time - shooter.reload_time > config.object_reload_time then
|
local name = player:get_player_name()
|
||||||
shooter:load_objects()
|
local time = minetest.get_us_time() / 1000000
|
||||||
elseif shooter.time - shooter.update_time > config.object_update_time then
|
if shots[name] and time <= shots[name] then
|
||||||
for i, ref in ipairs(shooter.objects) do
|
return false
|
||||||
if ref.object then
|
|
||||||
local pos = ref.object:getpos()
|
|
||||||
if pos then
|
|
||||||
shooter.objects[i].pos = pos
|
|
||||||
end
|
|
||||||
else
|
|
||||||
table.remove(shooter.objects, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
shooter.update_time = shooter.time
|
|
||||||
end
|
end
|
||||||
|
if config.admin_weapons and minetest.check_player_privs(name,
|
||||||
|
{server=true}) then
|
||||||
|
spec.automatic = true
|
||||||
|
end
|
||||||
|
shooting[name] = true
|
||||||
|
spec.user = name
|
||||||
|
fire_weapon(player, itemstack, spec)
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function shooter:blast(pos, radius, fleshy, distance, user)
|
function shooter:blast(pos, radius, fleshy, distance, user)
|
||||||
|
@ -394,14 +269,12 @@ function shooter:blast(pos, radius, fleshy, distance, user)
|
||||||
end
|
end
|
||||||
local objects = minetest.get_objects_inside_radius(pos, distance)
|
local objects = minetest.get_objects_inside_radius(pos, distance)
|
||||||
for _,obj in ipairs(objects) do
|
for _,obj in ipairs(objects) do
|
||||||
if (obj:is_player() and config.allow_players == true) or
|
if shooter:is_valid_object(obj) then
|
||||||
(obj:get_luaentity() and config.allow_entities == true and
|
|
||||||
obj:get_luaentity().name ~= "__builtin:item") then
|
|
||||||
local obj_pos = obj:getpos()
|
local obj_pos = obj:getpos()
|
||||||
local dist = vector.distance(obj_pos, pos)
|
local dist = vector.distance(obj_pos, pos)
|
||||||
local damage = (fleshy * 0.5 ^ dist) * 2
|
local damage = (fleshy * 0.5 ^ dist) * 2
|
||||||
if dist ~= 0 then
|
if dist ~= 0 then
|
||||||
obj_pos.y = obj_pos.y + 1.7
|
obj_pos.y = obj_pos.y + 1
|
||||||
blast_pos = {x=pos.x, y=pos.y + 4, z=pos.z}
|
blast_pos = {x=pos.x, y=pos.y + 4, z=pos.z}
|
||||||
if minetest.line_of_sight(obj_pos, blast_pos, 1) then
|
if minetest.line_of_sight(obj_pos, blast_pos, 1) then
|
||||||
obj:punch(user, 1.0, {
|
obj:punch(user, 1.0, {
|
||||||
|
@ -445,32 +318,11 @@ function shooter:blast(pos, radius, fleshy, distance, user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not singleplayer and config.admin_weapons then
|
minetest.register_globalstep(function(dtime)
|
||||||
local timer = 0
|
for _,player in pairs(minetest.get_connected_players()) do
|
||||||
local shooting = false
|
local name = player:get_player_name()
|
||||||
minetest.register_globalstep(function(dtime)
|
if name then
|
||||||
if not shooting then
|
shooting[name] = player:get_player_control().LMB == true
|
||||||
timer = timer+dtime
|
|
||||||
if timer < 2 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
timer = 0
|
|
||||||
end
|
end
|
||||||
shooting = false
|
end
|
||||||
for _,player in pairs(minetest.get_connected_players()) do
|
end)
|
||||||
if player:get_player_control().LMB then
|
|
||||||
local name = player:get_player_name()
|
|
||||||
if minetest.check_player_privs(name, {server=true}) then
|
|
||||||
local spec = shooter.registered_weapons[player:get_wielded_item():get_name()]
|
|
||||||
if spec then
|
|
||||||
spec = spec.spec
|
|
||||||
shooter.shots[name] = false
|
|
||||||
spec.name = name
|
|
||||||
shooter:fire_weapon(player, {}, spec)
|
|
||||||
shooting = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
|
@ -30,25 +30,6 @@ for name, _ in pairs(shooter.config) do
|
||||||
shooter.config[name] = _G[global]
|
shooter.config[name] = _G[global]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if minetest.global_exists("SHOOTER_PLAYER_OFFSET") then
|
|
||||||
shooter.player_offset = SHOOTER_PLAYER_OFFSET
|
|
||||||
end
|
|
||||||
if minetest.global_exists("SHOOTER_ENTITY_OFFSET") then
|
|
||||||
shooter.entity_offset = SHOOTER_ENTITY_OFFSET
|
|
||||||
end
|
|
||||||
if minetest.global_exists("SHOOTER_ENTITIES") then
|
|
||||||
for _, name in pairs(SHOOTER_ENTITIES) do
|
|
||||||
shooter:set_shootable_entity(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Simple Mobs Support
|
|
||||||
|
|
||||||
for name, _ in pairs(minetest.registered_entities) do
|
|
||||||
if string.find(name, "^mobs") then
|
|
||||||
shooter:set_shootable_entity(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Load Configuration
|
-- Load Configuration
|
||||||
|
|
||||||
|
|
|
@ -143,42 +143,27 @@ minetest.register_entity("shooter_crossbow:arrow_entity", {
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if self.timer > 0.2 then
|
if self.timer > 0.2 then
|
||||||
local pos = self.object:getpos()
|
|
||||||
local dir = vector.normalize(self.object:getvelocity())
|
local dir = vector.normalize(self.object:getvelocity())
|
||||||
local frame = get_animation_frame(dir)
|
local frame = get_animation_frame(dir)
|
||||||
self.object:set_animation({x=frame, y=frame}, 0)
|
local p1 = vector.add(self.object:getpos(), dir)
|
||||||
local objects = minetest.get_objects_inside_radius(pos, 5)
|
local p2 = vector.add(p1, vector.multiply(dir, 4))
|
||||||
for _,obj in ipairs(objects) do
|
local ray = minetest.raycast(p1, p2, true, true)
|
||||||
if shooter:is_valid_object(obj) and obj ~= self.player then
|
local pointed_thing = ray:next() or {}
|
||||||
local collisionbox = {-0.25,-1.0,-0.25, 0.25,0.8,0.25}
|
if pointed_thing.type == "object" then
|
||||||
local offset = shooter.player_offset
|
local obj = pointed_thing.ref
|
||||||
if not obj:is_player() then
|
if shooter:is_valid_object(obj) then
|
||||||
offset = shooter.entity_offset
|
self:strike(obj)
|
||||||
local ent = obj:get_luaentity()
|
|
||||||
if ent then
|
|
||||||
local def = minetest.registered_entities[ent.name]
|
|
||||||
collisionbox = def.collisionbox or collisionbox
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local opos = vector.add(obj:getpos(), offset)
|
|
||||||
local ray = {pos=pos, dir=dir}
|
|
||||||
local plane = {pos=opos, normal={x=-1, y=0, z=-1}}
|
|
||||||
local ipos = shooter:get_intersect_pos(ray, plane, collisionbox)
|
|
||||||
if ipos then
|
|
||||||
self:strike(obj)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
elseif pointed_thing.type == "node" then
|
||||||
local p = vector.add(pos, vector.multiply(dir, {x=5, y=5, z=5}))
|
local pos = minetest.get_pointed_thing_position(pointed_thing, false)
|
||||||
local _, npos = minetest.line_of_sight(pos, p, 1)
|
local node = minetest.get_node(pos)
|
||||||
if npos then
|
local target_pos = get_target_pos(p1, pos, dir, 0.66)
|
||||||
local node = minetest.get_node(npos)
|
self.node_pos = pos
|
||||||
local tpos = get_target_pos(pos, npos, dir, 0.66)
|
|
||||||
self.node_pos = npos
|
|
||||||
self.state = "stuck"
|
self.state = "stuck"
|
||||||
self:stop(tpos)
|
self:stop(target_pos)
|
||||||
shooter:play_node_sound(node, npos)
|
shooter:play_node_sound(node, pos)
|
||||||
end
|
end
|
||||||
|
self.object:set_animation({x=frame, y=frame}, 0)
|
||||||
self.timer = 0
|
self.timer = 0
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
@ -206,7 +191,8 @@ for _, color in pairs(dye_basecolors) do
|
||||||
local dir = user:get_look_dir()
|
local dir = user:get_look_dir()
|
||||||
local yaw = user:get_look_yaw()
|
local yaw = user:get_look_yaw()
|
||||||
if pos and dir and yaw then
|
if pos and dir and yaw then
|
||||||
pos.y = pos.y + 1.5
|
pos.y = pos.y + shooter.config.camera_height
|
||||||
|
pos = vector.add(pos, dir)
|
||||||
local obj = minetest.add_entity(pos, "shooter_crossbow:arrow_entity")
|
local obj = minetest.add_entity(pos, "shooter_crossbow:arrow_entity")
|
||||||
local ent = nil
|
local ent = nil
|
||||||
if obj then
|
if obj then
|
||||||
|
@ -310,7 +296,6 @@ if shooter.config.enable_crafting == true then
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--Backwards compatibility
|
--Backwards compatibility
|
||||||
minetest.register_alias("shooter:crossbow", "shooter_crossbow:crossbow")
|
minetest.register_alias("shooter:crossbow", "shooter_crossbow:crossbow")
|
||||||
for _, color in pairs(dye_basecolors) do
|
for _, color in pairs(dye_basecolors) do
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
shooter:register_weapon("shooter_guns:pistol", {
|
shooter:register_weapon("shooter_guns:pistol", {
|
||||||
description = "Pistol",
|
description = "Pistol",
|
||||||
inventory_image = "shooter_pistol.png",
|
inventory_image = "shooter_pistol.png",
|
||||||
rounds = 200,
|
|
||||||
spec = {
|
spec = {
|
||||||
range = 100,
|
rounds = 200,
|
||||||
|
range = 160,
|
||||||
step = 20,
|
step = 20,
|
||||||
tool_caps = {full_punch_interval=0.5, damage_groups={fleshy=2}},
|
tool_caps = {full_punch_interval=0.5, damage_groups={fleshy=2}},
|
||||||
groups = {snappy=3, fleshy=3, oddly_breakable_by_hand=3},
|
groups = {snappy=3, fleshy=3, oddly_breakable_by_hand=3},
|
||||||
|
@ -15,9 +15,9 @@ shooter:register_weapon("shooter_guns:pistol", {
|
||||||
shooter:register_weapon("shooter_guns:rifle", {
|
shooter:register_weapon("shooter_guns:rifle", {
|
||||||
description = "Rifle",
|
description = "Rifle",
|
||||||
inventory_image = "shooter_rifle.png",
|
inventory_image = "shooter_rifle.png",
|
||||||
rounds = 100,
|
|
||||||
spec = {
|
spec = {
|
||||||
range = 200,
|
rounds = 100,
|
||||||
|
range = 240,
|
||||||
step = 30,
|
step = 30,
|
||||||
tool_caps = {full_punch_interval=1.0, damage_groups={fleshy=3}},
|
tool_caps = {full_punch_interval=1.0, damage_groups={fleshy=3}},
|
||||||
groups = {snappy=3, crumbly=3, choppy=3, fleshy=2, oddly_breakable_by_hand=2},
|
groups = {snappy=3, crumbly=3, choppy=3, fleshy=2, oddly_breakable_by_hand=2},
|
||||||
|
@ -29,9 +29,9 @@ shooter:register_weapon("shooter_guns:rifle", {
|
||||||
shooter:register_weapon("shooter_guns:shotgun", {
|
shooter:register_weapon("shooter_guns:shotgun", {
|
||||||
description = "Shotgun",
|
description = "Shotgun",
|
||||||
inventory_image = "shooter_shotgun.png",
|
inventory_image = "shooter_shotgun.png",
|
||||||
rounds = 50,
|
|
||||||
spec = {
|
spec = {
|
||||||
range = 50,
|
rounds = 50,
|
||||||
|
range = 60,
|
||||||
step = 15,
|
step = 15,
|
||||||
tool_caps = {full_punch_interval=1.5, damage_groups={fleshy=4}},
|
tool_caps = {full_punch_interval=1.5, damage_groups={fleshy=4}},
|
||||||
groups = {cracky=3, snappy=2, crumbly=2, choppy=2, fleshy=1, oddly_breakable_by_hand=1},
|
groups = {cracky=3, snappy=2, crumbly=2, choppy=2, fleshy=1, oddly_breakable_by_hand=1},
|
||||||
|
@ -43,12 +43,12 @@ shooter:register_weapon("shooter_guns:shotgun", {
|
||||||
shooter:register_weapon("shooter_guns:machine_gun", {
|
shooter:register_weapon("shooter_guns:machine_gun", {
|
||||||
description = "Sub Machine Gun",
|
description = "Sub Machine Gun",
|
||||||
inventory_image = "shooter_smgun.png",
|
inventory_image = "shooter_smgun.png",
|
||||||
rounds = 50,
|
|
||||||
shots = 4,
|
|
||||||
spec = {
|
spec = {
|
||||||
range = 100,
|
automatic = true,
|
||||||
|
rounds = 100,
|
||||||
|
range = 160,
|
||||||
step = 20,
|
step = 20,
|
||||||
tool_caps = {full_punch_interval=0.125, damage_groups={fleshy=2}},
|
tool_caps = {full_punch_interval=0.1, damage_groups={fleshy=2}},
|
||||||
groups = {snappy=3, fleshy=3, oddly_breakable_by_hand=3},
|
groups = {snappy=3, fleshy=3, oddly_breakable_by_hand=3},
|
||||||
sound = "shooter_pistol",
|
sound = "shooter_pistol",
|
||||||
particle = "shooter_cap.png",
|
particle = "shooter_cap.png",
|
||||||
|
@ -100,32 +100,6 @@ if shooter.config.enable_crafting == true then
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
local rounds_update_time = 0
|
|
||||||
|
|
||||||
minetest.register_globalstep(function(dtime)
|
|
||||||
shooter.time = shooter.time + dtime
|
|
||||||
if shooter.time - rounds_update_time > shooter.config.rounds_update_time then
|
|
||||||
for i, round in ipairs(shooter.rounds) do
|
|
||||||
if shooter:process_round(round) or round.dist > round.def.range then
|
|
||||||
table.remove(shooter.rounds, i)
|
|
||||||
else
|
|
||||||
local v = vector.multiply(round.ray, round.def.step)
|
|
||||||
shooter.rounds[i].pos = vector.add(round.pos, v)
|
|
||||||
shooter.rounds[i].dist = round.dist + round.def.step
|
|
||||||
end
|
|
||||||
end
|
|
||||||
rounds_update_time = shooter.time
|
|
||||||
end
|
|
||||||
if shooter.time > 100000 then
|
|
||||||
shooter.shots = {}
|
|
||||||
rounds_update_time = 0
|
|
||||||
shooter.reload_time = 0
|
|
||||||
shooter.update_time = 0
|
|
||||||
shooter.time = 0
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
--Backwards compatibility
|
--Backwards compatibility
|
||||||
minetest.register_alias("shooter:shotgun", "shooter_guns:shotgun")
|
minetest.register_alias("shooter:shotgun", "shooter_guns:shotgun")
|
||||||
minetest.register_alias("shooter:pistol", "shooter_guns:pistol")
|
minetest.register_alias("shooter:pistol", "shooter_guns:pistol")
|
||||||
|
|
Loading…
Reference in a new issue