From cff296d70b5941ccf9edc80d19c56e0e9d64a2df Mon Sep 17 00:00:00 2001 From: stujones11 Date: Fri, 15 Mar 2019 17:55:37 +0000 Subject: [PATCH] Crossbow improvements Update turret mod Fix undeclared global in blast function Update rockets and grenades Update grapple hook and flares Unlink model textures --- shooter/api.lua | 47 +++++-- shooter_crossbow/init.lua | 152 +++++++++++----------- shooter_crossbow/models/shooter_arrow.b3d | Bin 21158 -> 21101 bytes shooter_flaregun/init.lua | 52 ++++---- shooter_grenade/init.lua | 30 +++-- shooter_hook/init.lua | 29 +++-- shooter_rocket/init.lua | 29 +++-- shooter_turret/depends.txt | 3 +- shooter_turret/init.lua | 130 +++++++++--------- shooter_turret/models/shooter_turret.b3d | Bin 84912 -> 84854 bytes 10 files changed, 252 insertions(+), 220 deletions(-) diff --git a/shooter/api.lua b/shooter/api.lua index 512fb30..0ae0e77 100644 --- a/shooter/api.lua +++ b/shooter/api.lua @@ -80,12 +80,22 @@ function shooter:spawn_particles(pos, texture) texture = config.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 - ) + minetest.add_particlespawner({ + amount = 15, + time = 0.3, + minpos = vector.subtract(pos, spread), + maxpos = vector.add(pos, spread), + minvel = {x=-1, y=1, z=-1}, + maxvel = {x=1, y=2, z=1}, + minacc = {x=-2, y=-2, z=-2}, + maxacc = {x=2, y=-2, z=2}, + minexptime = 0.1, + maxexptime = 0.75, + minsize = 1, + maxsize = 2, + collisiondetection = false, + texture = texture, + }) end end @@ -261,21 +271,32 @@ function shooter:blast(pos, radius, fleshy, distance, user) end end if config.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" - ) + minetest.add_particlespawner({ + amount = 50, + time = 0.1, + minpos = p1, + maxpos = p2, + minvel = {x=0, y=0, z=0}, + maxvel = {x=0, y=0, z=0}, + minacc = {x=-0.5, y=5, z=-0.5}, + maxacc = {x=0.5, y=5, z=0.5}, + minexptime = 0.1, + maxexptime = 1, + minsize = 8, + maxsize = 15, + collisiondetection = false, + texture = "tnt_smoke.png", + }) end local objects = minetest.get_objects_inside_radius(pos, distance) for _,obj in ipairs(objects) do if shooter:is_valid_object(obj) then - local obj_pos = obj:getpos() + local obj_pos = obj:get_pos() 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 - blast_pos = {x=pos.x, y=pos.y + 4, z=pos.z} + local blast_pos = {x=pos.x, y=pos.y + 4, z=pos.z} if minetest.line_of_sight(obj_pos, blast_pos, 1) then obj:punch(user, 1.0, { full_punch_interval = 1.0, diff --git a/shooter_crossbow/init.lua b/shooter_crossbow/init.lua index 460e783..a6beb1c 100644 --- a/shooter_crossbow/init.lua +++ b/shooter_crossbow/init.lua @@ -1,6 +1,7 @@ local config = { crossbow_uses = 50, arrow_lifetime = 180, + arrow_object_attach = false, } -- Legacy Config Support @@ -21,12 +22,14 @@ if minetest.global_exists("SHOOTER_ARROW_TOOL_CAPS") then arrow_tool_caps = table.copy(SHOOTER_ARROW_TOOL_CAPS) end -minetest.register_alias("shooter_crossbow:arrow", "shooter_crossbow: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"} +-- name is the overlay texture name, colour is used to select the wool texture +local function get_texture(name, colour) + return "wool_"..colour..".png^shooter_"..name..".png^[makealpha:255,126,126" +end + local function get_animation_frame(dir) local angle = math.atan(dir.y) local frame = 90 - math.floor(angle * 360 / math.pi) @@ -38,15 +41,55 @@ local function get_animation_frame(dir) 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) +local function get_pointed_thing(pos, dir, dist) + local p1 = vector.add(pos, dir) + local p2 = vector.add(pos, vector.multiply(dir, dist)) + local ray = minetest.raycast(p1, p2, true, true) + return ray:next() end --- name is the overlay texture name, colour is used to select the wool texture -local function get_texture(name, colour) - return "wool_"..colour..".png^shooter_"..name..".png^[makealpha:255,126,126" +local function strike(arrow, pointed_thing, name) + local puncher = minetest.get_player_by_name(name) + if not puncher then + return + end + local object = arrow.object + local hit_pos = pointed_thing.intersection_point or object:get_pos() + local dir = vector.normalize(object:get_velocity()) + if pointed_thing.type == "object" then + local target = pointed_thing.ref + if shooter:is_valid_object(target) then + local puncher = minetest.get_player_by_name(name) + if puncher and puncher ~= target then + local groups = target:get_armor_groups() or {} + if groups.fleshy then + shooter:spawn_particles(hit_pos, + shooter.config.explosion_texture) + end + target:punch(object, nil, arrow_tool_caps, dir) + if config.arrow_object_attach then + local pos = vector.multiply(vector.subtract(target:get_pos(), + hit_pos), -10) + local rot = vector.new() + rot.y = (target:get_yaw() - object:get_yaw()) * 57.2958 + object:set_attach(target, "", pos, rot) + arrow.state = "stuck" + else + arrow.state = "dropped" + end + end + end + elseif pointed_thing.type == "node" then + local pos = minetest.get_pointed_thing_position(pointed_thing, false) + local node = minetest.get_node(pos) + hit_pos = vector.subtract(hit_pos, vector.multiply(dir, 0.25)) + arrow.node_pos = pos + arrow.state = "stuck" + shooter:play_node_sound(node, pos) + else + return + end + arrow:stop(hit_pos) end minetest.register_entity("shooter_crossbow:arrow_entity", { @@ -60,14 +103,14 @@ minetest.register_entity("shooter_crossbow:arrow_entity", { color = "white", timer = 0, lifetime = config.arrow_lifetime, - player = nil, + user = 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() + pos = pos or self.object:get_pos() acceleration = {x=0, y=0, z=0} end if pos then @@ -77,22 +120,8 @@ minetest.register_entity("shooter_crossbow:arrow_entity", { 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.config.explosion_texture) - object:punch(puncher, nil, arrow_tool_caps, dir) - end - end - self:stop(object:getpos()) + self.object:set_velocity({x=0, y=0, z=0}) + self.object:set_acceleration(acceleration) end, on_activate = function(self, staticdata) self.object:set_armor_groups({immortal=1}) @@ -143,25 +172,12 @@ minetest.register_entity("shooter_crossbow:arrow_entity", { return end if self.timer > 0.2 then - local dir = vector.normalize(self.object:getvelocity()) + local dir = vector.normalize(self.object:get_velocity()) local frame = get_animation_frame(dir) - local p1 = vector.add(self.object:getpos(), dir) - local p2 = vector.add(p1, vector.multiply(dir, 4)) - local ray = minetest.raycast(p1, p2, true, true) - local pointed_thing = ray:next() or {} - if pointed_thing.type == "object" then - local obj = pointed_thing.ref - if shooter:is_valid_object(obj) then - self:strike(obj) - end - elseif pointed_thing.type == "node" then - local pos = minetest.get_pointed_thing_position(pointed_thing, false) - local node = minetest.get_node(pos) - local target_pos = get_target_pos(p1, pos, dir, 0.66) - self.node_pos = pos - self.state = "stuck" - self:stop(target_pos) - shooter:play_node_sound(node, pos) + local pos = self.object:get_pos() + local pointed_thing = get_pointed_thing(pos, dir, 5) + if pointed_thing then + strike(self, pointed_thing, self.user) end self.object:set_animation({x=frame, y=frame}, 0) self.timer = 0 @@ -184,55 +200,37 @@ for _, color in pairs(dye_basecolors) do 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/config.crossbow_uses) + itemstack:add_wear(65535 / config.crossbow_uses) end itemstack = "shooter_crossbow:crossbow 1 "..itemstack:get_wear() - local pos = user:getpos() + local pos = user:get_pos() local dir = user:get_look_dir() - local yaw = user:get_look_yaw() + local yaw = user:get_look_horizontal() if pos and dir and yaw then pos.y = pos.y + shooter.config.camera_height - pos = vector.add(pos, dir) - local obj = minetest.add_entity(pos, "shooter_crossbow:arrow_entity") + local obj = minetest.add_entity(pos, + "shooter_crossbow:arrow_entity") local ent = nil if obj then ent = obj:get_luaentity() end if ent then - ent.player = ent.player or user + ent.user = user:get_player_name() ent.state = "flight" ent.color = color obj:set_properties({ textures = {get_texture("arrow_uv", color)} }) - minetest.sound_play("shooter_throw", {object=obj}) + minetest.sound_play("shooter_throw", {object=obj}) local frame = get_animation_frame(dir) - obj:setyaw(yaw + math.pi) + obj:set_yaw(yaw - math.pi / 2) 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 + obj:set_velocity({x=dir.x * 14, y=dir.y * 14, z=dir.z * 14}) + obj:set_acceleration({x=dir.x * -3, y=-5, z=dir.z * -3}) + pointed_thing = get_pointed_thing(pos, dir, 5) + if pointed_thing then + strike(ent, pointed_thing, ent.user) end - obj:setacceleration({x=dir.x * -3, y=-5, z=dir.z * -3}) end end return itemstack diff --git a/shooter_crossbow/models/shooter_arrow.b3d b/shooter_crossbow/models/shooter_arrow.b3d index d24be3ca656d692174d010a2a8305e5b462c0683..a3de77841186a252cb62577373a1111e68a7123f 100644 GIT binary patch delta 4107 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 delta 3862 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 diff --git a/shooter_flaregun/init.lua b/shooter_flaregun/init.lua index 7cd9270..f26e4f1 100644 --- a/shooter_flaregun/init.lua +++ b/shooter_flaregun/init.lua @@ -12,7 +12,7 @@ minetest.register_node("shooter_flaregun:flare_light", { walkable = false, buildable_to = true, sunlight_propagates = true, - light_source = LIGHT_MAX, + light_source = 14, pointable = false, }) @@ -47,7 +47,7 @@ minetest.register_entity("shooter_flaregun:flare_entity", { "shooter_flare.png", "shooter_flare.png", }, - player = nil, + glow = 14, collisionbox = {-1/16,-1/16,-1/16, 1/16,1/16,1/16}, on_activate = function(self, staticdata) if staticdata == "expired" then @@ -57,29 +57,41 @@ minetest.register_entity("shooter_flaregun:flare_entity", { on_step = function(self, dtime) self.timer = self.timer + dtime if self.timer > 0.2 then - local pos = self.object:getpos() + local pos = self.object:get_pos() 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}) + self.object:set_velocity({x=0, y=-10, z=0}) + self.object:set_acceleration({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_flaregun:flare_light"}) local meta = minetest.get_meta(pos) 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 id = minetest.add_particlespawner({ + amount = 1000, + time = 30, + minpos = pos, + maxpos = pos, + minvel = {x=-1, y=1, z=-1}, + maxvel = {x=1, y=1, z=1}, + minacc = {x=2, y=-2, z=-2}, + maxacc = {x=2, y=-2, z=2}, + minexptime = 0.1, + maxexptime = 0.75, + minsize = 1, + maxsize = 8, + collisiondetection = false, + texture = "shooter_flare_particle.png", + glow = 14, + }) meta:set_int("particle_id", id) meta:set_int("init_time", os.time()) local sound = minetest.sound_play("shooter_flare_burn", { - object = self.player, + pos = pos, loop = true, + max_hear_distance = 8, }) minetest.after(30, function(sound) minetest.sound_stop(sound) @@ -106,23 +118,19 @@ minetest.register_tool("shooter_flaregun:flaregun", { end if not minetest.setting_getbool("creative_mode") then inv:remove_item("main", "shooter:flare 1") - itemstack:add_wear(65535/100) + itemstack:add_wear(65535 / 100) end - local pos = user:getpos() + local pos = user:get_pos() local dir = user:get_look_dir() - local yaw = user:get_look_yaw() + local yaw = user:get_look_horizontal() if pos and dir and yaw then pos.y = pos.y + 1.5 local obj = minetest.add_entity(pos, "shooter_flaregun: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 + obj:set_velocity(vector.multiply(dir, 16)) + obj:set_acceleration({x=dir.x * -3, y=-10, z=dir.z * -3}) + obj:set_yaw(yaw + math.pi / 2) end end return itemstack diff --git a/shooter_grenade/init.lua b/shooter_grenade/init.lua index e674be3..7d08d50 100644 --- a/shooter_grenade/init.lua +++ b/shooter_grenade/init.lua @@ -11,7 +11,7 @@ minetest.register_entity("shooter_grenade:grenade_entity", { "shooter_grenade.png", "shooter_grenade.png", }, - player = nil, + user = nil, collisionbox = {0,0,0, 0,0,0}, on_activate = function(self, staticdata) if staticdata == "expired" then @@ -21,11 +21,16 @@ minetest.register_entity("shooter_grenade:grenade_entity", { on_step = function(self, dtime) self.timer = self.timer + dtime if self.timer > 0.2 then - local pos = self.object:getpos() + local pos = self.object:get_pos() local above = {x=pos.x, y=pos.y + 1, z=pos.z} if minetest.get_node(pos).name ~= "air" then + if self.user then + local player = minetest.get_player_by_name(self.user) + if player then + shooter:blast(above, 2, 25, 5, player) + end + end self.object:remove() - shooter:blast(above, 2, 25, 5, self.player) end self.timer = 0 end @@ -40,28 +45,29 @@ minetest.register_tool("shooter_grenade:grenade", { inventory_image = "shooter_hand_grenade.png", on_use = function(itemstack, user, pointed_thing) if not minetest.setting_getbool("creative_mode") then - itemstack = "" + itemstack:clear() end if pointed_thing.type ~= "nothing" then local pointed = minetest.get_pointed_thing_position(pointed_thing) - if vector.distance(user:getpos(), pointed) < 8 then + if vector.distance(user:get_pos(), pointed) < 8 then shooter:blast(pointed, 1, 25, 5) return end end - local pos = user:getpos() + local pos = user:get_pos() local dir = user:get_look_dir() - local yaw = user:get_look_yaw() + local yaw = user:get_look_horizontal() if pos and dir then - pos.y = pos.y + 1.5 + pos.y = pos.y + shooter.config.camera_height local obj = minetest.add_entity(pos, "shooter_grenade: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) + minetest.sound_play("shooter_throw", {object=obj}) + obj:set_velocity(vector.multiply(dir, 15)) + obj:set_acceleration({x=dir.x * -3, y=-10, z=dir.z * -3}) + obj:set_yaw(yaw + math.pi / 2) local ent = obj:get_luaentity() if ent then - ent.player = ent.player or user + ent.user = user:get_player_name() end end end diff --git a/shooter_hook/init.lua b/shooter_hook/init.lua index 671f6d7..5e8639d 100644 --- a/shooter_hook/init.lua +++ b/shooter_hook/init.lua @@ -1,22 +1,22 @@ local function throw_hook(itemstack, user, vel) local inv = user:get_inventory() - local pos = user:getpos() + local pos = user:get_pos() local dir = user:get_look_dir() - local yaw = user:get_look_yaw() + local yaw = user:get_look_horizontal() if pos and dir and yaw then if not minetest.setting_getbool("creative_mode") then - itemstack:add_wear(65535/100) + itemstack:add_wear(65535 / 100) end pos.y = pos.y + 1.5 local obj = minetest.add_entity(pos, "shooter_hook: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) + obj:set_velocity(vector.multiply(dir, vel)) + obj:set_acceleration({x=dir.x * -3, y=-10, z=dir.z * -3}) + obj:set_yaw(yaw + math.pi / 2) local ent = obj:get_luaentity() if ent then - ent.player = ent.player or user + ent.user = user:get_player_name() ent.itemstack = itemstack end end @@ -29,7 +29,7 @@ minetest.register_entity("shooter_hook:hook", { visual = "wielditem", visual_size = {x=1/2, y=1/2}, textures = {"shooter_hook:grapple_hook"}, - player = nil, + user = nil, itemstack = "", collisionbox = {-1/4,-1/4,-1/4, 1/4,1/4,1/4}, on_activate = function(self, staticdata) @@ -39,20 +39,23 @@ minetest.register_entity("shooter_hook:hook", { end end, on_step = function(self, dtime) - if not self.player then + if not self.user then return end self.timer = self.timer + dtime if self.timer > 0.25 then - local pos = self.object:getpos() + local pos = self.object:get_pos() 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}) + self.object:set_velocity({x=0, y=-10, z=0}) + self.object:set_acceleration({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) + local player = minetest.get_player_by_name(self.user) + if player then + player:moveto(pos) + end end if minetest.get_item_group(node.name, "lava") == 0 then minetest.add_item(pos, self.itemstack) diff --git a/shooter_rocket/init.lua b/shooter_rocket/init.lua index 45d1bcc..d4ea153 100644 --- a/shooter_rocket/init.lua +++ b/shooter_rocket/init.lua @@ -17,7 +17,7 @@ minetest.register_entity("shooter_rocket:rocket_entity", { "shooter_bullet.png", "shooter_bullet.png", }, - player = nil, + user = nil, collisionbox = {0,0,0, 0,0,0}, on_activate = function(self, staticdata) if staticdata == "expired" then @@ -27,11 +27,16 @@ minetest.register_entity("shooter_rocket:rocket_entity", { on_step = function(self, dtime) self.timer = self.timer + dtime if self.timer > 0.2 then - local pos = self.object:getpos() + local pos = self.object:get_pos() local above = {x=pos.x, y=pos.y + 1, z=pos.z} if minetest.get_node(pos).name ~= "air" then + if self.user then + local player = minetest.get_player_by_name(self.user) + if player then + shooter:blast(above, 4, 50, 8, player) + end + end self.object:remove() - shooter:blast(above, 4, 50, 8, self.player) end self.timer = 0 end @@ -47,30 +52,30 @@ minetest.register_tool("shooter_rocket:rocket_gun_loaded", { 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) + itemstack:add_wear(65535 / 50) end itemstack = "shooter_rocket: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 + if vector.distance(user:get_pos(), pointed) < 8 then shooter:blast(pointed, 2, 50, 7) return itemstack end end - local pos = user:getpos() + local pos = user:get_pos() local dir = user:get_look_dir() - local yaw = user:get_look_yaw() + local yaw = user:get_look_horizontal() if pos and dir and yaw then - pos.y = pos.y + 1.5 + pos.y = pos.y + shooter.config.camera_height local obj = minetest.add_entity(pos, "shooter_rocket: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) + obj:set_velocity(vector.multiply(dir, 20)) + obj:set_acceleration({x=dir.x * -3, y=-10, z=dir.z * -3}) + obj:set_yaw(yaw + math.pi / 2) local ent = obj:get_luaentity() if ent then - ent.player = ent.player or user + ent.user = user:get_player_name() end end end diff --git a/shooter_turret/depends.txt b/shooter_turret/depends.txt index 91ee42b..554434c 100644 --- a/shooter_turret/depends.txt +++ b/shooter_turret/depends.txt @@ -1 +1,2 @@ -shooter +shooter_rocket +player_api? diff --git a/shooter_turret/init.lua b/shooter_turret/init.lua index 645e828..e66376d 100644 --- a/shooter_turret/init.lua +++ b/shooter_turret/init.lua @@ -1,3 +1,5 @@ +local use_player_api = minetest.get_modpath("player_api") + local function get_turret_entity(pos) local entity = nil local objects = minetest.get_objects_inside_radius(pos, 1) @@ -17,42 +19,6 @@ local function get_turret_entity(pos) return entity end -minetest.register_entity("shooter_turret: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:turret_entity", { physical = true, visual = "mesh", @@ -63,13 +29,13 @@ minetest.register_entity("shooter_turret:turret_entity", { "shooter_turret_uv.png", }, timer = 0, - player = nil, + user = nil, pitch = 40, yaw = 0, firing = false, on_activate = function(self, staticdata) - self.pos = self.object:getpos() - self.yaw = self.object:getyaw() + self.pos = self.object:get_pos() + self.yaw = self.object:get_yaw() if minetest.get_node(self.pos).name ~= "shooter_turret:turret" then self.object:remove() return @@ -80,23 +46,36 @@ minetest.register_entity("shooter_turret:turret_entity", { get_turret_entity(self.pos) end, on_rightclick = function(self, clicker) - if self.player then - self.player:set_detach() - self.player = nil + if self.user then + local player = minetest.get_player_by_name(self.user) + if player then + player:set_detach() + if use_player_api then + player_api.player_attached[self.user] = false + end + end + self.user = nil else - clicker:set_attach(self.object, "", {x=0,y=5,z=-8}, {x=0,y=0,z=0}) - self.player = clicker + clicker:set_attach(self.object, "", {x=0,y=-5,z=-8}, {x=0,y=0,z=0}) + self.user = clicker:get_player_name() + if use_player_api then + player_api.player_attached[self.user] = true + end end end, on_step = function(self, dtime) - self.timer = self.timer + dtime - if self.timer < 0.1 then + if not self.user then return - end - if self.player then + end + self.timer = self.timer + dtime + if self.timer < 0.2 then + return + end + local player = minetest.get_player_by_name(self.user) + if player then local pitch = self.pitch - local yaw = self.object:getyaw() - local ctrl = self.player:get_player_control() + local yaw = self.object:get_yaw() + local ctrl = player:get_player_control() local step = 2 if ctrl then if ctrl.sneak then @@ -130,7 +109,7 @@ minetest.register_entity("shooter_turret:turret_entity", { self.pitch = pitch end if self.yaw ~= yaw then - self.object:setyaw(yaw) + self.object:set_yaw(yaw) self.yaw = yaw end end @@ -138,19 +117,20 @@ minetest.register_entity("shooter_turret:turret_entity", { self.timer = 0 end, fire = function(self) + if not self.user then + return + end 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 + if not inv:contains_item("main", "shooter_rocket:rocket") then minetest.sound_play("shooter_click", {object=self.object}) return end + inv:remove_item("main", "shooter_rocket:rocket") 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({ @@ -159,26 +139,35 @@ minetest.register_entity("shooter_turret:turret_entity", { 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_turret:tnt_entity") + pos = vector.add(pos, vector.multiply(dir, 1.5)) + local obj = minetest.add_entity(pos, "shooter_rocket:rocket_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}) + ent.user = self.user + obj:set_yaw(self.yaw) + obj:set_velocity(vector.multiply(dir, 30)) + obj:set_acceleration({x=dir.x * -3, y=-10, z=dir.z * -3}) end end if shooter.config.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" - ) + minetest.add_particlespawner({ + amount = 10, + time = 0.1, + minpos = {x=pos.x - 1, y=pos.y - 1, z=pos.z - 1}, + maxpos = {x=pos.x + 1, y=pos.y + 1, z=pos.z + 1}, + minvel = {x=0, y=0, z=0}, + maxvel = {x=0, y=0, z=0}, + minacc = {x=-0.5, y=-0.5, z=-0.5}, + maxacc = {x=0.5, y=0.5, z=0.5}, + minexptime = 0.1, + maxexptime = 1, + minsize = 8, + maxsize = 15, + collisiondetection = false, + texture = "tnt_smoke.png", + }) end end }) @@ -191,7 +180,7 @@ minetest.register_node("shooter_turret:turret", { drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir", - groups = {snappy=2,choppy=2,oddly_breakable_by_hand=3}, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=3}, node_box = { type = "fixed", fixed = { @@ -207,7 +196,8 @@ minetest.register_node("shooter_turret:turret", { 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;]" + "list[current_player;main;0,5;8,4;]".. + "listring[]" ) meta:set_string("infotext", "Turret Gun") local inv = meta:get_inventory() diff --git a/shooter_turret/models/shooter_turret.b3d b/shooter_turret/models/shooter_turret.b3d index 8aa291c6868ed73185fffd06b3079b8b5ae210d8..da6301107f564c9894715c18eb76db47e92ec875 100644 GIT binary patch delta 8909 zcmZ{pe{>bqwa4!X#1g8MAK}+Pyxf9BR{0qMfiZU`A;I8}r-1w%z#EHCl=Z|wksl*) z`5{FtpyVh6WAQ?z3I!iFS5XIY6SXSzX~l@3Q`VC9buDSjdJC~AnFZv1_nzF$O-=aY z!@1||*|YcA`|NYh=w~`$m2|-^(#!fvOqOnku(&Ke@LQ>L42wdkb__=jHN|V!mg=d^ zxlT#{P)G}f9@ayl^V%S9LUeQPk&;GfLbg%bkloUz>^ZGZv+Pyrc8vAC+Vp*0YmF1LC~9#gr2JXFDuG;a6`RDbjpyiz)mZ)&F^u|h8C6i5H1 zPO+R`|LRb`Irmh_WNGAt;hmX7v*e=fNe{d%mCi&J#Jn+0?y-qUr*n}ImGaV$7eL6k zk%Ua94Sp*f@UnEd$Gb5c@!E9iq&EEgGj%jgc+pM#qMKsSsC4fZkBo)d^3J_WuQwIdpZew>(Xt!9FS*Al zOoc)_5us4DP}X$Ir;Sg8Myii&T1GG^zHe6Bzb#DG8LG zF`B-f^nl${r^kARBbS@v{}#k5*!@L@ze=xg-^pzz#7V7EPVJR14oR~Yz0~d%7ssX2 zJ4WvI=49#}EKBI5DtKKQAo8{!IpA{JV=Db=R0WZ- z{bL~YoR@BYo!WV1lA0G6=aWue48cw+1K!LME0PUA-6SG~@c)mWJy_R&>3bOqFQf&D zZ4Qbd6Wu|6G)A7ckZEqSEJdR}8ptZQ@PY=B2uu^CWs%o`7KwvjSRPD|$Cbg9=jvb` zMw)1Q(q=j!++=#(qvZ3mytE8%o8V<>GaV4}AQm#{N#$0e3SN~4)8rnTm~?JE+Ch}d zWkbW+<(<2fB2Ys~&>4ylNo5$dRi-hlU$cZctRJ4(F-!+f4~v0gho_%5hWERX^kju@ zEP1x^Lrv}-mP^7d0?u$!=?+gT^IBTU2!7cJ9pfgqZEm~V_L#~@mKm8K9V268+$e63 zqJEF56i{0&&_S~x{T{o3j6PB@5WQ|ej3h?0#AuSXx$Ta=4Klq7)6S@c^vsOHFuO#B z^r_utb#m{}-1J&f-sPGC&kuqiu9$7Xf4DJ|H*DPm@r7@Ffk4>B8@NbvtF_j|7 zCDkHbh(6LB7w#Jht!-ZSUPh*sXlG^3xO|H9IEuCh;??7c>Uc|>l?~&mw0q-8!xh%h zy5g0f{1>SCVwyD6CR$Rr@seWN;C1PM$k5wjlsm_sVI6%9)wscOANPB3KX{1&DSVr$U3Jes8>ZI@zhu%stYIq<+n zsg%(is7wRI771egfJo#r9bS56SoYE^kI}Q`JZDU0qK;>ciR7`#bWx#D`u+CAn7E!) zZ;uHvEooOYb%ZAS?l68hcUveK*cB#r?o@iM>5cl%qqB7?2mYo)yTaP&Sh?h$CY1Cg z_Y!Mn4wTPNE{+FJyby_huhxt z1lsnD<+KmZ)LU$CYMS0+yT1>fB;75x(KyXWU^|Ux+TONrf$eS1jXXJX9hp9hQs10a zgm%rWO=zpL$#R2fGHs?an|x6W8daHwp|`Xhqv*%!H)3a(#gqHWo^yf-(Qe;5uE$$> z`NPuyjR#(~Hw)=^wljLE_*qbmfQ4t+M0sd+~dDT*37NwM5BEU|Ef+#=H%v4 zI<~F0N-LBF^GKyJuL$9+rgqYq7v}iiPc!7*PqSsjsBOm3PP#FyHtdrRG?A1tpGMUA zBxQ5knIET~2NNXwAjwMQp*kU?`%oD4Ky17Vi0XpnSUoihkZ;mO4@S9Pc^IQf6-1Zu z2o0EENZL&2kp%TG56s^RO znC6DY{ll}` z1_yR}+G&=eL*iWLe@p)P!G`8{WY{1*)~GxdXr$8N+d~>dE%w0m$Jq4@+2HMcp!=K_ z*zT~b%k)6ZeHHt`G?*sSW;!6E!SuLCSwbfvy?7nmX-fk`p_igVoR4Hqg=A+KL zOT(pYUvDzbrET66GA~r>Q!P<#&e&j_GPXX*XsMbMGsA2v zn@HE%3|X6H9Wz`i*51^-64DpV{>Y~DE!oue_}^N_ky}r2t~`;TNT7`)&=cWE+wnN3 zIlM;bX6DNpt73SlweUY!67)_h189Vs`#>(b`71NM>bIvxGWdNv=#@rP+LZKkt+rZ^(IZ>S(W8(5MTt-ZmYW;*@^ z3;Y5n!(7~DxX4JiS*mrZA*r<)#X@;92w4zb+U4t`>3b0hz>}0PX0vST_fi3vq@`t1 zex7VEu;;XNk!m}zXIsWGGaKpH=oiYsF2C5|tHH(?f>N`Q3;9M)Y!FZVl4t3c2`pY0 z?MCS_l}&te1961hgrFy#O?noc-Zs;K^0W?7<7pZ;nKsy%be={G5t%Kd)nwWr4yIcY z6qBvo&$O8i(`9;0WgA-rViuVu_t;Elo0StJrSS|K0OH^XUX~8`xX;As0Q@Xx3DbOb zdE^w5nIcUmfOL!-n__jL&_0gwLfL)0jx?USJth{)n(ZHA#>{HE0NT}hq^ixUc4iuT zkj42}(i5tjDISv5G65DmS0S!Q^EujwZ4eQE?tA2E&GS@*+~w?_$tbVsp zNlr(YP8FFq?v^}}#tzQB9f8)?+3-b1&Nw>~6km(x$z<9f7Pu8W9oY0Qo~2Bi$QNZN z$7^S14yUg@RGenDWO|Upnd6gN#&JquUCz!JVz2BXKh#~+wz=(aTd}#{=6*ZeSA=dT zZGEjDfVW~ZmJN1Aghu^Xrwb;H2HP**@B(XkfwVf@R({QI_%-))+u^pdoBMYc4M~^z z^!JZohD)G5D7UbDw{PJOZ8)zPvSGJxVe4xdSs2s@SomVmkaT?8eq&Gv@WvO}lNZT) zCBYUasBI_Ov*dzyL^dSao2wvSV9B1MA?do6wj{_z@;!(q-nfS?VY(oWX-s7=Tg5b( zCevm*Oqb~~mEW*Dhzi0qnKsh_u~{=crt%WYGYt@xh-trs8Ndcg_cz)F{5udG8R~Jd zZg`0*WWhc@Z11DBYBFu6v(FNSoch}sSo7OD{sK1f>6@`0D|J7%>71_gXCYbr@{a^6 zrTq$h%yM4Qsdl1`+POaln)|~zb=dpk*xHl>37k5d1Gu9~_dpC(e;3E71NM>X!6LkL z$-#US5&NJ{&K@KOJ*IMqon;zKlW8*@rpxr0%Bw8TG?*sSel;AS$!WcmXaQ%QYh9N0 znq^xjHOaPGSpQ9LGMFaQW;#rl=`oeVY|~+skT#cV#`&hr@m34&u{n2 ztk?B6eAsxK4;vs(L~k$00pilzI7TF=IyiFS6Y^0$ zM;z7BcG1S)keJFbJ}n$8!Z~5du^8BJY!hmaQOk;$Hi(Z~wN^{*ZSNEi?9FD19I}}X zi0Nc{+@sX7yC8OdrpdIK4v1heJ*HC6@*t+4X>yOvbn0X1SKgsf^&M*4+;-mKn)xo* z%y;?Z`7X(LOyxb6XBteCX%myqdkOxu@IDEdAe>=3Adae_fBwXm#1GOvaOQ)Uz)|%B z|EPML%k2q1s-9q9H>HWA>Iwf_#7Cst{3zU!CRIka_Qy|$J6)#7R6gbz05JnhlY4BY z^KlIQ%AaUd{S&oqZaYku=`od0ScYjZO{UFsKwL#ZY!;uyX`48i0F_U5%85_IbdChE zt$^td$u74&?pGRUyHOj$eXq2fSJO+G{w9f~ESEG?kWQ9#LART>oo#pBjrip2-B66^)Afa`HE9OXdCbalJFE6Mwa8qvB`clJ)nfn3?m4vpjXrf3DEGSlcV0X@>Qv zCVrN)YxYB_DOD@=uKY+&>^JjLoBwa6-p$wWne`2XM8wL|A-imTS?Zs6J)!6NvR7VE zQ#+45q4)HEx+h1a?(e@!@5Mi@k97F*z{mlq!C$V@`&fH5_%f$=>XwnK^}cLD&cY2{ zQe)Sz))jUw`_=u~sTtO~68JSaDsppP+0j_LuJ;v zX6^gdUrL+bW_6k%`tW>Oh3S^~qxHZ9(a)NziLN5o+ByMK5WBMNSoU{u{Z?OTePfqn z>#xQ2A->OD%bJyB|Dmx<@p`MYOqB8CIXxDiF8Yb^=I?uGhauK zT2m&bXY;_0#wg9^IDa-V+1iXxR_o(^drnRi9kVGGDhJBCHW9x5eB=O)f>-QYP?j}B z8@qay9`%1B+!}>jCfSt9%MQERnLR<}taKj+ehC$)dvzFeQ=t6KfpQ`)N6mg#r+A)Y&6 ztETr{rr+s5XD-~X6r+qtlu|CCD zi6yAf5}e8tBSu?!cf$9rr{2=uI<`ok<_q;+nbJn@c~qb7{~UVnAGBXQ_Fwu8U;9UQ zQrIhyvp?_niPm$_LVcDm*CFzmwr|`c`fUCwE?QIWg41iP)%dT|k_W!fPIP!!|9{X> Bp^^Xq delta 7253 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 YoJx$IveIqj$6>3#+m(20@Jjc80F={9@&Et;