tons of changes, probably, not sure
This commit is contained in:
parent
295cd8fa79
commit
6ec442ee31
@ -17,8 +17,6 @@ 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
|
||||
|
@ -82,7 +82,6 @@ function Ammo_handler:load_magazine()
|
||||
if ammo > highest_ammo then
|
||||
highest_ammo = ammo
|
||||
local has_unaccepted = false
|
||||
print(meta:get_string("guns4d_loaded_bullets"))
|
||||
for bullet, _ in pairs(minetest.deserialize(meta:get_string("guns4d_loaded_bullets"))) do
|
||||
if not gun.accepted_bullets[bullet] then
|
||||
has_unaccepted = true
|
||||
@ -138,7 +137,6 @@ end
|
||||
function Ammo_handler:unload_magazine(to_ground)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
if self.ammo.loaded_mag ~= "empty" then
|
||||
minetest.chat_send_all("not empty")
|
||||
local inv = self.handler.inventory
|
||||
local magstack = ItemStack(self.ammo.loaded_mag)
|
||||
local magmeta = magstack:get_meta()
|
||||
|
@ -9,16 +9,11 @@ local ray = {
|
||||
--exit_direction = dir,
|
||||
--range_left = def.bullet.range,
|
||||
--energy = def.bullet.penetration_RHA
|
||||
mmRHA_to_Pa_energy_ratio = .5,
|
||||
ITERATION_DISTANCE = .3,
|
||||
damage = 0
|
||||
}
|
||||
|
||||
function ray:record_state()
|
||||
table.insert(self.history, {
|
||||
state = self.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_edge()
|
||||
assert(self.instance, "attempt to call obj method on a class")
|
||||
@ -65,7 +60,7 @@ function ray:_cast()
|
||||
local pointed_object
|
||||
for hit in cast do
|
||||
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 (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
|
||||
@ -97,8 +92,6 @@ function ray:_cast()
|
||||
--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_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_object = hit
|
||||
break
|
||||
@ -107,6 +100,7 @@ function ray:_cast()
|
||||
continue = false
|
||||
break
|
||||
end
|
||||
end_pos = pointed_object.intersection_point
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -133,7 +127,7 @@ function ray:_iterate(initialized)
|
||||
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.
|
||||
self.energy = self.energy-((self.init_energy*self.energy_sharp_ratio)*(penetration_loss/self.init_penetration))
|
||||
self.energy = self.energy-((self.init_energy*self.energy_sharp_ratio)*(penetration_loss/self.sharp_penetration))
|
||||
end
|
||||
if self.state ~= self.next_state then
|
||||
|
||||
@ -148,7 +142,7 @@ function ray:_iterate(initialized)
|
||||
if pointed_object then
|
||||
self.pos = pointed_object.intersection_point
|
||||
self.last_pointed_object = pointed_object
|
||||
ray:hit_entity(pointed_object.ref)
|
||||
self:hit_entity(pointed_object.ref)
|
||||
else
|
||||
self.pos = end_pos
|
||||
end
|
||||
@ -166,7 +160,7 @@ function ray:_iterate(initialized)
|
||||
if continue and self.range > 0 and self.energy > 0 then
|
||||
self:_iterate(true)
|
||||
end
|
||||
if not initialized then
|
||||
--[[if not initialized then
|
||||
for i, v in pairs(self.history) do
|
||||
local hud = self.player:hud_add({
|
||||
hud_elem_type = "waypoint",
|
||||
@ -182,19 +176,64 @@ function ray:_iterate(initialized)
|
||||
self.player:hud_remove(hud)
|
||||
end, hud)
|
||||
end
|
||||
end]]
|
||||
end
|
||||
--can be safely overridden
|
||||
function ray:calculate_sharp_conversion(resistance, sharp_penetration)
|
||||
assert(self.instance, "attempt to call obj method on a class")
|
||||
end
|
||||
function ray:hit_entity(object)
|
||||
assert(self.instance, "attempt to call obj method on a class")
|
||||
|
||||
local resistance = object:get_armor_groups() -- support for different body parts is needed here, that's for... a later date, though.
|
||||
local sharp_pen = self.sharp_penetration-(self.sharp_penetration*(self.energy/self.init_energy)*self.energy_sharp_ratio)
|
||||
sharp_pen = math.clamp(sharp_pen - (resistance.guns4d_mmRHA or 0), 0, 65535)
|
||||
local converted_Pa = (resistance.guns4d_mmRHA or 0) * self.mmRHA_to_Pa_energy_ratio
|
||||
|
||||
local blunt_pen = converted_Pa+(self.blunt_penetration-(self.blunt_penetration*(self.energy/self.init_energy)*(1-self.energy_sharp_ratio)))
|
||||
blunt_pen = math.clamp(blunt_pen - (resistance.guns4d_Pa or 0), 0, 65535)
|
||||
self:apply_damage(object, sharp_pen, blunt_pen)
|
||||
|
||||
--raw damage first
|
||||
end
|
||||
--not point in overriding this if you remove hit_entity()
|
||||
--blunt & sharp ratio are the ratios of initial damage to damage at this bullet's current energy.
|
||||
function ray:apply_damage(object, sharp_pen, blunt_pen)
|
||||
assert(self.instance, "attempt to call obj method on a class")
|
||||
--coefficients for damage
|
||||
local blunt_ratio = blunt_pen/self.blunt_penetration
|
||||
local sharp_ratio = sharp_pen/self.sharp_penetration
|
||||
|
||||
--raw damage values
|
||||
local blunt_dmg = self.raw_blunt_damage*blunt_ratio
|
||||
local sharp_dmg = self.raw_sharp_damage*sharp_ratio
|
||||
|
||||
local hp = (object:get_hp()-blunt_dmg)-sharp_dmg
|
||||
print(blunt_dmg, sharp_dmg, blunt_ratio, sharp_ratio)
|
||||
print(self.blunt_penetration, self.sharp_penetration)
|
||||
if hp < 0 then hp = 0 end
|
||||
object:set_hp(hp, {type="set_hp", from="guns4d"})
|
||||
|
||||
--now apply damage groups.
|
||||
if self.blunt_damage_groups then
|
||||
local damage_values = {}
|
||||
for i, v in pairs(self.blunt_damage_groups) do
|
||||
damage_values[i] = v*blunt_ratio
|
||||
end
|
||||
object:punch(self.gun.entity, 1000, {damage_groups=damage_values}, self.dir)
|
||||
end
|
||||
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()
|
||||
if self.sharp_damage_groups then
|
||||
local damage_values = {}
|
||||
for i, v in pairs(self.sharp_damage_groups) do
|
||||
damage_values[i] = v*sharp_ratio
|
||||
end
|
||||
object:punch(self.gun.entity, 1000, {damage_groups=damage_values}, self.dir)
|
||||
end
|
||||
--punch SUCKS for this, apparently armor can only have flat rates of protection, which is sort of the worst thing i've ever heard.
|
||||
--object:punch()
|
||||
end
|
||||
function ray:bullet_hole(pos, normal)
|
||||
assert(self.instance, "attempt to call obj method on a class")
|
||||
local nearby_players = false
|
||||
for pname, player in pairs(minetest.get_connected_players()) do
|
||||
if vector.distance(player:get_pos(), pos) < 50 then
|
||||
@ -222,21 +261,33 @@ function ray.construct(def)
|
||||
assert(def.range, "no range")
|
||||
assert(def.energy, "no energy")
|
||||
assert(def.energy_dropoff, "no energy dropoff")
|
||||
assert(def.blunt_damage, "no blunt damage")
|
||||
|
||||
def.sharp_damage = def.sharp_damage or 0
|
||||
def.sharp_penetration = def.sharp_penetration or 0
|
||||
if def.sharp_penetration==0 then
|
||||
def.blunt_penetration = def.blunt_penetration or def.energy/2
|
||||
else
|
||||
def.blunt_penetration = def.blunt_penetration or def.energy
|
||||
--use this if you don't want to use the built-in system for penetrations.
|
||||
assert(not(def.ignore_penetration and not rawget(def, "hit_entity")), "bullet ray cannot ignore default penetration if hit_entity() is undefined. Use ignore_penetration for custom damage systems." )
|
||||
if not def.ignore_penetration then
|
||||
assert((not (def.blunt_penetration and def.energy)) or (def.blunt_penetration < def.energy), "blunt penetration may not be greater than energy! Blunt penetration is in Joules/Megapascals, energy is also in Joules.")
|
||||
|
||||
--"raw" damages define the damage (unaffected by armor groups) for the initial penetration value of each type.
|
||||
--def.sharp_damage_groups = {} --tool capabilities
|
||||
--def.blunt_damage_groups = {}
|
||||
|
||||
--guns4d mmRHA is used in traditional context.
|
||||
assert((not def.blunt_damage_groups) or not def.blunt_damage_groups["guns4d_mmRHA"], "guns4d_mmRHA damage group is not used in a traditional context. To increase penetration, increase sharp_penetration field.")
|
||||
assert((not def.blunt_damage_groups) or not def.blunt_damage_groups["guns4d_Pa"], "guns4d_Pa is not used in a traditional context. To increase blunt penetration, increase blunt_penetration field.")
|
||||
|
||||
|
||||
def.raw_sharp_damage = def.raw_sharp_damage or 0
|
||||
def.raw_blunt_damage = def.raw_blunt_damage or 0
|
||||
def.sharp_penetration = def.sharp_penetration or 0
|
||||
if def.sharp_penetration==0 then
|
||||
def.blunt_penetration = def.blunt_penetration or def.energy/2
|
||||
else
|
||||
def.blunt_penetration = def.blunt_penetration or def.energy
|
||||
end
|
||||
def.energy_sharp_ratio = (def.energy-def.blunt_penetration)/def.energy
|
||||
end
|
||||
|
||||
def.init_energy = def.energy
|
||||
def.init_penetration = def.sharp_penetration
|
||||
def.init_blunt = def.blunt_penetration
|
||||
--blunt pen is in the same units (1 Joule/Area^3 = 1 MPa), so we use it to make the ratio by subtraction.
|
||||
def.energy_sharp_ratio = (def.energy-def.blunt_penetration)/def.energy
|
||||
--blunt pen is in the same units (1 Joule/Area^3 = 1 Pa), so we use it to make the ratio by subtraction.
|
||||
|
||||
def.dir = vector.new(def.dir)
|
||||
def.pos = vector.new(def.pos)
|
||||
|
159
classes/Gun.lua
159
classes/Gun.lua
@ -144,13 +144,69 @@ local gun_default = {
|
||||
muzzle_flash = Guns4d.effects.muzzle_flash
|
||||
}
|
||||
|
||||
--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(); self:clear_animation() end
|
||||
local handler = self.handler
|
||||
local look_rotation = {x=handler.look_rotation.x,y=handler.look_rotation.y}
|
||||
local total_rot = self.offsets.total_offset_rotation
|
||||
local player_rot = self.offsets.player_rotation
|
||||
local constant = 6
|
||||
|
||||
--player look rotation. I'm going to keep it real, I don't remember what this equation does.
|
||||
if not self.sprite_scope then
|
||||
local next_vert_aim = ((player_rot.x+look_rotation.x)/(1+constant*dt))-look_rotation.x
|
||||
if math.abs(look_rotation.x-next_vert_aim) > .005 then
|
||||
player_rot.x = next_vert_aim
|
||||
else
|
||||
player_rot.x = -look_rotation.x
|
||||
end
|
||||
else
|
||||
player_rot.x = -look_rotation.x
|
||||
end
|
||||
--timers
|
||||
if self.rechamber_time > 0 then
|
||||
self.rechamber_time = self.rechamber_time - dt
|
||||
else
|
||||
self.rechamber_time = 0
|
||||
end
|
||||
self.time_since_creation = self.time_since_creation + dt
|
||||
self.time_since_last_fire = self.time_since_last_fire + dt
|
||||
|
||||
--update some vectors
|
||||
if self.consts.HAS_SWAY then self:update_sway(dt) end
|
||||
if self.consts.HAS_RECOIL then self:update_recoil(dt) end
|
||||
if self.consts.HAS_BREATHING then self:update_breathing(dt) end
|
||||
if self.consts.HAS_WAG then self:update_wag(dt) end
|
||||
self.dir = self:get_dir()
|
||||
self.local_dir = self:get_dir(true)
|
||||
self.paxial_dir = self:get_player_axial_dir()
|
||||
self.local_paxial_dir = self:get_player_axial_dir(true)
|
||||
self.pos = self:get_pos()
|
||||
|
||||
local bone, quat = self.model_handler:get_bone_global("Magazine")
|
||||
minetest.chat_send_all(dump(bone))
|
||||
--minetest.chat_send_all(dump(quat))
|
||||
self:get_pos(bone/10, true)
|
||||
--sprite scope
|
||||
if self.properties.sprite_scope then
|
||||
self.sprite_scope:update()
|
||||
end
|
||||
|
||||
player_rot.y = -handler.look_rotation.y
|
||||
local offsets = self.offsets
|
||||
total_rot.player_axial = offsets.recoil.player_axial + offsets.walking.player_axial + offsets.sway.player_axial + {x=offsets.breathing.player_axial,y=0,z=0}
|
||||
total_rot.gun_axial = offsets.recoil.gun_axial + offsets.walking.gun_axial + offsets.sway.gun_axial
|
||||
end
|
||||
|
||||
function gun_default:attempt_fire()
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
if self.rechamber_time <= 0 then
|
||||
local spent_bullet = self.ammo_handler:spend_round()
|
||||
if spent_bullet then
|
||||
local dir = self.dir
|
||||
local pos = self:get_pos()
|
||||
local pos = self.pos
|
||||
--[[print(dump(Guns4d.ammo.registered_bullets))
|
||||
print(self.ammo_handler.next_bullet)
|
||||
print(Guns4d.ammo.registered_bullets[self.ammo_handler.next_bullet])]]
|
||||
@ -192,7 +248,7 @@ function gun_default:get_player_axial_dir(rltv)
|
||||
local dir = Vec.new(Vec.rotate({x=0, y=0, z=1}, {y=0, x=((rotation.player_axial.x)*math.pi/180), z=0}))
|
||||
dir = Vec.rotate(dir, {y=((rotation.player_axial.y)*math.pi/180), x=0, z=0})
|
||||
if not rltv then
|
||||
dir = Vec.rotate(dir, {x=self.offsets.player_rotation.x*(math.pi/180),y=0,z=0})
|
||||
dir = Vec.rotate(dir, {x=self.offsets.player_rotation.x*math.pi/180,y=self.offsets.player_rotation.y*math.pi/180,z=0})
|
||||
end
|
||||
--[[local hud_pos = Vec.rotate(dir, {x=0,y=self.offsets.player_rotation.y*math.pi/180,z=0})+player:get_pos()+{x=0,y=player:get_properties().eye_height,z=0}+vector.rotate(player:get_eye_offset()/10, {x=0,y=self.offsets.player_rotation.y*math.pi/180,z=0})
|
||||
local hud = player:hud_add({
|
||||
@ -232,30 +288,35 @@ function gun_default:get_dir(rltv)
|
||||
return dir
|
||||
end
|
||||
|
||||
|
||||
function gun_default:get_pos(added_pos)
|
||||
--broken! doesn't properly reflect values.
|
||||
function gun_default:get_pos(added_pos, debug)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
added_pos = Vec.new(added_pos)
|
||||
local player = self.player
|
||||
local handler = self.handler
|
||||
local bone_location = Vec.new(handler.model_handler.offsets.arm.right)/10
|
||||
local gun_offset = Vec.new(self.properties.hip.offset)
|
||||
local player_rotation = Vec.new(self.offsets.player_rotation.x, self.offsets.player_rotation.y, 0)
|
||||
local bone_location
|
||||
local gun_offset
|
||||
if handler.control_bools.ads then
|
||||
gun_offset = self.properties.ads.offset
|
||||
bone_location = Vec.new(0, handler:get_properties().eye_height, 0)+player:get_eye_offset()/10
|
||||
bone_location, _ = player:get_eye_offset() or vector.zero(), nil
|
||||
bone_location.y = bone_location.y + handler:get_properties().eye_height
|
||||
bone_location.x = handler.horizontal_offset
|
||||
else
|
||||
--minetest is really wacky.
|
||||
bone_location.x = -bone_location.x
|
||||
player_rotation.x = self.offsets.player_rotation.x*self.consts.HIP_PLAYER_GUN_ROT_RATIO
|
||||
gun_offset = self.properties.hip.offset
|
||||
bone_location = handler.model_handler.offsets.arm.right
|
||||
bone_location.x = -bone_location.x / 10
|
||||
bone_location.z = bone_location.z / 10
|
||||
bone_location.y = bone_location.y / 10
|
||||
end
|
||||
if added_pos then
|
||||
gun_offset = gun_offset+added_pos
|
||||
end
|
||||
gun_offset = gun_offset+added_pos
|
||||
--dir needs to be rotated twice seperately to avoid weirdness
|
||||
local rotation = self.offsets.total_offset_rotation
|
||||
local bone_pos = Vec.rotate(bone_location, {x=0, y=player_rotation.y*math.pi/180, z=0})
|
||||
local gun_offset = Vec.rotate(Vec.rotate(gun_offset, {x=(rotation.player_axial.x+player_rotation.x)*math.pi/180,y=0,z=0}), {x=0,y=(rotation.player_axial.y+player_rotation.y)*math.pi/180,z=0})
|
||||
--[[local hud_pos = bone_pos+gun_offset+handler:get_pos()
|
||||
if not false then
|
||||
local pos = Vec.rotate(bone_location, {x=0, y=-handler.look_rotation.y*math.pi/180, z=0})
|
||||
pos = pos+Vec.rotate(gun_offset, Vec.dir_to_rotation(self.paxial_dir))
|
||||
local hud_pos = pos+handler:get_pos()
|
||||
if debug then
|
||||
local hud = player:hud_add({
|
||||
hud_elem_type = "image_waypoint",
|
||||
text = "muzzle_flash2.png",
|
||||
@ -267,9 +328,9 @@ function gun_default:get_pos(added_pos)
|
||||
minetest.after(0, function(hud)
|
||||
player:hud_remove(hud)
|
||||
end, hud)
|
||||
end]]
|
||||
end
|
||||
--world pos, position of bone, offset of gun from bone (with added_pos)
|
||||
return bone_pos+gun_offset+handler:get_pos(), bone_pos, gun_offset
|
||||
return pos
|
||||
end
|
||||
|
||||
function gun_default:add_entity()
|
||||
@ -277,6 +338,7 @@ function gun_default:add_entity()
|
||||
self.entity = minetest.add_entity(self.player:get_pos(), self.name.."_visual")
|
||||
local obj = self.entity:get_luaentity()
|
||||
obj.parent_player = self.player
|
||||
Guns4d.gun_by_ObjRef[self.entity] = self
|
||||
obj:on_step()
|
||||
end
|
||||
|
||||
@ -286,59 +348,6 @@ function gun_default:has_entity()
|
||||
if not self.entity:get_pos() then return false end
|
||||
return true
|
||||
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(); 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}
|
||||
local total_rot = self.offsets.total_offset_rotation
|
||||
local player_rot = self.offsets.player_rotation
|
||||
local constant = 6
|
||||
|
||||
--player look rotation. I'm going to keep it real, I don't remember what this equation does.
|
||||
if not self.sprite_scope then
|
||||
local next_vert_aim = ((player_rot.x+look_rotation.x)/(1+constant*dt))-look_rotation.x
|
||||
if math.abs(look_rotation.x-next_vert_aim) > .005 then
|
||||
player_rot.x = next_vert_aim
|
||||
else
|
||||
player_rot.x = -look_rotation.x
|
||||
end
|
||||
else
|
||||
player_rot.x = -look_rotation.x
|
||||
end
|
||||
--timers
|
||||
if self.rechamber_time > 0 then
|
||||
self.rechamber_time = self.rechamber_time - dt
|
||||
else
|
||||
self.rechamber_time = 0
|
||||
end
|
||||
self.time_since_creation = self.time_since_creation + dt
|
||||
self.time_since_last_fire = self.time_since_last_fire + dt
|
||||
|
||||
--update some vectors
|
||||
if self.consts.HAS_SWAY then self:update_sway(dt) end
|
||||
if self.consts.HAS_RECOIL then self:update_recoil(dt) end
|
||||
if self.consts.HAS_BREATHING then self:update_breathing(dt) end
|
||||
if self.consts.HAS_WAG then self:update_wag(dt) end
|
||||
self.dir = self:get_dir()
|
||||
self.local_dir = self:get_dir(true)
|
||||
self.paxial_dir = self:get_player_axial_dir()
|
||||
self.local_paxial_dir = self:get_player_axial_dir(true)
|
||||
|
||||
--sprite scope
|
||||
if self.properties.sprite_scope then
|
||||
self.sprite_scope:update()
|
||||
end
|
||||
|
||||
player_rot.y = -handler.look_rotation.y
|
||||
local offsets = self.offsets
|
||||
total_rot.player_axial = offsets.recoil.player_axial + offsets.walking.player_axial + offsets.sway.player_axial + {x=offsets.breathing.player_axial,y=0,z=0}
|
||||
total_rot.gun_axial = offsets.recoil.gun_axial + offsets.walking.gun_axial + offsets.sway.gun_axial
|
||||
end
|
||||
|
||||
function gun_default:update_wag(dt)
|
||||
local handler = self.handler
|
||||
if handler.walking then
|
||||
@ -531,6 +540,8 @@ gun_default.construct = function(def)
|
||||
def.meta = meta
|
||||
local out = {}
|
||||
|
||||
|
||||
|
||||
--create ID so we can track switches between weapons
|
||||
if meta:get_string("guns4d_id") == "" then
|
||||
local id = tostring(Unique_id.generate())
|
||||
@ -612,6 +623,9 @@ gun_default.construct = function(def)
|
||||
def.consts = table.fill(def.parent_class.consts, def.consts or {})
|
||||
props = def.properties --have to reinitialize this as the reference is replaced.
|
||||
|
||||
--print(table.tostring(props))
|
||||
def.model_handler = Guns4d.Model_bone_handler:new({modelpath = props.mesh})
|
||||
|
||||
if def.name ~= "__template" then
|
||||
assert(rawget(def, "name"), "no name provided in new class")
|
||||
assert(rawget(def, "itemstring"), "no itemstring provided in new class")
|
||||
@ -687,8 +701,9 @@ gun_default.construct = function(def)
|
||||
-- Vec.multiply({x=normal_pos.x, y=normal_pos.z, z=-normal_pos.y}, 10)
|
||||
obj:set_attach(player, lua_object.consts.HIPFIRE_BONE, normal_pos, -axial_rot, visibility)
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
--I don't know why lua's syntax makes me make it anon, but uh, fuck you.
|
||||
end
|
||||
end
|
||||
Guns4d.gun = Instantiatable_class:inherit(gun_default)
|
117
classes/Model_reader.lua
Normal file
117
classes/Model_reader.lua
Normal file
@ -0,0 +1,117 @@
|
||||
local path_seperator = "/@/"
|
||||
|
||||
Guns4d.Model_bone_handler = Instantiatable_class:inherit({
|
||||
construct = function(def)
|
||||
if def.instance then
|
||||
assert(def.modelpath, "no path provided")
|
||||
if mtul.media_paths[def.modelpath] then def.modelpath = mtul.media_paths[def.modelpath] end
|
||||
local stream = io.open(def.modelpath, "rb")
|
||||
def.b3d_table = mtul.b3d.read(stream)
|
||||
stream:close()
|
||||
stream = minetest.request_insecure_environment().io.open(minetest.get_modpath("guns4d").."/test.gltf", "wb")
|
||||
modlib.b3d.write_gltf(def.b3d_table, stream)
|
||||
stream:close()
|
||||
|
||||
def.paths = {}
|
||||
def:process_and_reformat()
|
||||
end
|
||||
end
|
||||
})
|
||||
local model_bones = Guns4d.Model_bone_handler
|
||||
--this creates a list of bone paths, and changes the index from an int to names.
|
||||
local function retrieve_hierarchy(node, out)
|
||||
if not out then out = {node} end
|
||||
if node.parent then
|
||||
table.insert(out, 1, node.parent)
|
||||
retrieve_hierarchy(node.parent, out)
|
||||
end
|
||||
return out
|
||||
end
|
||||
function model_bones:solve_global_transform(node)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
local global_transform
|
||||
local hierarcy = retrieve_hierarchy(node)
|
||||
print("start")
|
||||
for i, v in pairs(hierarcy) do
|
||||
print(i, v.name)
|
||||
end
|
||||
print("end")
|
||||
for i, v in pairs(hierarcy) do
|
||||
local pos_vec = v.position
|
||||
local rot_vec = v.rotation
|
||||
local scl_vec = v.scale
|
||||
if v.keys[2] then
|
||||
pos_vec = v.keys[2].position
|
||||
rot_vec = v.keys[2].rotation
|
||||
scl_vec = v.keys[2].scale
|
||||
end
|
||||
--rot_vec = {rot_vec[2], rot_vec[3], rot_vec[4], rot_vec[1]}
|
||||
pos_vec = {-pos_vec[1], pos_vec[2], pos_vec[3]}
|
||||
local pos = modlib.matrix4.translation(pos_vec)
|
||||
rot_vec = {-rot_vec[1], rot_vec[2], rot_vec[3], rot_vec[4]}
|
||||
local rot = modlib.matrix4.rotation(modlib.quaternion.normalize(rot_vec))
|
||||
local scl = modlib.matrix4.scale(scl_vec)
|
||||
local local_transform = scl:compose(rot):compose(pos)
|
||||
|
||||
if global_transform then
|
||||
global_transform=global_transform:multiply(local_transform)
|
||||
else
|
||||
global_transform=local_transform
|
||||
end
|
||||
end
|
||||
local pos
|
||||
if node.keys[2] then
|
||||
pos = node.position
|
||||
else
|
||||
pos = node.keys[2].position
|
||||
end
|
||||
--pos = global_transform:apply({pos[1], pos[2], pos[3], 1})
|
||||
--print(dump(global_transform))
|
||||
--return vector.new(pos[1], pos[2], pos[3])
|
||||
return vector.new(global_transform[1][4], global_transform[2][4], global_transform[3][4])
|
||||
end
|
||||
function model_bones:get_bone_global(bone_name)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
for i, v in pairs(self.paths) do
|
||||
local s, e = string.find(i, bone_name, #i-#bone_name)
|
||||
--this needs to be fixed.
|
||||
if s then
|
||||
local v1, v2 = self:solve_global_transform(v)
|
||||
return v1, v2
|
||||
end
|
||||
end
|
||||
end
|
||||
function model_bones:process_and_reformat(node, path)
|
||||
assert(self.instance, "attempt to call object method on a class")
|
||||
local first = false
|
||||
if not node then
|
||||
first = true
|
||||
node = self.b3d_table.node
|
||||
end
|
||||
path = path or ""
|
||||
node.mesh = nil --we wont be needing this
|
||||
for i, v in pairs(node.children) do
|
||||
if type(i) == "number" then
|
||||
local newpath
|
||||
if path ~= "" then
|
||||
newpath = path.." @ "..v.name
|
||||
else
|
||||
newpath = v.name
|
||||
end
|
||||
self.paths[newpath] = v
|
||||
v.mesh = nil
|
||||
v.parent = node
|
||||
node.children[v.name] = v
|
||||
node.children[i] = nil
|
||||
self:process_and_reformat(v, newpath)
|
||||
end
|
||||
end
|
||||
if first then
|
||||
for i, v in pairs(self.paths) do
|
||||
print(i)
|
||||
print(table.tostring(v.rotation))
|
||||
print(table.tostring(v.position))
|
||||
print(table.tostring(v.scale))
|
||||
end
|
||||
end
|
||||
end
|
@ -47,7 +47,9 @@ function player_model:update()
|
||||
player:set_bone_position("guns3d_reticle_bone", eye_pos, vector.new(combined.x, 180-combined.y, 0))
|
||||
player:set_bone_position("guns3d_head", self.offsets.head, {x=pitch,z=0,y=0})
|
||||
|
||||
local rot = vector.dir_to_rotation(gun.paxial_dir)*180/math.pi
|
||||
--can't use paxial dir as it needs to be relative on Y still.
|
||||
local dir = vector.rotate(gun.local_paxial_dir, {x=gun.offsets.player_rotation.x*math.pi/180,y=0,z=0})
|
||||
local rot = vector.dir_to_rotation(dir)*180/math.pi
|
||||
player:set_bone_position("guns3d_aiming_bone", eye_pos, {x=rot.x,y=-rot.y+180,z=0})
|
||||
end
|
||||
function player_model:prepare_deletion()
|
||||
|
@ -1,2 +0,0 @@
|
||||
player_api
|
||||
modlib
|
@ -1,2 +1,3 @@
|
||||
when spamming on_use, sometimes RMB in get_player_control will become stuck
|
||||
when aim >75 <-75 it gets wonky, no idea how this happens, seemingly defies laws of math.
|
||||
when spamming on_use, sometimes RMB in get_player_control will become stuck (engine)
|
||||
|
||||
classes that pollute global environment: Sprite_scope, Bullet_ray, Sprite_scope
|
@ -2,26 +2,23 @@
|
||||
|
||||
|
||||
VFX, SFX:
|
||||
Bullet hit node FX (steal mostly from 3dguns)
|
||||
~Bullet hit node FX (steal mostly from 3dguns)
|
||||
Bullet fly-by SFX
|
||||
HUD system (most can once again be pulled from 3dguns)
|
||||
reload progress
|
||||
ammunition left
|
||||
ammo type
|
||||
gun animations (take 3dguns as an example, then completely rewrite)
|
||||
+player model & gun model reading
|
||||
player model & gun model reading
|
||||
gun sounds
|
||||
|
||||
gun features
|
||||
firemodes
|
||||
gun ammo:
|
||||
~magazine relaoding
|
||||
fractional reloading
|
||||
magless flat reload
|
||||
*!!fix gimbal lock (ironsights broken)*
|
||||
"3d" optics
|
||||
attachments (last before beta)
|
||||
fix shooting through walls be pressing against them
|
||||
fix shooting through walls while pressing against them
|
||||
correct player look-down
|
||||
gun leaning
|
||||
add hip and aim bone offsets (this is for guns or modifiers that add stuff like "laser sights" or hud that simulates holographic sights, could be cool for futuristic type shooters)
|
||||
@ -33,8 +30,9 @@ bullets
|
||||
on_hitnode function callback
|
||||
|
||||
compatibility
|
||||
add consts for player inv use in Ammo_handler
|
||||
make monoid for player properties, player look offsets (especially needed for vehicle mods)
|
||||
add consts for player inv use in Ammo_handler (i.e. "main", "craft_inv")
|
||||
make monoid or use for player properties, player look offsets (especially needed for vehicle mods)
|
||||
possibly make a library for overriding core functions.
|
||||
|
||||
optimization
|
||||
hardcore optimization of get_dir() type functions required- super inefficient.
|
||||
|
39
init.lua
39
init.lua
@ -1,6 +1,7 @@
|
||||
local Vec = vector
|
||||
Guns4d = {
|
||||
players = {}
|
||||
players = {},
|
||||
gun_by_ObjRef = {} --used for getting the gun object by the ObjRef of the gun
|
||||
}
|
||||
local path = minetest.get_modpath("guns4d")
|
||||
dofile(path.."/misc_helpers.lua")
|
||||
@ -10,6 +11,7 @@ dofile(path.."/block_values.lua")
|
||||
dofile(path.."/register_ammo.lua")
|
||||
path = path .. "/classes"
|
||||
dofile(path.."/Instantiatable_class.lua")
|
||||
dofile(path.."/Model_reader.lua")
|
||||
dofile(path.."/Bullet_ray.lua")
|
||||
dofile(path.."/Control_handler.lua")
|
||||
dofile(path.."/Ammo_handler.lua")
|
||||
@ -19,19 +21,50 @@ dofile(path.."/Player_model_handler.lua")
|
||||
dofile(path.."/Player_handler.lua")
|
||||
dofile(path.."/Proxy_table.lua")
|
||||
|
||||
Guns4d.Model_bone_handler:new({modelpath="model_reader_test.b3d"})
|
||||
|
||||
--load after
|
||||
path = minetest.get_modpath("guns4d")
|
||||
|
||||
local player_handler = Guns4d.player_handler
|
||||
|
||||
local objref_mtable
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local pname = player:get_player_name()
|
||||
Guns4d.players[pname] = {
|
||||
handler = player_handler:new({player=player})
|
||||
}
|
||||
player:set_fov(80)
|
||||
end)
|
||||
|
||||
if not objref_mtable then
|
||||
objref_mtable = getmetatable(player)
|
||||
--putting this here is hacky as fuck.
|
||||
local old_get_pos = objref_mtable.get_pos
|
||||
function objref_mtable.get_pos(self)
|
||||
local gun = Guns4d.gun_by_ObjRef[self]
|
||||
if not gun then
|
||||
return old_get_pos(self)
|
||||
else
|
||||
local v, _, _ = gun:get_pos()
|
||||
return v
|
||||
end
|
||||
end
|
||||
local old_remove = objref_mtable.remove
|
||||
function objref_mtable.remove(self)
|
||||
local gun = Guns4d.gun_by_ObjRef[self]
|
||||
if gun then
|
||||
Guns4d.gun_by_ObjRef[self] = nil
|
||||
end
|
||||
return old_remove(self)
|
||||
end
|
||||
end
|
||||
end)
|
||||
--we grab the ObjRef metatable from the first available source.
|
||||
--because we want guns to function as real objects, we have to override the metatable get_pos() for all objects
|
||||
--this is made more efficient by using a table lookup for ObjRefs we want to update properly.
|
||||
--"uns4d[ObjRef] = gun" is declared on_activate() in the entity.
|
||||
--[[minetest.after(0, function()
|
||||
|
||||
end)]]
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
local pname = player:get_player_name()
|
||||
Guns4d.players[pname].handler:prepare_deletion()
|
||||
|
5
mod.conf
Normal file
5
mod.conf
Normal file
@ -0,0 +1,5 @@
|
||||
name = guns4d
|
||||
title = guns4d
|
||||
description = Adds a library for 3d guns
|
||||
author = FatalError42O
|
||||
depends = mtul_b3d
|
BIN
models/model_reader_test.b3d
Normal file
BIN
models/model_reader_test.b3d
Normal file
Binary file not shown.
@ -148,7 +148,6 @@ minetest.register_entity("guns4d:bullet_hole", {
|
||||
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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user