Version 0.5.0 - Lots of new stuff
10
LICENSE.txt
|
@ -1,10 +1,12 @@
|
||||||
Minetest Mod - Simple Shooter [shooter]
|
Minetest Mod - Simple Shooter [shooter]
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
License Source: 2013 Stuart Jones - LGPL
|
License Source Code: 2013 Stuart Jones - LGPL v2.1
|
||||||
|
|
||||||
License Textures: Stuart Jones - WTFPL
|
License Textures: Stuart Jones - WTFPL
|
||||||
|
|
||||||
|
Licence Models: Stuart Jones - CC-BY-SA 3.0
|
||||||
|
|
||||||
License Sounds: freesound.org
|
License Sounds: freesound.org
|
||||||
|
|
||||||
flobert1_20070728.wav by Nonoo - Attribution 3.0 Unported (CC BY 3.0)
|
flobert1_20070728.wav by Nonoo - Attribution 3.0 Unported (CC BY 3.0)
|
||||||
|
@ -17,3 +19,9 @@ License Sounds: freesound.org
|
||||||
|
|
||||||
trigger-with-hammer-fall.wav by Nanashi - CC0 1.0 Universal (CC0 1.0)
|
trigger-with-hammer-fall.wav by Nanashi - CC0 1.0 Universal (CC0 1.0)
|
||||||
|
|
||||||
|
woosh.wav by ReadeOnly - CC0 1.0 Universal (CC0 1.0)
|
||||||
|
|
||||||
|
AGM-114 Hellfire Rocket Missile Launch.flac by qubodup - CC0 1.0 Universal (CC0 1.0)
|
||||||
|
|
||||||
|
Sparkler.aif by Ned Bouhalassa - CC0 1.0 Universal (CC0 1.0)
|
||||||
|
|
||||||
|
|
68
README.txt
|
@ -1,10 +1,12 @@
|
||||||
Minetest Mod - Simple Shooter [shooter]
|
Minetest Mod - Simple Shooter [shooter]
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
Mod Version: 0.4.1
|
Mod Version: 0.5.0
|
||||||
|
|
||||||
Minetest Version: 0.4.9
|
Minetest Version: 0.4.9
|
||||||
|
|
||||||
|
Depends: default, wool, tnt
|
||||||
|
|
||||||
An experimental first person shooter mod that uses simple vector mathematics
|
An experimental first person shooter mod that uses simple vector mathematics
|
||||||
to produce an accurate and server-firendly method of hit detection.
|
to produce an accurate and server-firendly method of hit detection.
|
||||||
|
|
||||||
|
@ -23,6 +25,8 @@ Crafting
|
||||||
S = Steel Ingot [default:steel_ingot]
|
S = Steel Ingot [default:steel_ingot]
|
||||||
B = Bronze Ingot [default:bronze_ingot]
|
B = Bronze Ingot [default:bronze_ingot]
|
||||||
M = Mese Crystal [default:mese_crysytal]
|
M = Mese Crystal [default:mese_crysytal]
|
||||||
|
D = Diamond [default:diamond]
|
||||||
|
R = Red Wool [wool:red]
|
||||||
G = Gun Powder [tnt:gunpowder]
|
G = Gun Powder [tnt:gunpowder]
|
||||||
|
|
||||||
Pistol: [shooter:pistol]
|
Pistol: [shooter:pistol]
|
||||||
|
@ -69,3 +73,65 @@ Ammo Pack: [shooter:ammo]
|
||||||
| G | B |
|
| G | B |
|
||||||
+---+---+
|
+---+---+
|
||||||
|
|
||||||
|
Grappling Hook: [shooter:grapple_hook]
|
||||||
|
|
||||||
|
+---+---+---+
|
||||||
|
| S | S | D |
|
||||||
|
+---+---+---+
|
||||||
|
| S | S | |
|
||||||
|
+---+---+---+
|
||||||
|
| D | | S |
|
||||||
|
+---+---+---+
|
||||||
|
|
||||||
|
Grappling Hook Gun: [shooter:grapple_gun]
|
||||||
|
|
||||||
|
+---+---+
|
||||||
|
| S | S |
|
||||||
|
+---+---+
|
||||||
|
| | D |
|
||||||
|
+---+---+
|
||||||
|
|
||||||
|
Flare: [shooter:flare]
|
||||||
|
|
||||||
|
+---+---+
|
||||||
|
| G | R |
|
||||||
|
+---+---+
|
||||||
|
|
||||||
|
Flare Gun: [shooter:flaregun]
|
||||||
|
|
||||||
|
+---+---+---+
|
||||||
|
| R | R | R |
|
||||||
|
+---+---+---+
|
||||||
|
| | | S |
|
||||||
|
+---+---+---+
|
||||||
|
|
||||||
|
Grenade: [shooter:grenade]
|
||||||
|
|
||||||
|
+---+---+
|
||||||
|
| G | S |
|
||||||
|
+---+---+
|
||||||
|
|
||||||
|
Flare Gun: [shooter:rocket_gun]
|
||||||
|
|
||||||
|
+---+---+---+
|
||||||
|
| B | S | S |
|
||||||
|
+---+---+---+
|
||||||
|
| | | D |
|
||||||
|
+---+---+---+
|
||||||
|
|
||||||
|
Rocket: [shooter:rocket]
|
||||||
|
|
||||||
|
+---+---+---+
|
||||||
|
| B | G | B |
|
||||||
|
+---+---+---+
|
||||||
|
|
||||||
|
Turret: [shooter:turret]
|
||||||
|
|
||||||
|
+---+---+---+
|
||||||
|
| B | B | S |
|
||||||
|
+---+---+---+
|
||||||
|
| | B | S |
|
||||||
|
+---+---+---+
|
||||||
|
| | D | |
|
||||||
|
+---+---+---+
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
default
|
default
|
||||||
|
wool
|
||||||
tnt
|
tnt
|
||||||
|
|
147
flaregun.lua
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
minetest.register_craftitem("shooter:flare", {
|
||||||
|
description = "Flare",
|
||||||
|
inventory_image = "shooter_flare_inv.png",
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_node("shooter:flare_light", {
|
||||||
|
drawtype = "glasslike",
|
||||||
|
tiles = {"shooter_flare_light.png"},
|
||||||
|
paramtype = "light",
|
||||||
|
groups = {not_in_creative_inventory=1},
|
||||||
|
drop = "",
|
||||||
|
walkable = false,
|
||||||
|
buildable_to = true,
|
||||||
|
sunlight_propagates = true,
|
||||||
|
light_source = LIGHT_MAX,
|
||||||
|
pointable = false,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = "shooter:flare_light",
|
||||||
|
interval = 5,
|
||||||
|
chance = 1,
|
||||||
|
action = function(pos, node)
|
||||||
|
local time = os.time()
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local init_time = meta:get_int("init_time") or 0
|
||||||
|
if time > init_time + 30 then
|
||||||
|
local id = meta:get_int("particle_id")
|
||||||
|
if id then
|
||||||
|
minetest.delete_particlespawner(id)
|
||||||
|
end
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_entity("shooter:flare_entity", {
|
||||||
|
physical = true,
|
||||||
|
timer = 0,
|
||||||
|
visual = "cube",
|
||||||
|
visual_size = {x=1/8, y=1/8},
|
||||||
|
textures = {
|
||||||
|
"shooter_flare.png",
|
||||||
|
"shooter_flare.png",
|
||||||
|
"shooter_flare.png",
|
||||||
|
"shooter_flare.png",
|
||||||
|
"shooter_flare.png",
|
||||||
|
"shooter_flare.png",
|
||||||
|
},
|
||||||
|
player = nil,
|
||||||
|
collisionbox = {-1/16,-1/16,-1/16, 1/16,1/16,1/16},
|
||||||
|
on_activate = function(self, staticdata)
|
||||||
|
if staticdata == "expired" then
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
self.timer = self.timer + dtime
|
||||||
|
if self.timer > 0.2 then
|
||||||
|
local pos = self.object:getpos()
|
||||||
|
local below = {x=pos.x, y=pos.y - 1, z=pos.z}
|
||||||
|
local node = minetest.get_node(below)
|
||||||
|
if node.name ~= "air" then
|
||||||
|
self.object:setvelocity({x=0, y=-10, z=0})
|
||||||
|
self.object:setacceleration({x=0, y=0, z=0})
|
||||||
|
if minetest.get_node(pos).name == "air" and
|
||||||
|
node.name ~= "default:water_source" and
|
||||||
|
node.name ~= "default:water_flowing" then
|
||||||
|
minetest.place_node(pos, {name="shooter:flare_light"})
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
meta:set_int("particle_id", id)
|
||||||
|
meta:set_int("init_time", os.time())
|
||||||
|
pos.y = pos.y - 0.1
|
||||||
|
local id = minetest.add_particlespawner(
|
||||||
|
1000, 30, pos, pos,
|
||||||
|
{x=-1, y=1, z=-1}, {x=1, y=1, z=1},
|
||||||
|
{x=2, y=-2, z=-2}, {x=2, y=-2, z=2},
|
||||||
|
0.1, 0.75, 1, 8, false, "shooter_flare_particle.png"
|
||||||
|
)
|
||||||
|
local sound = minetest.sound_play("shooter_flare_burn", {
|
||||||
|
object = self.player,
|
||||||
|
loop = true,
|
||||||
|
})
|
||||||
|
minetest.after(30, function(sound)
|
||||||
|
minetest.sound_stop(sound)
|
||||||
|
end, sound)
|
||||||
|
end
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
self.timer = 0
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
get_staticdata = function(self)
|
||||||
|
return "expired"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_tool("shooter:flaregun", {
|
||||||
|
description = "Flare Gun",
|
||||||
|
inventory_image = "shooter_flaregun.png",
|
||||||
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
local inv = user:get_inventory()
|
||||||
|
if not inv:contains_item("main", "shooter:flare") then
|
||||||
|
minetest.sound_play("shooter_click", {object=user})
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
|
inv:remove_item("main", "shooter:flare 1")
|
||||||
|
itemstack:add_wear(65535/100)
|
||||||
|
end
|
||||||
|
local pos = user:getpos()
|
||||||
|
local dir = user:get_look_dir()
|
||||||
|
local yaw = user:get_look_yaw()
|
||||||
|
if pos and dir and yaw then
|
||||||
|
pos.y = pos.y + 1.5
|
||||||
|
local obj = minetest.add_entity(pos, "shooter:flare_entity")
|
||||||
|
if obj then
|
||||||
|
minetest.sound_play("shooter_flare_fire", {object=obj})
|
||||||
|
obj:setvelocity({x=dir.x * 16, y=dir.y * 16, z=dir.z * 16})
|
||||||
|
obj:setacceleration({x=dir.x * -3, y=-10, z=dir.z * -3})
|
||||||
|
obj:setyaw(yaw + math.pi)
|
||||||
|
local ent = obj:get_luaentity()
|
||||||
|
if ent then
|
||||||
|
ent.player = ent.player or user
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
if SHOOTER_ENABLE_CRAFTING == true then
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:flare",
|
||||||
|
recipe = {
|
||||||
|
{"tnt:gunpowder", "wool:red"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:flaregun",
|
||||||
|
recipe = {
|
||||||
|
{"wool:red", "wool:red", "wool:red"},
|
||||||
|
{"", "", "default:steel_ingot"}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
132
grapple.lua
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
local function throw_hook(itemstack, user, vel)
|
||||||
|
local inv = user:get_inventory()
|
||||||
|
local pos = user:getpos()
|
||||||
|
local dir = user:get_look_dir()
|
||||||
|
local yaw = user:get_look_yaw()
|
||||||
|
if pos and dir and yaw then
|
||||||
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
|
itemstack:add_wear(65535/100)
|
||||||
|
end
|
||||||
|
pos.y = pos.y + 1.5
|
||||||
|
local obj = minetest.add_entity(pos, "shooter:hook")
|
||||||
|
if obj then
|
||||||
|
minetest.sound_play("shooter_throw", {object=obj})
|
||||||
|
obj:setvelocity({x=dir.x * vel, y=dir.y * vel, z=dir.z * vel})
|
||||||
|
obj:setacceleration({x=dir.x * -3, y=-10, z=dir.z * -3})
|
||||||
|
obj:setyaw(yaw + math.pi)
|
||||||
|
local ent = obj:get_luaentity()
|
||||||
|
if ent then
|
||||||
|
ent.player = ent.player or user
|
||||||
|
ent.itemstack = itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_entity("shooter:hook", {
|
||||||
|
physical = true,
|
||||||
|
timer = 0,
|
||||||
|
visual = "wielditem",
|
||||||
|
visual_size = {x=1/2, y=1/2},
|
||||||
|
textures = {"shooter:grapple_hook"},
|
||||||
|
player = nil,
|
||||||
|
itemstack = "",
|
||||||
|
collisionbox = {-1/4,-1/4,-1/4, 1/4,1/4,1/4},
|
||||||
|
on_activate = function(self, staticdata)
|
||||||
|
self.object:set_armor_groups({fleshy=0})
|
||||||
|
if staticdata == "expired" then
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
if not self.player then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self.timer = self.timer + dtime
|
||||||
|
if self.timer > 0.25 then
|
||||||
|
local pos = self.object:getpos()
|
||||||
|
local below = {x=pos.x, y=pos.y - 1, z=pos.z}
|
||||||
|
local node = minetest.get_node(below)
|
||||||
|
if node.name ~= "air" then
|
||||||
|
self.object:setvelocity({x=0, y=-10, z=0})
|
||||||
|
self.object:setacceleration({x=0, y=0, z=0})
|
||||||
|
if minetest.get_item_group(node.name, "liquid") == 0 and
|
||||||
|
minetest.get_node(pos).name == "air" then
|
||||||
|
self.player:setpos(pos)
|
||||||
|
end
|
||||||
|
if minetest.get_item_group(node.name, "lava") == 0 then
|
||||||
|
minetest.add_item(pos, self.itemstack)
|
||||||
|
end
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
self.timer = 0
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
get_staticdata = function(self)
|
||||||
|
return "expired"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_tool("shooter:grapple_hook", {
|
||||||
|
description = "Grappling Hook",
|
||||||
|
inventory_image = "shooter_hook.png",
|
||||||
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
if pointed_thing.type ~= "nothing" then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
throw_hook(itemstack, user, 14)
|
||||||
|
return ""
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_tool("shooter:grapple_gun", {
|
||||||
|
description = "Grappling Gun",
|
||||||
|
inventory_image = "shooter_hook_gun.png",
|
||||||
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
local inv = user:get_inventory()
|
||||||
|
if inv:contains_item("main", "shooter:grapple_hook") and
|
||||||
|
inv:contains_item("main", "tnt:gunpowder") then
|
||||||
|
inv:remove_item("main", "tnt:gunpowder")
|
||||||
|
minetest.sound_play("shooter_reload", {object=user})
|
||||||
|
local stack = inv:remove_item("main", "shooter:grapple_hook")
|
||||||
|
itemstack = "shooter:grapple_gun_loaded 1 "..stack:get_wear()
|
||||||
|
else
|
||||||
|
minetest.sound_play("shooter_click", {object=user})
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_tool("shooter:grapple_gun_loaded", {
|
||||||
|
description = "Grappling Gun",
|
||||||
|
inventory_image = "shooter_hook_gun_loaded.png",
|
||||||
|
groups = {not_in_creative_inventory=1},
|
||||||
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
if pointed_thing.type ~= "nothing" then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
minetest.sound_play("shooter_pistol", {object=user})
|
||||||
|
itemstack = ItemStack("shooter:grapple_hook 1 "..itemstack:get_wear())
|
||||||
|
throw_hook(itemstack, user, 20)
|
||||||
|
return "shooter:grapple_gun"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
if SHOOTER_ENABLE_CRAFTING == true then
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:grapple_hook",
|
||||||
|
recipe = {
|
||||||
|
{"default:steel_ingot", "default:steel_ingot", "default:diamond"},
|
||||||
|
{"default:steel_ingot", "default:steel_ingot", ""},
|
||||||
|
{"default:diamond", "", "default:steel_ingot"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:grapple_gun",
|
||||||
|
recipe = {
|
||||||
|
{"", "default:steel_ingot", "default:steel_ingot"},
|
||||||
|
{"", "", "default:diamond"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
80
grenade.lua
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
minetest.register_entity("shooter:grenade_entity", {
|
||||||
|
physical = false,
|
||||||
|
timer = 0,
|
||||||
|
visual = "cube",
|
||||||
|
visual_size = {x=1/8, y=1/8},
|
||||||
|
textures = {
|
||||||
|
"shooter_grenade.png",
|
||||||
|
"shooter_grenade.png",
|
||||||
|
"shooter_grenade.png",
|
||||||
|
"shooter_grenade.png",
|
||||||
|
"shooter_grenade.png",
|
||||||
|
"shooter_grenade.png",
|
||||||
|
},
|
||||||
|
player = nil,
|
||||||
|
collisionbox = {0,0,0, 0,0,0},
|
||||||
|
on_activate = function(self, staticdata)
|
||||||
|
if staticdata == "expired" then
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
self.timer = self.timer + dtime
|
||||||
|
if self.timer > 0.2 then
|
||||||
|
local pos = self.object:getpos()
|
||||||
|
local below = {x=pos.x, y=pos.y - 1, z=pos.z}
|
||||||
|
if minetest.get_node(below).name ~= "air" then
|
||||||
|
self.object:remove()
|
||||||
|
shooter:blast(pos, 1, 25, 5)
|
||||||
|
end
|
||||||
|
self.timer = 0
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
get_staticdata = function(self)
|
||||||
|
return "expired"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_tool("shooter:grenade", {
|
||||||
|
description = "Grenade",
|
||||||
|
inventory_image = "shooter_hand_grenade.png",
|
||||||
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
|
itemstack = ""
|
||||||
|
end
|
||||||
|
if pointed_thing.type ~= "nothing" then
|
||||||
|
local pointed = minetest.get_pointed_thing_position(pointed_thing)
|
||||||
|
if vector.distance(user:getpos(), pointed) < 8 then
|
||||||
|
shooter:blast(pointed, 1, 25, 5)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local pos = user:getpos()
|
||||||
|
local dir = user:get_look_dir()
|
||||||
|
local yaw = user:get_look_yaw()
|
||||||
|
if pos and dir then
|
||||||
|
pos.y = pos.y + 1.5
|
||||||
|
local obj = minetest.add_entity(pos, "shooter:grenade_entity")
|
||||||
|
if obj then
|
||||||
|
obj:setvelocity({x=dir.x * 15, y=dir.y * 15, z=dir.z * 15})
|
||||||
|
obj:setacceleration({x=dir.x * -3, y=-10, z=dir.z * -3})
|
||||||
|
obj:setyaw(yaw + math.pi)
|
||||||
|
local ent = obj:get_luaentity()
|
||||||
|
if ent then
|
||||||
|
ent.player = ent.player or user
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
if SHOOTER_ENABLE_CRAFTING == true then
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:grenade",
|
||||||
|
recipe = {
|
||||||
|
{"tnt:gunpowder", "default:steel_ingot"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
127
guns.lua
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
shooter:register_weapon("shooter:pistol", {
|
||||||
|
description = "Pistol",
|
||||||
|
inventory_image = "shooter_pistol.png",
|
||||||
|
rounds = 200,
|
||||||
|
spec = {
|
||||||
|
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},
|
||||||
|
sound = "shooter_pistol",
|
||||||
|
particle = "shooter_cap.png",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
shooter:register_weapon("shooter:rifle", {
|
||||||
|
description = "Rifle",
|
||||||
|
inventory_image = "shooter_rifle.png",
|
||||||
|
rounds = 100,
|
||||||
|
spec = {
|
||||||
|
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},
|
||||||
|
sound = "shooter_rifle",
|
||||||
|
particle = "shooter_bullet.png",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
shooter:register_weapon("shooter:shotgun", {
|
||||||
|
description = "Shotgun",
|
||||||
|
inventory_image = "shooter_shotgun.png",
|
||||||
|
rounds = 50,
|
||||||
|
spec = {
|
||||||
|
range = 50,
|
||||||
|
step = 15,
|
||||||
|
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},
|
||||||
|
sound = "shooter_shotgun",
|
||||||
|
particle = "smoke_puff.png",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
shooter:register_weapon("shooter:machine_gun", {
|
||||||
|
description = "Sub Machine Gun",
|
||||||
|
inventory_image = "shooter_smgun.png",
|
||||||
|
rounds = 50,
|
||||||
|
shots = 4,
|
||||||
|
spec = {
|
||||||
|
range = 100,
|
||||||
|
step = 20,
|
||||||
|
tool_caps = {full_punch_interval=0.125, damage_groups={fleshy=2}},
|
||||||
|
groups = {snappy=3, fleshy=3, oddly_breakable_by_hand=3},
|
||||||
|
sound = "shooter_pistol",
|
||||||
|
particle = "shooter_cap.png",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craftitem("shooter:ammo", {
|
||||||
|
description = "Ammo pack",
|
||||||
|
inventory_image = "shooter_ammo.png",
|
||||||
|
})
|
||||||
|
|
||||||
|
if SHOOTER_ENABLE_CRAFTING == true then
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:pistol 1 65535",
|
||||||
|
recipe = {
|
||||||
|
{"default:steel_ingot", "default:steel_ingot"},
|
||||||
|
{"", "default:mese_crystal"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:rifle 1 65535",
|
||||||
|
recipe = {
|
||||||
|
{"default:steel_ingot", "", ""},
|
||||||
|
{"", "default:bronze_ingot", ""},
|
||||||
|
{"", "default:mese_crystal", "default:bronze_ingot"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:shotgun 1 65535",
|
||||||
|
recipe = {
|
||||||
|
{"default:steel_ingot", "", ""},
|
||||||
|
{"", "default:steel_ingot", ""},
|
||||||
|
{"", "default:mese_crystal", "default:bronze_ingot"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:machine_gun 1 65535",
|
||||||
|
recipe = {
|
||||||
|
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||||
|
{"", "default:bronze_ingot", "default:mese_crystal"},
|
||||||
|
{"", "default:bronze_ingot", ""},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:ammo",
|
||||||
|
recipe = {
|
||||||
|
{"tnt:gunpowder", "default:bronze_ingot"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local rounds_update_time = 0
|
||||||
|
|
||||||
|
minetest.register_globalstep(function(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 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)
|
||||||
|
|
124
init.lua
|
@ -1,107 +1,23 @@
|
||||||
dofile(minetest.get_modpath(minetest.get_current_modname()).."/shooter.lua")
|
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||||
|
|
||||||
shooter:register_weapon("shooter:pistol", {
|
dofile(modpath.."/shooter.lua")
|
||||||
description = "Pistol",
|
|
||||||
inventory_image = "shooter_pistol.png",
|
|
||||||
rounds = 200,
|
|
||||||
spec = {
|
|
||||||
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},
|
|
||||||
sound = "shooter_pistol",
|
|
||||||
particle = "shooter_cap.png",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
shooter:register_weapon("shooter:rifle", {
|
if SHOOTER_ENABLE_GUNS == true then
|
||||||
description = "Rifle",
|
dofile(modpath.."/guns.lua")
|
||||||
inventory_image = "shooter_rifle.png",
|
end
|
||||||
rounds = 100,
|
if SHOOTER_ENABLE_FLARES == true then
|
||||||
spec = {
|
dofile(modpath.."/flaregun.lua")
|
||||||
range = 200,
|
end
|
||||||
step = 30,
|
if SHOOTER_ENABLE_HOOK == true then
|
||||||
tool_caps = {full_punch_interval=1.0, damage_groups={fleshy=3}},
|
dofile(modpath.."/grapple.lua")
|
||||||
groups = {snappy=3, crumbly=3, choppy=3, fleshy=2, oddly_breakable_by_hand=2},
|
end
|
||||||
sound = "shooter_rifle",
|
if SHOOTER_ENABLE_GRENADES == true then
|
||||||
particle = "shooter_bullet.png",
|
dofile(modpath.."/grenade.lua")
|
||||||
},
|
end
|
||||||
})
|
if SHOOTER_ENABLE_ROCKETS == true then
|
||||||
|
dofile(modpath.."/rocket.lua")
|
||||||
shooter:register_weapon("shooter:shotgun", {
|
end
|
||||||
description = "Shotgun",
|
if SHOOTER_ENABLE_TURRETS == true then
|
||||||
inventory_image = "shooter_shotgun.png",
|
dofile(modpath.."/turret.lua")
|
||||||
rounds = 50,
|
end
|
||||||
spec = {
|
|
||||||
range = 50,
|
|
||||||
step = 15,
|
|
||||||
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},
|
|
||||||
sound = "shooter_shotgun",
|
|
||||||
particle = "smoke_puff.png",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
shooter:register_weapon("shooter:machine_gun", {
|
|
||||||
description = "Sub Machine Gun",
|
|
||||||
inventory_image = "shooter_smgun.png",
|
|
||||||
rounds = 50,
|
|
||||||
shots = 4,
|
|
||||||
spec = {
|
|
||||||
range = 100,
|
|
||||||
step = 20,
|
|
||||||
tool_caps = {full_punch_interval=0.125, damage_groups={fleshy=2}},
|
|
||||||
groups = {snappy=3, fleshy=3, oddly_breakable_by_hand=3},
|
|
||||||
sound = "shooter_pistol",
|
|
||||||
particle = "shooter_cap.png",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craftitem("shooter:ammo", {
|
|
||||||
description = "Ammo pack",
|
|
||||||
inventory_image = "shooter_ammo.png",
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "shooter:pistol 1 65535",
|
|
||||||
recipe = {
|
|
||||||
{"default:steel_ingot", "default:steel_ingot"},
|
|
||||||
{"", "default:mese_crystal"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "shooter:rifle 1 65535",
|
|
||||||
recipe = {
|
|
||||||
{"default:steel_ingot", "", ""},
|
|
||||||
{"", "default:bronze_ingot", ""},
|
|
||||||
{"", "default:mese_crystal", "default:bronze_ingot"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "shooter:shotgun 1 65535",
|
|
||||||
recipe = {
|
|
||||||
{"default:steel_ingot", "", ""},
|
|
||||||
{"", "default:steel_ingot", ""},
|
|
||||||
{"", "default:mese_crystal", "default:bronze_ingot"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "shooter:machine_gun 1 65535",
|
|
||||||
recipe = {
|
|
||||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
|
||||||
{"", "default:bronze_ingot", "default:mese_crystal"},
|
|
||||||
{"", "default:bronze_ingot", ""},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "shooter:ammo",
|
|
||||||
recipe = {
|
|
||||||
{"tnt:gunpowder", "default:bronze_ingot"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
BIN
models/shooter_turret.b3d
Normal file
BIN
models/shooter_turret.blend
Normal file
BIN
models/shooter_turret_uv.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
113
rocket.lua
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
minetest.register_craftitem("shooter:rocket", {
|
||||||
|
description = "Rocket",
|
||||||
|
stack_max = 1,
|
||||||
|
inventory_image = "shooter_rocket_inv.png",
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_entity("shooter:rocket_entity", {
|
||||||
|
physical = false,
|
||||||
|
timer = 0,
|
||||||
|
visual = "cube",
|
||||||
|
visual_size = {x=1/8, y=1/8},
|
||||||
|
textures = {
|
||||||
|
"shooter_bullet.png",
|
||||||
|
"shooter_bullet.png",
|
||||||
|
"shooter_bullet.png",
|
||||||
|
"shooter_bullet.png",
|
||||||
|
"shooter_bullet.png",
|
||||||
|
"shooter_bullet.png",
|
||||||
|
},
|
||||||
|
player = nil,
|
||||||
|
collisionbox = {0,0,0, 0,0,0},
|
||||||
|
on_activate = function(self, staticdata)
|
||||||
|
if staticdata == "expired" then
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
self.timer = self.timer + dtime
|
||||||
|
if self.timer > 0.2 then
|
||||||
|
local pos = self.object:getpos()
|
||||||
|
if minetest.get_node(pos).name ~= "air" then
|
||||||
|
self.object:remove()
|
||||||
|
shooter:blast(pos, 2, 50, 7)
|
||||||
|
end
|
||||||
|
self.timer = 0
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
get_staticdata = function(self)
|
||||||
|
return "expired"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_tool("shooter:rocket_gun_loaded", {
|
||||||
|
description = "Rocket Gun",
|
||||||
|
inventory_image = "shooter_rocket_gun_loaded.png",
|
||||||
|
groups = {not_in_creative_inventory=1},
|
||||||
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
|
itemstack:add_wear(65535/50)
|
||||||
|
end
|
||||||
|
itemstack = "shooter:rocket_gun 1 "..itemstack:get_wear()
|
||||||
|
if pointed_thing.type ~= "nothing" then
|
||||||
|
local pointed = minetest.get_pointed_thing_position(pointed_thing)
|
||||||
|
if vector.distance(user:getpos(), pointed) < 8 then
|
||||||
|
shooter:blast(pointed, 2, 50, 7)
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local pos = user:getpos()
|
||||||
|
local dir = user:get_look_dir()
|
||||||
|
local yaw = user:get_look_yaw()
|
||||||
|
if pos and dir and yaw then
|
||||||
|
pos.y = pos.y + 1.5
|
||||||
|
local obj = minetest.add_entity(pos, "shooter:rocket_entity")
|
||||||
|
if obj then
|
||||||
|
minetest.sound_play("shooter_rocket_fire", {object=obj})
|
||||||
|
obj:setvelocity({x=dir.x * 20, y=dir.y * 20, z=dir.z * 20})
|
||||||
|
obj:setacceleration({x=dir.x * -3, y=-10, z=dir.z * -3})
|
||||||
|
obj:setyaw(yaw + math.pi)
|
||||||
|
local ent = obj:get_luaentity()
|
||||||
|
if ent then
|
||||||
|
ent.player = ent.player or user
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_tool("shooter:rocket_gun", {
|
||||||
|
description = "Rocket Gun",
|
||||||
|
inventory_image = "shooter_rocket_gun.png",
|
||||||
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
local inv = user:get_inventory()
|
||||||
|
if inv:contains_item("main", "shooter:rocket") then
|
||||||
|
minetest.sound_play("shooter_reload", {object=user})
|
||||||
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
|
inv:remove_item("main", "shooter:rocket 1")
|
||||||
|
end
|
||||||
|
itemstack = "shooter:rocket_gun_loaded 1 "..itemstack:get_wear()
|
||||||
|
else
|
||||||
|
minetest.sound_play("shooter_click", {object=user})
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
if SHOOTER_ENABLE_CRAFTING == true then
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:rocket_gun",
|
||||||
|
recipe = {
|
||||||
|
{"default:bronze_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||||
|
{"", "", "default:diamond"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:rocket",
|
||||||
|
recipe = {
|
||||||
|
{"default:bronze_ingot", "tnt:gunpowder", "default:bronze_ingot"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
|
@ -2,6 +2,27 @@
|
||||||
|
|
||||||
-- Global Constants (defaults)
|
-- Global Constants (defaults)
|
||||||
|
|
||||||
|
-- Enable basic guns (Pistol, Rifle, Shotgun, Machine Gun)
|
||||||
|
SHOOTER_ENABLE_GUNS = true
|
||||||
|
|
||||||
|
-- Enable Flare Gun
|
||||||
|
SHOOTER_ENABLE_FLARES = true
|
||||||
|
|
||||||
|
-- Enable Grappling Hook
|
||||||
|
SHOOTER_ENABLE_HOOK = true
|
||||||
|
|
||||||
|
-- Enable Grenades
|
||||||
|
SHOOTER_ENABLE_GRENADES = true
|
||||||
|
|
||||||
|
-- Enable Rocket Gun
|
||||||
|
SHOOTER_ENABLE_ROCKETS = true
|
||||||
|
|
||||||
|
-- Enable Turrret Gun
|
||||||
|
SHOOTER_ENABLE_TURRETS = true
|
||||||
|
|
||||||
|
-- Enable Crafting
|
||||||
|
SHOOTER_ENABLE_CRAFTING = true
|
||||||
|
|
||||||
-- Enable particle effects
|
-- Enable particle effects
|
||||||
SHOOTER_ENABLE_PARTICLE_FX = true
|
SHOOTER_ENABLE_PARTICLE_FX = true
|
||||||
|
|
||||||
|
|
105
shooter.lua
|
@ -3,8 +3,17 @@ shooter = {
|
||||||
objects = {},
|
objects = {},
|
||||||
rounds = {},
|
rounds = {},
|
||||||
shots = {},
|
shots = {},
|
||||||
|
update_time = 0,
|
||||||
|
reload_time = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SHOOTER_ENABLE_GUNS = true
|
||||||
|
SHOOTER_ENABLE_FLARES = true
|
||||||
|
SHOOTER_ENABLE_HOOK = true
|
||||||
|
SHOOTER_ENABLE_GRENADES = true
|
||||||
|
SHOOTER_ENABLE_ROCKETS = true
|
||||||
|
SHOOTER_ENABLE_TURRETS = true
|
||||||
|
SHOOTER_ENABLE_CRAFTING = true
|
||||||
SHOOTER_ENABLE_PARTICLE_FX = true
|
SHOOTER_ENABLE_PARTICLE_FX = true
|
||||||
SHOOTER_EXPLOSION_TEXTURE = "shooter_hit.png"
|
SHOOTER_EXPLOSION_TEXTURE = "shooter_hit.png"
|
||||||
SHOOTER_ALLOW_NODES = true
|
SHOOTER_ALLOW_NODES = true
|
||||||
|
@ -44,10 +53,6 @@ if input then
|
||||||
input = nil
|
input = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local rounds_update_time = 0
|
|
||||||
local object_update_time = 0
|
|
||||||
local object_reload_time = 0
|
|
||||||
|
|
||||||
local function get_dot_product(v1, v2)
|
local function get_dot_product(v1, v2)
|
||||||
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
|
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
|
||||||
end
|
end
|
||||||
|
@ -121,7 +126,7 @@ local function punch_node(pos, def)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function process_round(round)
|
function shooter:process_round(round)
|
||||||
local target = {object=nil, distance=10000}
|
local target = {object=nil, distance=10000}
|
||||||
local p1 = round.pos
|
local p1 = round.pos
|
||||||
local v1 = round.ray
|
local v1 = round.ray
|
||||||
|
@ -307,8 +312,8 @@ function shooter:load_objects()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
object_reload_time = shooter.time
|
shooter.reload_time = shooter.time
|
||||||
object_update_time = shooter.time
|
shooter.update_time = shooter.time
|
||||||
shooter.objects = {}
|
shooter.objects = {}
|
||||||
for _,v in ipairs(objects) do
|
for _,v in ipairs(objects) do
|
||||||
table.insert(shooter.objects, v)
|
table.insert(shooter.objects, v)
|
||||||
|
@ -316,9 +321,9 @@ function shooter:load_objects()
|
||||||
end
|
end
|
||||||
|
|
||||||
function shooter:update_objects()
|
function shooter:update_objects()
|
||||||
if shooter.time - object_reload_time > SHOOTER_OBJECT_RELOAD_TIME then
|
if shooter.time - shooter.reload_time > SHOOTER_OBJECT_RELOAD_TIME then
|
||||||
shooter:load_objects()
|
shooter:load_objects()
|
||||||
elseif shooter.time - object_update_time > SHOOTER_OBJECT_UPDATE_TIME then
|
elseif shooter.time - shooter.update_time > SHOOTER_OBJECT_UPDATE_TIME then
|
||||||
for i, ref in ipairs(shooter.objects) do
|
for i, ref in ipairs(shooter.objects) do
|
||||||
if ref.object then
|
if ref.object then
|
||||||
local pos = ref.object:getpos()
|
local pos = ref.object:getpos()
|
||||||
|
@ -329,34 +334,68 @@ function shooter:update_objects()
|
||||||
table.remove(shooter.objects, i)
|
table.remove(shooter.objects, i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
object_update_time = shooter.time
|
shooter.update_time = shooter.time
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function shooter:blast(pos, radius, fleshy, distance)
|
||||||
|
local pos = vector.round(pos)
|
||||||
|
local p1 = vector.subtract(pos, radius)
|
||||||
|
local p2 = vector.add(pos, radius)
|
||||||
|
minetest.sound_play("tnt_explode", {pos=pos, gain=1})
|
||||||
|
minetest.set_node(pos, {name="tnt:boom"})
|
||||||
|
if SHOOTER_ENABLE_PARTICLE_FX == true then
|
||||||
|
minetest.add_particlespawner(50, 0.1,
|
||||||
|
p1, p2, {x=-0, y=-0, z=-0}, {x=0, y=0, z=0},
|
||||||
|
{x=-0.5, y=5, z=-0.5}, {x=0.5, y=5, z=0.5},
|
||||||
|
0.1, 1, 8, 15, false, "tnt_smoke.png"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
local objects = minetest.get_objects_inside_radius(pos, distance)
|
||||||
|
for _,obj in ipairs(objects) do
|
||||||
|
if (obj:is_player() and SHOOTER_ALLOW_PLAYERS == true) or
|
||||||
|
(obj:get_luaentity() and SHOOTER_ALLOW_ENTITIES == true and
|
||||||
|
obj:get_luaentity().name ~= "__builtin:item") then
|
||||||
|
local obj_pos = obj:getpos()
|
||||||
|
local dist = vector.distance(obj_pos, pos)
|
||||||
|
local damage = (fleshy * 0.5 ^ dist) * 2
|
||||||
|
if dist ~= 0 then
|
||||||
|
obj_pos.y = obj_pos.y + 1.7
|
||||||
|
blast_pos = {x=pos.x, y=pos.y + 4, z=pos.z}
|
||||||
|
if minetest.line_of_sight(obj_pos, blast_pos, 1) then
|
||||||
|
obj:punch(obj, 1.0, {
|
||||||
|
full_punch_interval = 1.0,
|
||||||
|
damage_groups = {fleshy=damage},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local pr = PseudoRandom(os.time())
|
||||||
|
local vm = VoxelManip()
|
||||||
|
local min, max = vm:read_from_map(p1, p2)
|
||||||
|
local area = VoxelArea:new({MinEdge=min, MaxEdge=max})
|
||||||
|
local data = vm:get_data()
|
||||||
|
local c_air = minetest.get_content_id("air")
|
||||||
|
for z = -radius, radius do
|
||||||
|
for y = -radius, radius do
|
||||||
|
local vi = area:index(pos.x - radius, pos.y + y, pos.z + z)
|
||||||
|
for x = -radius, radius do
|
||||||
|
if (x * x) + (y * y) + (z * z) <=
|
||||||
|
(radius * radius) + pr:next(-radius, radius) then
|
||||||
|
data[vi] = c_air
|
||||||
|
end
|
||||||
|
vi = vi + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
vm:set_data(data)
|
||||||
|
vm:update_liquids()
|
||||||
|
vm:write_to_map()
|
||||||
|
vm:update_map()
|
||||||
|
end
|
||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
minetest.register_on_joinplayer(function(player)
|
||||||
player:hud_set_flags({crosshair = true})
|
player:hud_set_flags({crosshair = true})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
minetest.register_globalstep(function(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)
|
|
||||||
|
|
||||||
|
|
BIN
sounds/shooter_flare_burn.ogg
Normal file
BIN
sounds/shooter_flare_fire.ogg
Normal file
BIN
sounds/shooter_rocket_fire.ogg
Normal file
BIN
sounds/shooter_throw.ogg
Normal file
Before Width: | Height: | Size: 268 B After Width: | Height: | Size: 268 B |
BIN
textures/shooter_flare.png
Normal file
After Width: | Height: | Size: 173 B |
BIN
textures/shooter_flare_inv.png
Normal file
After Width: | Height: | Size: 278 B |
BIN
textures/shooter_flare_light.png
Normal file
After Width: | Height: | Size: 291 B |
BIN
textures/shooter_flare_particle.png
Normal file
After Width: | Height: | Size: 310 B |
BIN
textures/shooter_flaregun.png
Normal file
After Width: | Height: | Size: 498 B |
BIN
textures/shooter_grenade.png
Normal file
After Width: | Height: | Size: 178 B |
BIN
textures/shooter_hand_grenade.png
Normal file
After Width: | Height: | Size: 381 B |
BIN
textures/shooter_hook.png
Normal file
After Width: | Height: | Size: 567 B |
BIN
textures/shooter_hook_gun.png
Normal file
After Width: | Height: | Size: 537 B |
BIN
textures/shooter_hook_gun_loaded.png
Normal file
After Width: | Height: | Size: 569 B |
BIN
textures/shooter_rocket_gun.png
Normal file
After Width: | Height: | Size: 690 B |
BIN
textures/shooter_rocket_gun_loaded.png
Normal file
After Width: | Height: | Size: 679 B |
BIN
textures/shooter_rocket_inv.png
Normal file
After Width: | Height: | Size: 376 B |
BIN
textures/shooter_turret_base.png
Normal file
After Width: | Height: | Size: 178 B |
BIN
textures/shooter_turret_gun.png
Normal file
After Width: | Height: | Size: 354 B |
BIN
textures/shooter_turret_uv.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
272
turret.lua
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
local function get_turret_entity(pos)
|
||||||
|
local entity = nil
|
||||||
|
local objects = minetest.get_objects_inside_radius(pos, 1)
|
||||||
|
for _, obj in ipairs(objects) do
|
||||||
|
local ent = obj:get_luaentity()
|
||||||
|
if ent then
|
||||||
|
if ent.name == "shooter:turret_entity" then
|
||||||
|
-- Remove duplicates
|
||||||
|
if entity then
|
||||||
|
obj:remove()
|
||||||
|
else
|
||||||
|
entity = ent
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return entity
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_entity("shooter:tnt_entity", {
|
||||||
|
physical = false,
|
||||||
|
timer = 0,
|
||||||
|
visual = "cube",
|
||||||
|
visual_size = {x=1/4, y=1/4},
|
||||||
|
textures = {
|
||||||
|
"tnt_top.png",
|
||||||
|
"tnt_bottom.png",
|
||||||
|
"tnt_side.png",
|
||||||
|
"tnt_side.png",
|
||||||
|
"tnt_side.png",
|
||||||
|
"tnt_side.png",
|
||||||
|
},
|
||||||
|
player = nil,
|
||||||
|
collisionbox = {0,0,0, 0,0,0},
|
||||||
|
on_activate = function(self, staticdata)
|
||||||
|
if staticdata == "expired" then
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
self.timer = self.timer + dtime
|
||||||
|
if self.timer > 0.2 then
|
||||||
|
local pos = self.object:getpos()
|
||||||
|
if minetest.get_node(pos).name ~= "air" then
|
||||||
|
self.object:remove()
|
||||||
|
shooter:blast(pos, 4, 80, 10)
|
||||||
|
end
|
||||||
|
self.timer = 0
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
get_staticdata = function(self)
|
||||||
|
return "expired"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_entity("shooter:turret_entity", {
|
||||||
|
physical = true,
|
||||||
|
visual = "mesh",
|
||||||
|
mesh = "shooter_turret.b3d",
|
||||||
|
visual_size = {x=1, y=1},
|
||||||
|
collisionbox = {-0.3, 0.5,-0.3, 0.3,1,0.3},
|
||||||
|
textures = {
|
||||||
|
"shooter_turret_uv.png",
|
||||||
|
},
|
||||||
|
timer = 0,
|
||||||
|
player = nil,
|
||||||
|
pitch = 40,
|
||||||
|
yaw = 0,
|
||||||
|
firing = false,
|
||||||
|
on_activate = function(self, staticdata)
|
||||||
|
self.pos = self.object:getpos()
|
||||||
|
self.yaw = self.object:getyaw()
|
||||||
|
if minetest.get_node(self.pos).name ~= "shooter:turret" then
|
||||||
|
self.object:remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self.object:set_animation({x=self.pitch, y=self.pitch}, 0)
|
||||||
|
self.object:set_armor_groups({fleshy=0})
|
||||||
|
-- Remove duplicates
|
||||||
|
get_turret_entity(self.pos)
|
||||||
|
end,
|
||||||
|
on_rightclick = function(self, clicker)
|
||||||
|
if self.player == nil then
|
||||||
|
clicker:set_attach(self.object, "", {x=0,y=5,z=-8}, {x=0,y=0,z=0})
|
||||||
|
self.player = clicker
|
||||||
|
else
|
||||||
|
self.player:set_detach()
|
||||||
|
local yaw = self.yaw + math.pi / 2
|
||||||
|
local dir = vector.normalize({
|
||||||
|
x = math.cos(yaw),
|
||||||
|
y = 0,
|
||||||
|
z = math.sin(yaw),
|
||||||
|
})
|
||||||
|
local pos = vector.subtract(self.player:getpos(), dir)
|
||||||
|
minetest.after(0.2, function(player)
|
||||||
|
player:setpos(pos)
|
||||||
|
end, self.player)
|
||||||
|
self.player = nil
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
self.timer = self.timer + dtime
|
||||||
|
if self.timer < 0.1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if self.player then
|
||||||
|
local pitch = self.pitch
|
||||||
|
local yaw = self.object:getyaw()
|
||||||
|
local ctrl = self.player:get_player_control()
|
||||||
|
local step = 2
|
||||||
|
if ctrl then
|
||||||
|
if ctrl.sneak then
|
||||||
|
step = 1
|
||||||
|
if ctrl.jump then
|
||||||
|
if self.firing == false then
|
||||||
|
self:fire()
|
||||||
|
self.firing = true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.firing = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ctrl.down then
|
||||||
|
pitch = pitch + 1 * step
|
||||||
|
elseif ctrl.up then
|
||||||
|
pitch = pitch - 1 * step
|
||||||
|
end
|
||||||
|
if ctrl.left then
|
||||||
|
yaw = yaw + 0.025 * step
|
||||||
|
elseif ctrl.right then
|
||||||
|
yaw = yaw - 0.025 * step
|
||||||
|
end
|
||||||
|
if pitch < 0 then
|
||||||
|
pitch = 0
|
||||||
|
elseif pitch > 90 then
|
||||||
|
pitch = 90
|
||||||
|
end
|
||||||
|
if self.pitch ~= pitch then
|
||||||
|
self.object:set_animation({x=pitch, y=pitch}, 0)
|
||||||
|
self.pitch = pitch
|
||||||
|
end
|
||||||
|
if self.yaw ~= yaw then
|
||||||
|
self.object:setyaw(yaw)
|
||||||
|
self.yaw = yaw
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.timer = 0
|
||||||
|
end,
|
||||||
|
fire = function(self)
|
||||||
|
local meta = minetest.get_meta(self.pos)
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
if not inv then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not inv:contains_item("main", "tnt:tnt") then
|
||||||
|
minetest.sound_play("shooter_click", {object=self.object})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
minetest.sound_play("shooter_shotgun", {object=self.object})
|
||||||
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
|
inv:remove_item("main", "tnt:tnt")
|
||||||
|
end
|
||||||
|
local pitch = math.rad(self.pitch - 40)
|
||||||
|
local len = math.cos(pitch)
|
||||||
|
local dir = vector.normalize({
|
||||||
|
x = len * math.sin(-self.yaw),
|
||||||
|
y = math.sin(pitch),
|
||||||
|
z = len * math.cos(self.yaw),
|
||||||
|
})
|
||||||
|
local pos = {x=self.pos.x, y=self.pos.y + 0.87, z=self.pos.z}
|
||||||
|
pos = vector.add(pos, {x=dir.x * 1.5, y=dir.y * 1.5, z=dir.z * 1.5})
|
||||||
|
local obj = minetest.add_entity(pos, "shooter:tnt_entity")
|
||||||
|
if obj then
|
||||||
|
minetest.sound_play("shooter_rocket_fire", {object=obj})
|
||||||
|
obj:setyaw(self.yaw)
|
||||||
|
obj:setvelocity({x=dir.x * 20, y=dir.y * 20, z=dir.z * 20})
|
||||||
|
obj:setacceleration({x=dir.x * -3, y=-10, z=dir.z * -3})
|
||||||
|
end
|
||||||
|
if SHOOTER_ENABLE_PARTICLE_FX == true then
|
||||||
|
minetest.add_particlespawner(10, 0.1,
|
||||||
|
{x=pos.x - 1, y=pos.y - 1, z=pos.z - 1},
|
||||||
|
{x=pos.x + 1, y=pos.y + 1, z=pos.z + 1},
|
||||||
|
{x=0, y=0, z=0}, {x=0, y=0, z=0},
|
||||||
|
{x=-0.5, y=-0.5, z=-0.5}, {x=0.5, y=0.5, z=0.5},
|
||||||
|
0.1, 1, 8, 15, false, "tnt_smoke.png"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_node("shooter:turret", {
|
||||||
|
description = "Turret Gun",
|
||||||
|
tiles = {"shooter_turret_base.png"},
|
||||||
|
inventory_image = "shooter_turret_gun.png",
|
||||||
|
wield_image = "shooter_turret_gun.png",
|
||||||
|
drawtype = "nodebox",
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=3},
|
||||||
|
node_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {
|
||||||
|
{-1/8, 1/8, -1/8, 1/8, 1/2, 1/8},
|
||||||
|
{-5/16, 0, -5/16, 5/16, 1/8, 5/16},
|
||||||
|
{-3/8, -1/2, -3/8, -1/4, 0, -1/4},
|
||||||
|
{1/4, -1/2, 1/4, 3/8, 0, 3/8},
|
||||||
|
{1/4, -1/2, -3/8, 3/8, 0, -1/4},
|
||||||
|
{-3/8, -1/2, 1/4, -1/4, 0, 3/8},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_construct = function(pos)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
meta:set_string("formspec", "size[8,9]"..
|
||||||
|
"list[current_name;main;2,0;4,4;]"..
|
||||||
|
"list[current_player;main;0,5;8,4;]"
|
||||||
|
)
|
||||||
|
meta:set_string("infotext", "Turret Gun")
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
inv:set_size("main", 16)
|
||||||
|
end,
|
||||||
|
after_place_node = function(pos, placer)
|
||||||
|
local node = minetest.get_node({x=pos.x, y=pos.y + 1, z=pos.z})
|
||||||
|
if node.name == "air" then
|
||||||
|
if not get_turret_entity(pos) then
|
||||||
|
minetest.add_entity(pos, "shooter:turret_entity")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
can_dig = function(pos, player)
|
||||||
|
local meta = minetest.get_meta(pos);
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
return inv:is_empty("main")
|
||||||
|
end,
|
||||||
|
after_destruct = function(pos, oldnode)
|
||||||
|
local ent = get_turret_entity(pos)
|
||||||
|
if ent then
|
||||||
|
ent.object:remove()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
mesecons = {
|
||||||
|
effector = {
|
||||||
|
action_on = function(pos, node)
|
||||||
|
local ent = get_turret_entity(pos)
|
||||||
|
if ent then
|
||||||
|
if ent.firing == false then
|
||||||
|
ent:fire()
|
||||||
|
ent.firing = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
action_off = function(pos, node)
|
||||||
|
local ent = get_turret_entity(pos)
|
||||||
|
if ent then
|
||||||
|
ent.firing = false
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if SHOOTER_ENABLE_CRAFTING == true then
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "shooter:turret",
|
||||||
|
recipe = {
|
||||||
|
{"default:bronze_ingot", "default:bronze_ingot", "default:steel_ingot"},
|
||||||
|
{"", "default:bronze_ingot", "default:steel_ingot"},
|
||||||
|
{"", "default:diamond", ""},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|