added some effects, probably fixed some stuff. Added bullet holes, fixed raycasting, but it's currently broken (entities not working?)
This commit is contained in:
parent
36e2af9f20
commit
295cd8fa79
@ -17,20 +17,18 @@ Guns4d.node_properties = {}
|
||||
--in a perfect world you could perfectly balance each node, but a aproximation will have to do
|
||||
--luckily its still an option, if you are literally out of your fucking mind.
|
||||
minetest.register_on_mods_loaded(function()
|
||||
print(table.tostring(minetest.registered_nodes["stairs:slab_wood"].groups))
|
||||
print(table.tostring(minetest.registered_nodes["default:wood"].groups))
|
||||
for i, v in pairs(minetest.registered_nodes) do
|
||||
local groups = v.groups
|
||||
local RHA = 1
|
||||
local random_deviation = 1
|
||||
local behavior_type = "normal"
|
||||
if groups.wood then
|
||||
RHA = RHA*.1
|
||||
random_deviation = random_deviation/groups.wood
|
||||
end
|
||||
if groups.oddly_breakable_by_hand then
|
||||
RHA = RHA / groups.oddly_breakable_by_hand
|
||||
end
|
||||
if groups.choppy then
|
||||
RHA = RHA*.5
|
||||
RHA = RHA/(5*groups.choppy)
|
||||
end
|
||||
if groups.flora or groups.grass then
|
||||
RHA = 0
|
||||
|
64
classes/Bullet_hole.lua
Normal file
64
classes/Bullet_hole.lua
Normal file
@ -0,0 +1,64 @@
|
||||
local player_positions = {}
|
||||
minetest.register_globalstep(function(dt)
|
||||
|
||||
end)
|
||||
|
||||
Bullet_hole = Instantiatable_class:inherit({
|
||||
unrendered_exptime = 20,
|
||||
unrendered_texture = 'bullet_hole.png',
|
||||
expiration_time = 60,
|
||||
heat_effect = false,
|
||||
render_distance = 50,
|
||||
deletion_distance = 80,
|
||||
timer = 0,
|
||||
construct = function(def)
|
||||
assert(def.pos)
|
||||
end
|
||||
})
|
||||
function Bullet_hole:render()
|
||||
if self.old_timer then
|
||||
--acount for the time lost.
|
||||
self.timer = self.old_timer-(self.unrendered_exptime-self.timer)
|
||||
end
|
||||
end
|
||||
function Bullet_hole:unrender()
|
||||
self.old_timer = self.timer
|
||||
self.timer = self.unrendered_exptime
|
||||
minetest.add_particlespawner({
|
||||
pos = self.pos,
|
||||
amount = 1,
|
||||
time=0,
|
||||
exptime = self.unrendered_exptime,
|
||||
texture = {
|
||||
name = 'bullet_hole.png',
|
||||
alpha_tween = {1,0}
|
||||
}
|
||||
})
|
||||
if self.entity:get_pos() then
|
||||
self.entity:remove()
|
||||
end
|
||||
end
|
||||
function Bullet_hole:update()
|
||||
end
|
||||
function Bullet_hole:update_ent()
|
||||
end
|
||||
minetest.register_entity("guns4d:bullet_hole", {
|
||||
initial_properties = {
|
||||
visual = "cube",
|
||||
visual_size = {x=.15, y=.15, z=0},
|
||||
pointable = false,
|
||||
static_save = false,
|
||||
use_texture_alpha = true,
|
||||
textures = {"blank.png", "blank.png", "blank.png", "blank.png", "bullet_hole.png", "blank.png"}
|
||||
},
|
||||
on_step = function(self, dtime)
|
||||
if TICK % 50 then
|
||||
local class_inst = self.class_Inst
|
||||
if class_inst.timer < 30 then
|
||||
local properties = self.object:get_properties()
|
||||
properties.textures[5] = 'bullet_hole.png^[opacity:'..(math.floor((12.75*tostring(self.timer/30)))*20)
|
||||
self.object:set_properties(properties)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
@ -3,6 +3,7 @@ local ray = {
|
||||
state = "free",
|
||||
--pos = pos,
|
||||
last_node = "",
|
||||
hole_entity = "guns4d:bullet_hole",
|
||||
normal = vector.new(),
|
||||
--last_dir
|
||||
--exit_direction = dir,
|
||||
@ -19,18 +20,17 @@ function ray:record_state()
|
||||
})
|
||||
end
|
||||
--find (valid) edge. Slabs or other nodeboxes that are not the last hit position are not considered (to account for holes) TODO: update to account for hollow nodes
|
||||
function ray:find_transverse_end_point()
|
||||
function ray:find_transverse_edge()
|
||||
assert(self.instance, "attempt to call obj method on a class")
|
||||
local pointed
|
||||
local cast = minetest.raycast(self.pos+(self.dir*(self.ITERATION_DISTANCE+.01)), self.pos, false, false)
|
||||
for hit in cast do
|
||||
local cast1 = minetest.raycast(self.pos+(self.dir*(self.ITERATION_DISTANCE+.001)), self.pos, false, false)
|
||||
for hit in cast1 do
|
||||
--we can't solidly predict all nodes, so ignore them as the distance will be solved regardless. If node name is different then
|
||||
if hit.type == "node" and (vector.equals(hit.under, self.last_pointed.under) or not minetest.registered_nodes[self.last_node_name].node_box) then
|
||||
if hit.type == "node" and (vector.distance(hit.intersection_point, self.pos) > 0.0001) and (vector.equals(hit.under, self.last_pointed_node.under) or not minetest.registered_nodes[self.last_node_name].node_box) then
|
||||
pointed = hit
|
||||
break
|
||||
end
|
||||
end
|
||||
if pointed and vector.distance(pointed.intersection_point, self.pos) < self.ITERATION_DISTANCE then
|
||||
if (pointed) and (vector.distance(pointed.intersection_point, self.pos) < self.ITERATION_DISTANCE) then
|
||||
return pointed.intersection_point, pointed.intersection_normal
|
||||
end
|
||||
end
|
||||
@ -42,12 +42,11 @@ function ray:_cast()
|
||||
|
||||
local end_pos
|
||||
local edge
|
||||
--if block ends early, then we find it and set end position of the ray accordingly.
|
||||
--edge is where the section of solid blocks ends and becomes open air again.
|
||||
--detect the "edge" of the block
|
||||
if self.state == "transverse" then
|
||||
edge, end_normal = self:find_transverse_end_point()
|
||||
edge, end_normal = self:find_transverse_edge()
|
||||
if edge then
|
||||
end_pos = edge
|
||||
end_pos = edge+(self.dir*.001) --give it a tolerance, it still needs to intersect with any node edges connected to the edge's block.
|
||||
next_state = "free"
|
||||
else
|
||||
end_pos = self.pos+(self.dir*self.ITERATION_DISTANCE)
|
||||
@ -58,23 +57,33 @@ function ray:_cast()
|
||||
--do the main raycast. We don't account for mmRHA dropoff here.
|
||||
local continue = true --indicates wether to :_iterate wether the Bullet_ray has ended
|
||||
local cast = minetest.raycast(self.pos, end_pos, true, true)
|
||||
local pointed
|
||||
local edge_length
|
||||
if edge then
|
||||
edge_length = vector.distance(edge, self.pos)
|
||||
end
|
||||
local pointed_node
|
||||
local pointed_object
|
||||
for hit in cast do
|
||||
if vector.distance(hit.intersection_point, self.pos) > 0.0005 and vector.distance(hit.intersection_point, self.pos) < self.range then
|
||||
local h_length = vector.distance(hit.intersection_point, self.pos)
|
||||
if ( (not hit.ref) and h_length > 0.0001) and h_length < self.range then
|
||||
--if it's a node, check that it's note supposed to be ignored according to it's generated properties
|
||||
if hit.type == "node" then
|
||||
if self.state == "free" and Guns4d.node_properties[minetest.get_node(hit.under).name].behavior ~= "ignore" then
|
||||
next_state = "transverse"
|
||||
pointed = hit
|
||||
pointed_node = hit
|
||||
end_normal = hit.intersection_normal
|
||||
end_pos = pointed.intersection_point
|
||||
end_pos = pointed_node.intersection_point
|
||||
break
|
||||
end
|
||||
if self.state == "transverse" then
|
||||
--if it isn't the same name as the last node we intersected, then it's a different block with different stats for penetration
|
||||
pointed_node = hit
|
||||
if minetest.get_node(hit.under).name ~= self.last_node_name then
|
||||
pointed = hit
|
||||
end_pos = pointed.intersection_point
|
||||
end_pos = pointed_node.intersection_point
|
||||
elseif edge then
|
||||
if h_length-edge_length < 0.01 then
|
||||
next_state = "transverse"
|
||||
end
|
||||
end
|
||||
--make sure it's set to transverse if the edge has a block infront of it
|
||||
if Guns4d.node_properties[minetest.get_node(hit.under).name].behavior == "ignore" then
|
||||
@ -87,77 +96,66 @@ function ray:_cast()
|
||||
end
|
||||
--if it's an object, make sure it's not the player object
|
||||
--note that while it may seem like this will create a infinite hit loop, it resolves itself as the intersection_point of the next ray will be close enough as to skip the pointed. See first line of iterator.
|
||||
if (hit.type == "object") and (hit.ref ~= self.player) and ((not self.last_pointed) or (hit.ref ~= self.last_pointed.ref)) then
|
||||
if (hit.type == "object") and (hit.ref ~= self.player) and ((not self.last_pointed_object) or (hit.ref ~= self.last_pointed_object.ref)) then
|
||||
minetest.chat_send_all("ent hit, ray")
|
||||
end_pos = pointed_object.intersection_point
|
||||
if self.over_penetrate then
|
||||
pointed = hit
|
||||
pointed_object = hit
|
||||
break
|
||||
else
|
||||
pointed = hit
|
||||
pointed_object = hit
|
||||
continue = false
|
||||
break
|
||||
end
|
||||
end_pos = pointed.intersection_point
|
||||
end
|
||||
end
|
||||
end
|
||||
--[[if pointed then
|
||||
end_pos = pointed.intersection_point
|
||||
if self.state == "transverse" then
|
||||
next_penetration_val = self.energy-(vector.distance(self.pos, end_pos)*Guns4d.node_properties[self.last_node_name].mmRHA)
|
||||
else -- transverse
|
||||
next_penetration_val = self.energy-(vector.distance(self.pos, end_pos)*self.dropoff_mmRHA)
|
||||
end
|
||||
else
|
||||
--if there is no pointed, and it's not transverse, then the ray has ended.
|
||||
if self.state == "transverse" then
|
||||
next_penetration_val = self.energy-(vector.distance(self.pos, end_pos)*Guns4d.node_properties[self.last_node_name].mmRHA)
|
||||
else --free
|
||||
continue = false
|
||||
next_penetration_val = self.energy-(self.range*self.dropoff_mmRHA)
|
||||
end
|
||||
end]]
|
||||
|
||||
--set "last" values.
|
||||
return pointed, next_state, end_pos, end_normal, continue
|
||||
return pointed_node, pointed_object, next_state, end_pos, end_normal, continue
|
||||
end
|
||||
--the main function.
|
||||
function ray:_iterate(initialized)
|
||||
assert(self.instance, "attempt to call obj method on a class")
|
||||
local pointed, next_state, end_pos, end_normal, continue = self:_cast()
|
||||
local pointed_node, pointed_object, next_state, end_pos, end_normal, continue = self:_cast()
|
||||
|
||||
local distance = vector.distance(self.pos, end_pos)
|
||||
if self.state == "free" then
|
||||
self.energy = self.energy-(distance*self.energy_dropoff)
|
||||
if distance ~= self.pos+(self.dir*self.range) then
|
||||
self:bullet_hole(end_pos, end_normal)
|
||||
end
|
||||
else
|
||||
if self.history[#self.history].state == "free" then
|
||||
self:bullet_hole(self.pos, self.history[#self.history-1].normal)
|
||||
end
|
||||
if next_state == "free" then
|
||||
self:bullet_hole(end_pos, end_normal)
|
||||
end
|
||||
local penetration_loss = distance*Guns4d.node_properties[self.last_node_name].mmRHA
|
||||
--calculate our energy loss based on the percentage of energy our penetration represents.
|
||||
minetest.chat_send_all(penetration_loss/self.init_penetration)
|
||||
minetest.chat_send_all(distance)
|
||||
minetest.chat_send_all(Guns4d.node_properties[self.last_node_name].mmRHA)
|
||||
--minetest.chat_send_all(penetration_loss)
|
||||
self.energy = self.energy-((self.init_energy*self.energy_sharp_ratio)*(penetration_loss/self.init_penetration))
|
||||
end
|
||||
if self.state ~= self.next_state then
|
||||
|
||||
end
|
||||
--set values for next iteration.
|
||||
self.range = self.range-distance
|
||||
if self.range <= 0.0005 or self.energy < 0 then
|
||||
continue = false
|
||||
minetest.chat_send_all("range ended, dist:"); minetest.chat_send_all(tostring(distance))
|
||||
end
|
||||
---@diagnostic disable-next-line: assign-type-mismatch
|
||||
self.state = next_state
|
||||
if pointed then
|
||||
self.last_pointed = pointed
|
||||
self.pos = pointed.intersection_point
|
||||
if self.energy > 0 then
|
||||
if pointed.type == "node" then
|
||||
self.last_node_name = minetest.get_node(pointed.under).name
|
||||
elseif pointed.type == "object" then
|
||||
ray:hit_entity(pointed.ref)
|
||||
end
|
||||
end
|
||||
if pointed_object then
|
||||
self.pos = pointed_object.intersection_point
|
||||
self.last_pointed_object = pointed_object
|
||||
ray:hit_entity(pointed_object.ref)
|
||||
else
|
||||
self.pos = end_pos
|
||||
end
|
||||
if pointed_node then
|
||||
self.last_node_name = minetest.get_node(pointed_node.under).name
|
||||
self.last_pointed_node = pointed_node
|
||||
end
|
||||
table.insert(self.history, {
|
||||
pos = self.pos,
|
||||
energy = self.energy,
|
||||
@ -172,7 +170,7 @@ function ray:_iterate(initialized)
|
||||
for i, v in pairs(self.history) do
|
||||
local hud = self.player:hud_add({
|
||||
hud_elem_type = "waypoint",
|
||||
text = "mmRHA:"..tostring(v.energy).." ",
|
||||
text = " "..self.history[i].energy,
|
||||
number = 255255255,
|
||||
precision = 1,
|
||||
world_pos = v.pos,
|
||||
@ -180,21 +178,40 @@ function ray:_iterate(initialized)
|
||||
alignment = {x=0,y=0},
|
||||
offset = {x=0,y=0},
|
||||
})
|
||||
minetest.after(40, function(hud)
|
||||
minetest.after(15, function(hud)
|
||||
self.player:hud_remove(hud)
|
||||
end, hud)
|
||||
end
|
||||
end
|
||||
end
|
||||
function ray:calculate_blunt_damage(bullet, armor, groups)
|
||||
end
|
||||
function ray:calculate_sharp_conversion(bullet, armor, groups)
|
||||
end
|
||||
function ray:calculate_sharp_damage(bullet, armor, groups)
|
||||
end
|
||||
function ray:calculate_blunt_damage(bullet, armor, groups)
|
||||
end
|
||||
function ray:apply_damage(object, blunt_pen, sharp_pen, blunt_dmg, sharp_dmg)
|
||||
minetest.chat_send_all("ent hit")
|
||||
object:punch()
|
||||
end
|
||||
function ray:bullet_hole(pos, normal)
|
||||
local nearby_players = false
|
||||
for pname, player in pairs(minetest.get_connected_players()) do
|
||||
if vector.distance(player:get_pos(), pos) < 50 then
|
||||
nearby_players = true; break
|
||||
end
|
||||
end
|
||||
--if it's close enough to any players, then add it
|
||||
if nearby_players then
|
||||
--this entity will keep track of itself.
|
||||
local ent = minetest.add_entity(pos+(normal*(.0001+math.random()/1000)), self.hole_entity)
|
||||
ent:set_rotation(vector.dir_to_rotation(normal))
|
||||
local lua_ent = ent:get_luaentity()
|
||||
lua_ent.block_pos = pos
|
||||
else
|
||||
Guns4d.effects.spawn_bullet_hole_particle(pos, self.hole_scale, '(bullet_hole_1.png^(bullet_hole_2.png^[opacity:129))')
|
||||
end
|
||||
end
|
||||
function ray.construct(def)
|
||||
if def.instance then
|
||||
assert(def.player, "no player")
|
||||
|
@ -141,7 +141,7 @@ local gun_default = {
|
||||
time_since_last_fire = 0,
|
||||
time_since_creation = 0,
|
||||
rechamber_time = 0,
|
||||
muzzle_flash = Guns4d.muzzle_flash
|
||||
muzzle_flash = Guns4d.effects.muzzle_flash
|
||||
}
|
||||
|
||||
function gun_default:attempt_fire()
|
||||
@ -290,7 +290,7 @@ end
|
||||
--update the gun, da meat and da potatoes
|
||||
function gun_default:update(dt)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
if not self:has_entity() then self:add_entity() end
|
||||
if not self:has_entity() then self:add_entity(); self:clear_animation() end
|
||||
self.pos = self:get_pos()
|
||||
local handler = self.handler
|
||||
local look_rotation = {x=handler.look_rotation.x,y=handler.look_rotation.y}
|
||||
@ -448,9 +448,6 @@ function gun_default:set_animation(frames, length, fps, loop)
|
||||
end
|
||||
function gun_default:clear_animation()
|
||||
local loaded = false
|
||||
for i, v in pairs(self.ammo_handler) do
|
||||
print(i,v )
|
||||
end
|
||||
if self.properties.ammo.magazine_only then
|
||||
if self.ammo_handler.ammo.loaded_mag ~= "empty" then
|
||||
loaded = true
|
||||
@ -612,7 +609,6 @@ gun_default.construct = function(def)
|
||||
|
||||
--fill in the properties.
|
||||
def.properties = table.fill(def.parent_class.properties, props or {})
|
||||
print(table.tostring(def.properties))
|
||||
def.consts = table.fill(def.parent_class.consts, def.consts or {})
|
||||
props = def.properties --have to reinitialize this as the reference is replaced.
|
||||
|
||||
|
@ -2,7 +2,6 @@ Instantiatable_class = {
|
||||
instance = false,
|
||||
__no_copy = true
|
||||
}
|
||||
--not that construction change is NOT called for inheriting an object.
|
||||
function Instantiatable_class:inherit(def)
|
||||
--construction chain for inheritance
|
||||
--if not def then def = {} else def = table.shallow_copy(def) end
|
||||
|
0
model_reader.lua
Normal file
0
model_reader.lua
Normal file
0
patches/3d_armor.lua
Normal file
0
patches/3d_armor.lua
Normal file
BIN
textures/bullet_hole.png
Normal file
BIN
textures/bullet_hole.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 131 B |
BIN
textures/bullet_hole_1.png
Normal file
BIN
textures/bullet_hole_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 151 B |
BIN
textures/bullet_hole_2.png
Normal file
BIN
textures/bullet_hole_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 554 B |
@ -1,5 +1,9 @@
|
||||
Guns4d.effects={
|
||||
bullet_holes = {}
|
||||
}
|
||||
|
||||
--designed for use with the gun class
|
||||
function Guns4d.muzzle_flash(self)
|
||||
function Guns4d.effects.muzzle_flash(self)
|
||||
local playername = self.player:get_player_name()
|
||||
if self.particle_spawners.muzzle_smoke and self.particle_spawners.muzzle_smoke ~= -1 then
|
||||
minetest.delete_particlespawner(self.particle_spawners.muzzle_smoke, self.player:get_player_name())
|
||||
@ -66,13 +70,90 @@ function Guns4d.muzzle_flash(self)
|
||||
},
|
||||
},
|
||||
{name = "smoke.png^[multiply:#b0b0b0", alpha_tween = {.2, 0}, scale = 1.4, blend = "alpha",
|
||||
animation = {
|
||||
type = "vertical_frames",
|
||||
aspect_w = 16,
|
||||
aspect_h = 16,
|
||||
length = .35,
|
||||
},
|
||||
animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = .35,},
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
end
|
||||
function Guns4d.effects.spawn_bullet_hole_particle(pos, size, texture)
|
||||
--modern syntax isn't accepted by add particle to my knowledge, or it's not documented.
|
||||
--so I have to use a particle spawner
|
||||
minetest.add_particlespawner({
|
||||
pos = pos,
|
||||
amount = 1,
|
||||
time=.1,
|
||||
exptime = 10,
|
||||
texture = {
|
||||
name = 'bullet_hole.png',
|
||||
alpha_tween = {1,0}
|
||||
}
|
||||
})
|
||||
end
|
||||
local bullet_holes = Guns4d.effects.bullet_holes
|
||||
local hole_despawn_dist = 20
|
||||
local time_since_last_check = 5
|
||||
minetest.register_globalstep(function(dt)
|
||||
if time_since_last_check >= 5 then
|
||||
time_since_last_check = 0
|
||||
for i, v in pairs(bullet_holes) do
|
||||
local pos = v:get_pos()
|
||||
if pos then
|
||||
local nearby_players = false
|
||||
for pname, player in pairs(minetest.get_connected_players()) do
|
||||
if vector.distance(player:get_pos(), pos) < hole_despawn_dist then
|
||||
nearby_players = true
|
||||
end
|
||||
end
|
||||
if not nearby_players then
|
||||
local props = v:get_properties()
|
||||
Guns4d.effects.spawn_bullet_hole_particle(v:get_pos(), props.visual_size.x, props.textures[5])
|
||||
bullet_holes[i]:remove()
|
||||
table.remove(bullet_holes, i)
|
||||
end
|
||||
else
|
||||
--if pos is nil, we know the bullet delete itself.
|
||||
table.remove(bullet_holes, i)
|
||||
end
|
||||
end
|
||||
else
|
||||
time_since_last_check = time_since_last_check + dt
|
||||
end
|
||||
end)
|
||||
minetest.register_entity("guns4d:bullet_hole", {
|
||||
initial_properties = {
|
||||
visual = "cube",
|
||||
visual_size = {x=.15, y=.15, z=0},
|
||||
pointable = false,
|
||||
static_save = false,
|
||||
use_texture_alpha = true,
|
||||
textures = {"blank.png", "bullet_hole.png", "blank.png", "blank.png", "bullet_hole.png", "bullet_hole.png"}
|
||||
},
|
||||
on_step = function(self, dtime)
|
||||
if not self.block_name then
|
||||
table.insert(bullet_holes, 1, self.object)
|
||||
self.block_name = minetest.get_node(self.block_pos).name
|
||||
elseif (TICK%3==0) and (self.block_name ~= minetest.get_node(self.block_pos).name) then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
if not self.timer then
|
||||
local properties = self.object:get_properties()
|
||||
self.timer = 31
|
||||
properties.textures[5] = 'bullet_hole.png'
|
||||
self.object:set_properties(properties)
|
||||
else
|
||||
self.timer = self.timer - dtime
|
||||
end
|
||||
if self.timer < 30 then
|
||||
if self.timer < 0 then
|
||||
self.object:remove()
|
||||
minetest.chat_send_all("removed")
|
||||
return
|
||||
end
|
||||
local properties = self.object:get_properties()
|
||||
properties.textures[5] = 'bullet_hole.png^[opacity:'..(math.floor((12.75*tostring(self.timer/30)))*20)
|
||||
self.object:set_properties(properties)
|
||||
end
|
||||
end
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user