Add gauges, shooter, ctf_treasure, chatplus
2
mods/ctf_treasure/depends.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
treasurer
|
||||
default
|
34
mods/ctf_treasure/init.lua
Normal file
|
@ -0,0 +1,34 @@
|
|||
--treasurer.register_treasure("firearms:m3",0.5,2,{1,2})
|
||||
--treasurer.register_treasure("firearms:bullet_12g",0.7,1,{1,10})
|
||||
--treasurer.register_treasure("firearms:m4",0.3,3,{1,2})
|
||||
--treasurer.register_treasure("firearms:bullet_556mm", 0.5, 2,{1,10})
|
||||
--treasurer.register_treasure("firearms:m9",0.2,3,{1,2})
|
||||
--treasurer.register_treasure("firearms:bullet_45",0.5,2,{1,20})
|
||||
--[[treasurer.register_treasure("firearms:awp",0.05,8,1)
|
||||
treasurer.register_treasure("firearms:bullet_762mm",0.1,5,{1,22})
|
||||
]]--
|
||||
|
||||
|
||||
treasurer.register_treasure("shooter:pistol",0.5,2,{1,5})
|
||||
treasurer.register_treasure("shooter:rifle",0.1,2,{1,2})
|
||||
treasurer.register_treasure("shooter:shotgun",0.05,2,1)
|
||||
treasurer.register_treasure("shooter:machine_gun",0.01,2,1)
|
||||
treasurer.register_treasure("shooter:ammo",0.5,2,{1,10})
|
||||
|
||||
|
||||
treasurer.register_treasure("throwing:arrow_steel",0.1,5,{1,12})
|
||||
treasurer.register_treasure("throwing:arrow_stone",0.2,5,{1,12})
|
||||
treasurer.register_treasure("throwing:arrow_obsidian",0.3,5,{1,8})
|
||||
--treasurer.register_treasure("throwing:arrow_fire",0.1,5,{1,2})
|
||||
--treasurer.register_treasure("throwing:arrow_tnt",0.1,5,1)
|
||||
treasurer.register_treasure("throwing:arrow_steel",0.2,5,{1,12})
|
||||
treasurer.register_treasure("throwing:bow_wood",0.9,5,{1,12})
|
||||
treasurer.register_treasure("throwing:longbow",0.4,5,1)
|
||||
treasurer.register_treasure("throwing:bow_steel",0.1,5,1)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
43
mods/gauges/init.lua
Normal file
|
@ -0,0 +1,43 @@
|
|||
-- Adds health bars above players.
|
||||
-- Code by 4aiman, textures by Calinou. Licensed under CC0.
|
||||
|
||||
local hp_bar = {
|
||||
physical = false,
|
||||
collisionbox = {x = 0, y = 0, z = 0},
|
||||
visual = "sprite",
|
||||
textures = {"20.png"}, -- The texture is changed later in the code.
|
||||
visual_size = {x = 1.5, y = 0.09375, z = 1.5}, -- Y value is (1 / 16) * 1.5.
|
||||
wielder = nil,
|
||||
}
|
||||
|
||||
function hp_bar:on_step(dtime)
|
||||
local wielder = self.wielder
|
||||
if wielder == nil then
|
||||
self.object:remove()
|
||||
return
|
||||
elseif minetest.env:get_player_by_name(wielder:get_player_name()) == nil then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
hp = wielder:get_hp()
|
||||
breath = wielder:get_breath()
|
||||
self.object:set_properties({textures = {"health_" .. tostring(hp) .. ".png^breath_" .. tostring(breath) .. ".png",},}
|
||||
)
|
||||
end
|
||||
|
||||
minetest.register_entity("gauges:hp_bar", hp_bar)
|
||||
|
||||
function add_HP_gauge(pl)
|
||||
local pos = pl:getpos()
|
||||
local ent = minetest.env:add_entity(pos, "gauges:hp_bar")
|
||||
if ent ~= nil then
|
||||
ent:set_attach(pl, "", {x = 0, y = 10, z = 0}, {x = 0, y = 0, z = 0})
|
||||
ent = ent:get_luaentity()
|
||||
ent.wielder = pl
|
||||
end
|
||||
end
|
||||
|
||||
if minetest.setting_getbool("health_bars") ~= false -- “If not defined or set to true then”
|
||||
and minetest.setting_getbool("enable_damage") then -- Health bars only display when damage is enabled.
|
||||
minetest.register_on_joinplayer(add_HP_gauge)
|
||||
end
|
BIN
mods/gauges/textures/breath_0.png
Normal file
After Width: | Height: | Size: 131 B |
BIN
mods/gauges/textures/breath_1.png
Normal file
After Width: | Height: | Size: 170 B |
BIN
mods/gauges/textures/breath_10.png
Normal file
After Width: | Height: | Size: 124 B |
BIN
mods/gauges/textures/breath_11.png
Normal file
After Width: | Height: | Size: 68 B |
BIN
mods/gauges/textures/breath_2.png
Normal file
After Width: | Height: | Size: 171 B |
BIN
mods/gauges/textures/breath_3.png
Normal file
After Width: | Height: | Size: 167 B |
BIN
mods/gauges/textures/breath_4.png
Normal file
After Width: | Height: | Size: 162 B |
BIN
mods/gauges/textures/breath_5.png
Normal file
After Width: | Height: | Size: 155 B |
BIN
mods/gauges/textures/breath_6.png
Normal file
After Width: | Height: | Size: 151 B |
BIN
mods/gauges/textures/breath_65535.png
Normal file
After Width: | Height: | Size: 68 B |
BIN
mods/gauges/textures/breath_7.png
Normal file
After Width: | Height: | Size: 146 B |
BIN
mods/gauges/textures/breath_8.png
Normal file
After Width: | Height: | Size: 140 B |
BIN
mods/gauges/textures/breath_9.png
Normal file
After Width: | Height: | Size: 130 B |
BIN
mods/gauges/textures/health_0.png
Normal file
After Width: | Height: | Size: 68 B |
BIN
mods/gauges/textures/health_1.png
Normal file
After Width: | Height: | Size: 100 B |
BIN
mods/gauges/textures/health_10.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_11.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_12.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_13.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_14.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_15.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_16.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_17.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_18.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_19.png
Normal file
After Width: | Height: | Size: 106 B |
BIN
mods/gauges/textures/health_2.png
Normal file
After Width: | Height: | Size: 105 B |
BIN
mods/gauges/textures/health_20.png
Normal file
After Width: | Height: | Size: 104 B |
BIN
mods/gauges/textures/health_3.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_4.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_5.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_6.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_7.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_8.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
mods/gauges/textures/health_9.png
Normal file
After Width: | Height: | Size: 108 B |
8
mods/shooter/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
## Generic ignorable patterns and files
|
||||
*~
|
||||
.*.swp
|
||||
*bak*
|
||||
tags
|
||||
*.vim
|
||||
shooter.conf
|
||||
crosshair.png
|
32
mods/shooter/LICENSE.txt
Normal file
|
@ -0,0 +1,32 @@
|
|||
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)
|
||||
|
169
mods/shooter/README.txt
Normal file
|
@ -0,0 +1,169 @@
|
|||
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 | |
|
||||
+---+---+---+
|
||||
|
293
mods/shooter/crossbow.lua
Normal file
|
@ -0,0 +1,293 @@
|
|||
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,
|
||||
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:getpos()
|
||||
acceleration = {x=0, y=0, z=0}
|
||||
end
|
||||
if pos then
|
||||
self.object:moveto(pos)
|
||||
end
|
||||
self.object:set_properties({
|
||||
physical = true,
|
||||
collisionbox = {-1/8,-1/8,-1/8, 1/8,1/8,1/8},
|
||||
})
|
||||
self.object:setvelocity({x=0, y=0, z=0})
|
||||
self.object:setacceleration(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:getpos()
|
||||
local p2 = object:getpos()
|
||||
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:getpos())
|
||||
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) 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:getpos(), offset)
|
||||
local ray = {pos=pos, dir=dir}
|
||||
local plane = {pos=opos, normal={x=-1, y=0, z=-1}}
|
||||
local ipos = shooter:get_intersect_pos(ray, plane, collisionbox)
|
||||
if ipos then
|
||||
self:strike(obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
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.setting_getbool("creative_mode") then
|
||||
itemstack:add_wear(65535/SHOOTER_CROSSBOW_USES)
|
||||
end
|
||||
itemstack = "shooter:crossbow 1 "..itemstack:get_wear()
|
||||
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: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:setyaw(yaw + math.pi)
|
||||
obj:set_animation({x=frame, y=frame}, 0)
|
||||
obj:setvelocity({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:setacceleration({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.setting_getbool("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.setting_getbool("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
|
||||
|
5
mods/shooter/depends.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
default
|
||||
dye
|
||||
tnt
|
||||
wool
|
||||
mobs?
|
147
mods/shooter/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
mods/shooter/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: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
|
||||
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
mods/shooter/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, 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.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
mods/shooter/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)
|
||||
|
26
mods/shooter/init.lua
Normal file
|
@ -0,0 +1,26 @@
|
|||
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
|
||||
|
BIN
mods/shooter/models/shooter_arrow.b3d
Normal file
BIN
mods/shooter/models/shooter_arrow.blend
Normal file
BIN
mods/shooter/models/shooter_turret.b3d
Normal file
BIN
mods/shooter/models/shooter_turret.blend
Normal file
113
mods/shooter/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, 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.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
|
||||
|
81
mods/shooter/shooter.conf.example
Normal file
|
@ -0,0 +1,81 @@
|
|||
-- 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",
|
||||
}
|
||||
|
465
mods/shooter/shooter.lua
Normal file
|
@ -0,0 +1,465 @@
|
|||
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 = 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_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_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
|
||||
|
||||
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
|
||||
def.spec.name = user:get_player_name()
|
||||
if shots > 1 then
|
||||
local step = def.spec.tool_caps.full_punch_interval
|
||||
for i = 0, step * shots, step do
|
||||
minetest.after(i, function()
|
||||
shooter:fire_weapon(user, pointed_thing, def.spec)
|
||||
end)
|
||||
end
|
||||
else
|
||||
shooter:fire_weapon(user, pointed_thing, def.spec)
|
||||
end
|
||||
itemstack:add_wear(wear)
|
||||
else
|
||||
local inv = user:get_inventory()
|
||||
if inv then
|
||||
local stack = "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: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 + 1.6, 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 + 1.75
|
||||
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=1.75, 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("tnt_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
|
||||
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
|
||||
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.registered_weapons[player:get_wielded_item():get_name()]
|
||||
if spec then
|
||||
spec = spec.spec
|
||||
shooter.shots[name] = false
|
||||
spec.name = name
|
||||
shooter:fire_weapon(player, {}, spec)
|
||||
shooting = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
BIN
mods/shooter/sounds/shooter_click.ogg
Normal file
BIN
mods/shooter/sounds/shooter_flare_burn.ogg
Normal file
BIN
mods/shooter/sounds/shooter_flare_fire.ogg
Normal file
BIN
mods/shooter/sounds/shooter_pistol.ogg
Normal file
BIN
mods/shooter/sounds/shooter_reload.ogg
Normal file
BIN
mods/shooter/sounds/shooter_rifle.ogg
Normal file
BIN
mods/shooter/sounds/shooter_rocket_fire.ogg
Normal file
BIN
mods/shooter/sounds/shooter_shotgun.ogg
Normal file
BIN
mods/shooter/sounds/shooter_throw.ogg
Normal file
BIN
mods/shooter/textures/shooter_ammo.png
Normal file
After Width: | Height: | Size: 268 B |
BIN
mods/shooter/textures/shooter_arrow_inv.png
Normal file
After Width: | Height: | Size: 234 B |
BIN
mods/shooter/textures/shooter_arrow_uv.png
Normal file
After Width: | Height: | Size: 290 B |
BIN
mods/shooter/textures/shooter_bullet.png
Normal file
After Width: | Height: | Size: 178 B |
BIN
mods/shooter/textures/shooter_cap.png
Normal file
After Width: | Height: | Size: 157 B |
BIN
mods/shooter/textures/shooter_crossbow.png
Normal file
After Width: | Height: | Size: 500 B |
BIN
mods/shooter/textures/shooter_crossbow_loaded.png
Normal file
After Width: | Height: | Size: 389 B |
BIN
mods/shooter/textures/shooter_flare.png
Normal file
After Width: | Height: | Size: 173 B |
BIN
mods/shooter/textures/shooter_flare_inv.png
Normal file
After Width: | Height: | Size: 278 B |
BIN
mods/shooter/textures/shooter_flare_light.png
Normal file
After Width: | Height: | Size: 291 B |
BIN
mods/shooter/textures/shooter_flare_particle.png
Normal file
After Width: | Height: | Size: 310 B |
BIN
mods/shooter/textures/shooter_flaregun.png
Normal file
After Width: | Height: | Size: 498 B |
BIN
mods/shooter/textures/shooter_grenade.png
Normal file
After Width: | Height: | Size: 178 B |
BIN
mods/shooter/textures/shooter_hand_grenade.png
Normal file
After Width: | Height: | Size: 381 B |
BIN
mods/shooter/textures/shooter_hit.png
Normal file
After Width: | Height: | Size: 659 B |
BIN
mods/shooter/textures/shooter_hook.png
Normal file
After Width: | Height: | Size: 567 B |
BIN
mods/shooter/textures/shooter_hook_gun.png
Normal file
After Width: | Height: | Size: 537 B |
BIN
mods/shooter/textures/shooter_hook_gun_loaded.png
Normal file
After Width: | Height: | Size: 569 B |
BIN
mods/shooter/textures/shooter_pistol.png
Normal file
After Width: | Height: | Size: 274 B |
BIN
mods/shooter/textures/shooter_rifle.png
Normal file
After Width: | Height: | Size: 420 B |
BIN
mods/shooter/textures/shooter_rocket_gun.png
Normal file
After Width: | Height: | Size: 690 B |
BIN
mods/shooter/textures/shooter_rocket_gun_loaded.png
Normal file
After Width: | Height: | Size: 679 B |
BIN
mods/shooter/textures/shooter_rocket_inv.png
Normal file
After Width: | Height: | Size: 376 B |
BIN
mods/shooter/textures/shooter_shotgun.png
Normal file
After Width: | Height: | Size: 402 B |
BIN
mods/shooter/textures/shooter_smgun.png
Normal file
After Width: | Height: | Size: 289 B |
BIN
mods/shooter/textures/shooter_turret_base.png
Normal file
After Width: | Height: | Size: 178 B |
BIN
mods/shooter/textures/shooter_turret_gun.png
Normal file
After Width: | Height: | Size: 354 B |
BIN
mods/shooter/textures/shooter_turret_uv.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
276
mods/shooter/turret.lua
Normal file
|
@ -0,0 +1,276 @@
|
|||
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 == 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
|
||||
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
|
||||
|
112
mods/throwing/README.txt
Normal file
|
@ -0,0 +1,112 @@
|
|||
=== THROWING ENHANCED for MINETEST ===
|
||||
|
||||
Inroduction:
|
||||
This mod adds many bows and arrows to Minetest.
|
||||
It began as a fork of PilzAdam's throwing mod with some enhancements from me. Enjoy!
|
||||
Echoes91
|
||||
|
||||
How to install:
|
||||
http://wiki.minetest.com/wiki/Installing_Mods
|
||||
|
||||
How to use the mod:
|
||||
Select a bow and place the arrows into the slot next to it; shoot with left mouse click.
|
||||
Every shoot will take 1 arrow from your inventory and wears out the bow.
|
||||
Select a spear and attack with left mouse click; it will be used as a melee weapon if pointing any target, otherwise it will be thrown.
|
||||
|
||||
License:
|
||||
This mod was originally published by Jeija and reworked by PilzAdam
|
||||
Sourcecode: LGPLv2.1 (see http://www.gnu.org/licenses/lgpl-2.1.html)
|
||||
Grahpics & sounds: CC-BY 3.0 (see http://creativecommons.org/licenses/by/3.0/legalcode)
|
||||
|
||||
|
||||
Changelog:
|
||||
|
||||
Update 1.4.1:
|
||||
- Fixed spears not retaining wear
|
||||
- Improved textures
|
||||
- Torch arrows have light trail
|
||||
|
||||
Update 1.4:
|
||||
- Added spears, capable of melee and ranged attacks
|
||||
- Improved arrows textures
|
||||
|
||||
Update 1.3:
|
||||
- Added automated arbalest, the ultimate weapon
|
||||
- New arbalest texture coherent with steel color
|
||||
|
||||
Update 1.2:
|
||||
- Added arbalest
|
||||
- Defaults initialized
|
||||
|
||||
Update 1.1:
|
||||
- Added crossbow
|
||||
- Code shrink
|
||||
- Offensive arrows go through flora's and farming's
|
||||
- Small fixes
|
||||
|
||||
Update 1.0:
|
||||
- Definitive reload, unload and shot system based on tool metadata, new global functions, no more "throw" privilege
|
||||
- New textures for loaded bows
|
||||
- Fireworks arrows to celebrate!
|
||||
|
||||
Update 1.0rc2:
|
||||
- Fixed "compare nil with number" due to self.break not being retained
|
||||
- Filled conf.example's list
|
||||
- Added Royal bow
|
||||
|
||||
Update 1.0rc1:
|
||||
- Added longbow and removed golden bow, definitive bow set for stable release. Feature freeze
|
||||
- Fixed torch arrow recipe, thanks to Excalibur Zero
|
||||
- Removed config.lua, configuration now goes int throwing.config, see example
|
||||
|
||||
Update 0.9.8:
|
||||
- New damage calculation for offensive arrows based on arrow's speed and material. Beware that dependency is more than linear for both, so that differences between arrows will be enhanced if they're shot at higher speed.
|
||||
- Fixed bug that blocked ability to shot after shooting with empty arrow stack.
|
||||
- Removed annoying debug symbols
|
||||
|
||||
Update 0.9.7:
|
||||
- Added visual feedback for reload
|
||||
- Fixed reload for players who die while reloading and for multiplayer
|
||||
- Changed license for the code to LGPLv2
|
||||
|
||||
Update 0.9.6:
|
||||
- Any bow and arrow is now deactivable under config.lua, which won't be overwritten
|
||||
- Changed license for media to CC-BY
|
||||
|
||||
Update 0.9.5:
|
||||
- Added shell arrows
|
||||
- Revised sounds and some textures
|
||||
- General balancing of bow's statistics
|
||||
|
||||
Update 0.9.4:
|
||||
- New bow texture
|
||||
- Made recipes coherent
|
||||
|
||||
Update 0.9.3:
|
||||
- Added symmetric recipes, fixed golden bow recipe
|
||||
- Adjusted few parameters
|
||||
|
||||
Update 0.9.2:
|
||||
- Added a chance to break for many arrows, so they don't last forever and outclass any other tool
|
||||
- Build and torch arrows won't build on fluids and torches any more, build arrows won't place torches
|
||||
- TNT arrow digs instead if removing blocks, eventual indestructible nodes are safe
|
||||
- Added golden bow with possible new bow style
|
||||
- Changed the (bit OP) composite bow resistance and new recipe
|
||||
- New teleport arrow recipe, cheaper but single use
|
||||
|
||||
Update 0.9.1:
|
||||
- Good improvement for torch arrows, now they always attach and are often turned to the right direction
|
||||
- Git repository will make things nicer
|
||||
|
||||
Update 0.9:
|
||||
- Now bows have reload times! They depend on weight and quality, anyway no more machine-gun-style shell swarms
|
||||
- Fixed build arrow behavior, now it placed and consumes the node from the slot [b]right next to the arrow[/b] or drops the item beside it if not a node; no more disappearing nor 'CONTENT_IGNORE' errors
|
||||
- Code cleanup and rationalization
|
||||
|
||||
Update 0.8.1:
|
||||
- Fixed wrong texture reference which made some arrows get a bad color during flight.
|
||||
- Now bows have different stiffness besides wear resistances, which means that they shot arrows at different initial speed and learning to hit the target will become even harder.
|
||||
Get rid of the old .env: API
|
||||
Added new bows and new offensive, utility and harmful arrows (these are just my categories, they're not present into the code at all).
|
||||
Removed stone bow, at least as long as somebody discovers an elastic rock ;)
|
||||
Non-exploding arrows won't disappear any more after hitting target.
|
107
mods/throwing/build_arrow.lua
Normal file
|
@ -0,0 +1,107 @@
|
|||
minetest.register_craftitem("throwing:arrow_build", {
|
||||
description = "Build Arrow",
|
||||
inventory_image = "throwing_arrow_build.png",
|
||||
})
|
||||
|
||||
minetest.register_node("throwing:arrow_build_box", {
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
-- Shaft
|
||||
{-6.5/17, -1.5/17, -1.5/17, 6.5/17, 1.5/17, 1.5/17},
|
||||
--Spitze
|
||||
{-4.5/17, 2.5/17, 2.5/17, -3.5/17, -2.5/17, -2.5/17},
|
||||
{-8.5/17, 0.5/17, 0.5/17, -6.5/17, -0.5/17, -0.5/17},
|
||||
--Federn
|
||||
{6.5/17, 1.5/17, 1.5/17, 7.5/17, 2.5/17, 2.5/17},
|
||||
{7.5/17, -2.5/17, 2.5/17, 6.5/17, -1.5/17, 1.5/17},
|
||||
{7.5/17, 2.5/17, -2.5/17, 6.5/17, 1.5/17, -1.5/17},
|
||||
{6.5/17, -1.5/17, -1.5/17, 7.5/17, -2.5/17, -2.5/17},
|
||||
|
||||
{7.5/17, 2.5/17, 2.5/17, 8.5/17, 3.5/17, 3.5/17},
|
||||
{8.5/17, -3.5/17, 3.5/17, 7.5/17, -2.5/17, 2.5/17},
|
||||
{8.5/17, 3.5/17, -3.5/17, 7.5/17, 2.5/17, -2.5/17},
|
||||
{7.5/17, -2.5/17, -2.5/17, 8.5/17, -3.5/17, -3.5/17},
|
||||
}
|
||||
},
|
||||
tiles = {"throwing_arrow_build.png", "throwing_arrow_build.png", "throwing_arrow_build_back.png", "throwing_arrow_build_front.png", "throwing_arrow_build_2.png", "throwing_arrow_build.png"},
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
local THROWING_ARROW_ENTITY={
|
||||
physical = false,
|
||||
timer=0,
|
||||
visual = "wielditem",
|
||||
visual_size = {x=0.1, y=0.1},
|
||||
textures = {"throwing:arrow_build_box"},
|
||||
lastpos={},
|
||||
collisionbox = {0,0,0,0,0,0},
|
||||
node = "",
|
||||
}
|
||||
|
||||
THROWING_ARROW_ENTITY.on_step = function(self, dtime)
|
||||
self.timer=self.timer+dtime
|
||||
local pos = self.object:getpos()
|
||||
local node = minetest.get_node(pos)
|
||||
if not self.inventory or not self.stack then
|
||||
self.object:remove()
|
||||
end
|
||||
|
||||
if self.timer>0.2 then
|
||||
local objs = minetest.get_objects_inside_radius({x=pos.x,y=pos.y,z=pos.z}, 1)
|
||||
for k, obj in pairs(objs) do
|
||||
if obj:get_luaentity() ~= nil then
|
||||
if obj:get_luaentity().name ~= "throwing:arrow_build_entity" and obj:get_luaentity().name ~= "__builtin:item" then
|
||||
self.object:remove()
|
||||
if self.inventory and self.stack and not minetest.setting_getbool("creative_mode") then
|
||||
self.inventory:remove_item("main", {name=self.stack:get_name()})
|
||||
end
|
||||
if self.stack then
|
||||
minetest.add_item(self.lastpos, {name=self.stack:get_name()})
|
||||
end
|
||||
local toughness = 0.95
|
||||
if math.random() < toughness then
|
||||
minetest.add_item(self.lastpos, 'throwing:arrow_build')
|
||||
else
|
||||
minetest.add_item(self.lastpos, 'default:stick')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.lastpos.x~=nil then
|
||||
if node.name ~= "air" then
|
||||
self.object:remove()
|
||||
if self.inventory and self.stack and not minetest.setting_getbool("creative_mode") then
|
||||
self.inventory:remove_item("main", {name=self.stack:get_name()})
|
||||
end
|
||||
if self.stack then
|
||||
if not string.find(node.name, "water") and not string.find(node.name, "lava") and not string.find(node.name, "torch") and self.stack:get_definition().type == "node" and self.stack:get_name() ~= "default:torch" then
|
||||
minetest.place_node(self.lastpos, {name=self.stack:get_name()})
|
||||
else
|
||||
minetest.add_item(self.lastpos, {name=self.stack:get_name()})
|
||||
end
|
||||
end
|
||||
minetest.add_item(self.lastpos, 'default:shovel_steel')
|
||||
end
|
||||
end
|
||||
self.lastpos={x=pos.x, y=pos.y, z=pos.z}
|
||||
end
|
||||
|
||||
minetest.register_entity("throwing:arrow_build_entity", THROWING_ARROW_ENTITY)
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'throwing:arrow_build',
|
||||
recipe = {
|
||||
{'default:stick', 'default:stick', 'default:shovel_steel'},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'throwing:arrow_build',
|
||||
recipe = {
|
||||
{'default:shovel_steel', 'default:stick', 'default:stick'},
|
||||
}
|
||||
})
|
24
mods/throwing/defaults.lua
Normal file
|
@ -0,0 +1,24 @@
|
|||
DISABLE_WOODEN_BOW = false
|
||||
DISABLE_LONGBOW = false
|
||||
DISABLE_COMPOSITE_BOW = false
|
||||
DISABLE_STEEL_BOW = false
|
||||
DISABLE_ROYAL_BOW = false
|
||||
DISABLE_CROSSBOW = false
|
||||
DISABLE_ARBALEST = false
|
||||
DISABLE_AUTOMATED_ARBALEST = false
|
||||
|
||||
DISABLE_TELEPORT_ARROW = true
|
||||
DISABLE_DIG_ARROW = true
|
||||
DISABLE_BUILD_ARROW = true
|
||||
DISABLE_TNT_ARROW = true
|
||||
DISABLE_FIRE_ARROW = true
|
||||
DISABLE_TORCH_ARROW = false
|
||||
DISABLE_SHELL_ARROW = false
|
||||
|
||||
DISABLE_FIREWORKS_BLUE_ARROW = false
|
||||
DISABLE_FIREWORKS_RED_ARROW = false
|
||||
|
||||
DISABLE_STONE_ARROW = false
|
||||
DISABLE_STEEL_ARROW = false
|
||||
DISABLE_DIAMOND_ARROW = false
|
||||
DISABLE_OBSIDIAN_ARROW = false
|
6
mods/throwing/depends.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
default
|
||||
farming?
|
||||
dye?
|
||||
bucket?
|
||||
fire?
|
||||
tnt?
|
1
mods/throwing/description.txt
Normal file
|
@ -0,0 +1 @@
|
|||
This mod adds many bows and arrows to Minetest.
|
100
mods/throwing/dig_arrow.lua
Normal file
|
@ -0,0 +1,100 @@
|
|||
minetest.register_craftitem("throwing:arrow_dig", {
|
||||
description = "Dig Arrow",
|
||||
inventory_image = "throwing_arrow_dig.png",
|
||||
})
|
||||
|
||||
minetest.register_node("throwing:arrow_dig_box", {
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
-- Shaft
|
||||
{-6.5/17, -1.5/17, -1.5/17, 6.5/17, 1.5/17, 1.5/17},
|
||||
--Spitze
|
||||
{-4.5/17, 2.5/17, 2.5/17, -3.5/17, -2.5/17, -2.5/17},
|
||||
{-8.5/17, 0.5/17, 0.5/17, -6.5/17, -0.5/17, -0.5/17},
|
||||
--Federn
|
||||
{6.5/17, 1.5/17, 1.5/17, 7.5/17, 2.5/17, 2.5/17},
|
||||
{7.5/17, -2.5/17, 2.5/17, 6.5/17, -1.5/17, 1.5/17},
|
||||
{7.5/17, 2.5/17, -2.5/17, 6.5/17, 1.5/17, -1.5/17},
|
||||
{6.5/17, -1.5/17, -1.5/17, 7.5/17, -2.5/17, -2.5/17},
|
||||
|
||||
{7.5/17, 2.5/17, 2.5/17, 8.5/17, 3.5/17, 3.5/17},
|
||||
{8.5/17, -3.5/17, 3.5/17, 7.5/17, -2.5/17, 2.5/17},
|
||||
{8.5/17, 3.5/17, -3.5/17, 7.5/17, 2.5/17, -2.5/17},
|
||||
{7.5/17, -2.5/17, -2.5/17, 8.5/17, -3.5/17, -3.5/17},
|
||||
}
|
||||
},
|
||||
tiles = {"throwing_arrow_dig.png", "throwing_arrow_dig.png", "throwing_arrow_dig_back.png", "throwing_arrow_dig_front.png", "throwing_arrow_dig_2.png", "throwing_arrow_dig.png"},
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
local THROWING_ARROW_ENTITY={
|
||||
physical = false,
|
||||
timer=0,
|
||||
visual = "wielditem",
|
||||
visual_size = {x=0.1, y=0.1},
|
||||
textures = {"throwing:arrow_dig_box"},
|
||||
lastpos={},
|
||||
collisionbox = {0,0,0,0,0,0},
|
||||
}
|
||||
|
||||
THROWING_ARROW_ENTITY.on_step = function(self, dtime)
|
||||
self.timer=self.timer+dtime
|
||||
local pos = self.object:getpos()
|
||||
local node = minetest.get_node(pos)
|
||||
|
||||
if self.timer>0.2 then
|
||||
local objs = minetest.get_objects_inside_radius({x=pos.x,y=pos.y,z=pos.z}, 1)
|
||||
for k, obj in pairs(objs) do
|
||||
if obj:get_luaentity() ~= nil then
|
||||
if obj:get_luaentity().name ~= "throwing:arrow_dig_entity" and obj:get_luaentity().name ~= "__builtin:item" then
|
||||
local damage = 1.5
|
||||
obj:punch(self.object, 1.0, {
|
||||
full_punch_interval=1.0,
|
||||
damage_groups={fleshy=damage},
|
||||
}, nil)
|
||||
self.object:remove()
|
||||
local toughness = 0.9
|
||||
if math.random() < toughness then
|
||||
minetest.add_item(self.lastpos, 'throwing:arrow_dig')
|
||||
else
|
||||
minetest.add_item(self.lastpos, 'default:stick')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.lastpos.x~=nil then
|
||||
if node.name ~= "air" then
|
||||
self.object:remove()
|
||||
if node.diggable ~= false then
|
||||
minetest.dig_node(pos)
|
||||
end
|
||||
local toughness = 0.65
|
||||
if math.random() < toughness then
|
||||
minetest.add_item(self.lastpos, 'default:pick_steel')
|
||||
else
|
||||
minetest.add_item(self.lastpos, 'default:stick')
|
||||
end
|
||||
end
|
||||
end
|
||||
self.lastpos={x=pos.x, y=pos.y, z=pos.z}
|
||||
end
|
||||
|
||||
minetest.register_entity("throwing:arrow_dig_entity", THROWING_ARROW_ENTITY)
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'throwing:arrow_dig',
|
||||
recipe = {
|
||||
{'default:stick', 'default:stick', 'default:pick_steel'},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'throwing:arrow_dig',
|
||||
recipe = {
|
||||
{'default:pick_steel', 'default:stick', 'default:stick'},
|
||||
}
|
||||
})
|
125
mods/throwing/fire_arrow.lua
Normal file
|
@ -0,0 +1,125 @@
|
|||
minetest.register_craftitem("throwing:arrow_fire", {
|
||||
description = "Fire Arrow",
|
||||
inventory_image = "throwing_arrow_fire.png",
|
||||
})
|
||||
|
||||
minetest.register_node("throwing:arrow_fire_box", {
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
-- Shaft
|
||||
{-6.5/17, -1.5/17, -1.5/17, 6.5/17, 1.5/17, 1.5/17},
|
||||
--Spitze
|
||||
{-4.5/17, 2.5/17, 2.5/17, -3.5/17, -2.5/17, -2.5/17},
|
||||
{-8.5/17, 0.5/17, 0.5/17, -6.5/17, -0.5/17, -0.5/17},
|
||||
--Federn
|
||||
{6.5/17, 1.5/17, 1.5/17, 7.5/17, 2.5/17, 2.5/17},
|
||||
{7.5/17, -2.5/17, 2.5/17, 6.5/17, -1.5/17, 1.5/17},
|
||||
{7.5/17, 2.5/17, -2.5/17, 6.5/17, 1.5/17, -1.5/17},
|
||||
{6.5/17, -1.5/17, -1.5/17, 7.5/17, -2.5/17, -2.5/17},
|
||||
|
||||
{7.5/17, 2.5/17, 2.5/17, 8.5/17, 3.5/17, 3.5/17},
|
||||
{8.5/17, -3.5/17, 3.5/17, 7.5/17, -2.5/17, 2.5/17},
|
||||
{8.5/17, 3.5/17, -3.5/17, 7.5/17, 2.5/17, -2.5/17},
|
||||
{7.5/17, -2.5/17, -2.5/17, 8.5/17, -3.5/17, -3.5/17},
|
||||
}
|
||||
},
|
||||
tiles = {"throwing_arrow_fire.png", "throwing_arrow_fire.png", "throwing_arrow_fire_back.png", "throwing_arrow_fire_front.png", "throwing_arrow_fire_2.png", "throwing_arrow_fire.png"},
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
local THROWING_ARROW_ENTITY={
|
||||
physical = false,
|
||||
timer=0,
|
||||
visual = "wielditem",
|
||||
visual_size = {x=0.1, y=0.1},
|
||||
textures = {"throwing:arrow_fire_box"},
|
||||
lastpos={},
|
||||
collisionbox = {0,0,0,0,0,0},
|
||||
}
|
||||
|
||||
THROWING_ARROW_ENTITY.on_step = function(self, dtime)
|
||||
self.timer=self.timer+dtime
|
||||
local pos = self.object:getpos()
|
||||
local node = minetest.get_node(pos)
|
||||
|
||||
if self.timer>0.2 then
|
||||
local objs = minetest.get_objects_inside_radius({x=pos.x,y=pos.y,z=pos.z}, 2)
|
||||
for k, obj in pairs(objs) do
|
||||
if obj:get_luaentity() ~= nil then
|
||||
if obj:get_luaentity().name ~= "throwing:arrow_fire_entity" and obj:get_luaentity().name ~= "__builtin:item" then
|
||||
local damage = 4
|
||||
obj:punch(self.object, 1.0, {
|
||||
full_punch_interval=1.0,
|
||||
damage_groups={fleshy=damage},
|
||||
}, nil)
|
||||
self.object:remove()
|
||||
minetest.add_item(self.lastpos, 'default:stick')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.lastpos.x~=nil then
|
||||
if node.name ~= "air" and node.name ~= "throwing:light" then
|
||||
minetest.set_node(self.lastpos, {name="fire:basic_flame"})
|
||||
self.object:remove()
|
||||
end
|
||||
if math.floor(self.lastpos.x+0.5) ~= math.floor(pos.x+0.5) or math.floor(self.lastpos.y+0.5) ~= math.floor(pos.y+0.5) or math.floor(self.lastpos.z+0.5) ~= math.floor(pos.z+0.5) then
|
||||
if minetest.get_node(self.lastpos).name == "throwing:light" then
|
||||
minetest.remove_node(self.lastpos)
|
||||
end
|
||||
if minetest.get_node(pos).name == "air" then
|
||||
minetest.set_node(pos, {name="throwing:light"})
|
||||
end
|
||||
end
|
||||
end
|
||||
self.lastpos={x=pos.x, y=pos.y, z=pos.z}
|
||||
end
|
||||
|
||||
minetest.register_entity("throwing:arrow_fire_entity", THROWING_ARROW_ENTITY)
|
||||
|
||||
minetest.register_node("throwing:light", {
|
||||
drawtype = "airlike",
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
tiles = {"throwing_empty.png"},
|
||||
light_source = LIGHT_MAX-4,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{0,0,0,0,0,0}
|
||||
}
|
||||
},
|
||||
groups = {not_in_creative_inventory=1}
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"throwing:light"},
|
||||
interval = 10,
|
||||
chance = 1,
|
||||
action = function(pos, node)
|
||||
minetest.remove_node(pos)
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'throwing:arrow_fire 4',
|
||||
recipe = {
|
||||
{'default:stick', 'default:stick', 'bucket:bucket_lava'},
|
||||
},
|
||||
replacements = {
|
||||
{"bucket:bucket_lava", "bucket:bucket_empty"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'throwing:arrow_fire 4',
|
||||
recipe = {
|
||||
{'bucket:bucket_lava', 'default:stick', 'default:stick'},
|
||||
},
|
||||
replacements = {
|
||||
{"bucket:bucket_lava", "bucket:bucket_empty"}
|
||||
}
|
||||
})
|
195
mods/throwing/fireworks_arrows.lua
Normal file
|
@ -0,0 +1,195 @@
|
|||
local function throwing_register_fireworks(color, desc)
|
||||
minetest.register_craftitem("throwing:arrow_fireworks_" .. color, {
|
||||
description = desc .. "fireworks arrow",
|
||||
inventory_image = "throwing_arrow_fireworks_" .. color .. ".png",
|
||||
})
|
||||
|
||||
minetest.register_node("throwing:arrow_fireworks_" .. color .. "_box", {
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
-- Shaft
|
||||
{-6.5/17, -1.5/17, -1.5/17, 6.5/17, 1.5/17, 1.5/17},
|
||||
--Spitze
|
||||
{-4.5/17, 2.5/17, 2.5/17, -3.5/17, -2.5/17, -2.5/17},
|
||||
{-8.5/17, 0.5/17, 0.5/17, -6.5/17, -0.5/17, -0.5/17},
|
||||
--Federn
|
||||
{6.5/17, 1.5/17, 1.5/17, 7.5/17, 2.5/17, 2.5/17},
|
||||
{7.5/17, -2.5/17, 2.5/17, 6.5/17, -1.5/17, 1.5/17},
|
||||
{7.5/17, 2.5/17, -2.5/17, 6.5/17, 1.5/17, -1.5/17},
|
||||
{6.5/17, -1.5/17, -1.5/17, 7.5/17, -2.5/17, -2.5/17},
|
||||
|
||||
{7.5/17, 2.5/17, 2.5/17, 8.5/17, 3.5/17, 3.5/17},
|
||||
{8.5/17, -3.5/17, 3.5/17, 7.5/17, -2.5/17, 2.5/17},
|
||||
{8.5/17, 3.5/17, -3.5/17, 7.5/17, 2.5/17, -2.5/17},
|
||||
{7.5/17, -2.5/17, -2.5/17, 8.5/17, -3.5/17, -3.5/17},
|
||||
}
|
||||
},
|
||||
tiles = {"throwing_arrow_fireworks_" .. color .. ".png", "throwing_arrow_fireworks_" .. color .. ".png", "throwing_arrow_fireworks_" .. color .. "_back.png", "throwing_arrow_fireworks_" .. color .. "_front.png", "throwing_arrow_fireworks_" .. color .. "_2.png", "throwing_arrow_fireworks_" .. color .. ".png"},
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
local THROWING_ARROW_ENTITY={
|
||||
physical = false,
|
||||
timer=0,
|
||||
visual = "wielditem",
|
||||
visual_size = {x=0.1, y=0.1},
|
||||
textures = {"throwing:arrow_fireworks_" .. color .. "_box"},
|
||||
lastpos={},
|
||||
collisionbox = {0,0,0,0,0,0},
|
||||
}
|
||||
|
||||
local radius = 0.5
|
||||
|
||||
local function add_effects(pos, radius)
|
||||
minetest.add_particlespawner({
|
||||
amount = 256,
|
||||
time = 0.2,
|
||||
minpos = vector.subtract(pos, radius / 2),
|
||||
maxpos = vector.add(pos, radius / 2),
|
||||
minvel = {x=-5, y=-5, z=-5},
|
||||
maxvel = {x=5, y=5, z=5},
|
||||
minacc = {x=0, y=-8, z=0},
|
||||
--~ maxacc = {x=-20, y=-50, z=-50},
|
||||
minexptime = 2.5,
|
||||
maxexptime = 3,
|
||||
minsize = 1,
|
||||
maxsize = 2.5,
|
||||
texture = "throwing_sparkle_" .. color .. ".png",
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
local function boom(pos)
|
||||
minetest.sound_play("throwing_firework_boom", {pos=pos, gain=1, max_hear_distance=2*64})
|
||||
if minetest.get_node(pos).name == 'air' or minetest.get_node(pos).name == 'throwing:firework_trail' then
|
||||
minetest.add_node(pos, {name="throwing:firework_boom"})
|
||||
minetest.get_node_timer(pos):start(0.2)
|
||||
end
|
||||
add_effects(pos, radius)
|
||||
end
|
||||
|
||||
-- Back to the arrow
|
||||
|
||||
THROWING_ARROW_ENTITY.on_step = function(self, dtime)
|
||||
self.timer=self.timer+dtime
|
||||
local pos = self.object:getpos()
|
||||
local node = minetest.get_node(pos)
|
||||
if self.timer < 0.07 then
|
||||
minetest.sound_play("throwing_firework_launch", {pos=pos, gain=0.8, max_hear_distance=2*64})
|
||||
end
|
||||
minetest.add_particlespawner({
|
||||
amount = 16,
|
||||
time = 0.1,
|
||||
minpos = pos,
|
||||
maxpos = pos,
|
||||
minvel = {x=-5, y=-5, z=-5},
|
||||
maxvel = {x=5, y=5, z=5},
|
||||
minacc = vector.new(),
|
||||
maxacc = vector.new(),
|
||||
minexptime = 0.3,
|
||||
maxexptime = 0.5,
|
||||
minsize = 0.5,
|
||||
maxsize = 1,
|
||||
texture = "throwing_sparkle.png",
|
||||
})
|
||||
if self.timer>0.2 then
|
||||
local objs = minetest.get_objects_inside_radius({x=pos.x,y=pos.y,z=pos.z}, 2)
|
||||
for k, obj in pairs(objs) do
|
||||
if obj:get_luaentity() ~= nil then
|
||||
if obj:get_luaentity().name ~= "throwing:arrow_fireworks_" .. color .. "_entity" and obj:get_luaentity().name ~= "__builtin:item" then
|
||||
local damage = 2
|
||||
obj:punch(self.object, 1.0, {
|
||||
full_punch_interval=1.0,
|
||||
damage_groups={fleshy=damage},
|
||||
}, nil)
|
||||
self.object:remove()
|
||||
boom(pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.timer > 2 then
|
||||
self.object:remove()
|
||||
boom(self.lastpos)
|
||||
end
|
||||
if self.lastpos.x~=nil then
|
||||
if node.name ~= "air" and node.name ~= "throwing:firework_trail" then
|
||||
self.object:remove()
|
||||
boom(self.lastpos)
|
||||
end
|
||||
end
|
||||
if node.name == 'air' then
|
||||
minetest.add_node(pos, {name="throwing:firework_trail"})
|
||||
minetest.get_node_timer(pos):start(0.1)
|
||||
end
|
||||
self.lastpos={x=pos.x, y=pos.y, z=pos.z}
|
||||
end
|
||||
|
||||
minetest.register_entity("throwing:arrow_fireworks_" .. color .. "_entity", THROWING_ARROW_ENTITY)
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'throwing:arrow_fireworks_' .. color .. ' 8',
|
||||
recipe = {
|
||||
{'default:stick', 'tnt:gunpowder', 'dye:' .. color},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'throwing:arrow_fireworks_' .. color .. ' 8',
|
||||
recipe = {
|
||||
{'dye:' .. color, 'tnt:gunpowder', 'default:stick'},
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
--~ Arrows
|
||||
|
||||
if not DISABLE_FIREWORKS_BLUE_ARROW then
|
||||
throwing_register_fireworks('blue', 'Blue')
|
||||
end
|
||||
|
||||
if not DISABLE_FIREWORKS_RED_ARROW then
|
||||
throwing_register_fireworks('red', 'Red')
|
||||
end
|
||||
|
||||
--~ Nodes
|
||||
|
||||
minetest.register_node("throwing:firework_trail", {
|
||||
drawtype = "airlike",
|
||||
light_source = 9,
|
||||
walkable = false,
|
||||
drop = "",
|
||||
groups = {dig_immediate=3},
|
||||
on_timer = function(pos, elapsed)
|
||||
minetest.remove_node(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_node("throwing:firework_boom", {
|
||||
drawtype = "plantlike",
|
||||
tiles = {"throwing_sparkle.png"},
|
||||
light_source = default.LIGHT_MAX,
|
||||
walkable = false,
|
||||
drop = "",
|
||||
groups = {dig_immediate=3},
|
||||
on_timer = function(pos, elapsed)
|
||||
minetest.remove_node(pos)
|
||||
end,
|
||||
after_destruct = function(pos, oldnode)
|
||||
minetest.set_node(pos, {name="throwing:firework_light"})
|
||||
minetest.get_node_timer(pos):start(3)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_node("throwing:firework_light", {
|
||||
drawtype = "airlike",
|
||||
light_source = default.LIGHT_MAX,
|
||||
walkable = false,
|
||||
drop = "",
|
||||
groups = {dig_immediate=3},
|
||||
on_timer = function(pos, elapsed)
|
||||
minetest.remove_node(pos)
|
||||
end,
|
||||
})
|