Update shooter to 0.6.1
3
.gitmodules
vendored
|
@ -4,3 +4,6 @@
|
||||||
[submodule "mods/ctf/ctf_map/ctf_map_core/maps"]
|
[submodule "mods/ctf/ctf_map/ctf_map_core/maps"]
|
||||||
path = mods/ctf/ctf_map/ctf_map_core/maps
|
path = mods/ctf/ctf_map/ctf_map_core/maps
|
||||||
url = https://github.com/MT-CTF/maps
|
url = https://github.com/MT-CTF/maps
|
||||||
|
[submodule "mods/pvp/shooter"]
|
||||||
|
path = mods/pvp/shooter
|
||||||
|
url = https://github.com/MT-CTF/shooter
|
||||||
|
|
|
@ -30,6 +30,10 @@ read_globals = {
|
||||||
"prometheus", "hb",
|
"prometheus", "hb",
|
||||||
"awards",
|
"awards",
|
||||||
|
|
||||||
|
"VoxelArea",
|
||||||
|
"VoxelManip",
|
||||||
|
"PseudoRandom",
|
||||||
|
|
||||||
|
|
||||||
-- Testing
|
-- Testing
|
||||||
"describe",
|
"describe",
|
||||||
|
|
|
@ -17,16 +17,28 @@ function ctf_classes.register(cname, def)
|
||||||
if not def.properties.item_blacklist then
|
if not def.properties.item_blacklist then
|
||||||
def.properties.item_blacklist = {}
|
def.properties.item_blacklist = {}
|
||||||
for i=1, #def.properties.initial_stuff do
|
for i=1, #def.properties.initial_stuff do
|
||||||
table.insert(def.properties.item_blacklist, def.properties.initial_stuff[i])
|
def.properties.item_blacklist[i] =
|
||||||
|
ItemStack(def.properties.initial_stuff[i]):get_name()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if def.properties.additional_item_blacklist then
|
if def.properties.additional_item_blacklist then
|
||||||
for i=1, #def.properties.additional_item_blacklist do
|
for i=1, #def.properties.additional_item_blacklist do
|
||||||
table.insert(def.properties.item_blacklist, def.properties.additional_item_blacklist[i])
|
table.insert(def.properties.item_blacklist,
|
||||||
|
def.properties.additional_item_blacklist[i])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Validate items
|
||||||
|
for i=1, #def.properties.initial_stuff do
|
||||||
|
local item_name = ItemStack(def.properties.initial_stuff[i]):get_name()
|
||||||
|
assert(minetest.registered_items[item_name], "Item " .. item_name .. " not found")
|
||||||
|
end
|
||||||
|
for i=1, #def.properties.item_blacklist do
|
||||||
|
local item_name = def.properties.item_blacklist[i]
|
||||||
|
assert(minetest.registered_items[item_name], "Item " .. item_name .. " not found")
|
||||||
|
end
|
||||||
|
|
||||||
def.properties.speed = def.properties.speed or 1
|
def.properties.speed = def.properties.speed or 1
|
||||||
def.properties.max_hp = def.properties.max_hp or 20
|
def.properties.max_hp = def.properties.max_hp or 20
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,9 +14,9 @@ ctf_classes.register("knight", {
|
||||||
},
|
},
|
||||||
|
|
||||||
allowed_guns = {
|
allowed_guns = {
|
||||||
"shooter:pistol",
|
"shooter_guns:pistol",
|
||||||
"shooter:smg",
|
"shooter_guns:smg",
|
||||||
"shooter:shotgun",
|
"shooter_guns:shotgun",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -30,27 +30,30 @@ ctf_classes.register("shooter", {
|
||||||
allow_grapples = true,
|
allow_grapples = true,
|
||||||
|
|
||||||
initial_stuff = {
|
initial_stuff = {
|
||||||
"shooter:rifle",
|
"shooter_guns:rifle_loaded",
|
||||||
"shooter:grapple_gun_loaded",
|
"shooter_hook:grapple_gun_loaded",
|
||||||
},
|
},
|
||||||
|
|
||||||
additional_item_blacklist = {
|
additional_item_blacklist = {
|
||||||
"shooter:grapple_gun",
|
"shooter_hook:grapple_gun",
|
||||||
"shooter:grapple_hook",
|
"shooter_hook:grapple_hook",
|
||||||
|
"shooter_guns:rifle",
|
||||||
},
|
},
|
||||||
|
|
||||||
allowed_guns = {
|
allowed_guns = {
|
||||||
"shooter:pistol",
|
"shooter_guns:pistol",
|
||||||
"shooter:rifle",
|
"shooter_guns:rifle",
|
||||||
"shooter:smg",
|
"shooter_guns:smg",
|
||||||
"shooter:shotgun",
|
"shooter_guns:shotgun",
|
||||||
},
|
},
|
||||||
|
|
||||||
shooter_multipliers = {
|
shooter_multipliers = {
|
||||||
range = 1.5,
|
range = 1.5,
|
||||||
|
tool_caps = {
|
||||||
full_punch_interval = 0.8,
|
full_punch_interval = 0.8,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
ctf_classes.register("medic", {
|
ctf_classes.register("medic", {
|
||||||
|
@ -66,9 +69,9 @@ ctf_classes.register("medic", {
|
||||||
},
|
},
|
||||||
|
|
||||||
allowed_guns = {
|
allowed_guns = {
|
||||||
"shooter:pistol",
|
"shooter_guns:pistol",
|
||||||
"shooter:smg",
|
"shooter_guns:smg",
|
||||||
"shooter:shotgun",
|
"shooter_guns:shotgun",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -80,18 +83,18 @@ ctf_classes.register("rocketeer", {
|
||||||
color = "#fa0",
|
color = "#fa0",
|
||||||
properties = {
|
properties = {
|
||||||
initial_stuff = {
|
initial_stuff = {
|
||||||
"shooter:rocket_gun_loaded",
|
"shooter_rocket:rocket_gun_loaded",
|
||||||
"shooter:rocket 4",
|
"shooter_rocket:rocket 4",
|
||||||
},
|
},
|
||||||
|
|
||||||
additional_item_blacklist = {
|
additional_item_blacklist = {
|
||||||
"shooter:rocket_gun",
|
"shooter_rocket:rocket_gun",
|
||||||
},
|
},
|
||||||
|
|
||||||
allowed_guns = {
|
allowed_guns = {
|
||||||
"shooter:pistol",
|
"shooter_guns:pistol",
|
||||||
"shooter:smg",
|
"shooter_guns:smg",
|
||||||
"shooter:shotgun",
|
"shooter_guns:shotgun",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -9,30 +9,46 @@ end
|
||||||
-- Returns true if the item shouldn't be allowed to be dropped etc
|
-- Returns true if the item shouldn't be allowed to be dropped etc
|
||||||
local function is_class_blacklisted(player, itemname)
|
local function is_class_blacklisted(player, itemname)
|
||||||
local class = ctf_classes.get(player)
|
local class = ctf_classes.get(player)
|
||||||
local items = stack_list_to_map(class.properties.item_blacklist or {})
|
local items = stack_list_to_map(class.properties.item_blacklist)
|
||||||
return items[itemname]
|
return items[itemname]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
give_initial_stuff.register_stuff_provider(function(player)
|
give_initial_stuff.register_stuff_provider(function(player)
|
||||||
local class = ctf_classes.get(player)
|
local class = ctf_classes.get(player)
|
||||||
return class.properties.initial_stuff or {}
|
return class.properties.initial_stuff
|
||||||
end, 1)
|
end, 1)
|
||||||
|
|
||||||
|
|
||||||
|
local function remove_blacklist_in_list(list, blacklist_map)
|
||||||
|
local removed = false
|
||||||
|
for i=1, #list do
|
||||||
|
if blacklist_map[ItemStack(list[i]):get_name()] then
|
||||||
|
list[i] = ""
|
||||||
|
removed = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return removed
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
ctf_classes.register_on_changed(function(player, old, new)
|
ctf_classes.register_on_changed(function(player, old, new)
|
||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
|
|
||||||
if old then
|
local blacklist = old.properties.item_blacklist
|
||||||
local items = old.properties.item_blacklist or {}
|
if old and #blacklist > 0 then
|
||||||
for i = 1, #items do
|
local blacklist_map = stack_list_to_map(blacklist)
|
||||||
inv:remove_item("main", ItemStack(items[i]))
|
for listname, list in pairs(inv:get_lists()) do
|
||||||
|
if remove_blacklist_in_list(list, blacklist_map) then
|
||||||
|
inv:set_list(listname, list)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
assert(new)
|
assert(new)
|
||||||
|
|
||||||
local items = new.properties.initial_stuff or {}
|
local items = new.properties.initial_stuff
|
||||||
for i = 1, #items do
|
for i = 1, #items do
|
||||||
inv:add_item("main", ItemStack(items[i]))
|
inv:add_item("main", ItemStack(items[i]))
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
name = ctf_classes
|
name = ctf_classes
|
||||||
depends = ctf, ctf_flag, ctf_colors, ctf_map_core, physics, shooter, hpregen, give_initial_stuff, dropondie
|
depends = ctf, ctf_flag, ctf_colors, ctf_map_core, ctf_bandages, physics, shooter, hpregen, give_initial_stuff, dropondie
|
||||||
description = Adds classes, including knight, shooter, and medic
|
description = Adds classes, including knight, shooter, and medic
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
local specs_cache = {}
|
local function recursive_multiply(source, multiplier)
|
||||||
|
for key, value in pairs(multiplier) do
|
||||||
|
assert(type(source[key]) == type(value))
|
||||||
|
if type(value) == "table" then
|
||||||
|
recursive_multiply(source[key], value)
|
||||||
|
else
|
||||||
|
source[key] = source[key] * value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function get_shooter_specs(weapon_name, multiplier)
|
local function get_shooter_specs(weapon_name, multiplier)
|
||||||
local spec = shooter.registered_weapons[weapon_name]
|
local spec = shooter.registered_weapons[weapon_name]
|
||||||
if not spec then
|
if not spec then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
spec = spec.spec
|
|
||||||
|
|
||||||
-- this will convert the multipler to a table pointer
|
spec = table.copy(spec.spec)
|
||||||
local idx = ("%s:%s"):format(multiplier or "nil", weapon_name)
|
|
||||||
|
|
||||||
if specs_cache[idx] then
|
if multiplier then
|
||||||
return specs_cache[idx]
|
recursive_multiply(spec, multiplier)
|
||||||
end
|
|
||||||
|
|
||||||
spec = table.copy(spec)
|
|
||||||
specs_cache[idx] = spec
|
|
||||||
|
|
||||||
for key, value in pairs(multiplier) do
|
|
||||||
spec[key] = spec[key] * value
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return spec
|
return spec
|
||||||
end
|
end
|
||||||
|
|
||||||
shooter.get_weapon_spec = function(_, user, weapon_name)
|
shooter.get_weapon_spec = function(user, weapon_name)
|
||||||
local class = ctf_classes.get(user)
|
local class = ctf_classes.get(user)
|
||||||
|
|
||||||
if table.indexof(class.properties.allowed_guns or {}, weapon_name) == -1 then
|
if table.indexof(class.properties.allowed_guns or {}, weapon_name) == -1 then
|
||||||
|
@ -34,7 +34,9 @@ shooter.get_weapon_spec = function(_, user, weapon_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
local spec = get_shooter_specs(weapon_name, class.properties.shooter_multipliers)
|
local spec = get_shooter_specs(weapon_name, class.properties.shooter_multipliers)
|
||||||
spec.name = user and user:get_player_name()
|
if not spec then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
return spec
|
return spec
|
||||||
end
|
end
|
||||||
|
@ -64,6 +66,6 @@ local function check_grapple(itemname)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
check_grapple("shooter:grapple_gun_loaded")
|
check_grapple("shooter_hook:grapple_gun_loaded")
|
||||||
check_grapple("shooter:grapple_gun")
|
check_grapple("shooter_hook:grapple_gun")
|
||||||
check_grapple("shooter:grapple_hook")
|
check_grapple("shooter_hook:grapple_hook")
|
||||||
|
|
|
@ -40,3 +40,11 @@ end
|
||||||
minetest.after(5, function()
|
minetest.after(5, function()
|
||||||
ctf_match.next()
|
ctf_match.next()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
ctf_match.register_on_build_time_start(function()
|
||||||
|
shooter.config.allow_players = false
|
||||||
|
end)
|
||||||
|
|
||||||
|
ctf_match.register_on_build_time_end(function()
|
||||||
|
shooter.config.allow_players = true
|
||||||
|
end)
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
name = ctf_match
|
name = ctf_match
|
||||||
depends = ctf, ctf_flag, ctf_inventory, ctf_alloc, vote, hudkit
|
depends = ctf, ctf_flag, ctf_inventory, ctf_alloc, vote, hudkit, shooter
|
||||||
optional_depends = irc
|
optional_depends = irc
|
||||||
|
|
1
mods/pvp/shooter
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 5593df448fbb8a74478c54ad2e4e3755ffa51ce9
|
8
mods/pvp/shooter/.gitignore
vendored
|
@ -1,8 +0,0 @@
|
||||||
## Generic ignorable patterns and files
|
|
||||||
*~
|
|
||||||
.*.swp
|
|
||||||
*bak*
|
|
||||||
tags
|
|
||||||
*.vim
|
|
||||||
shooter.conf
|
|
||||||
crosshair.png
|
|
|
@ -1,33 +0,0 @@
|
||||||
Minetest Mod - Simple Shooter [shooter]
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
License Source Code: 2013 Stuart Jones - LGPL v2.1
|
|
||||||
|
|
||||||
Additional credit for code ideas taken from other mods.
|
|
||||||
|
|
||||||
PilzAdam [throwing] for the throwing physics
|
|
||||||
ShadowNinja [nuke] for the vm explosion routine
|
|
||||||
|
|
||||||
License Textures: Stuart Jones - WTFPL
|
|
||||||
|
|
||||||
Licence Models: Stuart Jones - CC-BY-SA 3.0
|
|
||||||
|
|
||||||
License Sounds: freesound.org
|
|
||||||
|
|
||||||
flobert1_20070728.wav by Nonoo - Attribution 3.0 Unported (CC BY 3.0)
|
|
||||||
|
|
||||||
shot.wav by Sergenious - Attribution 3.0 Unported (CC BY 3.0)
|
|
||||||
|
|
||||||
GUNSHOT.WAV by erkanozan - CC0 1.0 Universal (CC0 1.0)
|
|
||||||
|
|
||||||
winchester-rifle-cock-reload.wav by MentalSanityOff - 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)
|
|
||||||
|
|
||||||
tnt_explode.ogg by steveygos93, TumeniNodes - CC0 1.0 Universal (CC0 1.0)
|
|
|
@ -1,169 +0,0 @@
|
||||||
Minetest Mod - Simple Shooter [shooter]
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
Mod Version: 0.5.3
|
|
||||||
|
|
||||||
Minetest Version: 0.4.9, 0.4.10, 0.4.11
|
|
||||||
|
|
||||||
Depends: default, dye, tnt, wool
|
|
||||||
|
|
||||||
An experimental first person shooter mod that uses simple vector mathematics
|
|
||||||
to produce an accurate and server-firendly method of hit detection.
|
|
||||||
|
|
||||||
By default this mod is configured to work only against other players in
|
|
||||||
multiplayer mode and against Simple Mobs [mobs] in singleplayer mode.
|
|
||||||
|
|
||||||
Default configuration can be customised by adding a shooter.conf file to
|
|
||||||
the mod's main directory, see shooter.conf.example for more details.
|
|
||||||
|
|
||||||
This is still very much a work in progress which I eventually plan to use
|
|
||||||
as the base for a 'Spades' style FPS game using the minetest engine.
|
|
||||||
|
|
||||||
Crafting
|
|
||||||
========
|
|
||||||
|
|
||||||
<color> = grey, black, red, yellow, green, cyan, blue, magenta
|
|
||||||
|
|
||||||
A = Arrow [shooter:arrow_white]
|
|
||||||
C = Color Dye [dye:<color>]
|
|
||||||
W = Wooden Stick [default:stick]
|
|
||||||
P = Paper [default:paper]
|
|
||||||
S = Steel Ingot [default:steel_ingot]
|
|
||||||
B = Bronze Ingot [default:bronze_ingot]
|
|
||||||
M = Mese Crystal [default:mese_crysytal]
|
|
||||||
D = Diamond [default:diamond]
|
|
||||||
R = Red Wool [wool:red]
|
|
||||||
G = Gun Powder [tnt:gunpowder]
|
|
||||||
|
|
||||||
Crossbow: [shooter:crossbow]
|
|
||||||
|
|
||||||
+---+---+---+
|
|
||||||
| W | W | W |
|
|
||||||
+---+---+---+
|
|
||||||
| W | W | |
|
|
||||||
+---+---+---+
|
|
||||||
| W | | B |
|
|
||||||
+---+---+---+
|
|
||||||
|
|
||||||
White Arrow: [shooter:arrow_white]
|
|
||||||
|
|
||||||
+---+---+---+
|
|
||||||
| S | | |
|
|
||||||
+---+---+---+
|
|
||||||
| | W | P |
|
|
||||||
+---+---+---+
|
|
||||||
| | P | W |
|
|
||||||
+---+---+---+
|
|
||||||
|
|
||||||
Coloured Arrow: [shooter:arrow_<color>]
|
|
||||||
|
|
||||||
+---+---+
|
|
||||||
| C | A |
|
|
||||||
+---+---+
|
|
||||||
|
|
||||||
Pistol: [shooter:pistol]
|
|
||||||
|
|
||||||
+---+---+
|
|
||||||
| S | S |
|
|
||||||
+---+---+
|
|
||||||
| | M |
|
|
||||||
+---+---+
|
|
||||||
|
|
||||||
Rifle: [shooter:rifle]
|
|
||||||
|
|
||||||
+---+---+---+
|
|
||||||
| S | | |
|
|
||||||
+---+---+---+
|
|
||||||
| | B | |
|
|
||||||
+---+---+---+
|
|
||||||
| | M | B |
|
|
||||||
+---+---+---+
|
|
||||||
|
|
||||||
Shotgun: [shooter:shotgun]
|
|
||||||
|
|
||||||
+---+---+---+
|
|
||||||
| S | | |
|
|
||||||
+---+---+---+
|
|
||||||
| | S | |
|
|
||||||
+---+---+---+
|
|
||||||
| | M | B |
|
|
||||||
+---+---+---+
|
|
||||||
|
|
||||||
Sub Machine Gun: [shooter:machine_gun]
|
|
||||||
|
|
||||||
+---+---+---+
|
|
||||||
| S | S | S |
|
|
||||||
+---+---+---+
|
|
||||||
| | B | M |
|
|
||||||
+---+---+---+
|
|
||||||
| | B | |
|
|
||||||
+---+---+---+
|
|
||||||
|
|
||||||
Ammo Pack: [shooter:ammo]
|
|
||||||
|
|
||||||
+---+---+
|
|
||||||
| 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,293 +0,0 @@
|
||||||
SHOOTER_CROSSBOW_USES = 50
|
|
||||||
SHOOTER_ARROW_TOOL_CAPS = {damage_groups={fleshy=2}}
|
|
||||||
SHOOTER_ARROW_LIFETIME = 180 -- 3 minutes
|
|
||||||
|
|
||||||
minetest.register_alias("shooter:arrow", "shooter:arrow_white")
|
|
||||||
minetest.register_alias("shooter:crossbow_loaded", "shooter:crossbow_loaded_white")
|
|
||||||
|
|
||||||
local dye_basecolors = (dye and dye.basecolors) or
|
|
||||||
{"white", "grey", "black", "red", "yellow", "green", "cyan", "blue", "magenta"}
|
|
||||||
|
|
||||||
local function get_animation_frame(dir)
|
|
||||||
local angle = math.atan(dir.y)
|
|
||||||
local frame = 90 - math.floor(angle * 360 / math.pi)
|
|
||||||
if frame < 1 then
|
|
||||||
frame = 1
|
|
||||||
elseif frame > 180 then
|
|
||||||
frame = 180
|
|
||||||
end
|
|
||||||
return frame
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_target_pos(p1, p2, dir, offset)
|
|
||||||
local d = vector.distance(p1, p2) - offset
|
|
||||||
local td = vector.multiply(dir, {x=d, y=d, z=d})
|
|
||||||
return vector.add(p1, td)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- name is the overlay texture name, colour is used to select the wool texture
|
|
||||||
local function get_texture(name, colour)
|
|
||||||
return "shooter_"..name..".png^wool_"..colour..".png^shooter_"..name..".png^[makealpha:255,126,126"
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_entity("shooter:arrow_entity", {
|
|
||||||
physical = false,
|
|
||||||
collide_with_objects = false,
|
|
||||||
visual = "mesh",
|
|
||||||
mesh = "shooter_arrow.b3d",
|
|
||||||
visual_size = {x=1, y=1},
|
|
||||||
textures = {
|
|
||||||
get_texture("arrow_uv", "white"),
|
|
||||||
},
|
|
||||||
color = "white",
|
|
||||||
timer = 0,
|
|
||||||
lifetime = SHOOTER_ARROW_LIFETIME,
|
|
||||||
player = nil,
|
|
||||||
state = "init",
|
|
||||||
node_pos = nil,
|
|
||||||
collisionbox = {0,0,0, 0,0,0},
|
|
||||||
stop = function(self, pos)
|
|
||||||
local acceleration = {x=0, y=-10, z=0}
|
|
||||||
if self.state == "stuck" then
|
|
||||||
pos = pos or self.object:get_pos()
|
|
||||||
acceleration = {x=0, y=0, z=0}
|
|
||||||
end
|
|
||||||
if pos then
|
|
||||||
self.object:move_to(pos)
|
|
||||||
end
|
|
||||||
self.object:set_properties({
|
|
||||||
physical = true,
|
|
||||||
collisionbox = {-1/8, -1/8, -1/8, 1/8, 1/8, 1/8},
|
|
||||||
})
|
|
||||||
self.object:set_velocity({x=0, y=0, z=0})
|
|
||||||
self.object:set_acceleration(acceleration)
|
|
||||||
end,
|
|
||||||
strike = function(self, object)
|
|
||||||
local puncher = self.player
|
|
||||||
if puncher and shooter:is_valid_object(object) then
|
|
||||||
if puncher ~= object then
|
|
||||||
local dir = puncher:get_look_dir()
|
|
||||||
local p1 = puncher:get_pos()
|
|
||||||
local p2 = object:get_pos()
|
|
||||||
local tpos = get_target_pos(p1, p2, dir, 0)
|
|
||||||
shooter:spawn_particles(tpos, SHOOTER_EXPLOSION_TEXTURE)
|
|
||||||
object:punch(puncher, nil, SHOOTER_ARROW_TOOL_CAPS, dir)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self:stop(object:get_pos())
|
|
||||||
end,
|
|
||||||
on_activate = function(self, staticdata)
|
|
||||||
self.object:set_armor_groups({immortal=1})
|
|
||||||
if staticdata == "expired" then
|
|
||||||
self.object:remove()
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
on_punch = function(self, puncher)
|
|
||||||
if puncher then
|
|
||||||
if puncher:is_player() then
|
|
||||||
local stack = "shooter:arrow_"..self.color
|
|
||||||
local inv = puncher:get_inventory()
|
|
||||||
if inv:room_for_item("main", stack) then
|
|
||||||
inv:add_item("main", stack)
|
|
||||||
self.object:remove()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
on_step = function(self, dtime)
|
|
||||||
if self.state == "init" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
self.timer = self.timer + dtime
|
|
||||||
self.lifetime = self.lifetime - dtime
|
|
||||||
if self.lifetime < 0 then
|
|
||||||
self.object:remove()
|
|
||||||
return
|
|
||||||
elseif self.state == "dropped" then
|
|
||||||
return
|
|
||||||
elseif self.state == "stuck" then
|
|
||||||
if self.timer > 1 then
|
|
||||||
if self.node_pos then
|
|
||||||
local node = minetest.get_node(self.node_pos)
|
|
||||||
if node.name then
|
|
||||||
local item = minetest.registered_items[node.name]
|
|
||||||
if item then
|
|
||||||
if not item.walkable then
|
|
||||||
self.state = "dropped"
|
|
||||||
self:stop()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self.timer = 0
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if self.timer > 0.2 then
|
|
||||||
local pos = self.object:getpos()
|
|
||||||
local dir = vector.normalize(self.object:getvelocity())
|
|
||||||
local frame = get_animation_frame(dir)
|
|
||||||
self.object:set_animation({x=frame, y=frame}, 0)
|
|
||||||
local objects = minetest.get_objects_inside_radius(pos, 5)
|
|
||||||
for _, obj in ipairs(objects) do
|
|
||||||
if shooter:is_valid_object(obj) and obj ~= self.player then
|
|
||||||
local collisionbox = {-0.25,-1.0,-0.25, 0.25,0.8,0.25}
|
|
||||||
local offset = SHOOTER_PLAYER_OFFSET
|
|
||||||
if not obj:is_player() then
|
|
||||||
offset = SHOOTER_ENTITY_OFFSET
|
|
||||||
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:get_pos(), 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
|
|
||||||
local p = vector.add(pos, vector.multiply(dir, {x=5, y=5, z=5}))
|
|
||||||
local _, npos = minetest.line_of_sight(pos, p, 1)
|
|
||||||
if npos then
|
|
||||||
local node = minetest.get_node(npos)
|
|
||||||
local tpos = get_target_pos(pos, npos, dir, 0.66)
|
|
||||||
self.node_pos = npos
|
|
||||||
self.state = "stuck"
|
|
||||||
self:stop(tpos)
|
|
||||||
shooter:play_node_sound(node, npos)
|
|
||||||
end
|
|
||||||
self.timer = 0
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
get_staticdata = function(self)
|
|
||||||
return "expired"
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, color in pairs(dye_basecolors) do
|
|
||||||
minetest.register_craftitem("shooter:arrow_"..color, {
|
|
||||||
description = color:gsub("%a", string.upper, 1).." Arrow",
|
|
||||||
inventory_image = get_texture("arrow_inv", color),
|
|
||||||
})
|
|
||||||
minetest.register_tool("shooter:crossbow_loaded_"..color, {
|
|
||||||
description = "Crossbow",
|
|
||||||
inventory_image = get_texture("crossbow_loaded", color),
|
|
||||||
groups = {not_in_creative_inventory=1},
|
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
|
||||||
minetest.sound_play("shooter_click", {object=user})
|
|
||||||
if not minetest.settings:get_bool("creative_mode") then
|
|
||||||
itemstack:add_wear(65535/SHOOTER_CROSSBOW_USES)
|
|
||||||
end
|
|
||||||
itemstack = "shooter:crossbow 1 "..itemstack:get_wear()
|
|
||||||
local pos = user:get_pos()
|
|
||||||
local dir = user:get_look_dir()
|
|
||||||
local yaw = user:get_look_horizontal()
|
|
||||||
if pos and dir and yaw then
|
|
||||||
pos.y = pos.y + 1.5
|
|
||||||
local obj = minetest.add_entity(pos, "shooter:arrow_entity")
|
|
||||||
local ent = nil
|
|
||||||
if obj then
|
|
||||||
ent = obj:get_luaentity()
|
|
||||||
end
|
|
||||||
if ent then
|
|
||||||
ent.player = ent.player or user
|
|
||||||
ent.state = "flight"
|
|
||||||
ent.color = color
|
|
||||||
obj:set_properties({
|
|
||||||
textures = {get_texture("arrow_uv", color)}
|
|
||||||
})
|
|
||||||
minetest.sound_play("shooter_throw", {object=obj})
|
|
||||||
local frame = get_animation_frame(dir)
|
|
||||||
obj:set_yaw(yaw + math.pi)
|
|
||||||
obj:set_animation({x=frame, y=frame}, 0)
|
|
||||||
obj:set_velocity({x=dir.x * 14, y=dir.y * 14, z=dir.z * 14})
|
|
||||||
if pointed_thing.type ~= "nothing" then
|
|
||||||
local ppos = minetest.get_pointed_thing_position(pointed_thing, false)
|
|
||||||
local _, npos = minetest.line_of_sight(pos, ppos, 1)
|
|
||||||
if npos then
|
|
||||||
ppos = npos
|
|
||||||
pointed_thing.type = "node"
|
|
||||||
end
|
|
||||||
if pointed_thing.type == "object" then
|
|
||||||
ent:strike(pointed_thing.ref)
|
|
||||||
return itemstack
|
|
||||||
elseif pointed_thing.type == "node" then
|
|
||||||
local node = minetest.get_node(ppos)
|
|
||||||
local tpos = get_target_pos(pos, ppos, dir, 0.66)
|
|
||||||
minetest.after(0.2, function(object, pos, npos)
|
|
||||||
ent.node_pos = npos
|
|
||||||
ent.state = "stuck"
|
|
||||||
ent:stop(pos)
|
|
||||||
shooter:play_node_sound(node, npos)
|
|
||||||
end, obj, tpos, ppos)
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
end
|
|
||||||
obj:set_acceleration({x=dir.x * -3, y=-5, z=dir.z * -3})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return itemstack
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_tool("shooter:crossbow", {
|
|
||||||
description = "Crossbow",
|
|
||||||
inventory_image = "shooter_crossbow.png",
|
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
|
||||||
local inv = user:get_inventory()
|
|
||||||
local stack = inv:get_stack("main", user:get_wield_index() + 1)
|
|
||||||
local color = string.match(stack:get_name(), "shooter:arrow_(%a+)")
|
|
||||||
if color then
|
|
||||||
minetest.sound_play("shooter_reload", {object=user})
|
|
||||||
if not minetest.settings:get_bool("creative_mode") then
|
|
||||||
inv:remove_item("main", "shooter:arrow_"..color.." 1")
|
|
||||||
end
|
|
||||||
return "shooter:crossbow_loaded_"..color.." 1 "..itemstack:get_wear()
|
|
||||||
end
|
|
||||||
for _, color in pairs(dye_basecolors) do
|
|
||||||
if inv:contains_item("main", "shooter:arrow_"..color) then
|
|
||||||
minetest.sound_play("shooter_reload", {object=user})
|
|
||||||
if not minetest.settings:get_bool("creative_mode") then
|
|
||||||
inv:remove_item("main", "shooter:arrow_"..color.." 1")
|
|
||||||
end
|
|
||||||
return "shooter:crossbow_loaded_"..color.." 1 "..itemstack:get_wear()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
minetest.sound_play("shooter_click", {object=user})
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
if SHOOTER_ENABLE_CRAFTING == true then
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "shooter:crossbow",
|
|
||||||
recipe = {
|
|
||||||
{"default:stick", "default:stick", "default:stick"},
|
|
||||||
{"default:stick", "default:stick", ""},
|
|
||||||
{"default:stick", "", "default:bronze_ingot"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "shooter:arrow_white",
|
|
||||||
recipe = {
|
|
||||||
{"default:steel_ingot", "", ""},
|
|
||||||
{"", "default:stick", "default:paper"},
|
|
||||||
{"", "default:paper", "default:stick"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
for _, color in pairs(dye_basecolors) do
|
|
||||||
if color ~= "white" then
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "shooter:arrow_"..color,
|
|
||||||
recipe = {
|
|
||||||
{"", "dye:" .. color, "shooter:arrow_white"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,146 +0,0 @@
|
||||||
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.settings:get_bool("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
|
|
|
@ -1,136 +0,0 @@
|
||||||
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.settings:get_bool("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:moveto(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
|
|
||||||
itemstack:add_wear(65536 / 16)
|
|
||||||
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 ent = pointed_thing.ref and pointed_thing.ref:get_luaentity()
|
|
||||||
if ent and ent.name == "__builtin:item" then
|
|
||||||
return ent:on_punch(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
local inv = user:get_inventory()
|
|
||||||
if inv:contains_item("main", "shooter:grapple_hook") then
|
|
||||||
minetest.sound_play("shooter_reload", {object=user})
|
|
||||||
local stack = inv:remove_item("main", "shooter:grapple_hook")
|
|
||||||
itemstack = 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())
|
|
||||||
itemstack:add_wear(65536 / 8)
|
|
||||||
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
|
|
|
@ -1,81 +0,0 @@
|
||||||
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,
|
|
||||||
player_name = 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.1 then
|
|
||||||
local pos = self.object:getpos()
|
|
||||||
local above = {x=pos.x, y=pos.y + 1, z=pos.z}
|
|
||||||
if minetest.get_node(pos).name ~= "air" then
|
|
||||||
self.object:remove()
|
|
||||||
shooter:blast(above, 2, 25, 5, self.player)
|
|
||||||
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.settings:get_bool("creative_mode") then
|
|
||||||
itemstack:take_item()
|
|
||||||
end
|
|
||||||
if pointed_thing.type ~= "nothing" then
|
|
||||||
local pointed = minetest.get_pointed_thing_position(pointed_thing)
|
|
||||||
if vector.distance(user:get_pos(), pointed) < 10 then
|
|
||||||
shooter:blast(pointed, 2, 25, 5)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local pos = user:get_pos()
|
|
||||||
local dir = user:get_look_dir()
|
|
||||||
local yaw = user:get_look_horizontal()
|
|
||||||
if pos and dir then
|
|
||||||
pos.y = pos.y + 1.5
|
|
||||||
local obj = minetest.add_entity(pos, "shooter:grenade_entity")
|
|
||||||
if obj then
|
|
||||||
obj:set_velocity({x = dir.x * 20, y = dir.y * 20, z = dir.z * 20})
|
|
||||||
obj:set_acceleration({x=dir.x * -3, y=-10, z=dir.z * -3})
|
|
||||||
obj:set_yaw(yaw + math.pi)
|
|
||||||
local ent = obj:get_luaentity()
|
|
||||||
if ent then
|
|
||||||
ent.player = ent.player or user
|
|
||||||
ent.player_name = user:get_player_name()
|
|
||||||
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
|
|
|
@ -1,126 +0,0 @@
|
||||||
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=6}},
|
|
||||||
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)
|
|
|
@ -1,26 +0,0 @@
|
||||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
|
||||||
|
|
||||||
dofile(modpath.."/shooter.lua")
|
|
||||||
|
|
||||||
if SHOOTER_ENABLE_CROSSBOW == true then
|
|
||||||
dofile(modpath.."/crossbow.lua")
|
|
||||||
end
|
|
||||||
if SHOOTER_ENABLE_GUNS == true then
|
|
||||||
dofile(modpath.."/guns.lua")
|
|
||||||
end
|
|
||||||
if SHOOTER_ENABLE_FLARES == true then
|
|
||||||
dofile(modpath.."/flaregun.lua")
|
|
||||||
end
|
|
||||||
if SHOOTER_ENABLE_HOOK == true then
|
|
||||||
dofile(modpath.."/grapple.lua")
|
|
||||||
end
|
|
||||||
if SHOOTER_ENABLE_GRENADES == true then
|
|
||||||
dofile(modpath.."/grenade.lua")
|
|
||||||
end
|
|
||||||
if SHOOTER_ENABLE_ROCKETS == true then
|
|
||||||
dofile(modpath.."/rocket.lua")
|
|
||||||
end
|
|
||||||
if SHOOTER_ENABLE_TURRETS == true then
|
|
||||||
dofile(modpath.."/turret.lua")
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
name = shooter
|
|
||||||
depends = default
|
|
||||||
description = First person shooter mod. Adds firearms plus a few other fun items.
|
|
|
@ -1,113 +0,0 @@
|
||||||
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()
|
|
||||||
local above = {x=pos.x, y=pos.y + 1, z=pos.z}
|
|
||||||
if minetest.get_node(pos).name ~= "air" then
|
|
||||||
self.object:remove()
|
|
||||||
shooter:blast(above, 4, 50, 8, self.player)
|
|
||||||
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.settings:get_bool("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.settings:get_bool("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
|
|
Before Width: | Height: | Size: 175 KiB |
|
@ -1,81 +0,0 @@
|
||||||
-- Simple Shooter config example
|
|
||||||
|
|
||||||
-- Global Constants (defaults)
|
|
||||||
|
|
||||||
-- Enable admin super weapons
|
|
||||||
-- This lets admins shoot guns automatically after 2 seconds without munition.
|
|
||||||
SHOOTER_ADMIN_WEAPONS = false
|
|
||||||
|
|
||||||
-- Enable node destruction with explosives
|
|
||||||
SHOOTER_ENABLE_BLASTING = true
|
|
||||||
|
|
||||||
-- Enable Crossbow
|
|
||||||
SHOOTER_ENABLE_CROSSBOW = true
|
|
||||||
|
|
||||||
-- 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
|
|
||||||
SHOOTER_ENABLE_PARTICLE_FX = true
|
|
||||||
|
|
||||||
-- Enable protection mod support, requires a protection mod that utilizes
|
|
||||||
-- minetest.is_protected(), tested with TenPlus1's version of [protector]
|
|
||||||
SHOOTER_ENABLE_PROTECTION = false
|
|
||||||
|
|
||||||
-- Particle texture used when a player or entity is hit
|
|
||||||
SHOOTER_EXPLOSION_TEXTURE = "shooter_hit.png"
|
|
||||||
|
|
||||||
-- Allow node destruction
|
|
||||||
SHOOTER_ALLOW_NODES = true
|
|
||||||
|
|
||||||
-- Allow entities in multiplayer mode
|
|
||||||
SHOOTER_ALLOW_ENTITIES = false
|
|
||||||
|
|
||||||
-- Allow players in multiplayer mode
|
|
||||||
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",
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,492 +0,0 @@
|
||||||
shooter = {
|
|
||||||
time = 0,
|
|
||||||
objects = {},
|
|
||||||
rounds = {},
|
|
||||||
shots = {},
|
|
||||||
update_time = 0,
|
|
||||||
reload_time = 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
SHOOTER_ADMIN_WEAPONS = false
|
|
||||||
SHOOTER_ENABLE_BLASTING = false
|
|
||||||
SHOOTER_ENABLE_CROSSBOW = true
|
|
||||||
SHOOTER_ENABLE_GUNS = true
|
|
||||||
SHOOTER_ENABLE_FLARES = false
|
|
||||||
SHOOTER_ENABLE_HOOK = true
|
|
||||||
SHOOTER_ENABLE_GRENADES = true
|
|
||||||
SHOOTER_ENABLE_ROCKETS = true
|
|
||||||
SHOOTER_ENABLE_TURRETS = true
|
|
||||||
SHOOTER_ENABLE_CRAFTING = false
|
|
||||||
SHOOTER_ENABLE_PARTICLE_FX = true
|
|
||||||
SHOOTER_ENABLE_PROTECTION = false
|
|
||||||
SHOOTER_EXPLOSION_TEXTURE = "shooter_hit.png"
|
|
||||||
SHOOTER_ALLOW_NODES = true
|
|
||||||
SHOOTER_ALLOW_ENTITIES = false
|
|
||||||
SHOOTER_ALLOW_PLAYERS = true
|
|
||||||
SHOOTER_OBJECT_RELOAD_TIME = 1
|
|
||||||
SHOOTER_OBJECT_UPDATE_TIME = 0.25
|
|
||||||
SHOOTER_ROUNDS_UPDATE_TIME = 0.4
|
|
||||||
SHOOTER_EYE_HEIGHT = 1.47
|
|
||||||
SHOOTER_PLAYER_OFFSET = {x=0, y=1, z=0}
|
|
||||||
SHOOTER_ENTITY_OFFSET = {x=0, y=0, z=0}
|
|
||||||
SHOOTER_ENTITIES = {}
|
|
||||||
for k, v in pairs(minetest.registered_entities) do
|
|
||||||
if string.find(k, "^mobs") then
|
|
||||||
table.insert(SHOOTER_ENTITIES, k)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local singleplayer = minetest.is_singleplayer()
|
|
||||||
if singleplayer then
|
|
||||||
SHOOTER_ENABLE_BLASTING = true
|
|
||||||
SHOOTER_ALLOW_ENTITIES = true
|
|
||||||
SHOOTER_ALLOW_PLAYERS = false
|
|
||||||
end
|
|
||||||
|
|
||||||
if minetest.global_exists("ctf_match") then
|
|
||||||
ctf_match.register_on_build_time_start(function()
|
|
||||||
SHOOTER_ALLOW_PLAYERS = false
|
|
||||||
end)
|
|
||||||
ctf_match.register_on_build_time_end(function()
|
|
||||||
SHOOTER_ALLOW_PLAYERS = true
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
|
||||||
local worldpath = minetest.get_worldpath()
|
|
||||||
local input = io.open(modpath.."/shooter.conf", "r")
|
|
||||||
if input then
|
|
||||||
dofile(modpath.."/shooter.conf")
|
|
||||||
input:close()
|
|
||||||
input = nil
|
|
||||||
end
|
|
||||||
input = io.open(worldpath.."/shooter.conf", "r")
|
|
||||||
if input then
|
|
||||||
dofile(worldpath.."/shooter.conf")
|
|
||||||
input:close()
|
|
||||||
input = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local allowed_entities = {}
|
|
||||||
for _,v in ipairs(SHOOTER_ENTITIES) do
|
|
||||||
allowed_entities[v] = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_dot_product(v1, v2)
|
|
||||||
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_particle_pos(p, v, d)
|
|
||||||
return vector.add(p, vector.multiply(v, {x=d, y=d, z=d}))
|
|
||||||
end
|
|
||||||
|
|
||||||
function shooter:spawn_particles(pos, texture)
|
|
||||||
if SHOOTER_ENABLE_PARTICLE_FX == true then
|
|
||||||
if type(texture) ~= "string" then
|
|
||||||
texture = SHOOTER_EXPLOSION_TEXTURE
|
|
||||||
end
|
|
||||||
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
|
|
||||||
|
|
||||||
function shooter:play_node_sound(node, pos)
|
|
||||||
local item = minetest.registered_items[node.name]
|
|
||||||
if item then
|
|
||||||
if item.sounds then
|
|
||||||
local spec = item.sounds.dug
|
|
||||||
if spec then
|
|
||||||
spec.pos = pos
|
|
||||||
minetest.sound_play(spec.name, spec)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function shooter:punch_node(pos, def)
|
|
||||||
local node = minetest.get_node(pos)
|
|
||||||
if not node then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local item = minetest.registered_items[node.name]
|
|
||||||
if not item then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if SHOOTER_ENABLE_PROTECTION then
|
|
||||||
if minetest.is_protected(pos, def.name) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if item.groups then
|
|
||||||
for k, v in pairs(def.groups) do
|
|
||||||
local level = item.groups[k] or 0
|
|
||||||
if level >= v then
|
|
||||||
minetest.remove_node(pos)
|
|
||||||
shooter:play_node_sound(node, pos)
|
|
||||||
if item.tiles then
|
|
||||||
if item.tiles[1] then
|
|
||||||
shooter:spawn_particles(pos, item.tiles[1])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function shooter:is_valid_object(object)
|
|
||||||
if object then
|
|
||||||
if object:is_player() == true then
|
|
||||||
return SHOOTER_ALLOW_PLAYERS
|
|
||||||
end
|
|
||||||
if SHOOTER_ALLOW_ENTITIES == true then
|
|
||||||
local luaentity = object:get_luaentity()
|
|
||||||
if luaentity then
|
|
||||||
if luaentity.name then
|
|
||||||
if allowed_entities[luaentity.name] then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function shooter:get_intersect_pos(ray, plane, collisionbox)
|
|
||||||
local v = vector.subtract(ray.pos, plane.pos)
|
|
||||||
local r1 = get_dot_product(v, plane.normal)
|
|
||||||
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, SHOOTER_EXPLOSION_TEXTURE)
|
|
||||||
end
|
|
||||||
return 1
|
|
||||||
elseif pos and SHOOTER_ALLOW_NODES == true then
|
|
||||||
shooter:punch_node(pos, round.def)
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
local spec = shooter:get_weapon_spec(user, name)
|
|
||||||
if spec then
|
|
||||||
if shots > 1 then
|
|
||||||
local step = spec.tool_caps.full_punch_interval
|
|
||||||
for i = 0, step * shots, step do
|
|
||||||
minetest.after(i, function()
|
|
||||||
shooter:fire_weapon(user, pointed_thing, spec)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
shooter:fire_weapon(user, pointed_thing, spec)
|
|
||||||
end
|
|
||||||
itemstack:add_wear(wear)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local inv = user:get_inventory()
|
|
||||||
if inv then
|
|
||||||
local stack = "shooter:ammo 1"
|
|
||||||
if inv:contains_item("main", stack) then
|
|
||||||
minetest.sound_play("shooter_reload", {object=user})
|
|
||||||
inv:remove_item("main", stack)
|
|
||||||
itemstack:replace(name.." 1 1")
|
|
||||||
else
|
|
||||||
minetest.sound_play("shooter_click", {object=user})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return itemstack
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
function shooter:get_weapon_spec(user, name)
|
|
||||||
local spec = shooter.registered_weapons[name]
|
|
||||||
if not spec then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
spec = spec.spec
|
|
||||||
spec.name = user:get_player_name()
|
|
||||||
return spec
|
|
||||||
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
|
|
||||||
end
|
|
||||||
minetest.add_particle({x=p1.x, y=p1.y + SHOOTER_EYE_HEIGHT, z=p1.z},
|
|
||||||
vector.multiply(v1, {x=30, y=30, z=30}),
|
|
||||||
{x=0, y=0, z=0}, 0.5, 0.25,
|
|
||||||
false, def.particle
|
|
||||||
)
|
|
||||||
if pointed_thing.type == "node" and SHOOTER_ALLOW_NODES == true then
|
|
||||||
local pos = minetest.get_pointed_thing_position(pointed_thing, false)
|
|
||||||
shooter:punch_node(pos, def)
|
|
||||||
elseif pointed_thing.type == "object" then
|
|
||||||
local object = pointed_thing.ref
|
|
||||||
if shooter:is_valid_object(object) == true then
|
|
||||||
object:punch(user, nil, def.tool_caps, v1)
|
|
||||||
local p2 = object:getpos()
|
|
||||||
local pp = get_particle_pos(p1, v1, vector.distance(p1, p2))
|
|
||||||
pp.y = pp.y + SHOOTER_EYE_HEIGHT
|
|
||||||
shooter:spawn_particles(pp, SHOOTER_EXPLOSION_TEXTURE)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
shooter:update_objects()
|
|
||||||
table.insert(shooter.rounds, {
|
|
||||||
name = def.name,
|
|
||||||
pos = vector.add(p1, {x=0, y=SHOOTER_EYE_HEIGHT, z=0}),
|
|
||||||
ray = v1,
|
|
||||||
dist = 0,
|
|
||||||
def = def,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function shooter:load_objects()
|
|
||||||
local objects = {}
|
|
||||||
if SHOOTER_ALLOW_PLAYERS == true then
|
|
||||||
local players = minetest.get_connected_players()
|
|
||||||
for _,player in ipairs(players) do
|
|
||||||
local pos = player:getpos()
|
|
||||||
local name = player:get_player_name()
|
|
||||||
local hp = player:get_hp() or 0
|
|
||||||
if pos and name and hp > 0 then
|
|
||||||
table.insert(objects, {
|
|
||||||
name = name,
|
|
||||||
object = player,
|
|
||||||
pos = pos,
|
|
||||||
collisionbox = {-0.25,-1.0,-0.25, 0.25,0.8,0.25},
|
|
||||||
offset = SHOOTER_PLAYER_OFFSET,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if SHOOTER_ALLOW_ENTITIES == true then
|
|
||||||
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 or {0,0,0, 0,0,0},
|
|
||||||
offset = SHOOTER_ENTITY_OFFSET,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
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
|
|
||||||
|
|
||||||
function shooter:update_objects()
|
|
||||||
if shooter.time - shooter.reload_time > SHOOTER_OBJECT_RELOAD_TIME then
|
|
||||||
shooter:load_objects()
|
|
||||||
elseif shooter.time - shooter.update_time > SHOOTER_OBJECT_UPDATE_TIME then
|
|
||||||
for i, ref in ipairs(shooter.objects) do
|
|
||||||
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
|
|
||||||
|
|
||||||
function shooter:blast(pos, radius, fleshy, distance, user)
|
|
||||||
if not user then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local name = user:get_player_name()
|
|
||||||
local pos = vector.round(pos)
|
|
||||||
local p1 = vector.subtract(pos, radius)
|
|
||||||
local p2 = vector.add(pos, radius)
|
|
||||||
minetest.sound_play("shooter_explode", {pos=pos, gain=1})
|
|
||||||
if SHOOTER_ALLOW_NODES and SHOOTER_ENABLE_BLASTING then
|
|
||||||
if SHOOTER_ENABLE_PROTECTION then
|
|
||||||
if not minetest.is_protected(pos, name) then
|
|
||||||
minetest.set_node(pos, {name="tnt:boom"})
|
|
||||||
end
|
|
||||||
else
|
|
||||||
minetest.set_node(pos, {name="tnt:boom"})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Explosion particles
|
|
||||||
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
|
|
||||||
|
|
||||||
-- Damage to objects within range
|
|
||||||
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.707106 ^ dist) * 3
|
|
||||||
if dist ~= 0 then
|
|
||||||
obj_pos.y = obj_pos.y + SHOOTER_EYE_HEIGHT
|
|
||||||
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(user or obj, 2.0, {
|
|
||||||
full_punch_interval = 1.0,
|
|
||||||
damage_groups = {fleshy=damage, grenade=damage},
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Node blasting using LVM
|
|
||||||
if SHOOTER_ALLOW_NODES and SHOOTER_ENABLE_BLASTING then
|
|
||||||
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 vp = {x=pos.x - radius, y=pos.y + y, z=pos.z + z}
|
|
||||||
local vi = area:index(vp.x, vp.y, vp.z)
|
|
||||||
for x = -radius, radius do
|
|
||||||
if (x * x) + (y * y) + (z * z) <=
|
|
||||||
(radius * radius) + pr:next(-radius, radius) then
|
|
||||||
if SHOOTER_ENABLE_PROTECTION then
|
|
||||||
if not minetest.is_protected(vp, name) then
|
|
||||||
data[vi] = c_air
|
|
||||||
end
|
|
||||||
else
|
|
||||||
data[vi] = c_air
|
|
||||||
end
|
|
||||||
end
|
|
||||||
vi = vi + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
vm:set_data(data)
|
|
||||||
vm:update_liquids()
|
|
||||||
vm:write_to_map()
|
|
||||||
vm:update_map()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not singleplayer and SHOOTER_ADMIN_WEAPONS then
|
|
||||||
local timer = 0
|
|
||||||
local shooting = false
|
|
||||||
minetest.register_globalstep(function(dtime)
|
|
||||||
if not shooting then
|
|
||||||
timer = timer+dtime
|
|
||||||
if timer < 2 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
timer = 0
|
|
||||||
end
|
|
||||||
shooting = false
|
|
||||||
for _,player in pairs(minetest.get_connected_players()) do
|
|
||||||
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:get_weapon_spec(player, player:get_wielded_item():get_name())
|
|
||||||
if spec then
|
|
||||||
shooter.shots[name] = false
|
|
||||||
spec.name = name
|
|
||||||
shooter:fire_weapon(player, {}, spec)
|
|
||||||
shooting = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
Before Width: | Height: | Size: 268 B |
Before Width: | Height: | Size: 234 B |
Before Width: | Height: | Size: 290 B |
Before Width: | Height: | Size: 178 B |
Before Width: | Height: | Size: 157 B |
Before Width: | Height: | Size: 500 B |
Before Width: | Height: | Size: 389 B |
Before Width: | Height: | Size: 173 B |
Before Width: | Height: | Size: 278 B |
Before Width: | Height: | Size: 291 B |
Before Width: | Height: | Size: 310 B |
Before Width: | Height: | Size: 498 B |
Before Width: | Height: | Size: 178 B |
Before Width: | Height: | Size: 381 B |
Before Width: | Height: | Size: 621 B |
Before Width: | Height: | Size: 567 B |
Before Width: | Height: | Size: 537 B |
Before Width: | Height: | Size: 569 B |
Before Width: | Height: | Size: 274 B |
Before Width: | Height: | Size: 420 B |
Before Width: | Height: | Size: 690 B |
Before Width: | Height: | Size: 679 B |
Before Width: | Height: | Size: 376 B |
Before Width: | Height: | Size: 402 B |
Before Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 178 B |
Before Width: | Height: | Size: 354 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 213 B |
Before Width: | Height: | Size: 269 B |
Before Width: | Height: | Size: 267 B |
Before Width: | Height: | Size: 305 B |
Before Width: | Height: | Size: 259 B |
Before Width: | Height: | Size: 265 B |
Before Width: | Height: | Size: 308 B |
Before Width: | Height: | Size: 315 B |
Before Width: | Height: | Size: 301 B |
Before Width: | Height: | Size: 288 B |
Before Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 292 B |
Before Width: | Height: | Size: 251 B |
Before Width: | Height: | Size: 306 B |
Before Width: | Height: | Size: 263 B |
|
@ -1,265 +0,0 @@
|
||||||
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, self.player)
|
|
||||||
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 then
|
|
||||||
self.player:set_detach()
|
|
||||||
self.player = nil
|
|
||||||
else
|
|
||||||
clicker:set_attach(self.object, "", {x=0,y=5,z=-8}, {x=0,y=0,z=0})
|
|
||||||
self.player = clicker
|
|
||||||
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.settings:get_bool("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
|
|
||||||
local ent = obj:get_luaentity()
|
|
||||||
if ent then
|
|
||||||
minetest.sound_play("shooter_rocket_fire", {object=obj})
|
|
||||||
ent.player = self.player
|
|
||||||
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
|
|
||||||
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
|
|
135
mods/pvp/shooter_tweaks/init.lua
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
local function wrap_callback(name, callback, func)
|
||||||
|
assert(type(name) == "string")
|
||||||
|
assert(type(callback) == "string")
|
||||||
|
|
||||||
|
local old_callback = minetest.registered_items[name][callback]
|
||||||
|
assert(old_callback)
|
||||||
|
|
||||||
|
local overrides = {}
|
||||||
|
overrides[callback] = function(...)
|
||||||
|
return func(old_callback, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.override_item(name, overrides)
|
||||||
|
end
|
||||||
|
|
||||||
|
wrap_callback("shooter_hook:grapple_hook", "on_use", function(old, itemstack, ...)
|
||||||
|
itemstack:add_wear(65536 / 16)
|
||||||
|
return old(itemstack, ...)
|
||||||
|
end)
|
||||||
|
|
||||||
|
wrap_callback("shooter_hook:grapple_gun_loaded", "on_use", function(old, itemstack, ...)
|
||||||
|
itemstack:add_wear(65536 / 8)
|
||||||
|
return old(itemstack, ...)
|
||||||
|
end)
|
||||||
|
|
||||||
|
wrap_callback("shooter_hook:grapple_gun", "on_use", function(old, itemstack, user)
|
||||||
|
local inv = user:get_inventory()
|
||||||
|
if inv:contains_item("main", "shooter_hook:grapple_hook") then
|
||||||
|
minetest.sound_play("shooter_reload", {object=user})
|
||||||
|
local stack = inv:remove_item("main", "shooter_hook:grapple_hook")
|
||||||
|
itemstack = "shooter_hook:grapple_gun_loaded 1 "..stack:get_wear()
|
||||||
|
else
|
||||||
|
minetest.sound_play("shooter_click", {object=user})
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
local config = shooter.config
|
||||||
|
local v3d = vector
|
||||||
|
|
||||||
|
shooter.blast = function(pos, radius, fleshy, distance, user)
|
||||||
|
if not user then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
pos = v3d.round(pos)
|
||||||
|
local name = user:get_player_name()
|
||||||
|
local p1 = v3d.subtract(pos, radius)
|
||||||
|
local p2 = v3d.add(pos, radius)
|
||||||
|
minetest.sound_play("shooter_explode", {
|
||||||
|
pos = pos,
|
||||||
|
gain = 10,
|
||||||
|
max_hear_distance = 100
|
||||||
|
})
|
||||||
|
if config.allow_nodes and config.enable_blasting then
|
||||||
|
if not config.enable_protection or
|
||||||
|
not minetest.is_protected(pos, name) then
|
||||||
|
minetest.set_node(pos, {name="shooter:boom"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if config.enable_particle_fx == true then
|
||||||
|
minetest.add_particlespawner({
|
||||||
|
amount = 50,
|
||||||
|
time = 0.1,
|
||||||
|
minpos = p1,
|
||||||
|
maxpos = p2,
|
||||||
|
minvel = {x=0, y=0, z=0},
|
||||||
|
maxvel = {x=0, y=0, z=0},
|
||||||
|
minacc = {x=-0.5, y=5, z=-0.5},
|
||||||
|
maxacc = {x=0.5, y=5, z=0.5},
|
||||||
|
minexptime = 0.1,
|
||||||
|
maxexptime = 1,
|
||||||
|
minsize = 8,
|
||||||
|
maxsize = 15,
|
||||||
|
collisiondetection = false,
|
||||||
|
texture = "shooter_smoke.png",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
local objects = minetest.get_objects_inside_radius(pos, distance)
|
||||||
|
for _,obj in ipairs(objects) do
|
||||||
|
if shooter.is_valid_object(obj) then
|
||||||
|
local obj_pos = obj:get_pos()
|
||||||
|
local dist = v3d.distance(obj_pos, pos)
|
||||||
|
|
||||||
|
-- PATCH
|
||||||
|
local damage = fleshy * (0.707106 ^ dist) * 3
|
||||||
|
-- END PATCH
|
||||||
|
|
||||||
|
if dist ~= 0 then
|
||||||
|
obj_pos.y = obj_pos.y + 1
|
||||||
|
local blast_pos = {x=pos.x, y=pos.y + 4, z=pos.z}
|
||||||
|
if shooter.is_valid_object(obj) and
|
||||||
|
minetest.line_of_sight(obj_pos, blast_pos, 1) then
|
||||||
|
shooter.punch_object(obj, {
|
||||||
|
full_punch_interval = 1.0,
|
||||||
|
damage_groups = {fleshy=damage},
|
||||||
|
}, nil, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if config.allow_nodes and config.enable_blasting then
|
||||||
|
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 vp = {x=pos.x - radius, y=pos.y + y, z=pos.z + z}
|
||||||
|
local vi = area:index(vp.x, vp.y, vp.z)
|
||||||
|
for x = -radius, radius do
|
||||||
|
if (x * x) + (y * y) + (z * z) <=
|
||||||
|
(radius * radius) + pr:next(-radius, radius) then
|
||||||
|
if config.enable_protection then
|
||||||
|
if not minetest.is_protected(vp, name) then
|
||||||
|
data[vi] = c_air
|
||||||
|
end
|
||||||
|
else
|
||||||
|
data[vi] = c_air
|
||||||
|
end
|
||||||
|
end
|
||||||
|
vi = vi + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
vm:set_data(data)
|
||||||
|
vm:update_liquids()
|
||||||
|
vm:write_to_map()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
minetest.registered_entities["shooter_crossbow:arrow_entity"].collide_with_objects = false
|
2
mods/pvp/shooter_tweaks/mod.conf
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
name = shooter_tweaks
|
||||||
|
depends = shooter_grenade, shooter_hook, shooter_guns, shooter_crossbow
|