Version 0.4.0 (rework)
This commit is contained in:
parent
40e7645a43
commit
a19923e6aa
8 changed files with 325 additions and 141 deletions
37
README.txt
37
README.txt
|
@ -1,28 +1,21 @@
|
||||||
Minetest Mod - Simple Shooter [shooter]
|
Minetest Mod - Simple Shooter [shooter]
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
Mod Version: 0.3.0
|
Mod Version: 0.4.0
|
||||||
|
|
||||||
Minetest Version: 0.4.8-dev d9ef072305
|
Minetest Version: 0.4.9
|
||||||
|
|
||||||
Depends: default
|
An experimental first person shooter mod that uses simple vector mathematics
|
||||||
|
to produce an accurate and server-firendly method of hit detection.
|
||||||
An experimental first person shooter mod using simple vector mathematics
|
|
||||||
in an effort to find a more server-firendly method of hit detection from
|
|
||||||
that which is currently being used by the firearms mod.
|
|
||||||
|
|
||||||
For the most part I think I have achieved this for straight pvp, however,
|
|
||||||
the jury is still out as to whether it is any faster against entities (mobs)
|
|
||||||
|
|
||||||
By default this mod is configured to work only against other players in
|
By default this mod is configured to work only against other players in
|
||||||
multiplayer (server) mode. This is overridden in singleplayer mode to work
|
multiplayer mode and against Simple Mobs [mobs] in singleplayer mode.
|
||||||
against all registered entities instead.
|
|
||||||
|
|
||||||
Default configuration can be customised by adding a shooter.conf file to the
|
Default configuration can be customised by adding a shooter.conf file to
|
||||||
mod's main directory, see shooter.conf.example for more details.
|
the mod's main directory, see shooter.conf.example for more details.
|
||||||
|
|
||||||
This is still very much a work in progress which I plan to eventually use as
|
This is still very much a work in progress which I eventually plan to use
|
||||||
the base for a 'Spades' style FPS game using the minetest engine.
|
as the base for a 'Spades' style FPS game using the minetest engine.
|
||||||
|
|
||||||
Crafting
|
Crafting
|
||||||
========
|
========
|
||||||
|
@ -34,7 +27,7 @@ M = Mese Crystal [default:mese_crysytal]
|
||||||
Pistol: [shooter:pistol]
|
Pistol: [shooter:pistol]
|
||||||
|
|
||||||
+---+---+
|
+---+---+
|
||||||
| S | B |
|
| S | S |
|
||||||
+---+---+
|
+---+---+
|
||||||
| | M |
|
| | M |
|
||||||
+---+---+
|
+---+---+
|
||||||
|
@ -59,3 +52,13 @@ Shotgun: [shooter:shotgun]
|
||||||
| | M | B |
|
| | M | B |
|
||||||
+---+---+---+
|
+---+---+---+
|
||||||
|
|
||||||
|
Sub Machine Gun: [shooter:machine_gun]
|
||||||
|
|
||||||
|
+---+---+---+
|
||||||
|
| S | S | S |
|
||||||
|
+---+---+---+
|
||||||
|
| | B | M |
|
||||||
|
+---+---+---+
|
||||||
|
| | B | |
|
||||||
|
+---+---+---+
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
default
|
|
||||||
|
|
57
init.lua
57
init.lua
|
@ -4,12 +4,15 @@ minetest.register_tool("shooter:pistol", {
|
||||||
description = "Pistol",
|
description = "Pistol",
|
||||||
inventory_image = "shooter_pistol.png",
|
inventory_image = "shooter_pistol.png",
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
local name = user:get_player_name()
|
||||||
shooter:fire_weapon(user, pointed_thing, {
|
shooter:fire_weapon(user, pointed_thing, {
|
||||||
range = 30,
|
name = name,
|
||||||
tool_caps = {full_punch_interval=0.5, damage_groups={fleshy=1}},
|
range = 100,
|
||||||
|
step = 20,
|
||||||
|
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},
|
||||||
sound = "shooter_pistol",
|
sound = "shooter_pistol",
|
||||||
particle = "default_obsidian.png",
|
particle = "shooter_cap.png",
|
||||||
})
|
})
|
||||||
itemstack:add_wear(328) -- 200 Rounds
|
itemstack:add_wear(328) -- 200 Rounds
|
||||||
return itemstack
|
return itemstack
|
||||||
|
@ -20,12 +23,15 @@ minetest.register_tool("shooter:riffle", {
|
||||||
description = "Riffle",
|
description = "Riffle",
|
||||||
inventory_image = "shooter_riffle.png",
|
inventory_image = "shooter_riffle.png",
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
local name = user:get_player_name()
|
||||||
shooter:fire_weapon(user, pointed_thing, {
|
shooter:fire_weapon(user, pointed_thing, {
|
||||||
range = 80,
|
name = name,
|
||||||
tool_caps = {full_punch_interval=1.0, damage_groups={fleshy=2}},
|
range = 200,
|
||||||
|
step = 30,
|
||||||
|
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},
|
||||||
sound = "shooter_riffle",
|
sound = "shooter_riffle",
|
||||||
particle = "default_gold_block.png",
|
particle = "shooter_bullet.png",
|
||||||
})
|
})
|
||||||
itemstack:add_wear(656) -- 100 Rounds
|
itemstack:add_wear(656) -- 100 Rounds
|
||||||
return itemstack
|
return itemstack
|
||||||
|
@ -36,8 +42,11 @@ minetest.register_tool("shooter:shotgun", {
|
||||||
description = "Shotgun",
|
description = "Shotgun",
|
||||||
inventory_image = "shooter_shotgun.png",
|
inventory_image = "shooter_shotgun.png",
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
local name = user:get_player_name()
|
||||||
shooter:fire_weapon(user, pointed_thing, {
|
shooter:fire_weapon(user, pointed_thing, {
|
||||||
range = 15,
|
name = name,
|
||||||
|
range = 50,
|
||||||
|
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},
|
||||||
sound = "shooter_shotgun",
|
sound = "shooter_shotgun",
|
||||||
|
@ -48,10 +57,33 @@ minetest.register_tool("shooter:shotgun", {
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
minetest.register_tool("shooter:machine_gun", {
|
||||||
|
description = "Sub Machine Gun",
|
||||||
|
inventory_image = "shooter_smgun.png",
|
||||||
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
local name = user:get_player_name()
|
||||||
|
for i = 0, 0.45, 0.15 do
|
||||||
|
minetest.after(i, function()
|
||||||
|
shooter:fire_weapon(user, pointed_thing, {
|
||||||
|
name = name,
|
||||||
|
range = 100,
|
||||||
|
step = 20,
|
||||||
|
tool_caps = {full_punch_interval=0.1, damage_groups={fleshy=2}},
|
||||||
|
groups = {snappy=3, fleshy=3, oddly_breakable_by_hand=3},
|
||||||
|
sound = "shooter_pistol",
|
||||||
|
particle = "shooter_cap.png",
|
||||||
|
})
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
itemstack:add_wear(328) -- 4 x 200 Rounds
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
output = "shooter:pistol",
|
output = "shooter:pistol",
|
||||||
recipe = {
|
recipe = {
|
||||||
{"default:steel_ingot", "default:bronze_ingot"},
|
{"default:steel_ingot", "default:steel_ingot"},
|
||||||
{"", "default:mese_crystal"},
|
{"", "default:mese_crystal"},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -74,3 +106,12 @@ minetest.register_craft({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:machine_gun",
|
||||||
|
recipe = {
|
||||||
|
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||||
|
{"", "default:bronze_ingot", "default:mese_crystal"},
|
||||||
|
{"", "default:bronze_ingot", ""},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,42 @@
|
||||||
|
|
||||||
-- Global Constants (defaults)
|
-- Global Constants (defaults)
|
||||||
|
|
||||||
-- Particle texture used when target it hit
|
-- Particle texture used when a player or entity it hit
|
||||||
SHOOTER_EXPLOSION_TEXTURE = "shooter_hit.png"
|
SHOOTER_EXPLOSION_TEXTURE = "shooter_hit.png"
|
||||||
|
|
||||||
-- Allow node destruction
|
-- Allow node destruction
|
||||||
SHOOTER_ALLOW_NODES = true
|
SHOOTER_ALLOW_NODES = true
|
||||||
|
|
||||||
-- Maximum node rage, applies only if nodes are allowed
|
|
||||||
SHOOTER_NODE_RANGE = 50
|
|
||||||
|
|
||||||
-- Allow entities in multiplayer mode
|
-- Allow entities in multiplayer mode
|
||||||
SHOOTER_ALLOW_ENTITIES = false
|
SHOOTER_ALLOW_ENTITIES = false
|
||||||
|
|
||||||
-- Maximum object range, applies only if entities are allowed
|
-- Allow players in multiplayer mode
|
||||||
SHOOTER_OBJECT_RANGE = 50
|
SHOOTER_ALLOW_PLAYERS = true
|
||||||
|
|
||||||
|
-- How often objects are fully reloaded
|
||||||
|
SHOOTER_OBJECT_RELOAD_TIME = 1
|
||||||
|
|
||||||
|
-- How often object positions are updated
|
||||||
|
SHOOTER_OBJECT_UPDATE_TIME = 0.25
|
||||||
|
|
||||||
|
-- How often rounds are processed
|
||||||
|
SHOOTER_ROUNDS_UPDATE_TIME = 0.4
|
||||||
|
|
||||||
|
-- Player collision box offset (may require adjustment for some games)
|
||||||
|
SHOOTER_PLAYER_OFFSET = {x=0, y=1, z=0}
|
||||||
|
|
||||||
|
-- Entity collision box offset (may require adjustment for other mobs)
|
||||||
|
SHOOTER_ENTITY_OFFSET = {x=0, y=0, z=0}
|
||||||
|
|
||||||
|
-- Shootable entities (default support for Simple Mobs)
|
||||||
|
SHOOTER_ENTITIES = {
|
||||||
|
"mobs:dirt_monster",
|
||||||
|
"mobs:stone_monster",
|
||||||
|
"mobs:sand_monster",
|
||||||
|
"mobs:tree_monster",
|
||||||
|
"mobs:sheep",
|
||||||
|
"mobs:rat",
|
||||||
|
"mobs:oerkki",
|
||||||
|
"mobs:dungeon_master",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
334
shooter.lua
334
shooter.lua
|
@ -1,10 +1,39 @@
|
||||||
shooter = {}
|
shooter = {
|
||||||
|
time = 0,
|
||||||
|
objects = {},
|
||||||
|
rounds = {},
|
||||||
|
shots = {},
|
||||||
|
}
|
||||||
|
|
||||||
SHOOTER_EXPLOSION_TEXTURE = "shooter_hit.png"
|
SHOOTER_EXPLOSION_TEXTURE = "shooter_hit.png"
|
||||||
SHOOTER_ALLOW_NODES = true
|
SHOOTER_ALLOW_NODES = true
|
||||||
SHOOTER_ALLOW_ENTITIES = false
|
SHOOTER_ALLOW_ENTITIES = false
|
||||||
SHOOTER_NODE_RANGE = 50
|
SHOOTER_ALLOW_PLAYERS = true
|
||||||
SHOOTER_OBJECT_RANGE = 50
|
SHOOTER_OBJECT_RELOAD_TIME = 1
|
||||||
|
SHOOTER_OBJECT_UPDATE_TIME = 0.25
|
||||||
|
SHOOTER_ROUNDS_UPDATE_TIME = 0.4
|
||||||
|
SHOOTER_PLAYER_OFFSET = {x=0, y=1, z=0}
|
||||||
|
SHOOTER_ENTITY_OFFSET = {x=0, y=0, z=0}
|
||||||
|
SHOOTER_ENTITIES = {
|
||||||
|
"mobs:dirt_monster",
|
||||||
|
"mobs:stone_monster",
|
||||||
|
"mobs:sand_monster",
|
||||||
|
"mobs:tree_monster",
|
||||||
|
"mobs:sheep",
|
||||||
|
"mobs:rat",
|
||||||
|
"mobs:oerkki",
|
||||||
|
"mobs:dungeon_master",
|
||||||
|
}
|
||||||
|
|
||||||
|
if minetest.is_singleplayer() == true then
|
||||||
|
SHOOTER_ALLOW_ENTITIES = true
|
||||||
|
SHOOTER_ALLOW_PLAYERS = false
|
||||||
|
end
|
||||||
|
|
||||||
|
local allowed_entities = {}
|
||||||
|
for _,v in ipairs(SHOOTER_ENTITIES) do
|
||||||
|
allowed_entities[v] = 1
|
||||||
|
end
|
||||||
|
|
||||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||||
local input = io.open(modpath.."/shooter.conf", "r")
|
local input = io.open(modpath.."/shooter.conf", "r")
|
||||||
|
@ -13,36 +42,45 @@ if input then
|
||||||
input:close()
|
input:close()
|
||||||
input = nil
|
input = nil
|
||||||
end
|
end
|
||||||
if minetest.is_singleplayer() == true then
|
|
||||||
SHOOTER_ALLOW_ENTITIES = true
|
local rounds_update_time = 0
|
||||||
|
local object_update_time = 0
|
||||||
|
local object_reload_time = 0
|
||||||
|
|
||||||
|
local function get_dot_product(v1, v2)
|
||||||
|
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
|
||||||
end
|
end
|
||||||
local timer = 0
|
|
||||||
local shots = {}
|
|
||||||
|
|
||||||
local function spawn_particles(p, v, d, texture)
|
local function spawn_particles(p, v, d, texture)
|
||||||
if type(texture) ~= "string" then
|
if p and v and d then
|
||||||
texture = SHOOTER_EXPLOSION_TEXTURE
|
if type(texture) ~= "string" then
|
||||||
|
texture = SHOOTER_EXPLOSION_TEXTURE
|
||||||
|
end
|
||||||
|
local pos = vector.add(p, vector.multiply(v, {x=d, y=d, z=d}))
|
||||||
|
pos.y = pos.y + 0.75
|
||||||
|
local spread = {x=0.1, y=0.1, z=0.1}
|
||||||
|
minetest.add_particlespawner(15, 0.3,
|
||||||
|
vector.subtract(pos, spread), vector.add(pos, spread),
|
||||||
|
{x=-1, y=1, z=-1}, {x=1, y=2, z=1},
|
||||||
|
{x=-2, y=-2, z=-2}, {x=2, y=-2, z=2},
|
||||||
|
0.1, 0.75, 1, 2, false, texture
|
||||||
|
)
|
||||||
end
|
end
|
||||||
local pos = vector.add(p, vector.multiply(v, {x=d, y=d, z=d}))
|
|
||||||
pos.y = pos.y + 0.75
|
|
||||||
local spread = {x=0.1, y=0.1, z=0.1}
|
|
||||||
minetest.add_particlespawner(15, 0.3,
|
|
||||||
vector.subtract(pos, spread), vector.add(pos, spread),
|
|
||||||
{x=-1, y=1, z=-1}, {x=1, y=2, z=1},
|
|
||||||
{x=-2, y=-2, z=-2}, {x=2, y=-2, z=2},
|
|
||||||
0.1, 0.75, 1, 2, false, texture
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function is_valid_object(object)
|
local function is_valid_object(object)
|
||||||
if object:is_player() == true then
|
if object then
|
||||||
return true
|
if object:is_player() == true then
|
||||||
end
|
return true
|
||||||
if SHOOTER_ALLOW_ENTITIES == true then
|
end
|
||||||
local luaentity = object:get_luaentity()
|
if SHOOTER_ALLOW_ENTITIES == true then
|
||||||
if luaentity then
|
local luaentity = object:get_luaentity()
|
||||||
if minetest.registered_entities[luaentity.name] then
|
if luaentity then
|
||||||
return true
|
if luaentity.name then
|
||||||
|
if allowed_entities[luaentity.name] then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -64,16 +102,15 @@ local function punch_node(pos, def)
|
||||||
if level >= v then
|
if level >= v then
|
||||||
minetest.remove_node(pos)
|
minetest.remove_node(pos)
|
||||||
local sounds = item.sounds
|
local sounds = item.sounds
|
||||||
if sounds then
|
if item.sounds then
|
||||||
local soundspec = sounds.dug
|
local spec = item.sounds.dug
|
||||||
if soundspec then
|
if spec then
|
||||||
soundspec.pos = pos
|
spec.pos = pos
|
||||||
minetest.sound_play(soundspec.name, soundspec)
|
minetest.sound_play(spec.name, spec)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local tiles = item.tiles
|
if item.tiles then
|
||||||
if tiles then
|
return item.tiles[1]
|
||||||
return tiles[1]
|
|
||||||
end
|
end
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
@ -81,17 +118,81 @@ local function punch_node(pos, def)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function 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 x = vector.distance(p1, p2)
|
||||||
|
if x < round.def.step then
|
||||||
|
local n = vector.multiply(v1, {x=-1, y=0, z=-1})
|
||||||
|
local v2 = vector.subtract(p1, p2)
|
||||||
|
local r1 = get_dot_product(n, v2)
|
||||||
|
local r2 = get_dot_product(n, v1)
|
||||||
|
if r2 ~= 0 then
|
||||||
|
local t = -(r1 / r2)
|
||||||
|
local td = vector.multiply(v1, {x=t, y=t, z=t})
|
||||||
|
local pt = vector.add(p1, td)
|
||||||
|
local pd = vector.subtract(pt, p2)
|
||||||
|
if math.abs(pd.x) < ref.collisionbox[4] and
|
||||||
|
math.abs(pd.y) < ref.collisionbox[5] and
|
||||||
|
math.abs(pd.z) < ref.collisionbox[6] then
|
||||||
|
target.object = ref.object
|
||||||
|
target.pos = pt
|
||||||
|
target.distance = x
|
||||||
|
end
|
||||||
|
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)
|
||||||
|
spawn_particles({x=p1.x, y=p1.y - 1, z=p1.z}, v1,
|
||||||
|
target.distance, SHOOTER_EXPLOSION_TEXTURE)
|
||||||
|
end
|
||||||
|
return 1
|
||||||
|
elseif pos and SHOOTER_ALLOW_NODES == true then
|
||||||
|
local texture = punch_node(pos, round.def)
|
||||||
|
if texture then
|
||||||
|
spawn_particles({x=p1.x, y=p1.y - 1, z=p1.z},
|
||||||
|
v1, vector.distance(p1, pos), texture)
|
||||||
|
end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
elseif SHOOTER_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
|
||||||
|
local texture = punch_node(pos, round.def)
|
||||||
|
if texture then
|
||||||
|
spawn_particles({x=p1.x, y=p1.y - 1, z=p1.z},
|
||||||
|
v1, vector.distance(p1, pos), texture)
|
||||||
|
end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function shooter:fire_weapon(user, pointed_thing, def)
|
function shooter:fire_weapon(user, pointed_thing, def)
|
||||||
local name = user:get_player_name()
|
if shooter.shots[def.name] then
|
||||||
if shots[name] then
|
if shooter.time < shooter.shots[def.name] then
|
||||||
if timer < shots[name] then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
shots[name] = timer + def.tool_caps.full_punch_interval
|
shooter.shots[def.name] = shooter.time + def.tool_caps.full_punch_interval
|
||||||
minetest.sound_play(def.sound, {object=user})
|
minetest.sound_play(def.sound, {object=user})
|
||||||
local v1 = user:get_look_dir()
|
local v1 = user:get_look_dir()
|
||||||
local p1 = user:getpos()
|
local p1 = user:getpos()
|
||||||
|
if not v1 or not p1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
minetest.add_particle({x=p1.x, y=p1.y + 1.6, z=p1.z},
|
minetest.add_particle({x=p1.x, y=p1.y + 1.6, z=p1.z},
|
||||||
vector.multiply(v1, {x=30, y=30, z=30}),
|
vector.multiply(v1, {x=30, y=30, z=30}),
|
||||||
{x=0, y=0, z=0}, 0.5, 0.25,
|
{x=0, y=0, z=0}, 0.5, 0.25,
|
||||||
|
@ -102,92 +203,90 @@ function shooter:fire_weapon(user, pointed_thing, def)
|
||||||
local texture = punch_node(pos, def)
|
local texture = punch_node(pos, def)
|
||||||
if texture then
|
if texture then
|
||||||
spawn_particles({x=p1.x, y=p1.y + 0.75, z=p1.z},
|
spawn_particles({x=p1.x, y=p1.y + 0.75, z=p1.z},
|
||||||
v1, vector.distance(p1, pos), texture)
|
v1, vector.distance(p1, pos), texture)
|
||||||
end
|
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 is_valid_object(object) == true then
|
if is_valid_object(object) == true then
|
||||||
object:punch(user, nil, def.tool_caps, v1)
|
object:punch(user, nil, def.tool_caps, v1)
|
||||||
local p2 = object:getpos()
|
local p2 = object:getpos()
|
||||||
spawn_particles({x=p1.x, y=p1.y + 0.75, z=p1.z}, v1,
|
spawn_particles({x=p1.x, y=p1.y + 0.75, z=p1.z}, v1,
|
||||||
vector.distance(p1, p2), SHOOTER_EXPLOSION_TEXTURE)
|
vector.distance(p1, p2), SHOOTER_EXPLOSION_TEXTURE)
|
||||||
return
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
if def.range > 100 then
|
|
||||||
def.range = 100
|
|
||||||
end
|
|
||||||
local target = {object=nil, distance=100}
|
|
||||||
local objects = {}
|
|
||||||
if SHOOTER_ALLOW_ENTITIES == true then
|
|
||||||
local range = def.range
|
|
||||||
if range > SHOOTER_OBJECT_RANGE then
|
|
||||||
range = SHOOTER_OBJECT_RANGE
|
|
||||||
end
|
|
||||||
local r = math.ceil(range * 0.5)
|
|
||||||
local p = vector.add(p1, vector.multiply(v1, {x=r, y=r, z=r}))
|
|
||||||
objects = minetest.get_objects_inside_radius(p, r)
|
|
||||||
else
|
else
|
||||||
objects = minetest.get_connected_players()
|
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
|
||||||
for _,object in ipairs(objects) do
|
end
|
||||||
if is_valid_object(object) == true then
|
|
||||||
local p2 = object:getpos()
|
function shooter:load_objects()
|
||||||
if p1 and p2 then
|
local objects = {}
|
||||||
local x = vector.distance(p1, p2)
|
if SHOOTER_ALLOW_PLAYERS == true then
|
||||||
p2.y = p2.y - 0.75
|
local players = minetest.get_connected_players()
|
||||||
if x > 0 and x < target.distance and x < def.range then
|
for _,player in ipairs(players) do
|
||||||
local yx = 0
|
local pos = player:getpos()
|
||||||
if x > 30 then
|
local name = player:get_player_name()
|
||||||
yx = 0.001 * (10 - x * 0.1)
|
local hp = player:get_hp() or 0
|
||||||
else
|
if pos and name and hp > 0 then
|
||||||
yx = 0.00002 * (x * x) - 0.002 * x + 0.05
|
table.insert(objects, {
|
||||||
end
|
name = name,
|
||||||
local yy = yx * 3
|
object = player,
|
||||||
local v2 = vector.normalize(vector.direction(p1, p2))
|
pos = pos,
|
||||||
local vd = vector.subtract(v1, v2)
|
collisionbox = {-0.25,-1.0,-0.25, 0.25, 0.8, 0.25},
|
||||||
if math.abs(vd.x) < yx and
|
offset = SHOOTER_PLAYER_OFFSET,
|
||||||
math.abs(vd.z) < yx and
|
})
|
||||||
math.abs(vd.y) < yy then
|
end
|
||||||
target = {
|
end
|
||||||
object = object,
|
end
|
||||||
distance = x,
|
if SHOOTER_ALLOW_ENTITIES == true then
|
||||||
pos = {x=p2.x, z=p2.z, y=p2.y+1.75},
|
for _,ref in pairs(minetest.luaentities) do
|
||||||
}
|
if ref.object and ref.name then
|
||||||
|
if allowed_entities[ref.name] then
|
||||||
|
local pos = ref.object:getpos()
|
||||||
|
local hp = ref.object:get_hp() or 0
|
||||||
|
if pos and hp > 0 then
|
||||||
|
local def = minetest.registered_entities[ref.name]
|
||||||
|
table.insert(objects, {
|
||||||
|
name = ref.name,
|
||||||
|
object = ref.object,
|
||||||
|
pos = pos,
|
||||||
|
collisionbox = def.collisionbox,
|
||||||
|
offset = SHOOTER_ENTITY_OFFSET,
|
||||||
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local view_pos = {x=p1.x, y=p1.y + 1.75, z=p1.z}
|
object_reload_time = shooter.time
|
||||||
if target.object then
|
object_update_time = shooter.time
|
||||||
local success, pos = minetest.line_of_sight(view_pos, target.pos, 1)
|
shooter.objects = {}
|
||||||
if success then
|
for _,v in ipairs(objects) do
|
||||||
target.object:punch(user, nil, def.tool_caps, v1)
|
table.insert(shooter.objects, v)
|
||||||
spawn_particles({x=p1.x, y=p1.y + 0.75, z=p1.z}, v1,
|
end
|
||||||
target.distance, SHOOTER_EXPLOSION_TEXTURE)
|
end
|
||||||
elseif pos and SHOOTER_ALLOW_NODES == true then
|
|
||||||
local texture = punch_node(pos, def)
|
function shooter:update_objects()
|
||||||
if texture then
|
if shooter.time - object_reload_time > SHOOTER_OBJECT_RELOAD_TIME then
|
||||||
spawn_particles({x=p1.x, y=p1.y + 0.75, z=p1.z},
|
shooter:load_objects()
|
||||||
v1, vector.distance(p1, pos), texture)
|
elseif shooter.time - object_update_time > SHOOTER_OBJECT_UPDATE_TIME then
|
||||||
end
|
for i, ref in ipairs(shooter.objects) do
|
||||||
end
|
if ref.object then
|
||||||
elseif SHOOTER_ALLOW_NODES == true then
|
local pos = ref.object:getpos()
|
||||||
local d = def.range
|
if pos then
|
||||||
if d > SHOOTER_NODE_RANGE then
|
shooter.objects[i].pos = pos
|
||||||
d = SHOOTER_NODE_RANGE
|
end
|
||||||
end
|
else
|
||||||
local p2 = vector.add(view_pos, vector.multiply(v1, {x=d, y=d, z=d}))
|
table.remove(shooter.objects, i)
|
||||||
local success, pos = minetest.line_of_sight(view_pos, p2, 1)
|
|
||||||
if pos then
|
|
||||||
local texture = punch_node(pos, def)
|
|
||||||
if texture then
|
|
||||||
spawn_particles({x=p1.x, y=p1.y + 0.75, z=p1.z},
|
|
||||||
v1, vector.distance(p1, pos), texture)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
object_update_time = shooter.time
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -196,6 +295,25 @@ minetest.register_on_joinplayer(function(player)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
timer = timer + dtime
|
shooter.time = shooter.time + dtime
|
||||||
|
if shooter.time - rounds_update_time > SHOOTER_ROUNDS_UPDATE_TIME then
|
||||||
|
for i, round in ipairs(shooter.rounds) do
|
||||||
|
if 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
|
||||||
|
object_reload_time = 0
|
||||||
|
object_update_time = 0
|
||||||
|
shooter.time = 0
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
BIN
textures/shooter_bullet.png
Normal file
BIN
textures/shooter_bullet.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 178 B |
BIN
textures/shooter_cap.png
Normal file
BIN
textures/shooter_cap.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 157 B |
BIN
textures/shooter_smgun.png
Normal file
BIN
textures/shooter_smgun.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 289 B |
Loading…
Reference in a new issue